Bug 1284166 - <setting>s do not properly handle non-ASCII characters. r=kmag
authorGeoff Lankow <geoff@darktrojan.net>
Fri, 22 Jul 2016 12:12:11 +1200
changeset 346362 d12890b78b043ccc2445dcef144e982f83b65e5f
parent 346361 c88b3a45bf362e00e0f40639a7968567d336c1ce
child 346363 f55699ce1dbdef37a792f3f8787b8b8895511a1e
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1284166
milestone50.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 1284166 - <setting>s do not properly handle non-ASCII characters. r=kmag
mobile/android/chrome/content/aboutAddons.js
mobile/android/themes/core/aboutAddons.css
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/content/setting.xml
toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js
toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js
toolkit/mozapps/extensions/test/browser/more_options.xul
--- a/mobile/android/chrome/content/aboutAddons.js
+++ b/mobile/android/chrome/content/aboutAddons.js
@@ -20,16 +20,18 @@ XPCOMUtils.defineLazyGetter(window, "gCh
   return window.QueryInterface(Ci.nsIInterfaceRequestor)
            .getInterface(Ci.nsIWebNavigation)
            .QueryInterface(Ci.nsIDocShellTreeItem)
            .rootTreeItem
            .QueryInterface(Ci.nsIInterfaceRequestor)
            .getInterface(Ci.nsIDOMWindow)
            .QueryInterface(Ci.nsIDOMChromeWindow);
 });
+XPCOMUtils.defineLazyModuleGetter(window, "Preferences",
+                                  "resource://gre/modules/Preferences.jsm");
 
 var ContextMenus = {
   target: null,
 
   init: function() {
     document.addEventListener("contextmenu", this, false);
 
     document.getElementById("contextmenu-enable").addEventListener("click", ContextMenus.enable.bind(this), false);
--- a/mobile/android/themes/core/aboutAddons.css
+++ b/mobile/android/themes/core/aboutAddons.css
@@ -254,20 +254,16 @@ select {
   background: #fff;
   border: 1px solid #ccc;
   border-radius: 4px;
   padding: 1em;
 }
 
 /* XBL bindings */
 
-settings {
-  -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#settings");
-}
-
 setting {
   display: none;
 }
 
 setting[type="bool"] {
   display: -moz-box;
   -moz-binding: url("chrome://browser/content/bindings/settings.xml#setting-fulltoggle-bool");
 }
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -21,16 +21,18 @@ Cu.import("resource://gre/modules/addons
 const CONSTANTS = {};
 Cu.import("resource://gre/modules/addons/AddonConstants.jsm", CONSTANTS);
 const SIGNING_REQUIRED = CONSTANTS.REQUIRE_SIGNING ?
                          true :
                          Services.prefs.getBoolPref("xpinstall.signatures.required");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
+                                  "resource://gre/modules/Preferences.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
   "resource:///modules/experiments/Experiments.jsm");
 
 const PREF_DISCOVERURL = "extensions.webservice.discoverURL";
 const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane";
 const PREF_XPI_ENABLED = "xpinstall.enabled";
 const PREF_MAXRESULTS = "extensions.getAddons.maxResults";
--- a/toolkit/mozapps/extensions/content/setting.xml
+++ b/toolkit/mozapps/extensions/content/setting.xml
@@ -10,23 +10,16 @@
 
 <!-- import-globals-from extensions.js -->
 
 <bindings xmlns="http://www.mozilla.org/xbl"
           xmlns:xbl="http://www.mozilla.org/xbl"
           xmlns:html="http://www.w3.org/1999/xhtml"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
-  <binding id="settings">
-    <content orient="vertical">
-      <xul:label class="settings-title" xbl:inherits="xbl:text=label" flex="1"/>
-      <children/>
-    </content>
-  </binding>
-
   <binding id="setting-base">
     <implementation>
       <constructor><![CDATA[
         this.preferenceChanged();
 
         this.addEventListener("keypress", function(event) {
           event.stopPropagation();
         }, false);
@@ -294,29 +287,25 @@
                      xbl:inherits="disabled,emptytext,type=inputtype,min,max,increment,hidespinbuttons,decimalplaces,wraparound"/>
       </xul:hbox>
     </content>
 
     <implementation>
       <method name="valueFromPreference">
         <body>
         <![CDATA[
-          const nsISupportsString = Components.interfaces.nsISupportsString;
-          this.value = Services.prefs.getComplexValue(this.pref, nsISupportsString).data;
+          this.value = Preferences.get(this.pref, "");
          ]]>
         </body>
       </method>
 
       <method name="valueToPreference">
         <body>
         <![CDATA[
-          const nsISupportsString = Components.interfaces.nsISupportsString;
-          let iss = Components.classes["@mozilla.org/supports-string;1"].createInstance(nsISupportsString);
-          iss.data = this.value;
-          Services.prefs.setComplexValue(this.pref, nsISupportsString, iss);
+          Preferences.set(this.pref, this.value);
         ]]>
         </body>
       </method>
     </implementation>
   </binding>
 
   <binding id="setting-color" extends="chrome://mozapps/content/extensions/setting.xml#setting-base">
     <content>
@@ -392,25 +381,25 @@
           }
         ]]>
         </body>
       </method>
 
       <method name="valueFromPreference">
         <body>
         <![CDATA[
-          this.value = Services.prefs.getCharPref(this.pref);
+          this.value = Preferences.get(this.pref, "");
         ]]>
         </body>
       </method>
 
       <method name="valueToPreference">
         <body>
         <![CDATA[
-          Services.prefs.setCharPref(this.pref, this.value);
+          Preferences.set(this.pref, this.value);
         ]]>
         </body>
       </method>
 
       <field name="_value"></field>
 
       <property name="value">
         <getter>
@@ -455,30 +444,17 @@
       <![CDATA[
         this.control.addEventListener("command", this.inputChanged.bind(this), false);
       ]]>
       </constructor>
 
       <method name="valueFromPreference">
         <body>
         <![CDATA[
-          let val;
-          switch (Services.prefs.getPrefType(this.pref)) {
-            case Ci.nsIPrefBranch.PREF_STRING:
-              val = Services.prefs.getCharPref(this.pref);
-              break;
-            case Ci.nsIPrefBranch.PREF_INT:
-              val = Services.prefs.getIntPref(this.pref);
-              break;
-            case Ci.nsIPrefBranch.PREF_BOOL:
-              val = Services.prefs.getBoolPref(this.pref).toString();
-              break;
-            default:
-              return;
-          }
+          let val = Preferences.get(this.pref, "").toString();
 
           if ("itemCount" in this.control) {
             for (let i = 0; i < this.control.itemCount; i++) {
               if (this.control.getItemAtIndex(i).value == val) {
                 this.control.selectedIndex = i;
                 break;
               }
             }
@@ -489,22 +465,22 @@
         </body>
       </method>
 
       <method name="valueToPreference">
         <body>
         <![CDATA[
           // We might not have a pref already set, so we guess the type from the value attribute
           let val = this.control.selectedItem.value;
-          if (val == "true" || val == "false")
-            Services.prefs.setBoolPref(this.pref, val == "true");
-          else if (/^-?\d+$/.test(val))
-            Services.prefs.setIntPref(this.pref, val);
-          else
-            Services.prefs.setCharPref(this.pref, val);
+          if (val == "true" || val == "false") {
+            val = val == "true";
+          } else if (/^-?\d+$/.test(val)) {
+            val = parseInt(val, 10);
+          }
+          Preferences.set(this.pref, val);
         ]]>
         </body>
       </method>
 
       <field name="control">this.getElementsByTagName(this.getAttribute("type") == "radio" ? "radiogroup" : "menulist")[0];</field>
     </implementation>
   </binding>
 </bindings>
--- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js
@@ -1,13 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests various aspects of the details view
+Components.utils.import("resource://gre/modules/Preferences.jsm");
 
 var gManagerWindow;
 var gCategoryUtilities;
 var gProvider;
 
 const SETTINGS_ROWS = 9;
 
 var MockFilePicker = SpecialPowers.MockFilePicker;
@@ -244,20 +245,21 @@ add_test(function() {
     Services.prefs.setCharPref("extensions.inlinesettings1.string", "foo");
     input = gManagerWindow.document.getAnonymousElementByAttribute(settings[3], "anonid", "input");
     is(input.value, "foo", "Text box should have initial value");
     input.select();
     EventUtils.synthesizeKey("b", {}, gManagerWindow);
     EventUtils.synthesizeKey("a", {}, gManagerWindow);
     EventUtils.synthesizeKey("r", {}, gManagerWindow);
     is(input.value, "bar", "Text box should have updated value");
+    input.value += "\u03DE"; // Cheat to add this non-ASCII character without typing it.
     EventUtils.synthesizeKey("/", {}, gManagerWindow);
-    is(input.value, "bar/", "Text box should have updated value");
+    is(input.value, "bar\u03DE/", "Text box should have updated value");
     is(gManagerWindow.document.getBindingParent(gManagerWindow.document.activeElement), input, "Search box should not have focus");
-    is(Services.prefs.getCharPref("extensions.inlinesettings1.string"), "bar/", "String pref should have been updated");
+    is(Preferences.get("extensions.inlinesettings1.string", "wrong"), "bar\u03DE/", "String pref should have been updated");
 
     ok(!settings[4].hasAttribute("first-row"), "Not the first row");
     input = settings[4].firstElementChild;
     is(input.value, "1", "Menulist should have initial value");
     input.focus();
     EventUtils.synthesizeKey("b", {}, gManagerWindow);
     is(input.value, "2", "Menulist should have updated value");
     is(gManagerWindow._testValue, "2", "Menulist oncommand handler should've updated the test value");
@@ -277,56 +279,57 @@ add_test(function() {
 
     try {
       ok(!settings[6].hasAttribute("first-row"), "Not the first row");
       var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button");
       input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
       is(input.value, "", "Label value should be empty");
       is(input.tooltipText, "", "Label tooltip should be empty");
 
-      var profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+      var testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
+      testFile.append("\u2622");
       var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile);
 
-      MockFilePicker.returnFiles = [profD];
+      MockFilePicker.returnFiles = [testFile];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
       EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
-      is(input.value, profD.path, "Label value should match file chosen");
-      is(input.tooltipText, profD.path, "Label tooltip should match file chosen");
-      is(Services.prefs.getCharPref("extensions.inlinesettings1.file"), profD.path, "File pref should match file chosen");
+      is(input.value, testFile.path, "Label value should match file chosen");
+      is(input.tooltipText, testFile.path, "Label tooltip should match file chosen");
+      is(Preferences.get("extensions.inlinesettings1.file", "wrong"), testFile.path, "File pref should match file chosen");
 
       MockFilePicker.returnFiles = [curProcD];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
       EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
-      is(input.value, profD.path, "Label value should not have changed");
-      is(input.tooltipText, profD.path, "Label tooltip should not have changed");
-      is(Services.prefs.getCharPref("extensions.inlinesettings1.file"), profD.path, "File pref should not have changed");
+      is(input.value, testFile.path, "Label value should not have changed");
+      is(input.tooltipText, testFile.path, "Label tooltip should not have changed");
+      is(Preferences.get("extensions.inlinesettings1.file", "wrong"), testFile.path, "File pref should not have changed");
 
       ok(!settings[7].hasAttribute("first-row"), "Not the first row");
       button = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "button");
       input = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "input");
       is(input.value, "", "Label value should be empty");
       is(input.tooltipText, "", "Label tooltip should be empty");
 
-      MockFilePicker.returnFiles = [profD];
+      MockFilePicker.returnFiles = [testFile];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
       EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
-      is(input.value, profD.path, "Label value should match file chosen");
-      is(input.tooltipText, profD.path, "Label tooltip should match file chosen");
-      is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should match file chosen");
+      is(input.value, testFile.path, "Label value should match file chosen");
+      is(input.tooltipText, testFile.path, "Label tooltip should match file chosen");
+      is(Preferences.get("extensions.inlinesettings1.directory", "wrong"), testFile.path, "Directory pref should match file chosen");
 
       MockFilePicker.returnFiles = [curProcD];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
       EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
-      is(input.value, profD.path, "Label value should not have changed");
-      is(input.tooltipText, profD.path, "Label tooltip should not have changed");
-      is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should not have changed");
+      is(input.value, testFile.path, "Label value should not have changed");
+      is(input.tooltipText, testFile.path, "Label tooltip should not have changed");
+      is(Preferences.get("extensions.inlinesettings1.directory", "wrong"), testFile.path, "Directory pref should not have changed");
 
       var unsizedInput = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input");
       var sizedInput = gManagerWindow.document.getAnonymousElementByAttribute(settings[8], "anonid", "input");
       is(unsizedInput.clientWidth > sizedInput.clientWidth, true, "Input with size attribute should be smaller than input without");
     } finally {
       button = gManagerWindow.document.getElementById("detail-prefs-btn");
       is_element_hidden(button, "Preferences button should not be visible");
 
@@ -375,19 +378,19 @@ add_test(function() {
 
     ok(!settings[2].hasAttribute("first-row"), "Not the first row");
     Services.prefs.setCharPref("extensions.inlinesettings3.radioString", "juliet");
     radios = settings[2].getElementsByTagName("radio");
     isnot(radios[0].selected, true, "Correct radio button should be selected");
     is(radios[1].selected, true, "Correct radio button should be selected");
     isnot(radios[2].selected, true, "Correct radio button should be selected");
     EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
-    is(Services.prefs.getCharPref("extensions.inlinesettings3.radioString"), "india", "Radio pref should have been updated");
+    is(Preferences.get("extensions.inlinesettings3.radioString", "wrong"), "india", "Radio pref should have been updated");
     EventUtils.synthesizeMouseAtCenter(radios[2], { clickCount: 1 }, gManagerWindow);
-    is(Services.prefs.getCharPref("extensions.inlinesettings3.radioString"), "kilo", "Radio pref should have been updated");
+    is(Preferences.get("extensions.inlinesettings3.radioString", "wrong"), "kilo \u338F", "Radio pref should have been updated");
 
     ok(!settings[3].hasAttribute("first-row"), "Not the first row");
     Services.prefs.setIntPref("extensions.inlinesettings3.menulist", 8);
     var input = settings[3].firstElementChild;
     is(input.value, "8", "Menulist should have initial value");
     input.focus();
     EventUtils.synthesizeKey("n", {}, gManagerWindow);
     is(input.value, "9", "Menulist should have updated value");
@@ -583,17 +586,17 @@ add_test(function() {
   observer.checkHidden("inlinesettings2@tests.mozilla.org");
 
   // Ensure these prefs are set. They should be set above, but somebody might
   // change the tests above.
   var profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
   Services.prefs.setBoolPref("extensions.inlinesettings1.bool", false);
   Services.prefs.setIntPref("extensions.inlinesettings1.boolint", 1);
   Services.prefs.setIntPref("extensions.inlinesettings1.integer", 12);
-  Services.prefs.setCharPref("extensions.inlinesettings1.string", "bar/");
+  Preferences.set("extensions.inlinesettings1.string", "bar\u03DE/");
   Services.prefs.setCharPref("extensions.inlinesettings1.color", "#FF9900");
   Services.prefs.setCharPref("extensions.inlinesettings1.file", profD.path);
   Services.prefs.setCharPref("extensions.inlinesettings1.directory", profD.path);
 
   var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
   addon.parentNode.ensureElementIsVisible(addon);
 
   var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
@@ -610,17 +613,17 @@ add_test(function() {
 
     input = gManagerWindow.document.getAnonymousElementByAttribute(settings[1], "anonid", "input");
     is(input.checked, true, "Checkbox should have initial value");
 
     input = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input");
     is(input.value, "12", "Number box should have initial value");
 
     input = gManagerWindow.document.getAnonymousElementByAttribute(settings[3], "anonid", "input");
-    is(input.value, "bar/", "Text box should have initial value");
+    is(input.value, "bar\u03DE/", "Text box should have initial value");
 
     input = gManagerWindow.document.getAnonymousElementByAttribute(settings[5], "anonid", "input");
     is(input.color, "#FF9900", "Color picker should have initial value");
 
     input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
     is(input.value, profD.path, "Label should have initial value");
     is(input.tooltipText, profD.path, "Label tooltip should have initial value");
 
@@ -635,17 +638,17 @@ add_test(function() {
 // Tests bindings with existing prefs.
 add_test(function() {
   observer.checkHidden("inlinesettings1@tests.mozilla.org");
 
   // Ensure these prefs are set. They should be set above, but somebody might
   // change the tests above.
   Services.prefs.setBoolPref("extensions.inlinesettings3.radioBool", false);
   Services.prefs.setIntPref("extensions.inlinesettings3.radioInt", 6);
-  Services.prefs.setCharPref("extensions.inlinesettings3.radioString", "kilo");
+  Preferences.set("extensions.inlinesettings3.radioString", "kilo \u338F");
   Services.prefs.setIntPref("extensions.inlinesettings3.menulist", 9);
 
   var addon = get_addon_element(gManagerWindow, "inlinesettings3@tests.mozilla.org");
   addon.parentNode.ensureElementIsVisible(addon);
 
   var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
   EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
 
--- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js
@@ -1,13 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests various aspects of the details view
+Components.utils.import("resource://gre/modules/Preferences.jsm");
 
 var gManagerWindow;
 var gCategoryUtilities;
 var gProvider;
 
 const SETTINGS_ROWS = 8;
 
 var MockFilePicker = SpecialPowers.MockFilePicker;
@@ -371,17 +372,17 @@ add_test(function() {
     Services.prefs.setCharPref("extensions.inlinesettings3.radioString", "juliet");
     radios = settings[2].getElementsByTagName("radio");
     isnot(radios[0].selected, true, "Correct radio button should be selected");
     is(radios[1].selected, true, "Correct radio button should be selected");
     isnot(radios[2].selected, true, "Correct radio button should be selected");
     EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
     is(Services.prefs.getCharPref("extensions.inlinesettings3.radioString"), "india", "Radio pref should have been updated");
     EventUtils.synthesizeMouseAtCenter(radios[2], { clickCount: 1 }, gManagerWindow);
-    is(Services.prefs.getCharPref("extensions.inlinesettings3.radioString"), "kilo", "Radio pref should have been updated");
+    is(Preferences.get("extensions.inlinesettings3.radioString", "wrong"), "kilo \u338F", "Radio pref should have been updated");
 
     ok(!settings[3].hasAttribute("first-row"), "Not the first row");
     Services.prefs.setIntPref("extensions.inlinesettings3.menulist", 8);
     var input = settings[3].firstElementChild;
     is(input.value, "8", "Menulist should have initial value");
     input.focus();
     EventUtils.synthesizeKey("n", {}, gManagerWindow);
     is(input.value, "9", "Menulist should have updated value");
--- a/toolkit/mozapps/extensions/test/browser/more_options.xul
+++ b/toolkit/mozapps/extensions/test/browser/more_options.xul
@@ -12,17 +12,17 @@
       <radio label="Golf" value="5" />
       <radio label="Hotel" value="6" />
     </radiogroup>
   </setting>
   <setting pref="extensions.inlinesettings3.radioString" type="radio" title="Radio">
     <radiogroup>
       <radio label="India" value="india" />
       <radio label="Juliet" value="juliet" />
-      <radio label="Kilo" value="kilo" />
+      <radio label="Kilo &#x338F;" value="kilo &#x338F;" />
     </radiogroup>
   </setting>
   <setting pref="extensions.inlinesettings3.menulist" type="menulist" title="Menulist">
     <menulist sizetopopup="always">
       <menupopup>
         <menuitem label="Lima" value="7" />
         <menuitem label="Mike" value="8" />
         <menuitem label="November" value="9" />