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#include "SVGPathStringSource.h"
23
24#include "FloatPoint.h"
25#include "SVGParserUtilities.h"
26
27namespace WebCore {
28
29SVGPathStringSource::SVGPathStringSource(const String& string)
30 : m_string(string)
31 , m_is8BitSource(string.is8Bit())
32{
33 ASSERT(!string.isEmpty());
34
35 if (m_is8BitSource) {
36 m_current.m_character8 = string.characters8();
37 m_end.m_character8 = m_current.m_character8 + string.length();
38 } else {
39 m_current.m_character16 = string.characters16();
40 m_end.m_character16 = m_current.m_character16 + string.length();
41 }
42}
43
44bool SVGPathStringSource::hasMoreData() const
45{
46 if (m_is8BitSource)
47 return m_current.m_character8 < m_end.m_character8;
48 return m_current.m_character16 < m_end.m_character16;
49}
50
51bool SVGPathStringSource::moveToNextToken()
52{
53 if (m_is8BitSource)
54 return skipOptionalSVGSpaces(m_current.m_character8, m_end.m_character8);
55 return skipOptionalSVGSpaces(m_current.m_character16, m_end.m_character16);
56}
57
58template <typename CharacterType>
59static bool parseSVGSegmentTypeHelper(const CharacterType*& current, SVGPathSegType& pathSegType)
60{
61 switch (*(current++)) {
62 case 'Z':
63 case 'z':
64 pathSegType = PathSegClosePath;
65 break;
66 case 'M':
67 pathSegType = PathSegMoveToAbs;
68 break;
69 case 'm':
70 pathSegType = PathSegMoveToRel;
71 break;
72 case 'L':
73 pathSegType = PathSegLineToAbs;
74 break;
75 case 'l':
76 pathSegType = PathSegLineToRel;
77 break;
78 case 'C':
79 pathSegType = PathSegCurveToCubicAbs;
80 break;
81 case 'c':
82 pathSegType = PathSegCurveToCubicRel;
83 break;
84 case 'Q':
85 pathSegType = PathSegCurveToQuadraticAbs;
86 break;
87 case 'q':
88 pathSegType = PathSegCurveToQuadraticRel;
89 break;
90 case 'A':
91 pathSegType = PathSegArcAbs;
92 break;
93 case 'a':
94 pathSegType = PathSegArcRel;
95 break;
96 case 'H':
97 pathSegType = PathSegLineToHorizontalAbs;
98 break;
99 case 'h':
100 pathSegType = PathSegLineToHorizontalRel;
101 break;
102 case 'V':
103 pathSegType = PathSegLineToVerticalAbs;
104 break;
105 case 'v':
106 pathSegType = PathSegLineToVerticalRel;
107 break;
108 case 'S':
109 pathSegType = PathSegCurveToCubicSmoothAbs;
110 break;
111 case 's':
112 pathSegType = PathSegCurveToCubicSmoothRel;
113 break;
114 case 'T':
115 pathSegType = PathSegCurveToQuadraticSmoothAbs;
116 break;
117 case 't':
118 pathSegType = PathSegCurveToQuadraticSmoothRel;
119 break;
120 default:
121 pathSegType = PathSegUnknown;
122 }
123 return true;
124}
125
126bool SVGPathStringSource::parseSVGSegmentType(SVGPathSegType& pathSegType)
127{
128 if (m_is8BitSource)
129 return parseSVGSegmentTypeHelper(m_current.m_character8, pathSegType);
130 return parseSVGSegmentTypeHelper(m_current.m_character16, pathSegType);
131}
132
133template <typename CharacterType>
134static bool nextCommandHelper(const CharacterType*& current, SVGPathSegType previousCommand, SVGPathSegType& nextCommand)
135{
136 // Check for remaining coordinates in the current command.
137 if ((*current == '+' || *current == '-' || *current == '.' || isASCIIDigit(*current))
138 && previousCommand != PathSegClosePath) {
139 if (previousCommand == PathSegMoveToAbs) {
140 nextCommand = PathSegLineToAbs;
141 return true;
142 }
143 if (previousCommand == PathSegMoveToRel) {
144 nextCommand = PathSegLineToRel;
145 return true;
146 }
147 nextCommand = previousCommand;
148 return true;
149 }
150
151 return false;
152}
153
154SVGPathSegType SVGPathStringSource::nextCommand(SVGPathSegType previousCommand)
155{
156 SVGPathSegType nextCommand;
157 if (m_is8BitSource) {
158 if (nextCommandHelper(m_current.m_character8, previousCommand, nextCommand))
159 return nextCommand;
160 } else {
161 if (nextCommandHelper(m_current.m_character16, previousCommand, nextCommand))
162 return nextCommand;
163 }
164
165 parseSVGSegmentType(nextCommand);
166 return nextCommand;
167}
168
169bool SVGPathStringSource::parseMoveToSegment(FloatPoint& targetPoint)
170{
171 if (m_is8BitSource)
172 return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
173 return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
174}
175
176bool SVGPathStringSource::parseLineToSegment(FloatPoint& targetPoint)
177{
178 if (m_is8BitSource)
179 return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
180 return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
181}
182
183bool SVGPathStringSource::parseLineToHorizontalSegment(float& x)
184{
185 if (m_is8BitSource)
186 return parseNumber(m_current.m_character8, m_end.m_character8, x);
187 return parseNumber(m_current.m_character16, m_end.m_character16, x);
188}
189
190bool SVGPathStringSource::parseLineToVerticalSegment(float& y)
191{
192 if (m_is8BitSource)
193 return parseNumber(m_current.m_character8, m_end.m_character8, y);
194 return parseNumber(m_current.m_character16, m_end.m_character16, y);
195}
196
197bool SVGPathStringSource::parseCurveToCubicSegment(FloatPoint& point1, FloatPoint& point2, FloatPoint& targetPoint)
198{
199 if (m_is8BitSource)
200 return parseFloatPoint3(m_current.m_character8, m_end.m_character8, point1, point2, targetPoint);
201 return parseFloatPoint3(m_current.m_character16, m_end.m_character16, point1, point2, targetPoint);
202}
203
204bool SVGPathStringSource::parseCurveToCubicSmoothSegment(FloatPoint& point1, FloatPoint& targetPoint)
205{
206 if (m_is8BitSource)
207 return parseFloatPoint2(m_current.m_character8, m_end.m_character8, point1, targetPoint);
208 return parseFloatPoint2(m_current.m_character16, m_end.m_character16, point1, targetPoint);
209}
210
211bool SVGPathStringSource::parseCurveToQuadraticSegment(FloatPoint& point2, FloatPoint& targetPoint)
212{
213 if (m_is8BitSource)
214 return parseFloatPoint2(m_current.m_character8, m_end.m_character8, point2, targetPoint);
215 return parseFloatPoint2(m_current.m_character16, m_end.m_character16, point2, targetPoint);
216}
217
218bool SVGPathStringSource::parseCurveToQuadraticSmoothSegment(FloatPoint& targetPoint)
219{
220 if (m_is8BitSource)
221 return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
222 return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
223}
224
225template <typename CharacterType>
226static bool parseArcToSegmentHelper(const CharacterType*& current, const CharacterType* end, float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
227{
228 float toX;
229 float toY;
230 if (!parseNumber(current, end, rx)
231 || !parseNumber(current, end, ry)
232 || !parseNumber(current, end, angle)
233 || !parseArcFlag(current, end, largeArc)
234 || !parseArcFlag(current, end, sweep)
235 || !parseNumber(current, end, toX)
236 || !parseNumber(current, end, toY))
237 return false;
238 targetPoint = FloatPoint(toX, toY);
239 return true;
240}
241
242bool SVGPathStringSource::parseArcToSegment(float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
243{
244 if (m_is8BitSource)
245 return parseArcToSegmentHelper(m_current.m_character8, m_end.m_character8, rx, ry, angle, largeArc, sweep, targetPoint);
246 return parseArcToSegmentHelper(m_current.m_character16, m_end.m_character16, rx, ry, angle, largeArc, sweep, targetPoint);
247}
248
249} // namespace WebKit
250