Bug 1317101 - Part 7c: Run extension popups in a remote browser. r=aswan
☠☠ backed out by ed48815cbe18 ☠ ☠
authorKris Maglione <maglione.k@gmail.com>
Wed, 16 Nov 2016 13:39:45 -0800
changeset 322832 b7892d3fb0ca5268a252377ecbb44dfb1d289500
parent 322831 039d63d5fef77d7b77c0a7f9724ec9e6347be09a
child 322833 0f8144296a9d8e67a4f307491559a0051f95a9a7
push id83985
push usermaglione.k@gmail.com
push dateWed, 16 Nov 2016 21:47:37 +0000
treeherdermozilla-inbound@61f8a4084bbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1317101
milestone53.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 1317101 - Part 7c: Run extension popups in a remote browser. r=aswan MozReview-Commit-ID: CATeESBwj1J
browser/components/extensions/ext-utils.js
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -118,17 +118,17 @@ class BasePopup {
   }
 
   destroy() {
     this.extension.forgetOnClose(this);
 
     this.destroyed = true;
     this.browserLoadedDeferred.reject(new Error("Popup destroyed"));
     return this.browserReady.then(() => {
-      this.destroyBrowser(this.browser);
+      this.destroyBrowser(this.browser, true);
       this.browser.remove();
 
       this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
       this.viewNode.style.maxHeight = "";
 
       if (this.panel) {
         this.panel.style.removeProperty("--arrowpanel-background");
         this.panel.style.removeProperty("--panel-arrow-image-vertical");
@@ -136,26 +136,29 @@ class BasePopup {
 
       BasePopup.instances.get(this.window).delete(this.extension);
 
       this.browser = null;
       this.viewNode = null;
     });
   }
 
-  destroyBrowser(browser) {
+  destroyBrowser(browser, finalize = false) {
     let mm = browser.messageManager;
     // If the browser has already been removed from the document, because the
-    // popup was closed externally, there will be no message manager here.
+    // popup was closed externally, there will be no message manager here, so
+    // just replace our receiveMessage method with a stub.
     if (mm) {
       mm.removeMessageListener("DOMTitleChanged", this);
       mm.removeMessageListener("Extension:BrowserBackgroundChanged", this);
       mm.removeMessageListener("Extension:BrowserContentLoaded", this);
       mm.removeMessageListener("Extension:BrowserResized", this);
       mm.removeMessageListener("Extension:DOMWindowClose", this);
+    } else if (finalize) {
+      this.receiveMessage = () => {};
     }
   }
 
   // Returns the name of the event fired on `viewNode` when the popup is being
   // destroyed. This must be implemented by every subclass.
   get DESTROY_EVENT() {
     throw new Error("Not implemented");
   }
@@ -223,47 +226,57 @@ class BasePopup {
     this.browser = document.createElementNS(XUL_NS, "browser");
     this.browser.setAttribute("type", "content");
     this.browser.setAttribute("disableglobalhistory", "true");
     this.browser.setAttribute("transparent", "true");
     this.browser.setAttribute("class", "webextension-popup-browser");
     this.browser.setAttribute("webextension-view-type", "popup");
     this.browser.setAttribute("tooltip", "aHTMLTooltip");
 
+    if (this.extension.remote) {
+      this.browser.setAttribute("remote", "true");
+    }
+
     // We only need flex sizing for the sake of the slide-in sub-views of the
     // main menu panel, so that the browser occupies the full width of the view,
     // and also takes up any extra height that's available to it.
     this.browser.setAttribute("flex", "1");
 
     // Note: When using noautohide panels, the popup manager will add width and
     // height attributes to the panel, breaking our resize code, if the browser
     // starts out smaller than 30px by 10px. This isn't an issue now, but it
     // will be if and when we popup debugging.
 
+
+    let readyPromise;
+    if (this.extension.remote) {
+      readyPromise = promiseEvent(this.browser, "XULFrameLoaderCreated");
+    } else {
+      readyPromise = promiseEvent(this.browser, "load");
+    }
+
     viewNode.appendChild(this.browser);
 
     extensions.emit("extension-browser-inserted", this.browser);
 
-    let initBrowser = browser => {
-      let mm = browser.messageManager;
+    readyPromise = readyPromise.then(() => {
+      let mm = this.browser.messageManager;
       mm.addMessageListener("DOMTitleChanged", this);
       mm.addMessageListener("Extension:BrowserBackgroundChanged", this);
       mm.addMessageListener("Extension:BrowserContentLoaded", this);
       mm.addMessageListener("Extension:BrowserResized", this);
       mm.addMessageListener("Extension:DOMWindowClose", this, true);
-    };
+      return this.browser;
+    });
 
     if (!popupURL) {
-      initBrowser(this.browser);
-      return this.browser;
+      return readyPromise;
     }
 
-    return promiseEvent(this.browser, "load").then(() => {
-      initBrowser(this.browser);
-
+    return readyPromise.then(() => {
       let mm = this.browser.messageManager;
 
       mm.loadFrameScript(
         "chrome://extensions/content/ext-browser-content.js", false);
 
       mm.sendAsyncMessage("Extension:InitBrowser", {
         allowScriptsToClose: true,
         fixedWidth: this.fixedWidth,
@@ -362,18 +375,18 @@ class PanelPopup extends BasePopup {
 
   destroy() {
     super.destroy();
     this.viewNode.remove();
   }
 
   closePopup() {
     promisePopupShown(this.viewNode).then(() => {
-      // Make sure we're not already destroyed.
-      if (this.viewNode) {
+      // Make sure we're not already destroyed, or removed from the DOM.
+      if (this.viewNode && this.viewNode.hidePopup) {
         this.viewNode.hidePopup();
       }
     });
   }
 }
 
 class ViewPopup extends BasePopup {
   constructor(extension, window, popupURL, browserStyle, fixedWidth) {
@@ -452,17 +465,17 @@ class ViewPopup extends BasePopup {
       let screenBottom = win.screen.availTop + win.screen.availHeight;
       this.extraHeight = {
         bottom: Math.max(0, screenBottom - popupBottom),
         top:  Math.max(0, popupTop - win.screen.availTop),
       };
 
       // Create a new browser in the real popup.
       let browser = this.browser;
-      this.createBrowser(this.viewNode);
+      yield this.createBrowser(this.viewNode);
 
       this.browser.swapDocShells(browser);
       this.destroyBrowser(browser);
 
       this.ignoreResizes = false;
       if (this.dimensions) {
         this.resizeBrowser(this.dimensions);
       }