1 /* 2 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2007 Rob Buis <buis (at) kde.org> 4 * Copyright (C) 2008 Dirk Schulze <krit (at) webkit.org> 5 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 */ 22 23 #include "config.h" 24 25 #include "core/rendering/svg/RenderSVGResource.h" 26 27 #include "core/frame/FrameView.h" 28 #include "core/frame/LocalFrame.h" 29 #include "core/rendering/svg/RenderSVGResourceClipper.h" 30 #include "core/rendering/svg/RenderSVGResourceFilter.h" 31 #include "core/rendering/svg/RenderSVGResourceMasker.h" 32 #include "core/rendering/svg/RenderSVGResourceSolidColor.h" 33 #include "core/rendering/svg/SVGResources.h" 34 #include "core/rendering/svg/SVGResourcesCache.h" 35 36 namespace blink { 37 38 RenderSVGResource* RenderSVGResource::requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, bool& hasFallback) 39 { 40 ASSERT(object); 41 ASSERT(style); 42 43 hasFallback = false; 44 45 // If we have no style at all, ignore it. 46 const SVGRenderStyle& svgStyle = style->svgStyle(); 47 48 bool isRenderingMask = false; 49 if (object->frame() && object->frame()->view()) 50 isRenderingMask = object->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask; 51 52 // If we have no fill/stroke, return 0. 53 if (mode == ApplyToFillMode) { 54 // When rendering the mask for a RenderSVGResourceClipper, always use the initial fill paint server, and ignore stroke. 55 if (isRenderingMask) { 56 RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); 57 colorResource->setColor(SVGRenderStyle::initialFillPaintColor()); 58 return colorResource; 59 } 60 61 if (!svgStyle.hasFill()) 62 return 0; 63 } else { 64 if (!svgStyle.hasStroke() || isRenderingMask) 65 return 0; 66 } 67 68 bool applyToFill = mode == ApplyToFillMode; 69 SVGPaintType paintType = applyToFill ? svgStyle.fillPaintType() : svgStyle.strokePaintType(); 70 ASSERT(paintType != SVG_PAINTTYPE_NONE); 71 72 Color color; 73 bool hasColor = false; 74 switch (paintType) { 75 case SVG_PAINTTYPE_CURRENTCOLOR: 76 case SVG_PAINTTYPE_RGBCOLOR: 77 case SVG_PAINTTYPE_URI_CURRENTCOLOR: 78 case SVG_PAINTTYPE_URI_RGBCOLOR: 79 color = applyToFill ? svgStyle.fillPaintColor() : svgStyle.strokePaintColor(); 80 hasColor = true; 81 default: 82 break; 83 } 84 85 if (style->insideLink() == InsideVisitedLink) { 86 // FIXME: This code doesn't support the uri component of the visited link paint, https://bugs.webkit.org/show_bug.cgi?id=70006 87 SVGPaintType visitedPaintType = applyToFill ? svgStyle.visitedLinkFillPaintType() : svgStyle.visitedLinkStrokePaintType(); 88 89 // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. 90 if (visitedPaintType < SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVG_PAINTTYPE_CURRENTCOLOR) { 91 const Color& visitedColor = applyToFill ? svgStyle.visitedLinkFillPaintColor() : svgStyle.visitedLinkStrokePaintColor(); 92 color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); 93 hasColor = true; 94 } 95 } 96 97 // If the primary resource is just a color, return immediately. 98 RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); 99 if (paintType < SVG_PAINTTYPE_URI_NONE) { 100 // |paintType| will be either <current-color> or <rgb-color> here - both of which will have a color. 101 ASSERT(hasColor); 102 colorResource->setColor(color); 103 return colorResource; 104 } 105 106 RenderSVGResource* uriResource = 0; 107 if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object)) 108 uriResource = applyToFill ? resources->fill() : resources->stroke(); 109 110 // If the requested resource is not available, return the color resource or 'none'. 111 if (!uriResource) { 112 // The fallback is 'none'. (SVG2 say 'none' is implied when no fallback is specified.) 113 if (paintType == SVG_PAINTTYPE_URI_NONE || !hasColor) 114 return 0; 115 116 colorResource->setColor(color); 117 return colorResource; 118 } 119 120 // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller 121 // via sharedSolidPaintingResource so it can use the solid color painting resource, if applyResource() on the URI resource failed. 122 if (hasColor) { 123 colorResource->setColor(color); 124 hasFallback = true; 125 } 126 return uriResource; 127 } 128 129 RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() 130 { 131 static RenderSVGResourceSolidColor* s_sharedSolidPaintingResource = 0; 132 if (!s_sharedSolidPaintingResource) 133 s_sharedSolidPaintingResource = new RenderSVGResourceSolidColor; 134 return s_sharedSolidPaintingResource; 135 } 136 137 static inline void removeFromCacheAndInvalidateDependencies(RenderObject* object, bool needsLayout) 138 { 139 ASSERT(object); 140 if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object)) { 141 if (RenderSVGResourceFilter* filter = resources->filter()) 142 filter->removeClientFromCache(object); 143 144 if (RenderSVGResourceMasker* masker = resources->masker()) 145 masker->removeClientFromCache(object); 146 147 if (RenderSVGResourceClipper* clipper = resources->clipper()) 148 clipper->removeClientFromCache(object); 149 } 150 151 if (!object->node() || !object->node()->isSVGElement()) 152 return; 153 SVGElementSet* dependencies = toSVGElement(object->node())->setOfIncomingReferences(); 154 if (!dependencies) 155 return; 156 157 // We allow cycles in SVGDocumentExtensions reference sets in order to avoid expensive 158 // reference graph adjustments on changes, so we need to break possible cycles here. 159 // This strong reference is safe, as it is guaranteed that this set will be emptied 160 // at the end of recursion. 161 typedef WillBeHeapHashSet<RawPtrWillBeMember<SVGElement> > SVGElementSet; 162 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<SVGElementSet>, invalidatingDependencies, (adoptPtrWillBeNoop(new SVGElementSet))); 163 164 SVGElementSet::iterator end = dependencies->end(); 165 for (SVGElementSet::iterator it = dependencies->begin(); it != end; ++it) { 166 if (RenderObject* renderer = (*it)->renderer()) { 167 if (UNLIKELY(!invalidatingDependencies->add(*it).isNewEntry)) { 168 // Reference cycle: we are in process of invalidating this dependant. 169 continue; 170 } 171 172 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, needsLayout); 173 invalidatingDependencies->remove(*it); 174 } 175 } 176 } 177 178 void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* object, bool needsLayout) 179 { 180 ASSERT(object); 181 ASSERT(object->node()); 182 183 if (needsLayout && !object->documentBeingDestroyed()) 184 object->setNeedsLayoutAndFullPaintInvalidation(); 185 186 removeFromCacheAndInvalidateDependencies(object, needsLayout); 187 188 // Invalidate resources in ancestor chain, if needed. 189 RenderObject* current = object->parent(); 190 while (current) { 191 removeFromCacheAndInvalidateDependencies(current, needsLayout); 192 193 if (current->isSVGResourceContainer()) { 194 // This will process the rest of the ancestors. 195 toRenderSVGResourceContainer(current)->removeAllClientsFromCache(); 196 break; 197 } 198 199 current = current->parent(); 200 } 201 } 202 203 } 204