• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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.
6  *
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.
11  *
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.
16  *
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.
21  */
22 
23 #include "config.h"
24 #include "core/svg/SVGParserUtilities.h"
25 
26 #include "core/dom/Document.h"
27 #include "core/svg/SVGPointList.h"
28 #include "core/svg/SVGTransformList.h"
29 #include "platform/geometry/FloatRect.h"
30 #include "platform/transforms/AffineTransform.h"
31 #include "wtf/ASCIICType.h"
32 #include <limits>
33 
34 namespace WebCore {
35 
36 template <typename FloatType>
isValidRange(const FloatType & x)37 static inline bool isValidRange(const FloatType& x)
38 {
39     static const FloatType max = std::numeric_limits<FloatType>::max();
40     return x >= -max && x <= max;
41 }
42 
43 // We use this generic parseNumber function to allow the Path parsing code to work
44 // at a higher precision internally, without any unnecessary runtime cost or code
45 // complexity.
46 template <typename CharType, typename FloatType>
genericParseNumber(const CharType * & ptr,const CharType * end,FloatType & number,bool skip)47 static bool genericParseNumber(const CharType*& ptr, const CharType* end, FloatType& number, bool skip)
48 {
49     FloatType integer, decimal, frac, exponent;
50     int sign, expsign;
51     const CharType* start = ptr;
52 
53     exponent = 0;
54     integer = 0;
55     frac = 1;
56     decimal = 0;
57     sign = 1;
58     expsign = 1;
59 
60     // read the sign
61     if (ptr < end && *ptr == '+')
62         ptr++;
63     else if (ptr < end && *ptr == '-') {
64         ptr++;
65         sign = -1;
66     }
67 
68     if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.'))
69         // The first character of a number must be one of [0-9+-.]
70         return false;
71 
72     // read the integer part, build right-to-left
73     const CharType* ptrStartIntPart = ptr;
74     while (ptr < end && *ptr >= '0' && *ptr <= '9')
75         ++ptr; // Advance to first non-digit.
76 
77     if (ptr != ptrStartIntPart) {
78         const CharType* ptrScanIntPart = ptr - 1;
79         FloatType multiplier = 1;
80         while (ptrScanIntPart >= ptrStartIntPart) {
81             integer += multiplier * static_cast<FloatType>(*(ptrScanIntPart--) - '0');
82             multiplier *= 10;
83         }
84         // Bail out early if this overflows.
85         if (!isValidRange(integer))
86             return false;
87     }
88 
89     if (ptr < end && *ptr == '.') { // read the decimals
90         ptr++;
91 
92         // There must be a least one digit following the .
93         if (ptr >= end || *ptr < '0' || *ptr > '9')
94             return false;
95 
96         while (ptr < end && *ptr >= '0' && *ptr <= '9')
97             decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1));
98     }
99 
100     // read the exponent part
101     if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E')
102         && (ptr[1] != 'x' && ptr[1] != 'm')) {
103         ptr++;
104 
105         // read the sign of the exponent
106         if (*ptr == '+')
107             ptr++;
108         else if (*ptr == '-') {
109             ptr++;
110             expsign = -1;
111         }
112 
113         // There must be an exponent
114         if (ptr >= end || *ptr < '0' || *ptr > '9')
115             return false;
116 
117         while (ptr < end && *ptr >= '0' && *ptr <= '9') {
118             exponent *= static_cast<FloatType>(10);
119             exponent += *ptr - '0';
120             ptr++;
121         }
122         // Make sure exponent is valid.
123         if (!isValidRange(exponent) || exponent > std::numeric_limits<FloatType>::max_exponent)
124             return false;
125     }
126 
127     number = integer + decimal;
128     number *= sign;
129 
130     if (exponent)
131         number *= static_cast<FloatType>(pow(10.0, expsign * static_cast<int>(exponent)));
132 
133     // Don't return Infinity() or NaN().
134     if (!isValidRange(number))
135         return false;
136 
137     if (start == ptr)
138         return false;
139 
140     if (skip)
141         skipOptionalSVGSpacesOrDelimiter(ptr, end);
142 
143     return true;
144 }
145 
146 template <typename CharType>
parseSVGNumber(CharType * begin,size_t length,double & number)147 bool parseSVGNumber(CharType* begin, size_t length, double& number)
148 {
149     const CharType* ptr = begin;
150     const CharType* end = ptr + length;
151     return genericParseNumber(ptr, end, number, false);
152 }
153 
154 // Explicitly instantiate the two flavors of parseSVGNumber() to satisfy external callers
155 template bool parseSVGNumber(LChar* begin, size_t length, double&);
156 template bool parseSVGNumber(UChar* begin, size_t length, double&);
157 
parseNumber(const LChar * & ptr,const LChar * end,float & number,bool skip)158 bool parseNumber(const LChar*& ptr, const LChar* end, float& number, bool skip)
159 {
160     return genericParseNumber(ptr, end, number, skip);
161 }
162 
parseNumber(const UChar * & ptr,const UChar * end,float & number,bool skip)163 bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip)
164 {
165     return genericParseNumber(ptr, end, number, skip);
166 }
167 
parseNumberFromString(const String & string,float & number,bool skip)168 bool parseNumberFromString(const String& string, float& number, bool skip)
169 {
170     if (string.isEmpty())
171         return false;
172     if (string.is8Bit()) {
173         const LChar* ptr = string.characters8();
174         const LChar* end = ptr + string.length();
175         return genericParseNumber(ptr, end, number, skip) && ptr == end;
176     }
177     const UChar* ptr = string.characters16();
178     const UChar* end = ptr + string.length();
179     return genericParseNumber(ptr, end, number, skip) && ptr == end;
180 }
181 
182 // only used to parse largeArcFlag and sweepFlag which must be a "0" or "1"
183 // and might not have any whitespace/comma after it
184 template <typename CharType>
genericParseArcFlag(const CharType * & ptr,const CharType * end,bool & flag)185 bool genericParseArcFlag(const CharType*& ptr, const CharType* end, bool& flag)
186 {
187     if (ptr >= end)
188         return false;
189     const CharType flagChar = *ptr++;
190     if (flagChar == '0')
191         flag = false;
192     else if (flagChar == '1')
193         flag = true;
194     else
195         return false;
196 
197     skipOptionalSVGSpacesOrDelimiter(ptr, end);
198 
199     return true;
200 }
201 
parseArcFlag(const LChar * & ptr,const LChar * end,bool & flag)202 bool parseArcFlag(const LChar*& ptr, const LChar* end, bool& flag)
203 {
204     return genericParseArcFlag(ptr, end, flag);
205 }
206 
parseArcFlag(const UChar * & ptr,const UChar * end,bool & flag)207 bool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag)
208 {
209     return genericParseArcFlag(ptr, end, flag);
210 }
211 
212 template<typename CharType>
genericParseNumberOptionalNumber(const CharType * & ptr,const CharType * end,float & x,float & y)213 static bool genericParseNumberOptionalNumber(const CharType*& ptr, const CharType* end, float& x, float& y)
214 {
215     if (!parseNumber(ptr, end, x))
216         return false;
217 
218     if (ptr == end)
219         y = x;
220     else if (!parseNumber(ptr, end, y, false))
221         return false;
222 
223     return ptr == end;
224 }
225 
parseNumberOptionalNumber(const String & string,float & x,float & y)226 bool parseNumberOptionalNumber(const String& string, float& x, float& y)
227 {
228     if (string.isEmpty())
229         return false;
230     if (string.is8Bit()) {
231         const LChar* ptr = string.characters8();
232         const LChar* end = ptr + string.length();
233         return genericParseNumberOptionalNumber(ptr, end, x, y);
234     }
235     const UChar* ptr = string.characters16();
236     const UChar* end = ptr + string.length();
237     return genericParseNumberOptionalNumber(ptr, end, x, y);
238 }
239 
240 template<typename CharType>
genericParseRect(const CharType * & ptr,const CharType * end,FloatRect & rect)241 static bool genericParseRect(const CharType*& ptr, const CharType* end, FloatRect& rect)
242 {
243     skipOptionalSVGSpaces(ptr, end);
244 
245     float x = 0;
246     float y = 0;
247     float width = 0;
248     float height = 0;
249     bool valid = parseNumber(ptr, end, x) && parseNumber(ptr, end, y) && parseNumber(ptr, end, width) && parseNumber(ptr, end, height, false);
250     rect = FloatRect(x, y, width, height);
251     return valid;
252 }
253 
parseRect(const String & string,FloatRect & rect)254 bool parseRect(const String& string, FloatRect& rect)
255 {
256     if (string.isEmpty())
257         return false;
258     if (string.is8Bit()) {
259         const LChar* ptr = string.characters8();
260         const LChar* end = ptr + string.length();
261         return genericParseRect(ptr, end, rect);
262     }
263     const UChar* ptr = string.characters16();
264     const UChar* end = ptr + string.length();
265     return genericParseRect(ptr, end, rect);
266 }
267 
268 template<typename CharType>
genericParsePointsList(SVGPointList & pointsList,const CharType * & ptr,const CharType * end)269 static bool genericParsePointsList(SVGPointList& pointsList, const CharType*& ptr, const CharType* end)
270 {
271     skipOptionalSVGSpaces(ptr, end);
272 
273     bool delimParsed = false;
274     while (ptr < end) {
275         delimParsed = false;
276         float xPos = 0.0f;
277         if (!parseNumber(ptr, end, xPos))
278            return false;
279 
280         float yPos = 0.0f;
281         if (!parseNumber(ptr, end, yPos, false))
282             return false;
283 
284         skipOptionalSVGSpaces(ptr, end);
285 
286         if (ptr < end && *ptr == ',') {
287             delimParsed = true;
288             ptr++;
289         }
290         skipOptionalSVGSpaces(ptr, end);
291 
292         pointsList.append(FloatPoint(xPos, yPos));
293     }
294     return ptr == end && !delimParsed;
295 }
296 
297 // FIXME: Why is the out parameter first?
pointsListFromSVGData(SVGPointList & pointsList,const String & points)298 bool pointsListFromSVGData(SVGPointList& pointsList, const String& points)
299 {
300     if (points.isEmpty())
301         return true;
302     if (points.is8Bit()) {
303         const LChar* ptr = points.characters8();
304         const LChar* end = ptr + points.length();
305         return genericParsePointsList(pointsList, ptr, end);
306     }
307     const UChar* ptr = points.characters16();
308     const UChar* end = ptr + points.length();
309     return genericParsePointsList(pointsList, ptr, end);
310 }
311 
312 template<typename CharType>
parseGlyphName(const CharType * & ptr,const CharType * end,HashSet<String> & values)313 static bool parseGlyphName(const CharType*& ptr, const CharType* end, HashSet<String>& values)
314 {
315     skipOptionalSVGSpaces(ptr, end);
316 
317     while (ptr < end) {
318         // Leading and trailing white space, and white space before and after separators, will be ignored.
319         const CharType* inputStart = ptr;
320         while (ptr < end && *ptr != ',')
321             ++ptr;
322 
323         if (ptr == inputStart)
324             break;
325 
326         // walk backwards from the ; to ignore any whitespace
327         const CharType* inputEnd = ptr - 1;
328         while (inputStart < inputEnd && isSVGSpace(*inputEnd))
329             --inputEnd;
330 
331         values.add(String(inputStart, inputEnd - inputStart + 1));
332         skipOptionalSVGSpacesOrDelimiter(ptr, end, ',');
333     }
334 
335     return true;
336 }
337 
parseGlyphName(const String & input,HashSet<String> & values)338 bool parseGlyphName(const String& input, HashSet<String>& values)
339 {
340     // FIXME: Parsing error detection is missing.
341     values.clear();
342     if (input.isEmpty())
343         return true;
344     if (input.is8Bit()) {
345         const LChar* ptr = input.characters8();
346         const LChar* end = ptr + input.length();
347         return parseGlyphName(ptr, end, values);
348     }
349     const UChar* ptr = input.characters16();
350     const UChar* end = ptr + input.length();
351     return parseGlyphName(ptr, end, values);
352 }
353 
354 template<typename CharType>
parseUnicodeRange(const CharType * characters,unsigned length,UnicodeRange & range)355 static bool parseUnicodeRange(const CharType* characters, unsigned length, UnicodeRange& range)
356 {
357     if (length < 2 || characters[0] != 'U' || characters[1] != '+')
358         return false;
359 
360     // Parse the starting hex number (or its prefix).
361     unsigned startRange = 0;
362     unsigned startLength = 0;
363 
364     const CharType* ptr = characters + 2;
365     const CharType* end = characters + length;
366     while (ptr < end) {
367         if (!isASCIIHexDigit(*ptr))
368             break;
369         ++startLength;
370         if (startLength > 6)
371             return false;
372         startRange = (startRange << 4) | toASCIIHexValue(*ptr);
373         ++ptr;
374     }
375 
376     // Handle the case of ranges separated by "-" sign.
377     if (2 + startLength < length && *ptr == '-') {
378         if (!startLength)
379             return false;
380 
381         // Parse the ending hex number (or its prefix).
382         unsigned endRange = 0;
383         unsigned endLength = 0;
384         ++ptr;
385         while (ptr < end) {
386             if (!isASCIIHexDigit(*ptr))
387                 break;
388             ++endLength;
389             if (endLength > 6)
390                 return false;
391             endRange = (endRange << 4) | toASCIIHexValue(*ptr);
392             ++ptr;
393         }
394 
395         if (!endLength)
396             return false;
397 
398         range.first = startRange;
399         range.second = endRange;
400         return true;
401     }
402 
403     // Handle the case of a number with some optional trailing question marks.
404     unsigned endRange = startRange;
405     while (ptr < end) {
406         if (*ptr != '?')
407             break;
408         ++startLength;
409         if (startLength > 6)
410             return false;
411         startRange <<= 4;
412         endRange = (endRange << 4) | 0xF;
413         ++ptr;
414     }
415 
416     if (!startLength)
417         return false;
418 
419     range.first = startRange;
420     range.second = endRange;
421     return true;
422 }
423 
424 template<typename CharType>
genericParseKerningUnicodeString(const CharType * & ptr,const CharType * end,UnicodeRanges & rangeList,HashSet<String> & stringList)425 static bool genericParseKerningUnicodeString(const CharType*& ptr, const CharType* end, UnicodeRanges& rangeList, HashSet<String>& stringList)
426 {
427     while (ptr < end) {
428         const CharType* inputStart = ptr;
429         while (ptr < end && *ptr != ',')
430             ++ptr;
431 
432         if (ptr == inputStart)
433             break;
434 
435         // Try to parse unicode range first
436         UnicodeRange range;
437         if (parseUnicodeRange(inputStart, ptr - inputStart, range))
438             rangeList.append(range);
439         else
440             stringList.add(String(inputStart, ptr - inputStart));
441         ++ptr;
442     }
443 
444     return true;
445 }
446 
parseKerningUnicodeString(const String & input,UnicodeRanges & rangeList,HashSet<String> & stringList)447 bool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, HashSet<String>& stringList)
448 {
449     // FIXME: Parsing error detection is missing.
450     if (input.isEmpty())
451         return true;
452     if (input.is8Bit()) {
453         const LChar* ptr = input.characters8();
454         const LChar* end = ptr + input.length();
455         return genericParseKerningUnicodeString(ptr, end, rangeList, stringList);
456     }
457     const UChar* ptr = input.characters16();
458     const UChar* end = ptr + input.length();
459     return genericParseKerningUnicodeString(ptr, end, rangeList, stringList);
460 }
461 
462 template<typename CharType>
genericParseDelimitedString(const CharType * & ptr,const CharType * end,const char seperator)463 static Vector<String> genericParseDelimitedString(const CharType*& ptr, const CharType* end, const char seperator)
464 {
465     Vector<String> values;
466 
467     skipOptionalSVGSpaces(ptr, end);
468 
469     while (ptr < end) {
470         // Leading and trailing white space, and white space before and after semicolon separators, will be ignored.
471         const CharType* inputStart = ptr;
472         while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs
473             ptr++;
474 
475         if (ptr == inputStart)
476             break;
477 
478         // walk backwards from the ; to ignore any whitespace
479         const CharType* inputEnd = ptr - 1;
480         while (inputStart < inputEnd && isSVGSpace(*inputEnd))
481             inputEnd--;
482 
483         values.append(String(inputStart, inputEnd - inputStart + 1));
484         skipOptionalSVGSpacesOrDelimiter(ptr, end, seperator);
485     }
486 
487     return values;
488 }
489 
parseDelimitedString(const String & input,const char seperator)490 Vector<String> parseDelimitedString(const String& input, const char seperator)
491 {
492     if (input.isEmpty())
493         return Vector<String>();
494     if (input.is8Bit()) {
495         const LChar* ptr = input.characters8();
496         const LChar* end = ptr + input.length();
497         return genericParseDelimitedString(ptr, end, seperator);
498     }
499     const UChar* ptr = input.characters16();
500     const UChar* end = ptr + input.length();
501     return genericParseDelimitedString(ptr, end, seperator);
502 }
503 
504 template <typename CharType>
parseFloatPoint(const CharType * & current,const CharType * end,FloatPoint & point)505 bool parseFloatPoint(const CharType*& current, const CharType* end, FloatPoint& point)
506 {
507     float x;
508     float y;
509     if (!parseNumber(current, end, x)
510         || !parseNumber(current, end, y))
511         return false;
512     point = FloatPoint(x, y);
513     return true;
514 }
515 
516 template bool parseFloatPoint(const LChar*& current, const LChar* end, FloatPoint& point1);
517 template bool parseFloatPoint(const UChar*& current, const UChar* end, FloatPoint& point1);
518 
519 template <typename CharType>
parseFloatPoint2(const CharType * & current,const CharType * end,FloatPoint & point1,FloatPoint & point2)520 inline bool parseFloatPoint2(const CharType*& current, const CharType* end, FloatPoint& point1, FloatPoint& point2)
521 {
522     float x1;
523     float y1;
524     float x2;
525     float y2;
526     if (!parseNumber(current, end, x1)
527         || !parseNumber(current, end, y1)
528         || !parseNumber(current, end, x2)
529         || !parseNumber(current, end, y2))
530         return false;
531     point1 = FloatPoint(x1, y1);
532     point2 = FloatPoint(x2, y2);
533     return true;
534 }
535 
536 template bool parseFloatPoint2(const LChar*& current, const LChar* end, FloatPoint& point1, FloatPoint& point2);
537 template bool parseFloatPoint2(const UChar*& current, const UChar* end, FloatPoint& point1, FloatPoint& point2);
538 
539 template <typename CharType>
parseFloatPoint3(const CharType * & current,const CharType * end,FloatPoint & point1,FloatPoint & point2,FloatPoint & point3)540 bool parseFloatPoint3(const CharType*& current, const CharType* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3)
541 {
542     float x1;
543     float y1;
544     float x2;
545     float y2;
546     float x3;
547     float y3;
548     if (!parseNumber(current, end, x1)
549         || !parseNumber(current, end, y1)
550         || !parseNumber(current, end, x2)
551         || !parseNumber(current, end, y2)
552         || !parseNumber(current, end, x3)
553         || !parseNumber(current, end, y3))
554         return false;
555     point1 = FloatPoint(x1, y1);
556     point2 = FloatPoint(x2, y2);
557     point3 = FloatPoint(x3, y3);
558     return true;
559 }
560 
561 template bool parseFloatPoint3(const LChar*& current, const LChar* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3);
562 template bool parseFloatPoint3(const UChar*& current, const UChar* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3);
563 
564 template<typename CharType>
parseTransformParamList(const CharType * & ptr,const CharType * end,float * values,int required,int optional)565 static int parseTransformParamList(const CharType*& ptr, const CharType* end, float* values, int required, int optional)
566 {
567     int optionalParams = 0, requiredParams = 0;
568 
569     if (!skipOptionalSVGSpaces(ptr, end) || *ptr != '(')
570         return -1;
571 
572     ptr++;
573 
574     skipOptionalSVGSpaces(ptr, end);
575 
576     while (requiredParams < required) {
577         if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false))
578             return -1;
579         requiredParams++;
580         if (requiredParams < required)
581             skipOptionalSVGSpacesOrDelimiter(ptr, end);
582     }
583     if (!skipOptionalSVGSpaces(ptr, end))
584         return -1;
585 
586     bool delimParsed = skipOptionalSVGSpacesOrDelimiter(ptr, end);
587 
588     if (ptr >= end)
589         return -1;
590 
591     if (*ptr == ')') { // skip optionals
592         ptr++;
593         if (delimParsed)
594             return -1;
595     } else {
596         while (optionalParams < optional) {
597             if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false))
598                 return -1;
599             optionalParams++;
600             if (optionalParams < optional)
601                 skipOptionalSVGSpacesOrDelimiter(ptr, end);
602         }
603 
604         if (!skipOptionalSVGSpaces(ptr, end))
605             return -1;
606 
607         delimParsed = skipOptionalSVGSpacesOrDelimiter(ptr, end);
608 
609         if (ptr >= end || *ptr != ')' || delimParsed)
610             return -1;
611         ptr++;
612     }
613 
614     return requiredParams + optionalParams;
615 }
616 
617 // These should be kept in sync with enum SVGTransformType
618 static const int requiredValuesForType[] =  {0, 6, 1, 1, 1, 1, 1};
619 static const int optionalValuesForType[] =  {0, 0, 1, 1, 2, 0, 0};
620 
621 template<typename CharType>
parseTransformValueInternal(unsigned type,const CharType * & ptr,const CharType * end,SVGTransform & transform)622 static bool parseTransformValueInternal(unsigned type, const CharType*& ptr, const CharType* end, SVGTransform& transform)
623 {
624     if (type == SVGTransform::SVG_TRANSFORM_UNKNOWN)
625         return false;
626 
627     int valueCount = 0;
628     float values[] = {0, 0, 0, 0, 0, 0};
629     if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0)
630         return false;
631 
632     switch (type) {
633     case SVGTransform::SVG_TRANSFORM_SKEWX:
634         transform.setSkewX(values[0]);
635         break;
636     case SVGTransform::SVG_TRANSFORM_SKEWY:
637         transform.setSkewY(values[0]);
638         break;
639     case SVGTransform::SVG_TRANSFORM_SCALE:
640         if (valueCount == 1) // Spec: if only one param given, assume uniform scaling
641             transform.setScale(values[0], values[0]);
642         else
643             transform.setScale(values[0], values[1]);
644         break;
645     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
646         if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0
647             transform.setTranslate(values[0], 0);
648         else
649             transform.setTranslate(values[0], values[1]);
650         break;
651     case SVGTransform::SVG_TRANSFORM_ROTATE:
652         if (valueCount == 1)
653             transform.setRotate(values[0], 0, 0);
654         else
655             transform.setRotate(values[0], values[1], values[2]);
656         break;
657     case SVGTransform::SVG_TRANSFORM_MATRIX:
658         transform.setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5]));
659         break;
660     }
661 
662     return true;
663 }
664 
parseTransformValue(unsigned type,const LChar * & ptr,const LChar * end,SVGTransform & transform)665 bool parseTransformValue(unsigned type, const LChar*& ptr, const LChar* end, SVGTransform& transform)
666 {
667     return parseTransformValueInternal(type, ptr, end, transform);
668 }
669 
parseTransformValue(unsigned type,const UChar * & ptr,const UChar * end,SVGTransform & transform)670 bool parseTransformValue(unsigned type, const UChar*& ptr, const UChar* end, SVGTransform& transform)
671 {
672     return parseTransformValueInternal(type, ptr, end, transform);
673 }
674 
675 static const LChar skewXDesc[] =  {'s', 'k', 'e', 'w', 'X'};
676 static const LChar skewYDesc[] =  {'s', 'k', 'e', 'w', 'Y'};
677 static const LChar scaleDesc[] =  {'s', 'c', 'a', 'l', 'e'};
678 static const LChar translateDesc[] =  {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'};
679 static const LChar rotateDesc[] =  {'r', 'o', 't', 'a', 't', 'e'};
680 static const LChar matrixDesc[] =  {'m', 'a', 't', 'r', 'i', 'x'};
681 
682 template<typename CharType>
parseAndSkipType(const CharType * & ptr,const CharType * end,unsigned short & type)683 static inline bool parseAndSkipType(const CharType*& ptr, const CharType* end, unsigned short& type)
684 {
685     if (ptr >= end)
686         return false;
687 
688     if (*ptr == 's') {
689         if (skipString(ptr, end, skewXDesc, WTF_ARRAY_LENGTH(skewXDesc)))
690             type = SVGTransform::SVG_TRANSFORM_SKEWX;
691         else if (skipString(ptr, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc)))
692             type = SVGTransform::SVG_TRANSFORM_SKEWY;
693         else if (skipString(ptr, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc)))
694             type = SVGTransform::SVG_TRANSFORM_SCALE;
695         else
696             return false;
697     } else if (skipString(ptr, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc)))
698         type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
699     else if (skipString(ptr, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc)))
700         type = SVGTransform::SVG_TRANSFORM_ROTATE;
701     else if (skipString(ptr, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc)))
702         type = SVGTransform::SVG_TRANSFORM_MATRIX;
703     else
704         return false;
705 
706     return true;
707 }
708 
parseTransformType(const String & string)709 SVGTransform::SVGTransformType parseTransformType(const String& string)
710 {
711     if (string.isEmpty())
712         return SVGTransform::SVG_TRANSFORM_UNKNOWN;
713     unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
714     if (string.is8Bit()) {
715         const LChar* ptr = string.characters8();
716         const LChar* end = ptr + string.length();
717         parseAndSkipType(ptr, end, type);
718     } else {
719         const UChar* ptr = string.characters16();
720         const UChar* end = ptr + string.length();
721         parseAndSkipType(ptr, end, type);
722     }
723     return static_cast<SVGTransform::SVGTransformType>(type);
724 }
725 
726 template<typename CharType>
parseTransformAttributeInternal(SVGTransformList & list,const CharType * & ptr,const CharType * end,TransformParsingMode mode)727 bool parseTransformAttributeInternal(SVGTransformList& list, const CharType*& ptr, const CharType* end, TransformParsingMode mode)
728 {
729     if (mode == ClearList)
730         list.clear();
731 
732     bool delimParsed = false;
733     while (ptr < end) {
734         delimParsed = false;
735         unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
736         skipOptionalSVGSpaces(ptr, end);
737 
738         if (!parseAndSkipType(ptr, end, type))
739             return false;
740 
741         SVGTransform transform;
742         if (!parseTransformValue(type, ptr, end, transform))
743             return false;
744 
745         list.append(transform);
746         skipOptionalSVGSpaces(ptr, end);
747         if (ptr < end && *ptr == ',') {
748             delimParsed = true;
749             ++ptr;
750         }
751         skipOptionalSVGSpaces(ptr, end);
752     }
753 
754     return !delimParsed;
755 }
756 
parseTransformAttribute(SVGTransformList & list,const LChar * & ptr,const LChar * end,TransformParsingMode mode)757 bool parseTransformAttribute(SVGTransformList& list, const LChar*& ptr, const LChar* end, TransformParsingMode mode)
758 {
759     return parseTransformAttributeInternal(list, ptr, end, mode);
760 }
761 
parseTransformAttribute(SVGTransformList & list,const UChar * & ptr,const UChar * end,TransformParsingMode mode)762 bool parseTransformAttribute(SVGTransformList& list, const UChar*& ptr, const UChar* end, TransformParsingMode mode)
763 {
764     return parseTransformAttributeInternal(list, ptr, end, mode);
765 }
766 
767 }
768