2 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
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.
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.
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.
21 #include "SVGResources.h"
23 #include "RenderSVGResourceClipper.h"
24 #include "RenderSVGResourceFilter.h"
25 #include "RenderSVGResourceMarker.h"
26 #include "RenderSVGResourceMasker.h"
27 #include "SVGGradientElement.h"
30 #include "SVGPatternElement.h"
31 #include "SVGRenderStyle.h"
32 #include "SVGURIReference.h"
40 SVGResources::SVGResources()
45 static HashSet<AtomicString>& clipperFilterMaskerTags()
47 DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
48 if (s_tagList.isEmpty()) {
49 // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
50 // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
51 s_tagList.add(SVGNames::aTag.localName());
52 s_tagList.add(SVGNames::circleTag.localName());
53 s_tagList.add(SVGNames::ellipseTag.localName());
54 s_tagList.add(SVGNames::glyphTag.localName());
55 s_tagList.add(SVGNames::gTag.localName());
56 s_tagList.add(SVGNames::imageTag.localName());
57 s_tagList.add(SVGNames::lineTag.localName());
58 s_tagList.add(SVGNames::markerTag.localName());
59 s_tagList.add(SVGNames::maskTag.localName());
60 s_tagList.add(SVGNames::missing_glyphTag.localName());
61 s_tagList.add(SVGNames::pathTag.localName());
62 s_tagList.add(SVGNames::polygonTag.localName());
63 s_tagList.add(SVGNames::polylineTag.localName());
64 s_tagList.add(SVGNames::rectTag.localName());
65 s_tagList.add(SVGNames::svgTag.localName());
66 s_tagList.add(SVGNames::textTag.localName());
67 s_tagList.add(SVGNames::useTag.localName());
69 // Not listed in the definitions is the clipPath element, the SVG spec says though:
70 // The "clipPath" element or any of its children can specify property "clip-path".
71 // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail.
72 // (Already mailed SVG WG, waiting for a solution)
73 s_tagList.add(SVGNames::clipPathTag.localName());
75 // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed.
76 // (Already mailed SVG WG, waiting for a solution)
77 s_tagList.add(SVGNames::altGlyphTag.localName());
78 s_tagList.add(SVGNames::textPathTag.localName());
79 s_tagList.add(SVGNames::trefTag.localName());
80 s_tagList.add(SVGNames::tspanTag.localName());
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());
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.)
94 static HashSet<AtomicString>& markerTags()
96 DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
97 if (s_tagList.isEmpty()) {
98 s_tagList.add(SVGNames::lineTag.localName());
99 s_tagList.add(SVGNames::pathTag.localName());
100 s_tagList.add(SVGNames::polygonTag.localName());
101 s_tagList.add(SVGNames::polylineTag.localName());
107 static HashSet<AtomicString>& fillAndStrokeTags()
109 DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
110 if (s_tagList.isEmpty()) {
111 s_tagList.add(SVGNames::altGlyphTag.localName());
112 s_tagList.add(SVGNames::circleTag.localName());
113 s_tagList.add(SVGNames::ellipseTag.localName());
114 s_tagList.add(SVGNames::lineTag.localName());
115 s_tagList.add(SVGNames::pathTag.localName());
116 s_tagList.add(SVGNames::polygonTag.localName());
117 s_tagList.add(SVGNames::polylineTag.localName());
118 s_tagList.add(SVGNames::rectTag.localName());
119 s_tagList.add(SVGNames::textTag.localName());
120 s_tagList.add(SVGNames::textPathTag.localName());
121 s_tagList.add(SVGNames::trefTag.localName());
122 s_tagList.add(SVGNames::tspanTag.localName());
128 static HashSet<AtomicString>& chainableResourceTags()
130 DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
131 if (s_tagList.isEmpty()) {
132 s_tagList.add(SVGNames::linearGradientTag.localName());
133 s_tagList.add(SVGNames::filterTag.localName());
134 s_tagList.add(SVGNames::patternTag.localName());
135 s_tagList.add(SVGNames::radialGradientTag.localName());
141 static inline String targetReferenceFromResource(SVGElement& element)
144 if (isSVGPatternElement(element))
145 target = downcast<SVGPatternElement>(element).href();
146 else if (isSVGGradientElement(element))
147 target = toSVGGradientElement(element).href();
148 else if (isSVGFilterElement(element))
149 target = downcast<SVGFilterElement>(element).href();
151 ASSERT_NOT_REACHED();
153 return SVGURIReference::fragmentIdentifierFromIRIString(target, element.document());
156 static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& document, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource)
158 if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)
161 id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, document);
162 RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id);
164 hasPendingResource = true;
168 RenderSVGResourceType resourceType = container->resourceType();
169 if (resourceType != PatternResourceType && resourceType != LinearGradientResourceType && resourceType != RadialGradientResourceType)
175 static inline void registerPendingResource(SVGDocumentExtensions& extensions, const AtomicString& id, SVGElement& element)
177 extensions.addPendingResource(id, &element);
180 bool SVGResources::buildCachedResources(const RenderElement& renderer, const SVGRenderStyle& svgStyle)
182 ASSERT(renderer.element());
183 ASSERT_WITH_SECURITY_IMPLICATION(renderer.element()->isSVGElement());
185 if (!renderer.element())
188 auto& element = downcast<SVGElement>(*renderer.element());
190 Document& document = element.document();
192 SVGDocumentExtensions& extensions = document.accessSVGExtensions();
194 const AtomicString& tagName = element.localName();
195 if (tagName.isNull())
198 bool foundResources = false;
199 if (clipperFilterMaskerTags().contains(tagName)) {
200 if (svgStyle.hasClipper()) {
201 AtomicString id(svgStyle.clipperResource());
202 if (setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id)))
203 foundResources = true;
205 registerPendingResource(extensions, id, element);
208 if (svgStyle.hasFilter()) {
209 AtomicString id(svgStyle.filterResource());
210 if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id)))
211 foundResources = true;
213 registerPendingResource(extensions, id, element);
216 if (svgStyle.hasMasker()) {
217 AtomicString id(svgStyle.maskerResource());
218 if (setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id)))
219 foundResources = true;
221 registerPendingResource(extensions, id, element);
225 if (markerTags().contains(tagName) && svgStyle.hasMarkers()) {
226 AtomicString markerStartId(svgStyle.markerStartResource());
227 if (setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId)))
228 foundResources = true;
230 registerPendingResource(extensions, markerStartId, element);
232 AtomicString markerMidId(svgStyle.markerMidResource());
233 if (setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId)))
234 foundResources = true;
236 registerPendingResource(extensions, markerMidId, element);
238 AtomicString markerEndId(svgStyle.markerEndResource());
239 if (setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId)))
240 foundResources = true;
242 registerPendingResource(extensions, markerEndId, element);
245 if (fillAndStrokeTags().contains(tagName)) {
246 if (svgStyle.hasFill()) {
247 bool hasPendingResource = false;
249 if (setFill(paintingResourceFromSVGPaint(document, svgStyle.fillPaintType(), svgStyle.fillPaintUri(), id, hasPendingResource)))
250 foundResources = true;
251 else if (hasPendingResource)
252 registerPendingResource(extensions, id, element);
255 if (svgStyle.hasStroke()) {
256 bool hasPendingResource = false;
258 if (setStroke(paintingResourceFromSVGPaint(document, svgStyle.strokePaintType(), svgStyle.strokePaintUri(), id, hasPendingResource)))
259 foundResources = true;
260 else if (hasPendingResource)
261 registerPendingResource(extensions, id, element);
265 if (chainableResourceTags().contains(tagName)) {
266 AtomicString id(targetReferenceFromResource(element));
267 if (setLinkedResource(getRenderSVGResourceContainerById(document, id)))
268 foundResources = true;
270 registerPendingResource(extensions, id, element);
273 return foundResources;
276 void SVGResources::removeClientFromCache(RenderElement& renderer, bool markForInvalidation) const
278 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
281 if (m_linkedResource) {
282 ASSERT(!m_clipperFilterMaskerData);
283 ASSERT(!m_markerData);
284 ASSERT(!m_fillStrokeData);
285 m_linkedResource->removeClientFromCache(renderer, markForInvalidation);
289 if (m_clipperFilterMaskerData) {
290 if (m_clipperFilterMaskerData->clipper)
291 m_clipperFilterMaskerData->clipper->removeClientFromCache(renderer, markForInvalidation);
292 if (m_clipperFilterMaskerData->filter)
293 m_clipperFilterMaskerData->filter->removeClientFromCache(renderer, markForInvalidation);
294 if (m_clipperFilterMaskerData->masker)
295 m_clipperFilterMaskerData->masker->removeClientFromCache(renderer, markForInvalidation);
299 if (m_markerData->markerStart)
300 m_markerData->markerStart->removeClientFromCache(renderer, markForInvalidation);
301 if (m_markerData->markerMid)
302 m_markerData->markerMid->removeClientFromCache(renderer, markForInvalidation);
303 if (m_markerData->markerEnd)
304 m_markerData->markerEnd->removeClientFromCache(renderer, markForInvalidation);
307 if (m_fillStrokeData) {
308 if (m_fillStrokeData->fill)
309 m_fillStrokeData->fill->removeClientFromCache(renderer, markForInvalidation);
310 if (m_fillStrokeData->stroke)
311 m_fillStrokeData->stroke->removeClientFromCache(renderer, markForInvalidation);
315 void SVGResources::resourceDestroyed(RenderSVGResourceContainer& resource)
317 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
320 if (m_linkedResource == &resource) {
321 ASSERT(!m_clipperFilterMaskerData);
322 ASSERT(!m_markerData);
323 ASSERT(!m_fillStrokeData);
324 m_linkedResource->removeAllClientsFromCache();
325 m_linkedResource = 0;
329 switch (resource.resourceType()) {
330 case MaskerResourceType:
331 if (!m_clipperFilterMaskerData)
333 if (m_clipperFilterMaskerData->masker == &resource) {
334 m_clipperFilterMaskerData->masker->removeAllClientsFromCache();
335 m_clipperFilterMaskerData->masker = 0;
338 case MarkerResourceType:
341 if (m_markerData->markerStart == &resource) {
342 m_markerData->markerStart->removeAllClientsFromCache();
343 m_markerData->markerStart = 0;
345 if (m_markerData->markerMid == &resource) {
346 m_markerData->markerMid->removeAllClientsFromCache();
347 m_markerData->markerMid = 0;
349 if (m_markerData->markerEnd == &resource) {
350 m_markerData->markerEnd->removeAllClientsFromCache();
351 m_markerData->markerEnd = 0;
354 case PatternResourceType:
355 case LinearGradientResourceType:
356 case RadialGradientResourceType:
357 if (!m_fillStrokeData)
359 if (m_fillStrokeData->fill == &resource) {
360 m_fillStrokeData->fill->removeAllClientsFromCache();
361 m_fillStrokeData->fill = 0;
363 if (m_fillStrokeData->stroke == &resource) {
364 m_fillStrokeData->stroke->removeAllClientsFromCache();
365 m_fillStrokeData->stroke = 0;
368 case FilterResourceType:
369 if (!m_clipperFilterMaskerData)
371 if (m_clipperFilterMaskerData->filter == &resource) {
372 m_clipperFilterMaskerData->filter->removeAllClientsFromCache();
373 m_clipperFilterMaskerData->filter = 0;
376 case ClipperResourceType:
377 if (!m_clipperFilterMaskerData)
379 if (m_clipperFilterMaskerData->clipper == &resource) {
380 m_clipperFilterMaskerData->clipper->removeAllClientsFromCache();
381 m_clipperFilterMaskerData->clipper = 0;
384 case SolidColorResourceType:
385 ASSERT_NOT_REACHED();
389 void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set)
391 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
394 if (m_linkedResource) {
395 ASSERT(!m_clipperFilterMaskerData);
396 ASSERT(!m_markerData);
397 ASSERT(!m_fillStrokeData);
398 set.add(m_linkedResource);
402 if (m_clipperFilterMaskerData) {
403 if (m_clipperFilterMaskerData->clipper)
404 set.add(m_clipperFilterMaskerData->clipper);
405 if (m_clipperFilterMaskerData->filter)
406 set.add(m_clipperFilterMaskerData->filter);
407 if (m_clipperFilterMaskerData->masker)
408 set.add(m_clipperFilterMaskerData->masker);
412 if (m_markerData->markerStart)
413 set.add(m_markerData->markerStart);
414 if (m_markerData->markerMid)
415 set.add(m_markerData->markerMid);
416 if (m_markerData->markerEnd)
417 set.add(m_markerData->markerEnd);
420 if (m_fillStrokeData) {
421 if (m_fillStrokeData->fill)
422 set.add(m_fillStrokeData->fill);
423 if (m_fillStrokeData->stroke)
424 set.add(m_fillStrokeData->stroke);
428 bool SVGResources::setClipper(RenderSVGResourceClipper* clipper)
433 ASSERT(clipper->resourceType() == ClipperResourceType);
435 if (!m_clipperFilterMaskerData)
436 m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>();
438 m_clipperFilterMaskerData->clipper = clipper;
442 void SVGResources::resetClipper()
444 ASSERT(m_clipperFilterMaskerData);
445 ASSERT(m_clipperFilterMaskerData->clipper);
446 m_clipperFilterMaskerData->clipper = 0;
449 bool SVGResources::setFilter(RenderSVGResourceFilter* filter)
454 ASSERT(filter->resourceType() == FilterResourceType);
456 if (!m_clipperFilterMaskerData)
457 m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>();
459 m_clipperFilterMaskerData->filter = filter;
463 void SVGResources::resetFilter()
465 ASSERT(m_clipperFilterMaskerData);
466 ASSERT(m_clipperFilterMaskerData->filter);
467 m_clipperFilterMaskerData->filter = 0;
470 bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart)
475 ASSERT(markerStart->resourceType() == MarkerResourceType);
478 m_markerData = std::make_unique<MarkerData>();
480 m_markerData->markerStart = markerStart;
484 void SVGResources::resetMarkerStart()
486 ASSERT(m_markerData);
487 ASSERT(m_markerData->markerStart);
488 m_markerData->markerStart = 0;
491 bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid)
496 ASSERT(markerMid->resourceType() == MarkerResourceType);
499 m_markerData = std::make_unique<MarkerData>();
501 m_markerData->markerMid = markerMid;
505 void SVGResources::resetMarkerMid()
507 ASSERT(m_markerData);
508 ASSERT(m_markerData->markerMid);
509 m_markerData->markerMid = 0;
512 bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd)
517 ASSERT(markerEnd->resourceType() == MarkerResourceType);
520 m_markerData = std::make_unique<MarkerData>();
522 m_markerData->markerEnd = markerEnd;
526 void SVGResources::resetMarkerEnd()
528 ASSERT(m_markerData);
529 ASSERT(m_markerData->markerEnd);
530 m_markerData->markerEnd = 0;
533 bool SVGResources::setMasker(RenderSVGResourceMasker* masker)
538 ASSERT(masker->resourceType() == MaskerResourceType);
540 if (!m_clipperFilterMaskerData)
541 m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>();
543 m_clipperFilterMaskerData->masker = masker;
547 void SVGResources::resetMasker()
549 ASSERT(m_clipperFilterMaskerData);
550 ASSERT(m_clipperFilterMaskerData->masker);
551 m_clipperFilterMaskerData->masker = 0;
554 bool SVGResources::setFill(RenderSVGResourceContainer* fill)
559 ASSERT(fill->resourceType() == PatternResourceType
560 || fill->resourceType() == LinearGradientResourceType
561 || fill->resourceType() == RadialGradientResourceType);
563 if (!m_fillStrokeData)
564 m_fillStrokeData = std::make_unique<FillStrokeData>();
566 m_fillStrokeData->fill = fill;
570 void SVGResources::resetFill()
572 ASSERT(m_fillStrokeData);
573 ASSERT(m_fillStrokeData->fill);
574 m_fillStrokeData->fill = 0;
577 bool SVGResources::setStroke(RenderSVGResourceContainer* stroke)
582 ASSERT(stroke->resourceType() == PatternResourceType
583 || stroke->resourceType() == LinearGradientResourceType
584 || stroke->resourceType() == RadialGradientResourceType);
586 if (!m_fillStrokeData)
587 m_fillStrokeData = std::make_unique<FillStrokeData>();
589 m_fillStrokeData->stroke = stroke;
593 void SVGResources::resetStroke()
595 ASSERT(m_fillStrokeData);
596 ASSERT(m_fillStrokeData->stroke);
597 m_fillStrokeData->stroke = 0;
600 bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource)
605 m_linkedResource = linkedResource;
609 void SVGResources::resetLinkedResource()
611 ASSERT(m_linkedResource);
612 m_linkedResource = 0;
616 void SVGResources::dump(const RenderObject* object)
619 ASSERT(object->node());
621 fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node());
622 fprintf(stderr, " | DOM Tree:\n");
623 object->node()->showTreeForThis();
625 fprintf(stderr, "\n | List of resources:\n");
626 if (m_clipperFilterMaskerData) {
627 if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
628 fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper, &clipper->clipPathElement());
629 if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
630 fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter, &filter->filterElement());
631 if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
632 fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker, &masker->maskElement());
636 if (RenderSVGResourceMarker* markerStart = m_markerData->markerStart)
637 fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, &markerStart->markerElement());
638 if (RenderSVGResourceMarker* markerMid = m_markerData->markerMid)
639 fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", markerMid, &markerMid->markerElement());
640 if (RenderSVGResourceMarker* markerEnd = m_markerData->markerEnd)
641 fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", markerEnd, &markerEnd->markerElement());
644 if (m_fillStrokeData) {
645 if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill)
646 fprintf(stderr, " |-> Fill : %p (node=%p)\n", fill, &fill->element());
647 if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke)
648 fprintf(stderr, " |-> Stroke : %p (node=%p)\n", stroke, &stroke->element());
651 if (m_linkedResource)
652 fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, &m_linkedResource->element());