https://bugs.webkit.org/show_bug.cgi?id=69966
[WebKit-https.git] / Source / WebCore / rendering / svg / RenderSVGResource.cpp
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 "RenderSVGResourceContainer.h"
29 #include "RenderSVGResourceSolidColor.h"
30 #include "SVGResources.h"
31 #include "SVGURIReference.h"
32
33 namespace WebCore {
34
35 static inline bool inheritColorFromParentStyleIfNeeded(RenderObject* object, bool applyToFill, Color& color)
36 {
37     if (color.isValid())
38         return true;
39     if (!object->parent() || !object->parent()->style())
40         return false;
41     const SVGRenderStyle* parentSVGStyle = object->parent()->style()->svgStyle();
42     color = applyToFill ? parentSVGStyle->fillPaintColor() : parentSVGStyle->strokePaintColor();
43     return true;
44 }
45
46 static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor)
47 {
48     ASSERT(object);
49     ASSERT(style);
50
51     // If we have no style at all, ignore it.
52     const SVGRenderStyle* svgStyle = style->svgStyle();
53     if (!svgStyle)
54         return 0;
55
56     // If we have no fill/stroke, return 0.
57     if (mode == ApplyToFillMode) {
58         if (!svgStyle->hasFill())
59             return 0;
60     } else {
61         if (!svgStyle->hasStroke())
62             return 0;
63     }
64
65     bool applyToFill = mode == ApplyToFillMode;
66     SVGPaint::SVGPaintType paintType = applyToFill ? svgStyle->fillPaintType() : svgStyle->strokePaintType();
67     if (paintType == SVGPaint::SVG_PAINTTYPE_NONE)
68         return 0;
69
70     Color color;
71     switch (paintType) {
72     case SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR:
73     case SVGPaint::SVG_PAINTTYPE_RGBCOLOR:
74     case SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR:
75     case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR:
76     case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR:
77     case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR:
78         color = applyToFill ? svgStyle->fillPaintColor() : svgStyle->strokePaintColor();
79     default:
80         break;
81     }
82
83     if (style->insideLink() == InsideVisitedLink) {
84         // FIXME: This code doesn't support the uri component of the visited link paint, https://bugs.webkit.org/show_bug.cgi?id=70006
85         SVGPaint::SVGPaintType visitedPaintType = applyToFill ? svgStyle->visitedLinkFillPaintType() : svgStyle->visitedLinkStrokePaintType();
86
87         // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'.
88         if (visitedPaintType < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) {
89             const Color& visitedColor = applyToFill ? svgStyle->visitedLinkFillPaintColor() : svgStyle->visitedLinkStrokePaintColor();
90             if (visitedColor.isValid())
91                 color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha());
92         }
93     }
94
95     // If the primary resource is just a color, return immediately.
96     RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource();
97     if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) {
98         if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color))
99             return 0;
100
101         colorResource->setColor(color);
102         return colorResource;
103     }
104
105     // If no resources are associated with the given renderer, return the color resource.
106     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
107     if (!resources) {
108         if (paintType == SVGPaint::SVG_PAINTTYPE_URI_NONE || !inheritColorFromParentStyleIfNeeded(object, applyToFill, color))
109             return 0;
110
111         colorResource->setColor(color);
112         return colorResource;
113     }
114
115     // If the requested resource is not available, return the color resource.
116     RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke();
117     if (!uriResource) {
118         if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color))
119             return 0;
120
121         colorResource->setColor(color);
122         return colorResource;
123     }
124
125     // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller
126     // so it can use the solid color painting resource, if applyResource() on the URI resource failed.
127     fallbackColor = color;
128     return uriResource;
129 }
130
131 RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor)
132 {
133     return requestPaintingResource(ApplyToFillMode, object, style, fallbackColor);
134 }
135
136 RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor)
137 {
138     return requestPaintingResource(ApplyToStrokeMode, object, style, fallbackColor);
139 }
140
141 RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource()
142 {
143     static RenderSVGResourceSolidColor* s_sharedSolidPaintingResource = 0;
144     if (!s_sharedSolidPaintingResource)
145         s_sharedSolidPaintingResource = new RenderSVGResourceSolidColor;
146     return s_sharedSolidPaintingResource;
147 }
148
149 void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* object, bool needsLayout)
150 {
151     ASSERT(object);
152     if (needsLayout)
153         object->setNeedsLayout(true);
154
155     // Invalidate resources in ancestor chain, if needed.
156     RenderObject* current = object->parent();
157     while (current) {
158         if (current->isSVGResourceContainer()) {
159             current->toRenderSVGResourceContainer()->removeAllClientsFromCache();
160             break;
161         }
162
163         current = current->parent();
164     }
165 }
166
167 }
168
169 #endif
170