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