Bug 1317101 - Part 4: Deduplicate the handling of context tab and window IDs, and handle <browser> nesting in tabs. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 12 Nov 2016 15:41:47 -0800
changeset 438070 9ed79e6ee300850f9dcd17e868194e9ed070df63
parent 438069 370f4aba873c81d22ad92374e9773a246d370a07
child 438071 95f17737b12c457a9aece9159a6cf1e4c2a98174
push id35614
push usermaglione.k@gmail.com
push dateSun, 13 Nov 2016 03:28:59 +0000
reviewersaswan
bugs1317101
milestone52.0a1
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);
+    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,17 +63,22 @@ extensions.on("page-shutdown", (type, co
       if (tab) {
         gBrowser.removeTab(tab);
       }
     }
   }
 });
 
 extensions.on("fill-browser-data", (type, browser, data) => {
-  data.tabId = browser ? TabManager.getBrowserId(browser) : -1;
+  let tabId = null;
+  if (browser) {
+    tabId = getBrowserInfo(browser).tabId;
+  }
+
+  data.tabId = tabId || -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,22 @@ 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) {
+      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() {