Bug 1012223 - Make opening about:preferences faster (includes fix for bug 1132031. r=jaws, r=florian, a=lmandel
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Mon, 19 Jan 2015 17:40:12 +0000
changeset 249739 d03da8430432bd0611e2791c0235ed21748c43a0
parent 249738 895903e491e00d4ef3dc0f2bb56a0eb853f827f9
child 249740 d0d290f35a8419df151f6177101d3c2616928db7
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws, florian, lmandel
bugs1012223, 1132031
milestone37.0a2
Bug 1012223 - Make opening about:preferences faster (includes fix for bug 1132031. r=jaws, r=florian, a=lmandel
browser/components/preferences/in-content/advanced.xul
browser/components/preferences/in-content/applications.xul
browser/components/preferences/in-content/content.js
browser/components/preferences/in-content/content.xul
browser/components/preferences/in-content/main.xul
browser/components/preferences/in-content/preferences.js
browser/components/preferences/in-content/privacy.xul
browser/components/preferences/in-content/search.xul
browser/components/preferences/in-content/security.xul
browser/components/preferences/in-content/sync.xul
browser/components/preferences/in-content/tests/browser_bug410900.js
browser/components/preferences/in-content/tests/browser_bug731866.js
browser/components/preferences/in-content/tests/browser_bug795764_cachedisabled.js
browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js
--- a/browser/components/preferences/in-content/advanced.xul
+++ b/browser/components/preferences/in-content/advanced.xul
@@ -2,17 +2,17 @@
 # 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/.
 
 <!-- Advanced panel -->
 
 <script type="application/javascript"
         src="chrome://browser/content/preferences/in-content/advanced.js"/>
 
-<preferences id="advancedPreferences">
+<preferences id="advancedPreferences" hidden="true" data-category="paneAdvanced">
   <preference id="browser.preferences.advanced.selectedTabIndex"
               name="browser.preferences.advanced.selectedTabIndex"
               type="int"/>
 
   <!-- General tab -->
   <preference id="accessibility.browsewithcaret"
               name="accessibility.browsewithcaret"
               type="bool"/>
--- a/browser/components/preferences/in-content/applications.xul
+++ b/browser/components/preferences/in-content/applications.xul
@@ -2,17 +2,17 @@
 # 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/.
 
 <!-- Applications panel -->
 
 <script type="application/javascript"
         src="chrome://browser/content/preferences/in-content/applications.js"/>
 
-<preferences id="feedsPreferences">
+<preferences id="feedsPreferences" hidden="true" data-category="paneApplications">
   <preference id="browser.feeds.handler"
               name="browser.feeds.handler"
               type="string"/>
   <preference id="browser.feeds.handler.default"
               name="browser.feeds.handler.default"
               type="string"/>
   <preference id="browser.feeds.handlers.application"
               name="browser.feeds.handlers.application"
--- a/browser/components/preferences/in-content/content.js
+++ b/browser/components/preferences/in-content/content.js
@@ -117,16 +117,20 @@ var gContentPane = {
                    type     : "unichar",
                    element  : null,
                    fonttype : aIsSerif ? "serif" : "sans-serif" },
                  { format   : kFontSizeFmtVariable,
                    type     : "int",
                    element  : "defaultFontSize",
                    fonttype : null }];
     var preferences = document.getElementById("contentPreferences");
+    // Ensure preferences are "visible" to ensure bindings work.
+    preferences.hidden = false;
+    // Force flush:
+    preferences.clientHeight;
     for (var i = 0; i < prefs.length; ++i) {
       var preference = document.getElementById(prefs[i].format.replace(/%LANG%/, aLanguageGroup));
       if (!preference) {
         preference = document.createElement("preference");
         var name = prefs[i].format.replace(/%LANG%/, aLanguageGroup);
         preference.id = name;
         preference.setAttribute("name", name);
         preference.setAttribute("type", prefs[i].type);
--- a/browser/components/preferences/in-content/content.xul
+++ b/browser/components/preferences/in-content/content.xul
@@ -1,15 +1,15 @@
 # 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/.
 
 <!-- Content panel -->
 
-<preferences id="contentPreferences">
+<preferences id="contentPreferences" hidden="true" data-category="paneContent">
 
   <!-- Popups -->
   <preference id="dom.disable_open_during_load"
               name="dom.disable_open_during_load"
               type="bool"/>
 
   <!-- Fonts -->
   <preference id="font.language.group"
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -2,17 +2,17 @@
 # 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/.
 
 <!-- General panel -->
 
 <script type="application/javascript" 
         src="chrome://browser/content/preferences/in-content/main.js"/>
 
-<preferences id="mainPreferences">
+<preferences id="mainPreferences" hidden="true" data-category="paneGeneral">
 
 #ifdef E10S_TESTING_ONLY
     <preference id="browser.tabs.remote.autostart"
                 name="browser.tabs.remote.autostart"
                 type="bool"/>
     <preference id="e10sTempPref"
                 name="browser.tabs.remote.autostart.1"
                 type="bool"/>
--- a/browser/components/preferences/in-content/preferences.js
+++ b/browser/components/preferences/in-content/preferences.js
@@ -9,55 +9,77 @@ const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 let gLastHash = "";
 
+let gCategoryInits = new Map();
+function init_category_if_required(category) {
+  let categoryInfo = gCategoryInits.get(category);
+  if (!categoryInfo) {
+    throw "Unknown in-content prefs category! Can't init " + category;
+  }
+  if (categoryInfo.inited) {
+    return;
+  }
+  categoryInfo.init();
+}
+
+function register_module(categoryName, categoryObject) {
+  gCategoryInits.set(categoryName, {
+    inited: false,
+    init: function() {
+      categoryObject.init();
+      this.inited = true;
+    }
+  });
+}
+
 addEventListener("DOMContentLoaded", function onLoad() {
   removeEventListener("DOMContentLoaded", onLoad);
   init_all();
 });
 
 function init_all() {
   document.documentElement.instantApply = true;
 
   gSubDialog.init();
-  gMainPane.init();
-  gSearchPane.init();
-  gPrivacyPane.init();
-  gAdvancedPane.init();
-  gApplicationsPane.init();
-  gContentPane.init();
-  gSyncPane.init();
-  gSecurityPane.init();
-
-  var initFinished = new CustomEvent("Initialized", {
-  'bubbles': true,
-  'cancelable': true
-  });
-  document.dispatchEvent(initFinished);
+  register_module("paneGeneral", gMainPane);
+  register_module("paneSearch", gSearchPane);
+  register_module("panePrivacy", gPrivacyPane);
+  register_module("paneAdvanced", gAdvancedPane);
+  register_module("paneApplications", gApplicationsPane);
+  register_module("paneContent", gContentPane);
+  register_module("paneSync", gSyncPane);
+  register_module("paneSecurity", gSecurityPane);
 
   let categories = document.getElementById("categories");
   categories.addEventListener("select", event => gotoPref(event.target.value));
 
   document.documentElement.addEventListener("keydown", function(event) {
     if (event.keyCode == KeyEvent.DOM_VK_TAB) {
       categories.setAttribute("keyboard-navigation", "true");
     }
   });
   categories.addEventListener("mousedown", function() {
     this.removeAttribute("keyboard-navigation");
   });
 
   window.addEventListener("hashchange", onHashChange);
   gotoPref();
 
+  var initFinished = new CustomEvent("Initialized", {
+    'bubbles': true,
+    'cancelable': true
+  });
+  document.dispatchEvent(initFinished);
+
   let helpCmd = document.getElementById("help-button");
   helpCmd.addEventListener("command", helpButtonCommand);
 
   // Wait until initialization of all preferences are complete before
   // notifying observers that the UI is now ready.
   Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
 }
 
@@ -81,16 +103,23 @@ function gotoPref(aCategory) {
   if (gLastHash == category)
     return;
   let item = categories.querySelector(".category[value=" + category + "]");
   if (!item) {
     category = kDefaultCategoryInternalName;
     item = categories.querySelector(".category[value=" + category + "]");
   }
 
+  try {
+    init_category_if_required(category);
+  } catch (ex) {
+    Cu.reportError("Error initializing preference category " + category + ": " + ex);
+    throw ex;
+  }
+
   let newHash = internalPrefCategoryNameToFriendlyName(category);
   if (gLastHash || category != kDefaultCategoryInternalName) {
     document.location.hash = newHash;
   }
   // Need to set the gLastHash before setting categories.selectedItem since
   // the categories 'select' event will re-enter the gotoPref codepath.
   gLastHash = category;
   categories.selectedItem = item;
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -2,17 +2,17 @@
 # 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/.
 
 <!-- Privacy panel -->
 
 <script type="application/javascript"
         src="chrome://browser/content/preferences/in-content/privacy.js"/>
 
-<preferences id="privacyPreferences">
+<preferences id="privacyPreferences" hidden="true" data-category="panePrivacy">
 
   <!-- Tracking -->
   <preference id="privacy.donottrackheader.enabled"
               name="privacy.donottrackheader.enabled"
               type="bool"/>
   <preference id="privacy.trackingprotection.enabled"
               name="privacy.trackingprotection.enabled"
               type="bool"/>
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -1,9 +1,9 @@
-    <preferences id="searchPreferences">
+    <preferences id="searchPreferences" hidden="true" data-category="paneSearch">
 
       <!-- Suggest -->
       <preference id="browser.search.suggest.enabled"
                   name="browser.search.suggest.enabled"
                   type="bool"/>
 
       <!-- One off providers -->
       <preference id="browser.search.hiddenOneOffs"
--- a/browser/components/preferences/in-content/security.xul
+++ b/browser/components/preferences/in-content/security.xul
@@ -2,17 +2,17 @@
 # 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/.
 
 <!-- Security panel -->
 
 <script type="application/javascript" 
         src="chrome://browser/content/preferences/in-content/security.js"/>  
 
-<preferences id="securityPreferences">
+<preferences id="securityPreferences" hidden="true" data-category="paneSecurity">
   <!-- XXX buttons -->
   <preference id="pref.privacy.disable_button.view_passwords"
               name="pref.privacy.disable_button.view_passwords"
               type="bool"/>
   <preference id="pref.privacy.disable_button.view_passwords_exceptions"
               name="pref.privacy.disable_button.view_passwords_exceptions"
               type="bool"/>
 
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -1,15 +1,15 @@
 # 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/.
 
-<!-- Synch panel -->
+<!-- Sync panel -->
 
-<preferences>
+<preferences hidden="true" data-category="paneSync">
   <preference id="engine.addons"
               name="services.sync.engine.addons"
               type="bool"/>
   <preference id="engine.bookmarks"
               name="services.sync.engine.bookmarks"
               type="bool"/>
   <preference id="engine.history"
               name="services.sync.engine.history"
--- a/browser/components/preferences/in-content/tests/browser_bug410900.js
+++ b/browser/components/preferences/in-content/tests/browser_bug410900.js
@@ -1,58 +1,48 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
 
 function test() {
   waitForExplicitFinish();
+  Services.prefs.setBoolPref("browser.preferences.inContent", true);
+  registerCleanupFunction(() => Services.prefs.clearUserPref("browser.preferences.inContent"));
 
   // Setup a phony handler to ensure the app pane will be populated.
   var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
                 createInstance(Ci.nsIWebHandlerApp);
   handler.name = "App pane alive test";
   handler.uriTemplate = "http://test.mozilla.org/%s";
 
   var extps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
               getService(Ci.nsIExternalProtocolService);
   var info = extps.getProtocolHandlerInfo("apppanetest");
   info.possibleApplicationHandlers.appendElement(handler, false);
 
   var hserv = Cc["@mozilla.org/uriloader/handler-service;1"].
               getService(Ci.nsIHandlerService);
   hserv.store(info);
 
-  function observer(win, topic, data) {
-    if (topic != "app-handler-pane-loaded")
-      return;
-
-    Services.obs.removeObserver(observer, "app-handler-pane-loaded");
-    runTest(win);
-  }
-  Services.obs.addObserver(observer, "app-handler-pane-loaded", false);
-
-  gBrowser.selectedTab = gBrowser.addTab("about:preferences");
+  openPreferencesViaOpenPreferencesAPI("applications", null, {leaveOpen: true}).then(
+      () => runTest(gBrowser.selectedBrowser.contentWindow)
+  );
 }
 
 function runTest(win) {
-  win.gotoPref("applications");
-  var sel = win.history.state;
-  is(sel, "paneApplications", "Specified pane was opened");
-
   var rbox = win.document.getElementById("handlersView");
   ok(rbox, "handlersView is present");
 
   var items = rbox && rbox.getElementsByTagName("richlistitem");
   ok(items && items.length > 0, "App handler list populated");
 
   var handlerAdded = false;
   for (let i = 0; i < items.length; i++) {
     if (items[i].getAttribute('type') == "apppanetest")
       handlerAdded = true;
   }
   ok(handlerAdded, "apppanetest protocol handler was successfully added");
 
   gBrowser.removeCurrentTab();
-  win.close();
   finish();
 }
--- a/browser/components/preferences/in-content/tests/browser_bug731866.js
+++ b/browser/components/preferences/in-content/tests/browser_bug731866.js
@@ -4,95 +4,45 @@
 Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
 
 function test() {
   waitForExplicitFinish();
   open_preferences(runTest);
 }
 
+let gElements;
+
+function checkElements(expectedPane) {
+  for (let element of gElements) {
+    // preferences elements fail is_element_visible checks because they are never visible.
+    if (element.nodeName == "preferences") {
+      continue;
+    }
+    let attributeValue = element.getAttribute("data-category");
+    if (attributeValue == "pane" + expectedPane) {
+      is_element_visible(element, expectedPane + " elements should be visible");
+    } else {
+      is_element_hidden(element, "Elements not in " + expectedPane + " should be hidden");
+    }
+  }
+}
+
 function runTest(win) {
   is(gBrowser.currentURI.spec, "about:preferences", "about:preferences loaded");
 
   let tab = win.document;
-  let elements = tab.getElementById("mainPrefPane").children;
-
-  //Test if general pane is opened correctly
-  win.gotoPref("paneGeneral");
-  for (let element of elements) {
-    let attributeValue = element.getAttribute("data-category");
-    if (attributeValue == "paneGeneral") {
-      is_element_visible(element, "General elements should be visible");
-    } else {
-      is_element_hidden(element, "Non-General elements should be hidden");
-    }
-  }
-
-  //Test if content pane is opened correctly
-  win.gotoPref("paneContent");
-  for (let element of elements) {
-    let attributeValue = element.getAttribute("data-category");
-    if (attributeValue == "paneContent") {
-      is_element_visible(element, "Content elements should be visible");
-    } else {
-      is_element_hidden(element, "Non-Content elements should be hidden");
-    }
-  }
-
-  //Test if applications pane is opened correctly
-  win.gotoPref("paneApplications");
-  for (let element of elements) {
-    let attributeValue = element.getAttribute("data-category");
-    if (attributeValue == "paneApplications") {
-      is_element_visible(element, "Application elements should be visible");
-    } else {
-      is_element_hidden(element, "Non-Application elements should be hidden");
-    }
-  }
+  gElements = tab.getElementById("mainPrefPane").children;
 
-  //Test if privacy pane is opened correctly
-  win.gotoPref("panePrivacy");
-  for (let element of elements) {
-    let attributeValue = element.getAttribute("data-category");
-    if (attributeValue == "panePrivacy") {
-      is_element_visible(element, "Privacy elements should be visible");
-    } else {
-      is_element_hidden(element, "Non-Privacy elements should be hidden");
-    }
-  }
+  let panes = [
+    "General", "Search", "Content", "Applications",
+    "Privacy", "Security", "Sync", "Advanced",
+  ];
 
-  //Test if security pane is opened correctly
-  win.gotoPref("paneSecurity");
-  for (let element of elements) {
-    let attributeValue = element.getAttribute("data-category");
-    if (attributeValue == "paneSecurity") {
-      is_element_visible(element, "Security elements should be visible");
-    } else {
-      is_element_hidden(element, "Non-Security elements should be hidden");
-    }
-  }
-
-  //Test if sync pane is opened correctly
-  win.gotoPref("paneSync");
-  for (let element of elements) {
-    let attributeValue = element.getAttribute("data-category");
-    if (attributeValue == "paneSync") {
-      is_element_visible(element, "Sync elements should be visible");
-    } else {
-      is_element_hidden(element, "Non-Sync elements should be hidden");
-    }
-  }
-
-  //Test if advanced pane is opened correctly
-  win.gotoPref("paneAdvanced");
-  for (let element of elements) {
-    let attributeValue = element.getAttribute("data-category");
-    if (attributeValue == "paneAdvanced") {
-      is_element_visible(element, "Advanced elements should be visible");
-    } else {
-      is_element_hidden(element, "Non-Advanced elements should be hidden");
-    }
+  for (let pane of panes) {
+    win.gotoPref("pane" + pane);
+    checkElements(pane);
   }
 
   gBrowser.removeCurrentTab();
   win.close();
   finish();
 }
--- a/browser/components/preferences/in-content/tests/browser_bug795764_cachedisabled.js
+++ b/browser/components/preferences/in-content/tests/browser_bug795764_cachedisabled.js
@@ -30,16 +30,19 @@ function runTest(win) {
   is(gBrowser.currentURI.spec, "about:preferences", "about:preferences loaded");
 
   let tab = win.document;
   let elements = tab.getElementById("mainPrefPane").children;
 
   // Test if advanced pane is opened correctly
   win.gotoPref("paneAdvanced");
   for (let element of elements) {
+    if (element.nodeName == "preferences") {
+      continue;
+    }
     let attributeValue = element.getAttribute("data-category");
     if (attributeValue == "paneAdvanced") {
       is_element_visible(element, "Advanced elements should be visible");
     } else {
       is_element_hidden(element, "Non-Advanced elements should be hidden");
     }
   }
 
--- a/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js
+++ b/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js
@@ -4,16 +4,17 @@
 function runTestOnPrivacyPrefPane(testFunc) {
   
   gBrowser.tabContainer.addEventListener("TabOpen", function(aEvent) {
     gBrowser.tabContainer.removeEventListener("TabOpen", arguments.callee, true);
     let browser = aEvent.originalTarget.linkedBrowser;
     browser.addEventListener("Initialized", function(aEvent) {
       browser.removeEventListener("Initialized", arguments.callee, true);
       is(browser.contentWindow.location.href, "about:preferences", "Checking if the preferences tab was opened");
+      browser.contentWindow.gotoPref("panePrivacy");
       testFunc(browser.contentWindow);
       gBrowser.removeCurrentTab();
       testRunner.runNext();
     }, true);
   }, true);
   
   gBrowser.selectedTab = gBrowser.addTab("about:preferences");
 }