c117c7a123580724bac8755cb776afd1fd2201ae
[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 "FloatPoint.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         skipOptionalSpacesOrDelimiter(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);
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     const UChar flagChar = *ptr++;
162     if (flagChar == '0')
163         flag = false;
164     else if (flagChar == '1')
165         flag = true;
166     else
167         return false;
168     
169     skipOptionalSpacesOrDelimiter(ptr, end);
170     
171     return true;
172 }
173
174 bool parseNumberOptionalNumber(const String& s, float& x, float& y)
175 {
176     if (s.isEmpty())
177         return false;
178     const UChar* cur = s.characters();
179     const UChar* end = cur + s.length();
180
181     if (!parseNumber(cur, end, x))
182         return false;
183
184     if (cur == end)
185         y = x;
186     else if (!parseNumber(cur, end, y, false))
187         return false;
188
189     return cur == end;
190 }
191
192 bool pointsListFromSVGData(SVGPointList& pointsList, const String& points)
193 {
194     if (points.isEmpty())
195         return true;
196     const UChar* cur = points.characters();
197     const UChar* end = cur + points.length();
198
199     skipOptionalSpaces(cur, end);
200
201     bool delimParsed = false;
202     while (cur < end) {
203         delimParsed = false;
204         float xPos = 0.0f;
205         if (!parseNumber(cur, end, xPos))
206            return false;
207
208         float yPos = 0.0f;
209         if (!parseNumber(cur, end, yPos, false))
210             return false;
211
212         skipOptionalSpaces(cur, end);
213
214         if (cur < end && *cur == ',') {
215             delimParsed = true;
216             cur++;
217         }
218         skipOptionalSpaces(cur, end);
219
220         pointsList.append(FloatPoint(xPos, yPos));
221     }
222     return cur == end && !delimParsed;
223 }
224
225 bool parseGlyphName(const String& input, HashSet<String>& values)
226 {
227     // FIXME: Parsing error detection is missing.
228     values.clear();
229
230     const UChar* ptr = input.characters();
231     const UChar* end = ptr + input.length();
232     skipOptionalSpaces(ptr, end);
233
234     while (ptr < end) {
235         // Leading and trailing white space, and white space before and after separators, will be ignored.
236         const UChar* inputStart = ptr;
237         while (ptr < end && *ptr != ',')
238             ++ptr;
239
240         if (ptr == inputStart)
241             break;
242
243         // walk backwards from the ; to ignore any whitespace
244         const UChar* inputEnd = ptr - 1;
245         while (inputStart < inputEnd && isWhitespace(*inputEnd))
246             --inputEnd;
247
248         values.add(String(inputStart, inputEnd - inputStart + 1));
249         skipOptionalSpacesOrDelimiter(ptr, end, ',');
250     }
251
252     return true;
253 }
254
255 static bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeRange& range)
256 {
257     if (length < 2 || characters[0] != 'U' || characters[1] != '+')
258         return false;
259     
260     // Parse the starting hex number (or its prefix).
261     unsigned startRange = 0;
262     unsigned startLength = 0;
263
264     const UChar* ptr = characters + 2;
265     const UChar* end = characters + length;
266     while (ptr < end) {
267         if (!isASCIIHexDigit(*ptr))
268             break;
269         ++startLength;
270         if (startLength > 6)
271             return false;
272         startRange = (startRange << 4) | toASCIIHexValue(*ptr);
273         ++ptr;
274     }
275     
276     // Handle the case of ranges separated by "-" sign.
277     if (2 + startLength < length && *ptr == '-') {
278         if (!startLength)
279             return false;
280         
281         // Parse the ending hex number (or its prefix).
282         unsigned endRange = 0;
283         unsigned endLength = 0;
284         ++ptr;
285         while (ptr < end) {
286             if (!isASCIIHexDigit(*ptr))
287                 break;
288             ++endLength;
289             if (endLength > 6)
290                 return false;
291             endRange = (endRange << 4) | toASCIIHexValue(*ptr);
292             ++ptr;
293         }
294         
295         if (!endLength)
296             return false;
297         
298         range.first = startRange;
299         range.second = endRange;
300         return true;
301     }
302     
303     // Handle the case of a number with some optional trailing question marks.
304     unsigned endRange = startRange;
305     while (ptr < end) {
306         if (*ptr != '?')
307             break;
308         ++startLength;
309         if (startLength > 6)
310             return false;
311         startRange <<= 4;
312         endRange = (endRange << 4) | 0xF;
313         ++ptr;
314     }
315     
316     if (!startLength)
317         return false;
318     
319     range.first = startRange;
320     range.second = endRange;
321     return true;
322 }
323
324 bool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, HashSet<String>& stringList)
325 {
326     // FIXME: Parsing error detection is missing.
327     const UChar* ptr = input.characters();
328     const UChar* end = ptr + input.length();
329
330     while (ptr < end) {
331         const UChar* inputStart = ptr;
332         while (ptr < end && *ptr != ',')
333             ++ptr;
334
335         if (ptr == inputStart)
336             break;
337
338         // Try to parse unicode range first
339         UnicodeRange range;
340         if (parseUnicodeRange(inputStart, ptr - inputStart, range))
341             rangeList.append(range);
342         else
343             stringList.add(String(inputStart, ptr - inputStart));
344         ++ptr;
345     }
346
347     return true;
348 }
349
350 Vector<String> parseDelimitedString(const String& input, const char seperator)
351 {
352     Vector<String> values;
353
354     const UChar* ptr = input.characters();
355     const UChar* end = ptr + input.length();
356     skipOptionalSpaces(ptr, end);
357
358     while (ptr < end) {
359         // Leading and trailing white space, and white space before and after semicolon separators, will be ignored.
360         const UChar* inputStart = ptr;
361         while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs
362             ptr++;
363
364         if (ptr == inputStart)
365             break;
366
367         // walk backwards from the ; to ignore any whitespace
368         const UChar* inputEnd = ptr - 1;
369         while (inputStart < inputEnd && isWhitespace(*inputEnd))
370             inputEnd--;
371
372         values.append(String(inputStart, inputEnd - inputStart + 1));
373         skipOptionalSpacesOrDelimiter(ptr, end, seperator);
374     }
375
376     return values;
377 }
378
379 }
380
381 #endif // ENABLE(SVG)