Use NeverDestroyed instead of DEPRECATED_DEFINE_STATIC_LOCAL
[WebKit-https.git] / Source / WebCore / html / NumberInputType.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2011 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "NumberInputType.h"
34
35 #include "ExceptionCode.h"
36 #include "HTMLInputElement.h"
37 #include "HTMLNames.h"
38 #include "HTMLParserIdioms.h"
39 #include "InputTypeNames.h"
40 #include "KeyboardEvent.h"
41 #include "LocalizedStrings.h"
42 #include "PlatformLocale.h"
43 #include "RenderTextControl.h"
44 #include <limits>
45 #include <wtf/ASCIICType.h>
46 #include <wtf/MathExtras.h>
47
48 namespace WebCore {
49
50 using namespace HTMLNames;
51
52 static const int numberDefaultStep = 1;
53 static const int numberDefaultStepBase = 0;
54 static const int numberStepScaleFactor = 1;
55
56 struct RealNumberRenderSize {
57     unsigned sizeBeforeDecimalPoint;
58     unsigned sizeAfteDecimalPoint;
59
60     RealNumberRenderSize(unsigned before, unsigned after)
61         : sizeBeforeDecimalPoint(before)
62         , sizeAfteDecimalPoint(after)
63     {
64     }
65
66     RealNumberRenderSize max(const RealNumberRenderSize& other) const
67     {
68         return RealNumberRenderSize(
69             std::max(sizeBeforeDecimalPoint, other.sizeBeforeDecimalPoint),
70             std::max(sizeAfteDecimalPoint, other.sizeAfteDecimalPoint));
71     }
72 };
73
74 static RealNumberRenderSize calculateRenderSize(const Decimal& value)
75 {
76     ASSERT(value.isFinite());
77     const unsigned sizeOfDigits = String::number(value.value().coefficient()).length();
78     const unsigned sizeOfSign = value.isNegative() ? 1 : 0;
79     const int exponent = value.exponent();
80     if (exponent >= 0)
81         return RealNumberRenderSize(sizeOfSign + sizeOfDigits, 0);
82
83     const int sizeBeforeDecimalPoint = exponent + sizeOfDigits;
84     if (sizeBeforeDecimalPoint > 0) {
85         // In case of "123.456"
86         return RealNumberRenderSize(sizeOfSign + sizeBeforeDecimalPoint, sizeOfDigits - sizeBeforeDecimalPoint);
87     }
88
89     // In case of "0.00012345"
90     const unsigned sizeOfZero = 1;
91     const unsigned numberOfZeroAfterDecimalPoint = -sizeBeforeDecimalPoint;
92     return RealNumberRenderSize(sizeOfSign + sizeOfZero , numberOfZeroAfterDecimalPoint + sizeOfDigits);
93 }
94
95 const AtomicString& NumberInputType::formControlType() const
96 {
97     return InputTypeNames::number();
98 }
99
100 void NumberInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
101 {
102     if (!valueChanged && sanitizedValue.isEmpty() && !element().innerTextValue().isEmpty())
103         updateInnerTextValue();
104     TextFieldInputType::setValue(sanitizedValue, valueChanged, eventBehavior);
105 }
106
107 double NumberInputType::valueAsDouble() const
108 {
109     return parseToDoubleForNumberType(element().value());
110 }
111
112 void NumberInputType::setValueAsDouble(double newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
113 {
114     // FIXME: We should use numeric_limits<double>::max for number input type.
115     const double floatMax = std::numeric_limits<float>::max();
116     if (newValue < -floatMax) {
117         ec = INVALID_STATE_ERR;
118         return;
119     }
120     if (newValue > floatMax) {
121         ec = INVALID_STATE_ERR;
122         return;
123     }
124     element().setValue(serializeForNumberType(newValue), eventBehavior);
125 }
126
127 void NumberInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
128 {
129     // FIXME: We should use numeric_limits<double>::max for number input type.
130     const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
131     if (newValue < -floatMax) {
132         ec = INVALID_STATE_ERR;
133         return;
134     }
135     if (newValue > floatMax) {
136         ec = INVALID_STATE_ERR;
137         return;
138     }
139     element().setValue(serializeForNumberType(newValue), eventBehavior);
140 }
141
142 bool NumberInputType::typeMismatchFor(const String& value) const
143 {
144     return !value.isEmpty() && !std::isfinite(parseToDoubleForNumberType(value));
145 }
146
147 bool NumberInputType::typeMismatch() const
148 {
149     ASSERT(!typeMismatchFor(element().value()));
150     return false;
151 }
152
153 StepRange NumberInputType::createStepRange(AnyStepHandling anyStepHandling) const
154 {
155     static NeverDestroyed<const StepRange::StepDescription> stepDescription(numberDefaultStep, numberDefaultStepBase, numberStepScaleFactor);
156     const Decimal stepBase = parseToDecimalForNumberType(element().fastGetAttribute(minAttr), numberDefaultStepBase);
157     // FIXME: We should use numeric_limits<double>::max for number input type.
158     const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
159     const Decimal minimum = parseToNumber(element().fastGetAttribute(minAttr), -floatMax);
160     const Decimal maximum = parseToNumber(element().fastGetAttribute(maxAttr), floatMax);
161     const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element().fastGetAttribute(stepAttr));
162     return StepRange(stepBase, minimum, maximum, step, stepDescription);
163 }
164
165 bool NumberInputType::sizeShouldIncludeDecoration(int defaultSize, int& preferredSize) const
166 {
167     preferredSize = defaultSize;
168
169     const String stepString = element().fastGetAttribute(stepAttr);
170     if (equalIgnoringCase(stepString, "any"))
171         return false;
172
173     const Decimal minimum = parseToDecimalForNumberType(element().fastGetAttribute(minAttr));
174     if (!minimum.isFinite())
175         return false;
176
177     const Decimal maximum = parseToDecimalForNumberType(element().fastGetAttribute(maxAttr));
178     if (!maximum.isFinite())
179         return false;
180
181     const Decimal step = parseToDecimalForNumberType(stepString, 1);
182     ASSERT(step.isFinite());
183
184     RealNumberRenderSize size = calculateRenderSize(minimum).max(calculateRenderSize(maximum).max(calculateRenderSize(step)));
185
186     preferredSize = size.sizeBeforeDecimalPoint + size.sizeAfteDecimalPoint + (size.sizeAfteDecimalPoint ? 1 : 0);
187
188     return true;
189 }
190
191 float NumberInputType::decorationWidth() const
192 {
193     float width = 0;
194     HTMLElement* spinButton = element().innerSpinButtonElement();
195     if (RenderBox* spinRenderer = spinButton ? spinButton->renderBox() : 0) {
196         width += spinRenderer->borderAndPaddingLogicalWidth();
197         // Since the width of spinRenderer is not calculated yet, spinRenderer->logicalWidth() returns 0.
198         // So computedStyle()->logicalWidth() is used instead.
199         width += spinButton->computedStyle()->logicalWidth().value();
200     }
201     return width;
202 }
203
204 bool NumberInputType::isSteppable() const
205 {
206     return true;
207 }
208
209 void NumberInputType::handleKeydownEvent(KeyboardEvent* event)
210 {
211     handleKeydownEventForSpinButton(event);
212     if (!event->defaultHandled())
213         TextFieldInputType::handleKeydownEvent(event);
214 }
215
216 Decimal NumberInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
217 {
218     return parseToDecimalForNumberType(src, defaultValue);
219 }
220
221 String NumberInputType::serialize(const Decimal& value) const
222 {
223     if (!value.isFinite())
224         return String();
225     return serializeForNumberType(value);
226 }
227
228 static bool isE(UChar ch)
229 {
230     return ch == 'e' || ch == 'E';
231 }
232
233 String NumberInputType::localizeValue(const String& proposedValue) const
234 {
235     if (proposedValue.isEmpty())
236         return proposedValue;
237     // We don't localize scientific notations.
238     if (proposedValue.find(isE) != notFound)
239         return proposedValue;
240     return element().locale().convertToLocalizedNumber(proposedValue);
241 }
242
243 String NumberInputType::visibleValue() const
244 {
245     return localizeValue(element().value());
246 }
247
248 String NumberInputType::convertFromVisibleValue(const String& visibleValue) const
249 {
250     if (visibleValue.isEmpty())
251         return visibleValue;
252     // We don't localize scientific notations.
253     if (visibleValue.find(isE) != notFound)
254         return visibleValue;
255     return element().locale().convertFromLocalizedNumber(visibleValue);
256 }
257
258 String NumberInputType::sanitizeValue(const String& proposedValue) const
259 {
260     if (proposedValue.isEmpty())
261         return proposedValue;
262     return std::isfinite(parseToDoubleForNumberType(proposedValue)) ? proposedValue : emptyString();
263 }
264
265 bool NumberInputType::hasBadInput() const
266 {
267     String standardValue = convertFromVisibleValue(element().innerTextValue());
268     return !standardValue.isEmpty() && !std::isfinite(parseToDoubleForNumberType(standardValue));
269 }
270
271 String NumberInputType::badInputText() const
272 {
273     return validationMessageBadInputForNumberText();
274 }
275
276 bool NumberInputType::supportsPlaceholder() const
277 {
278     return true;
279 }
280
281 bool NumberInputType::isNumberField() const
282 {
283     return true;
284 }
285
286 void NumberInputType::minOrMaxAttributeChanged()
287 {
288     InputType::minOrMaxAttributeChanged();
289
290     if (element().renderer())
291         element().renderer()->setNeedsLayoutAndPrefWidthsRecalc();
292 }
293
294 void NumberInputType::stepAttributeChanged()
295 {
296     InputType::stepAttributeChanged();
297
298     if (element().renderer())
299         element().renderer()->setNeedsLayoutAndPrefWidthsRecalc();
300 }
301
302 } // namespace WebCore