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.
22 #include "core/svg/SVGPathStringSource.h"
24 #include "core/svg/SVGParserUtilities.h"
25 #include "platform/geometry/FloatPoint.h"
29 SVGPathStringSource::SVGPathStringSource(const String
& string
)
31 , m_is8BitSource(string
.is8Bit())
33 , m_previousCommand(PathSegUnknown
)
35 ASSERT(!string
.isEmpty());
38 m_current
.m_character8
= string
.characters8();
39 m_end
.m_character8
= m_current
.m_character8
+ string
.length();
41 m_current
.m_character16
= string
.characters16();
42 m_end
.m_character16
= m_current
.m_character16
+ string
.length();
47 bool SVGPathStringSource::hasMoreData() const
50 return m_current
.m_character8
< m_end
.m_character8
;
51 return m_current
.m_character16
< m_end
.m_character16
;
54 void SVGPathStringSource::eatWhitespace()
57 skipOptionalSVGSpaces(m_current
.m_character8
, m_end
.m_character8
);
59 skipOptionalSVGSpaces(m_current
.m_character16
, m_end
.m_character16
);
62 static SVGPathSegType
parseSVGSegmentTypeHelper(unsigned lookahead
)
67 return PathSegClosePath
;
69 return PathSegMoveToAbs
;
71 return PathSegMoveToRel
;
73 return PathSegLineToAbs
;
75 return PathSegLineToRel
;
77 return PathSegCurveToCubicAbs
;
79 return PathSegCurveToCubicRel
;
81 return PathSegCurveToQuadraticAbs
;
83 return PathSegCurveToQuadraticRel
;
89 return PathSegLineToHorizontalAbs
;
91 return PathSegLineToHorizontalRel
;
93 return PathSegLineToVerticalAbs
;
95 return PathSegLineToVerticalRel
;
97 return PathSegCurveToCubicSmoothAbs
;
99 return PathSegCurveToCubicSmoothRel
;
101 return PathSegCurveToQuadraticSmoothAbs
;
103 return PathSegCurveToQuadraticSmoothRel
;
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
;
118 if (previousCommand
== PathSegMoveToRel
) {
119 nextCommand
= PathSegLineToRel
;
122 nextCommand
= previousCommand
;
128 float SVGPathStringSource::parseNumberWithError()
130 float numberValue
= 0;
132 m_seenError
|= !parseNumber(m_current
.m_character8
, m_end
.m_character8
, numberValue
);
134 m_seenError
|= !parseNumber(m_current
.m_character16
, m_end
.m_character16
, numberValue
);
138 bool SVGPathStringSource::parseArcFlagWithError()
140 bool flagValue
= false;
142 m_seenError
|= !parseArcFlag(m_current
.m_character8
, m_end
.m_character8
, flagValue
);
144 m_seenError
|= !parseArcFlag(m_current
.m_character16
, m_end
.m_character16
, 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
)
166 if (!nextCommandHelper(lookahead
, m_previousCommand
, command
))
169 // Valid explicit command.
171 m_current
.m_character8
++;
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());
186 case PathSegCurveToCubicSmoothRel
:
187 case PathSegCurveToCubicSmoothAbs
:
188 segment
.point2
.setX(parseNumberWithError());
189 segment
.point2
.setY(parseNumberWithError());
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());
200 case PathSegLineToHorizontalRel
:
201 case PathSegLineToHorizontalAbs
:
202 segment
.targetPoint
.setX(parseNumberWithError());
204 case PathSegLineToVerticalRel
:
205 case PathSegLineToVerticalAbs
:
206 segment
.targetPoint
.setY(parseNumberWithError());
208 case PathSegClosePath
:
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());
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());
229 ASSERT_NOT_REACHED();
232 if (UNLIKELY(m_seenError
))
233 segment
.command
= PathSegUnknown
;