Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/rendering/svg/SVGResources.h"
22
23 #include "SVGNames.h"
24 #include "core/rendering/style/SVGRenderStyle.h"
25 #include "core/rendering/svg/RenderSVGResourceClipper.h"
26 #include "core/rendering/svg/RenderSVGResourceFilter.h"
27 #include "core/rendering/svg/RenderSVGResourceMarker.h"
28 #include "core/rendering/svg/RenderSVGResourceMasker.h"
29 #include "core/svg/SVGFilterElement.h"
30 #include "core/svg/SVGGradientElement.h"
31 #include "core/svg/SVGPaint.h"
32 #include "core/svg/SVGPatternElement.h"
33 #include "core/svg/SVGURIReference.h"
34
35 #ifndef NDEBUG
36 #include <stdio.h>
37 #endif
38
39 namespace WebCore {
40
41 SVGResources::SVGResources()
42     : m_linkedResource(0)
43 {
44 }
45
46 static HashSet<AtomicString>& clipperFilterMaskerTags()
47 {
48     DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
49     if (s_tagList.isEmpty()) {
50         // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
51         // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
52         s_tagList.add(SVGNames::aTag.localName());
53         s_tagList.add(SVGNames::circleTag.localName());
54         s_tagList.add(SVGNames::ellipseTag.localName());
55         s_tagList.add(SVGNames::glyphTag.localName());
56         s_tagList.add(SVGNames::gTag.localName());
57         s_tagList.add(SVGNames::imageTag.localName());
58         s_tagList.add(SVGNames::lineTag.localName());
59         s_tagList.add(SVGNames::markerTag.localName());
60         s_tagList.add(SVGNames::maskTag.localName());
61         s_tagList.add(SVGNames::missing_glyphTag.localName());
62         s_tagList.add(SVGNames::pathTag.localName());
63         s_tagList.add(SVGNames::polygonTag.localName());
64         s_tagList.add(SVGNames::polylineTag.localName());
65         s_tagList.add(SVGNames::rectTag.localName());
66         s_tagList.add(SVGNames::svgTag.localName());
67         s_tagList.add(SVGNames::textTag.localName());
68         s_tagList.add(SVGNames::useTag.localName());
69
70         // Not listed in the definitions is the clipPath element, the SVG spec says though:
71         // The "clipPath" element or any of its children can specify property "clip-path".
72         // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail.
73         // (Already mailed SVG WG, waiting for a solution)
74         s_tagList.add(SVGNames::clipPathTag.localName());
75
76         // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed.
77         // (Already mailed SVG WG, waiting for a solution)
78         s_tagList.add(SVGNames::altGlyphTag.localName());
79         s_tagList.add(SVGNames::textPathTag.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 bool SVGResources::supportsMarkers(const SVGElement& element)
95 {
96     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.contains(element.localName());
105 }
106
107 static HashSet<AtomicString>& fillAndStrokeTags()
108 {
109     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::tspanTag.localName());
122     }
123
124     return s_tagList;
125 }
126
127 static HashSet<AtomicString>& chainableResourceTags()
128 {
129     DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
130     if (s_tagList.isEmpty()) {
131         s_tagList.add(SVGNames::linearGradientTag.localName());
132         s_tagList.add(SVGNames::filterTag.localName());
133         s_tagList.add(SVGNames::patternTag.localName());
134         s_tagList.add(SVGNames::radialGradientTag.localName());
135     }
136
137     return s_tagList;
138 }
139
140 static inline AtomicString targetReferenceFromResource(SVGElement& element)
141 {
142     String target;
143     if (isSVGPatternElement(element))
144         target = toSVGPatternElement(element).href()->currentValue()->value();
145     else if (isSVGGradientElement(element))
146         target = toSVGGradientElement(element).href()->currentValue()->value();
147     else if (isSVGFilterElement(element))
148         target = toSVGFilterElement(element).href()->currentValue()->value();
149     else
150         ASSERT_NOT_REACHED();
151
152     return SVGURIReference::fragmentIdentifierFromIRIString(target, element.treeScope());
153 }
154
155 static inline bool svgPaintTypeHasURL(SVGPaint::SVGPaintType paintType)
156 {
157     switch (paintType) {
158     case SVGPaint::SVG_PAINTTYPE_URI_NONE:
159     case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR:
160     case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR:
161     case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR:
162     case SVGPaint::SVG_PAINTTYPE_URI:
163         return true;
164     default:
165         break;
166     }
167     return false;
168 }
169
170 static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(TreeScope& treeScope, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource)
171 {
172     if (!svgPaintTypeHasURL(paintType))
173         return 0;
174
175     id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, treeScope);
176     RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(treeScope, id);
177     if (!container) {
178         hasPendingResource = true;
179         return 0;
180     }
181
182     RenderSVGResourceType resourceType = container->resourceType();
183     if (resourceType != PatternResourceType && resourceType != LinearGradientResourceType && resourceType != RadialGradientResourceType)
184         return 0;
185
186     return container;
187 }
188
189 static inline void registerPendingResource(SVGDocumentExtensions& extensions, const AtomicString& id, SVGElement* element)
190 {
191     ASSERT(element);
192     extensions.addPendingResource(id, element);
193 }
194
195 bool SVGResources::hasResourceData() const
196 {
197     return !m_clipperFilterMaskerData
198         && !m_markerData
199         && !m_fillStrokeData
200         && !m_linkedResource;
201 }
202
203 static inline SVGResources* ensureResources(OwnPtr<SVGResources>& resources)
204 {
205     if (!resources)
206         resources = adoptPtr(new SVGResources);
207
208     return resources.get();
209 }
210
211 PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object, const SVGRenderStyle* style)
212 {
213     ASSERT(object);
214     ASSERT(style);
215
216     Node* node = object->node();
217     ASSERT(node);
218     ASSERT_WITH_SECURITY_IMPLICATION(node->isSVGElement());
219
220     SVGElement* element = toSVGElement(node);
221     if (!element)
222         return nullptr;
223
224     TreeScope& treeScope = element->treeScope();
225
226     SVGDocumentExtensions& extensions = object->document().accessSVGExtensions();
227
228     const AtomicString& tagName = element->localName();
229     if (tagName.isNull())
230         return nullptr;
231
232     OwnPtr<SVGResources> resources;
233     if (clipperFilterMaskerTags().contains(tagName)) {
234         if (style->hasClipper()) {
235             AtomicString id = style->clipperResource();
236             if (!ensureResources(resources)->setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(treeScope, id)))
237                 registerPendingResource(extensions, id, element);
238         }
239
240         if (style->hasFilter()) {
241             AtomicString id = style->filterResource();
242             if (!ensureResources(resources)->setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(treeScope, id)))
243                 registerPendingResource(extensions, id, element);
244         }
245
246         if (style->hasMasker()) {
247             AtomicString id = style->maskerResource();
248             if (!ensureResources(resources)->setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(treeScope, id)))
249                 registerPendingResource(extensions, id, element);
250         }
251     }
252
253     if (style->hasMarkers() && supportsMarkers(*element)) {
254         const AtomicString& markerStartId = style->markerStartResource();
255         if (!ensureResources(resources)->setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, markerStartId)))
256             registerPendingResource(extensions, markerStartId, element);
257
258         const AtomicString& markerMidId = style->markerMidResource();
259         if (!ensureResources(resources)->setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, markerMidId)))
260             registerPendingResource(extensions, markerMidId, element);
261
262         const AtomicString& markerEndId = style->markerEndResource();
263         if (!ensureResources(resources)->setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, style->markerEndResource())))
264             registerPendingResource(extensions, markerEndId, element);
265     }
266
267     if (fillAndStrokeTags().contains(tagName)) {
268         if (style->hasFill()) {
269             bool hasPendingResource = false;
270             AtomicString id;
271             RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(treeScope, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource);
272             if (!ensureResources(resources)->setFill(resource) && hasPendingResource) {
273                 registerPendingResource(extensions, id, element);
274             }
275         }
276
277         if (style->hasStroke()) {
278             bool hasPendingResource = false;
279             AtomicString id;
280             RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(treeScope, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource);
281             if (!ensureResources(resources)->setStroke(resource) && hasPendingResource) {
282                 registerPendingResource(extensions, id, element);
283             }
284         }
285     }
286
287     if (chainableResourceTags().contains(tagName)) {
288         AtomicString id = targetReferenceFromResource(*element);
289         if (!ensureResources(resources)->setLinkedResource(getRenderSVGResourceContainerById(treeScope, id)))
290             registerPendingResource(extensions, id, element);
291     }
292
293     return (!resources || resources->hasResourceData()) ? nullptr : resources.release();
294 }
295
296 void SVGResources::layoutIfNeeded()
297 {
298     if (m_clipperFilterMaskerData) {
299         if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
300             clipper->layoutIfNeeded();
301         if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
302             masker->layoutIfNeeded();
303         if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
304             filter->layoutIfNeeded();
305     }
306
307     if (m_markerData) {
308         if (RenderSVGResourceMarker* marker = m_markerData->markerStart)
309             marker->layoutIfNeeded();
310         if (RenderSVGResourceMarker* marker = m_markerData->markerMid)
311             marker->layoutIfNeeded();
312         if (RenderSVGResourceMarker* marker = m_markerData->markerEnd)
313             marker->layoutIfNeeded();
314     }
315
316     if (m_fillStrokeData) {
317         if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill)
318             fill->layoutIfNeeded();
319         if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke)
320             stroke->layoutIfNeeded();
321     }
322
323     if (m_linkedResource)
324         m_linkedResource->layoutIfNeeded();
325 }
326
327 void SVGResources::removeClientFromCache(RenderObject* object, bool markForInvalidation) const
328 {
329     if (hasResourceData())
330         return;
331
332     if (m_linkedResource) {
333         ASSERT(!m_clipperFilterMaskerData);
334         ASSERT(!m_markerData);
335         ASSERT(!m_fillStrokeData);
336         m_linkedResource->removeClientFromCache(object, markForInvalidation);
337         return;
338     }
339
340     if (m_clipperFilterMaskerData) {
341         if (m_clipperFilterMaskerData->clipper)
342             m_clipperFilterMaskerData->clipper->removeClientFromCache(object, markForInvalidation);
343         if (m_clipperFilterMaskerData->filter)
344             m_clipperFilterMaskerData->filter->removeClientFromCache(object, markForInvalidation);
345         if (m_clipperFilterMaskerData->masker)
346             m_clipperFilterMaskerData->masker->removeClientFromCache(object, markForInvalidation);
347     }
348
349     if (m_markerData) {
350         if (m_markerData->markerStart)
351             m_markerData->markerStart->removeClientFromCache(object, markForInvalidation);
352         if (m_markerData->markerMid)
353             m_markerData->markerMid->removeClientFromCache(object, markForInvalidation);
354         if (m_markerData->markerEnd)
355             m_markerData->markerEnd->removeClientFromCache(object, markForInvalidation);
356     }
357
358     if (m_fillStrokeData) {
359         if (m_fillStrokeData->fill)
360             m_fillStrokeData->fill->removeClientFromCache(object, markForInvalidation);
361         if (m_fillStrokeData->stroke)
362             m_fillStrokeData->stroke->removeClientFromCache(object, markForInvalidation);
363     }
364 }
365
366 void SVGResources::resourceDestroyed(RenderSVGResourceContainer* resource)
367 {
368     ASSERT(resource);
369     if (hasResourceData())
370         return;
371
372     if (m_linkedResource == resource) {
373         ASSERT(!m_clipperFilterMaskerData);
374         ASSERT(!m_markerData);
375         ASSERT(!m_fillStrokeData);
376         m_linkedResource->removeAllClientsFromCache();
377         m_linkedResource = 0;
378         return;
379     }
380
381     switch (resource->resourceType()) {
382     case MaskerResourceType:
383         if (!m_clipperFilterMaskerData)
384             break;
385         if (m_clipperFilterMaskerData->masker == resource) {
386             m_clipperFilterMaskerData->masker->removeAllClientsFromCache();
387             m_clipperFilterMaskerData->masker = 0;
388         }
389         break;
390     case MarkerResourceType:
391         if (!m_markerData)
392             break;
393         if (m_markerData->markerStart == resource) {
394             m_markerData->markerStart->removeAllClientsFromCache();
395             m_markerData->markerStart = 0;
396         }
397         if (m_markerData->markerMid == resource) {
398             m_markerData->markerMid->removeAllClientsFromCache();
399             m_markerData->markerMid = 0;
400         }
401         if (m_markerData->markerEnd == resource) {
402             m_markerData->markerEnd->removeAllClientsFromCache();
403             m_markerData->markerEnd = 0;
404         }
405         break;
406     case PatternResourceType:
407     case LinearGradientResourceType:
408     case RadialGradientResourceType:
409         if (!m_fillStrokeData)
410             break;
411         if (m_fillStrokeData->fill == resource) {
412             m_fillStrokeData->fill->removeAllClientsFromCache();
413             m_fillStrokeData->fill = 0;
414         }
415         if (m_fillStrokeData->stroke == resource) {
416             m_fillStrokeData->stroke->removeAllClientsFromCache();
417             m_fillStrokeData->stroke = 0;
418         }
419         break;
420     case FilterResourceType:
421         if (!m_clipperFilterMaskerData)
422             break;
423         if (m_clipperFilterMaskerData->filter == resource) {
424             m_clipperFilterMaskerData->filter->removeAllClientsFromCache();
425             m_clipperFilterMaskerData->filter = 0;
426         }
427         break;
428     case ClipperResourceType:
429         if (!m_clipperFilterMaskerData)
430             break;
431         if (m_clipperFilterMaskerData->clipper == resource) {
432             m_clipperFilterMaskerData->clipper->removeAllClientsFromCache();
433             m_clipperFilterMaskerData->clipper = 0;
434         }
435         break;
436     case SolidColorResourceType:
437         ASSERT_NOT_REACHED();
438     }
439 }
440
441 void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set)
442 {
443     if (hasResourceData())
444         return;
445
446     if (m_linkedResource) {
447         ASSERT(!m_clipperFilterMaskerData);
448         ASSERT(!m_markerData);
449         ASSERT(!m_fillStrokeData);
450         set.add(m_linkedResource);
451         return;
452     }
453
454     if (m_clipperFilterMaskerData) {
455         if (m_clipperFilterMaskerData->clipper)
456             set.add(m_clipperFilterMaskerData->clipper);
457         if (m_clipperFilterMaskerData->filter)
458             set.add(m_clipperFilterMaskerData->filter);
459         if (m_clipperFilterMaskerData->masker)
460             set.add(m_clipperFilterMaskerData->masker);
461     }
462
463     if (m_markerData) {
464         if (m_markerData->markerStart)
465             set.add(m_markerData->markerStart);
466         if (m_markerData->markerMid)
467             set.add(m_markerData->markerMid);
468         if (m_markerData->markerEnd)
469             set.add(m_markerData->markerEnd);
470     }
471
472     if (m_fillStrokeData) {
473         if (m_fillStrokeData->fill)
474             set.add(m_fillStrokeData->fill);
475         if (m_fillStrokeData->stroke)
476             set.add(m_fillStrokeData->stroke);
477     }
478 }
479
480 bool SVGResources::setClipper(RenderSVGResourceClipper* clipper)
481 {
482     if (!clipper)
483         return false;
484
485     ASSERT(clipper->resourceType() == ClipperResourceType);
486
487     if (!m_clipperFilterMaskerData)
488         m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
489
490     m_clipperFilterMaskerData->clipper = clipper;
491     return true;
492 }
493
494 void SVGResources::resetClipper()
495 {
496     ASSERT(m_clipperFilterMaskerData);
497     ASSERT(m_clipperFilterMaskerData->clipper);
498     m_clipperFilterMaskerData->clipper = 0;
499 }
500
501 bool SVGResources::setFilter(RenderSVGResourceFilter* filter)
502 {
503     if (!filter)
504         return false;
505
506     ASSERT(filter->resourceType() == FilterResourceType);
507
508     if (!m_clipperFilterMaskerData)
509         m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
510
511     m_clipperFilterMaskerData->filter = filter;
512     return true;
513 }
514
515 void SVGResources::resetFilter()
516 {
517     ASSERT(m_clipperFilterMaskerData);
518     ASSERT(m_clipperFilterMaskerData->filter);
519     m_clipperFilterMaskerData->filter = 0;
520 }
521
522 bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart)
523 {
524     if (!markerStart)
525         return false;
526
527     ASSERT(markerStart->resourceType() == MarkerResourceType);
528
529     if (!m_markerData)
530         m_markerData = MarkerData::create();
531
532     m_markerData->markerStart = markerStart;
533     return true;
534 }
535
536 void SVGResources::resetMarkerStart()
537 {
538     ASSERT(m_markerData);
539     ASSERT(m_markerData->markerStart);
540     m_markerData->markerStart = 0;
541 }
542
543 bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid)
544 {
545     if (!markerMid)
546         return false;
547
548     ASSERT(markerMid->resourceType() == MarkerResourceType);
549
550     if (!m_markerData)
551         m_markerData = MarkerData::create();
552
553     m_markerData->markerMid = markerMid;
554     return true;
555 }
556
557 void SVGResources::resetMarkerMid()
558 {
559     ASSERT(m_markerData);
560     ASSERT(m_markerData->markerMid);
561     m_markerData->markerMid = 0;
562 }
563
564 bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd)
565 {
566     if (!markerEnd)
567         return false;
568
569     ASSERT(markerEnd->resourceType() == MarkerResourceType);
570
571     if (!m_markerData)
572         m_markerData = MarkerData::create();
573
574     m_markerData->markerEnd = markerEnd;
575     return true;
576 }
577
578 void SVGResources::resetMarkerEnd()
579 {
580     ASSERT(m_markerData);
581     ASSERT(m_markerData->markerEnd);
582     m_markerData->markerEnd = 0;
583 }
584
585 bool SVGResources::setMasker(RenderSVGResourceMasker* masker)
586 {
587     if (!masker)
588         return false;
589
590     ASSERT(masker->resourceType() == MaskerResourceType);
591
592     if (!m_clipperFilterMaskerData)
593         m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
594
595     m_clipperFilterMaskerData->masker = masker;
596     return true;
597 }
598
599 void SVGResources::resetMasker()
600 {
601     ASSERT(m_clipperFilterMaskerData);
602     ASSERT(m_clipperFilterMaskerData->masker);
603     m_clipperFilterMaskerData->masker = 0;
604 }
605
606 bool SVGResources::setFill(RenderSVGResourceContainer* fill)
607 {
608     if (!fill)
609         return false;
610
611     ASSERT(fill->resourceType() == PatternResourceType
612            || fill->resourceType() == LinearGradientResourceType
613            || fill->resourceType() == RadialGradientResourceType);
614
615     if (!m_fillStrokeData)
616         m_fillStrokeData = FillStrokeData::create();
617
618     m_fillStrokeData->fill = fill;
619     return true;
620 }
621
622 void SVGResources::resetFill()
623 {
624     ASSERT(m_fillStrokeData);
625     ASSERT(m_fillStrokeData->fill);
626     m_fillStrokeData->fill = 0;
627 }
628
629 bool SVGResources::setStroke(RenderSVGResourceContainer* stroke)
630 {
631     if (!stroke)
632         return false;
633
634     ASSERT(stroke->resourceType() == PatternResourceType
635            || stroke->resourceType() == LinearGradientResourceType
636            || stroke->resourceType() == RadialGradientResourceType);
637
638     if (!m_fillStrokeData)
639         m_fillStrokeData = FillStrokeData::create();
640
641     m_fillStrokeData->stroke = stroke;
642     return true;
643 }
644
645 void SVGResources::resetStroke()
646 {
647     ASSERT(m_fillStrokeData);
648     ASSERT(m_fillStrokeData->stroke);
649     m_fillStrokeData->stroke = 0;
650 }
651
652 bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource)
653 {
654     if (!linkedResource)
655         return false;
656
657     m_linkedResource = linkedResource;
658     return true;
659 }
660
661 void SVGResources::resetLinkedResource()
662 {
663     ASSERT(m_linkedResource);
664     m_linkedResource = 0;
665 }
666
667 #ifndef NDEBUG
668 void SVGResources::dump(const RenderObject* object)
669 {
670     ASSERT(object);
671     ASSERT(object->node());
672
673     fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node());
674     fprintf(stderr, " | DOM Tree:\n");
675     object->node()->showTreeForThis();
676
677     fprintf(stderr, "\n | List of resources:\n");
678     if (m_clipperFilterMaskerData) {
679         if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
680             fprintf(stderr, " |-> Clipper    : %p (node=%p)\n", clipper, clipper->element());
681         if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
682             fprintf(stderr, " |-> Filter     : %p (node=%p)\n", filter, filter->element());
683         if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
684             fprintf(stderr, " |-> Masker     : %p (node=%p)\n", masker, masker->element());
685     }
686
687     if (m_markerData) {
688         if (RenderSVGResourceMarker* markerStart = m_markerData->markerStart)
689             fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, markerStart->element());
690         if (RenderSVGResourceMarker* markerMid = m_markerData->markerMid)
691             fprintf(stderr, " |-> MarkerMid  : %p (node=%p)\n", markerMid, markerMid->element());
692         if (RenderSVGResourceMarker* markerEnd = m_markerData->markerEnd)
693             fprintf(stderr, " |-> MarkerEnd  : %p (node=%p)\n", markerEnd, markerEnd->element());
694     }
695
696     if (m_fillStrokeData) {
697         if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill)
698             fprintf(stderr, " |-> Fill       : %p (node=%p)\n", fill, fill->element());
699         if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke)
700             fprintf(stderr, " |-> Stroke     : %p (node=%p)\n", stroke, stroke->element());
701     }
702
703     if (m_linkedResource)
704         fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, m_linkedResource->element());
705 }
706 #endif
707
708 }