Source/JavaScriptCore/ChangeLog

 12012-01-28 Eli Fidler <efidler@rim.com>
 2
 3 Implement Number.toLocaleString() using ICU
 4 https://bugs.webkit.org/show_bug.cgi?id=77018
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * GNUmakefile.list.am:
 9 * JavaScriptCore.exp:
 10 * JavaScriptCore.gypi:
 11 * JavaScriptCore.order:
 12 * JavaScriptCore.xcodeproj/project.pbxproj:
 13 * runtime/NumberPrototype.cpp:
 14 (JSC::cachedNumberFormatterMutex): added
 15 (JSC::formatLocaleNumber): added
 16 (JSC::numberProtoFuncToLocaleString):
 17 * wtf/DecimalNumber.cpp:
 18 (WTF::DecimalNumber::toStringDecimal): make this a template to support a char* version
 19 * wtf/DecimalNumber.h:
 20 * wtf/PlatformBlackBerry.cmake:
 21 * wtf/PlatformEfl.cmake:
 22 * wtf/unicode/UnicodeMacrosFromICU.h: add ICU_VERSION_AT_LEAST macro
 23 * wtf/unicode/icu/UnicodeIcu.cpp: added
 24 * wtf/unicode/icu/UnicodeIcu.h: add ICU_VERSION_AT_LEAST macro and numeric locale accessor
 25
1262012-01-30 Oliver Hunt <oliver@apple.com>
227
328 get_by_val_arguments is broken in the interpreter

Source/JavaScriptCore/GNUmakefile.list.am

@@endif
769769if USE_ICU_UNICODE
770770javascriptcore_sources += \
771771 Source/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp \
 772 Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.cpp \
772773 Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h
773774endif # USE_ICU_UNICODE
774775

Source/JavaScriptCore/JavaScriptCore.exp

@@__ZNK3WTF10StringImpl12hashSlowCaseEv
594594__ZNK3WTF10StringImpl17getData16SlowCaseEv
595595__ZNK3WTF10StringImpl19upconvertCharactersEjj
596596__ZNK3WTF12AtomicString5lowerEv
597 __ZNK3WTF13DecimalNumber15toStringDecimalEPtj
 597__ZNK3WTF13DecimalNumber15toStringDecimalItEEjPT_j
598598__ZNK3WTF13DecimalNumber19toStringExponentialEPtj
599599__ZNK3WTF13DecimalNumber28bufferLengthForStringDecimalEv
600600__ZNK3WTF13DecimalNumber32bufferLengthForStringExponentialEv

Source/JavaScriptCore/JavaScriptCore.gypi

649649 'wtf/unicode/glib/UnicodeGLib.cpp',
650650 'wtf/unicode/glib/UnicodeGLib.h',
651651 'wtf/unicode/icu/CollatorICU.cpp',
 652 'wtf/unicode/icu/UnicodeIcu.cpp',
652653 'wtf/unicode/qt4/UnicodeQt4.h',
653654 'wtf/unicode/wince/UnicodeWinCE.cpp',
654655 'wtf/unicode/wince/UnicodeWinCE.h',

Source/JavaScriptCore/JavaScriptCore.order

@@__ZNK3JSC7JSArray12subclassDataEv
11271127__ZN3WTF10StringImpl16findIgnoringCaseEPKcj
11281128__ZN3WTF14numberToStringEdPt
11291129__ZN3WTF4dtoaILb1ELb0ELb0ELb1EEEvPcdiRbRiRj
1130 __ZNK3WTF13DecimalNumber15toStringDecimalEPtj
 1130__ZNK3WTF13DecimalNumber15toStringDecimalItEEjPT_j
11311131__ZN3WTF10StringImpl8toDoubleEPbS1_
11321132__ZN3WTF6VectorIjLm16EE6resizeEm
11331133__ZN3WTFL7multaddERNS_6BigIntEii

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

15821582 F692A8870255597D01FF60F7 /* JSValue.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSValue.cpp; sourceTree = "<group>"; tabWidth = 8; };
15831583 F69E86C114C6E551002C2C62 /* NumberOfCores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NumberOfCores.cpp; path = wtf/NumberOfCores.cpp; sourceTree = "<group>"; };
15841584 F69E86C214C6E551002C2C62 /* NumberOfCores.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NumberOfCores.h; path = wtf/NumberOfCores.h; sourceTree = "<group>"; };
 1585 F98352FB14D217A600C1DC99 /* UnicodeIcu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnicodeIcu.cpp; sourceTree = "<group>"; };
15851586 FDA15C1612B03028003A583A /* Complex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Complex.h; sourceTree = "<group>"; };
15861587 FE1B44790ECCD73B004F4DD1 /* StdLibExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StdLibExtras.h; sourceTree = "<group>"; };
15871588/* End PBXFileReference section */

26412642 E195678E09E7CF1200B89D13 /* icu */ = {
26422643 isa = PBXGroup;
26432644 children = (
 2645 F98352FB14D217A600C1DC99 /* UnicodeIcu.cpp */,
26442646 E1A862A80D7EBB76001EC6AA /* CollatorICU.cpp */,
26452647 E195678F09E7CF1200B89D13 /* UnicodeIcu.h */,
26462648 );

Source/JavaScriptCore/runtime/NumberPrototype.cpp

3131#include "Uint16WithFraction.h"
3232#include "dtoa.h"
3333#include <wtf/Assertions.h>
 34#include <wtf/DecimalNumber.h>
3435#include <wtf/MathExtras.h>
3536#include <wtf/Vector.h>
3637#include <wtf/dtoa/double-conversion.h>

@@using namespace WTF::double_conversion;
4041// To avoid conflict with WTF::StringBuilder.
4142typedef WTF::double_conversion::StringBuilder DoubleConversionStringBuilder;
4243
 44#if USE(ICU_UNICODE) && !UCONFIG_NO_FORMATTING && defined(ICU_VERSION_AT_LEAST) && ICU_VERSION_AT_LEAST(4, 4, 0)
 45#include <unicode/unum.h>
 46#endif
 47
4348namespace JSC {
4449
4550static EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);

@@static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
5560
5661namespace JSC {
5762
 63#if USE(ICU_UNICODE) && !UCONFIG_NO_FORMATTING && defined(ICU_VERSION_AT_LEAST) && ICU_VERSION_AT_LEAST(4, 4, 0)
 64
 65static UNumberFormat* cachedNumberFormatter = 0;
 66static Mutex& cachedNumberFormatterMutex()
 67{
 68 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
 69 return mutex;
 70}
 71
 72static JSCell* formatLocaleNumber(ExecState* exec, JSValue v)
 73{
 74 ASSERT(v.isNumber());
 75
 76 Locker<Mutex> lock(cachedNumberFormatterMutex());
 77 UErrorCode status = U_ZERO_ERROR;
 78 UNumberFormat* nf = 0;
 79 if (cachedNumberFormatter) {
 80 const char* cachedNumberFormatterLocale = unum_getLocaleByType(cachedNumberFormatter, ULOC_REQUESTED_LOCALE, &status);
 81 ASSERT(U_SUCCESS(status));
 82 ASSERT(cachedNumberFormatterLocale);
 83
 84 if (!strcmp(cachedNumberFormatterLocale, currentNumericLocaleID()))
 85 nf = cachedNumberFormatter;
 86 else {
 87 // locale changed... we'll need a new formatter
 88 unum_close(cachedNumberFormatter);
 89 cachedNumberFormatter = 0;
 90 }
 91 }
 92
 93 if (!nf) {
 94 nf = unum_open(UNUM_DEFAULT, 0, 0, currentNumericLocaleID(), 0, &status);
 95 if (!nf || U_FAILURE(status))
 96 return jsEmptyString(exec);
 97 cachedNumberFormatter = nf;
 98 }
 99
 100 unum_setAttribute(nf, UNUM_MAX_SIGNIFICANT_DIGITS, WTF::NumberToStringBufferLength);
 101 unum_setAttribute(nf, UNUM_SIGNIFICANT_DIGITS_USED, 1);
 102
 103 NumberToUStringBuffer buffer;
 104 int32_t length;
 105
 106 if (v.isInt32()) {
 107 int32_t num = v.asInt32();
 108 length = unum_format(nf, num, buffer, WTF::NumberToStringBufferLength, 0, &status);
 109 } else {
 110 double num;
 111 if (v.isDouble())
 112 num = v.asDouble();
 113 else
 114 num = v.toNumber(exec);
 115
 116 DecimalNumber d(num);
 117 char numberString[WTF::NumberToStringBufferLength];
 118 length = d.toStringDecimal(numberString, WTF::NumberToStringBufferLength);
 119 length = unum_formatDecimal(nf, numberString, length, buffer, WTF::NumberToStringBufferLength, 0, &status);
 120 }
 121
 122 if (U_FAILURE(status))
 123 return jsEmptyString(exec);
 124
 125 return jsNontrivialString(exec, UString(buffer, length));
 126}
 127
 128#else
 129
 130static inline JSCell* formatLocaleNumber(ExecState* exec, JSValue v)
 131{
 132 // FIXME: Not implemented yet.
 133
 134 return v.toString(exec);
 135}
 136
 137#endif
 138
58139const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) };
59140
60141/* Source for NumberPrototype.lut.h

@@EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
474555 if (!toThisNumber(exec->hostThisValue(), x))
475556 return throwVMTypeError(exec);
476557
477  return JSValue::encode(jsNumber(x).toString(exec));
 558 return JSValue::encode(formatLocaleNumber(exec, jsNumber(x)));
478559}
479560
480561EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)

Source/JavaScriptCore/wtf/DecimalNumber.cpp

@@unsigned DecimalNumber::bufferLengthForStringExponential() const
9999 return length;
100100}
101101
102 unsigned DecimalNumber::toStringDecimal(UChar* buffer, unsigned bufferLength) const
 102template <typename T>
 103unsigned DecimalNumber::toStringDecimal(T* buffer, unsigned bufferLength) const
103104{
104105 ASSERT_UNUSED(bufferLength, bufferLength >= bufferLengthForStringDecimal());
105106
106107 // Should always be at least one digit to add to the string!
107108 ASSERT(m_precision);
108  UChar* next = buffer;
 109 T* next = buffer;
109110
110111 // if the exponent is negative the number decimal representation is of the form:
111112 // [<sign>]0.[<zeros>]<significand>

@@unsigned DecimalNumber::toStringDecimal(UChar* buffer, unsigned bufferLength) co
155156 return next - buffer;
156157}
157158
 159template unsigned DecimalNumber::toStringDecimal(char* buffer, unsigned bufferLength) const;
 160template unsigned DecimalNumber::toStringDecimal(UChar* buffer, unsigned bufferLength) const;
 161
158162unsigned DecimalNumber::toStringExponential(UChar* buffer, unsigned bufferLength) const
159163{
160164 ASSERT_UNUSED(bufferLength, bufferLength >= bufferLengthForStringExponential());

Source/JavaScriptCore/wtf/DecimalNumber.h

@@public:
8484 WTF_EXPORT_PRIVATE unsigned bufferLengthForStringDecimal() const;
8585 WTF_EXPORT_PRIVATE unsigned bufferLengthForStringExponential() const;
8686
87  WTF_EXPORT_PRIVATE unsigned toStringDecimal(UChar* buffer, unsigned bufferLength) const;
 87 template <typename T>
 88 WTF_EXPORT_PRIVATE unsigned toStringDecimal(T* buffer, unsigned bufferLength) const;
8889 WTF_EXPORT_PRIVATE unsigned toStringExponential(UChar* buffer, unsigned bufferLength) const;
8990
9091 bool sign() const { return m_sign; }

Source/JavaScriptCore/wtf/PlatformBlackBerry.cmake

@@LIST(APPEND WTF_SOURCES
55 ThreadingPthreads.cpp
66 blackberry/MainThreadBlackBerry.cpp
77 unicode/icu/CollatorICU.cpp
 8 unicode/icu/UnicodeIcu.cpp
89)
910
1011LIST(INSERT WTF_INCLUDE_DIRECTORIES 0

Source/JavaScriptCore/wtf/PlatformEfl.cmake

@@LIST(APPEND WTF_SOURCES
77 ThreadingPthreads.cpp
88
99 unicode/icu/CollatorICU.cpp
 10 unicode/icu/UnicodeIcu.cpp
1011)
1112
1213IF (ENABLE_GLIB_SUPPORT)

Source/JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h

9898 } \
9999}
100100#endif
 101
 102#define ICU_VERSION (U_ICU_VERSION_MAJOR_NUM * 10000 + U_ICU_VERSION_MINOR_NUM * 100 + U_ICU_VERSION_PATCHLEVEL_NUM)
 103#define ICU_VERSION_AT_LEAST(major, minor, patch) (ICU_VERSION >= (major * 10000 + minor * 100 + patch))
 104

Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.cpp

 1/*
 2 * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
 3 *
 4 * This library is free software; you can redistribute it and/or
 5 * modify it under the terms of the GNU Lesser General Public
 6 * License as published by the Free Software Foundation; either
 7 * version 2 of the License, or (at your option) any later version.
 8 *
 9 * This library is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 12 * Lesser General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU Lesser General Public
 15 * License along with this library; if not, write to the Free Software
 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 17 */
 18
 19#include "config.h"
 20#include "UnicodeIcu.h"
 21
 22#if USE(ICU_UNICODE)
 23
 24#include <unicode/uloc.h>
 25
 26namespace WTF {
 27namespace Unicode {
 28
 29const char* currentNumericLocaleID()
 30{
 31#if OS(DARWIN) && USE(CF)
 32 // Mac OS X doesn't set UNIX locale to match user-selected one, so ICU default doesn't work.
 33 RetainPtr<CFLocaleRef> currentLocale(AdoptCF, CFLocaleCopyCurrent());
 34 CFStringRef localeID = CFLocaleGetIdentifier(currentLocale.get());
 35
 36 return CFStringGetCStringPtr(localeID, CFStringGetSystemEncoding());
 37#else
 38 return uloc_getDefault();
 39#endif
 40}
 41
 42} }
 43
 44#endif

Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h

2929#include <unicode/ustring.h>
3030#include <unicode/utf16.h>
3131
 32#define ICU_VERSION (U_ICU_VERSION_MAJOR_NUM * 10000 + U_ICU_VERSION_MINOR_NUM * 100 + U_ICU_VERSION_PATCHLEVEL_NUM)
 33#define ICU_VERSION_AT_LEAST(major, minor, patch) (ICU_VERSION >= (major * 10000 + minor * 100 + patch))
 34
3235namespace WTF {
3336namespace Unicode {
3437

@@inline int umemcasecmp(const UChar* a, const UChar* b, int len)
231234 return u_memcasecmp(a, b, len, U_FOLD_CASE_DEFAULT);
232235}
233236
 237const char* currentNumericLocaleID();
 238
234239} }
235240
 241using WTF::Unicode::currentNumericLocaleID;
 242
236243#endif // WTF_UNICODE_ICU_H

LayoutTests/ChangeLog

 12012-01-28 Eli Fidler <efidler@rim.com>
 2
 3 Implement Number.toLocaleString() using ICU
 4 https://bugs.webkit.org/show_bug.cgi?id=77018
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 These tests are quite minimal, since we don't have a way to set the
 9 numeric locale in DRT.
 10
 11 * fast/js/number-toLocaleString-expected.txt: Added.
 12 * fast/js/number-toLocaleString.html: Added.
 13 * fast/js/script-tests/number-toLocaleString.js: Added.
 14 (isNonEmptyString):
 15
1162012-01-31 Yuzo Fujishima <yuzo@google.com>
217
318 [Chromium] Unreviewed test expectation change.

LayoutTests/fast/js/number-toLocaleString-expected.txt

 1PASS isNonEmptyString((0.0).toLocaleString()) is true
 2PASS isNonEmptyString((-0.0).toLocaleString()) is true
 3PASS isNonEmptyString((1234.567).toLocaleString()) is true
 4PASS successfullyParsed is true
 5
 6TEST COMPLETE
 7

LayoutTests/fast/js/number-toLocaleString.html

 1<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
 2<html>
 3<head>
 4<script src="resources/js-test-pre.js"></script>
 5</head>
 6<body>
 7<script src="script-tests/number-toLocaleString.js"></script>
 8<script src="resources/js-test-post.js"></script>
 9</body>
 10</html>

LayoutTests/fast/js/script-tests/number-toLocaleString.js

 1function isNonEmptyString(s)
 2{
 3 return typeof s == "string" && /[^\s]+/.test(s);
 4}
 5
 6shouldBeTrue("isNonEmptyString((0.0).toLocaleString())");
 7shouldBeTrue("isNonEmptyString((-0.0).toLocaleString())");
 8shouldBeTrue("isNonEmptyString((1234.567).toLocaleString())");