Move Source/WebCore/rendering/ code to std::unique_ptr
[WebKit-https.git] / Source / WebCore / rendering / svg / SVGResources.cpp
1 /*
2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "SVGResources.h"
22
23 #include "RenderSVGResourceClipper.h"
24 #include "RenderSVGResourceFilter.h"
25 #include "RenderSVGResourceMarker.h"
26 #include "RenderSVGResourceMasker.h"
27 #include "SVGGradientElement.h"
28 #include "SVGNames.h"
29 #include "SVGPaint.h"
30 #include "SVGPatternElement.h"
31 #include "SVGRenderStyle.h"
32 #include "SVGURIReference.h"
33
34 #ifndef NDEBUG
35 #include <stdio.h>
36 #endif
37
38 namespace WebCore {
39
40 SVGResources::SVGResources()
41     : m_linkedResource(0)
42 {
43 }
44
45 static HashSet<AtomicString>& clipperFilterMaskerTags()
46 {
47     DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
48     if (s_tagList.isEmpty()) {
49         // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
50         // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
51         s_tagList.add(SVGNames::aTag.localName());
52         s_tagList.add(SVGNames::circleTag.localName());
53         s_tagList.add(SVGNames::ellipseTag.localName());
54         s_tagList.add(SVGNames::glyphTag.localName());
55         s_tagList.add(SVGNames::gTag.localName());
56         s_tagList.add(SVGNames::imageTag.localName());
57         s_tagList.add(SVGNames::lineTag.localName());
58         s_tagList.add(SVGNames::markerTag.localName());
59         s_tagList.add(SVGNames::maskTag.localName());
60         s_tagList.add(SVGNames::missing_glyphTag.localName());
61         s_tagList.add(SVGNames::pathTag.localName());
62         s_tagList.add(SVGNames::polygonTag.localName());
63         s_tagList.add(SVGNames::polylineTag.localName());
64         s_tagList.add(SVGNames::rectTag.localName());
65         s_tagList.add(SVGNames::svgTag.localName());
66         s_tagList.add(SVGNames::textTag.localName());
67         s_tagList.add(SVGNames::useTag.localName());
68
69         // Not listed in the definitions is the clipPath element, the SVG spec says though:
70         // The "clipPath" element or any of its children can specify property "clip-path".
71         // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail.
72         // (Already mailed SVG WG, waiting for a solution)
73         s_tagList.add(SVGNames::clipPathTag.localName());
74
75         // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed.
76         // (Already mailed SVG WG, waiting for a solution)
77         s_tagList.add(SVGNames::altGlyphTag.localName());
78         s_tagList.add(SVGNames::textPathTag.localName());
79         s_tagList.add(SVGNames::trefTag.localName());
80         s_tagList.add(SVGNames::tspanTag.localName());
81
82         // Not listed in the definitions is the foreignObject element, but clip-path
83         // is a supported attribute.
84         s_tagList.add(SVGNames::foreignObjectTag.localName());
85
86         // Elements that we ignore, as it doesn't make any sense.
87         // defs, pattern, switch (FIXME: Mail SVG WG about these)
88         // symbol (is converted to a svg element, when referenced by use, we can safely ignore it.)
89     }
90
91     return s_tagList;
92 }
93
94 static HashSet<AtomicString>& markerTags()
95 {
96     DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
97     if (s_tagList.isEmpty()) {
98         s_tagList.add(SVGNames::lineTag.localName());
99         s_tagList.add(SVGNames::pathTag.localName());
100         s_tagList.add(SVGNames::polygonTag.localName());
101         s_tagList.add(SVGNames::polylineTag.localName());
102     }
103
104     return s_tagList;
105 }
106
107 static HashSet<AtomicString>& fillAndStrokeTags()
108 {
109     DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
110     if (s_tagList.isEmpty()) {
111         s_tagList.add(SVGNames::altGlyphTag.localName());
112         s_tagList.add(SVGNames::circleTag.localName());
113         s_tagList.add(SVGNames::ellipseTag.localName());
114         s_tagList.add(SVGNames::lineTag.localName());
115         s_tagList.add(SVGNames::pathTag.localName());
116         s_tagList.add(SVGNames::polygonTag.localName());
117         s_tagList.add(SVGNames::polylineTag.localName());
118         s_tagList.add(SVGNames::rectTag.localName());
119         s_tagList.add(SVGNames::textTag.localName());
120         s_tagList.add(SVGNames::textPathTag.localName());
121         s_tagList.add(SVGNames::trefTag.localName());
122         s_tagList.add(SVGNames::tspanTag.localName());
123     }
124
125     return s_tagList;
126 }
127
128 static HashSet<AtomicString>& chainableResourceTags()
129 {
130     DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
131     if (s_tagList.isEmpty()) {
132         s_tagList.add(SVGNames::linearGradientTag.localName());
133         s_tagList.add(SVGNames::filterTag.localName());
134         s_tagList.add(SVGNames::patternTag.localName());
135         s_tagList.add(SVGNames::radialGradientTag.localName());
136     }
137
138     return s_tagList;
139 }
140
141 static inline String targetReferenceFromResource(SVGElement& element)
142 {
143     String target;
144     if (isSVGPatternElement(element))
145         target = toSVGPatternElement(element).href();
146     else if (isSVGGradientElement(element))
147         target = toSVGGradientElement(element).href();
148 #if ENABLE(FILTERS)
149     else if (isSVGFilterElement(element))
150         target = toSVGFilterElement(element).href();
151 #endif
152     else
153         ASSERT_NOT_REACHED();
154
155     return SVGURIReference::fragmentIdentifierFromIRIString(target, element.document());
156 }
157
158 static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& document, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource)
159 {
160     if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)
161         return 0;
162
163     id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, document);
164     RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id);
165     if (!container) {
166         hasPendingResource = true;
167         return 0;
168     }
169
170     RenderSVGResourceType resourceType = container->resourceType();
171     if (resourceType != PatternResourceType && resourceType != LinearGradientResourceType && resourceType != RadialGradientResourceType)
172         return 0;
173
174     return container;
175 }
176
177 static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement& element)
178 {
179     extensions->addPendingResource(id, &element);
180 }
181
182 bool SVGResources::buildCachedResources(const RenderElement& renderer, const SVGRenderStyle& svgStyle)
183 {
184     ASSERT(renderer.element());
185     ASSERT_WITH_SECURITY_IMPLICATION(renderer.element()->isSVGElement());
186
187     if (!renderer.element())
188         return false;
189
190     auto& element = toSVGElement(*renderer.element());
191
192     Document& document = element.document();
193
194     SVGDocumentExtensions* extensions = document.accessSVGExtensions();
195     ASSERT(extensions);
196
197     const AtomicString& tagName = element.localName();
198     if (tagName.isNull())
199         return false;
200
201     bool foundResources = false;
202     if (clipperFilterMaskerTags().contains(tagName)) {
203         if (svgStyle.hasClipper()) {
204             AtomicString id(svgStyle.clipperResource());
205             if (setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id)))
206                 foundResources = true;
207             else
208                 registerPendingResource(extensions, id, element);
209         }
210
211 #if ENABLE(FILTERS)
212         if (svgStyle.hasFilter()) {
213             AtomicString id(svgStyle.filterResource());
214             if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id)))
215                 foundResources = true;
216             else
217                 registerPendingResource(extensions, id, element);
218         }
219 #endif
220
221         if (svgStyle.hasMasker()) {
222             AtomicString id(svgStyle.maskerResource());
223             if (setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id)))
224                 foundResources = true;
225             else
226                 registerPendingResource(extensions, id, element);
227         }
228     }
229
230     if (markerTags().contains(tagName) && svgStyle.hasMarkers()) {
231         AtomicString markerStartId(svgStyle.markerStartResource());
232         if (setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId)))
233             foundResources = true;
234         else
235             registerPendingResource(extensions, markerStartId, element);
236
237         AtomicString markerMidId(svgStyle.markerMidResource());
238         if (setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId)))
239             foundResources = true;
240         else
241             registerPendingResource(extensions, markerMidId, element);
242
243         AtomicString markerEndId(svgStyle.markerEndResource());
244         if (setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId)))
245             foundResources = true;
246         else
247             registerPendingResource(extensions, markerEndId, element);
248     }
249
250     if (fillAndStrokeTags().contains(tagName)) {
251         if (svgStyle.hasFill()) {
252             bool hasPendingResource = false;
253             AtomicString id;
254             if (setFill(paintingResourceFromSVGPaint(document, svgStyle.fillPaintType(), svgStyle.fillPaintUri(), id, hasPendingResource)))
255                 foundResources = true;
256             else if (hasPendingResource)
257                 registerPendingResource(extensions, id, element);
258         }
259
260         if (svgStyle.hasStroke()) {
261             bool hasPendingResource = false;
262             AtomicString id;
263             if (setStroke(paintingResourceFromSVGPaint(document, svgStyle.strokePaintType(), svgStyle.strokePaintUri(), id, hasPendingResource)))
264                 foundResources = true;
265             else if (hasPendingResource)
266                 registerPendingResource(extensions, id, element);
267         }
268     }
269
270     if (chainableResourceTags().contains(tagName)) {
271         AtomicString id(targetReferenceFromResource(element));
272         if (setLinkedResource(getRenderSVGResourceContainerById(document, id)))
273             foundResources = true;
274         else
275             registerPendingResource(extensions, id, element);
276     }
277
278     return foundResources;
279 }
280
281 void SVGResources::removeClientFromCache(RenderElement& renderer, bool markForInvalidation) const
282 {
283     if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
284         return;
285
286     if (m_linkedResource) {
287         ASSERT(!m_clipperFilterMaskerData);
288         ASSERT(!m_markerData);
289         ASSERT(!m_fillStrokeData);
290         m_linkedResource->removeClientFromCache(renderer, markForInvalidation);
291         return;
292     }
293
294     if (m_clipperFilterMaskerData) {
295         if (m_clipperFilterMaskerData->clipper)
296             m_clipperFilterMaskerData->clipper->removeClientFromCache(renderer, markForInvalidation);
297 #if ENABLE(FILTERS)
298         if (m_clipperFilterMaskerData->filter)
299             m_clipperFilterMaskerData->filter->removeClientFromCache(renderer, markForInvalidation);
300 #endif
301         if (m_clipperFilterMaskerData->masker)
302             m_clipperFilterMaskerData->masker->removeClientFromCache(renderer, markForInvalidation);
303     }
304
305     if (m_markerData) {
306         if (m_markerData->markerStart)
307             m_markerData->markerStart->removeClientFromCache(renderer, markForInvalidation);
308         if (m_markerData->markerMid)
309             m_markerData->markerMid->removeClientFromCache(renderer, markForInvalidation);
310         if (m_markerData->markerEnd)
311             m_markerData->markerEnd->removeClientFromCache(renderer, markForInvalidation);
312     }
313
314     if (m_fillStrokeData) {
315         if (m_fillStrokeData->fill)
316             m_fillStrokeData->fill->removeClientFromCache(renderer, markForInvalidation);
317         if (m_fillStrokeData->stroke)
318             m_fillStrokeData->stroke->removeClientFromCache(renderer, markForInvalidation);
319     }
320 }
321
322 void SVGResources::resourceDestroyed(RenderSVGResourceContainer& resource)
323 {
324     if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
325         return;
326
327     if (m_linkedResource == &resource) {
328         ASSERT(!m_clipperFilterMaskerData);
329         ASSERT(!m_markerData);
330         ASSERT(!m_fillStrokeData);
331         m_linkedResource->removeAllClientsFromCache();
332         m_linkedResource = 0;
333         return;
334     }
335
336     switch (resource.resourceType()) {
337     case MaskerResourceType:
338         if (!m_clipperFilterMaskerData)
339             break;
340         if (m_clipperFilterMaskerData->masker == &resource) {
341             m_clipperFilterMaskerData->masker->removeAllClientsFromCache();
342             m_clipperFilterMaskerData->masker = 0;
343         }
344         break;
345     case MarkerResourceType:
346         if (!m_markerData)
347             break;
348         if (m_markerData->markerStart == &resource) {
349             m_markerData->markerStart->removeAllClientsFromCache();
350             m_markerData->markerStart = 0;
351         }
352         if (m_markerData->markerMid == &resource) {
353             m_markerData->markerMid->removeAllClientsFromCache();
354             m_markerData->markerMid = 0;
355         }
356         if (m_markerData->markerEnd == &resource) {
357             m_markerData->markerEnd->removeAllClientsFromCache();
358             m_markerData->markerEnd = 0;
359         }
360         break;
361     case PatternResourceType:
362     case LinearGradientResourceType:
363     case RadialGradientResourceType:
364         if (!m_fillStrokeData)
365             break;
366         if (m_fillStrokeData->fill == &resource) {
367             m_fillStrokeData->fill->removeAllClientsFromCache();
368             m_fillStrokeData->fill = 0;
369         }
370         if (m_fillStrokeData->stroke == &resource) {
371             m_fillStrokeData->stroke->removeAllClientsFromCache();
372             m_fillStrokeData->stroke = 0;
373         }
374         break;
375     case FilterResourceType:
376 #if ENABLE(FILTERS)
377         if (!m_clipperFilterMaskerData)
378             break;
379         if (m_clipperFilterMaskerData->filter == &resource) {
380             m_clipperFilterMaskerData->filter->removeAllClientsFromCache();
381             m_clipperFilterMaskerData->filter = 0;
382         }
383 #else
384         ASSERT_NOT_REACHED();
385 #endif
386         break;
387     case ClipperResourceType:
388         if (!m_clipperFilterMaskerData)
389             break; 
390         if (m_clipperFilterMaskerData->clipper == &resource) {
391             m_clipperFilterMaskerData->clipper->removeAllClientsFromCache();
392             m_clipperFilterMaskerData->clipper = 0;
393         }
394         break;
395     case SolidColorResourceType:
396         ASSERT_NOT_REACHED();
397     }
398 }
399
400 void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set)
401 {
402     if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
403         return;
404
405     if (m_linkedResource) {
406         ASSERT(!m_clipperFilterMaskerData);
407         ASSERT(!m_markerData);
408         ASSERT(!m_fillStrokeData);
409         set.add(m_linkedResource);
410         return;
411     }
412
413     if (m_clipperFilterMaskerData) {
414         if (m_clipperFilterMaskerData->clipper)
415             set.add(m_clipperFilterMaskerData->clipper);
416 #if ENABLE(FILTERS)
417         if (m_clipperFilterMaskerData->filter)
418             set.add(m_clipperFilterMaskerData->filter);
419 #endif
420         if (m_clipperFilterMaskerData->masker)
421             set.add(m_clipperFilterMaskerData->masker);
422     }
423
424     if (m_markerData) {
425         if (m_markerData->markerStart)
426             set.add(m_markerData->markerStart);
427         if (m_markerData->markerMid)
428             set.add(m_markerData->markerMid);
429         if (m_markerData->markerEnd)
430             set.add(m_markerData->markerEnd);
431     }
432
433     if (m_fillStrokeData) {
434         if (m_fillStrokeData->fill)
435             set.add(m_fillStrokeData->fill);
436         if (m_fillStrokeData->stroke)
437             set.add(m_fillStrokeData->stroke);
438     }
439 }
440
441 bool SVGResources::setClipper(RenderSVGResourceClipper* clipper)
442 {
443     if (!clipper)
444         return false;
445
446     ASSERT(clipper->resourceType() == ClipperResourceType);
447
448     if (!m_clipperFilterMaskerData)
449         m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>();
450
451     m_clipperFilterMaskerData->clipper = clipper;
452     return true;
453 }
454
455 void SVGResources::resetClipper()
456 {
457     ASSERT(m_clipperFilterMaskerData);
458     ASSERT(m_clipperFilterMaskerData->clipper);
459     m_clipperFilterMaskerData->clipper = 0;
460 }
461
462 #if ENABLE(FILTERS)
463 bool SVGResources::setFilter(RenderSVGResourceFilter* filter)
464 {
465     if (!filter)
466         return false;
467
468     ASSERT(filter->resourceType() == FilterResourceType);
469
470     if (!m_clipperFilterMaskerData)
471         m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>();
472
473     m_clipperFilterMaskerData->filter = filter;
474     return true;
475 }
476
477 void SVGResources::resetFilter()
478 {
479     ASSERT(m_clipperFilterMaskerData);
480     ASSERT(m_clipperFilterMaskerData->filter);
481     m_clipperFilterMaskerData->filter = 0;
482 }
483 #endif
484
485 bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart)
486 {
487     if (!markerStart)
488         return false;
489
490     ASSERT(markerStart->resourceType() == MarkerResourceType);
491
492     if (!m_markerData)
493         m_markerData = std::make_unique<MarkerData>();
494
495     m_markerData->markerStart = markerStart;
496     return true;
497 }
498
499 void SVGResources::resetMarkerStart()
500 {
501     ASSERT(m_markerData);
502     ASSERT(m_markerData->markerStart);
503     m_markerData->markerStart = 0;
504 }
505
506 bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid)
507 {
508     if (!markerMid)
509         return false;
510
511     ASSERT(markerMid->resourceType() == MarkerResourceType);
512
513     if (!m_markerData)
514         m_markerData = std::make_unique<MarkerData>();
515
516     m_markerData->markerMid = markerMid;
517     return true;
518 }
519
520 void SVGResources::resetMarkerMid()
521 {
522     ASSERT(m_markerData);
523     ASSERT(m_markerData->markerMid);
524     m_markerData->markerMid = 0;
525 }
526
527 bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd)
528 {
529     if (!markerEnd)
530         return false;
531
532     ASSERT(markerEnd->resourceType() == MarkerResourceType);
533
534     if (!m_markerData)
535         m_markerData = std::make_unique<MarkerData>();
536
537     m_markerData->markerEnd = markerEnd;
538     return true;
539 }
540
541 void SVGResources::resetMarkerEnd()
542 {
543     ASSERT(m_markerData);
544     ASSERT(m_markerData->markerEnd);
545     m_markerData->markerEnd = 0;
546 }
547
548 bool SVGResources::setMasker(RenderSVGResourceMasker* masker)
549 {
550     if (!masker)
551         return false;
552
553     ASSERT(masker->resourceType() == MaskerResourceType);
554
555     if (!m_clipperFilterMaskerData)
556         m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>();
557
558     m_clipperFilterMaskerData->masker = masker;
559     return true;
560 }
561
562 void SVGResources::resetMasker()
563 {
564     ASSERT(m_clipperFilterMaskerData);
565     ASSERT(m_clipperFilterMaskerData->masker);
566     m_clipperFilterMaskerData->masker = 0;
567 }
568
569 bool SVGResources::setFill(RenderSVGResourceContainer* fill)
570 {
571     if (!fill)
572         return false;
573
574     ASSERT(fill->resourceType() == PatternResourceType
575            || fill->resourceType() == LinearGradientResourceType
576            || fill->resourceType() == RadialGradientResourceType);
577
578     if (!m_fillStrokeData)
579         m_fillStrokeData = std::make_unique<FillStrokeData>();
580
581     m_fillStrokeData->fill = fill;
582     return true;
583 }
584
585 void SVGResources::resetFill()
586 {
587     ASSERT(m_fillStrokeData);
588     ASSERT(m_fillStrokeData->fill);
589     m_fillStrokeData->fill = 0;
590 }
591
592 bool SVGResources::setStroke(RenderSVGResourceContainer* stroke)
593 {
594     if (!stroke)
595         return false;
596
597     ASSERT(stroke->resourceType() == PatternResourceType
598            || stroke->resourceType() == LinearGradientResourceType
599            || stroke->resourceType() == RadialGradientResourceType);
600
601     if (!m_fillStrokeData)
602         m_fillStrokeData = std::make_unique<FillStrokeData>();
603
604     m_fillStrokeData->stroke = stroke;
605     return true;
606 }
607
608 void SVGResources::resetStroke()
609 {
610     ASSERT(m_fillStrokeData);
611     ASSERT(m_fillStrokeData->stroke);
612     m_fillStrokeData->stroke = 0;
613 }
614
615 bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource)
616 {
617     if (!linkedResource)
618         return false;
619
620     m_linkedResource = linkedResource;
621     return true;
622 }
623
624 void SVGResources::resetLinkedResource()
625 {
626     ASSERT(m_linkedResource);
627     m_linkedResource = 0;
628 }
629
630 #ifndef NDEBUG
631 void SVGResources::dump(const RenderObject* object)
632 {
633     ASSERT(object);
634     ASSERT(object->node());
635
636     fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node());
637     fprintf(stderr, " | DOM Tree:\n");
638     object->node()->showTreeForThis();
639
640     fprintf(stderr, "\n | List of resources:\n");
641     if (m_clipperFilterMaskerData) {
642         if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
643             fprintf(stderr, " |-> Clipper    : %p (node=%p)\n", clipper, &clipper->clipPathElement());
644 #if ENABLE(FILTERS)
645         if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
646             fprintf(stderr, " |-> Filter     : %p (node=%p)\n", filter, &filter->filterElement());
647 #endif
648         if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
649             fprintf(stderr, " |-> Masker     : %p (node=%p)\n", masker, &masker->maskElement());
650     }
651
652     if (m_markerData) {
653         if (RenderSVGResourceMarker* markerStart = m_markerData->markerStart)
654             fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, &markerStart->markerElement());
655         if (RenderSVGResourceMarker* markerMid = m_markerData->markerMid)
656             fprintf(stderr, " |-> MarkerMid  : %p (node=%p)\n", markerMid, &markerMid->markerElement());
657         if (RenderSVGResourceMarker* markerEnd = m_markerData->markerEnd)
658             fprintf(stderr, " |-> MarkerEnd  : %p (node=%p)\n", markerEnd, &markerEnd->markerElement());
659     }
660
661     if (m_fillStrokeData) {
662         if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill)
663             fprintf(stderr, " |-> Fill       : %p (node=%p)\n", fill, &fill->element());
664         if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke)
665             fprintf(stderr, " |-> Stroke     : %p (node=%p)\n", stroke, &stroke->element());
666     }
667
668     if (m_linkedResource)
669         fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, &m_linkedResource->element());
670 }
671 #endif
672
673 }