Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / rendering / svg / SVGPathData.cpp
1 /*
2  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "SVGPathData.h"
22
23 #include "Path.h"
24 #include "RenderElement.h"
25 #include "RenderStyle.h"
26 #include "SVGCircleElement.h"
27 #include "SVGEllipseElement.h"
28 #include "SVGLengthContext.h"
29 #include "SVGLineElement.h"
30 #include "SVGNames.h"
31 #include "SVGPathElement.h"
32 #include "SVGPathUtilities.h"
33 #include "SVGPoint.h"
34 #include "SVGPointList.h"
35 #include "SVGPolygonElement.h"
36 #include "SVGPolylineElement.h"
37 #include "SVGRectElement.h"
38 #include <wtf/HashMap.h>
39
40 namespace WebCore {
41
42 static Path pathFromCircleElement(const SVGElement& element)
43 {
44     ASSERT(is<SVGCircleElement>(element));
45
46     RenderElement* renderer = element.renderer();
47     if (!renderer)
48         return { };
49
50     Path path;
51     auto& style = renderer->style();
52     SVGLengthContext lengthContext(&element);
53     float r = lengthContext.valueForLength(style.svgStyle().r());
54     if (r > 0) {
55         float cx = lengthContext.valueForLength(style.svgStyle().cx(), LengthModeWidth);
56         float cy = lengthContext.valueForLength(style.svgStyle().cy(), LengthModeHeight);
57         path.addEllipse(FloatRect(cx - r, cy - r, r * 2, r * 2));
58     }
59     return path;
60 }
61
62 static Path pathFromEllipseElement(const SVGElement& element)
63 {
64     RenderElement* renderer = element.renderer();
65     if (!renderer)
66         return { };
67
68     auto& style = renderer->style();
69     SVGLengthContext lengthContext(&element);
70     float rx = lengthContext.valueForLength(style.svgStyle().rx(), LengthModeWidth);
71     if (rx <= 0)
72         return { };
73
74     float ry = lengthContext.valueForLength(style.svgStyle().ry(), LengthModeHeight);
75     if (ry <= 0)
76         return { };
77
78     Path path;
79     float cx = lengthContext.valueForLength(style.svgStyle().cx(), LengthModeWidth);
80     float cy = lengthContext.valueForLength(style.svgStyle().cy(), LengthModeHeight);
81     path.addEllipse(FloatRect(cx - rx, cy - ry, rx * 2, ry * 2));
82     return path;
83 }
84
85 static Path pathFromLineElement(const SVGElement& element)
86 {
87     Path path;
88     const auto& line = downcast<SVGLineElement>(element);
89
90     SVGLengthContext lengthContext(&element);
91     path.moveTo(FloatPoint(line.x1().value(lengthContext), line.y1().value(lengthContext)));
92     path.addLineTo(FloatPoint(line.x2().value(lengthContext), line.y2().value(lengthContext)));
93     return path;
94 }
95
96 static Path pathFromPathElement(const SVGElement& element)
97 {
98     return downcast<SVGPathElement>(element).path();
99 }
100
101 static Path pathFromPolygonElement(const SVGElement& element)
102 {
103     auto& points = downcast<SVGPolygonElement>(element).points().items();
104     if (points.isEmpty())
105         return { };
106
107     Path path;
108     path.moveTo(points.first()->value());
109
110     unsigned size = points.size();
111     for (unsigned i = 1; i < size; ++i)
112         path.addLineTo(points.at(i)->value());
113
114     path.closeSubpath();
115     return path;
116 }
117
118 static Path pathFromPolylineElement(const SVGElement& element)
119 {
120     auto& points = downcast<SVGPolylineElement>(element).points().items();
121     if (points.isEmpty())
122         return { };
123
124     Path path;
125     path.moveTo(points.first()->value());
126
127     unsigned size = points.size();
128     for (unsigned i = 1; i < size; ++i)
129         path.addLineTo(points.at(i)->value());
130     return path;
131 }
132
133 static Path pathFromRectElement(const SVGElement& element)
134 {
135     RenderElement* renderer = element.renderer();
136     if (!renderer)
137         return { };
138
139     auto& style = renderer->style();
140     SVGLengthContext lengthContext(&element);
141     float width = lengthContext.valueForLength(style.width(), LengthModeWidth);
142     if (width <= 0)
143         return { };
144
145     float height = lengthContext.valueForLength(style.height(), LengthModeHeight);
146     if (height <= 0)
147         return { };
148
149     Path path;
150     float x = lengthContext.valueForLength(style.svgStyle().x(), LengthModeWidth);
151     float y = lengthContext.valueForLength(style.svgStyle().y(), LengthModeHeight);
152     float rx = lengthContext.valueForLength(style.svgStyle().rx(), LengthModeWidth);
153     float ry = lengthContext.valueForLength(style.svgStyle().ry(), LengthModeHeight);
154     bool hasRx = rx > 0;
155     bool hasRy = ry > 0;
156     if (hasRx || hasRy) {
157         if (!hasRx)
158             rx = ry;
159         else if (!hasRy)
160             ry = rx;
161         // FIXME: We currently enforce using beziers here, as at least on CoreGraphics/Lion, as
162         // the native method uses a different line dash origin, causing svg/custom/dashOrigin.svg to fail.
163         // See bug https://bugs.webkit.org/show_bug.cgi?id=79932 which tracks this issue.
164         path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry), Path::PreferBezierRoundedRect);
165         return path;
166     }
167
168     path.addRect(FloatRect(x, y, width, height));
169     return path;
170 }
171
172 Path pathFromGraphicsElement(const SVGElement* element)
173 {
174     ASSERT(element);
175
176     typedef Path (*PathFromFunction)(const SVGElement&);
177     static HashMap<AtomStringImpl*, PathFromFunction>* map = 0;
178     if (!map) {
179         map = new HashMap<AtomStringImpl*, PathFromFunction>;
180         map->set(SVGNames::circleTag->localName().impl(), pathFromCircleElement);
181         map->set(SVGNames::ellipseTag->localName().impl(), pathFromEllipseElement);
182         map->set(SVGNames::lineTag->localName().impl(), pathFromLineElement);
183         map->set(SVGNames::pathTag->localName().impl(), pathFromPathElement);
184         map->set(SVGNames::polygonTag->localName().impl(), pathFromPolygonElement);
185         map->set(SVGNames::polylineTag->localName().impl(), pathFromPolylineElement);
186         map->set(SVGNames::rectTag->localName().impl(), pathFromRectElement);
187     }
188
189     if (PathFromFunction pathFromFunction = map->get(element->localName().impl()))
190         return (*pathFromFunction)(*element);
191     
192     return { };
193 }
194
195 } // namespace WebCore