Bug 837957 - Implement ICU dependent functions of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat (part 4). r=jwalden
authorNorbert Lindenberg <mozilladev@lindenbergsoftware.com>
Sat, 16 Mar 2013 16:39:58 -0700
changeset 131502 605348ff1ee6a4742d480dda503410aa99deb0bc
parent 131501 124883708b7c0717fdef102d6e3975b3b0168b28
child 131503 44b0df91e49d7a9944725d3c1151b63dc2226bc1
push id3582
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 20:50:56 +0000
treeherdermozilla-aurora@400370bbc9fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs837957
milestone22.0a1
Bug 837957 - Implement ICU dependent functions of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat (part 4). r=jwalden
js/src/builtin/Intl.cpp
js/src/builtin/Intl.h
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -1029,26 +1029,32 @@ js::intl_CompareStrings(JSContext *cx, u
         return false;
     args.rval().set(result);
     return true;
 }
 
 
 /******************** NumberFormat ********************/
 
+static void numberFormat_finalize(FreeOp *fop, JSObject *obj);
+
+static const uint32_t UNUMBER_FORMAT_SLOT = 0;
+static const uint32_t NUMBER_FORMAT_SLOTS_COUNT = 1;
+
 static Class NumberFormatClass = {
     js_Object_str,
-    0,
+    JSCLASS_HAS_RESERVED_SLOTS(NUMBER_FORMAT_SLOTS_COUNT),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
-    JS_ConvertStub
+    JS_ConvertStub,
+    numberFormat_finalize
 };
 
 #if JS_HAS_TOSOURCE
 static JSBool
 numberFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     vp->setString(cx->names().NumberFormat);
     return true;
@@ -1086,46 +1092,58 @@ NumberFormat(JSContext *cx, unsigned arg
         if (!intl)
             return false;
         RootedValue self(cx, args.thisv());
         if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
             // 11.1.2.1 step 4
             obj = ToObject(cx, self);
             if (!obj)
                 return false;
+
             // 11.1.2.1 step 5
             if (!obj->isExtensible())
                 return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
         } else {
             // 11.1.2.1 step 3.a
             construct = true;
         }
     }
     if (construct) {
         // 11.1.3.1 paragraph 2
         RootedObject proto(cx, cx->global()->getOrCreateNumberFormatPrototype(cx));
         if (!proto)
             return false;
         obj = NewObjectWithGivenProto(cx, &NumberFormatClass, proto, cx->global());
         if (!obj)
             return false;
+
+        obj->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(NULL));
     }
 
     // 11.1.2.1 steps 1 and 2; 11.1.3.1 steps 1 and 2
     RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
     RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
+
     // 11.1.2.1 step 6; 11.1.3.1 step 3
     if (!IntlInitialize(cx, obj, cx->names().InitializeNumberFormat, locales, options))
         return false;
 
     // 11.1.2.1 steps 3.a and 7
     args.rval().setObject(*obj);
     return true;
 }
 
+static void
+numberFormat_finalize(FreeOp *fop, JSObject *obj)
+{
+    UNumberFormat *nf = static_cast<UNumberFormat *>(obj->getReservedSlot(UNUMBER_FORMAT_SLOT).toPrivate());
+    if (nf)
+        unum_close(nf);
+}
+
 static JSObject *
 InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
 {
     RootedFunction ctor(cx, global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0));
     if (!ctor)
         return NULL;
 
     RootedObject proto(cx, global->asGlobal().getOrCreateNumberFormatPrototype(cx));
@@ -1148,46 +1166,90 @@ InitNumberFormatClass(JSContext *cx, Han
      * for passing to methods like Array.prototype.map).
      */
     RootedValue getter(cx);
     if (!cx->global()->getIntrinsicValue(cx, cx->names().NumberFormatFormatGet, &getter))
         return NULL;
     RootedValue undefinedValue(cx, UndefinedValue());
     if (!JSObject::defineProperty(cx, proto, cx->names().format, undefinedValue,
                                   JS_DATA_TO_FUNC_PTR(JSPropertyOp, &getter.toObject()),
-                                  NULL, JSPROP_GETTER)) {
+                                  NULL, JSPROP_GETTER))
+    {
         return NULL;
     }
 
     // 11.2.1 and 11.3
     RootedValue locales(cx, UndefinedValue());
     RootedValue options(cx, UndefinedValue());
     if (!IntlInitialize(cx, proto, cx->names().InitializeNumberFormat, locales, options))
         return NULL;
 
     // 8.1
     RootedValue ctorValue(cx, ObjectValue(*ctor));
     if (!JSObject::defineProperty(cx, Intl, cx->names().NumberFormat, ctorValue,
-                                  JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+                                  JS_PropertyStub, JS_StrictPropertyStub, 0))
+    {
         return NULL;
     }
 
     return ctor;
 }
 
 bool
 GlobalObject::initNumberFormatProto(JSContext *cx, Handle<GlobalObject*> global)
 {
     RootedObject proto(cx, global->createBlankPrototype(cx, &NumberFormatClass));
     if (!proto)
         return false;
+    proto->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(NULL));
     global->setReservedSlot(NUMBER_FORMAT_PROTO, ObjectValue(*proto));
     return true;
 }
 
+JSBool
+js::intl_NumberFormat_availableLocales(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JS_ASSERT(args.length() == 0);
+
+    RootedValue result(cx);
+    if (!intl_availableLocales(cx, unum_countAvailable, unum_getAvailable, &result))
+        return false;
+    args.rval().set(result);
+    return true;
+}
+
+JSBool
+js::intl_numberingSystem(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JS_ASSERT(args.length() == 1);
+    JS_ASSERT(args[0].isString());
+
+    JSAutoByteString locale(cx, args[0].toString());
+    if (!locale)
+        return false;
+
+    // There's no C API for numbering system, so use the C++ API and hope it
+    // won't break. http://bugs.icu-project.org/trac/ticket/10039
+    Locale ulocale(locale.ptr());
+    UErrorCode status = U_ZERO_ERROR;
+    NumberingSystem *numbers = NumberingSystem::createInstance(ulocale, status);
+    if (U_FAILURE(status)) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INTERNAL_INTL_ERROR);
+        return false;
+    }
+    const char *name = numbers->getName();
+    JSString *jsname = JS_NewStringCopyZ(cx, name);
+    delete numbers;
+    if (!jsname)
+        return false;
+    args.rval().setString(jsname);
+    return true;
+}
 
 /******************** DateTimeFormat ********************/
 
 static Class DateTimeFormatClass = {
     js_Object_str,
     0,
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -64,11 +64,35 @@ intl_availableCollations(JSContext *cx, 
  *
  * Spec: ECMAScript Internationalization API Specification, 10.3.2.
  *
  * Usage: result = intl_CompareStrings(collator, x, y)
  */
 extern JSBool
 intl_CompareStrings(JSContext *cx, unsigned argc, Value *vp);
 
+
+/******************** NumberFormat ********************/
+
+/**
+ * Returns an object indicating the supported locales for number formatting
+ * by having a true-valued property for each such locale with the
+ * canonicalized language tag as the property name. The object has no
+ * prototype.
+ *
+ * Usage: availableLocales = intl_NumberFormat_availableLocales()
+ */
+extern JSBool
+intl_NumberFormat_availableLocales(JSContext *cx, unsigned argc, Value *vp);
+
+/**
+ * Returns the numbering system type identifier per Unicode
+ * Technical Standard 35, Unicode Locale Data Markup Language, for the
+ * default numbering system for the given locale.
+ *
+ * Usage: defaultNumberingSystem = intl_numberingSystem(locale)
+ */
+extern JSBool
+intl_numberingSystem(JSContext *cx, unsigned argc, Value *vp);
+
 } // namespace js
 
 #endif /* Intl_h___ */