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 // Not listed in the definitions is the foreignObject element, but clip-path
85 // is a supported attribute.
86 s_tagList.add(SVGNames::foreignObjectTag.localName().impl());
88 // Elements that we ignore, as it doesn't make any sense.
89 // defs, pattern, switch (FIXME: Mail SVG WG about these)
90 // symbol (is converted to a svg element, when referenced by use, we can safely ignore it.)
96 static HashSet<AtomicStringImpl*>& markerTags()
98 DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
99 if (s_tagList.isEmpty()) {
100 s_tagList.add(SVGNames::lineTag.localName().impl());
101 s_tagList.add(SVGNames::pathTag.localName().impl());
102 s_tagList.add(SVGNames::polygonTag.localName().impl());
103 s_tagList.add(SVGNames::polylineTag.localName().impl());
109 static HashSet<AtomicStringImpl*>& fillAndStrokeTags()
111 DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
112 if (s_tagList.isEmpty()) {
113 s_tagList.add(SVGNames::altGlyphTag.localName().impl());
114 s_tagList.add(SVGNames::circleTag.localName().impl());
115 s_tagList.add(SVGNames::ellipseTag.localName().impl());
116 s_tagList.add(SVGNames::lineTag.localName().impl());
117 s_tagList.add(SVGNames::pathTag.localName().impl());
118 s_tagList.add(SVGNames::polygonTag.localName().impl());
119 s_tagList.add(SVGNames::polylineTag.localName().impl());
120 s_tagList.add(SVGNames::rectTag.localName().impl());
121 s_tagList.add(SVGNames::textTag.localName().impl());
122 s_tagList.add(SVGNames::textPathTag.localName().impl());
123 s_tagList.add(SVGNames::trefTag.localName().impl());
124 s_tagList.add(SVGNames::tspanTag.localName().impl());
130 static HashSet<AtomicStringImpl*>& chainableResourceTags()
132 DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
133 if (s_tagList.isEmpty()) {
134 s_tagList.add(SVGNames::linearGradientTag.localName().impl());
135 s_tagList.add(SVGNames::filterTag.localName().impl());
136 s_tagList.add(SVGNames::patternTag.localName().impl());
137 s_tagList.add(SVGNames::radialGradientTag.localName().impl());
143 static inline String targetReferenceFromResource(SVGElement* element)
146 if (element->hasTagName(SVGNames::patternTag))
147 target = static_cast<SVGPatternElement*>(element)->href();
148 else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag))
149 target = static_cast<SVGGradientElement*>(element)->href();
151 else if (element->hasTagName(SVGNames::filterTag))
152 target = static_cast<SVGFilterElement*>(element)->href();
155 ASSERT_NOT_REACHED();
157 return SVGURIReference::fragmentIdentifierFromIRIString(target, element->document());
160 static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document* document, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource)
162 if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)
165 id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, document);
166 RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id);
168 hasPendingResource = true;
172 RenderSVGResourceType resourceType = container->resourceType();
173 if (resourceType != PatternResourceType && resourceType != LinearGradientResourceType && resourceType != RadialGradientResourceType)
179 static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement* element)
182 ASSERT(element->isStyled());
183 extensions->addPendingResource(id, static_cast<SVGStyledElement*>(element));
186 bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRenderStyle* style)
191 Node* node = object->node();
193 ASSERT(node->isSVGElement());
195 SVGElement* element = static_cast<SVGElement*>(node);
199 Document* document = object->document();
202 SVGDocumentExtensions* extensions = document->accessSVGExtensions();
205 AtomicStringImpl* tagNameImpl = element->tagQName().localName().impl();
209 bool foundResources = false;
210 if (clipperFilterMaskerTags().contains(tagNameImpl)) {
211 if (style->hasClipper()) {
212 AtomicString id(style->clipperResource());
213 if (setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id)))
214 foundResources = true;
216 registerPendingResource(extensions, id, element);
220 if (style->hasFilter()) {
221 AtomicString id(style->filterResource());
222 if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id)))
223 foundResources = true;
225 registerPendingResource(extensions, id, element);
229 if (style->hasMasker()) {
230 AtomicString id(style->maskerResource());
231 if (setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id)))
232 foundResources = true;
234 registerPendingResource(extensions, id, element);
238 if (markerTags().contains(tagNameImpl) && style->hasMarkers()) {
239 AtomicString markerStartId(style->markerStartResource());
240 if (setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId)))
241 foundResources = true;
243 registerPendingResource(extensions, markerStartId, element);
245 AtomicString markerMidId(style->markerMidResource());
246 if (setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId)))
247 foundResources = true;
249 registerPendingResource(extensions, markerMidId, element);
251 AtomicString markerEndId(style->markerEndResource());
252 if (setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId)))
253 foundResources = true;
255 registerPendingResource(extensions, markerEndId, element);
258 if (fillAndStrokeTags().contains(tagNameImpl)) {
259 if (style->hasFill()) {
260 bool hasPendingResource = false;
262 if (setFill(paintingResourceFromSVGPaint(document, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource)))
263 foundResources = true;
264 else if (hasPendingResource)
265 registerPendingResource(extensions, id, element);
268 if (style->hasStroke()) {
269 bool hasPendingResource = false;
271 if (setStroke(paintingResourceFromSVGPaint(document, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource)))
272 foundResources = true;
273 else if (hasPendingResource)
274 registerPendingResource(extensions, id, element);
278 if (chainableResourceTags().contains(tagNameImpl)) {
279 AtomicString id(targetReferenceFromResource(element));
280 if (setLinkedResource(getRenderSVGResourceContainerById(document, id)))
281 foundResources = true;
283 registerPendingResource(extensions, id, element);
286 return foundResources;
289 void SVGResources::removeClientFromCache(RenderObject* object, bool markForInvalidation) const
291 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
294 if (m_linkedResource) {
295 ASSERT(!m_clipperFilterMaskerData);
296 ASSERT(!m_markerData);
297 ASSERT(!m_fillStrokeData);
298 m_linkedResource->removeClientFromCache(object, markForInvalidation);
302 if (m_clipperFilterMaskerData) {
303 if (m_clipperFilterMaskerData->clipper)
304 m_clipperFilterMaskerData->clipper->removeClientFromCache(object, markForInvalidation);
306 if (m_clipperFilterMaskerData->filter)
307 m_clipperFilterMaskerData->filter->removeClientFromCache(object, markForInvalidation);
309 if (m_clipperFilterMaskerData->masker)
310 m_clipperFilterMaskerData->masker->removeClientFromCache(object, markForInvalidation);
314 if (m_markerData->markerStart)
315 m_markerData->markerStart->removeClientFromCache(object, markForInvalidation);
316 if (m_markerData->markerMid)
317 m_markerData->markerMid->removeClientFromCache(object, markForInvalidation);
318 if (m_markerData->markerEnd)
319 m_markerData->markerEnd->removeClientFromCache(object, markForInvalidation);
322 if (m_fillStrokeData) {
323 if (m_fillStrokeData->fill)
324 m_fillStrokeData->fill->removeClientFromCache(object, markForInvalidation);
325 if (m_fillStrokeData->stroke)
326 m_fillStrokeData->stroke->removeClientFromCache(object, markForInvalidation);
330 void SVGResources::resourceDestroyed(RenderSVGResourceContainer* resource)
333 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
336 if (m_linkedResource == resource) {
337 ASSERT(!m_clipperFilterMaskerData);
338 ASSERT(!m_markerData);
339 ASSERT(!m_fillStrokeData);
340 m_linkedResource->removeAllClientsFromCache();
341 m_linkedResource = 0;
345 switch (resource->resourceType()) {
346 case MaskerResourceType:
347 if (!m_clipperFilterMaskerData)
349 if (m_clipperFilterMaskerData->masker == resource) {
350 m_clipperFilterMaskerData->masker->removeAllClientsFromCache();
351 m_clipperFilterMaskerData->masker = 0;
354 case MarkerResourceType:
357 if (m_markerData->markerStart == resource) {
358 m_markerData->markerStart->removeAllClientsFromCache();
359 m_markerData->markerStart = 0;
361 if (m_markerData->markerMid == resource) {
362 m_markerData->markerMid->removeAllClientsFromCache();
363 m_markerData->markerMid = 0;
365 if (m_markerData->markerEnd == resource) {
366 m_markerData->markerEnd->removeAllClientsFromCache();
367 m_markerData->markerEnd = 0;
370 case PatternResourceType:
371 case LinearGradientResourceType:
372 case RadialGradientResourceType:
373 if (!m_fillStrokeData)
375 if (m_fillStrokeData->fill == resource) {
376 m_fillStrokeData->fill->removeAllClientsFromCache();
377 m_fillStrokeData->fill = 0;
379 if (m_fillStrokeData->stroke == resource) {
380 m_fillStrokeData->stroke->removeAllClientsFromCache();
381 m_fillStrokeData->stroke = 0;
384 case FilterResourceType:
386 if (!m_clipperFilterMaskerData)
388 if (m_clipperFilterMaskerData->filter == resource) {
389 m_clipperFilterMaskerData->filter->removeAllClientsFromCache();
390 m_clipperFilterMaskerData->filter = 0;
393 ASSERT_NOT_REACHED();
396 case ClipperResourceType:
397 if (!m_clipperFilterMaskerData)
399 if (m_clipperFilterMaskerData->clipper == resource) {
400 m_clipperFilterMaskerData->clipper->removeAllClientsFromCache();
401 m_clipperFilterMaskerData->clipper = 0;
404 case SolidColorResourceType:
405 ASSERT_NOT_REACHED();
409 void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set)
411 if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
414 if (m_linkedResource) {
415 ASSERT(!m_clipperFilterMaskerData);
416 ASSERT(!m_markerData);
417 ASSERT(!m_fillStrokeData);
418 set.add(m_linkedResource);
422 if (m_clipperFilterMaskerData) {
423 if (m_clipperFilterMaskerData->clipper)
424 set.add(m_clipperFilterMaskerData->clipper);
426 if (m_clipperFilterMaskerData->filter)
427 set.add(m_clipperFilterMaskerData->filter);
429 if (m_clipperFilterMaskerData->masker)
430 set.add(m_clipperFilterMaskerData->masker);
434 if (m_markerData->markerStart)
435 set.add(m_markerData->markerStart);
436 if (m_markerData->markerMid)
437 set.add(m_markerData->markerMid);
438 if (m_markerData->markerEnd)
439 set.add(m_markerData->markerEnd);
442 if (m_fillStrokeData) {
443 if (m_fillStrokeData->fill)
444 set.add(m_fillStrokeData->fill);
445 if (m_fillStrokeData->stroke)
446 set.add(m_fillStrokeData->stroke);
450 bool SVGResources::setClipper(RenderSVGResourceClipper* clipper)
455 ASSERT(clipper->resourceType() == ClipperResourceType);
457 if (!m_clipperFilterMaskerData)
458 m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
460 m_clipperFilterMaskerData->clipper = clipper;
464 void SVGResources::resetClipper()
466 ASSERT(m_clipperFilterMaskerData);
467 ASSERT(m_clipperFilterMaskerData->clipper);
468 m_clipperFilterMaskerData->clipper = 0;
472 bool SVGResources::setFilter(RenderSVGResourceFilter* filter)
477 ASSERT(filter->resourceType() == FilterResourceType);
479 if (!m_clipperFilterMaskerData)
480 m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
482 m_clipperFilterMaskerData->filter = filter;
486 void SVGResources::resetFilter()
488 ASSERT(m_clipperFilterMaskerData);
489 ASSERT(m_clipperFilterMaskerData->filter);
490 m_clipperFilterMaskerData->filter = 0;
494 bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart)
499 ASSERT(markerStart->resourceType() == MarkerResourceType);
502 m_markerData = MarkerData::create();
504 m_markerData->markerStart = markerStart;
508 void SVGResources::resetMarkerStart()
510 ASSERT(m_markerData);
511 ASSERT(m_markerData->markerStart);
512 m_markerData->markerStart = 0;
515 bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid)
520 ASSERT(markerMid->resourceType() == MarkerResourceType);
523 m_markerData = MarkerData::create();
525 m_markerData->markerMid = markerMid;
529 void SVGResources::resetMarkerMid()
531 ASSERT(m_markerData);
532 ASSERT(m_markerData->markerMid);
533 m_markerData->markerMid = 0;
536 bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd)
541 ASSERT(markerEnd->resourceType() == MarkerResourceType);
544 m_markerData = MarkerData::create();
546 m_markerData->markerEnd = markerEnd;
550 void SVGResources::resetMarkerEnd()
552 ASSERT(m_markerData);
553 ASSERT(m_markerData->markerEnd);
554 m_markerData->markerEnd = 0;
557 bool SVGResources::setMasker(RenderSVGResourceMasker* masker)
562 ASSERT(masker->resourceType() == MaskerResourceType);
564 if (!m_clipperFilterMaskerData)
565 m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
567 m_clipperFilterMaskerData->masker = masker;
571 void SVGResources::resetMasker()
573 ASSERT(m_clipperFilterMaskerData);
574 ASSERT(m_clipperFilterMaskerData->masker);
575 m_clipperFilterMaskerData->masker = 0;
578 bool SVGResources::setFill(RenderSVGResourceContainer* fill)
583 ASSERT(fill->resourceType() == PatternResourceType
584 || fill->resourceType() == LinearGradientResourceType
585 || fill->resourceType() == RadialGradientResourceType);
587 if (!m_fillStrokeData)
588 m_fillStrokeData = FillStrokeData::create();
590 m_fillStrokeData->fill = fill;
594 void SVGResources::resetFill()
596 ASSERT(m_fillStrokeData);
597 ASSERT(m_fillStrokeData->fill);
598 m_fillStrokeData->fill = 0;
601 bool SVGResources::setStroke(RenderSVGResourceContainer* stroke)
606 ASSERT(stroke->resourceType() == PatternResourceType
607 || stroke->resourceType() == LinearGradientResourceType
608 || stroke->resourceType() == RadialGradientResourceType);
610 if (!m_fillStrokeData)
611 m_fillStrokeData = FillStrokeData::create();
613 m_fillStrokeData->stroke = stroke;
617 void SVGResources::resetStroke()
619 ASSERT(m_fillStrokeData);
620 ASSERT(m_fillStrokeData->stroke);
621 m_fillStrokeData->stroke = 0;
624 bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource)
629 m_linkedResource = linkedResource;
633 void SVGResources::resetLinkedResource()
635 ASSERT(m_linkedResource);
636 m_linkedResource = 0;
640 void SVGResources::dump(const RenderObject* object)
643 ASSERT(object->node());
645 fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node());
646 fprintf(stderr, " | DOM Tree:\n");
647 object->node()->showTreeForThis();
649 fprintf(stderr, "\n | List of resources:\n");
650 if (m_clipperFilterMaskerData) {
651 if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
652 fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper, clipper->node());
654 if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
655 fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter, filter->node());
657 if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
658 fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker, masker->node());
662 if (RenderSVGResourceMarker* markerStart = m_markerData->markerStart)
663 fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, markerStart->node());
664 if (RenderSVGResourceMarker* markerMid = m_markerData->markerMid)
665 fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", markerMid, markerMid->node());
666 if (RenderSVGResourceMarker* markerEnd = m_markerData->markerEnd)
667 fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", markerEnd, markerEnd->node());
670 if (m_fillStrokeData) {
671 if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill)
672 fprintf(stderr, " |-> Fill : %p (node=%p)\n", fill, fill->node());
673 if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke)
674 fprintf(stderr, " |-> Stroke : %p (node=%p)\n", stroke, stroke->node());
677 if (m_linkedResource)
678 fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, m_linkedResource->node());