Bug 1317101 - Part 7e: Load extension options pages in a remote browser. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 12 Nov 2016 17:08:28 -0800
changeset 438077 5781a884fc0640acaf166632fb64fe244e900906
parent 438076 ca2f66ab4e0a446371cfb4c5276c11badaf55139
child 438078 3509bfa191c5520bafe8ce066bea872f46389a02
push id35614
push usermaglione.k@gmail.com
push dateSun, 13 Nov 2016 03:28:59 +0000
reviewersaswan
bugs1317101
milestone52.0a1
Bug 1317101 - Part 7e: Load extension options pages in a remote browser. r?aswan MozReview-Commit-ID: 963sD0DcwhT
toolkit/mozapps/extensions/content/extensions.js
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -8,21 +8,26 @@
 /* globals XMLStylesheetProcessingInstruction*/
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DownloadUtils.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/addons/AddonRepository.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils", "resource:///modules/E10SUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
+                                  "resource://gre/modules/ExtensionParent.jsm");
+
 const CONSTANTS = {};
 Cu.import("resource://gre/modules/addons/AddonConstants.jsm", CONSTANTS);
 const SIGNING_REQUIRED = CONSTANTS.REQUIRE_SIGNING ?
                          true :
                          Services.prefs.getBoolPref("xpinstall.signatures.required");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
@@ -151,16 +156,26 @@ class FakeFrameMessageManager {
     }
   }
 
   loadFrameScript(url) {
     Services.scriptloader.loadSubScript(url, Object.create(this.frame));
   }
 }
 
+function promiseEvent(event, target, useCapture = false) {
+  return new Promise(resolve => {
+    function listener(event) {
+      target.removeEventListener(event, listener, useCapture);
+      resolve(event);
+    }
+    target.addEventListener(event, listener, useCapture);
+  });
+}
+
 var gPendingInitializations = 1;
 Object.defineProperty(this, "gIsInitializing", {
   get: () => gPendingInitializations > 0
 });
 
 function initialize(event) {
   // XXXbz this listener gets _all_ load events for all nodes in the
   // document... but relies on not being called "too early".
@@ -3512,50 +3527,63 @@ var gDetailView = {
 
       let detailViewBoxObject = gDetailView.node.boxObject;
       top -= detailViewBoxObject.y;
 
       detailViewBoxObject.scrollTo(0, top);
     }
   },
 
-  createOptionsBrowser: function(parentNode) {
+  createOptionsBrowser: Task.async(function*(parentNode) {
     let browser = document.createElement("browser");
     browser.setAttribute("type", "content");
     browser.setAttribute("disableglobalhistory", "true");
     browser.setAttribute("class", "inline-options-browser");
 
-    return new Promise((resolve, reject) => {
+    let {optionsURL} = this._addon;
+    let remote = !E10SUtils.canLoadURIInProcess(optionsURL, Services.appinfo.PROCESS_TYPE_DEFAULT);
+
+    let readyPromise;
+    if (remote) {
+      browser.setAttribute("remote", "true");
+      readyPromise = promiseEvent("XULFrameLoaderCreated", browser);
+    } else {
+      readyPromise = promiseEvent("load", browser, true);
+    }
+
+    parentNode.appendChild(browser);
+
+    // Force bindings to apply synchronously.
+    browser.clientTop;
+
+    yield readyPromise;
+    if (remote) {
+      ExtensionParent.apiManager.emit("extension-browser-inserted", browser);
+    }
+
+    return new Promise(resolve => {
       let messageListener = {
         receiveMessage({name, data}) {
           if (name === "Extension:BrowserResized")
             browser.style.height = `${data.height}px`;
           else if (name === "Extension:BrowserContentLoaded")
             resolve(browser);
         },
       };
 
-      let onload = () => {
-        browser.removeEventListener("load", onload, true);
-
-        let mm = new FakeFrameMessageManager(browser);
-        mm.loadFrameScript("chrome://extensions/content/ext-browser-content.js",
-                           false);
-        mm.addMessageListener("Extension:BrowserContentLoaded", messageListener);
-        mm.addMessageListener("Extension:BrowserResized", messageListener);
-        mm.sendAsyncMessage("Extension:InitBrowser", {fixedWidth: true});
-
-        browser.setAttribute("src", this._addon.optionsURL);
-      };
-      browser.addEventListener("load", onload, true);
-      browser.addEventListener("error", reject);
-
-      parentNode.appendChild(browser);
+      let mm = browser.messageManager || new FakeFrameMessageManager(browser);
+      mm.loadFrameScript("chrome://extensions/content/ext-browser-content.js",
+                         false);
+      mm.addMessageListener("Extension:BrowserContentLoaded", messageListener);
+      mm.addMessageListener("Extension:BrowserResized", messageListener);
+      mm.sendAsyncMessage("Extension:InitBrowser", {fixedWidth: true});
+
+      browser.loadURI(optionsURL);
     });
-  },
+  }),
 
   getSelectedAddon: function() {
     return this._addon;
   },
 
   onEnabling: function() {
     this.updateState();
   },