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 "core/rendering/svg/SVGPathData.h"
22
23 #include "SVGNames.h"
24 #include "core/svg/SVGCircleElement.h"
25 #include "core/svg/SVGEllipseElement.h"
26 #include "core/svg/SVGLineElement.h"
27 #include "core/svg/SVGPathElement.h"
28 #include "core/svg/SVGPathUtilities.h"
29 #include "core/svg/SVGPolygonElement.h"
30 #include "core/svg/SVGPolylineElement.h"
31 #include "core/svg/SVGRectElement.h"
32 #include "platform/graphics/Path.h"
33 #include "wtf/HashMap.h"
34
35 namespace WebCore {
36
updatePathFromCircleElement(SVGElement * element,Path & path)37 static void updatePathFromCircleElement(SVGElement* element, Path& path)
38 {
39 SVGCircleElement* circle = toSVGCircleElement(element);
40
41 SVGLengthContext lengthContext(element);
42 float r = circle->rCurrentValue().value(lengthContext);
43 if (r > 0)
44 path.addEllipse(FloatRect(circle->cxCurrentValue().value(lengthContext) - r, circle->cyCurrentValue().value(lengthContext) - r, r * 2, r * 2));
45 }
46
updatePathFromEllipseElement(SVGElement * element,Path & path)47 static void updatePathFromEllipseElement(SVGElement* element, Path& path)
48 {
49 SVGEllipseElement* ellipse = toSVGEllipseElement(element);
50
51 SVGLengthContext lengthContext(element);
52 float rx = ellipse->rxCurrentValue().value(lengthContext);
53 if (rx <= 0)
54 return;
55 float ry = ellipse->ryCurrentValue().value(lengthContext);
56 if (ry <= 0)
57 return;
58 path.addEllipse(FloatRect(ellipse->cxCurrentValue().value(lengthContext) - rx, ellipse->cyCurrentValue().value(lengthContext) - ry, rx * 2, ry * 2));
59 }
60
updatePathFromLineElement(SVGElement * element,Path & path)61 static void updatePathFromLineElement(SVGElement* element, Path& path)
62 {
63 SVGLineElement* line = toSVGLineElement(element);
64
65 SVGLengthContext lengthContext(element);
66 path.moveTo(FloatPoint(line->x1CurrentValue().value(lengthContext), line->y1CurrentValue().value(lengthContext)));
67 path.addLineTo(FloatPoint(line->x2CurrentValue().value(lengthContext), line->y2CurrentValue().value(lengthContext)));
68 }
69
updatePathFromPathElement(SVGElement * element,Path & path)70 static void updatePathFromPathElement(SVGElement* element, Path& path)
71 {
72 buildPathFromByteStream(toSVGPathElement(element)->pathByteStream(), path);
73 }
74
updatePathFromPolygonElement(SVGElement * element,Path & path)75 static void updatePathFromPolygonElement(SVGElement* element, Path& path)
76 {
77 SVGPointList& points = toSVGPolygonElement(element)->pointsCurrentValue();
78 if (points.isEmpty())
79 return;
80
81 path.moveTo(points.first());
82
83 unsigned size = points.size();
84 for (unsigned i = 1; i < size; ++i)
85 path.addLineTo(points.at(i));
86
87 path.closeSubpath();
88 }
89
updatePathFromPolylineElement(SVGElement * element,Path & path)90 static void updatePathFromPolylineElement(SVGElement* element, Path& path)
91 {
92 SVGPointList& points = toSVGPolylineElement(element)->pointsCurrentValue();
93 if (points.isEmpty())
94 return;
95
96 path.moveTo(points.first());
97
98 unsigned size = points.size();
99 for (unsigned i = 1; i < size; ++i)
100 path.addLineTo(points.at(i));
101 }
102
updatePathFromRectElement(SVGElement * element,Path & path)103 static void updatePathFromRectElement(SVGElement* element, Path& path)
104 {
105 SVGRectElement* rect = toSVGRectElement(element);
106
107 SVGLengthContext lengthContext(element);
108 float width = rect->widthCurrentValue().value(lengthContext);
109 if (width <= 0)
110 return;
111 float height = rect->heightCurrentValue().value(lengthContext);
112 if (height <= 0)
113 return;
114 float x = rect->xCurrentValue().value(lengthContext);
115 float y = rect->yCurrentValue().value(lengthContext);
116 bool hasRx = rect->rxCurrentValue().value(lengthContext) > 0;
117 bool hasRy = rect->ryCurrentValue().value(lengthContext) > 0;
118 if (hasRx || hasRy) {
119 float rx = rect->rxCurrentValue().value(lengthContext);
120 float ry = rect->ryCurrentValue().value(lengthContext);
121 if (!hasRx)
122 rx = ry;
123 else if (!hasRy)
124 ry = rx;
125
126 path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry));
127 return;
128 }
129
130 path.addRect(FloatRect(x, y, width, height));
131 }
132
updatePathFromGraphicsElement(SVGElement * element,Path & path)133 void updatePathFromGraphicsElement(SVGElement* element, Path& path)
134 {
135 ASSERT(element);
136 ASSERT(path.isEmpty());
137
138 typedef void (*PathUpdateFunction)(SVGElement*, Path&);
139 static HashMap<StringImpl*, PathUpdateFunction>* map = 0;
140 if (!map) {
141 map = new HashMap<StringImpl*, PathUpdateFunction>;
142 map->set(SVGNames::circleTag.localName().impl(), updatePathFromCircleElement);
143 map->set(SVGNames::ellipseTag.localName().impl(), updatePathFromEllipseElement);
144 map->set(SVGNames::lineTag.localName().impl(), updatePathFromLineElement);
145 map->set(SVGNames::pathTag.localName().impl(), updatePathFromPathElement);
146 map->set(SVGNames::polygonTag.localName().impl(), updatePathFromPolygonElement);
147 map->set(SVGNames::polylineTag.localName().impl(), updatePathFromPolylineElement);
148 map->set(SVGNames::rectTag.localName().impl(), updatePathFromRectElement);
149 }
150
151 if (PathUpdateFunction pathUpdateFunction = map->get(element->localName().impl()))
152 (*pathUpdateFunction)(element, path);
153 }
154
155 } // namespace WebCore
156