2 * Copyright (C) 2002, 2003 The Karbon Developers
3 * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
4 * Copyright (C) 2006, 2007 Rob Buis <buis@kde.org>
5 * Copyright (C) 2007, 2009, 2013 Apple Inc. All rights reserved.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
24 #include "core/svg/SVGParserUtilities.h"
26 #include "core/svg/SVGPointList.h"
27 #include "platform/geometry/FloatRect.h"
28 #include "platform/transforms/AffineTransform.h"
29 #include "wtf/ASCIICType.h"
30 #include "wtf/text/StringHash.h"
35 template <typename FloatType>
36 static inline bool isValidRange(const FloatType& x)
38 static const FloatType max = std::numeric_limits<FloatType>::max();
39 return x >= -max && x <= max;
42 // We use this generic parseNumber function to allow the Path parsing code to work
43 // at a higher precision internally, without any unnecessary runtime cost or code
45 template <typename CharType, typename FloatType>
46 static bool genericParseNumber(const CharType*& ptr, const CharType* end, FloatType& number, WhitespaceMode mode)
48 FloatType integer, decimal, frac, exponent;
50 const CharType* start = ptr;
59 if (mode & AllowLeadingWhitespace)
60 skipOptionalSVGSpaces(ptr, end);
63 if (ptr < end && *ptr == '+')
65 else if (ptr < end && *ptr == '-') {
70 if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.'))
71 // The first character of a number must be one of [0-9+-.]
74 // read the integer part, build right-to-left
75 const CharType* ptrStartIntPart = ptr;
76 while (ptr < end && *ptr >= '0' && *ptr <= '9')
77 ++ptr; // Advance to first non-digit.
79 if (ptr != ptrStartIntPart) {
80 const CharType* ptrScanIntPart = ptr - 1;
81 FloatType multiplier = 1;
82 while (ptrScanIntPart >= ptrStartIntPart) {
83 integer += multiplier * static_cast<FloatType>(*(ptrScanIntPart--) - '0');
86 // Bail out early if this overflows.
87 if (!isValidRange(integer))
91 if (ptr < end && *ptr == '.') { // read the decimals
94 // There must be a least one digit following the .
95 if (ptr >= end || *ptr < '0' || *ptr > '9')
98 while (ptr < end && *ptr >= '0' && *ptr <= '9')
99 decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1));
102 // read the exponent part
103 if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E')
104 && (ptr[1] != 'x' && ptr[1] != 'm')) {
107 // read the sign of the exponent
110 else if (*ptr == '-') {
115 // There must be an exponent
116 if (ptr >= end || *ptr < '0' || *ptr > '9')
119 while (ptr < end && *ptr >= '0' && *ptr <= '9') {
120 exponent *= static_cast<FloatType>(10);
121 exponent += *ptr - '0';
124 // Make sure exponent is valid.
125 if (!isValidRange(exponent) || exponent > std::numeric_limits<FloatType>::max_exponent)
129 number = integer + decimal;
133 number *= static_cast<FloatType>(pow(10.0, expsign * static_cast<int>(exponent)));
135 // Don't return Infinity() or NaN().
136 if (!isValidRange(number))
142 if (mode & AllowTrailingWhitespace)
143 skipOptionalSVGSpacesOrDelimiter(ptr, end);
148 bool parseNumber(const LChar*& ptr, const LChar* end, float& number, WhitespaceMode mode)
150 return genericParseNumber(ptr, end, number, mode);
153 bool parseNumber(const UChar*& ptr, const UChar* end, float& number, WhitespaceMode mode)
155 return genericParseNumber(ptr, end, number, mode);
158 // only used to parse largeArcFlag and sweepFlag which must be a "0" or "1"
159 // and might not have any whitespace/comma after it
160 template <typename CharType>
161 bool genericParseArcFlag(const CharType*& ptr, const CharType* end, bool& flag)
165 const CharType flagChar = *ptr++;
168 else if (flagChar == '1')
173 skipOptionalSVGSpacesOrDelimiter(ptr, end);
178 bool parseArcFlag(const LChar*& ptr, const LChar* end, bool& flag)
180 return genericParseArcFlag(ptr, end, flag);
183 bool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag)
185 return genericParseArcFlag(ptr, end, flag);
188 template<typename CharType>
189 static bool genericParseNumberOptionalNumber(const CharType*& ptr, const CharType* end, float& x, float& y)
191 if (!parseNumber(ptr, end, x))
196 else if (!parseNumber(ptr, end, y, AllowLeadingAndTrailingWhitespace))
202 bool parseNumberOptionalNumber(const String& string, float& x, float& y)
204 if (string.isEmpty())
207 if (string.is8Bit()) {
208 const LChar* ptr = string.characters8();
209 const LChar* end = ptr + string.length();
210 return genericParseNumberOptionalNumber(ptr, end, x, y);
212 const UChar* ptr = string.characters16();
213 const UChar* end = ptr + string.length();
214 return genericParseNumberOptionalNumber(ptr, end, x, y);
217 template<typename CharType>
218 bool genericParseNumberOrPercentage(const CharType*& ptr, const CharType* end, float& number)
220 if (genericParseNumber(ptr, end, number, AllowLeadingWhitespace)) {
224 bool isPercentage = (*ptr == '%');
228 skipOptionalSVGSpaces(ptr, end);
239 bool parseNumberOrPercentage(const String& string, float& number)
241 if (string.isEmpty())
244 if (string.is8Bit()) {
245 const LChar* ptr = string.characters8();
246 const LChar* end = ptr + string.length();
247 return genericParseNumberOrPercentage(ptr, end, number);
249 const UChar* ptr = string.characters16();
250 const UChar* end = ptr + string.length();
251 return genericParseNumberOrPercentage(ptr, end, number);
254 template <typename CharType>
255 bool parseFloatPoint(const CharType*& current, const CharType* end, FloatPoint& point)
259 if (!parseNumber(current, end, x)
260 || !parseNumber(current, end, y))
262 point = FloatPoint(x, y);
266 template bool parseFloatPoint(const LChar*& current, const LChar* end, FloatPoint& point1);
267 template bool parseFloatPoint(const UChar*& current, const UChar* end, FloatPoint& point1);
269 template <typename CharType>
270 inline bool parseFloatPoint2(const CharType*& current, const CharType* end, FloatPoint& point1, FloatPoint& point2)
276 if (!parseNumber(current, end, x1)
277 || !parseNumber(current, end, y1)
278 || !parseNumber(current, end, x2)
279 || !parseNumber(current, end, y2))
281 point1 = FloatPoint(x1, y1);
282 point2 = FloatPoint(x2, y2);
286 template bool parseFloatPoint2(const LChar*& current, const LChar* end, FloatPoint& point1, FloatPoint& point2);
287 template bool parseFloatPoint2(const UChar*& current, const UChar* end, FloatPoint& point1, FloatPoint& point2);
289 template <typename CharType>
290 bool parseFloatPoint3(const CharType*& current, const CharType* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3)
298 if (!parseNumber(current, end, x1)
299 || !parseNumber(current, end, y1)
300 || !parseNumber(current, end, x2)
301 || !parseNumber(current, end, y2)
302 || !parseNumber(current, end, x3)
303 || !parseNumber(current, end, y3))
305 point1 = FloatPoint(x1, y1);
306 point2 = FloatPoint(x2, y2);
307 point3 = FloatPoint(x3, y3);
311 template bool parseFloatPoint3(const LChar*& current, const LChar* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3);
312 template bool parseFloatPoint3(const UChar*& current, const UChar* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3);
314 static const LChar skewXDesc[] = {'s', 'k', 'e', 'w', 'X'};
315 static const LChar skewYDesc[] = {'s', 'k', 'e', 'w', 'Y'};
316 static const LChar scaleDesc[] = {'s', 'c', 'a', 'l', 'e'};
317 static const LChar translateDesc[] = {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'};
318 static const LChar rotateDesc[] = {'r', 'o', 't', 'a', 't', 'e'};
319 static const LChar matrixDesc[] = {'m', 'a', 't', 'r', 'i', 'x'};
321 template<typename CharType>
322 bool parseAndSkipTransformType(const CharType*& ptr, const CharType* end, SVGTransformType& type)
328 if (skipString(ptr, end, skewXDesc, WTF_ARRAY_LENGTH(skewXDesc)))
329 type = SVG_TRANSFORM_SKEWX;
330 else if (skipString(ptr, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc)))
331 type = SVG_TRANSFORM_SKEWY;
332 else if (skipString(ptr, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc)))
333 type = SVG_TRANSFORM_SCALE;
336 } else if (skipString(ptr, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc)))
337 type = SVG_TRANSFORM_TRANSLATE;
338 else if (skipString(ptr, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc)))
339 type = SVG_TRANSFORM_ROTATE;
340 else if (skipString(ptr, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc)))
341 type = SVG_TRANSFORM_MATRIX;
348 template bool parseAndSkipTransformType(const UChar*& current, const UChar* end, SVGTransformType&);
349 template bool parseAndSkipTransformType(const LChar*& current, const LChar* end, SVGTransformType&);
351 SVGTransformType parseTransformType(const String& string)
353 if (string.isEmpty())
354 return SVG_TRANSFORM_UNKNOWN;
355 SVGTransformType type = SVG_TRANSFORM_UNKNOWN;
356 if (string.is8Bit()) {
357 const LChar* ptr = string.characters8();
358 const LChar* end = ptr + string.length();
359 parseAndSkipTransformType(ptr, end, type);
361 const UChar* ptr = string.characters16();
362 const UChar* end = ptr + string.length();
363 parseAndSkipTransformType(ptr, end, type);