Bug 881590 - Don't cancel loads when preloading in the hiddenWindow; r=jaws
authorTim Taubert <ttaubert@mozilla.com>
Mon, 17 Jun 2013 19:46:55 +0200
changeset 135965 c36e0340d4e03bd118aa2537736ad9cc52692468
parent 135964 2b9573964077de9278ca4857503ddf1bdaeb12f0
child 135966 8f5749eb49f6254be92646605322972c20abcd45
push id1777
push userttaubert@mozilla.com
push dateFri, 21 Jun 2013 18:23:48 +0000
treeherderfx-team@8f5749eb49f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs881590
milestone24.0a1
Bug 881590 - Don't cancel loads when preloading in the hiddenWindow; r=jaws
browser/base/content/test/newtab/browser_newtab_perwindow_private_browsing.js
browser/modules/BrowserNewTabPreloader.jsm
--- a/browser/base/content/test/newtab/browser_newtab_perwindow_private_browsing.js
+++ b/browser/base/content/test/newtab/browser_newtab_perwindow_private_browsing.js
@@ -40,19 +40,29 @@ function runTests() {
 
 var windowsToClose = [];
 function testOnWindow(options) {
   var win = OpenBrowserWindow(options);
   win.addEventListener("load", function onLoad() {
     win.removeEventListener("load", onLoad, false);
     windowsToClose.push(win);
     gWindow = win;
-    executeSoon(TestRunner.next);
+    whenDelayedStartupFinished(win, TestRunner.next);
   }, false);
 }
 
+function whenDelayedStartupFinished(win, callback) {
+  const topic = "browser-delayed-startup-finished";
+  Services.obs.addObserver(function onStartup(subject) {
+    if (win == subject) {
+      Services.obs.removeObserver(onStartup, topic);
+      executeSoon(callback);
+    }
+  }, topic, false);
+}
+
 registerCleanupFunction(function () {
   gWindow = window;
   windowsToClose.forEach(function(win) {
     win.close();
   });
 });
 
--- a/browser/modules/BrowserNewTabPreloader.jsm
+++ b/browser/modules/BrowserNewTabPreloader.jsm
@@ -7,20 +7,21 @@
 this.EXPORTED_SYMBOLS = ["BrowserNewTabPreloader"];
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Promise.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 XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='win'/>";
 const NEWTAB_URL = "about:newtab";
 const PREF_BRANCH = "browser.newtab.";
 
 // The interval between swapping in a preload docShell and kicking off the
 // next preload in the background.
 const PRELOADER_INTERVAL_MS = 3000;
 // The initial delay before we start preloading our first new tab page. The
 // timer is started after the first 'browser-delayed-startup' has been sent.
@@ -285,22 +286,22 @@ let HiddenBrowsers = {
 
     return sizes;
   }
 };
 
 function HiddenBrowser(width, height) {
   this.resize(width, height);
 
-  HostFrame.get(aFrame => {
+  HostFrame.get().then(aFrame => {
     let doc = aFrame.document;
     this._browser = doc.createElementNS(XUL_NS, "browser");
     this._browser.setAttribute("type", "content");
+    this._browser.setAttribute("src", NEWTAB_URL);
     doc.getElementById("win").appendChild(this._browser);
-    this.preload();
   });
 }
 
 HiddenBrowser.prototype = {
   _width: null,
   _height: null,
   _timer: null,
 
@@ -328,26 +329,16 @@ HiddenBrowser.prototype = {
     this._timer = createTimer(this, PRELOADER_INTERVAL_MS);
 
     // Signal that we swapped docShells.
     return true;
   },
 
   observe: function () {
     this._timer = null;
-    this.preload();
-  },
-
-  preload: function () {
-    if (!this._browser) {
-      return;
-    }
-
-    // Make sure the browser has the right size.
-    this.resize(this._width, this._height);
 
     // Start pre-loading the new tab page.
     this._browser.loadURI(NEWTAB_URL);
   },
 
   resize: function (width, height) {
     if (this._browser) {
       this._browser.style.width = width + "px";
@@ -365,53 +356,61 @@ HiddenBrowser.prototype = {
     }
 
     this._timer = clearTimer(this._timer);
   }
 };
 
 let HostFrame = {
   _frame: null,
-  _loading: false,
+  _deferred: null,
 
   get hiddenDOMDocument() {
     return Services.appShell.hiddenDOMWindow.document;
   },
 
   get isReady() {
     return this.hiddenDOMDocument.readyState === "complete";
   },
 
-  get: function (callback) {
-    if (this._frame) {
-      callback(this._frame);
-    } else if (this.isReady && !this._loading) {
-      this._create(callback);
-      this._loading = true;
-    } else {
-      Services.tm.currentThread.dispatch(() => HostFrame.get(callback),
-                                         Ci.nsIThread.DISPATCH_NORMAL);
+  get: function () {
+    if (!this._deferred) {
+      this._deferred = Promise.defer();
+      this._create();
     }
+
+    return this._deferred.promise;
   },
 
   destroy: function () {
-    this._frame = null;
+    if (this._frame) {
+      if (!Cu.isDeadWrapper(this._frame)) {
+        this._frame.removeEventListener("load", this, true);
+        this._frame.remove();
+      }
+
+      this._frame = null;
+      this._deferred = null;
+    }
   },
 
-  _create: function (callback) {
-    let doc = this.hiddenDOMDocument;
-    let iframe = doc.createElementNS(HTML_NS, "iframe");
-    doc.documentElement.appendChild(iframe);
-
-    let frame = iframe.contentWindow;
-    let docShell = frame.QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIDocShell);
+  handleEvent: function () {
+    let contentWindow = this._frame.contentWindow;
+    if (contentWindow.location.href === XUL_PAGE) {
+      this._frame.removeEventListener("load", this, true);
+      this._deferred.resolve(contentWindow);
+    } else {
+      contentWindow.location = XUL_PAGE;
+    }
+  },
 
-    docShell.createAboutBlankContentViewer(null);
-    frame.location = XUL_PAGE;
-
-    let eventHandler = docShell.chromeEventHandler;
-    eventHandler.addEventListener("DOMContentLoaded", function onLoad() {
-      eventHandler.removeEventListener("DOMContentLoaded", onLoad, false);
-      callback(HostFrame._frame = frame);
-    }, false);
+  _create: function () {
+    if (this.isReady) {
+      let doc = this.hiddenDOMDocument;
+      this._frame = doc.createElementNS(HTML_NS, "iframe");
+      this._frame.addEventListener("load", this, true);
+      doc.documentElement.appendChild(this._frame);
+    } else {
+      let flags = Ci.nsIThread.DISPATCH_NORMAL;
+      Services.tm.currentThread.dispatch(() => this._create(), flags);
+    }
   }
 };