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 "RenderObject.h"
35 #include "RenderStyle.h"
36 #include "SVGPaintServerSolid.h"
37 #include "SVGStyledElement.h"
38 #include "SVGURIReference.h"
39
40 namespace WebCore {
41
SVGPaintServer()42 SVGPaintServer::SVGPaintServer()
43 {
44 }
45
~SVGPaintServer()46 SVGPaintServer::~SVGPaintServer()
47 {
48 }
49
operator <<(TextStream & ts,const SVGPaintServer & paintServer)50 TextStream& operator<<(TextStream& ts, const SVGPaintServer& paintServer)
51 {
52 return paintServer.externalRepresentation(ts);
53 }
54
getPaintServerById(Document * document,const AtomicString & id)55 SVGPaintServer* getPaintServerById(Document* document, const AtomicString& id)
56 {
57 SVGResource* resource = getResourceById(document, id);
58 if (resource && resource->isPaintServer())
59 return static_cast<SVGPaintServer*>(resource);
60
61 return 0;
62 }
63
sharedSolidPaintServer()64 SVGPaintServerSolid* SVGPaintServer::sharedSolidPaintServer()
65 {
66 static SVGPaintServerSolid* _sharedSolidPaintServer = SVGPaintServerSolid::create().releaseRef();
67
68 return _sharedSolidPaintServer;
69 }
70
fillPaintServer(const RenderStyle * style,const RenderObject * item)71 SVGPaintServer* SVGPaintServer::fillPaintServer(const RenderStyle* style, const RenderObject* item)
72 {
73 if (!style->svgStyle()->hasFill())
74 return 0;
75
76 SVGPaint* fill = style->svgStyle()->fillPaint();
77
78 SVGPaintServer* fillPaintServer = 0;
79 SVGPaint::SVGPaintType paintType = fill->paintType();
80 if (paintType == SVGPaint::SVG_PAINTTYPE_URI ||
81 paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) {
82 AtomicString id(SVGURIReference::getTarget(fill->uri()));
83 fillPaintServer = getPaintServerById(item->document(), id);
84
85 SVGElement* svgElement = static_cast<SVGElement*>(item->element());
86 ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
87
88 if (item->isRenderPath() && fillPaintServer)
89 fillPaintServer->addClient(static_cast<SVGStyledElement*>(svgElement));
90 else if (!fillPaintServer && paintType == SVGPaint::SVG_PAINTTYPE_URI)
91 svgElement->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement));
92 }
93 if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !fillPaintServer) {
94 fillPaintServer = sharedSolidPaintServer();
95 SVGPaintServerSolid* fillPaintServerSolid = static_cast<SVGPaintServerSolid*>(fillPaintServer);
96 if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
97 fillPaintServerSolid->setColor(style->color());
98 else
99 fillPaintServerSolid->setColor(fill->color());
100 // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
101 if (!fillPaintServerSolid->color().isValid())
102 fillPaintServer = 0;
103 }
104 if (!fillPaintServer) {
105 // default value (black), see bug 11017
106 fillPaintServer = sharedSolidPaintServer();
107 static_cast<SVGPaintServerSolid*>(fillPaintServer)->setColor(Color::black);
108 }
109 return fillPaintServer;
110 }
111
strokePaintServer(const RenderStyle * style,const RenderObject * item)112 SVGPaintServer* SVGPaintServer::strokePaintServer(const RenderStyle* style, const RenderObject* item)
113 {
114 if (!style->svgStyle()->hasStroke())
115 return 0;
116
117 SVGPaint* stroke = style->svgStyle()->strokePaint();
118
119 SVGPaintServer* strokePaintServer = 0;
120 SVGPaint::SVGPaintType paintType = stroke->paintType();
121 if (paintType == SVGPaint::SVG_PAINTTYPE_URI ||
122 paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) {
123 AtomicString id(SVGURIReference::getTarget(stroke->uri()));
124 strokePaintServer = getPaintServerById(item->document(), id);
125
126 SVGElement* svgElement = static_cast<SVGElement*>(item->element());
127 ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
128
129 if (item->isRenderPath() && strokePaintServer)
130 strokePaintServer->addClient(static_cast<SVGStyledElement*>(svgElement));
131 else if (!strokePaintServer && paintType == SVGPaint::SVG_PAINTTYPE_URI)
132 svgElement->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement));
133 }
134 if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !strokePaintServer) {
135 strokePaintServer = sharedSolidPaintServer();
136 SVGPaintServerSolid* strokePaintServerSolid = static_cast<SVGPaintServerSolid*>(strokePaintServer);
137 if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
138 strokePaintServerSolid->setColor(style->color());
139 else
140 strokePaintServerSolid->setColor(stroke->color());
141 // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
142 if (!strokePaintServerSolid->color().isValid())
143 strokePaintServer = 0;
144 }
145
146 return strokePaintServer;
147 }
148
applyStrokeStyleToContext(GraphicsContext * context,RenderStyle * style,const RenderObject * object)149 void applyStrokeStyleToContext(GraphicsContext* context, RenderStyle* style, const RenderObject* object)
150 {
151 context->setStrokeThickness(SVGRenderStyle::cssPrimitiveToLength(object, style->svgStyle()->strokeWidth(), 1.0f));
152 context->setLineCap(style->svgStyle()->capStyle());
153 context->setLineJoin(style->svgStyle()->joinStyle());
154 if (style->svgStyle()->joinStyle() == MiterJoin)
155 context->setMiterLimit(style->svgStyle()->strokeMiterLimit());
156
157 const DashArray& dashes = dashArrayFromRenderingStyle(object->style());
158 float dashOffset = SVGRenderStyle::cssPrimitiveToLength(object, style->svgStyle()->strokeDashOffset(), 0.0f);
159 context->setLineDash(dashes, dashOffset);
160 }
161
draw(GraphicsContext * & context,const RenderObject * path,SVGPaintTargetType type) const162 void SVGPaintServer::draw(GraphicsContext*& context, const RenderObject* path, SVGPaintTargetType type) const
163 {
164 if (!setup(context, path, type))
165 return;
166
167 renderPath(context, path, type);
168 teardown(context, path, type);
169 }
170
renderPath(GraphicsContext * & context,const RenderObject * path,SVGPaintTargetType type) const171 void SVGPaintServer::renderPath(GraphicsContext*& context, const RenderObject* path, SVGPaintTargetType type) const
172 {
173 const SVGRenderStyle* style = path ? path->style()->svgStyle() : 0;
174
175 if ((type & ApplyToFillTargetType) && (!style || style->hasFill()))
176 context->fillPath();
177
178 if ((type & ApplyToStrokeTargetType) && (!style || style->hasStroke()))
179 context->strokePath();
180 }
181
teardown(GraphicsContext * &,const RenderObject *,SVGPaintTargetType,bool) const182 void SVGPaintServer::teardown(GraphicsContext*&, const RenderObject*, SVGPaintTargetType, bool) const
183 {
184 #if PLATFORM(SKIA)
185 // FIXME: Move this into the GraphicsContext
186 // WebKit implicitly expects us to reset the path.
187 // For example in fillAndStrokePath() of RenderPath.cpp the path is
188 // added back to the context after filling. This is because internally it
189 // calls CGContextFillPath() which closes the path.
190 context->beginPath();
191 context->platformContext()->setGradient(0);
192 context->platformContext()->setPattern(0);
193 #endif
194 }
195
dashArrayFromRenderingStyle(const RenderStyle * style)196 DashArray dashArrayFromRenderingStyle(const RenderStyle* style)
197 {
198 DashArray array;
199
200 CSSValueList* dashes = style->svgStyle()->strokeDashArray();
201 if (dashes) {
202 CSSPrimitiveValue* dash = 0;
203 unsigned long len = dashes->length();
204 for (unsigned long i = 0; i < len; i++) {
205 dash = static_cast<CSSPrimitiveValue*>(dashes->itemWithoutBoundsCheck(i));
206 if (!dash)
207 continue;
208
209 array.append((float) dash->computeLengthFloat(const_cast<RenderStyle*>(style)));
210 }
211 }
212
213 return array;
214 }
215
216 } // namespace WebCore
217
218 #endif
219