Bug 1260548: Part 5 - Factor out <browser> data logic into shared modules. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 29 Jan 2017 00:03:00 -0800
changeset 467789 1ffa5569b4360e7c0a54050dc40f7a6a54c67375
parent 467788 70a182894898860ee08f60944d61834de08f4b46
child 467790 6b324b135a70b8cc53bab9ccd74d4acafe4714d4
push id43274
push usermaglione.k@gmail.com
push dateSun, 29 Jan 2017 20:10:11 +0000
reviewersaswan
bugs1260548
milestone54.0a1
Bug 1260548: Part 5 - Factor out <browser> data logic into shared modules. r?aswan MozReview-Commit-ID: GHPympWA7U
browser/components/extensions/.eslintrc.js
browser/components/extensions/ext-tabs.js
browser/components/extensions/ext-utils.js
toolkit/components/extensions/ExtensionParent.jsm
toolkit/components/extensions/ext-webNavigation.js
toolkit/components/extensions/ext-webRequest.js
--- a/browser/components/extensions/.eslintrc.js
+++ b/browser/components/extensions/.eslintrc.js
@@ -6,16 +6,15 @@ module.exports = {  // eslint-disable-li
   "globals": {
     "EventEmitter": true,
     "IconDetails": true,
     "Tab": true,
     "TabContext": true,
     "Window": true,
     "WindowEventManager": true,
     "browserActionFor": true,
-    "getBrowserInfo": true,
     "getCookieStoreIdForTab": true,
     "makeWidgetId": true,
     "pageActionFor": true,
     "tabTracker": true,
     "windowTracker": true,
   },
 };
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -28,32 +28,31 @@ function getSender(extension, target, se
   let tabId;
   if ("tabId" in sender) {
     // The message came from a privileged extension page running in a tab. In
     // that case, it should include a tabId property (which is filled in by the
     // page-open listener below).
     tabId = sender.tabId;
     delete sender.tabId;
   } else if (target instanceof Ci.nsIDOMXULElement) {
-    tabId = getBrowserInfo(target).tabId;
+    tabId = tabTracker.getBrowserData(target).tabId;
   }
 
   if (tabId) {
     let tab = extension.tabManager.get(tabId, null);
     if (tab) {
       sender.tab = tab.convert();
     }
   }
 }
 
 // Used by Extension.jsm
 global.tabGetSender = getSender;
 
 /* eslint-disable mozilla/balanced-listeners */
-
 extensions.on("page-shutdown", (type, context) => {
   if (context.viewType == "tab") {
     if (context.extension.id !== context.xulBrowser.contentPrincipal.addonId) {
       // Only close extension tabs.
       // This check prevents about:addons from closing when it contains a
       // WebExtension as an embedded inline options page.
       return;
     }
@@ -61,26 +60,16 @@ extensions.on("page-shutdown", (type, co
     if (gBrowser) {
       let tab = gBrowser.getTabForBrowser(context.xulBrowser);
       if (tab) {
         gBrowser.removeTab(tab);
       }
     }
   }
 });
-
-extensions.on("fill-browser-data", (type, browser, data) => {
-  let tabId, windowId;
-  if (browser) {
-    ({tabId, windowId} = getBrowserInfo(browser));
-  }
-
-  data.tabId = tabId || -1;
-  data.windowId = windowId || -1;
-});
 /* eslint-enable mozilla/balanced-listeners */
 
 let tabListener = {
   tabReadyInitialized: false,
   tabReadyPromises: new WeakMap(),
   initializingTabs: new WeakSet(),
 
   initTabReady() {
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -90,63 +90,16 @@ TabContext.prototype = {
   },
 
   shutdown() {
     windowTracker.removeListener("progress", this);
     windowTracker.removeListener("TabSelect", this);
   },
 };
 
-function getBrowserInfo(browser) {
-  if (!browser.ownerGlobal.gBrowser) {
-    // When we're loaded into a <browser> inside about:addons, we need to go up
-    // one more level.
-    browser = browser.ownerGlobal.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDocShell)
-                     .chromeEventHandler;
-
-    if (!browser) {
-      return {};
-    }
-  }
-
-  let result = {};
-
-  let window = browser.ownerGlobal;
-  if (window.gBrowser) {
-    let tab = window.gBrowser.getTabForBrowser(browser);
-    if (tab) {
-      result.tabId = tabTracker.getId(tab);
-    }
-
-    result.windowId = windowTracker.getId(window);
-  }
-
-  return result;
-}
-global.getBrowserInfo = getBrowserInfo;
-
-// Sends the tab and windowId upon request. This is primarily used to support
-// the synchronous `browser.extension.getViews` API.
-let onGetTabAndWindowId = {
-  receiveMessage({name, target, sync}) {
-    let result = getBrowserInfo(target);
-
-    if (result.tabId) {
-      if (sync) {
-        return result;
-      }
-      target.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", result);
-    }
-  },
-};
-/* eslint-disable mozilla/balanced-listeners */
-Services.mm.addMessageListener("Extension:GetTabAndWindowId", onGetTabAndWindowId);
-/* eslint-enable mozilla/balanced-listeners */
-
 
 class WindowTracker extends WindowTrackerBase {
   addProgressListener(window, listener) {
     window.gBrowser.addTabsProgressListener(listener);
   }
 
   removeProgressListener(window, listener) {
     window.gBrowser.removeTabsProgressListener(listener);
@@ -373,27 +326,43 @@ class TabTracker extends TabTrackerBase 
     // `tabs.onRemoved.addListener`, then the tab would be closed before the
     // event listener is registered. To make sure that the event listener is
     // notified, we dispatch `tabs.onRemoved` asynchronously.
     Services.tm.mainThread.dispatch(() => {
       this.emit("tab-removed", {tab, tabId, windowId, isWindowClosing});
     }, Ci.nsIThread.DISPATCH_NORMAL);
   }
 
-  getBrowserId(browser) {
+  getBrowserData(browser) {
+    if (!browser.ownerGlobal.location.href === "about:addons") {
+      // When we're loaded into a <browser> inside about:addons, we need to go up
+      // one more level.
+      browser = browser.ownerGlobal.QueryInterface(Ci.nsIInterfaceRequestor)
+                       .getInterface(Ci.nsIDocShell)
+                       .chromeEventHandler;
+    }
+
+    let result = {
+      tabId: -1,
+      windowId: -1,
+    };
+
     let {gBrowser} = browser.ownerGlobal;
     // Some non-browser windows have gBrowser but not
     // getTabForBrowser!
     if (gBrowser && gBrowser.getTabForBrowser) {
+      result.windowId = windowTracker.getId(browser.ownerGlobal);
+
       let tab = gBrowser.getTabForBrowser(browser);
       if (tab) {
-        return this.getId(tab);
+        result.tabId = this.getId(tab);
       }
     }
-    return -1;
+
+    return result;
   }
 
   get activeTab() {
     let window = windowTracker.topWindow;
     if (window && window.gBrowser) {
       return window.gBrowser.selectedTab;
     }
     return null;
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -97,20 +97,37 @@ let apiManager = new class extends Schem
       }
       return Promise.all(promises);
     });
 
     for (let [/* name */, value] of XPCOMUtils.enumerateCategoryEntries(CATEGORY_EXTENSION_SCRIPTS)) {
       this.loadScript(value);
     }
 
+    /* eslint-disable mozilla/balanced-listeners */
+    Services.mm.addMessageListener("Extension:GetTabAndWindowId", this);
+    /* eslint-enable mozilla/balanced-listeners */
+
     this.initialized = promise;
     return this.initialized;
   }
 
+  receiveMessage({name, target, sync}) {
+    if (name === "Extension:GetTabAndWindowId") {
+      let result = this.global.tabTracker.getBrowserData(target);
+
+      if (result.tabId) {
+        if (sync) {
+          return result;
+        }
+        target.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", result);
+      }
+    }
+  }
+
   registerSchemaAPI(namespace, envType, getAPI) {
     if (envType == "addon_parent" || envType == "content_parent" ||
         envType == "devtools_parent") {
       super.registerSchemaAPI(namespace, envType, getAPI);
     }
   }
 }();
 
@@ -365,23 +382,21 @@ class ExtensionPageContextParent extends
     let {windowTracker} = apiManager.global;
 
     if (currentWindow && windowTracker) {
       return windowTracker.getId(currentWindow);
     }
   }
 
   get tabId() {
-    let {getBrowserInfo} = apiManager.global;
-
-    if (getBrowserInfo) {
-      // This is currently only available on desktop Firefox.
-      return getBrowserInfo(this.xulBrowser).tabId;
+    let {tabTracker} = apiManager.global;
+    let data = tabTracker.getBrowserData(this.xulBrowser);
+    if (data.tabId >= 0) {
+      return data.tabId;
     }
-    return undefined;
   }
 
   onBrowserChange(browser) {
     super.onBrowserChange(browser);
     this.xulBrowser = browser;
   }
 
   shutdown() {
--- a/toolkit/components/extensions/ext-webNavigation.js
+++ b/toolkit/components/extensions/ext-webNavigation.js
@@ -115,17 +115,17 @@ function WebNavigationEventManager(conte
         parentFrameId: ExtensionManagement.getParentFrameId(data.parentWindowId, data.windowId),
       };
 
       if (eventName == "onErrorOccurred") {
         data2.error = data.error;
       }
 
       // Fills in tabId typically.
-      extensions.emit("fill-browser-data", data.browser, data2);
+      Object.assign(data2, tabTracker.getBrowserData(data.browser));
       if (data2.tabId < 0) {
         return;
       }
 
       fillTransitionProperties(eventName, data, data2);
 
       context.runSafe(callback, data2);
     };
--- a/toolkit/components/extensions/ext-webRequest.js
+++ b/toolkit/components/extensions/ext-webRequest.js
@@ -22,18 +22,21 @@ function WebRequestEventManager(context,
   let name = `webRequest.${eventName}`;
   let register = (callback, filter, info) => {
     let listener = data => {
       // Prevent listening in on requests originating from system principal to
       // prevent tinkering with OCSP, app and addon updates, etc.
       if (data.isSystemPrincipal) {
         return;
       }
-      let browserData = {};
-      extensions.emit("fill-browser-data", data.browser, browserData);
+
+      let browserData = {tabId: -1, windowId: -1};
+      if (data.browser) {
+        browserData = tabTracker.getBrowserData(data.browser);
+      }
       if (filter.tabId != null && browserData.tabId != filter.tabId) {
         return;
       }
       if (filter.windowId != null && browserData.windowId != filter.windowId) {
         return;
       }
 
       let data2 = {