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"
24 #include "RenderSVGResourceClipper.h"
25 #include "RenderSVGResourceFilter.h"
26 #include "RenderSVGResourceMarker.h"
27 #include "RenderSVGResourceMasker.h"
28 #include "SVGFilterElement.h"
29 #include "SVGGradientElement.h"
32 #include "SVGPatternElement.h"
33 #include "SVGRenderStyle.h"
34 #include "SVGURIReference.h"
42 SVGResources::SVGResources()
47 static HashSet<AtomicStringImpl*>& clipperFilterMaskerTags()
49 DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
50 if (s_tagList.isEmpty()) {
51 // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
52 // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
53 s_tagList.add(SVGNames::aTag.localName().impl());
54 s_tagList.add(SVGNames::circleTag.localName().impl());
55 s_tagList.add(SVGNames::ellipseTag.localName().impl());
56 s_tagList.add(SVGNames::glyphTag.localName().impl());
57 s_tagList.add(SVGNames::gTag.localName().impl());
58 s_tagList.add(SVGNames::imageTag.localName().impl());
59 s_tagList.add(SVGNames::lineTag.localName().impl());
60 s_tagList.add(SVGNames::markerTag.localName().impl());
61 s_tagList.add(SVGNames::maskTag.localName().impl());
62 s_tagList.add(SVGNames::missing_glyphTag.localName().impl());
63 s_tagList.add(SVGNames::pathTag.localName().impl());
64 s_tagList.add(SVGNames::polygonTag.localName().impl());
65 s_tagList.add(SVGNames::polylineTag.localName().impl());
66 s_tagList.add(SVGNames::rectTag.localName().impl());
67 s_tagList.add(SVGNames::svgTag.localName().impl());
68 s_tagList.add(SVGNames::textTag.localName().impl());
69 s_tagList.add(SVGNames::useTag.localName().impl());
71 // Not listed in the definitions is the clipPath element, the SVG spec says though:
72 // The "clipPath" element or any of its children can specify property "clip-path".
73 // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail.
74 // (Already mailed SVG WG, waiting for a solution)
75 s_tagList.add(SVGNames::clipPathTag.localName().impl());
77 // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed.
78 // (Already mailed SVG WG, waiting for a solution)
79 s_tagList.add(SVGNames::altGlyphTag.localName().impl());
80 s_tagList.add(SVGNames::textPathTag.localName().impl());
81 s_tagList.add(SVGNames::trefTag.localName().impl());
82 s_tagList.add(SVGNames::tspanTag.localName().impl());
84 // Elements that we ignore, as it doesn't make any sense.
85 // defs, pattern, switch (FIXME: Mail SVG WG about these)
86 // symbol (is converted to a svg element, when referenced by use, we can safely ignore it.)
92 static HashSet<AtomicStringImpl*>& markerTags()
94 DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
95 if (s_tagList.isEmpty()) {
96 s_tagList.add(SVGNames::lineTag.localName().impl());
97 s_tagList.add(SVGNames::pathTag.localName().impl());
98 s_tagList.add(SVGNames::polygonTag.localName().impl());
99 s_tagList.add(SVGNames::polylineTag.localName().impl());
105 static HashSet<AtomicStringImpl*>& fillAndStrokeTags()
107 DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
108 if (s_tagList.isEmpty()) {
109 s_tagList.add(SVGNames::altGlyphTag.localName().impl());
110 s_tagList.add(SVGNames::circleTag.localName().impl());
111 s_tagList.add(SVGNames::ellipseTag.localName().impl());
112 s_tagList.add(SVGNames::lineTag.localName().impl());
113 s_tagList.add(SVGNames::pathTag.localName().impl());
114 s_tagList.add(SVGNames::polygonTag.localName().impl());
115 s_tagList.add(SVGNames::polylineTag.localName().impl());
116 s_tagList.add(SVGNames::rectTag.localName().impl());
117 s_tagList.add(SVGNames::textTag.localName().impl());
118 s_tagList.add(SVGNames::textPathTag.localName().impl());
119 s_tagList.add(SVGNames::trefTag.localName().impl());
120 s_tagList.add(SVGNames::tspanTag.localName().impl());
126 static HashSet<AtomicStringImpl*>& chainableResourceTags()
128 DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
129 if (s_tagList.isEmpty()) {
130 s_tagList.add(SVGNames::linearGradientTag.localName().impl());
131 s_tagList.add(SVGNames::filterTag.localName().impl());
132 s_tagList.add(SVGNames::patternTag.localName().impl());
133 s_tagList.add(SVGNames::radialGradientTag.localName().impl());
139 static inline String targetReferenceFromResource(SVGElement* element)
142 if (element->hasTagName(SVGNames::patternTag))
143 target = static_cast<SVGPatternElement*>(element)->href();
144 else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag))
145 target = static_cast<SVGGradientElement*>(element)->href();
147 else if (element->hasTagName(SVGNames::filterTag))
148 target = static_cast<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)
178 ASSERT(element->isStyled());
179 extensions->addPendingResource(id, static_cast<SVGStyledElement*>(element));
182 bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRenderStyle* style)
187 Node* node = object->node();
189 ASSERT(node->isSVGElement());
191 SVGElement* element = static_cast<SVGElement*>(node);
195 Document* document = object->document();
198 SVGDocumentExtensions* extensions = document->accessSVGExtensions();
201 AtomicStringImpl* tagNameImpl = element->tagQName().localName().impl();
205 bool foundResources = false;
206 if (clipperFilterMaskerTags().contains(tagNameImpl)) {
207 if (style->hasClipper()) {
208 AtomicString id(style->clipperResource());
209 if (setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id)))
210 foundResources = true;
212 registerPendingResource(extensions, id, element);
216 if (style->hasFilter()) {
217 AtomicString id(style->filterResource());
218 if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id)))
219 foundResources = true;
221 registerPendingResource(extensions, id, element);
225 if (style->hasMasker()) {
226 AtomicString id(style->maskerResource());
227 if (setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id)))
228 foundResources = true;
230 registerPendingResource(extensions, id, element);
234 if (markerTags().contains(tagNameImpl) && style->hasMarkers()) {
235 AtomicString markerStartId(style->markerStartResource());
236 if (setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId)))
237 foundResources = true;
239 registerPendingResource(extensions, markerStartId, element);
241 AtomicString markerMidId(style->markerMidResource());
242 if (setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId)))
243 foundResources = true;
245 registerPendingResource(extensions, markerMidId, element);
247 AtomicString markerEndId(style->markerEndResource());
248 if (setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId)))
249 foundResources = true;
251 registerPendingResource(extensions, markerEndId, element);
254 if (fillAndStrokeTags().contains(tagNameImpl)) {
255 if (style->hasFill()) {
256 bool hasPendingResource = false;
258 if (setFill(paintingResourceFromSVGPaint(document, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource)))
259 foundResources = true;
260 else if (hasPendingResource)
261 registerPendingResource(extensions, id, element);
264 if (style->hasStroke()) {
265 bool hasPendingResource = false;
267 if (setStroke(paintingResourceFromSVGPaint(document, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource)))
268 foundResources = true;
269 else if (hasPendingResource)
270 registerPendingResource(extensions, id, element);
274 if (chainableResourceTags().contains(tagNameImpl)) {
275 AtomicString id(targetReferenceFromResource(element));
276 if (setLinkedResource(getRenderSVGResourceContainerById(document, id)))
277 foundResources = true;
279 registerPendingResource(extensions, id, element);
282 return foundResources;
285 void SVGResources::removeClientFromCache(RenderObject* object, bool markForInvalidation) const
287 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
290 if (m_linkedResource) {
291 ASSERT(!m_clipperFilterMaskerData);
292 ASSERT(!m_markerData);
293 ASSERT(!m_fillStrokeData);
294 m_linkedResource->removeClientFromCache(object, markForInvalidation);
298 if (m_clipperFilterMaskerData) {
299 if (m_clipperFilterMaskerData->clipper)
300 m_clipperFilterMaskerData->clipper->removeClientFromCache(object, markForInvalidation);
302 if (m_clipperFilterMaskerData->filter)
303 m_clipperFilterMaskerData->filter->removeClientFromCache(object, markForInvalidation);
305 if (m_clipperFilterMaskerData->masker)
306 m_clipperFilterMaskerData->masker->removeClientFromCache(object, markForInvalidation);
310 if (m_markerData->markerStart)
311 m_markerData->markerStart->removeClientFromCache(object, markForInvalidation);
312 if (m_markerData->markerMid)
313 m_markerData->markerMid->removeClientFromCache(object, markForInvalidation);
314 if (m_markerData->markerEnd)
315 m_markerData->markerEnd->removeClientFromCache(object, markForInvalidation);
318 if (m_fillStrokeData) {
319 if (m_fillStrokeData->fill)
320 m_fillStrokeData->fill->removeClientFromCache(object, markForInvalidation);
321 if (m_fillStrokeData->stroke)
322 m_fillStrokeData->stroke->removeClientFromCache(object, markForInvalidation);
326 void SVGResources::resourceDestroyed(RenderSVGResourceContainer* resource)
329 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
332 if (m_linkedResource == resource) {
333 ASSERT(!m_clipperFilterMaskerData);
334 ASSERT(!m_markerData);
335 ASSERT(!m_fillStrokeData);
336 m_linkedResource->removeAllClientsFromCache();
337 m_linkedResource = 0;
341 switch (resource->resourceType()) {
342 case MaskerResourceType:
343 if (!m_clipperFilterMaskerData)
345 if (m_clipperFilterMaskerData->masker == resource) {
346 m_clipperFilterMaskerData->masker->removeAllClientsFromCache();
347 m_clipperFilterMaskerData->masker = 0;
350 case MarkerResourceType:
353 if (m_markerData->markerStart == resource) {
354 m_markerData->markerStart->removeAllClientsFromCache();
355 m_markerData->markerStart = 0;
357 if (m_markerData->markerMid == resource) {
358 m_markerData->markerMid->removeAllClientsFromCache();
359 m_markerData->markerMid = 0;
361 if (m_markerData->markerEnd == resource) {
362 m_markerData->markerEnd->removeAllClientsFromCache();
363 m_markerData->markerEnd = 0;
366 case PatternResourceType:
367 case LinearGradientResourceType:
368 case RadialGradientResourceType:
369 if (!m_fillStrokeData)
371 if (m_fillStrokeData->fill == resource) {
372 m_fillStrokeData->fill->removeAllClientsFromCache();
373 m_fillStrokeData->fill = 0;
375 if (m_fillStrokeData->stroke == resource) {
376 m_fillStrokeData->stroke->removeAllClientsFromCache();
377 m_fillStrokeData->stroke = 0;
380 case FilterResourceType:
382 if (!m_clipperFilterMaskerData)
384 if (m_clipperFilterMaskerData->filter == resource) {
385 m_clipperFilterMaskerData->filter->removeAllClientsFromCache();
386 m_clipperFilterMaskerData->filter = 0;
389 ASSERT_NOT_REACHED();
392 case ClipperResourceType:
393 if (!m_clipperFilterMaskerData)
395 if (m_clipperFilterMaskerData->clipper == resource) {
396 m_clipperFilterMaskerData->clipper->removeAllClientsFromCache();
397 m_clipperFilterMaskerData->clipper = 0;
400 case SolidColorResourceType:
401 ASSERT_NOT_REACHED();
405 void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set)
407 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
410 if (m_linkedResource) {
411 ASSERT(!m_clipperFilterMaskerData);
412 ASSERT(!m_markerData);
413 ASSERT(!m_fillStrokeData);
414 set.add(m_linkedResource);
418 if (m_clipperFilterMaskerData) {
419 if (m_clipperFilterMaskerData->clipper)
420 set.add(m_clipperFilterMaskerData->clipper);
422 if (m_clipperFilterMaskerData->filter)
423 set.add(m_clipperFilterMaskerData->filter);
425 if (m_clipperFilterMaskerData->masker)
426 set.add(m_clipperFilterMaskerData->masker);
430 if (m_markerData->markerStart)
431 set.add(m_markerData->markerStart);
432 if (m_markerData->markerMid)
433 set.add(m_markerData->markerMid);
434 if (m_markerData->markerEnd)
435 set.add(m_markerData->markerEnd);
438 if (m_fillStrokeData) {
439 if (m_fillStrokeData->fill)
440 set.add(m_fillStrokeData->fill);
441 if (m_fillStrokeData->stroke)
442 set.add(m_fillStrokeData->stroke);
446 bool SVGResources::setClipper(RenderSVGResourceClipper* clipper)
451 ASSERT(clipper->resourceType() == ClipperResourceType);
453 if (!m_clipperFilterMaskerData)
454 m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
456 m_clipperFilterMaskerData->clipper = clipper;
460 void SVGResources::resetClipper()
462 ASSERT(m_clipperFilterMaskerData);
463 ASSERT(m_clipperFilterMaskerData->clipper);
464 m_clipperFilterMaskerData->clipper = 0;
468 bool SVGResources::setFilter(RenderSVGResourceFilter* filter)
473 ASSERT(filter->resourceType() == FilterResourceType);
475 if (!m_clipperFilterMaskerData)
476 m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
478 m_clipperFilterMaskerData->filter = filter;
482 void SVGResources::resetFilter()
484 ASSERT(m_clipperFilterMaskerData);
485 ASSERT(m_clipperFilterMaskerData->filter);
486 m_clipperFilterMaskerData->filter = 0;
490 bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart)
495 ASSERT(markerStart->resourceType() == MarkerResourceType);
498 m_markerData = MarkerData::create();
500 m_markerData->markerStart = markerStart;
504 void SVGResources::resetMarkerStart()
506 ASSERT(m_markerData);
507 ASSERT(m_markerData->markerStart);
508 m_markerData->markerStart = 0;
511 bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid)
516 ASSERT(markerMid->resourceType() == MarkerResourceType);
519 m_markerData = MarkerData::create();
521 m_markerData->markerMid = markerMid;
525 void SVGResources::resetMarkerMid()
527 ASSERT(m_markerData);
528 ASSERT(m_markerData->markerMid);
529 m_markerData->markerMid = 0;
532 bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd)
537 ASSERT(markerEnd->resourceType() == MarkerResourceType);
540 m_markerData = MarkerData::create();
542 m_markerData->markerEnd = markerEnd;
546 void SVGResources::resetMarkerEnd()
548 ASSERT(m_markerData);
549 ASSERT(m_markerData->markerEnd);
550 m_markerData->markerEnd = 0;
553 bool SVGResources::setMasker(RenderSVGResourceMasker* masker)
558 ASSERT(masker->resourceType() == MaskerResourceType);
560 if (!m_clipperFilterMaskerData)
561 m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
563 m_clipperFilterMaskerData->masker = masker;
567 void SVGResources::resetMasker()
569 ASSERT(m_clipperFilterMaskerData);
570 ASSERT(m_clipperFilterMaskerData->masker);
571 m_clipperFilterMaskerData->masker = 0;
574 bool SVGResources::setFill(RenderSVGResourceContainer* fill)
579 ASSERT(fill->resourceType() == PatternResourceType
580 || fill->resourceType() == LinearGradientResourceType
581 || fill->resourceType() == RadialGradientResourceType);
583 if (!m_fillStrokeData)
584 m_fillStrokeData = FillStrokeData::create();
586 m_fillStrokeData->fill = fill;
590 void SVGResources::resetFill()
592 ASSERT(m_fillStrokeData);
593 ASSERT(m_fillStrokeData->fill);
594 m_fillStrokeData->fill = 0;
597 bool SVGResources::setStroke(RenderSVGResourceContainer* stroke)
602 ASSERT(stroke->resourceType() == PatternResourceType
603 || stroke->resourceType() == LinearGradientResourceType
604 || stroke->resourceType() == RadialGradientResourceType);
606 if (!m_fillStrokeData)
607 m_fillStrokeData = FillStrokeData::create();
609 m_fillStrokeData->stroke = stroke;
613 void SVGResources::resetStroke()
615 ASSERT(m_fillStrokeData);
616 ASSERT(m_fillStrokeData->stroke);
617 m_fillStrokeData->stroke = 0;
620 bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource)
625 m_linkedResource = linkedResource;
629 void SVGResources::resetLinkedResource()
631 ASSERT(m_linkedResource);
632 m_linkedResource = 0;
636 void SVGResources::dump(const RenderObject* object)
639 ASSERT(object->node());
641 fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node());
642 fprintf(stderr, " | DOM Tree:\n");
643 object->node()->showTreeForThis();
645 fprintf(stderr, "\n | List of resources:\n");
646 if (m_clipperFilterMaskerData) {
647 if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
648 fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper, clipper->node());
650 if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
651 fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter, filter->node());
653 if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
654 fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker, masker->node());
658 if (RenderSVGResourceMarker* markerStart = m_markerData->markerStart)
659 fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, markerStart->node());
660 if (RenderSVGResourceMarker* markerMid = m_markerData->markerMid)
661 fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", markerMid, markerMid->node());
662 if (RenderSVGResourceMarker* markerEnd = m_markerData->markerEnd)
663 fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", markerEnd, markerEnd->node());
666 if (m_fillStrokeData) {
667 if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill)
668 fprintf(stderr, " |-> Fill : %p (node=%p)\n", fill, fill->node());
669 if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke)
670 fprintf(stderr, " |-> Stroke : %p (node=%p)\n", stroke, stroke->node());
673 if (m_linkedResource)
674 fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, m_linkedResource->node());