[Forms] Introduce Decimal behind the InputNumber type
[WebKit-https.git] / Source / WebCore / html / parser / HTMLParserIdioms.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26 #include "HTMLParserIdioms.h"
27
28 #include "Decimal.h"
29 #include <limits>
30 #include <wtf/MathExtras.h>
31 #include <wtf/dtoa.h>
32 #include <wtf/text/AtomicString.h>
33 #include <wtf/text/StringBuilder.h>
34
35 namespace WebCore {
36
37 String stripLeadingAndTrailingHTMLSpaces(const String& string)
38 {
39     const UChar* characters = string.characters();
40     unsigned length = string.length();
41
42     unsigned numLeadingSpaces;
43     for (numLeadingSpaces = 0; numLeadingSpaces < length; ++numLeadingSpaces) {
44         if (isNotHTMLSpace(characters[numLeadingSpaces]))
45             break;
46     }
47
48     if (numLeadingSpaces == length)
49         return string.isNull() ? string : emptyAtom.string();
50
51     unsigned numTrailingSpaces;
52     for (numTrailingSpaces = 0; numTrailingSpaces < length; ++numTrailingSpaces) {
53         if (isNotHTMLSpace(characters[length - numTrailingSpaces - 1]))
54             break;
55     }
56
57     ASSERT(numLeadingSpaces + numTrailingSpaces < length);
58
59     return string.substring(numLeadingSpaces, length - (numLeadingSpaces + numTrailingSpaces));
60 }
61
62 String serializeForNumberType(const Decimal& number)
63 {
64     if (number.isZero()) {
65         // Decimal::toString appends exponent, e.g. "0e-18"
66         return number.isNegative() ? "-0" : "0";
67     }
68     return number.toString();
69 }
70
71 String serializeForNumberType(double number)
72 {
73     // According to HTML5, "the best representation of the number n as a floating
74     // point number" is a string produced by applying ToString() to n.
75     NumberToStringBuffer buffer;
76     return String(numberToString(number, buffer));
77 }
78
79 Decimal parseToDecimalForNumberType(const String& string, const Decimal& fallbackValue)
80 {
81     // See HTML5 2.5.4.3 `Real numbers.' and parseToDoubleForNumberType
82
83     // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
84     const UChar firstCharacter = string[0];
85     if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
86         return fallbackValue;
87
88     const Decimal value = Decimal::fromString(string);
89     if (!value.isFinite())
90         return fallbackValue;
91
92     // Numbers are considered finite IEEE 754 single-precision floating point values.
93     // See HTML5 2.5.4.3 `Real numbers.'
94     // FIXME: We should use numeric_limits<double>::max for number input type.
95     const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
96     if (value < -floatMax || value > floatMax)
97         return fallbackValue;
98
99     // We return +0 for -0 case.
100     return value.isZero() ? Decimal(0) : value;
101 }
102
103 Decimal parseToDecimalForNumberType(const String& string)
104 {
105     return parseToDecimalForNumberType(string, Decimal::nan());
106 }
107
108 double parseToDoubleForNumberType(const String& string, double fallbackValue)
109 {
110     // See HTML5 2.5.4.3 `Real numbers.'
111
112     // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
113     UChar firstCharacter = string[0];
114     if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
115         return fallbackValue;
116
117     bool valid = false;
118     double value = string.toDouble(&valid);
119     if (!valid)
120         return fallbackValue;
121
122     // NaN and infinity are considered valid by String::toDouble, but not valid here.
123     if (!isfinite(value))
124         return fallbackValue;
125
126     // Numbers are considered finite IEEE 754 single-precision floating point values.
127     // See HTML5 2.5.4.3 `Real numbers.'
128     if (-std::numeric_limits<float>::max() > value || value > std::numeric_limits<float>::max())
129         return fallbackValue;
130
131     // The following expression converts -0 to +0.
132     return value ? value : 0;
133 }
134
135 double parseToDoubleForNumberType(const String& string)
136 {
137     return parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN());
138 }
139
140 double parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, unsigned *decimalPlaces, double fallbackValue)
141 {
142     if (decimalPlaces)
143         *decimalPlaces = 0;
144
145     double value = parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN());
146     if (!isfinite(value))
147         return fallbackValue;
148
149     if (!decimalPlaces)
150         return value;
151
152     size_t dotIndex = string.find('.');
153     size_t eIndex = string.find('e');
154     if (eIndex == notFound) 
155         eIndex = string.find('E');
156
157     unsigned baseDecimalPlaces = 0;
158     if (dotIndex != notFound) {
159         if (eIndex == notFound)
160             baseDecimalPlaces = string.length() - dotIndex - 1;
161         else
162             baseDecimalPlaces = eIndex - dotIndex - 1;
163     }
164
165     int exponent = 0;
166     if (eIndex != notFound) {
167         unsigned cursor = eIndex + 1, cursorSaved;
168         int digit, exponentSign;
169         int32_t exponent32;
170         size_t length = string.length();
171
172         // Not using String.toInt() in order to perform the same computation as dtoa() does.
173         exponentSign = 0;
174         switch (digit = string[cursor]) {
175         case '-':
176             exponentSign = 1;
177         case '+':
178             digit = string[++cursor];
179         }
180         if (digit >= '0' && digit <= '9') {
181             while (cursor < length && digit == '0')
182                 digit = string[++cursor];
183             if (digit > '0' && digit <= '9') {
184                 exponent32 = digit - '0';
185                 cursorSaved = cursor;
186                 while (cursor < length && (digit = string[++cursor]) >= '0' && digit <= '9')
187                     exponent32 = (10 * exponent32) + digit - '0';
188                 if (cursor - cursorSaved > 8 || exponent32 > 19999)
189                     /* Avoid confusion from exponents
190                      * so large that e might overflow.
191                      */
192                     exponent = 19999; /* safe for 16 bit ints */
193                 else
194                     exponent = static_cast<int>(exponent32);
195                 if (exponentSign)
196                     exponent = -exponent;
197             } else
198                 exponent = 0;
199         }
200     }
201
202     int intDecimalPlaces = baseDecimalPlaces - exponent;
203     if (intDecimalPlaces < 0)
204         *decimalPlaces = 0;
205     else if (intDecimalPlaces > 19999)
206         *decimalPlaces = 19999;
207     else
208         *decimalPlaces = static_cast<unsigned>(intDecimalPlaces);
209
210     return value;
211 }
212
213 double parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, unsigned *decimalPlaces)
214 {
215     return parseToDoubleForNumberTypeWithDecimalPlaces(string, decimalPlaces, std::numeric_limits<double>::quiet_NaN());
216 }
217
218 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
219 bool parseHTMLInteger(const String& input, int& value)
220 {
221     // Step 1
222     // Step 2
223     const UChar* position = input.characters();
224     const UChar* end = position + input.length();
225
226     // Step 3
227     int sign = 1;
228
229     // Step 4
230     while (position < end) {
231         if (!isHTMLSpace(*position))
232             break;
233         ++position;
234     }
235
236     // Step 5
237     if (position == end)
238         return false;
239     ASSERT(position < end);
240
241     // Step 6
242     if (*position == '-') {
243         sign = -1;
244         ++position;
245     } else if (*position == '+')
246         ++position;
247     if (position == end)
248         return false;
249     ASSERT(position < end);
250
251     // Step 7
252     if (!isASCIIDigit(*position))
253         return false;
254
255     // Step 8
256     StringBuilder digits;
257     while (position < end) {
258         if (!isASCIIDigit(*position))
259             break;
260         digits.append(*position++);
261     }
262
263     // Step 9
264     bool ok;
265     value = sign * charactersToIntStrict(digits.characters(), digits.length(), &ok);
266     return ok;
267 }
268
269 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
270 bool parseHTMLNonNegativeInteger(const String& input, unsigned int& value)
271 {
272     // Step 1
273     // Step 2
274     const UChar* position = input.characters();
275     const UChar* end = position + input.length();
276
277     // Step 3
278     while (position < end) {
279         if (!isHTMLSpace(*position))
280             break;
281         ++position;
282     }
283
284     // Step 4
285     if (position == end)
286         return false;
287     ASSERT(position < end);
288
289     // Step 5
290     if (*position == '+')
291         ++position;
292
293     // Step 6
294     if (position == end)
295         return false;
296     ASSERT(position < end);
297
298     // Step 7
299     if (!isASCIIDigit(*position))
300         return false;
301
302     // Step 8
303     StringBuilder digits;
304     while (position < end) {
305         if (!isASCIIDigit(*position))
306             break;
307         digits.append(*position++);
308     }
309
310     // Step 9
311     bool ok;
312     value = charactersToUIntStrict(digits.characters(), digits.length(), &ok);
313     return ok;
314 }
315
316 }