Bug 1347306 - Hand over language negotiation from ChromeRegistry to LocaleService. r=jfkthame
authorZibi Braniecki <gandalf@mozilla.com>
Tue, 14 Mar 2017 15:28:47 -0700
changeset 400517 850cf5d6d37dcdb71cc9c22344a6ca33db6a382e
parent 400516 860cafd805c80326e83af4b1aaa9a3c3681f9b4d
child 400518 c7174ac72d14b0dd8da71c4bf490fdfb05660c2b
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1347306
milestone55.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 1347306 - Hand over language negotiation from ChromeRegistry to LocaleService. r=jfkthame MozReview-Commit-ID: RIPZUHN4LW
chrome/nsChromeRegistry.cpp
chrome/nsChromeRegistry.h
chrome/nsChromeRegistryChrome.cpp
chrome/nsChromeRegistryChrome.h
chrome/nsChromeRegistryContent.cpp
chrome/nsChromeRegistryContent.h
chrome/test/unit/test_bug519468.js
chrome/test/unit/xpcshell.ini
intl/locale/LocaleService.cpp
intl/locale/LocaleService.h
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -482,17 +482,16 @@ nsChromeRegistry::FlushAllCaches()
   obsSvc->NotifyObservers((nsIChromeRegistry*) this,
                           NS_CHROME_FLUSH_TOPIC, nullptr);
 }  
 
 // xxxbsmedberg Move me to nsIWindowMediator
 NS_IMETHODIMP
 nsChromeRegistry::ReloadChrome()
 {
-  UpdateSelectedLocale();
   FlushAllCaches();
   // Do a reload of all top level windows.
   nsresult rv = NS_OK;
 
   // Get the window mediator
   nsCOMPtr<nsIWindowMediator> windowMediator
     (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
   if (windowMediator) {
--- a/chrome/nsChromeRegistry.h
+++ b/chrome/nsChromeRegistry.h
@@ -74,34 +74,28 @@ public:
   static nsresult Canonify(nsIURL* aChromeURL);
 
 protected:
   virtual ~nsChromeRegistry();
 
   void FlushSkinCaches();
   void FlushAllCaches();
 
-  // Update the selected locale used by the chrome registry, and fire a
-  // notification about this change
-  virtual nsresult UpdateSelectedLocale() = 0;
-
   static void LogMessage(const char* aMsg, ...)
     MOZ_FORMAT_PRINTF(1, 2);
   static void LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber, uint32_t flags,
                                     const char* aMsg, ...)
     MOZ_FORMAT_PRINTF(4, 5);
 
   virtual nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                                         const nsCString& aProvider,
                                         const nsCString& aPath) = 0;
   virtual nsresult GetFlagsFromPackage(const nsCString& aPackage,
                                        uint32_t* aFlags) = 0;
 
-  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);
 
--- a/chrome/nsChromeRegistryChrome.cpp
+++ b/chrome/nsChromeRegistryChrome.cpp
@@ -23,37 +23,32 @@
 #include "nsStringEnumerator.h"
 #include "nsTextFormatter.h"
 #include "nsXPCOMCIDInternal.h"
 
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Unused.h"
 #include "mozilla/intl/LocaleService.h"
 
-#include "nsICommandLine.h"
-#include "nsILocaleService.h"
 #include "nsIObserverService.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "mozilla/Preferences.h"
 #include "nsIResProtocolHandler.h"
 #include "nsIScriptError.h"
 #include "nsIXPConnect.h"
 #include "nsIXULRuntime.h"
 
-#define UILOCALE_CMD_LINE_ARG "UILocale"
-
-#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
-#define SELECTED_LOCALE_PREF "general.useragent.locale"
 #define SELECTED_SKIN_PREF   "general.skins.selectedSkin"
 #define PACKAGE_OVERRIDE_BRANCH "chrome.override_package."
 
 using namespace mozilla;
 using mozilla::dom::ContentParent;
 using mozilla::dom::PContentParent;
+using mozilla::intl::LocaleService;
 
 // We use a "best-fit" algorithm for matching locales and themes.
 // 1) the exact selected locale/theme
 // 2) (locales only) same language, different country
 //    e.g. en-GB is the selected locale, only en-US is available
 // 3) any available locale/theme
 
 /**
@@ -108,17 +103,16 @@ nsChromeRegistryChrome::~nsChromeRegistr
 
 nsresult
 nsChromeRegistryChrome::Init()
 {
   nsresult rv = nsChromeRegistry::Init();
   if (NS_FAILED(rv))
     return rv;
 
-  mSelectedLocale = NS_LITERAL_CSTRING("en-US");
   mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
 
   bool safeMode = false;
   nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
   if (xulrun)
     xulrun->GetInSafeMode(&safeMode);
 
   nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
@@ -135,27 +129,23 @@ nsChromeRegistryChrome::Init()
   if (!prefs) {
     NS_WARNING("Could not get pref service!");
   } else {
     nsXPIDLCString provider;
     rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
     if (NS_SUCCEEDED(rv))
       mSelectedSkin = provider;
 
-    SelectLocaleFromPref(prefs);
-
-    rv = prefs->AddObserver(MATCH_OS_LOCALE_PREF, this, true);
-    rv = prefs->AddObserver(SELECTED_LOCALE_PREF, this, true);
     rv = prefs->AddObserver(SELECTED_SKIN_PREF, this, true);
   }
 
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   if (obsService) {
-    obsService->AddObserver(this, "command-line-startup", true);
     obsService->AddObserver(this, "profile-initial-state", true);
+    obsService->AddObserver(this, "intl:app-locales-changed", true);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsChromeRegistryChrome::CheckForOSAccessibility()
 {
@@ -198,60 +188,60 @@ nsChromeRegistryChrome::GetLocalesForPac
 
   rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
   if (NS_FAILED(rv))
     delete a;
 
   return rv;
 }
 
-static nsresult
-getUILangCountry(nsACString& aUILang)
-{
-  nsresult rv;
-
-  nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoString uiLang;
-  rv = localeService->GetLocaleComponentForUserAgent(uiLang);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  CopyUTF16toUTF8(uiLang, aUILang);
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
 {
   *aResult = false;
 
   nsAutoCString locale;
   GetSelectedLocale(package, false, locale);
   if (locale.Length() < 2)
     return NS_OK;
 
   *aResult = GetDirectionForLocale(locale);
   return NS_OK;
 }
 
+/**
+ * This method negotiates only between the app locale and the available
+ * chrome packages.
+ *
+ * If you want to get the current application's UI locale, please use
+ * LocaleService::GetAppLocaleAsLangTag.
+ */
 nsresult
 nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
                                           bool aAsBCP47,
                                           nsACString& aLocale)
 {
+  nsAutoCString reqLocale;
+  if (aPackage.Equals("global")) {
+    LocaleService::GetInstance()->GetAppLocaleAsLangTag(reqLocale);
+  } else {
+    AutoTArray<nsCString, 10> requestedLocales;
+    LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
+    reqLocale.Assign(requestedLocales[0]);
+  }
+
   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);
+  aLocale = entry->locales.GetSelected(reqLocale, nsProviderArray::LOCALE);
   if (aLocale.IsEmpty())
     return NS_ERROR_FAILURE;
 
   if (aAsBCP47) {
     SanitizeForBCP47(aLocale);
   }
 
   return NS_OK;
@@ -267,94 +257,50 @@ nsChromeRegistryChrome::OverrideLocalePa
     aOverride = override;
   }
   else {
     aOverride = aPackage;
   }
   return NS_OK;
 }
 
-nsresult
-nsChromeRegistryChrome::SelectLocaleFromPref(nsIPrefBranch* prefs)
-{
-  nsresult rv;
-  bool matchOSLocale = false;
-  rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
-
-  if (NS_SUCCEEDED(rv) && matchOSLocale) {
-    // compute lang and region code only when needed!
-    nsAutoCString uiLocale;
-    rv = getUILangCountry(uiLocale);
-    if (NS_SUCCEEDED(rv))
-      mSelectedLocale = uiLocale;
-  }
-  else {
-    nsXPIDLCString provider;
-    rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
-    if (NS_SUCCEEDED(rv)) {
-      mSelectedLocale = provider;
-    }
-  }
-
-  if (NS_FAILED(rv))
-    NS_ERROR("Couldn't select locale from pref!");
-
-  return rv;
-}
-
 NS_IMETHODIMP
 nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
                                 const char16_t *someData)
 {
   nsresult rv = NS_OK;
 
   if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
     nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
     NS_ASSERTION(prefs, "Bad observer call!");
 
     NS_ConvertUTF16toUTF8 pref(someData);
 
-    if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
-        pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
-        rv = UpdateSelectedLocale();
-        if (NS_SUCCEEDED(rv) && mProfileLoaded)
-          FlushAllCaches();
-    }
-    else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
+    if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
       nsXPIDLCString provider;
       rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
       if (NS_FAILED(rv)) {
         NS_ERROR("Couldn't get new skin pref!");
         return rv;
       }
 
       mSelectedSkin = provider;
       RefreshSkins();
     } else {
       NS_ERROR("Unexpected pref!");
     }
   }
-  else if (!strcmp("command-line-startup", aTopic)) {
-    nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
-    if (cmdLine) {
-      nsAutoString uiLocale;
-      rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
-                                        false, uiLocale);
-      if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
-        CopyUTF16toUTF8(uiLocale, mSelectedLocale);
-        nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
-        if (prefs) {
-          prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
-        }
-      }
-    }
-  }
   else if (!strcmp("profile-initial-state", aTopic)) {
     mProfileLoaded = true;
   }
+  else if (!strcmp("intl:app-locales-changed", aTopic)) {
+    if (mProfileLoaded) {
+      FlushAllCaches();
+    }
+  }
   else {
     NS_ERROR("Unexpected observer topic!");
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
@@ -370,35 +316,16 @@ nsChromeRegistryChrome::CheckForNewChrom
   nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
 
   mDynamicRegistration = true;
 
   SendRegisteredChrome(nullptr);
   return NS_OK;
 }
 
-nsresult nsChromeRegistryChrome::UpdateSelectedLocale()
-{
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
-  if (prefs) {
-    rv = SelectLocaleFromPref(prefs);
-    if (NS_SUCCEEDED(rv)) {
-      nsCOMPtr<nsIObserverService> obsSvc =
-        mozilla::services::GetObserverService();
-      NS_ASSERTION(obsSvc, "Couldn't get observer service.");
-      obsSvc->NotifyObservers((nsIChromeRegistry*) this,
-                              "selected-locale-has-changed", nullptr);
-      mozilla::intl::LocaleService::GetInstance()->Refresh();
-    }
-  }
-
-  return rv;
-}
-
 static void
 SerializeURI(nsIURI* aURI,
              SerializedURI& aSerializedURI)
 {
   if (!aURI)
     return;
 
   aURI->GetSpec(aSerializedURI.spec);
@@ -411,17 +338,17 @@ nsChromeRegistryChrome::SendRegisteredCh
 {
   InfallibleTArray<ChromePackage> packages;
   InfallibleTArray<SubstitutionMapping> resources;
   InfallibleTArray<OverrideMapping> overrides;
 
   for (auto iter = mPackagesHash.Iter(); !iter.Done(); iter.Next()) {
     ChromePackage chromePackage;
     ChromePackageFromPackageEntry(iter.Key(), iter.UserData(), &chromePackage,
-                                  mSelectedLocale, mSelectedSkin);
+                                  mSelectedSkin);
     packages.AppendElement(chromePackage);
   }
 
   // If we were passed a parent then a new child process has been created and
   // has requested all of the chrome so send it the resources too. Otherwise
   // resource mappings are sent by the resource protocol handler dynamically.
   if (aParent) {
     nsCOMPtr<nsIIOService> io (do_GetIOService());
@@ -442,46 +369,50 @@ nsChromeRegistryChrome::SendRegisteredCh
 
     SerializeURI(iter.Key(), chromeURI);
     SerializeURI(iter.UserData(), overrideURI);
 
     OverrideMapping override = { chromeURI, overrideURI };
     overrides.AppendElement(override);
   }
 
+  nsAutoCString appLocale;
+  LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
+
   if (aParent) {
     bool success = aParent->SendRegisterChrome(packages, resources, overrides,
-                                               mSelectedLocale, false);
+                                               appLocale, false);
     NS_ENSURE_TRUE_VOID(success);
   } else {
     nsTArray<ContentParent*> parents;
     ContentParent::GetAll(parents);
     if (!parents.Length())
       return;
 
     for (uint32_t i = 0; i < parents.Length(); i++) {
       DebugOnly<bool> success =
         parents[i]->SendRegisterChrome(packages, resources, overrides,
-                                       mSelectedLocale, true);
+                                       appLocale, true);
       NS_WARNING_ASSERTION(success,
                            "couldn't reset a child's registered chrome");
     }
   }
 }
 
 /* static */ void
 nsChromeRegistryChrome::ChromePackageFromPackageEntry(const nsACString& aPackageName,
                                                       PackageEntry* aPackage,
                                                       ChromePackage* aChromePackage,
-                                                      const nsCString& aSelectedLocale,
                                                       const nsCString& aSelectedSkin)
 {
+  nsAutoCString appLocale;
+  LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
+
   SerializeURI(aPackage->baseURI, aChromePackage->contentBaseURI);
-  SerializeURI(aPackage->locales.GetBase(aSelectedLocale,
-                                         nsProviderArray::LOCALE),
+  SerializeURI(aPackage->locales.GetBase(appLocale, nsProviderArray::LOCALE),
                aChromePackage->localeBaseURI);
   SerializeURI(aPackage->skins.GetBase(aSelectedSkin, nsProviderArray::ANY),
                aChromePackage->skinBaseURI);
   aChromePackage->package = aPackageName;
   aChromePackage->flags = aPackage->flags;
 }
 
 static bool
@@ -506,17 +437,19 @@ nsChromeRegistryChrome::GetBaseURIFromPa
 
     LogMessage("No chrome package registered for chrome://%s/%s/%s",
                aPackage.get(), aProvider.get(), aPath.get());
 
     return nullptr;
   }
 
   if (aProvider.EqualsLiteral("locale")) {
-    return entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
+    nsAutoCString appLocale;
+    LocaleService::GetInstance()->GetAppLocaleAsLangTag(appLocale);
+    return entry->locales.GetBase(appLocale, nsProviderArray::LOCALE);
   }
   else if (aProvider.EqualsLiteral("skin")) {
     return entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
   }
   else if (aProvider.EqualsLiteral("content")) {
     return entry->baseURI;
   }
   return nullptr;
@@ -759,17 +692,17 @@ nsChromeRegistryChrome::ManifestContent(
   nsDependentCString packageName(package);
   PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
   entry->baseURI = resolved;
   entry->flags = flags;
 
   if (mDynamicRegistration) {
     ChromePackage chromePackage;
     ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
-                                  mSelectedLocale, mSelectedSkin);
+                                  mSelectedSkin);
     SendManifestEntry(chromePackage);
   }
 }
 
 void
 nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno,
                                        char *const * argv, int flags)
 {
@@ -795,19 +728,25 @@ nsChromeRegistryChrome::ManifestLocale(M
 
   nsDependentCString packageName(package);
   PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
   entry->locales.SetBase(nsDependentCString(provider), resolved);
 
   if (mDynamicRegistration) {
     ChromePackage chromePackage;
     ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
-                                  mSelectedLocale, mSelectedSkin);
+                                  mSelectedSkin);
     SendManifestEntry(chromePackage);
   }
+
+  if (strcmp(package, "global") == 0) {
+    // We should refresh the LocaleService, since the available
+    // locales changed.
+    LocaleService::GetInstance()->Refresh();
+  }
 }
 
 void
 nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno,
                                      char *const * argv, int flags)
 {
   char* package = argv[0];
   char* provider = argv[1];
@@ -831,17 +770,17 @@ nsChromeRegistryChrome::ManifestSkin(Man
 
   nsDependentCString packageName(package);
   PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName);
   entry->skins.SetBase(nsDependentCString(provider), resolved);
 
   if (mDynamicRegistration) {
     ChromePackage chromePackage;
     ChromePackageFromPackageEntry(packageName, entry, &chromePackage,
-                                  mSelectedLocale, mSelectedSkin);
+                                  mSelectedSkin);
     SendManifestEntry(chromePackage);
   }
 }
 
 void
 nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
                                         char *const * argv, int flags)
 {
--- a/chrome/nsChromeRegistryChrome.h
+++ b/chrome/nsChromeRegistryChrome.h
@@ -53,23 +53,20 @@ class nsChromeRegistryChrome : public ns
   // children's registered chrome.
   void SendRegisteredChrome(mozilla::dom::PContentParent* aChild);
 
  private:
   struct PackageEntry;
   static void ChromePackageFromPackageEntry(const nsACString& aPackageName,
                                             PackageEntry* aPackage,
                                             ChromePackage* aChromePackage,
-                                            const nsCString& aSelectedLocale,
                                             const nsCString& aSelectedSkin);
 
   nsresult OverrideLocalePackage(const nsACString& aPackage,
                                  nsACString& aOverride);
-  nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
-  nsresult UpdateSelectedLocale() override;
   nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                                  const nsCString& aProvider,
                                  const nsCString& aPath) override;
   nsresult GetFlagsFromPackage(const nsCString& aPackage,
                                uint32_t* aFlags) override;
 
   struct ProviderEntry
   {
@@ -152,17 +149,16 @@ class nsChromeRegistryChrome : public ns
   // Hashes on the file to be overlaid (chrome://browser/content/browser.xul)
   // to a list of overlays/stylesheets
   OverlayListHash mOverlayHash;
   OverlayListHash mStyleHash;
 
   bool mProfileLoaded;
   bool mDynamicRegistration;
 
-  nsCString mSelectedLocale;
   nsCString mSelectedSkin;
 
   // Hash of package names ("global") to PackageEntry objects
   nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
 
   virtual void ManifestContent(ManifestProcessingContext& cx, int lineno,
                                char *const * argv, int flags) override;
   virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno,
--- a/chrome/nsChromeRegistryContent.cpp
+++ b/chrome/nsChromeRegistryContent.cpp
@@ -252,21 +252,16 @@ nsChromeRegistryContent::GetStyleOverlay
 
 NS_IMETHODIMP
 nsChromeRegistryContent::GetXULOverlays(nsIURI *aChromeURL,
                                         nsISimpleEnumerator **aResult)
 {
   CONTENT_NOT_IMPLEMENTED();
 }
 
-nsresult nsChromeRegistryContent::UpdateSelectedLocale()
-{
-  CONTENT_NOT_IMPLEMENTED();
-}
-
 void
 nsChromeRegistryContent::ManifestContent(ManifestProcessingContext& cx,
                                          int lineno, char *const * argv,
                                          int flags)
 {
   CONTENT_NOTREACHED();
 }
 
--- a/chrome/nsChromeRegistryContent.h
+++ b/chrome/nsChromeRegistryContent.h
@@ -51,17 +51,16 @@ class nsChromeRegistryContent : public n
     ~PackageEntry() { }
 
     nsCOMPtr<nsIURI> contentBaseURI;
     nsCOMPtr<nsIURI> localeBaseURI;
     nsCOMPtr<nsIURI> skinBaseURI;
     uint32_t         flags;
   };
 
-  nsresult UpdateSelectedLocale() override;
   nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                      const nsCString& aProvider,
                      const nsCString& aPath) override;
   nsresult GetFlagsFromPackage(const nsCString& aPackage, uint32_t* aFlags) override;
 
   nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
   nsCString mLocale;
 
deleted file mode 100644
--- a/chrome/test/unit/test_bug519468.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/* 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/.
- */
-
-var MANIFESTS = [
-  do_get_file("data/test_bug519468.manifest")
-];
-
-Components.utils.import("resource://testing-common/MockRegistrar.jsm");
-// Stub in the locale service so we can control what gets returned as the OS locale setting
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-var stubOSLocale = null;
-
-StubLocaleService = {
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsILocaleService, Ci.nsISupports]),
-
-  getLocaleComponentForUserAgent: function SLS_getLocaleComponentForUserAgent()
-  {
-    return stubOSLocale;
-  }
-}
-
-MockRegistrar.register("@mozilla.org/intl/nslocaleservice;1", StubLocaleService);
-
-// Now fire up the test
-do_test_pending()
-registerManifests(MANIFESTS);
-
-var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
-                .getService(Ci.nsIXULChromeRegistry)
-                .QueryInterface(Ci.nsIToolkitChromeRegistry);
-chromeReg.checkForNewChrome();
-
-var prefService = Cc["@mozilla.org/preferences-service;1"]
-                  .getService(Ci.nsIPrefService)
-                  .QueryInterface(Ci.nsIPrefBranch);
-var os = Cc["@mozilla.org/observer-service;1"]
-         .getService(Ci.nsIObserverService);
-
-var testsLocale = [
-  // These tests cover when the OS local is included in our manifest
-  {matchOS: false, selected: "en-US", osLocale: "xx-AA", locale: "en-US"},
-  {matchOS: true, selected: "en-US", osLocale: "xx-AA", locale: "xx-AA"},
-  {matchOS: false, selected: "fr-FR", osLocale: "xx-AA", locale: "fr-FR"},
-  {matchOS: true, selected: "fr-FR", osLocale: "xx-AA", locale: "xx-AA"},
-  {matchOS: false, selected: "de-DE", osLocale: "xx-AA", locale: "de-DE"},
-  {matchOS: true, selected: "de-DE", osLocale: "xx-AA", locale: "xx-AA"},
-  // these tests cover the case where the OS locale is not available in our manifest, but the
-  // base language is (ie, substitute xx-AA which we have for xx-BB which we don't)
-  {matchOS: false, selected: "en-US", osLocale: "xx-BB", locale: "en-US"},
-  {matchOS: true, selected: "en-US", osLocale: "xx-BB", locale: "xx-AA"},
-  {matchOS: false, selected: "fr-FR", osLocale: "xx-BB", locale: "fr-FR"},
-  {matchOS: true, selected: "fr-FR", osLocale: "xx-BB", locale: "xx-AA"},
-  // These tests cover where the language is not available
-  {matchOS: false, selected: "en-US", osLocale: "xy-BB", locale: "en-US"},
-  {matchOS: true, selected: "en-US", osLocale: "xy-BB", locale: "en-US"},
-  {matchOS: false, selected: "fr-FR", osLocale: "xy-BB", locale: "fr-FR"},
-  {matchOS: true, selected: "fr-FR", osLocale: "xy-BB", locale: "en-US"},
-];
-
-var observedLocale = null;
-
-function test_locale(aTest) {
-  observedLocale = null;
-
-  stubOSLocale = aTest.osLocale;
-  prefService.setBoolPref("intl.locale.matchOS", aTest.matchOS);
-  prefService.setCharPref("general.useragent.locale", aTest.selected);
-
-  chromeReg.reloadChrome();
-
-  do_check_eq(observedLocale, aTest.locale);
-}
-
-// Callback function for observing locale change. May be called more than once
-// per test iteration.
-function checkValidity() {
-  observedLocale = chromeReg.getSelectedLocale("testmatchos");
-  dump("checkValidity called back with locale = " + observedLocale + "\n");
-}
-
-function run_test() {
-  os.addObserver(checkValidity, "selected-locale-has-changed", false);
-
-  for (let count = 0 ; count < testsLocale.length ; count++) {
-    dump("count = " + count + " " + testsLocale[count].toSource() + "\n");
-    test_locale(testsLocale[count]);
-  }
-
-  os.removeObserver(checkValidity, "selected-locale-has-changed");
-  do_test_finished();
-}
--- a/chrome/test/unit/xpcshell.ini
+++ b/chrome/test/unit/xpcshell.ini
@@ -4,16 +4,15 @@ support-files = data/**
 
 [test_abi.js]
 [test_bug292789.js]
 [test_bug380398.js]
 [test_bug397073.js]
 [test_bug399707.js]
 [test_bug401153.js]
 [test_bug415367.js]
-[test_bug519468.js]
 [test_bug564667.js]
 tags = addons
 [test_bug848297.js]
 [test_crlf.js]
 [test_data_protocol_registration.js]
 [test_no_remote_registration.js]
 [test_resolve_uris.js]
--- a/intl/locale/LocaleService.cpp
+++ b/intl/locale/LocaleService.cpp
@@ -8,16 +8,17 @@
 #include <algorithm>  // find_if()
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/intl/OSPreferences.h"
 #include "nsIObserverService.h"
 #include "nsStringEnumerator.h"
 #include "nsIToolkitChromeRegistry.h"
+#include "nsXULAppAPI.h"
 
 #ifdef ENABLE_INTL_API
 #include "unicode/uloc.h"
 #endif
 
 #define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
 #define SELECTED_LOCALE_PREF "general.useragent.locale"
 
@@ -71,34 +72,49 @@ static void SanitizeForBCP47(nsACString&
 }
 
 /**
  * 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)
+void
+LocaleService::NegotiateAppLocales(nsTArray<nsCString>& aRetVal)
 {
-  nsAutoCString uaLangTag;
-  nsCOMPtr<nsIToolkitChromeRegistry> cr =
-    mozilla::services::GetToolkitChromeRegistryService();
-  if (cr) {
-    // We don't want to canonicalize the locale from ChromeRegistry into
-    // it's BCP47 form because we will use it for direct language
-    // negotiation and BCP47 changes `ja-JP-mac` into `ja-JP-x-variant-mac`.
-    cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), false, uaLangTag);
-  }
-  if (!uaLangTag.IsEmpty()) {
-    aRetVal.AppendElement(uaLangTag);
-  }
+  nsAutoCString defaultLocale;
+  GetDefaultLocale(defaultLocale);
+
+  if (XRE_IsParentProcess()) {
+    AutoTArray<nsCString, 100> availableLocales;
+    AutoTArray<nsCString, 10> requestedLocales;
+    GetAvailableLocales(availableLocales);
+    GetRequestedLocales(requestedLocales);
 
-  if (!uaLangTag.EqualsLiteral("en-US")) {
-    aRetVal.AppendElement(NS_LITERAL_CSTRING("en-US"));
+    NegotiateLanguages(requestedLocales, availableLocales, defaultLocale,
+                       LangNegStrategy::Filtering, aRetVal);
+  } else {
+    //XXX: In bug 1348042 we're working on getting the content process
+    //     to follow the parent process negotiated locales.
+    //     Until we have it, we're going to match the behavior of following
+    //     the ChromeRegistry locale in the content process.
+
+    nsAutoCString uaLangTag;
+    nsCOMPtr<nsIToolkitChromeRegistry> cr =
+      mozilla::services::GetToolkitChromeRegistryService();
+    if (cr) {
+      cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), false, uaLangTag);
+    }
+    if (!uaLangTag.IsEmpty()) {
+      aRetVal.AppendElement(uaLangTag);
+    }
+
+    if (!uaLangTag.Equals(defaultLocale)) {
+      aRetVal.AppendElement(defaultLocale);
+    }
   }
 }
 
 LocaleService*
 LocaleService::GetInstance()
 {
   if (!sInstance) {
     sInstance = new LocaleService();
@@ -116,26 +132,26 @@ LocaleService::~LocaleService()
 {
   Preferences::RemoveObservers(sInstance, kObservedPrefs);
 }
 
 void
 LocaleService::GetAppLocalesAsLangTags(nsTArray<nsCString>& aRetVal)
 {
   if (mAppLocales.IsEmpty()) {
-    ReadAppLocales(mAppLocales);
+    NegotiateAppLocales(mAppLocales);
   }
   aRetVal = mAppLocales;
 }
 
 void
 LocaleService::GetAppLocalesAsBCP47(nsTArray<nsCString>& aRetVal)
 {
   if (mAppLocales.IsEmpty()) {
-    ReadAppLocales(mAppLocales);
+    NegotiateAppLocales(mAppLocales);
   }
   for (uint32_t i = 0; i < mAppLocales.Length(); i++) {
     nsAutoCString locale(mAppLocales[i]);
     SanitizeForBCP47(locale);
     aRetVal.AppendElement(locale);
   }
 }
 
@@ -151,25 +167,18 @@ LocaleService::GetRequestedLocales(nsTAr
     // If he has, we'll pick the locale from the system
     if (OSPreferences::GetInstance()->GetSystemLocales(aRetVal)) {
       // If we succeeded, return.
       return true;
     }
   }
 
   // Otherwise, we'll try to get the requested locale from the prefs.
-
-  // In some cases, mainly on Fennec and on Linux version,
-  // `general.useragent.locale` is a special 'localized' value, like:
-  // "chrome://global/locale/intl.properties"
-  if (!NS_SUCCEEDED(Preferences::GetLocalizedCString(SELECTED_LOCALE_PREF, &locale))) {
-    // If not, we can attempt to retrieve it as a simple string value.
-    if (!NS_SUCCEEDED(Preferences::GetCString(SELECTED_LOCALE_PREF, &locale))) {
-      return false;
-    }
+  if (!NS_SUCCEEDED(Preferences::GetCString(SELECTED_LOCALE_PREF, &locale))) {
+    return false;
   }
 
   // At the moment we just take a single locale, but in the future
   // we'll want to allow user to specify a list of requested locales.
   aRetVal.AppendElement(locale);
   return true;
 }
 
@@ -198,24 +207,33 @@ LocaleService::GetAvailableLocales(nsTAr
     aRetVal.AppendElement(localeStr);
   }
   return !aRetVal.IsEmpty();
 }
 
 void
 LocaleService::Refresh()
 {
+  // if mAppLocales has not been initialized yet, just return
+  if (mAppLocales.IsEmpty()) {
+    return;
+  }
+
   nsTArray<nsCString> newLocales;
-  ReadAppLocales(newLocales);
+  NegotiateAppLocales(newLocales);
 
   if (mAppLocales != newLocales) {
     mAppLocales = Move(newLocales);
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->NotifyObservers(nullptr, "intl:app-locales-changed", nullptr);
+
+      // Deprecated, please use `intl:app-locales-changed`.
+      // Kept for now for compatibility reasons
+      obs->NotifyObservers(nullptr, "selected-locale-has-changed", nullptr);
     }
   }
 }
 
 // After trying each step of the negotiation algorithm for each requested locale,
 // if a match was found we use this macro to decide whether to return immediately,
 // skip to the next requested locale, or continue searching for additional matches,
 // according to the desired negotiation strategy.
@@ -381,16 +399,17 @@ LocaleService::NegotiateLanguages(const 
 NS_IMETHODIMP
 LocaleService::Observe(nsISupports *aSubject, const char *aTopic,
                       const char16_t *aData)
 {
   // At the moment the only thing we're observing are settings indicating
   // user requested locales.
   NS_ConvertUTF16toUTF8 pref(aData);
   if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) || pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
+    Refresh();
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->NotifyObservers(nullptr, "intl:requested-locales-changed", nullptr);
     }
   }
   return NS_OK;
 }
 
@@ -415,17 +434,17 @@ LocaleService::GetDefaultLocale(nsACStri
   aRetVal.AssignLiteral("en-US");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LocaleService::GetAppLocalesAsLangTags(uint32_t* aCount, char*** aOutArray)
 {
   if (mAppLocales.IsEmpty()) {
-    ReadAppLocales(mAppLocales);
+    NegotiateAppLocales(mAppLocales);
   }
 
   *aCount = mAppLocales.Length();
   *aOutArray = CreateOutArray(mAppLocales);
 
   return NS_OK;
 }
 
@@ -440,27 +459,27 @@ LocaleService::GetAppLocalesAsBCP47(uint
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LocaleService::GetAppLocaleAsLangTag(nsACString& aRetVal)
 {
   if (mAppLocales.IsEmpty()) {
-    ReadAppLocales(mAppLocales);
+    NegotiateAppLocales(mAppLocales);
   }
   aRetVal = mAppLocales[0];
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LocaleService::GetAppLocaleAsBCP47(nsACString& aRetVal)
 {
   if (mAppLocales.IsEmpty()) {
-    ReadAppLocales(mAppLocales);
+    NegotiateAppLocales(mAppLocales);
   }
   aRetVal = mAppLocales[0];
   SanitizeForBCP47(aRetVal);
   return NS_OK;
 }
 
 static LocaleService::LangNegStrategy
 ToLangNegStrategy(int32_t aStrategy)
--- a/intl/locale/LocaleService.h
+++ b/intl/locale/LocaleService.h
@@ -207,16 +207,18 @@ private:
     nsCString mVariant;
   };
 
   void FilterMatches(const nsTArray<nsCString>& aRequested,
                      const nsTArray<nsCString>& aAvailable,
                      LangNegStrategy aStrategy,
                      nsTArray<nsCString>& aRetVal);
 
+  void NegotiateAppLocales(nsTArray<nsCString>& aRetVal);
+
   virtual ~LocaleService();
 
   nsTArray<nsCString> mAppLocales;
 
   static StaticRefPtr<LocaleService> sInstance;
 };
 } // intl
 } // namespace mozilla