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