Bug 1451058: Save temporary popup pre-load panel for remote popups. r?mixedpuppy draft
authorKris Maglione <maglione.k@gmail.com>
Tue, 03 Apr 2018 11:14:49 -0700
changeset 776794 221d4804b6ed022ee578c6002e8c7def408fa632
parent 776793 1f8e34bd956bd3e80e46c68e510c8159d0008e5a
push id104994
push usermaglione.k@gmail.com
push dateTue, 03 Apr 2018 18:21:08 +0000
reviewersmixedpuppy
bugs1451058
milestone61.0a1
Bug 1451058: Save temporary popup pre-load panel for remote popups. r?mixedpuppy Creating the temporary panel for a pre-load popup can be expensive, especially for OOP popups, where we need to create a compositor. Since we currently need to create a pre-load popup every time we hover over a browser action with a popup, it's probably worth saving and re-using them, rather than always creating a new one. MozReview-Commit-ID: GwG7qJNdk8f
browser/components/extensions/ExtensionPopups.jsm
--- a/browser/components/extensions/ExtensionPopups.jsm
+++ b/browser/components/extensions/ExtensionPopups.jsm
@@ -55,16 +55,18 @@ XPCOMUtils.defineLazyGetter(this, "stand
     stylesheets.push("chrome://browser/content/extension-mac-panel.css");
   }
   if (AppConstants.platform === "win") {
     stylesheets.push("chrome://browser/content/extension-win-panel.css");
   }
   return stylesheets;
 });
 
+const REMOTE_PANEL_ID = "webextension-remote-preload-panel";
+
 class BasePopup {
   constructor(extension, viewNode, popupURL, browserStyle, fixedWidth = false, blockParser = false) {
     this.extension = extension;
     this.popupURL = popupURL;
     this.viewNode = viewNode;
     this.browserStyle = browserStyle;
     this.window = viewNode.ownerGlobal;
     this.destroyed = false;
@@ -117,17 +119,17 @@ class BasePopup {
       }
 
       if (this.viewNode) {
         this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
         delete this.viewNode.customRectGetter;
       }
 
       let {panel} = this;
-      if (panel) {
+      if (panel && panel.id !== REMOTE_PANEL_ID) {
         panel.style.removeProperty("--arrowpanel-background");
         panel.removeAttribute("remote");
       }
 
       this.browser = null;
       this.stack = null;
       this.viewNode = null;
     });
@@ -409,33 +411,49 @@ class PanelPopup extends BasePopup {
     });
   }
 }
 
 class ViewPopup extends BasePopup {
   constructor(extension, window, popupURL, browserStyle, fixedWidth, blockParser) {
     let document = window.document;
 
+    let createPanel = remote => {
+      let panel = document.createElement("panel");
+      panel.setAttribute("type", "arrow");
+      if (remote) {
+        panel.setAttribute("remote", "true");
+      }
+
+      document.getElementById("mainPopupSet").appendChild(panel);
+      return panel;
+    };
+
     // Create a temporary panel to hold the browser while it pre-loads its
     // content. This panel will never be shown, but the browser's docShell will
     // be swapped with the browser in the real panel when it's ready.
-    let panel = document.createElement("panel");
-    panel.setAttribute("type", "arrow");
+    let panel;
     if (extension.remote) {
-      panel.setAttribute("remote", "true");
+      panel = document.getElementById(REMOTE_PANEL_ID);
+      if (!panel) {
+        panel = createPanel(true);
+        panel.id = REMOTE_PANEL_ID;
+      }
+    } else {
+      panel = createPanel();
     }
-    document.getElementById("mainPopupSet").appendChild(panel);
 
     super(extension, panel, popupURL, browserStyle, fixedWidth, blockParser);
 
     this.ignoreResizes = true;
 
     this.attached = false;
     this.shown = false;
     this.tempPanel = panel;
+    this.tempBrowser = this.browser;
 
     this.browser.classList.add("webextension-preload-browser");
   }
 
   /**
    * Attaches the pre-loaded browser to the given view node, and reserves a
    * promise which resolves when the browser is ready.
    *
@@ -518,18 +536,17 @@ class ViewPopup extends BasePopup {
       }
       this.resizeBrowser(this.dimensions);
     }
 
     this.viewNode.customRectGetter = () => {
       return {height: this.lastCalculatedInViewHeight || this.viewHeight};
     };
 
-    this.tempPanel.remove();
-    this.tempPanel = null;
+    this.removeTempPanel();
 
     this.shown = true;
 
     if (this.destroyed) {
       this.closePopup();
       this.destroy();
       return false;
     }
@@ -538,22 +555,32 @@ class ViewPopup extends BasePopup {
       bubbles: true,
       detail: {extension: this.extension},
     });
     this.browser.dispatchEvent(event);
 
     return true;
   }
 
+  removeTempPanel() {
+    if (this.tempPanel) {
+      if (this.tempPanel.id !== REMOTE_PANEL_ID) {
+        this.tempPanel.remove();
+      }
+      this.tempPanel = null;
+    }
+    if (this.tempBrowser) {
+      this.tempBrowser.parentNode.remove();
+      this.tempBrowser = null;
+    }
+  }
+
   destroy() {
     return super.destroy().then(() => {
-      if (this.tempPanel) {
-        this.tempPanel.remove();
-        this.tempPanel = null;
-      }
+      this.removeTempPanel();
     });
   }
 
   get DESTROY_EVENT() {
     return "ViewHiding";
   }
 
   closePopup() {