Bug 1336281 - Expose mozILocaleService. r=jfkthame
authorZibi Braniecki <gandalf@mozilla.com>
Sun, 05 Feb 2017 12:29:39 -0800
changeset 389989 9a949ee9c2cdbca560a511eddccd5b96490cf4b4
parent 389988 b02d4bac89282c0b0913470fa3ef40021fad75f2
child 389990 02e1f85fa542de5b676770da58e3c98996a234f2
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1336281
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1336281 - Expose mozILocaleService. r=jfkthame MozReview-Commit-ID: 3fTtad7tAg6
intl/build/nsI18nModule.cpp
intl/locale/LocaleService.cpp
intl/locale/LocaleService.h
intl/locale/moz.build
intl/locale/mozILocaleService.idl
intl/locale/nsLocaleConstructors.h
intl/locale/tests/unit/test_localeService.js
intl/locale/tests/unit/xpcshell.ini
--- a/intl/build/nsI18nModule.cpp
+++ b/intl/build/nsI18nModule.cpp
@@ -39,16 +39,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSt
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCaseConversionImp2)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsCategoryImp,
                                          nsCategoryImp::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsEntityConverter)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSaveAsCharset)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeNormalizer)
 
+NS_DEFINE_NAMED_CID(MOZ_LOCALESERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_LBRK_CID);
 NS_DEFINE_NAMED_CID(NS_WBRK_CID);
 NS_DEFINE_NAMED_CID(NS_SEMANTICUNITSCANNER_CID);
 NS_DEFINE_NAMED_CID(NS_UNICHARUTIL_CID);
 NS_DEFINE_NAMED_CID(NS_UNICHARCATEGORY_CID);
 NS_DEFINE_NAMED_CID(NS_ENTITYCONVERTER_CID);
 NS_DEFINE_NAMED_CID(NS_SAVEASCHARSET_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODE_NORMALIZER_CID);
@@ -65,16 +66,17 @@ NS_DEFINE_NAMED_CID(NS_COLLATION_CID);
 #ifdef USE_UNIX_LOCALE
 NS_DEFINE_NAMED_CID(NS_COLLATION_CID);
 #endif
 #ifdef USE_MAC_LOCALE
 NS_DEFINE_NAMED_CID(NS_COLLATION_CID);
 #endif
 
 static const mozilla::Module::CIDEntry kIntlCIDs[] = {
+    { &kMOZ_LOCALESERVICE_CID, false, nullptr, mozilla::intl::LocaleServiceConstructor },
     { &kNS_LBRK_CID, false, nullptr, nsJISx4051LineBreakerConstructor },
     { &kNS_WBRK_CID, false, nullptr, nsSampleWordBreakerConstructor },
     { &kNS_SEMANTICUNITSCANNER_CID, false, nullptr, nsSemanticUnitScannerConstructor },
     { &kNS_UNICHARUTIL_CID, false, nullptr, nsCaseConversionImp2Constructor },
     { &kNS_UNICHARCATEGORY_CID, false, nullptr, nsCategoryImpConstructor },
     { &kNS_ENTITYCONVERTER_CID, false, nullptr, nsEntityConverterConstructor },
     { &kNS_SAVEASCHARSET_CID, false, nullptr, nsSaveAsCharsetConstructor },
     { &kNS_UNICODE_NORMALIZER_CID, false, nullptr, nsUnicodeNormalizerConstructor },
@@ -93,16 +95,17 @@ static const mozilla::Module::CIDEntry k
 #endif
 #ifdef USE_MAC_LOCALE
     { &kNS_COLLATION_CID, false, nullptr, nsCollationMacUCConstructor },
 #endif
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kIntlContracts[] = {
+    { MOZ_LOCALESERVICE_CONTRACTID, &kMOZ_LOCALESERVICE_CID },
     { NS_LBRK_CONTRACTID, &kNS_LBRK_CID },
     { NS_WBRK_CONTRACTID, &kNS_WBRK_CID },
     { NS_SEMANTICUNITSCANNER_CONTRACTID, &kNS_SEMANTICUNITSCANNER_CID },
     { NS_UNICHARUTIL_CONTRACTID, &kNS_UNICHARUTIL_CID },
     { NS_UNICHARCATEGORY_CONTRACTID, &kNS_UNICHARCATEGORY_CID },
     { NS_ENTITYCONVERTER_CONTRACTID, &kNS_ENTITYCONVERTER_CID },
     { NS_SAVEASCHARSET_CONTRACTID, &kNS_SAVEASCHARSET_CID },
     { NS_UNICODE_NORMALIZER_CONTRACTID, &kNS_UNICODE_NORMALIZER_CID },
--- a/intl/locale/LocaleService.cpp
+++ b/intl/locale/LocaleService.cpp
@@ -1,21 +1,27 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LocaleService.h"
+
+#include "jsapi.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "nsIToolkitChromeRegistry.h"
 
 using namespace mozilla::intl;
 
+NS_IMPL_ISUPPORTS(LocaleService, mozILocaleService)
+
+mozilla::StaticRefPtr<LocaleService> LocaleService::sInstance;
+
 /**
  * This function performs the actual language negotiation for the API.
  *
  * Currently it collects the locale ID used by nsChromeRegistry and
  * adds hardcoded "en-US" locale as a fallback.
  */
 static void
 ReadAppLocales(nsTArray<nsCString>& aRetVal)
@@ -30,19 +36,18 @@ ReadAppLocales(nsTArray<nsCString>& aRet
     aRetVal.AppendElement(uaLangTag);
   }
 
   if (!uaLangTag.EqualsLiteral("en-US")) {
     aRetVal.AppendElement(NS_LITERAL_CSTRING("en-US"));
   }
 }
 
-mozilla::StaticAutoPtr<LocaleService> LocaleService::sInstance;
-
-LocaleService* LocaleService::GetInstance()
+LocaleService*
+LocaleService::GetInstance()
 {
   if (!sInstance) {
     sInstance = new LocaleService();
     ClearOnShutdown(&sInstance);
   }
   return sInstance;
 }
 
@@ -73,8 +78,41 @@ LocaleService::Refresh()
   if (mAppLocales != newLocales) {
     mAppLocales = Move(newLocales);
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->NotifyObservers(nullptr, "intl:app-locales-changed", nullptr);
     }
   }
 }
+
+/**
+ * mozILocaleService methods
+ */
+NS_IMETHODIMP
+LocaleService::GetAppLocales(JSContext* aCtx, JS::MutableHandleValue aRetVal)
+{
+  if (mAppLocales.IsEmpty()) {
+    ReadAppLocales(mAppLocales);
+  }
+
+  uint32_t appLocalesNum = mAppLocales.Length();
+
+  JS::RootedObject locales(aCtx, JS_NewArrayObject(aCtx, appLocalesNum));
+  JS::Rooted<JS::Value> value(aCtx);
+
+  for (size_t i = 0; i < appLocalesNum; i++) {
+    const nsCString& loc = mAppLocales[i];
+    JSString* str = JS_NewStringCopyN(aCtx, loc.get(), loc.Length());
+    value.setString(str);
+    JS_DefineElement(aCtx, locales, i, value, JSPROP_ENUMERATE);
+  }
+
+  aRetVal.setObject(*locales);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LocaleService::GetAppLocale(JSContext* aCtx, nsACString& aRetVal)
+{
+  GetAppLocale(aRetVal);
+  return NS_OK;
+}
--- a/intl/locale/LocaleService.h
+++ b/intl/locale/LocaleService.h
@@ -5,33 +5,53 @@
 
 #ifndef mozilla_intl_LocaleService_h__
 #define mozilla_intl_LocaleService_h__
 
 #include "mozilla/StaticPtr.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
+#include "mozILocaleService.h"
+
 namespace mozilla {
 namespace intl {
 
-
 /**
  * LocaleService is a manager of language negotiation in Gecko.
  *
  * It's intended to be the core place for collecting available and
  * requested languages and negotiating them to produce a fallback
  * chain of locales for the application.
  */
-class LocaleService
+class LocaleService : public mozILocaleService
 {
 public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_MOZILOCALESERVICE
+
+  /**
+   * Create (if necessary) and return a raw pointer to the singleton instance.
+   * Use this accessor in C++ code that just wants to call a method on the
+   * instance, but does not need to hold a reference, as in
+   *    nsAutoCString str;
+   *    LocaleService::GetInstance()->GetAppLocale(str);
+   */
   static LocaleService* GetInstance();
 
   /**
+   * Return an addRef'd pointer to the singleton instance. This is used by the
+   * XPCOM constructor that exists to support usage from JS.
+   */
+  static already_AddRefed<LocaleService> GetInstanceAddRefed()
+  {
+    return RefPtr<LocaleService>(GetInstance()).forget();
+  }
+
+  /**
    * Returns a list of locales that the application should be localized to.
    *
    * The result is a sorted list of valid locale IDs and it should be
    * used for all APIs that accept list of locales, like ECMA402 and L10n APIs.
    *
    * This API always returns at least one locale.
    *
    * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"]
@@ -68,15 +88,17 @@ public:
    * trigger a global event "intl:app-locales-changed".
    */
   void Refresh();
 
 protected:
   nsTArray<nsCString> mAppLocales;
 
 private:
-  static StaticAutoPtr<LocaleService> sInstance;
+  virtual ~LocaleService() {};
+
+  static StaticRefPtr<LocaleService> sInstance;
 };
 
 } // intl
 } // namespace mozilla
 
 #endif /* mozilla_intl_LocaleService_h__ */
--- a/intl/locale/moz.build
+++ b/intl/locale/moz.build
@@ -14,16 +14,17 @@ toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 if toolkit == 'windows':
     DIRS += ['windows']
 elif toolkit == 'cocoa':
     DIRS += ['mac']
 else:
     DIRS += ['unix']
 
 XPIDL_SOURCES += [
+    'mozILocaleService.idl',
     'nsICollation.idl',
     'nsILocale.idl',
     'nsILocaleService.idl',
     'nsIScriptableDateFormat.idl',
 ]
 
 XPIDL_MODULE = 'locale'
 
new file mode 100644
--- /dev/null
+++ b/intl/locale/mozILocaleService.idl
@@ -0,0 +1,21 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+%{C++
+// Define Contractid and CID
+#define MOZ_LOCALESERVICE_CID \
+  { 0x92735ff4, 0x6384, 0x4ad6, { 0x85, 0x08, 0x75, 0x70, 0x10, 0xe1, 0x49, 0xee } }
+
+#define MOZ_LOCALESERVICE_CONTRACTID "@mozilla.org/intl/localeservice;1"
+%}
+
+[scriptable, uuid(C27F8983-B48B-4D1A-92D7-FEB8106F212D)]
+interface mozILocaleService : nsISupports
+{
+  [implicit_jscontext] jsval getAppLocales();
+  [implicit_jscontext] ACString getAppLocale();
+};
--- a/intl/locale/nsLocaleConstructors.h
+++ b/intl/locale/nsLocaleConstructors.h
@@ -8,16 +8,17 @@
 
 #include "nsCollationCID.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsILocaleService.h"
 #include "nsIScriptableDateFormat.h"
 #include "nsIServiceManager.h"
 #include "nsLanguageAtomService.h"
 #include "nsPlatformCharset.h"
+#include "LocaleService.h"
 
 #if defined(XP_MACOSX)
 #define USE_MAC_LOCALE
 #endif
 
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
 #define USE_UNIX_LOCALE
 #endif
@@ -52,16 +53,23 @@ ctor_(nsISupports* aOuter, REFNSIID aIID
 
 
 NSLOCALE_MAKE_CTOR(CreateLocaleService, nsILocaleService, NS_NewLocaleService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationFactory)
 //NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptableDateTimeFormat)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsLanguageAtomService)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPlatformCharset, Init)
 
+namespace mozilla {
+namespace intl {
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(LocaleService,
+                                         LocaleService::GetInstanceAddRefed)
+}
+}
+
 #ifdef XP_WIN
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationWin)
 #endif
 
 #ifdef USE_UNIX_LOCALE
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationUnix)
 #endif  
 
new file mode 100644
--- /dev/null
+++ b/intl/locale/tests/unit/test_localeService.js
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Make sure the locale service can be instantiated,
+ * and returns something plausible for getAppLocale and getAppLocales.
+ */
+
+function run_test()
+{
+  var localeService =
+    Components.classes["@mozilla.org/intl/localeservice;1"]
+    .getService(Components.interfaces.mozILocaleService);
+
+  var appLocale = localeService.getAppLocale();
+  do_check_true(appLocale != "", "appLocale is non-empty");
+
+  var appLocales = localeService.getAppLocales();
+  do_check_true(Array.isArray(appLocales), "appLocales returns an array");
+
+  do_check_true(appLocale == appLocales[0], "appLocale matches first entry in appLocales");
+
+  var enUScount = 0;
+  appLocales.forEach(function(loc) { if (loc == "en-US") { enUScount++; } });
+  do_check_true(enUScount == 1, "en-US is present exactly one time");
+}
--- a/intl/locale/tests/unit/xpcshell.ini
+++ b/intl/locale/tests/unit/xpcshell.ini
@@ -16,8 +16,10 @@ skip-if = toolkit != "cocoa"
 
 [test_bug1086527.js]
 [test_intl_on_workers.js]
 skip-if = toolkit == "android" # bug 1309447
 
 [test_pluralForm.js]
 [test_pluralForm_english.js]
 [test_pluralForm_makeGetter.js]
+
+[test_localeService.js]