Bug 1317101 - Part 4: Deduplicate the handling of context tab and window IDs, and handle <browser> nesting in tabs. r=aswan
☠☠ backed out by ed48815cbe18 ☠ ☠
authorKris Maglione <maglione.k@gmail.com>
Tue, 15 Nov 2016 15:13:50 -0800
changeset 322827 b0521588011d866ee6b2019ee71654768b9e7677
parent 322826 07321664430ab3416a0aa3a29055012b5eb149c5
child 322828 225ad2535585ff6ce38e1e9f8fe5371194a70658
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 4: Deduplicate the handling of context tab and window IDs, and handle <browser> nesting in tabs. r=aswan This could still use a fair amount of additional cleanup. MozReview-Commit-ID: BteBFMlZCsy
browser/components/extensions/.eslintrc.js
browser/components/extensions/ext-tabs.js
browser/components/extensions/ext-utils.js
toolkit/components/extensions/ExtensionParent.jsm
--- a/browser/components/extensions/.eslintrc.js
+++ b/browser/components/extensions/.eslintrc.js
@@ -3,16 +3,17 @@
 module.exports = {  // eslint-disable-line no-undef
   "extends": "../../../toolkit/components/extensions/.eslintrc.js",
 
   "globals": {
     "AllWindowEvents": true,
     "browserActionFor": true,
     "currentWindow": true,
     "EventEmitter": true,
+    "getBrowserInfo": true,
     "getCookieStoreIdForTab": true,
     "IconDetails": true,
     "makeWidgetId": true,
     "pageActionFor": true,
     "PanelPopup": true,
     "TabContext": true,
     "ViewPopup": true,
     "WindowEventManager": true,
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -20,39 +20,31 @@ Cu.import("resource://gre/modules/Extens
 var {
   EventManager,
   ignoreEvent,
 } = ExtensionUtils;
 
 // This function is pretty tightly tied to Extension.jsm.
 // Its job is to fill in the |tab| property of the sender.
 function getSender(extension, target, sender) {
+  let tabId;
   if ("tabId" in sender) {
-    // The message came from an ExtensionContext. In that case, it should
-    // include a tabId property (which is filled in by the page-open
-    // listener below).
-    let tab = TabManager.getTab(sender.tabId, null, null);
+    // 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;
+  }
+
+  if (tabId) {
+    let tab = TabManager.getTab(tabId, null, null);
     if (tab) {
       sender.tab = TabManager.convert(extension, tab);
-      return;
-    }
-  }
-  if (target instanceof Ci.nsIDOMXULElement) {
-    // If the message was sent from a content script to a <browser> element,
-    // then we can just get the `tab` from `target`.
-    let tabbrowser = target.ownerGlobal.gBrowser;
-    if (tabbrowser) {
-      let tab = tabbrowser.getTabForBrowser(target);
-
-      // `tab` can be `undefined`, e.g. for extension popups. This condition is
-      // reached if `getSender` is called for a popup without a valid `tabId`.
-      if (tab) {
-        sender.tab = TabManager.convert(extension, tab);
-      }
     }
   }
 }
 
 // Used by Extension.jsm
 global.tabGetSender = getSender;
 
 /* eslint-disable mozilla/balanced-listeners */
@@ -71,20 +63,23 @@ extensions.on("page-shutdown", (type, co
       if (tab) {
         gBrowser.removeTab(tab);
       }
     }
   }
 });
 
 extensions.on("fill-browser-data", (type, browser, data) => {
-  let gBrowser = browser && browser.ownerGlobal.gBrowser;
-  let tab = gBrowser && gBrowser.getTabForBrowser(browser);
-  data.tabId = tab ? TabManager.getId(tab) : -1;
-  data.windowId = tab ? WindowManager.getId(tab.ownerGlobal) : -1;
+  let tabId, windowId;
+  if (browser) {
+    ({tabId, windowId} = getBrowserInfo(browser));
+  }
+
+  data.tabId = tabId || -1;
+  data.windowId = windowId || -1;
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 global.currentWindow = function(context) {
   let {xulWindow} = context;
   if (xulWindow && context.viewType != "background") {
     return xulWindow;
   }
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -684,31 +684,56 @@ ExtensionTabManager.prototype = {
 
   getTabs(window) {
     return Array.from(window.gBrowser.tabs)
                 .filter(tab => !tab.closing)
                 .map(tab => this.convert(tab));
   },
 };
 
+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 = TabManager.getId(tab);
+    }
+
+    result.windowId = WindowManager.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 {gBrowser} = target.ownerGlobal;
-    let tab = gBrowser && gBrowser.getTabForBrowser(target);
-    if (tab) {
-      let reply = {
-        tabId: TabManager.getId(tab),
-        windowId: WindowManager.getId(tab.ownerGlobal),
-      };
+    let result = getBrowserInfo(target);
+
+    if (result.tabId) {
       if (sync) {
-        return reply;
+        return result;
       }
-      target.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", reply);
+      target.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", result);
     }
   },
 };
 /* eslint-disable mozilla/balanced-listeners */
 Services.mm.addMessageListener("Extension:GetTabAndWindowId", onGetTabAndWindowId);
 /* eslint-enable mozilla/balanced-listeners */
 
 
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -332,22 +332,23 @@ class ExtensionPageContextParent extends
     if (!apiManager.global.WindowManager || this.viewType == "background") {
       return;
     }
     // viewType popup or tab:
     return apiManager.global.WindowManager.getId(this.xulWindow);
   }
 
   get tabId() {
-    if (!apiManager.global.TabManager) {
-      return;  // Not yet supported on Android.
+    let {getBrowserInfo} = apiManager.global;
+
+    if (getBrowserInfo) {
+      // This is currently only available on desktop Firefox.
+      return getBrowserInfo(this.xulBrowser).tabId;
     }
-    let {gBrowser} = this.xulBrowser.ownerGlobal;
-    let tab = gBrowser && gBrowser.getTabForBrowser(this.xulBrowser);
-    return tab && apiManager.global.TabManager.getId(tab);
+    return undefined;
   }
 
   onBrowserChange(browser) {
     super.onBrowserChange(browser);
     this.xulBrowser = browser;
   }
 
   shutdown() {