Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / svg / SVGPathStringSource.cpp
blob069640ead9f61b2356281350276d4ce9c4ebcecc
1 /*
2 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3 * Copyright (C) 2013 Apple Inc. All rights reserved.
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.
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.
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.
21 #include "config.h"
22 #include "core/svg/SVGPathStringSource.h"
24 #include "core/svg/SVGParserUtilities.h"
25 #include "platform/geometry/FloatPoint.h"
27 namespace blink {
29 SVGPathStringSource::SVGPathStringSource(const String& string)
30 : m_string(string)
31 , m_is8BitSource(string.is8Bit())
32 , m_seenError(false)
33 , m_previousCommand(PathSegUnknown)
35 ASSERT(!string.isEmpty());
37 if (m_is8BitSource) {
38 m_current.m_character8 = string.characters8();
39 m_end.m_character8 = m_current.m_character8 + string.length();
40 } else {
41 m_current.m_character16 = string.characters16();
42 m_end.m_character16 = m_current.m_character16 + string.length();
44 eatWhitespace();
47 bool SVGPathStringSource::hasMoreData() const
49 if (m_is8BitSource)
50 return m_current.m_character8 < m_end.m_character8;
51 return m_current.m_character16 < m_end.m_character16;
54 void SVGPathStringSource::eatWhitespace()
56 if (m_is8BitSource)
57 skipOptionalSVGSpaces(m_current.m_character8, m_end.m_character8);
58 else
59 skipOptionalSVGSpaces(m_current.m_character16, m_end.m_character16);
62 static SVGPathSegType parseSVGSegmentTypeHelper(unsigned lookahead)
64 switch (lookahead) {
65 case 'Z':
66 case 'z':
67 return PathSegClosePath;
68 case 'M':
69 return PathSegMoveToAbs;
70 case 'm':
71 return PathSegMoveToRel;
72 case 'L':
73 return PathSegLineToAbs;
74 case 'l':
75 return PathSegLineToRel;
76 case 'C':
77 return PathSegCurveToCubicAbs;
78 case 'c':
79 return PathSegCurveToCubicRel;
80 case 'Q':
81 return PathSegCurveToQuadraticAbs;
82 case 'q':
83 return PathSegCurveToQuadraticRel;
84 case 'A':
85 return PathSegArcAbs;
86 case 'a':
87 return PathSegArcRel;
88 case 'H':
89 return PathSegLineToHorizontalAbs;
90 case 'h':
91 return PathSegLineToHorizontalRel;
92 case 'V':
93 return PathSegLineToVerticalAbs;
94 case 'v':
95 return PathSegLineToVerticalRel;
96 case 'S':
97 return PathSegCurveToCubicSmoothAbs;
98 case 's':
99 return PathSegCurveToCubicSmoothRel;
100 case 'T':
101 return PathSegCurveToQuadraticSmoothAbs;
102 case 't':
103 return PathSegCurveToQuadraticSmoothRel;
104 default:
105 return PathSegUnknown;
109 static bool nextCommandHelper(unsigned lookahead, SVGPathSegType previousCommand, SVGPathSegType& nextCommand)
111 // Check for remaining coordinates in the current command.
112 if ((lookahead == '+' || lookahead == '-' || lookahead == '.' || (lookahead >= '0' && lookahead <= '9'))
113 && previousCommand != PathSegClosePath) {
114 if (previousCommand == PathSegMoveToAbs) {
115 nextCommand = PathSegLineToAbs;
116 return true;
118 if (previousCommand == PathSegMoveToRel) {
119 nextCommand = PathSegLineToRel;
120 return true;
122 nextCommand = previousCommand;
123 return true;
125 return false;
128 float SVGPathStringSource::parseNumberWithError()
130 float numberValue = 0;
131 if (m_is8BitSource)
132 m_seenError |= !parseNumber(m_current.m_character8, m_end.m_character8, numberValue);
133 else
134 m_seenError |= !parseNumber(m_current.m_character16, m_end.m_character16, numberValue);
135 return numberValue;
138 bool SVGPathStringSource::parseArcFlagWithError()
140 bool flagValue = false;
141 if (m_is8BitSource)
142 m_seenError |= !parseArcFlag(m_current.m_character8, m_end.m_character8, flagValue);
143 else
144 m_seenError |= !parseArcFlag(m_current.m_character16, m_end.m_character16, flagValue);
145 return flagValue;
148 SVGPathSegType SVGPathStringSource::peekSegmentType()
150 ASSERT(hasMoreData());
151 // This won't work in all cases because of the state required to "detect" implicit commands.
152 unsigned lookahead = m_is8BitSource ? *m_current.m_character8 : *m_current.m_character16;
153 return parseSVGSegmentTypeHelper(lookahead);
156 PathSegmentData SVGPathStringSource::parseSegment()
158 ASSERT(hasMoreData());
159 PathSegmentData segment;
160 unsigned lookahead = m_is8BitSource ? *m_current.m_character8 : *m_current.m_character16;
161 SVGPathSegType command = parseSVGSegmentTypeHelper(lookahead);
162 if (command == PathSegUnknown) {
163 // Possibly an implicit command. Not allowed if this is the first command.
164 if (m_previousCommand == PathSegUnknown)
165 return segment;
166 if (!nextCommandHelper(lookahead, m_previousCommand, command))
167 return segment;
168 } else {
169 // Valid explicit command.
170 if (m_is8BitSource)
171 m_current.m_character8++;
172 else
173 m_current.m_character16++;
176 segment.command = m_previousCommand = command;
178 ASSERT(!m_seenError);
180 switch (segment.command) {
181 case PathSegCurveToCubicRel:
182 case PathSegCurveToCubicAbs:
183 segment.point1.setX(parseNumberWithError());
184 segment.point1.setY(parseNumberWithError());
185 /* fall through */
186 case PathSegCurveToCubicSmoothRel:
187 case PathSegCurveToCubicSmoothAbs:
188 segment.point2.setX(parseNumberWithError());
189 segment.point2.setY(parseNumberWithError());
190 /* fall through */
191 case PathSegMoveToRel:
192 case PathSegMoveToAbs:
193 case PathSegLineToRel:
194 case PathSegLineToAbs:
195 case PathSegCurveToQuadraticSmoothRel:
196 case PathSegCurveToQuadraticSmoothAbs:
197 segment.targetPoint.setX(parseNumberWithError());
198 segment.targetPoint.setY(parseNumberWithError());
199 break;
200 case PathSegLineToHorizontalRel:
201 case PathSegLineToHorizontalAbs:
202 segment.targetPoint.setX(parseNumberWithError());
203 break;
204 case PathSegLineToVerticalRel:
205 case PathSegLineToVerticalAbs:
206 segment.targetPoint.setY(parseNumberWithError());
207 break;
208 case PathSegClosePath:
209 eatWhitespace();
210 break;
211 case PathSegCurveToQuadraticRel:
212 case PathSegCurveToQuadraticAbs:
213 segment.point1.setX(parseNumberWithError());
214 segment.point1.setY(parseNumberWithError());
215 segment.targetPoint.setX(parseNumberWithError());
216 segment.targetPoint.setY(parseNumberWithError());
217 break;
218 case PathSegArcRel:
219 case PathSegArcAbs:
220 segment.point1.setX(parseNumberWithError()); // rx
221 segment.point1.setY(parseNumberWithError()); // ry
222 segment.point2.setX(parseNumberWithError()); // angle
223 segment.arcLarge = parseArcFlagWithError();
224 segment.arcSweep = parseArcFlagWithError();
225 segment.targetPoint.setX(parseNumberWithError());
226 segment.targetPoint.setY(parseNumberWithError());
227 break;
228 case PathSegUnknown:
229 ASSERT_NOT_REACHED();
232 if (UNLIKELY(m_seenError))
233 segment.command = PathSegUnknown;
234 return segment;
237 } // namespace blink