Web Inspector: beautify the paused in debugger message, make it configurable from...
[WebKit-https.git] / Source / WebCore / svg / SVGParserUtilities.cpp
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 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
25 #if ENABLE(SVG)
26 #include "SVGParserUtilities.h"
27
28 #include "Document.h"
29 #include "FloatRect.h"
30 #include "SVGPointList.h"
31
32 #include <limits>
33 #include <wtf/ASCIICType.h>
34
35 namespace WebCore {
36
37 template <typename FloatType> 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 FloatType> static bool genericParseNumber(const UChar*& ptr, const UChar* end, FloatType& number, bool skip)
47 {
48     FloatType integer, decimal, frac, exponent;
49     int sign, expsign;
50     const UChar* start = ptr;
51
52     exponent = 0;
53     integer = 0;
54     frac = 1;
55     decimal = 0;
56     sign = 1;
57     expsign = 1;
58
59     // read the sign
60     if (ptr < end && *ptr == '+')
61         ptr++;
62     else if (ptr < end && *ptr == '-') {
63         ptr++;
64         sign = -1;
65     } 
66     
67     if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.'))
68         // The first character of a number must be one of [0-9+-.]
69         return false;
70
71     // read the integer part, build right-to-left
72     const UChar* ptrStartIntPart = ptr;
73     while (ptr < end && *ptr >= '0' && *ptr <= '9')
74         ++ptr; // Advance to first non-digit.
75
76     if (ptr != ptrStartIntPart) {
77         const UChar* ptrScanIntPart = ptr - 1;
78         FloatType multiplier = 1;
79         while (ptrScanIntPart >= ptrStartIntPart) {
80             integer += multiplier * static_cast<FloatType>(*(ptrScanIntPart--) - '0');
81             multiplier *= 10;
82         }
83         // Bail out early if this overflows.
84         if (!isValidRange(integer))
85             return false;
86     }
87
88     if (ptr < end && *ptr == '.') { // read the decimals
89         ptr++;
90         
91         // There must be a least one digit following the .
92         if (ptr >= end || *ptr < '0' || *ptr > '9')
93             return false;
94         
95         while (ptr < end && *ptr >= '0' && *ptr <= '9')
96             decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1));
97     }
98
99     // read the exponent part
100     if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E') 
101         && (ptr[1] != 'x' && ptr[1] != 'm')) { 
102         ptr++;
103
104         // read the sign of the exponent
105         if (*ptr == '+')
106             ptr++;
107         else if (*ptr == '-') {
108             ptr++;
109             expsign = -1;
110         }
111         
112         // There must be an exponent
113         if (ptr >= end || *ptr < '0' || *ptr > '9')
114             return false;
115
116         while (ptr < end && *ptr >= '0' && *ptr <= '9') {
117             exponent *= static_cast<FloatType>(10);
118             exponent += *ptr - '0';
119             ptr++;
120         }
121         // Make sure exponent is valid.
122         if (!isValidRange(exponent) || exponent > std::numeric_limits<FloatType>::max_exponent)
123             return false;
124     }
125
126     number = integer + decimal;
127     number *= sign;
128
129     if (exponent)
130         number *= static_cast<FloatType>(pow(10.0, expsign * static_cast<int>(exponent)));
131
132     // Don't return Infinity() or NaN().
133     if (!isValidRange(number))
134         return false;
135
136     if (start == ptr)
137         return false;
138
139     if (skip)
140         skipOptionalSVGSpacesOrDelimiter(ptr, end);
141
142     return true;
143 }
144
145 bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip) 
146 {
147     return genericParseNumber(ptr, end, number, skip);
148 }
149
150 bool parseNumberFromString(const String& string, float& number, bool skip)
151 {
152     const UChar* ptr = string.characters();
153     const UChar* end = ptr + string.length();
154     return genericParseNumber(ptr, end, number, skip) && ptr == end;
155 }
156
157 // only used to parse largeArcFlag and sweepFlag which must be a "0" or "1"
158 // and might not have any whitespace/comma after it
159 bool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag)
160 {
161     if (ptr >= end)
162         return false;
163     const UChar flagChar = *ptr++;
164     if (flagChar == '0')
165         flag = false;
166     else if (flagChar == '1')
167         flag = true;
168     else
169         return false;
170     
171     skipOptionalSVGSpacesOrDelimiter(ptr, end);
172     
173     return true;
174 }
175
176 bool parseNumberOptionalNumber(const String& s, float& x, float& y)
177 {
178     if (s.isEmpty())
179         return false;
180     const UChar* cur = s.characters();
181     const UChar* end = cur + s.length();
182
183     if (!parseNumber(cur, end, x))
184         return false;
185
186     if (cur == end)
187         y = x;
188     else if (!parseNumber(cur, end, y, false))
189         return false;
190
191     return cur == end;
192 }
193
194 bool parseRect(const String& string, FloatRect& rect)
195 {
196     const UChar* ptr = string.characters();
197     const UChar* end = ptr + string.length();
198     skipOptionalSVGSpaces(ptr, end);
199     
200     float x = 0;
201     float y = 0;
202     float width = 0;
203     float height = 0;
204     bool valid = parseNumber(ptr, end, x) && parseNumber(ptr, end, y) && parseNumber(ptr, end, width) && parseNumber(ptr, end, height, false);
205     rect = FloatRect(x, y, width, height);
206     return valid;
207 }
208
209 bool pointsListFromSVGData(SVGPointList& pointsList, const String& points)
210 {
211     if (points.isEmpty())
212         return true;
213     const UChar* cur = points.characters();
214     const UChar* end = cur + points.length();
215
216     skipOptionalSVGSpaces(cur, end);
217
218     bool delimParsed = false;
219     while (cur < end) {
220         delimParsed = false;
221         float xPos = 0.0f;
222         if (!parseNumber(cur, end, xPos))
223            return false;
224
225         float yPos = 0.0f;
226         if (!parseNumber(cur, end, yPos, false))
227             return false;
228
229         skipOptionalSVGSpaces(cur, end);
230
231         if (cur < end && *cur == ',') {
232             delimParsed = true;
233             cur++;
234         }
235         skipOptionalSVGSpaces(cur, end);
236
237         pointsList.append(FloatPoint(xPos, yPos));
238     }
239     return cur == end && !delimParsed;
240 }
241
242 bool parseGlyphName(const String& input, HashSet<String>& values)
243 {
244     // FIXME: Parsing error detection is missing.
245     values.clear();
246
247     const UChar* ptr = input.characters();
248     const UChar* end = ptr + input.length();
249     skipOptionalSVGSpaces(ptr, end);
250
251     while (ptr < end) {
252         // Leading and trailing white space, and white space before and after separators, will be ignored.
253         const UChar* inputStart = ptr;
254         while (ptr < end && *ptr != ',')
255             ++ptr;
256
257         if (ptr == inputStart)
258             break;
259
260         // walk backwards from the ; to ignore any whitespace
261         const UChar* inputEnd = ptr - 1;
262         while (inputStart < inputEnd && isSVGSpace(*inputEnd))
263             --inputEnd;
264
265         values.add(String(inputStart, inputEnd - inputStart + 1));
266         skipOptionalSVGSpacesOrDelimiter(ptr, end, ',');
267     }
268
269     return true;
270 }
271
272 static bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeRange& range)
273 {
274     if (length < 2 || characters[0] != 'U' || characters[1] != '+')
275         return false;
276     
277     // Parse the starting hex number (or its prefix).
278     unsigned startRange = 0;
279     unsigned startLength = 0;
280
281     const UChar* ptr = characters + 2;
282     const UChar* end = characters + length;
283     while (ptr < end) {
284         if (!isASCIIHexDigit(*ptr))
285             break;
286         ++startLength;
287         if (startLength > 6)
288             return false;
289         startRange = (startRange << 4) | toASCIIHexValue(*ptr);
290         ++ptr;
291     }
292     
293     // Handle the case of ranges separated by "-" sign.
294     if (2 + startLength < length && *ptr == '-') {
295         if (!startLength)
296             return false;
297         
298         // Parse the ending hex number (or its prefix).
299         unsigned endRange = 0;
300         unsigned endLength = 0;
301         ++ptr;
302         while (ptr < end) {
303             if (!isASCIIHexDigit(*ptr))
304                 break;
305             ++endLength;
306             if (endLength > 6)
307                 return false;
308             endRange = (endRange << 4) | toASCIIHexValue(*ptr);
309             ++ptr;
310         }
311         
312         if (!endLength)
313             return false;
314         
315         range.first = startRange;
316         range.second = endRange;
317         return true;
318     }
319     
320     // Handle the case of a number with some optional trailing question marks.
321     unsigned endRange = startRange;
322     while (ptr < end) {
323         if (*ptr != '?')
324             break;
325         ++startLength;
326         if (startLength > 6)
327             return false;
328         startRange <<= 4;
329         endRange = (endRange << 4) | 0xF;
330         ++ptr;
331     }
332     
333     if (!startLength)
334         return false;
335     
336     range.first = startRange;
337     range.second = endRange;
338     return true;
339 }
340
341 bool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, HashSet<String>& stringList)
342 {
343     // FIXME: Parsing error detection is missing.
344     const UChar* ptr = input.characters();
345     const UChar* end = ptr + input.length();
346
347     while (ptr < end) {
348         const UChar* inputStart = ptr;
349         while (ptr < end && *ptr != ',')
350             ++ptr;
351
352         if (ptr == inputStart)
353             break;
354
355         // Try to parse unicode range first
356         UnicodeRange range;
357         if (parseUnicodeRange(inputStart, ptr - inputStart, range))
358             rangeList.append(range);
359         else
360             stringList.add(String(inputStart, ptr - inputStart));
361         ++ptr;
362     }
363
364     return true;
365 }
366
367 Vector<String> parseDelimitedString(const String& input, const char seperator)
368 {
369     Vector<String> values;
370
371     const UChar* ptr = input.characters();
372     const UChar* end = ptr + input.length();
373     skipOptionalSVGSpaces(ptr, end);
374
375     while (ptr < end) {
376         // Leading and trailing white space, and white space before and after semicolon separators, will be ignored.
377         const UChar* inputStart = ptr;
378         while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs
379             ptr++;
380
381         if (ptr == inputStart)
382             break;
383
384         // walk backwards from the ; to ignore any whitespace
385         const UChar* inputEnd = ptr - 1;
386         while (inputStart < inputEnd && isSVGSpace(*inputEnd))
387             inputEnd--;
388
389         values.append(String(inputStart, inputEnd - inputStart + 1));
390         skipOptionalSVGSpacesOrDelimiter(ptr, end, seperator);
391     }
392
393     return values;
394 }
395
396 }
397
398 #endif // ENABLE(SVG)