• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
3  *               2007 Rob Buis <buis@kde.org>
4  *               2008 Dirk Schulze <krit@webkit.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "config.h"
29 
30 #if ENABLE(SVG)
31 #include "SVGPaintServer.h"
32 
33 #include "GraphicsContext.h"
34 #include "NodeRenderStyle.h"
35 #include "RenderObject.h"
36 #include "RenderStyle.h"
37 #include "SVGPaintServerSolid.h"
38 #include "SVGStyledElement.h"
39 #include "SVGURIReference.h"
40 
41 #if PLATFORM(SKIA)
42 #include "PlatformContextSkia.h"
43 #endif
44 
45 namespace WebCore {
46 
SVGPaintServer()47 SVGPaintServer::SVGPaintServer()
48 {
49 }
50 
~SVGPaintServer()51 SVGPaintServer::~SVGPaintServer()
52 {
53 }
54 
operator <<(TextStream & ts,const SVGPaintServer & paintServer)55 TextStream& operator<<(TextStream& ts, const SVGPaintServer& paintServer)
56 {
57     return paintServer.externalRepresentation(ts);
58 }
59 
getPaintServerById(Document * document,const AtomicString & id)60 SVGPaintServer* getPaintServerById(Document* document, const AtomicString& id)
61 {
62     SVGResource* resource = getResourceById(document, id);
63     if (resource && resource->isPaintServer())
64         return static_cast<SVGPaintServer*>(resource);
65 
66     return 0;
67 }
68 
sharedSolidPaintServer()69 SVGPaintServerSolid* SVGPaintServer::sharedSolidPaintServer()
70 {
71     static SVGPaintServerSolid* _sharedSolidPaintServer = SVGPaintServerSolid::create().releaseRef();
72 
73     return _sharedSolidPaintServer;
74 }
75 
fillPaintServer(const RenderStyle * style,const RenderObject * item)76 SVGPaintServer* SVGPaintServer::fillPaintServer(const RenderStyle* style, const RenderObject* item)
77 {
78     if (!style->svgStyle()->hasFill())
79         return 0;
80 
81     SVGPaint* fill = style->svgStyle()->fillPaint();
82 
83     SVGPaintServer* fillPaintServer = 0;
84     SVGPaint::SVGPaintType paintType = fill->paintType();
85     if (paintType == SVGPaint::SVG_PAINTTYPE_URI ||
86         paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) {
87         AtomicString id(SVGURIReference::getTarget(fill->uri()));
88         fillPaintServer = getPaintServerById(item->document(), id);
89 
90         SVGElement* svgElement = static_cast<SVGElement*>(item->node());
91         ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
92 
93         if (item->isRenderPath() && fillPaintServer)
94             fillPaintServer->addClient(static_cast<SVGStyledElement*>(svgElement));
95         else if (!fillPaintServer && paintType == SVGPaint::SVG_PAINTTYPE_URI)
96             svgElement->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement));
97     }
98     if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !fillPaintServer) {
99         fillPaintServer = sharedSolidPaintServer();
100         SVGPaintServerSolid* fillPaintServerSolid = static_cast<SVGPaintServerSolid*>(fillPaintServer);
101         if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
102             fillPaintServerSolid->setColor(style->color());
103         else
104             fillPaintServerSolid->setColor(fill->color());
105         // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
106         if (!fillPaintServerSolid->color().isValid())
107             fillPaintServer = 0;
108     }
109     if (!fillPaintServer) {
110         // default value (black), see bug 11017
111         fillPaintServer = sharedSolidPaintServer();
112         static_cast<SVGPaintServerSolid*>(fillPaintServer)->setColor(Color::black);
113     }
114     return fillPaintServer;
115 }
116 
strokePaintServer(const RenderStyle * style,const RenderObject * item)117 SVGPaintServer* SVGPaintServer::strokePaintServer(const RenderStyle* style, const RenderObject* item)
118 {
119     if (!style->svgStyle()->hasStroke())
120         return 0;
121 
122     SVGPaint* stroke = style->svgStyle()->strokePaint();
123 
124     SVGPaintServer* strokePaintServer = 0;
125     SVGPaint::SVGPaintType paintType = stroke->paintType();
126     if (paintType == SVGPaint::SVG_PAINTTYPE_URI ||
127         paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) {
128         AtomicString id(SVGURIReference::getTarget(stroke->uri()));
129         strokePaintServer = getPaintServerById(item->document(), id);
130 
131         SVGElement* svgElement = static_cast<SVGElement*>(item->node());
132         ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
133 
134         if (item->isRenderPath() && strokePaintServer)
135             strokePaintServer->addClient(static_cast<SVGStyledElement*>(svgElement));
136         else if (!strokePaintServer && paintType == SVGPaint::SVG_PAINTTYPE_URI)
137             svgElement->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement));
138     }
139     if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !strokePaintServer) {
140         strokePaintServer = sharedSolidPaintServer();
141         SVGPaintServerSolid* strokePaintServerSolid = static_cast<SVGPaintServerSolid*>(strokePaintServer);
142         if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
143             strokePaintServerSolid->setColor(style->color());
144         else
145             strokePaintServerSolid->setColor(stroke->color());
146         // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
147         if (!strokePaintServerSolid->color().isValid())
148             strokePaintServer = 0;
149     }
150 
151     return strokePaintServer;
152 }
153 
applyStrokeStyleToContext(GraphicsContext * context,RenderStyle * style,const RenderObject * object)154 void applyStrokeStyleToContext(GraphicsContext* context, RenderStyle* style, const RenderObject* object)
155 {
156     context->setStrokeThickness(SVGRenderStyle::cssPrimitiveToLength(object, style->svgStyle()->strokeWidth(), 1.0f));
157     context->setLineCap(style->svgStyle()->capStyle());
158     context->setLineJoin(style->svgStyle()->joinStyle());
159     if (style->svgStyle()->joinStyle() == MiterJoin)
160         context->setMiterLimit(style->svgStyle()->strokeMiterLimit());
161 
162     const DashArray& dashes = dashArrayFromRenderingStyle(object->style(), object->document()->documentElement()->renderStyle());
163     float dashOffset = SVGRenderStyle::cssPrimitiveToLength(object, style->svgStyle()->strokeDashOffset(), 0.0f);
164     context->setLineDash(dashes, dashOffset);
165 }
166 
draw(GraphicsContext * & context,const RenderObject * path,SVGPaintTargetType type) const167 void SVGPaintServer::draw(GraphicsContext*& context, const RenderObject* path, SVGPaintTargetType type) const
168 {
169     if (!setup(context, path, type))
170         return;
171 
172     renderPath(context, path, type);
173     teardown(context, path, type);
174 }
175 
renderPath(GraphicsContext * & context,const RenderObject * path,SVGPaintTargetType type) const176 void SVGPaintServer::renderPath(GraphicsContext*& context, const RenderObject* path, SVGPaintTargetType type) const
177 {
178     const SVGRenderStyle* style = path ? path->style()->svgStyle() : 0;
179 
180     if ((type & ApplyToFillTargetType) && (!style || style->hasFill()))
181         context->fillPath();
182 
183     if ((type & ApplyToStrokeTargetType) && (!style || style->hasStroke()))
184         context->strokePath();
185 }
186 
187 #if PLATFORM(SKIA)
teardown(GraphicsContext * & context,const RenderObject *,SVGPaintTargetType,bool) const188 void SVGPaintServer::teardown(GraphicsContext*& context, const RenderObject*, SVGPaintTargetType, bool) const
189 {
190     // FIXME: Move this into the GraphicsContext
191     // WebKit implicitly expects us to reset the path.
192     // For example in fillAndStrokePath() of RenderPath.cpp the path is
193     // added back to the context after filling. This is because internally it
194     // calls CGContextFillPath() which closes the path.
195     context->beginPath();
196     context->platformContext()->setFillShader(0);
197     context->platformContext()->setStrokeShader(0);
198 }
199 #else
teardown(GraphicsContext * &,const RenderObject *,SVGPaintTargetType,bool) const200 void SVGPaintServer::teardown(GraphicsContext*&, const RenderObject*, SVGPaintTargetType, bool) const
201 {
202 }
203 #endif
204 
dashArrayFromRenderingStyle(const RenderStyle * style,RenderStyle * rootStyle)205 DashArray dashArrayFromRenderingStyle(const RenderStyle* style, RenderStyle* rootStyle)
206 {
207     DashArray array;
208 
209     CSSValueList* dashes = style->svgStyle()->strokeDashArray();
210     if (dashes) {
211         CSSPrimitiveValue* dash = 0;
212         unsigned long len = dashes->length();
213         for (unsigned long i = 0; i < len; i++) {
214             dash = static_cast<CSSPrimitiveValue*>(dashes->itemWithoutBoundsCheck(i));
215             if (!dash)
216                 continue;
217 
218             array.append((float) dash->computeLengthFloat(const_cast<RenderStyle*>(style), rootStyle));
219         }
220     }
221 
222     return array;
223 }
224 
225 } // namespace WebCore
226 
227 #endif
228