33ad02b060e82177c16d5ad9f66c542a8def0b3f
[WebKit.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 "BeforeTextInsertedEvent.h"
36 #include "ExceptionCode.h"
37 #include "HTMLInputElement.h"
38 #include "HTMLNames.h"
39 #include "HTMLParserIdioms.h"
40 #include "InputTypeNames.h"
41 #include "KeyboardEvent.h"
42 #include "LocalizedStrings.h"
43 #include "PlatformLocale.h"
44 #include "RenderTextControl.h"
45 #include <limits>
46 #include <wtf/ASCIICType.h>
47 #include <wtf/MathExtras.h>
48 #include <wtf/PassOwnPtr.h>
49
50 namespace WebCore {
51
52 using namespace HTMLNames;
53 using namespace std;
54
55 static const int numberDefaultStep = 1;
56 static const int numberDefaultStepBase = 0;
57 static const int numberStepScaleFactor = 1;
58
59 struct RealNumberRenderSize
60 {
61     unsigned sizeBeforeDecimalPoint;
62     unsigned sizeAfteDecimalPoint;
63
64     RealNumberRenderSize(unsigned before, unsigned after)
65         : sizeBeforeDecimalPoint(before)
66         , sizeAfteDecimalPoint(after)
67     {
68     }
69
70     RealNumberRenderSize max(const RealNumberRenderSize& other) const
71     {
72         return RealNumberRenderSize(
73             std::max(sizeBeforeDecimalPoint, other.sizeBeforeDecimalPoint),
74             std::max(sizeAfteDecimalPoint, other.sizeAfteDecimalPoint));
75     }
76 };
77
78 static RealNumberRenderSize calculateRenderSize(const Decimal& value)
79 {
80     ASSERT(value.isFinite());
81     const unsigned sizeOfDigits = String::number(value.value().coefficient()).length();
82     const unsigned sizeOfSign = value.isNegative() ? 1 : 0;
83     const int exponent = value.exponent();
84     if (exponent >= 0)
85         return RealNumberRenderSize(sizeOfSign + sizeOfDigits, 0);
86
87     const int sizeBeforeDecimalPoint = exponent + sizeOfDigits;
88     if (sizeBeforeDecimalPoint > 0) {
89         // In case of "123.456"
90         return RealNumberRenderSize(sizeOfSign + sizeBeforeDecimalPoint, sizeOfDigits - sizeBeforeDecimalPoint);
91     }
92
93     // In case of "0.00012345"
94     const unsigned sizeOfZero = 1;
95     const unsigned numberOfZeroAfterDecimalPoint = -sizeBeforeDecimalPoint;
96     return RealNumberRenderSize(sizeOfSign + sizeOfZero , numberOfZeroAfterDecimalPoint + sizeOfDigits);
97 }
98
99 PassOwnPtr<InputType> NumberInputType::create(HTMLInputElement* element)
100 {
101     return adoptPtr(new NumberInputType(element));
102 }
103
104 void NumberInputType::attach()
105 {
106     TextFieldInputType::attach();
107     observeFeatureIfVisible(FeatureObserver::InputTypeNumber);
108 }
109
110 const AtomicString& NumberInputType::formControlType() const
111 {
112     return InputTypeNames::number();
113 }
114
115 void NumberInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
116 {
117     if (!valueChanged && sanitizedValue.isEmpty() && !element()->innerTextValue().isEmpty())
118         updateInnerTextValue();
119     TextFieldInputType::setValue(sanitizedValue, valueChanged, eventBehavior);
120 }
121
122 double NumberInputType::valueAsDouble() const
123 {
124     return parseToDoubleForNumberType(element()->value());
125 }
126
127 void NumberInputType::setValueAsDouble(double newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
128 {
129     // FIXME: We should use numeric_limits<double>::max for number input type.
130     const double floatMax = 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 void NumberInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
143 {
144     // FIXME: We should use numeric_limits<double>::max for number input type.
145     const Decimal floatMax = Decimal::fromDouble(numeric_limits<float>::max());
146     if (newValue < -floatMax) {
147         ec = INVALID_STATE_ERR;
148         return;
149     }
150     if (newValue > floatMax) {
151         ec = INVALID_STATE_ERR;
152         return;
153     }
154     element()->setValue(serializeForNumberType(newValue), eventBehavior);
155 }
156
157 bool NumberInputType::typeMismatchFor(const String& value) const
158 {
159     return !value.isEmpty() && !isfinite(parseToDoubleForNumberType(value));
160 }
161
162 bool NumberInputType::typeMismatch() const
163 {
164     ASSERT(!typeMismatchFor(element()->value()));
165     return false;
166 }
167
168 StepRange NumberInputType::createStepRange(AnyStepHandling anyStepHandling) const
169 {
170     DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (numberDefaultStep, numberDefaultStepBase, numberStepScaleFactor));
171     const Decimal stepBase = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr), numberDefaultStepBase);
172     // FIXME: We should use numeric_limits<double>::max for number input type.
173     const Decimal floatMax = Decimal::fromDouble(numeric_limits<float>::max());
174     const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), -floatMax);
175     const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), floatMax);
176     const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
177     return StepRange(stepBase, minimum, maximum, step, stepDescription);
178 }
179
180 bool NumberInputType::sizeShouldIncludeDecoration(int defaultSize, int& preferredSize) const
181 {
182     preferredSize = defaultSize;
183
184     const String stepString = element()->fastGetAttribute(stepAttr);
185     if (equalIgnoringCase(stepString, "any"))
186         return false;
187
188     const Decimal minimum = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr));
189     if (!minimum.isFinite())
190         return false;
191
192     const Decimal maximum = parseToDecimalForNumberType(element()->fastGetAttribute(maxAttr));
193     if (!maximum.isFinite())
194         return false;
195
196     const Decimal step = parseToDecimalForNumberType(stepString, 1);
197     ASSERT(step.isFinite());
198
199     RealNumberRenderSize size = calculateRenderSize(minimum).max(calculateRenderSize(maximum).max(calculateRenderSize(step)));
200
201     preferredSize = size.sizeBeforeDecimalPoint + size.sizeAfteDecimalPoint + (size.sizeAfteDecimalPoint ? 1 : 0);
202
203     return true;
204 }
205
206 bool NumberInputType::isSteppable() const
207 {
208     return true;
209 }
210
211 void NumberInputType::handleKeydownEvent(KeyboardEvent* event)
212 {
213     handleKeydownEventForSpinButton(event);
214     if (!event->defaultHandled())
215         TextFieldInputType::handleKeydownEvent(event);
216 }
217
218 Decimal NumberInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
219 {
220     return parseToDecimalForNumberType(src, defaultValue);
221 }
222
223 String NumberInputType::serialize(const Decimal& value) const
224 {
225     if (!value.isFinite())
226         return String();
227     return serializeForNumberType(value);
228 }
229
230 static bool isE(UChar ch)
231 {
232     return ch == 'e' || ch == 'E';
233 }
234
235 String NumberInputType::localizeValue(const String& proposedValue) const
236 {
237     if (proposedValue.isEmpty())
238         return proposedValue;
239     // We don't localize scientific notations.
240     if (proposedValue.find(isE) != notFound)
241         return proposedValue;
242     return element()->locale().convertToLocalizedNumber(proposedValue);
243 }
244
245 String NumberInputType::visibleValue() const
246 {
247     return localizeValue(element()->value());
248 }
249
250 String NumberInputType::convertFromVisibleValue(const String& visibleValue) const
251 {
252     if (visibleValue.isEmpty())
253         return visibleValue;
254     // We don't localize scientific notations.
255     if (visibleValue.find(isE) != notFound)
256         return visibleValue;
257     return element()->locale().convertFromLocalizedNumber(visibleValue);
258 }
259
260 String NumberInputType::sanitizeValue(const String& proposedValue) const
261 {
262     if (proposedValue.isEmpty())
263         return proposedValue;
264     return isfinite(parseToDoubleForNumberType(proposedValue)) ? proposedValue : emptyString();
265 }
266
267 bool NumberInputType::hasBadInput() const
268 {
269     String standardValue = convertFromVisibleValue(element()->innerTextValue());
270     return !standardValue.isEmpty() && !isfinite(parseToDoubleForNumberType(standardValue));
271 }
272
273 String NumberInputType::badInputText() const
274 {
275     return validationMessageBadInputForNumberText();
276 }
277
278 bool NumberInputType::shouldRespectSpeechAttribute()
279 {
280     return true;
281 }
282
283 bool NumberInputType::supportsPlaceholder() const
284 {
285     return true;
286 }
287
288 bool NumberInputType::isNumberField() const
289 {
290     return true;
291 }
292
293 void NumberInputType::minOrMaxAttributeChanged()
294 {
295     InputType::minOrMaxAttributeChanged();
296
297     if (element()->renderer())
298         element()->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
299 }
300
301 void NumberInputType::stepAttributeChanged()
302 {
303     InputType::stepAttributeChanged();
304
305     if (element()->renderer())
306         element()->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
307 }
308
309 } // namespace WebCore