1 /*
2 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #include "core/svg/SVGPathStringSource.h"
24
25 #include "core/svg/SVGParserUtilities.h"
26 #include "platform/geometry/FloatPoint.h"
27
28 namespace WebCore {
29
SVGPathStringSource(const String & string)30 SVGPathStringSource::SVGPathStringSource(const String& string)
31 : m_string(string)
32 , m_is8BitSource(string.is8Bit())
33 {
34 ASSERT(!string.isEmpty());
35
36 if (m_is8BitSource) {
37 m_current.m_character8 = string.characters8();
38 m_end.m_character8 = m_current.m_character8 + string.length();
39 } else {
40 m_current.m_character16 = string.characters16();
41 m_end.m_character16 = m_current.m_character16 + string.length();
42 }
43 }
44
hasMoreData() const45 bool SVGPathStringSource::hasMoreData() const
46 {
47 if (m_is8BitSource)
48 return m_current.m_character8 < m_end.m_character8;
49 return m_current.m_character16 < m_end.m_character16;
50 }
51
moveToNextToken()52 bool SVGPathStringSource::moveToNextToken()
53 {
54 if (m_is8BitSource)
55 return skipOptionalSVGSpaces(m_current.m_character8, m_end.m_character8);
56 return skipOptionalSVGSpaces(m_current.m_character16, m_end.m_character16);
57 }
58
59 template <typename CharacterType>
parseSVGSegmentTypeHelper(const CharacterType * & current,SVGPathSegType & pathSegType)60 static bool parseSVGSegmentTypeHelper(const CharacterType*& current, SVGPathSegType& pathSegType)
61 {
62 switch (*(current++)) {
63 case 'Z':
64 case 'z':
65 pathSegType = PathSegClosePath;
66 break;
67 case 'M':
68 pathSegType = PathSegMoveToAbs;
69 break;
70 case 'm':
71 pathSegType = PathSegMoveToRel;
72 break;
73 case 'L':
74 pathSegType = PathSegLineToAbs;
75 break;
76 case 'l':
77 pathSegType = PathSegLineToRel;
78 break;
79 case 'C':
80 pathSegType = PathSegCurveToCubicAbs;
81 break;
82 case 'c':
83 pathSegType = PathSegCurveToCubicRel;
84 break;
85 case 'Q':
86 pathSegType = PathSegCurveToQuadraticAbs;
87 break;
88 case 'q':
89 pathSegType = PathSegCurveToQuadraticRel;
90 break;
91 case 'A':
92 pathSegType = PathSegArcAbs;
93 break;
94 case 'a':
95 pathSegType = PathSegArcRel;
96 break;
97 case 'H':
98 pathSegType = PathSegLineToHorizontalAbs;
99 break;
100 case 'h':
101 pathSegType = PathSegLineToHorizontalRel;
102 break;
103 case 'V':
104 pathSegType = PathSegLineToVerticalAbs;
105 break;
106 case 'v':
107 pathSegType = PathSegLineToVerticalRel;
108 break;
109 case 'S':
110 pathSegType = PathSegCurveToCubicSmoothAbs;
111 break;
112 case 's':
113 pathSegType = PathSegCurveToCubicSmoothRel;
114 break;
115 case 'T':
116 pathSegType = PathSegCurveToQuadraticSmoothAbs;
117 break;
118 case 't':
119 pathSegType = PathSegCurveToQuadraticSmoothRel;
120 break;
121 default:
122 pathSegType = PathSegUnknown;
123 }
124 return true;
125 }
126
parseSVGSegmentType(SVGPathSegType & pathSegType)127 bool SVGPathStringSource::parseSVGSegmentType(SVGPathSegType& pathSegType)
128 {
129 if (m_is8BitSource)
130 return parseSVGSegmentTypeHelper(m_current.m_character8, pathSegType);
131 return parseSVGSegmentTypeHelper(m_current.m_character16, pathSegType);
132 }
133
134 template <typename CharacterType>
nextCommandHelper(const CharacterType * & current,SVGPathSegType previousCommand,SVGPathSegType & nextCommand)135 static bool nextCommandHelper(const CharacterType*& current, SVGPathSegType previousCommand, SVGPathSegType& nextCommand)
136 {
137 // Check for remaining coordinates in the current command.
138 if ((*current == '+' || *current == '-' || *current == '.' || (*current >= '0' && *current <= '9'))
139 && previousCommand != PathSegClosePath) {
140 if (previousCommand == PathSegMoveToAbs) {
141 nextCommand = PathSegLineToAbs;
142 return true;
143 }
144 if (previousCommand == PathSegMoveToRel) {
145 nextCommand = PathSegLineToRel;
146 return true;
147 }
148 nextCommand = previousCommand;
149 return true;
150 }
151
152 return false;
153 }
154
nextCommand(SVGPathSegType previousCommand)155 SVGPathSegType SVGPathStringSource::nextCommand(SVGPathSegType previousCommand)
156 {
157 SVGPathSegType nextCommand;
158 if (m_is8BitSource) {
159 if (nextCommandHelper(m_current.m_character8, previousCommand, nextCommand))
160 return nextCommand;
161 } else {
162 if (nextCommandHelper(m_current.m_character16, previousCommand, nextCommand))
163 return nextCommand;
164 }
165
166 parseSVGSegmentType(nextCommand);
167 return nextCommand;
168 }
169
parseMoveToSegment(FloatPoint & targetPoint)170 bool SVGPathStringSource::parseMoveToSegment(FloatPoint& targetPoint)
171 {
172 if (m_is8BitSource)
173 return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
174 return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
175 }
176
parseLineToSegment(FloatPoint & targetPoint)177 bool SVGPathStringSource::parseLineToSegment(FloatPoint& targetPoint)
178 {
179 if (m_is8BitSource)
180 return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
181 return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
182 }
183
parseLineToHorizontalSegment(float & x)184 bool SVGPathStringSource::parseLineToHorizontalSegment(float& x)
185 {
186 if (m_is8BitSource)
187 return parseNumber(m_current.m_character8, m_end.m_character8, x);
188 return parseNumber(m_current.m_character16, m_end.m_character16, x);
189 }
190
parseLineToVerticalSegment(float & y)191 bool SVGPathStringSource::parseLineToVerticalSegment(float& y)
192 {
193 if (m_is8BitSource)
194 return parseNumber(m_current.m_character8, m_end.m_character8, y);
195 return parseNumber(m_current.m_character16, m_end.m_character16, y);
196 }
197
parseCurveToCubicSegment(FloatPoint & point1,FloatPoint & point2,FloatPoint & targetPoint)198 bool SVGPathStringSource::parseCurveToCubicSegment(FloatPoint& point1, FloatPoint& point2, FloatPoint& targetPoint)
199 {
200 if (m_is8BitSource)
201 return parseFloatPoint3(m_current.m_character8, m_end.m_character8, point1, point2, targetPoint);
202 return parseFloatPoint3(m_current.m_character16, m_end.m_character16, point1, point2, targetPoint);
203 }
204
parseCurveToCubicSmoothSegment(FloatPoint & point1,FloatPoint & targetPoint)205 bool SVGPathStringSource::parseCurveToCubicSmoothSegment(FloatPoint& point1, FloatPoint& targetPoint)
206 {
207 if (m_is8BitSource)
208 return parseFloatPoint2(m_current.m_character8, m_end.m_character8, point1, targetPoint);
209 return parseFloatPoint2(m_current.m_character16, m_end.m_character16, point1, targetPoint);
210 }
211
parseCurveToQuadraticSegment(FloatPoint & point2,FloatPoint & targetPoint)212 bool SVGPathStringSource::parseCurveToQuadraticSegment(FloatPoint& point2, FloatPoint& targetPoint)
213 {
214 if (m_is8BitSource)
215 return parseFloatPoint2(m_current.m_character8, m_end.m_character8, point2, targetPoint);
216 return parseFloatPoint2(m_current.m_character16, m_end.m_character16, point2, targetPoint);
217 }
218
parseCurveToQuadraticSmoothSegment(FloatPoint & targetPoint)219 bool SVGPathStringSource::parseCurveToQuadraticSmoothSegment(FloatPoint& targetPoint)
220 {
221 if (m_is8BitSource)
222 return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
223 return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
224 }
225
226 template <typename CharacterType>
parseArcToSegmentHelper(const CharacterType * & current,const CharacterType * end,float & rx,float & ry,float & angle,bool & largeArc,bool & sweep,FloatPoint & targetPoint)227 static bool parseArcToSegmentHelper(const CharacterType*& current, const CharacterType* end, float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
228 {
229 float toX;
230 float toY;
231 if (!parseNumber(current, end, rx)
232 || !parseNumber(current, end, ry)
233 || !parseNumber(current, end, angle)
234 || !parseArcFlag(current, end, largeArc)
235 || !parseArcFlag(current, end, sweep)
236 || !parseNumber(current, end, toX)
237 || !parseNumber(current, end, toY))
238 return false;
239 targetPoint = FloatPoint(toX, toY);
240 return true;
241 }
242
parseArcToSegment(float & rx,float & ry,float & angle,bool & largeArc,bool & sweep,FloatPoint & targetPoint)243 bool SVGPathStringSource::parseArcToSegment(float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
244 {
245 if (m_is8BitSource)
246 return parseArcToSegmentHelper(m_current.m_character8, m_end.m_character8, rx, ry, angle, largeArc, sweep, targetPoint);
247 return parseArcToSegmentHelper(m_current.m_character16, m_end.m_character16, rx, ry, angle, largeArc, sweep, targetPoint);
248 }
249
250 } // namespace blink
251