1/* 2 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> 3 * Copyright (C) 2007 Rob Buis <buis@kde.org> 4 * Copyright (C) 2008 Dirk Schulze <krit@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#if ENABLE(SVG) 26#include "RenderSVGResource.h" 27 28#include "Frame.h" 29#include "FrameView.h" 30#include "RenderSVGResourceClipper.h" 31#include "RenderSVGResourceContainer.h" 32#include "RenderSVGResourceFilter.h" 33#include "RenderSVGResourceMasker.h" 34#include "RenderSVGResourceSolidColor.h" 35#include "SVGResources.h" 36#include "SVGResourcesCache.h" 37#include "SVGURIReference.h" 38 39namespace WebCore { 40 41static inline bool inheritColorFromParentStyleIfNeeded(RenderObject* object, bool applyToFill, Color& color) 42{ 43 if (color.isValid()) 44 return true; 45 if (!object->parent() || !object->parent()->style()) 46 return false; 47 const SVGRenderStyle* parentSVGStyle = object->parent()->style()->svgStyle(); 48 color = applyToFill ? parentSVGStyle->fillPaintColor() : parentSVGStyle->strokePaintColor(); 49 return true; 50} 51 52static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor) 53{ 54 ASSERT(object); 55 ASSERT(style); 56 57 // If we have no style at all, ignore it. 58 const SVGRenderStyle* svgStyle = style->svgStyle(); 59 if (!svgStyle) 60 return 0; 61 62 bool isRenderingMask = false; 63 if (object->frame() && object->frame()->view()) 64 isRenderingMask = object->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask; 65 66 // If we have no fill/stroke, return 0. 67 if (mode == ApplyToFillMode) { 68 // When rendering the mask for a RenderSVGResourceClipper, always use the initial fill paint server, and ignore stroke. 69 if (isRenderingMask) { 70 RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); 71 colorResource->setColor(SVGRenderStyle::initialFillPaintColor()); 72 return colorResource; 73 } 74 75 if (!svgStyle->hasFill()) 76 return 0; 77 } else { 78 if (!svgStyle->hasStroke() || isRenderingMask) 79 return 0; 80 } 81 82 bool applyToFill = mode == ApplyToFillMode; 83 SVGPaint::SVGPaintType paintType = applyToFill ? svgStyle->fillPaintType() : svgStyle->strokePaintType(); 84 if (paintType == SVGPaint::SVG_PAINTTYPE_NONE) 85 return 0; 86 87 Color color; 88 switch (paintType) { 89 case SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR: 90 case SVGPaint::SVG_PAINTTYPE_RGBCOLOR: 91 case SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR: 92 case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR: 93 case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: 94 case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: 95 color = applyToFill ? svgStyle->fillPaintColor() : svgStyle->strokePaintColor(); 96 default: 97 break; 98 } 99 100 if (style->insideLink() == InsideVisitedLink) { 101 // FIXME: This code doesn't support the uri component of the visited link paint, https://bugs.webkit.org/show_bug.cgi?id=70006 102 SVGPaint::SVGPaintType visitedPaintType = applyToFill ? svgStyle->visitedLinkFillPaintType() : svgStyle->visitedLinkStrokePaintType(); 103 104 // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. 105 if (visitedPaintType < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { 106 const Color& visitedColor = applyToFill ? svgStyle->visitedLinkFillPaintColor() : svgStyle->visitedLinkStrokePaintColor(); 107 if (visitedColor.isValid()) 108 color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); 109 } 110 } 111 112 // If the primary resource is just a color, return immediately. 113 RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); 114 if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) { 115 if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) 116 return 0; 117 118 colorResource->setColor(color); 119 return colorResource; 120 } 121 122 // If no resources are associated with the given renderer, return the color resource. 123 SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); 124 if (!resources) { 125 if (paintType == SVGPaint::SVG_PAINTTYPE_URI_NONE || !inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) 126 return 0; 127 128 colorResource->setColor(color); 129 return colorResource; 130 } 131 132 // If the requested resource is not available, return the color resource. 133 RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke(); 134 if (!uriResource) { 135 if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) 136 return 0; 137 138 colorResource->setColor(color); 139 return colorResource; 140 } 141 142 // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller 143 // so it can use the solid color painting resource, if applyResource() on the URI resource failed. 144 fallbackColor = color; 145 return uriResource; 146} 147 148RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor) 149{ 150 return requestPaintingResource(ApplyToFillMode, object, style, fallbackColor); 151} 152 153RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor) 154{ 155 return requestPaintingResource(ApplyToStrokeMode, object, style, fallbackColor); 156} 157 158RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() 159{ 160 static RenderSVGResourceSolidColor* s_sharedSolidPaintingResource = 0; 161 if (!s_sharedSolidPaintingResource) 162 s_sharedSolidPaintingResource = new RenderSVGResourceSolidColor; 163 return s_sharedSolidPaintingResource; 164} 165 166static inline void removeFromCacheAndInvalidateDependencies(RenderObject* object, bool needsLayout) 167{ 168 ASSERT(object); 169 if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object)) { 170#if ENABLE(FILTERS) 171 if (RenderSVGResourceFilter* filter = resources->filter()) 172 filter->removeClientFromCache(object); 173#endif 174 if (RenderSVGResourceMasker* masker = resources->masker()) 175 masker->removeClientFromCache(object); 176 177 if (RenderSVGResourceClipper* clipper = resources->clipper()) 178 clipper->removeClientFromCache(object); 179 } 180 181 if (!object->node() || !object->node()->isSVGElement()) 182 return; 183 HashSet<SVGElement*>* dependencies = object->document()->accessSVGExtensions()->setOfElementsReferencingTarget(toSVGElement(object->node())); 184 if (!dependencies) 185 return; 186 HashSet<SVGElement*>::iterator end = dependencies->end(); 187 for (HashSet<SVGElement*>::iterator it = dependencies->begin(); it != end; ++it) { 188 if (RenderObject* renderer = (*it)->renderer()) 189 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, needsLayout); 190 } 191} 192 193void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* object, bool needsLayout) 194{ 195 ASSERT(object); 196 ASSERT(object->document()); 197 ASSERT(object->node()); 198 199 if (needsLayout) 200 object->setNeedsLayout(true); 201 202 removeFromCacheAndInvalidateDependencies(object, needsLayout); 203 204 // Invalidate resources in ancestor chain, if needed. 205 RenderObject* current = object->parent(); 206 while (current) { 207 removeFromCacheAndInvalidateDependencies(current, needsLayout); 208 209 if (current->isSVGResourceContainer()) { 210 // This will process the rest of the ancestors. 211 current->toRenderSVGResourceContainer()->removeAllClientsFromCache(); 212 break; 213 } 214 215 current = current->parent(); 216 } 217} 218 219} 220 221#endif 222 223