Bug 1301655 - pt 0 - Add an optional parameter to nsIChromeRegistry.getSelectedLocale to allow callers to request the locale be returned as a valid BCP47 lang tag. r=gandalf
authorJonathan Kew <jkew@mozilla.com>
Fri, 28 Oct 2016 12:04:06 +0100
changeset 319988 b6ab66ffae99eed12351041efd822efc6ae18858
parent 319987 d523f32cf87f2122fbbca86e0e3d2d0a26942ab6
child 319989 cd3bd7aa413d765587d94db7a6fc8b10c4008af6
push id20749
push userryanvm@gmail.com
push dateSat, 29 Oct 2016 13:21:21 +0000
treeherderfx-team@1b170b39ed6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgandalf
bugs1301655
milestone52.0a1
Bug 1301655 - pt 0 - Add an optional parameter to nsIChromeRegistry.getSelectedLocale to allow callers to request the locale be returned as a valid BCP47 lang tag. r=gandalf
chrome/nsChromeRegistry.cpp
chrome/nsChromeRegistry.h
chrome/nsChromeRegistryChrome.cpp
chrome/nsChromeRegistryChrome.h
chrome/nsChromeRegistryContent.cpp
chrome/nsChromeRegistryContent.h
chrome/nsIChromeRegistry.idl
dom/encoding/FallbackEncoding.cpp
dom/xul/nsXULPrototypeCache.cpp
editor/composer/nsEditorSpellCheck.cpp
intl/unicharutil/util/ICUUtils.cpp
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -27,16 +27,20 @@
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIScriptError.h"
 #include "nsIWindowMediator.h"
 #include "nsIPrefService.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 
+#ifdef ENABLE_INTL_API
+#include "unicode/uloc.h"
+#endif
+
 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
 
 // DO NOT use namespace mozilla; it'll break due to a naming conflict between
 // mozilla::TextRange and a TextRange in OSX headers.
 using mozilla::StyleSheet;
 using mozilla::dom::IsChromeURI;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -704,8 +708,37 @@ nsChromeRegistry::GetSingleton()
   else
     cr = new nsChromeRegistryChrome();
 
   if (NS_FAILED(cr->Init()))
     return nullptr;
 
   return cr.forget();
 }
+
+void
+nsChromeRegistry::SanitizeForBCP47(nsACString& aLocale)
+{
+#ifdef ENABLE_INTL_API
+  // Currently, the only locale code we use that's not BCP47-conformant is
+  // "ja-JP-mac" on OS X, but let's try to be more general than just
+  // hard-coding that here.
+  const int32_t LANG_TAG_CAPACITY = 128;
+  char langTag[LANG_TAG_CAPACITY];
+  nsAutoCString locale(aLocale);
+  UErrorCode err = U_ZERO_ERROR;
+  // This is a fail-safe method that will set langTag to "und" if it cannot
+  // match any part of the input locale code.
+  int32_t len = uloc_toLanguageTag(locale.get(), langTag, LANG_TAG_CAPACITY,
+                                   false, &err);
+  if (U_SUCCESS(err) && len > 0) {
+    aLocale.Assign(langTag, len);
+  }
+#else
+  // This is only really needed for Intl API purposes, AFAIK,
+  // so probably won't be used in a non-ENABLE_INTL_API build.
+  // But let's fix up the single anomalous code we actually ship,
+  // just in case:
+  if (aLocale.EqualsLiteral("ja-JP-mac")) {
+    aLocale.AssignLiteral("ja-JP");
+  }
+#endif
+}
--- a/chrome/nsChromeRegistry.h
+++ b/chrome/nsChromeRegistry.h
@@ -96,16 +96,18 @@ protected:
   nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
 
   static nsresult RefreshWindow(nsPIDOMWindowOuter* aWindow);
   static nsresult GetProviderAndPath(nsIURL* aChromeURL,
                                      nsACString& aProvider, nsACString& aPath);
 
   bool GetDirectionForLocale(const nsACString& aLocale);
 
+  void SanitizeForBCP47(nsACString& aLocale);
+
 public:
   static already_AddRefed<nsChromeRegistry> GetSingleton();
 
   struct ManifestProcessingContext
   {
     ManifestProcessingContext(NSLocationType aType, mozilla::FileLocation &aFile)
       : mType(aType)
       , mFile(aFile)
--- a/chrome/nsChromeRegistryChrome.cpp
+++ b/chrome/nsChromeRegistryChrome.cpp
@@ -219,40 +219,45 @@ getUILangCountry(nsACString& aUILang)
 }
 
 NS_IMETHODIMP
 nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
 {
   *aResult = false;
 
   nsAutoCString locale;
-  GetSelectedLocale(package, locale);
+  GetSelectedLocale(package, false, locale);
   if (locale.Length() < 2)
     return NS_OK;
 
   *aResult = GetDirectionForLocale(locale);
   return NS_OK;
 }
 
 nsresult
 nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
+                                          bool aAsBCP47,
                                           nsACString& aLocale)
 {
   nsCString realpackage;
   nsresult rv = OverrideLocalePackage(aPackage, realpackage);
   if (NS_FAILED(rv))
     return rv;
   PackageEntry* entry;
   if (!mPackagesHash.Get(realpackage, &entry))
     return NS_ERROR_FILE_NOT_FOUND;
 
   aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
   if (aLocale.IsEmpty())
     return NS_ERROR_FAILURE;
 
+  if (aAsBCP47) {
+    SanitizeForBCP47(aLocale);
+  }
+
   return NS_OK;
 }
 
 nsresult
 nsChromeRegistryChrome::OverrideLocalePackage(const nsACString& aPackage,
                                               nsACString& aOverride)
 {
   const nsACString& pref = NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage;
--- a/chrome/nsChromeRegistryChrome.h
+++ b/chrome/nsChromeRegistryChrome.h
@@ -31,16 +31,17 @@ class nsChromeRegistryChrome : public ns
 
   NS_IMETHOD CheckForNewChrome() override;
   NS_IMETHOD CheckForOSAccessibility() override;
   NS_IMETHOD GetLocalesForPackage(const nsACString& aPackage,
                                   nsIUTF8StringEnumerator* *aResult) override;
   NS_IMETHOD IsLocaleRTL(const nsACString& package,
                          bool *aResult) override;
   NS_IMETHOD GetSelectedLocale(const nsACString& aPackage,
+                               bool aAsBCP47,
                                nsACString& aLocale) override;
   NS_IMETHOD Observe(nsISupports *aSubject, const char *aTopic,
                      const char16_t *someData) override;
 
 #ifdef MOZ_XUL
   NS_IMETHOD GetXULOverlays(nsIURI *aURI,
                             nsISimpleEnumerator **_retval) override;
   NS_IMETHOD GetStyleOverlays(nsIURI *aURI,
--- a/chrome/nsChromeRegistryContent.cpp
+++ b/chrome/nsChromeRegistryContent.cpp
@@ -217,23 +217,27 @@ nsChromeRegistryContent::IsLocaleRTL(con
     return NS_ERROR_NOT_AVAILABLE;
   }
   *aResult = GetDirectionForLocale(mLocale);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsChromeRegistryContent::GetSelectedLocale(const nsACString& aPackage,
+                                           bool aAsBCP47,
                                            nsACString& aLocale)
 {
   if (aPackage != nsDependentCString("global")) {
     NS_ERROR("Uh-oh, caller wanted something other than 'some local'");
     return NS_ERROR_NOT_AVAILABLE;
   }
   aLocale = mLocale;
+  if (aAsBCP47) {
+    SanitizeForBCP47(aLocale);
+  }
   return NS_OK;
 }
   
 NS_IMETHODIMP
 nsChromeRegistryContent::Observe(nsISupports* aSubject, const char* aTopic,
                                  const char16_t* aData)
 {
   CONTENT_NOT_IMPLEMENTED();
--- a/chrome/nsChromeRegistryContent.h
+++ b/chrome/nsChromeRegistryContent.h
@@ -28,16 +28,17 @@ class nsChromeRegistryContent : public n
                                   nsIUTF8StringEnumerator* *aResult) override;
   NS_IMETHOD CheckForNewChrome() override;
   NS_IMETHOD CheckForOSAccessibility() override;
   NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
                      const char16_t* aData) override;
   NS_IMETHOD IsLocaleRTL(const nsACString& package,
                          bool *aResult) override;
   NS_IMETHOD GetSelectedLocale(const nsACString& aPackage,
+                               bool aAsBCP47,
                                nsACString& aLocale) override;
   NS_IMETHOD GetStyleOverlays(nsIURI *aChromeURL,
                               nsISimpleEnumerator **aResult) override;
   NS_IMETHOD GetXULOverlays(nsIURI *aChromeURL,
                             nsISimpleEnumerator **aResult) override;
 
   void RegisterPackage(const ChromePackage& aPackage);
   void RegisterOverride(const OverrideMapping& aOverride);
--- a/chrome/nsIChromeRegistry.idl
+++ b/chrome/nsIChromeRegistry.idl
@@ -45,18 +45,23 @@ interface nsIChromeRegistry : nsISupport
   [notxpcom] boolean wrappersEnabled(in nsIURI aURI);
 };
 
 [scriptable, uuid(93251ddf-5e85-4172-ac2a-31780562974f)]
 interface nsIXULChromeRegistry : nsIChromeRegistry
 {
   /* Should be called when locales change to reload all chrome (including XUL). */
   void reloadChrome();
-  
-  ACString getSelectedLocale(in ACString packageName);
+
+  // If the optional asBCP47 parameter is true, the locale code will be
+  // converted to a BCP47 language tag; in particular, this means that
+  // "ja-JP-mac" will be returned as "ja-JP-x-lvariant-mac", which can be
+  // passed to ECMA402 Intl API methods without throwing a RangeError.
+  ACString getSelectedLocale(in ACString packageName,
+                             [optional] in boolean asBCP47);
   
   // Get the direction of the locale via the intl.uidirection.<locale> pref
   boolean isLocaleRTL(in ACString package);
 
   /* Should be called when skins change. Reloads only stylesheets. */
   void refreshSkins();
 
   /**
--- a/dom/encoding/FallbackEncoding.cpp
+++ b/dom/encoding/FallbackEncoding.cpp
@@ -64,17 +64,17 @@ FallbackEncoding::Get(nsACString& aFallb
     aFallback = mFallback;
     return;
   }
 
   nsAutoCString locale;
   nsCOMPtr<nsIXULChromeRegistry> registry =
     mozilla::services::GetXULChromeRegistryService();
   if (registry) {
-    registry->GetSelectedLocale(NS_LITERAL_CSTRING("global"), locale);
+    registry->GetSelectedLocale(NS_LITERAL_CSTRING("global"), false, locale);
   }
 
   // Let's lower case the string just in case unofficial language packs
   // don't stick to conventions.
   ToLowerCase(locale); // ASCII lowercasing with CString input!
 
   // Special case Traditional Chinese before throwing away stuff after the
   // language itself. Today we only ship zh-TW, but be defensive about
--- a/dom/xul/nsXULPrototypeCache.cpp
+++ b/dom/xul/nsXULPrototypeCache.cpp
@@ -482,17 +482,17 @@ nsXULPrototypeCache::BeginCaching(nsIURI
     // all subsequent packages of cached chrome URIs....
     nsAutoCString package;
     rv = aURI->GetHost(package);
     if (NS_FAILED(rv))
         return rv;
     nsCOMPtr<nsIXULChromeRegistry> chromeReg
         = do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv);
     nsAutoCString locale;
-    rv = chromeReg->GetSelectedLocale(package, locale);
+    rv = chromeReg->GetSelectedLocale(package, false, locale);
     if (NS_FAILED(rv))
         return rv;
 
     nsAutoCString fileChromePath, fileLocale;
 
     UniquePtr<char[]> buf;
     uint32_t len, amtRead;
     nsCOMPtr<nsIObjectInputStream> objectInput;
--- a/editor/composer/nsEditorSpellCheck.cpp
+++ b/editor/composer/nsEditorSpellCheck.cpp
@@ -917,17 +917,17 @@ nsEditorSpellCheck::DictionaryFetched(Di
   // As next fallback, try the current locale.
   if (NS_FAILED(rv)) {
     nsCOMPtr<nsIXULChromeRegistry> packageRegistry =
       mozilla::services::GetXULChromeRegistryService();
 
     if (packageRegistry) {
       nsAutoCString utf8DictName;
       rv2 = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global"),
-                                               utf8DictName);
+                                               false, utf8DictName);
       dictName.Assign(EmptyString());
       AppendUTF8toUTF16(utf8DictName, dictName);
 #ifdef DEBUG_DICT
       printf("***** Trying locale |%s|\n",
              NS_ConvertUTF16toUTF8(dictName).get());
 #endif
       rv = TryDictionary (dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE);
     }
--- a/intl/unicharutil/util/ICUUtils.cpp
+++ b/intl/unicharutil/util/ICUUtils.cpp
@@ -70,17 +70,17 @@ ICUUtils::LanguageTagIterForContent::Get
 
   if (mCurrentFallbackIndex < 2) {
     mCurrentFallbackIndex = 2;
     // Else try the user-agent's locale:
     nsCOMPtr<nsIToolkitChromeRegistry> cr =
       mozilla::services::GetToolkitChromeRegistryService();
     nsAutoCString uaLangTag;
     if (cr) {
-      cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), uaLangTag);
+      cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), true, uaLangTag);
     }
     if (!uaLangTag.IsEmpty()) {
       aBCP47LangTag = uaLangTag;
       return;
     }
   }
 
   // TODO: Probably not worth it, but maybe have a fourth fallback to using