~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/html/NumberInputType.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
const AtomicString& NumberInputType::formControlType() const
 
105
{
 
106
    return InputTypeNames::number();
 
107
}
 
108
 
 
109
double NumberInputType::valueAsDouble() const
 
110
{
 
111
    return parseToDoubleForNumberType(element()->value());
 
112
}
 
113
 
 
114
void NumberInputType::setValueAsDouble(double newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
 
115
{
 
116
    // FIXME: We should use numeric_limits<double>::max for number input type.
 
117
    const double floatMax = numeric_limits<float>::max();
 
118
    if (newValue < -floatMax) {
 
119
        ec = INVALID_STATE_ERR;
 
120
        return;
 
121
    }
 
122
    if (newValue > floatMax) {
 
123
        ec = INVALID_STATE_ERR;
 
124
        return;
 
125
    }
 
126
    element()->setValue(serializeForNumberType(newValue), eventBehavior);
 
127
}
 
128
 
 
129
void NumberInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
 
130
{
 
131
    // FIXME: We should use numeric_limits<double>::max for number input type.
 
132
    const Decimal floatMax = Decimal::fromDouble(numeric_limits<float>::max());
 
133
    if (newValue < -floatMax) {
 
134
        ec = INVALID_STATE_ERR;
 
135
        return;
 
136
    }
 
137
    if (newValue > floatMax) {
 
138
        ec = INVALID_STATE_ERR;
 
139
        return;
 
140
    }
 
141
    element()->setValue(serializeForNumberType(newValue), eventBehavior);
 
142
}
 
143
 
 
144
bool NumberInputType::typeMismatchFor(const String& value) const
 
145
{
 
146
    return !value.isEmpty() && !isfinite(parseToDoubleForNumberType(value));
 
147
}
 
148
 
 
149
bool NumberInputType::typeMismatch() const
 
150
{
 
151
    ASSERT(!typeMismatchFor(element()->value()));
 
152
    return false;
 
153
}
 
154
 
 
155
StepRange NumberInputType::createStepRange(AnyStepHandling anyStepHandling) const
 
156
{
 
157
    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (numberDefaultStep, numberDefaultStepBase, numberStepScaleFactor));
 
158
    const Decimal stepBase = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr), numberDefaultStepBase);
 
159
    // FIXME: We should use numeric_limits<double>::max for number input type.
 
160
    const Decimal floatMax = Decimal::fromDouble(numeric_limits<float>::max());
 
161
    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), -floatMax);
 
162
    const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), floatMax);
 
163
    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
 
164
    return StepRange(stepBase, minimum, maximum, step, stepDescription);
 
165
}
 
166
 
 
167
bool NumberInputType::sizeShouldIncludeDecoration(int defaultSize, int& preferredSize) const
 
168
{
 
169
    preferredSize = defaultSize;
 
170
 
 
171
    const String stepString = element()->fastGetAttribute(stepAttr);
 
172
    if (equalIgnoringCase(stepString, "any"))
 
173
        return false;
 
174
 
 
175
    const Decimal minimum = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr));
 
176
    if (!minimum.isFinite())
 
177
        return false;
 
178
 
 
179
    const Decimal maximum = parseToDecimalForNumberType(element()->fastGetAttribute(maxAttr));
 
180
    if (!maximum.isFinite())
 
181
        return false;
 
182
 
 
183
    const Decimal step = parseToDecimalForNumberType(stepString, 1);
 
184
    ASSERT(step.isFinite());
 
185
 
 
186
    RealNumberRenderSize size = calculateRenderSize(minimum).max(calculateRenderSize(maximum).max(calculateRenderSize(step)));
 
187
 
 
188
    preferredSize = size.sizeBeforeDecimalPoint + size.sizeAfteDecimalPoint + (size.sizeAfteDecimalPoint ? 1 : 0);
 
189
 
 
190
    return true;
 
191
}
 
192
 
 
193
bool NumberInputType::isSteppable() const
 
194
{
 
195
    return true;
 
196
}
 
197
 
 
198
void NumberInputType::handleKeydownEvent(KeyboardEvent* event)
 
199
{
 
200
    handleKeydownEventForSpinButton(event);
 
201
    if (!event->defaultHandled())
 
202
        TextFieldInputType::handleKeydownEvent(event);
 
203
}
 
204
 
 
205
Decimal NumberInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
 
206
{
 
207
    return parseToDecimalForNumberType(src, defaultValue);
 
208
}
 
209
 
 
210
String NumberInputType::serialize(const Decimal& value) const
 
211
{
 
212
    if (!value.isFinite())
 
213
        return String();
 
214
    return serializeForNumberType(value);
 
215
}
 
216
 
 
217
static bool isE(UChar ch)
 
218
{
 
219
    return ch == 'e' || ch == 'E';
 
220
}
 
221
 
 
222
String NumberInputType::localizeValue(const String& proposedValue) const
 
223
{
 
224
    if (proposedValue.isEmpty())
 
225
        return proposedValue;
 
226
    // We don't localize scientific notations.
 
227
    if (proposedValue.find(isE) != notFound)
 
228
        return proposedValue;
 
229
    return element()->locale().convertToLocalizedNumber(proposedValue);
 
230
}
 
231
 
 
232
String NumberInputType::visibleValue() const
 
233
{
 
234
    return localizeValue(element()->value());
 
235
}
 
236
 
 
237
String NumberInputType::convertFromVisibleValue(const String& visibleValue) const
 
238
{
 
239
    if (visibleValue.isEmpty())
 
240
        return visibleValue;
 
241
    // We don't localize scientific notations.
 
242
    if (visibleValue.find(isE) != notFound)
 
243
        return visibleValue;
 
244
    return element()->locale().convertFromLocalizedNumber(visibleValue);
 
245
}
 
246
 
 
247
String NumberInputType::sanitizeValue(const String& proposedValue) const
 
248
{
 
249
    if (proposedValue.isEmpty())
 
250
        return proposedValue;
 
251
    return isfinite(parseToDoubleForNumberType(proposedValue)) ? proposedValue : emptyString();
 
252
}
 
253
 
 
254
bool NumberInputType::hasBadInput() const
 
255
{
 
256
    String standardValue = convertFromVisibleValue(element()->innerTextValue());
 
257
    return !standardValue.isEmpty() && !isfinite(parseToDoubleForNumberType(standardValue));
 
258
}
 
259
 
 
260
String NumberInputType::badInputText() const
 
261
{
 
262
    return validationMessageBadInputForNumberText();
 
263
}
 
264
 
 
265
bool NumberInputType::shouldRespectSpeechAttribute()
 
266
{
 
267
    return true;
 
268
}
 
269
 
 
270
bool NumberInputType::supportsPlaceholder() const
 
271
{
 
272
    return true;
 
273
}
 
274
 
 
275
bool NumberInputType::isNumberField() const
 
276
{
 
277
    return true;
 
278
}
 
279
 
 
280
void NumberInputType::minOrMaxAttributeChanged()
 
281
{
 
282
    InputType::minOrMaxAttributeChanged();
 
283
 
 
284
    if (element()->renderer())
 
285
        element()->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
 
286
}
 
287
 
 
288
void NumberInputType::stepAttributeChanged()
 
289
{
 
290
    InputType::stepAttributeChanged();
 
291
 
 
292
    if (element()->renderer())
 
293
        element()->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
 
294
}
 
295
 
 
296
} // namespace WebCore