From: Mike Hommey <mh@glandium.org>
Date: Fri, 29 Jan 2010 10:40:51 +0100
Subject: Allow intl.locale.matchOS to be modified in user profile

https://bugzilla.mozilla.org/show_bug.cgi?id=519468
Closes: #417961
---
 chrome/src/nsChromeRegistry.cpp               |   91 ++++++++++++++-----------
 chrome/src/nsChromeRegistry.h                 |    6 ++-
 chrome/test/unit/data/test_bug519468.manifest |    2 +
 chrome/test/unit/test_bug519468.js            |   80 ++++++++++++++++++++++
 toolkit/xre/nsXREDirProvider.cpp              |    2 +
 5 files changed, 139 insertions(+), 42 deletions(-)
 create mode 100644 chrome/test/unit/data/test_bug519468.manifest
 create mode 100644 chrome/test/unit/test_bug519468.js

diff --git a/chrome/src/nsChromeRegistry.cpp b/chrome/src/nsChromeRegistry.cpp
index 4e7efd7..2f55af4 100644
--- a/chrome/src/nsChromeRegistry.cpp
+++ b/chrome/src/nsChromeRegistry.cpp
@@ -550,48 +550,27 @@ nsChromeRegistry::Init()
   if (!prefs) {
     NS_WARNING("Could not get pref service!");
   }
-
-  PRBool useLocalePref = PR_TRUE;
-
-  if (prefs) {
-    // check the pref first
-    PRBool matchOS = PR_FALSE;
-    rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOS);
-
-    // match os locale
-    if (NS_SUCCEEDED(rv) && matchOS) {
-      // compute lang and region code only when needed!
-      nsCAutoString uiLocale;
-      rv = getUILangCountry(uiLocale);
-      if (NS_SUCCEEDED(rv)) {
-        useLocalePref = PR_FALSE;
-        mSelectedLocale = uiLocale;
-      }
-    }
-  }
-      
-  if (prefs) {
+  else {
     nsXPIDLCString provider;
-
     rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
     if (NS_SUCCEEDED(rv))
       mSelectedSkin = provider;
 
+    SelectLocalePref(prefs);
+
     nsCOMPtr<nsIPrefBranch2> prefs2 (do_QueryInterface(prefs));
 
-    if (prefs2)
+    if (prefs2) {
+      rv = prefs2->AddObserver(MATCH_OS_LOCALE_PREF, this, PR_TRUE);
+      rv = prefs2->AddObserver(SELECTED_LOCALE_PREF, this, PR_TRUE);
       rv = prefs2->AddObserver(SELECTED_SKIN_PREF, this, PR_TRUE);
-
-    if (useLocalePref) {
-      rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
-      if (NS_SUCCEEDED(rv))
-        mSelectedLocale = provider;
-      
-      if (prefs2)
-        prefs2->AddObserver(SELECTED_LOCALE_PREF, this, PR_TRUE);
     }
   }
 
+  nsCOMPtr<nsIObserverService> obsService (do_GetService("@mozilla.org/observer-service;1"));
+  if (obsService)
+    obsService->AddObserver(this, "profile-initial-state", PR_TRUE);
+
   CheckForNewChrome();
 
   mInitialized = PR_TRUE;
@@ -1484,6 +1463,31 @@ nsChromeRegistry::ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength,
   return NS_OK;
 }
 
+nsresult
+nsChromeRegistry::SelectLocalePref(nsIPrefBranch* prefs)
+{
+  nsresult rv;
+  PRBool matchOSLocale = PR_FALSE;
+  rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
+
+  if (NS_SUCCEEDED(rv) && matchOSLocale) {
+    // compute lang and region code only when needed!
+    nsCAutoString 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;
+    }
+  }
+
+  return rv;
+}
+
 NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
 {
   nsresult rv = NS_OK;
@@ -1494,20 +1498,22 @@ NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopi
 
     NS_ConvertUTF16toUTF8 pref(someData);
 
-    nsXPIDLCString provider;
-    rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
-    if (NS_FAILED(rv)) {
-      NS_ERROR("Couldn't get new locale or skin pref!");
-      return rv;
+    if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
+        pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
+      rv = SelectLocalePref(prefs);
+      if (NS_SUCCEEDED(rv) && mProfileLoaded)
+        FlushAllCaches();
     }
+    else 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 locale pref!");
+        return rv;
+      }
 
-    if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
       mSelectedSkin = provider;
       RefreshSkins();
-    }
-    else if (pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
-      mSelectedLocale = provider;
-      FlushAllCaches();
     } else {
       NS_ERROR("Unexpected pref!");
     }
@@ -1527,6 +1533,9 @@ NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopi
       }
     }
   }
+  else if (!strcmp("profile-initial-state", aTopic)) {
+    mProfileLoaded = PR_TRUE;
+  }
   else {
     NS_ERROR("Unexpected observer topic!");
   }
diff --git a/chrome/src/nsChromeRegistry.h b/chrome/src/nsChromeRegistry.h
index 0fa15c9..98a1d32 100644
--- a/chrome/src/nsChromeRegistry.h
+++ b/chrome/src/nsChromeRegistry.h
@@ -61,6 +61,7 @@ class nsICSSLoader;
 class nsICSSStyleSheet;
 class nsIDOMWindowInternal;
 class nsILocalFile;
+class nsIPrefBranch;
 class nsIRDFDataSource;
 class nsIRDFResource;
 class nsIRDFService;
@@ -94,7 +95,7 @@ public:
   NS_DECL_NSIOBSERVER
 
   // nsChromeRegistry methods:
-  nsChromeRegistry() : mInitialized(PR_FALSE) {
+  nsChromeRegistry() : mInitialized(PR_FALSE), mProfileLoaded(PR_FALSE) {
     mPackagesHash.ops = nsnull;
   }
   ~nsChromeRegistry();
@@ -115,6 +116,8 @@ protected:
   void FlushAllCaches();
 
 private:
+  nsresult SelectLocalePref(nsIPrefBranch* prefs);
+
   static nsresult RefreshWindow(nsIDOMWindowInternal* aWindow,
                                 nsICSSLoader* aCSSLoader);
   static nsresult GetProviderAndPath(nsIURL* aChromeURL,
@@ -244,6 +247,7 @@ public:
 
 private:
   PRBool mInitialized;
+  PRBool mProfileLoaded;
 
   // Hash of package names ("global") to PackageEntry objects
   PLDHashTable mPackagesHash;
diff --git a/chrome/test/unit/data/test_bug519468.manifest b/chrome/test/unit/data/test_bug519468.manifest
new file mode 100644
index 0000000..5d39f92
--- /dev/null
+++ b/chrome/test/unit/data/test_bug519468.manifest
@@ -0,0 +1,2 @@
+locale testmatchos en-US jar:en-US.jar!/locale/en-US/global/
+locale testmatchos fr-FR jar:en-US.jar!/locale/en-US/global/
diff --git a/chrome/test/unit/test_bug519468.js b/chrome/test/unit/test_bug519468.js
new file mode 100644
index 0000000..68ef753
--- /dev/null
+++ b/chrome/test/unit/test_bug519468.js
@@ -0,0 +1,80 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *      Vivien Nicolas <21@vingtetun.org>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****
+ */
+
+var MANIFESTS = [
+  do_get_file("data/test_bug519468.manifest")
+];
+
+registerManifests(MANIFESTS);
+
+var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
+                .getService(Ci.nsIXULChromeRegistry)
+                .QueryInterface(Ci.nsIToolkitChromeRegistry);
+
+var localeService = Cc["@mozilla.org/intl/nslocaleservice;1"]
+                    .getService(Ci.nsILocaleService);
+
+var prefService = Cc["@mozilla.org/preferences-service;1"]
+                  .getService(Ci.nsIPrefService)
+                  .QueryInterface(Ci.nsIPrefBranch);
+
+function test_locale(aTest) {
+  prefService.setBoolPref("intl.locale.matchOS", aTest.matchOS);
+  prefService.setCharPref("general.useragent.locale", aTest.selected || "en-US");
+
+  var selectedLocale = chromeReg.getSelectedLocale("testmatchos");
+  do_check_eq(selectedLocale, aTest.locale);
+}
+
+function run_test()
+{
+  var systemLocale = localeService.getLocaleComponentForUserAgent();
+
+  var tests = [
+    {matchOS: false, selected: null, locale: "en-US"},
+    {matchOS: true, selected: null, locale: systemLocale},
+    {matchOS: true, selected: "fr-FR", locale: systemLocale},
+    {matchOS: false, selected: "fr-FR", locale: "fr-FR"},
+    {matchOS: true, selected: null, locale: systemLocale}
+  ];
+
+  for (var i = 0; i < tests.length; ++ i) {
+    var test = tests[i];
+    test_locale(test);
+  }
+}
diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
index 7e37582..786cad1 100644
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -816,6 +816,8 @@ nsXREDirProvider::DoStartup()
     // should also be created at this time.
     (void)NS_CreateServicesFromCategory("profile-after-change", nsnull,
                                         "profile-after-change");
+
+    obsSvc->NotifyObservers(nsnull, "profile-initial-state", nsnull);
   }
   return NS_OK;
 }
