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