Bug 875509 - Defer loading the newly created docShell after a preloaded newtab page has been swapped in; r=dao
authorTim Taubert <ttaubert@mozilla.com>
Fri, 24 May 2013 12:08:31 +0200
changeset 132870 876d89111acb3e29cc6a50b0e9f2e575ed7f4b30
parent 132869 e356663119f86945a8b20ff6f8fa86dd8545899d
child 132871 af2fa5be5afd77087f6063c77ecba62f2656e7de
push id24720
push userttaubert@mozilla.com
push dateFri, 24 May 2013 20:17:22 +0000
treeherderautoland@b03efefcb51d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao
bugs875509
milestone24.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 875509 - Defer loading the newly created docShell after a preloaded newtab page has been swapped in; r=dao
browser/base/content/tabbrowser.xml
browser/modules/BrowserNewTabPreloader.jsm
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1410,17 +1410,28 @@
 
             // Dispatch a new tab notification.  We do this once we're
             // entirely done, so that things are in a consistent state
             // even if the event listener opens or closes tabs.
             var evt = document.createEvent("Events");
             evt.initEvent("TabOpen", true, false);
             t.dispatchEvent(evt);
 
-            if (!uriIsAboutBlank) {
+            // If we just created a new tab that loads the default
+            // newtab url, swap in a preloaded page if possible.
+            // Do nothing if we're a private window.
+            let docShellsSwapped = false;
+            if (aURI == BROWSER_NEW_TAB_URL &&
+                !PrivateBrowsingUtils.isWindowPrivate(window)) {
+              docShellsSwapped = gBrowserNewTabPreloader.newTab(t);
+            }
+
+            // If we didn't swap docShells with a preloaded browser
+            // then let's just continue loading the page normally.
+            if (!docShellsSwapped && !uriIsAboutBlank) {
               // pretend the user typed this so it'll be available till
               // the document successfully loads
               if (aURI && gInitialPages.indexOf(aURI) == -1)
                 b.userTypedValue = aURI;
 
               let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
               if (aAllowThirdPartyFixup)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
@@ -1434,24 +1445,16 @@
                 Cu.reportError(ex);
               }
             }
 
             // We start our browsers out as inactive, and then maintain
             // activeness in the tab switcher.
             b.docShellIsActive = false;
 
-            // If we just created a new tab that loads the default
-            // newtab url, swap in a preloaded page if possible.
-            // Do nothing if we're a private window.
-            if (aURI == BROWSER_NEW_TAB_URL &&
-                !PrivateBrowsingUtils.isWindowPrivate(window)) {
-              gBrowserNewTabPreloader.newTab(t);
-            }
-
             // Check if we're opening a tab related to the current tab and
             // move it to after the current tab.
             // aReferrerURI is null or undefined if the tab is opened from
             // an external application or bookmark, i.e. somewhere other
             // than the current tab.
             if ((aRelatedToCurrent == null ? aReferrerURI : aRelatedToCurrent) &&
                 Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")) {
               let newTabPos = (this._lastRelatedTab ||
--- a/browser/modules/BrowserNewTabPreloader.jsm
+++ b/browser/modules/BrowserNewTabPreloader.jsm
@@ -13,32 +13,33 @@ const Ci = Components.interfaces;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window id='win'/>";
 const PREF_BRANCH = "browser.newtab.";
 const TOPIC_DELAYED_STARTUP = "browser-delayed-startup-finished";
+const PRELOADER_INTERVAL_MS = 3000;
 const PRELOADER_INIT_DELAY_MS = 5000;
 
 this.BrowserNewTabPreloader = {
   init: function Preloader_init() {
     Initializer.start();
   },
 
   uninit: function Preloader_uninit() {
     Initializer.stop();
     HostFrame.destroy();
     Preferences.uninit();
     HiddenBrowser.destroy();
   },
 
   newTab: function Preloader_newTab(aTab) {
-    HiddenBrowser.swapWithNewTab(aTab);
+    return HiddenBrowser.swapWithNewTab(aTab);
   }
 };
 
 Object.freeze(BrowserNewTabPreloader);
 
 let Initializer = {
   _timer: null,
   _observing: false,
@@ -129,51 +130,78 @@ let Preferences = {
       HiddenBrowser.create();
     } else if (this._browser && url != this.url) {
       HiddenBrowser.update(this.url);
     }
   },
 };
 
 let HiddenBrowser = {
+  _timer: null,
+
   get isPreloaded() {
     return this._browser &&
            this._browser.contentDocument &&
            this._browser.contentDocument.readyState == "complete" &&
            this._browser.currentURI.spec == Preferences.url;
   },
 
-  swapWithNewTab: function HiddenBrowser_swapWithNewTab(aTab) {
-    if (this.isPreloaded) {
-      let tabbrowser = aTab.ownerDocument.defaultView.gBrowser;
-      if (tabbrowser) {
-        tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
-      }
+  swapWithNewTab: function (aTab) {
+    if (!this.isPreloaded || this._timer) {
+      return false;
+    }
+
+    let tabbrowser = aTab.ownerDocument.defaultView.gBrowser;
+    if (!tabbrowser) {
+      return false;
+    }
+
+    // Swap docShells.
+    tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
+
+    // Start a timer that will kick off preloading the next newtab page.
+    this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    this._timer.init(this, PRELOADER_INTERVAL_MS, Ci.nsITimer.TYPE_ONE_SHOT);
+
+    // Signal that we swapped docShells.
+    return true;
+  },
+
+  observe: function () {
+    this._timer = null;
+
+    if (this._browser) {
+      this._browser.loadURI(Preferences.url);
     }
   },
 
-  create: function HiddenBrowser_create() {
+  create: function () {
     HostFrame.get(aFrame => {
       let doc = aFrame.document;
       this._browser = doc.createElementNS(XUL_NS, "browser");
       this._browser.setAttribute("type", "content");
       this._browser.setAttribute("src", Preferences.url);
       doc.getElementById("win").appendChild(this._browser);
     });
   },
 
-  update: function HiddenBrowser_update(aURL) {
+  update: function (aURL) {
     this._browser.setAttribute("src", aURL);
   },
 
-  destroy: function HiddenBrowser_destroy() {
+  destroy: function () {
     if (this._browser) {
       this._browser.parentNode.removeChild(this._browser);
       this._browser = null;
     }
+
+    if (this._timer) {
+      this._timer.cancel();
+      this._timer = null;
+    }
   }
 };
 
 let HostFrame = {
   _frame: null,
   _loading: false,
 
   get hiddenDOMDocument() {