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
40namespace WebCore {
41
42SVGResources::SVGResources()
43{
44}
45
46static HashSet<AtomicString>& clipperFilterMaskerTags()
47{
48 static NeverDestroyed<HashSet<AtomicString>> 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
95static HashSet<AtomicString>& markerTags()
96{
97 static NeverDestroyed<HashSet<AtomicString>> 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
108static HashSet<AtomicString>& fillAndStrokeTags()
109{
110 static NeverDestroyed<HashSet<AtomicString>> 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
129static HashSet<AtomicString>& chainableResourceTags()
130{
131 static NeverDestroyed<HashSet<AtomicString>> 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
142static 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
157static 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
172static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& document, const SVGPaintType& paintType, const String& paintUri, AtomicString& 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
191static inline void registerPendingResource(SVGDocumentExtensions& extensions, const AtomicString& id, SVGElement& element)
192{
193 extensions.addPendingResource(id, element);
194}
195
196bool 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 AtomicString& 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 AtomicString 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 AtomicString 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 AtomicString 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 AtomicString 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 AtomicString markerStartId(svgStyle.markerStartResource());
261 if (setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId)))
262 foundResources = true;
263 else
264 registerPendingResource(extensions, markerStartId, element);
265
266 AtomicString markerMidId(svgStyle.markerMidResource());
267 if (setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId)))
268 foundResources = true;
269 else
270 registerPendingResource(extensions, markerMidId, element);
271
272 AtomicString 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 AtomicString 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 AtomicString 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 AtomicString 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
313void 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
334bool SVGResources::markerReverseStart() const
335{
336 return m_markerData
337 && m_markerData->markerStart
338 && m_markerData->markerStart->markerElement().orientType() == SVGMarkerOrientAutoStartReverse;
339}
340
341void 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
380bool 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
464void 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
503bool 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 = std::make_unique<ClipperFilterMaskerData>();
512
513 m_clipperFilterMaskerData->clipper = clipper;
514 return true;
515}
516
517void SVGResources::resetClipper()
518{
519 ASSERT(m_clipperFilterMaskerData);
520 ASSERT(m_clipperFilterMaskerData->clipper);
521 m_clipperFilterMaskerData->clipper = nullptr;
522}
523
524bool 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 = std::make_unique<ClipperFilterMaskerData>();
533
534 m_clipperFilterMaskerData->filter = filter;
535 return true;
536}
537
538void SVGResources::resetFilter()
539{
540 ASSERT(m_clipperFilterMaskerData);
541 ASSERT(m_clipperFilterMaskerData->filter);
542 m_clipperFilterMaskerData->filter = nullptr;
543}
544
545bool 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 = std::make_unique<MarkerData>();
554
555 m_markerData->markerStart = markerStart;
556 return true;
557}
558
559void SVGResources::resetMarkerStart()
560{
561 ASSERT(m_markerData);
562 ASSERT(m_markerData->markerStart);
563 m_markerData->markerStart = nullptr;
564}
565
566bool 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 = std::make_unique<MarkerData>();
575
576 m_markerData->markerMid = markerMid;
577 return true;
578}
579
580void SVGResources::resetMarkerMid()
581{
582 ASSERT(m_markerData);
583 ASSERT(m_markerData->markerMid);
584 m_markerData->markerMid = nullptr;
585}
586
587bool 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 = std::make_unique<MarkerData>();
596
597 m_markerData->markerEnd = markerEnd;
598 return true;
599}
600
601void SVGResources::resetMarkerEnd()
602{
603 ASSERT(m_markerData);
604 ASSERT(m_markerData->markerEnd);
605 m_markerData->markerEnd = nullptr;
606}
607
608bool 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 = std::make_unique<ClipperFilterMaskerData>();
617
618 m_clipperFilterMaskerData->masker = masker;
619 return true;
620}
621
622void SVGResources::resetMasker()
623{
624 ASSERT(m_clipperFilterMaskerData);
625 ASSERT(m_clipperFilterMaskerData->masker);
626 m_clipperFilterMaskerData->masker = nullptr;
627}
628
629bool 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 = std::make_unique<FillStrokeData>();
640
641 m_fillStrokeData->fill = fill;
642 return true;
643}
644
645void SVGResources::resetFill()
646{
647 ASSERT(m_fillStrokeData);
648 ASSERT(m_fillStrokeData->fill);
649 m_fillStrokeData->fill = nullptr;
650}
651
652bool 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 = std::make_unique<FillStrokeData>();
663
664 m_fillStrokeData->stroke = stroke;
665 return true;
666}
667
668void SVGResources::resetStroke()
669{
670 ASSERT(m_fillStrokeData);
671 ASSERT(m_fillStrokeData->stroke);
672 m_fillStrokeData->stroke = nullptr;
673}
674
675bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource)
676{
677 if (!linkedResource)
678 return false;
679
680 m_linkedResource = linkedResource;
681 return true;
682}
683
684void SVGResources::resetLinkedResource()
685{
686 ASSERT(m_linkedResource);
687 m_linkedResource = nullptr;
688}
689
690#if ENABLE(TREE_DEBUGGING)
691void 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}
732