Commit c945b6c5 authored by tkent@chromium.org's avatar tkent@chromium.org

Support localized numbers in <input type=number>

https://bugs.webkit.org/show_bug.cgi?id=42484

Reviewed by Dimitri Glazkov.

Source/WebCore:

This change adds support of localized numbers in <input type=number>.
This affects only the UI, and not HTMLInputElement::value.

- Remove the keyboard input restriction feature because it is hard to
  retrieve characters usable for localized numbers in ICU.

- Separate convertFromVisibleValue() from sanitizeValue().
  sanitizeValue() is used for not only converting a renderer value to a
  DOM value.

- Implement LocalizedNumber functions for ICU and NSNumberFormatter.
  It is used only in Chromium for now.

Test: manual-tests/input-number-localization.html

* WebCore.gypi: Use LocalizedNumberICU.cpp.
* WebCore.xcodeproj/project.pbxproj:
  Add LocalizedNumberMac.mm and remove LocalizedNumberNone.cpp.
* dom/InputElement.h: Introduce convertFromVisibleValue().
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::convertFromVisibleValue):
* html/HTMLInputElement.h:
* html/InputType.cpp:
(WebCore::InputType::convertFromVisibleValue):
* html/InputType.h:
* html/NumberInputType.cpp: Remove isHTMLNumberCharacter(),
  isNumberCharacter(), and handleBeforeTextInsertedEvent() because we
  remove the keyboard input restriction feature for type=number.
(WebCore::NumberInputType::convertFromVisibleValue):
(WebCore::NumberInputType::sanitizeValue):
* html/NumberInputType.h:
* manual-tests/input-number-localization.html: Add a manual test because
  the behavior depends on the current locale.
* platform/text/LocalizedNumber.h: Remove isLocalizedNumberCharacter().
* platform/text/LocalizedNumberICU.cpp:
  Implement LocalizedNumber functions with ICU NumberFormat.
(WebCore::createFormatterForCurrentLocale):
(WebCore::parseLocalizedNumber):
(WebCore::formatLocalizedNumber):
* platform/text/LocalizedNumberNone.cpp: Remove isLocalizedNumberCharacter().
* platform/text/mac/LocalizedNumberMac.mm:
  Implement LocalizedNumber functions with NSNumberFormatter.
(WebCore::parseLocalizedNumber):
(WebCore::formatLocalizedNumber):
* rendering/RenderTextControlSingleLine.cpp:
(WebCore::RenderTextControlSingleLine::subtreeHasChanged):
* wml/WMLInputElement.h:
(WebCore::WMLInputElement::convertFromVisibleValue):
  Implemented as a function doing nothing.

LayoutTests:

Update an existing test because of removing the keyboard input
restriction feature.

* fast/forms/input-number-keyoperation-expected.txt:
* fast/forms/script-tests/input-number-keyoperation.js:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@80096 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d959e445
2011-03-01 Kent Tamura <tkent@chromium.org>
Reviewed by Dimitri Glazkov.
Support localized numbers in <input type=number>
https://bugs.webkit.org/show_bug.cgi?id=42484
Update an existing test because of removing the keyboard input
restriction feature.
* fast/forms/input-number-keyoperation-expected.txt:
* fast/forms/script-tests/input-number-keyoperation.js:
2011-03-01 Victoria Kirst <vrk@chromium.org>
Reviewed by Kenneth Russell.
......
......@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
Inserting "ab123cd":
PASS input.value is "123"
PASS input.value is ""
Press the up arrow key:
PASS input.value is "124"
Press the down arrow key:
......
......@@ -7,9 +7,10 @@ var input = document.getElementById('number');
input.focus();
debug('Inserting "ab123cd":');
document.execCommand('InsertText', false, 'ab123cd');
shouldBe('input.value', '"123"');
shouldBe('input.value', '""');
debug('Press the up arrow key:');
input.valueAsNumber = 123;
eventSender.keyDown('upArrow');
shouldBe('input.value', '"124"');
......
2011-03-01 Kent Tamura <tkent@chromium.org>
Reviewed by Dimitri Glazkov.
Support localized numbers in <input type=number>
https://bugs.webkit.org/show_bug.cgi?id=42484
This change adds support of localized numbers in <input type=number>.
This affects only the UI, and not HTMLInputElement::value.
- Remove the keyboard input restriction feature because it is hard to
retrieve characters usable for localized numbers in ICU.
- Separate convertFromVisibleValue() from sanitizeValue().
sanitizeValue() is used for not only converting a renderer value to a
DOM value.
- Implement LocalizedNumber functions for ICU and NSNumberFormatter.
It is used only in Chromium for now.
Test: manual-tests/input-number-localization.html
* WebCore.gypi: Use LocalizedNumberICU.cpp.
* WebCore.xcodeproj/project.pbxproj:
Add LocalizedNumberMac.mm and remove LocalizedNumberNone.cpp.
* dom/InputElement.h: Introduce convertFromVisibleValue().
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::convertFromVisibleValue):
* html/HTMLInputElement.h:
* html/InputType.cpp:
(WebCore::InputType::convertFromVisibleValue):
* html/InputType.h:
* html/NumberInputType.cpp: Remove isHTMLNumberCharacter(),
isNumberCharacter(), and handleBeforeTextInsertedEvent() because we
remove the keyboard input restriction feature for type=number.
(WebCore::NumberInputType::convertFromVisibleValue):
(WebCore::NumberInputType::sanitizeValue):
* html/NumberInputType.h:
* manual-tests/input-number-localization.html: Add a manual test because
the behavior depends on the current locale.
* platform/text/LocalizedNumber.h: Remove isLocalizedNumberCharacter().
* platform/text/LocalizedNumberICU.cpp:
Implement LocalizedNumber functions with ICU NumberFormat.
(WebCore::createFormatterForCurrentLocale):
(WebCore::parseLocalizedNumber):
(WebCore::formatLocalizedNumber):
* platform/text/LocalizedNumberNone.cpp: Remove isLocalizedNumberCharacter().
* platform/text/mac/LocalizedNumberMac.mm:
Implement LocalizedNumber functions with NSNumberFormatter.
(WebCore::parseLocalizedNumber):
(WebCore::formatLocalizedNumber):
* rendering/RenderTextControlSingleLine.cpp:
(WebCore::RenderTextControlSingleLine::subtreeHasChanged):
* wml/WMLInputElement.h:
(WebCore::WMLInputElement::convertFromVisibleValue):
Implemented as a function doing nothing.
2011-03-01 Yuta Kitamura <yutak@chromium.org>
Reviewed by Darin Adler.
......
......@@ -3385,7 +3385,7 @@
'platform/text/LineEnding.cpp',
'platform/text/LineEnding.h',
'platform/text/LocalizedNumber.h',
'platform/text/LocalizedNumberNone.cpp',
'platform/text/LocalizedNumberICU.cpp',
'platform/text/ParserUtilities.h',
'platform/text/PlatformString.h',
'platform/text/RegularExpression.cpp',
......
......@@ -5602,7 +5602,6 @@
F4EAF4AE10C742B1009100D3 /* OpenTypeSanitizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4EAF4AC10C742B1009100D3 /* OpenTypeSanitizer.cpp */; };
F4EAF4AF10C742B1009100D3 /* OpenTypeSanitizer.h in Headers */ = {isa = PBXBuildFile; fileRef = F4EAF4AD10C742B1009100D3 /* OpenTypeSanitizer.h */; };
F5142C69123F12B000F5BD4C /* LocalizedNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = F5142C68123F12B000F5BD4C /* LocalizedNumber.h */; };
F5142C6B123F12C500F5BD4C /* LocalizedNumberNone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5142C6A123F12C500F5BD4C /* LocalizedNumberNone.cpp */; };
F55B3DAD1251F12D003EF269 /* BaseTextInputType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F55B3D791251F12D003EF269 /* BaseTextInputType.cpp */; };
F55B3DAE1251F12D003EF269 /* BaseTextInputType.h in Headers */ = {isa = PBXBuildFile; fileRef = F55B3D7A1251F12D003EF269 /* BaseTextInputType.h */; };
F55B3DAF1251F12D003EF269 /* ButtonInputType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F55B3D7B1251F12D003EF269 /* ButtonInputType.cpp */; };
......@@ -5666,6 +5665,7 @@
F5C041E50FFCA96D00839D4A /* DOMHTMLDataListElementInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = F5C041E00FFCA96D00839D4A /* DOMHTMLDataListElementInternal.h */; };
F5C041E60FFCA96D00839D4A /* JSHTMLDataListElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5C041E10FFCA96D00839D4A /* JSHTMLDataListElement.cpp */; };
F5C041E70FFCA96D00839D4A /* JSHTMLDataListElement.h in Headers */ = {isa = PBXBuildFile; fileRef = F5C041E20FFCA96D00839D4A /* JSHTMLDataListElement.h */; };
F5CC42DC12F801CA00D5F7E3 /* LocalizedNumberMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = F5CC42DB12F801CA00D5F7E3 /* LocalizedNumberMac.mm */; };
F5D3A57C106B83B300545297 /* DateComponents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5D3A57A106B83B300545297 /* DateComponents.cpp */; };
F5D3A57D106B83B300545297 /* DateComponents.h in Headers */ = {isa = PBXBuildFile; fileRef = F5D3A57B106B83B300545297 /* DateComponents.h */; settings = {ATTRIBUTES = (Private, ); }; };
F7A034C4126BF6BE007DC19E /* FontOrientation.h in Headers */ = {isa = PBXBuildFile; fileRef = F7A034C3126BF6BE007DC19E /* FontOrientation.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -12008,7 +12008,6 @@
F4EAF4AC10C742B1009100D3 /* OpenTypeSanitizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OpenTypeSanitizer.cpp; path = opentype/OpenTypeSanitizer.cpp; sourceTree = "<group>"; };
F4EAF4AD10C742B1009100D3 /* OpenTypeSanitizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenTypeSanitizer.h; path = opentype/OpenTypeSanitizer.h; sourceTree = "<group>"; };
F5142C68123F12B000F5BD4C /* LocalizedNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalizedNumber.h; sourceTree = "<group>"; };
F5142C6A123F12C500F5BD4C /* LocalizedNumberNone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LocalizedNumberNone.cpp; sourceTree = "<group>"; };
F523D23B02DE4396018635CA /* HTMLDocument.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLDocument.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
F523D23C02DE4396018635CA /* HTMLDocument.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = HTMLDocument.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
F523D23E02DE4396018635CA /* HTMLElement.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLElement.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
......@@ -12094,6 +12093,7 @@
F5C2869302846DCD018635CA /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = "<absolute>"; };
F5C2869402846DCD018635CA /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
F5C2869502846DCD018635CA /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
F5CC42DB12F801CA00D5F7E3 /* LocalizedNumberMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalizedNumberMac.mm; sourceTree = "<group>"; };
F5D3A57A106B83B300545297 /* DateComponents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DateComponents.cpp; sourceTree = "<group>"; };
F5D3A57B106B83B300545297 /* DateComponents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateComponents.h; sourceTree = "<group>"; };
F7A034C3126BF6BE007DC19E /* FontOrientation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontOrientation.h; sourceTree = "<group>"; };
......@@ -17593,7 +17593,6 @@
89B5EA9F11E8003D00F2367E /* LineEnding.cpp */,
89B5EAA011E8003D00F2367E /* LineEnding.h */,
F5142C68123F12B000F5BD4C /* LocalizedNumber.h */,
F5142C6A123F12C500F5BD4C /* LocalizedNumberNone.cpp */,
BC76AC110DD7AD5C00415F34 /* ParserUtilities.h */,
B2C3D9FB0D006C1D00EF6F26 /* PlatformString.h */,
B2C3D9FC0D006C1D00EF6F26 /* RegularExpression.cpp */,
......@@ -17642,6 +17641,7 @@
B2AFFC850D00A5DF0030074D /* character-sets.txt */,
B2C3D9FA0D006C1D00EF6F26 /* CharsetData.h */,
375CD239119D44EA00A2A859 /* HyphenationMac.mm */,
F5CC42DB12F801CA00D5F7E3 /* LocalizedNumberMac.mm */,
B2AFFC860D00A5DF0030074D /* mac-encodings.txt */,
B2AFFC870D00A5DF0030074D /* make-charset-table.pl */,
B2AFFC880D00A5DF0030074D /* ShapeArabic.c */,
......@@ -24361,7 +24361,7 @@
7EE6846812D26E3800E79415 /* LoaderRunLoopCF.cpp in Sources */,
06E81EEC0AB5DA9700C87837 /* LocalCurrentGraphicsContext.mm in Sources */,
89878567122CA064003AABDA /* LocalFileSystem.cpp in Sources */,
F5142C6B123F12C500F5BD4C /* LocalizedNumberNone.cpp in Sources */,
F5CC42DC12F801CA00D5F7E3 /* LocalizedNumberMac.mm in Sources */,
C046E1AC1208A9FE00BA2CF7 /* LocalizedStrings.cpp in Sources */,
BC25B52A131C6D3900180E10 /* LocalizedStringsMac.mm in Sources */,
511F23170DC160DA004F0032 /* LocalStorageTask.cpp in Sources */,
......@@ -61,6 +61,7 @@ public:
virtual void setValueForUser(const String&) = 0;
// The value which is drawn by a renderer.
virtual String visibleValue() const = 0;
virtual String convertFromVisibleValue(const String&) const = 0;
// Returns true if the specified string can be set as the value of InputElement.
virtual bool isAcceptableValue(const String&) const = 0;
......
......@@ -1150,6 +1150,11 @@ String HTMLInputElement::visibleValue() const
return m_inputType->visibleValue();
}
String HTMLInputElement::convertFromVisibleValue(const String& visibleValue) const
{
return m_inputType->convertFromVisibleValue(visibleValue);
}
bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const
{
return m_inputType->isAcceptableValue(proposedValue);
......
......@@ -260,6 +260,7 @@ private:
virtual void cacheSelection(int start, int end);
virtual String visibleValue() const;
virtual String convertFromVisibleValue(const String&) const;
virtual bool isAcceptableValue(const String&) const;
virtual String sanitizeValue(const String&) const;
virtual bool hasUnacceptableValue() const;
......
......@@ -515,6 +515,11 @@ String InputType::visibleValue() const
return element()->value();
}
String InputType::convertFromVisibleValue(const String& visibleValue) const
{
return visibleValue;
}
bool InputType::isAcceptableValue(const String&)
{
return true;
......
......@@ -149,6 +149,7 @@ public:
virtual String valueMissingText() const;
virtual bool canSetStringValue() const;
virtual String visibleValue() const;
virtual String convertFromVisibleValue(const String&) const;
virtual bool isAcceptableValue(const String&);
// Returing the null string means "use the default value."
virtual String sanitizeValue(const String&);
......
......@@ -53,18 +53,6 @@ using namespace std;
static const double numberDefaultStep = 1.0;
static const double numberStepScaleFactor = 1.0;
// Returns true if the specified character can be a part of 'valid floating
// point number' of HTML5.
static bool isHTMLNumberCharacter(UChar ch)
{
return ch == '+' || ch == '-' || ch == '.' || ch == 'e' || ch == 'E' || isASCIIDigit(ch);
}
static bool isNumberCharacter(UChar ch)
{
return isLocalizedNumberCharacter(ch) || isHTMLNumberCharacter(ch);
}
PassOwnPtr<InputType> NumberInputType::create(HTMLInputElement* element)
{
return adoptPtr(new NumberInputType(element));
......@@ -183,30 +171,6 @@ void NumberInputType::handleKeydownEvent(KeyboardEvent* event)
TextFieldInputType::handleKeydownEvent(event);
}
void NumberInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event)
{
unsigned length = event->text().length();
bool hasInvalidChar = false;
for (unsigned i = 0; i < length; ++i) {
if (!isNumberCharacter(event->text()[i])) {
hasInvalidChar = true;
break;
}
}
if (hasInvalidChar) {
Vector<UChar> stripped;
stripped.reserveCapacity(length);
for (unsigned i = 0; i < length; ++i) {
UChar ch = event->text()[i];
if (!isNumberCharacter(ch))
continue;
stripped.append(ch);
}
event->setText(String::adopt(stripped));
}
TextFieldInputType::handleBeforeTextInsertedEvent(event);
}
void NumberInputType::handleWheelEvent(WheelEvent* event)
{
handleWheelEventForSpinButton(event);
......@@ -264,6 +228,14 @@ String NumberInputType::visibleValue() const
return localized.isEmpty() ? currentValue : localized;
}
String NumberInputType::convertFromVisibleValue(const String& visibleValue) const
{
if (visibleValue.isEmpty())
return visibleValue;
double parsedNumber = parseLocalizedNumber(visibleValue);
return isfinite(parsedNumber) ? serializeForNumberType(parsedNumber) : visibleValue;
}
bool NumberInputType::isAcceptableValue(const String& proposedValue)
{
return proposedValue.isEmpty() || isfinite(parseLocalizedNumber(proposedValue)) || parseToDoubleForNumberType(proposedValue, 0);
......@@ -273,11 +245,6 @@ String NumberInputType::sanitizeValue(const String& proposedValue)
{
if (proposedValue.isEmpty())
return proposedValue;
// Try to parse the value as a localized number, then try to parse it as
// the standard format.
double parsedValue = parseLocalizedNumber(proposedValue);
if (isfinite(parsedValue))
return serializeForNumberType(parsedValue);
return parseToDoubleForNumberType(proposedValue, 0) ? proposedValue : emptyAtom.string();
}
......
......@@ -57,7 +57,6 @@ private:
virtual double defaultStep() const;
virtual double stepScaleFactor() const;
virtual void handleKeydownEvent(KeyboardEvent*);
virtual void handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*);
virtual void handleWheelEvent(WheelEvent*);
virtual double parseToDouble(const String&, double) const;
virtual double parseToDoubleWithDecimalPlaces(const String&, double, unsigned*) const;
......@@ -65,6 +64,7 @@ private:
virtual double acceptableError(double) const;
virtual void handleBlurEvent();
virtual String visibleValue() const;
virtual String convertFromVisibleValue(const String&) const;
virtual bool isAcceptableValue(const String&);
virtual String sanitizeValue(const String&);
virtual bool hasUnacceptableValue();
......
<!DOCTYPE html>
<html>
<head>
<title>Number type input shows and accepts localized numbers</title>
<style>
:invalid {
border-color: red;
-webkit-box-shadow: 4px 4px 8px #ff8888;
}
</style>
</head>
<body>
<div id="console"></div>
<p>Output test: The following text field should have a localized representation for "-1234.56".
e.g. "-1,234.56" for en_US locale, "-1.234,56" for fr_FR locale.</p>
<div><input type=number value="-1234.56" step=any></div>
<p>Input test: Type a localized representation of a number into the following text field.
You'll see an equivalent number in the standard format on the bottom of the text field.</p>
<div><input type=number id=target step=any oninput="handleInput()"></div>
<div>Standard format: <output id=output></output></div>
<script>
function handleInput() {
document.getElementById('output').value = document.getElementById('target').value;
}
</script>
</body>
</html>
......@@ -49,11 +49,6 @@ double parseLocalizedNumber(const String&);
// return an empty string.
String formatLocalizedNumber(double);
// Returns true if the input character can be used to represent a
// number in the browser locale. For example, this should return true for 0-9 .
// , + - for en-US locale.
bool isLocalizedNumberCharacter(UChar32);
} // namespace WebCore
#endif // LocalizedNumber_h
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "LocalizedNumber.h"
#include <limits>
#include <unicode/numfmt.h>
#include <wtf/PassOwnPtr.h>
using namespace std;
namespace WebCore {
static inline PassOwnPtr<NumberFormat> createFormatterForCurrentLocale()
{
UErrorCode status = U_ZERO_ERROR;
return adoptPtr(NumberFormat::createInstance(status));
}
double parseLocalizedNumber(const String& numberString)
{
if (numberString.isEmpty())
return numeric_limits<double>::quiet_NaN();
OwnPtr<NumberFormat> formatter = createFormatterForCurrentLocale();
if (!formatter)
return numeric_limits<double>::quiet_NaN();
UnicodeString numberUnicodeString(numberString.characters(), numberString.length());
UErrorCode status = U_ZERO_ERROR;
Formattable result;
formatter->parse(numberUnicodeString, result, status);
if (status != U_ZERO_ERROR)
return numeric_limits<double>::quiet_NaN();
double numericResult = result.getDouble(status);
return status == U_ZERO_ERROR ? numericResult : numeric_limits<double>::quiet_NaN();
}
String formatLocalizedNumber(double number)
{
OwnPtr<NumberFormat> formatter = createFormatterForCurrentLocale();
if (!formatter)
return String();
UnicodeString result;
formatter->format(number, result);
return String(result.getBuffer(), result.length());
}
} // namespace WebCore
......@@ -47,9 +47,4 @@ String formatLocalizedNumber(double)
return String();
}
bool isLocalizedNumberCharacter(UChar32)
{
return false;
}
} // namespace WebCore
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "LocalizedNumber.h"
#include <limits>
#import <Foundation/NSNumberFormatter.h>
#include <wtf/RetainPtr.h>
#include <wtf/text/CString.h>
using namespace std;
namespace WebCore {
double parseLocalizedNumber(const String& numberString)
{
if (numberString.isEmpty())
return numeric_limits<double>::quiet_NaN();
RetainPtr<NSNumberFormatter> formatter(AdoptNS, [[NSNumberFormatter alloc] init]);
[formatter.get() setLocalizesFormat:YES];
[formatter.get() setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *number = [formatter.get() numberFromString:numberString];
if (!number)
return numeric_limits<double>::quiet_NaN();
return [number doubleValue];
}
String formatLocalizedNumber(double inputNumber)
{
RetainPtr<NSNumber> number(AdoptNS, [[NSNumber alloc] initWithDouble:inputNumber]);
RetainPtr<NSNumberFormatter> formatter(AdoptNS, [[NSNumberFormatter alloc] init]);
[formatter.get() setLocalizesFormat:YES];
[formatter.get() setNumberStyle:NSNumberFormatterDecimalStyle];
return String([formatter.get() stringFromNumber:number.get()]);
}
} // namespace WebCore
......@@ -191,7 +191,7 @@ void RenderTextControlSingleLine::subtreeHasChanged()
// sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
String value = text();
if (input->isAcceptableValue(value))
input->setValueFromRenderer(input->sanitizeValue(value));
input->setValueFromRenderer(input->sanitizeValue(input->convertFromVisibleValue(value)));
if (node()->isHTMLElement()) {
// Recalc for :invalid and hasUnacceptableValue() change.
static_cast<HTMLInputElement*>(input)->setNeedsStyleRecalc();
......
......@@ -64,6 +64,7 @@ public:
virtual void setValue(const String&, bool sendChangeEvent = false);
virtual void setValueForUser(const String&);
virtual String visibleValue() const { return value(); }
virtual String convertFromVisibleValue(const String& value) const { return value; }
virtual void setValueFromRenderer(const String&);
virtual bool saveFormControlState(String& value) const;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment