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