Bug 1336308: Part 4 - Rename `tab` variables that refer to native tabs to avoid confusion. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Fri, 03 Feb 2017 12:57:43 -0800
changeset 470556 60723adac29fe79ef3c87f087bb88734dcd494ff
parent 470555 a334e32060e469fdfdd2fc42c88c0e45739e4956
child 470557 c7bcc0e90f6bc0b38881925e7dc6c912f20bde46
child 478926 39f19383656085081db6fa041e7489b822cfac79
push id44075
push usermaglione.k@gmail.com
push dateFri, 03 Feb 2017 23:30:42 +0000
reviewersaswan
bugs1336308
milestone54.0a1
Bug 1336308: Part 4 - Rename `tab` variables that refer to native tabs to avoid confusion. r?aswan MozReview-Commit-ID: 5An7K1crYRS
browser/components/extensions/ext-tabs.js
browser/components/extensions/ext-utils.js
mobile/android/components/extensions/ext-tabs.js
mobile/android/components/extensions/ext-utils.js
toolkit/components/extensions/ExtensionTabs.jsm
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -53,19 +53,19 @@ extensions.on("page-shutdown", (type, co
     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;
     }
     let {gBrowser} = context.xulBrowser.ownerGlobal;
     if (gBrowser) {
-      let tab = gBrowser.getTabForBrowser(context.xulBrowser);
-      if (tab) {
-        gBrowser.removeTab(tab);
+      let nativeTab = gBrowser.getTabForBrowser(context.xulBrowser);
+      if (nativeTab) {
+        gBrowser.removeTab(nativeTab);
       }
     }
   }
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 let tabListener = {
   tabReadyInitialized: false,
@@ -78,49 +78,50 @@ let tabListener = {
 
       this.tabReadyInitialized = true;
     }
   },
 
   onLocationChange(browser, webProgress, request, locationURI, flags) {
     if (webProgress.isTopLevel) {
       let {gBrowser} = browser.ownerGlobal;
-      let tab = gBrowser.getTabForBrowser(browser);
+      let nativeTab = gBrowser.getTabForBrowser(browser);
 
       // Now we are certain that the first page in the tab was loaded.
-      this.initializingTabs.delete(tab);
+      this.initializingTabs.delete(nativeTab);
 
       // browser.innerWindowID is now set, resolve the promises if any.
-      let deferred = this.tabReadyPromises.get(tab);
+      let deferred = this.tabReadyPromises.get(nativeTab);
       if (deferred) {
-        deferred.resolve(tab);
-        this.tabReadyPromises.delete(tab);
+        deferred.resolve(nativeTab);
+        this.tabReadyPromises.delete(nativeTab);
       }
     }
   },
 
   /**
    * Returns a promise that resolves when the tab is ready.
    * Tabs created via the `tabs.create` method are "ready" once the location
    * changes to the requested URL. Other tabs are assumed to be ready once their
    * inner window ID is known.
    *
-   * @param {XULElement} tab The <tab> element.
+   * @param {XULElement} nativeTab The <tab> element.
    * @returns {Promise} Resolves with the given tab once ready.
    */
-  awaitTabReady(tab) {
-    let deferred = this.tabReadyPromises.get(tab);
+  awaitTabReady(nativeTab) {
+    let deferred = this.tabReadyPromises.get(nativeTab);
     if (!deferred) {
       deferred = PromiseUtils.defer();
-      if (!this.initializingTabs.has(tab) && (tab.linkedBrowser.innerWindowID ||
-                                              tab.linkedBrowser.currentURI.spec === "about:blank")) {
-        deferred.resolve(tab);
+      if (!this.initializingTabs.has(nativeTab) &&
+          (nativeTab.linkedBrowser.innerWindowID ||
+           nativeTab.linkedBrowser.currentURI.spec === "about:blank")) {
+        deferred.resolve(nativeTab);
       } else {
         this.initTabReady();
-        this.tabReadyPromises.set(tab, deferred);
+        this.tabReadyPromises.set(nativeTab, deferred);
       }
     }
     return deferred.promise;
   },
 };
 
 extensions.registerSchemaAPI("tabs", "addon_parent", context => {
   let {extension} = context;
@@ -137,51 +138,51 @@ extensions.registerSchemaAPI("tabs", "ad
   async function promiseTabWhenReady(tabId) {
     let tab;
     if (tabId !== null) {
       tab = tabManager.get(tabId);
     } else {
       tab = tabManager.getWrapper(tabTracker.activeTab);
     }
 
-    await tabListener.awaitTabReady(tab.tab);
+    await tabListener.awaitTabReady(tab.nativeTab);
 
     return tab;
   }
 
   let self = {
     tabs: {
       onActivated: new WindowEventManager(context, "tabs.onActivated", "TabSelect", (fire, event) => {
-        let tab = event.originalTarget;
-        let tabId = tabTracker.getId(tab);
-        let windowId = windowTracker.getId(tab.ownerGlobal);
+        let nativeTab = event.originalTarget;
+        let tabId = tabTracker.getId(nativeTab);
+        let windowId = windowTracker.getId(nativeTab.ownerGlobal);
         fire.async({tabId, windowId});
       }).api(),
 
       onCreated: new SingletonEventManager(context, "tabs.onCreated", fire => {
         let listener = (eventName, event) => {
-          fire.async(tabManager.convert(event.tab));
+          fire.async(tabManager.convert(event.nativeTab));
         };
 
         tabTracker.on("tab-created", listener);
         return () => {
           tabTracker.off("tab-created", listener);
         };
       }).api(),
 
       /**
        * Since multiple tabs currently can't be highlighted, onHighlighted
        * essentially acts an alias for self.tabs.onActivated but returns
        * the tabId in an array to match the API.
        * @see  https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
       */
       onHighlighted: new WindowEventManager(context, "tabs.onHighlighted", "TabSelect", (fire, event) => {
-        let tab = event.originalTarget;
-        let tabIds = [tabTracker.getId(tab)];
-        let windowId = windowTracker.getId(tab.ownerGlobal);
+        let nativeTab = event.originalTarget;
+        let tabIds = [tabTracker.getId(nativeTab)];
+        let windowId = windowTracker.getId(nativeTab.ownerGlobal);
         fire.async({tabIds, windowId});
       }).api(),
 
       onAttached: new SingletonEventManager(context, "tabs.onAttached", fire => {
         let listener = (eventName, event) => {
           fire.async(event.tabId, {newWindowId: event.newWindowId, newPosition: event.newPosition});
         };
 
@@ -231,27 +232,27 @@ extensions.registerSchemaAPI("tabs", "ad
           // Remove the tab from the set on the next tick, since it will already
           // have been moved by then.
           Promise.resolve().then(() => {
             ignoreNextMove.delete(event.target);
           });
         };
 
         let moveListener = event => {
-          let tab = event.originalTarget;
+          let nativeTab = event.originalTarget;
 
-          if (ignoreNextMove.has(tab)) {
-            ignoreNextMove.delete(tab);
+          if (ignoreNextMove.has(nativeTab)) {
+            ignoreNextMove.delete(nativeTab);
             return;
           }
 
-          fire.async(tabTracker.getId(tab), {
-            windowId: windowTracker.getId(tab.ownerGlobal),
+          fire.async(tabTracker.getId(nativeTab), {
+            windowId: windowTracker.getId(nativeTab.ownerGlobal),
             fromIndex: event.detail,
-            toIndex: tab._tPos,
+            toIndex: nativeTab._tPos,
           });
         };
 
         windowTracker.addListener("TabMove", moveListener);
         windowTracker.addListener("TabOpen", openListener);
         return () => {
           windowTracker.removeListener("TabMove", moveListener);
           windowTracker.removeListener("TabOpen", openListener);
@@ -395,122 +396,120 @@ extensions.registerSchemaAPI("tabs", "ad
             }
           }
 
           // Make sure things like about:blank and data: URIs never inherit,
           // and instead always get a NullPrincipal.
           options.disallowInheritPrincipal = true;
 
           tabListener.initTabReady();
-          let tab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
+          let nativeTab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
 
           let active = true;
           if (createProperties.active !== null) {
             active = createProperties.active;
           }
           if (active) {
-            window.gBrowser.selectedTab = tab;
+            window.gBrowser.selectedTab = nativeTab;
           }
 
           if (createProperties.index !== null) {
-            window.gBrowser.moveTabTo(tab, createProperties.index);
+            window.gBrowser.moveTabTo(nativeTab, createProperties.index);
           }
 
           if (createProperties.pinned) {
-            window.gBrowser.pinTab(tab);
+            window.gBrowser.pinTab(nativeTab);
           }
 
           if (createProperties.url && createProperties.url !== window.BROWSER_NEW_TAB_URL) {
             // We can't wait for a location change event for about:newtab,
             // since it may be pre-rendered, in which case its initial
             // location change event has already fired.
 
             // Mark the tab as initializing, so that operations like
             // `executeScript` wait until the requested URL is loaded in
             // the tab before dispatching messages to the inner window
             // that contains the URL we're attempting to load.
-            tabListener.initializingTabs.add(tab);
+            tabListener.initializingTabs.add(nativeTab);
           }
 
-          return tabManager.convert(tab);
+          return tabManager.convert(nativeTab);
         });
       },
 
       async remove(tabs) {
         if (!Array.isArray(tabs)) {
           tabs = [tabs];
         }
 
         for (let tabId of tabs) {
-          let tab = tabTracker.getTab(tabId);
-          tab.ownerGlobal.gBrowser.removeTab(tab);
+          let nativeTab = tabTracker.getTab(tabId);
+          nativeTab.ownerGlobal.gBrowser.removeTab(nativeTab);
         }
       },
 
       async update(tabId, updateProperties) {
-        let tab = getTabOrActive(tabId);
+        let nativeTab = getTabOrActive(tabId);
 
-        let tabbrowser = tab.ownerGlobal.gBrowser;
+        let tabbrowser = nativeTab.ownerGlobal.gBrowser;
 
         if (updateProperties.url !== null) {
           let url = context.uri.resolve(updateProperties.url);
 
           if (!context.checkLoadURL(url, {dontReportErrors: true})) {
             return Promise.reject({message: `Illegal URL: ${url}`});
           }
 
-          tab.linkedBrowser.loadURI(url);
+          nativeTab.linkedBrowser.loadURI(url);
         }
 
         if (updateProperties.active !== null) {
           if (updateProperties.active) {
-            tabbrowser.selectedTab = tab;
+            tabbrowser.selectedTab = nativeTab;
           } else {
             // Not sure what to do here? Which tab should we select?
           }
         }
         if (updateProperties.muted !== null) {
-          if (tab.muted != updateProperties.muted) {
-            tab.toggleMuteAudio(extension.uuid);
+          if (nativeTab.muted != updateProperties.muted) {
+            nativeTab.toggleMuteAudio(extension.uuid);
           }
         }
         if (updateProperties.pinned !== null) {
           if (updateProperties.pinned) {
-            tabbrowser.pinTab(tab);
+            tabbrowser.pinTab(nativeTab);
           } else {
-            tabbrowser.unpinTab(tab);
+            tabbrowser.unpinTab(nativeTab);
           }
         }
         // FIXME: highlighted/selected, openerTabId
 
-        return tabManager.convert(tab);
+        return tabManager.convert(nativeTab);
       },
 
       async reload(tabId, reloadProperties) {
-        let tab = getTabOrActive(tabId);
+        let nativeTab = getTabOrActive(tabId);
 
         let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
         if (reloadProperties && reloadProperties.bypassCache) {
           flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
         }
-        tab.linkedBrowser.reloadWithFlags(flags);
+        nativeTab.linkedBrowser.reloadWithFlags(flags);
       },
 
       async get(tabId) {
-        let tab = tabTracker.getTab(tabId);
-
-        return tabManager.convert(tab);
+        return tabManager.get(tabId).convert();
       },
 
       getCurrent() {
-        let tab;
+        let tabData;
         if (context.tabId) {
-          tab = tabManager.get(context.tabId).convert();
+          tabData = tabManager.get(context.tabId).convert();
         }
-        return Promise.resolve(tab);
+        return Promise.resolve(tabData);
       },
 
       async query(queryInfo) {
         if (queryInfo.url !== null) {
           if (!extension.hasPermission("tabs")) {
             return Promise.reject({message: 'The "tabs" permission is required to use the query API with the "url" parameter'});
           }
 
@@ -523,17 +522,17 @@ extensions.registerSchemaAPI("tabs", "ad
       },
 
       async captureVisibleTab(windowId, options) {
         let window = windowId == null ?
           windowTracker.topWindow :
           windowTracker.getWindow(windowId, context);
 
         let tab = tabManager.wrapTab(window.gBrowser.selectedTab);
-        await tabListener.awaitTabReady(tab.tab);
+        await tabListener.awaitTabReady(tab.nativeTab);
 
         return tab.capture(context, options);
       },
 
       async detectLanguage(tabId) {
         let tab = await promiseTabWhenReady(tabId);
 
         return tab.sendMessage(context, "Extension:DetectLanguage");
@@ -578,131 +577,131 @@ extensions.registerSchemaAPI("tabs", "ad
             move([tabA, tabB], {index: 0})
               -> tabA to 0, tabB to 1 if tabA and tabB are in the same window
             move([tabA, tabB], {index: 0})
               -> tabA to 0, tabB to 0 if tabA and tabB are in different windows
         */
         let indexMap = new Map();
 
         let tabs = tabIds.map(tabId => tabTracker.getTab(tabId));
-        for (let tab of tabs) {
+        for (let nativeTab of tabs) {
           // If the window is not specified, use the window from the tab.
-          let window = destinationWindow || tab.ownerGlobal;
+          let window = destinationWindow || nativeTab.ownerGlobal;
           let gBrowser = window.gBrowser;
 
           let insertionPoint = indexMap.get(window) || index;
           // If the index is -1 it should go to the end of the tabs.
           if (insertionPoint == -1) {
             insertionPoint = gBrowser.tabs.length;
           }
 
           // We can only move pinned tabs to a point within, or just after,
           // the current set of pinned tabs. Unpinned tabs, likewise, can only
           // be moved to a position after the current set of pinned tabs.
           // Attempts to move a tab to an illegal position are ignored.
           let numPinned = gBrowser._numPinnedTabs;
-          let ok = tab.pinned ? insertionPoint <= numPinned : insertionPoint >= numPinned;
+          let ok = nativeTab.pinned ? insertionPoint <= numPinned : insertionPoint >= numPinned;
           if (!ok) {
             continue;
           }
 
           indexMap.set(window, insertionPoint + 1);
 
-          if (tab.ownerGlobal != window) {
+          if (nativeTab.ownerGlobal != window) {
             // If the window we are moving the tab in is different, then move the tab
             // to the new window.
-            tab = gBrowser.adoptTab(tab, insertionPoint, false);
+            nativeTab = gBrowser.adoptTab(nativeTab, insertionPoint, false);
           } else {
             // If the window we are moving is the same, just move the tab.
-            gBrowser.moveTabTo(tab, insertionPoint);
+            gBrowser.moveTabTo(nativeTab, insertionPoint);
           }
-          tabsMoved.push(tab);
+          tabsMoved.push(nativeTab);
         }
 
-        return tabsMoved.map(tab => tabManager.convert(tab));
+        return tabsMoved.map(nativeTab => tabManager.convert(nativeTab));
       },
 
       duplicate(tabId) {
-        let tab = tabTracker.getTab(tabId);
+        let nativeTab = tabTracker.getTab(tabId);
 
-        let gBrowser = tab.ownerGlobal.gBrowser;
-        let newTab = gBrowser.duplicateTab(tab);
+        let gBrowser = nativeTab.ownerGlobal.gBrowser;
+        let newTab = gBrowser.duplicateTab(nativeTab);
 
         return new Promise(resolve => {
           // We need to use SSTabRestoring because any attributes set before
           // are ignored. SSTabRestored is too late and results in a jump in
           // the UI. See http://bit.ly/session-store-api for more information.
           newTab.addEventListener("SSTabRestoring", function() {
             // As the tab is restoring, move it to the correct position.
 
             // Pinned tabs that are duplicated are inserted
             // after the existing pinned tab and pinned.
-            if (tab.pinned) {
+            if (nativeTab.pinned) {
               gBrowser.pinTab(newTab);
             }
-            gBrowser.moveTabTo(newTab, tab._tPos + 1);
+            gBrowser.moveTabTo(newTab, nativeTab._tPos + 1);
           }, {once: true});
 
           newTab.addEventListener("SSTabRestored", function() {
             // Once it has been restored, select it and return the promise.
             gBrowser.selectedTab = newTab;
 
             resolve(tabManager.convert(newTab));
           }, {once: true});
         });
       },
 
       getZoom(tabId) {
-        let tab = getTabOrActive(tabId);
+        let nativeTab = getTabOrActive(tabId);
 
-        let {ZoomManager} = tab.ownerGlobal;
-        let zoom = ZoomManager.getZoomForBrowser(tab.linkedBrowser);
+        let {ZoomManager} = nativeTab.ownerGlobal;
+        let zoom = ZoomManager.getZoomForBrowser(nativeTab.linkedBrowser);
 
         return Promise.resolve(zoom);
       },
 
       setZoom(tabId, zoom) {
-        let tab = getTabOrActive(tabId);
+        let nativeTab = getTabOrActive(tabId);
 
-        let {FullZoom, ZoomManager} = tab.ownerGlobal;
+        let {FullZoom, ZoomManager} = nativeTab.ownerGlobal;
 
         if (zoom === 0) {
           // A value of zero means use the default zoom factor.
-          return FullZoom.reset(tab.linkedBrowser);
+          return FullZoom.reset(nativeTab.linkedBrowser);
         } else if (zoom >= ZoomManager.MIN && zoom <= ZoomManager.MAX) {
-          FullZoom.setZoom(zoom, tab.linkedBrowser);
+          FullZoom.setZoom(zoom, nativeTab.linkedBrowser);
         } else {
           return Promise.reject({
             message: `Zoom value ${zoom} out of range (must be between ${ZoomManager.MIN} and ${ZoomManager.MAX})`,
           });
         }
 
         return Promise.resolve();
       },
 
       _getZoomSettings(tabId) {
-        let tab = getTabOrActive(tabId);
+        let nativeTab = getTabOrActive(tabId);
 
-        let {FullZoom} = tab.ownerGlobal;
+        let {FullZoom} = nativeTab.ownerGlobal;
 
         return {
           mode: "automatic",
           scope: FullZoom.siteSpecific ? "per-origin" : "per-tab",
           defaultZoomFactor: 1,
         };
       },
 
       getZoomSettings(tabId) {
         return Promise.resolve(this._getZoomSettings(tabId));
       },
 
       setZoomSettings(tabId, settings) {
-        let tab = getTabOrActive(tabId);
+        let nativeTab = getTabOrActive(tabId);
 
-        let currentSettings = this._getZoomSettings(tab.id);
+        let currentSettings = this._getZoomSettings(tabTracker.getId(nativeTab));
 
         if (!Object.keys(settings).every(key => settings[key] === currentSettings[key])) {
           return Promise.reject(`Unsupported zoom settings: ${JSON.stringify(settings)}`);
         }
         return Promise.resolve();
       },
 
       onZoomChange: new SingletonEventManager(context, "tabs.onZoomChange", fire => {
@@ -713,53 +712,53 @@ extensions.registerSchemaAPI("tabs", "ad
         };
 
         // Stores the last known zoom level for each tab's browser.
         // WeakMap[<browser> -> number]
         let zoomLevels = new WeakMap();
 
         // Store the zoom level for all existing tabs.
         for (let window of windowTracker.browserWindows()) {
-          for (let tab of window.gBrowser.tabs) {
-            let browser = tab.linkedBrowser;
+          for (let nativeTab of window.gBrowser.tabs) {
+            let browser = nativeTab.linkedBrowser;
             zoomLevels.set(browser, getZoomLevel(browser));
           }
         }
 
         let tabCreated = (eventName, event) => {
-          let browser = event.tab.linkedBrowser;
+          let browser = event.nativeTab.linkedBrowser;
           zoomLevels.set(browser, getZoomLevel(browser));
         };
 
 
         let zoomListener = event => {
           let browser = event.originalTarget;
 
           // For non-remote browsers, this event is dispatched on the document
           // rather than on the <browser>.
           if (browser instanceof Ci.nsIDOMDocument) {
             browser = browser.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIDocShell)
                              .chromeEventHandler;
           }
 
           let {gBrowser} = browser.ownerGlobal;
-          let tab = gBrowser.getTabForBrowser(browser);
-          if (!tab) {
+          let nativeTab = gBrowser.getTabForBrowser(browser);
+          if (!nativeTab) {
             // We only care about zoom events in the top-level browser of a tab.
             return;
           }
 
           let oldZoomFactor = zoomLevels.get(browser);
           let newZoomFactor = getZoomLevel(browser);
 
           if (oldZoomFactor != newZoomFactor) {
             zoomLevels.set(browser, newZoomFactor);
 
-            let tabId = tabTracker.getId(tab);
+            let tabId = tabTracker.getId(nativeTab);
             fire.async({
               tabId,
               oldZoomFactor,
               newZoomFactor,
               zoomSettings: self.tabs._getZoomSettings(tabId),
             });
           }
         };
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -44,33 +44,33 @@ global.TabContext = function TabContext(
 
   windowTracker.addListener("progress", this);
   windowTracker.addListener("TabSelect", this);
 
   EventEmitter.decorate(this);
 };
 
 TabContext.prototype = {
-  get(tab) {
-    if (!this.tabData.has(tab)) {
-      this.tabData.set(tab, this.getDefaults(tab));
+  get(nativeTab) {
+    if (!this.tabData.has(nativeTab)) {
+      this.tabData.set(nativeTab, this.getDefaults(nativeTab));
     }
 
-    return this.tabData.get(tab);
+    return this.tabData.get(nativeTab);
   },
 
-  clear(tab) {
-    this.tabData.delete(tab);
+  clear(nativeTab) {
+    this.tabData.delete(nativeTab);
   },
 
   handleEvent(event) {
     if (event.type == "TabSelect") {
-      let tab = event.target;
-      this.emit("tab-select", tab);
-      this.emit("location-change", tab);
+      let nativeTab = event.target;
+      this.emit("tab-select", nativeTab);
+      this.emit("location-change", nativeTab);
     }
   },
 
   onStateChange(browser, webProgress, request, stateFlags, statusCode) {
     let flags = Ci.nsIWebProgressListener;
 
     if (!(~stateFlags & (flags.STATE_IS_WINDOW | flags.STATE_START) ||
           this.lastLocation.has(browser))) {
@@ -78,18 +78,18 @@ TabContext.prototype = {
     }
   },
 
   onLocationChange(browser, webProgress, request, locationURI, flags) {
     let gBrowser = browser.ownerGlobal.gBrowser;
     let lastLocation = this.lastLocation.get(browser);
     if (browser === gBrowser.selectedBrowser &&
         !(lastLocation && lastLocation.equalsExceptRef(browser.currentURI))) {
-      let tab = gBrowser.getTabForBrowser(browser);
-      this.emit("location-change", tab, true);
+      let nativeTab = gBrowser.getTabForBrowser(browser);
+      this.emit("location-change", nativeTab, true);
     }
     this.lastLocation.set(browser, browser.currentURI);
   },
 
   shutdown() {
     windowTracker.removeListener("progress", this);
     windowTracker.removeListener("TabSelect", this);
   },
@@ -147,38 +147,38 @@ class TabTracker extends TabTrackerBase 
     windowTracker.addCloseListener(this._handleWindowClose);
 
     /* eslint-disable mozilla/balanced-listeners */
     this.on("tab-detached", this._handleTabDestroyed);
     this.on("tab-removed", this._handleTabDestroyed);
     /* eslint-enable mozilla/balanced-listeners */
   }
 
-  getId(tab) {
-    if (this._tabs.has(tab)) {
-      return this._tabs.get(tab);
+  getId(nativeTab) {
+    if (this._tabs.has(nativeTab)) {
+      return this._tabs.get(nativeTab);
     }
 
     this.init();
 
     let id = this._nextId++;
-    this.setId(tab, id);
+    this.setId(nativeTab, id);
     return id;
   }
 
-  setId(tab, id) {
-    this._tabs.set(tab, id);
-    this._tabIds.set(id, tab);
+  setId(nativeTab, id) {
+    this._tabs.set(nativeTab, id);
+    this._tabIds.set(id, nativeTab);
   }
 
-  _handleTabDestroyed(event, {tab}) {
-    let id = this._tabs.get(tab);
+  _handleTabDestroyed(event, {nativeTab}) {
+    let id = this._tabs.get(nativeTab);
     if (id) {
-      this._tabs.delete(tab);
-      if (this._tabIds.get(id) === tab) {
+      this._tabs.delete(nativeTab);
+      if (this._tabIds.get(id) === nativeTab) {
         this._tabIds.delete(id);
       }
     }
   }
 
   /**
    * Returns the XUL <tab> element associated with the given tab ID. If no tab
    * with the given ID exists, and no default value is provided, an error is
@@ -187,46 +187,46 @@ class TabTracker extends TabTrackerBase 
    * @param {integer} tabId
    *        The ID of the tab to retrieve.
    * @param {*} default_
    *        The value to return if no tab exists with the given ID.
    * @returns {Element<tab>}
    *        A XUL <tab> element.
    */
   getTab(tabId, default_ = undefined) {
-    let tab = this._tabIds.get(tabId);
-    if (tab) {
-      return tab;
+    let nativeTab = this._tabIds.get(tabId);
+    if (nativeTab) {
+      return nativeTab;
     }
     if (default_ !== undefined) {
       return default_;
     }
     throw new ExtensionError(`Invalid tab ID: ${tabId}`);
   }
 
   /**
    * @param {Event} event
    *        The DOM Event to handle.
    * @private
    */
   handleEvent(event) {
-    let tab = event.target;
+    let nativeTab = event.target;
 
     switch (event.type) {
       case "TabOpen":
         let {adoptedTab} = event.detail;
         if (adoptedTab) {
           this.adoptedTabs.set(adoptedTab, event.target);
 
           // This tab is being created to adopt a tab from a different window.
           // Copy the ID from the old tab to the new.
-          this.setId(tab, this.getId(adoptedTab));
+          this.setId(nativeTab, this.getId(adoptedTab));
 
           adoptedTab.linkedBrowser.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", {
-            windowId: windowTracker.getId(tab.ownerGlobal),
+            windowId: windowTracker.getId(nativeTab.ownerGlobal),
           });
         }
 
         // We need to delay sending this event until the next tick, since the
         // tab does not have its final index when the TabOpen event is dispatched.
         Promise.resolve().then(() => {
           if (event.detail.adoptedTab) {
             this.emitAttached(event.originalTarget);
@@ -238,21 +238,21 @@ class TabTracker extends TabTrackerBase 
 
       case "TabClose":
         let {adoptedBy} = event.detail;
         if (adoptedBy) {
           // This tab is being closed because it was adopted by a new window.
           // Copy its ID to the new tab, in case it was created as the first tab
           // of a new window, and did not have an `adoptedTab` detail when it was
           // opened.
-          this.setId(adoptedBy, this.getId(tab));
+          this.setId(adoptedBy, this.getId(nativeTab));
 
-          this.emitDetached(tab, adoptedBy);
+          this.emitDetached(nativeTab, adoptedBy);
         } else {
-          this.emitRemoved(tab, false);
+          this.emitRemoved(nativeTab, false);
         }
         break;
     }
   }
 
   /**
    * A private method which is called whenever a new browser window is opened,
    * and dispatches the necessary events for it.
@@ -267,127 +267,127 @@ class TabTracker extends TabTrackerBase 
       // window is about to adopt a tab from another window to replace its
       // initial tab.
       //
       // Note that this event handler depends on running before the
       // delayed startup code in browser.js, which is currently triggered
       // by the first MozAfterPaint event. That code handles finally
       // adopting the tab, and clears it from the arguments list in the
       // process, so if we run later than it, we're too late.
-      let tab = window.arguments[0];
+      let nativeTab = window.arguments[0];
       let adoptedBy = window.gBrowser.tabs[0];
 
-      this.adoptedTabs.set(tab, adoptedBy);
-      this.setId(adoptedBy, this.getId(tab));
+      this.adoptedTabs.set(nativeTab, adoptedBy);
+      this.setId(adoptedBy, this.getId(nativeTab));
 
       // We need to be sure to fire this event after the onDetached event
       // for the original tab.
       let listener = (event, details) => {
-        if (details.tab === tab) {
+        if (details.nativeTab === nativeTab) {
           this.off("tab-detached", listener);
 
           Promise.resolve().then(() => {
             this.emitAttached(details.adoptedBy);
           });
         }
       };
 
       this.on("tab-detached", listener);
     } else {
-      for (let tab of window.gBrowser.tabs) {
-        this.emitCreated(tab);
+      for (let nativeTab of window.gBrowser.tabs) {
+        this.emitCreated(nativeTab);
       }
     }
   }
 
   /**
    * A private method which is called whenever a browser window is closed,
    * and dispatches the necessary events for it.
    *
    * @param {DOMWindow} window
    *        The window being closed.
    * @private
    */
   _handleWindowClose(window) {
-    for (let tab of window.gBrowser.tabs) {
-      if (this.adoptedTabs.has(tab)) {
-        this.emitDetached(tab, this.adoptedTabs.get(tab));
+    for (let nativeTab of window.gBrowser.tabs) {
+      if (this.adoptedTabs.has(nativeTab)) {
+        this.emitDetached(nativeTab, this.adoptedTabs.get(nativeTab));
       } else {
-        this.emitRemoved(tab, true);
+        this.emitRemoved(nativeTab, true);
       }
     }
   }
 
   /**
    * Emits a "tab-attached" event for the given tab element.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The tab element in the window to which the tab is being attached.
    * @private
    */
-  emitAttached(tab) {
-    let newWindowId = windowTracker.getId(tab.ownerGlobal);
-    let tabId = this.getId(tab);
+  emitAttached(nativeTab) {
+    let newWindowId = windowTracker.getId(nativeTab.ownerGlobal);
+    let tabId = this.getId(nativeTab);
 
-    this.emit("tab-attached", {tab, tabId, newWindowId, newPosition: tab._tPos});
+    this.emit("tab-attached", {nativeTab, tabId, newWindowId, newPosition: nativeTab._tPos});
   }
 
   /**
    * Emits a "tab-detached" event for the given tab element.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The tab element in the window from which the tab is being detached.
    * @param {NativeTab} adoptedBy
    *        The tab element in the window to which detached tab is being moved,
    *        and will adopt this tab's contents.
    * @private
    */
-  emitDetached(tab, adoptedBy) {
-    let oldWindowId = windowTracker.getId(tab.ownerGlobal);
-    let tabId = this.getId(tab);
+  emitDetached(nativeTab, adoptedBy) {
+    let oldWindowId = windowTracker.getId(nativeTab.ownerGlobal);
+    let tabId = this.getId(nativeTab);
 
-    this.emit("tab-detached", {tab, adoptedBy, tabId, oldWindowId, oldPosition: tab._tPos});
+    this.emit("tab-detached", {nativeTab, adoptedBy, tabId, oldWindowId, oldPosition: nativeTab._tPos});
   }
 
   /**
    * Emits a "tab-created" event for the given tab element.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The tab element which is being created.
    * @private
    */
-  emitCreated(tab) {
-    this.emit("tab-created", {tab});
+  emitCreated(nativeTab) {
+    this.emit("tab-created", {nativeTab});
   }
 
   /**
    * Emits a "tab-removed" event for the given tab element.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The tab element which is being removed.
    * @param {boolean} isWindowClosing
    *        True if the tab is being removed because the browser window is
    *        closing.
    * @private
    */
-  emitRemoved(tab, isWindowClosing) {
-    let windowId = windowTracker.getId(tab.ownerGlobal);
-    let tabId = this.getId(tab);
+  emitRemoved(nativeTab, isWindowClosing) {
+    let windowId = windowTracker.getId(nativeTab.ownerGlobal);
+    let tabId = this.getId(nativeTab);
 
     // When addons run in-process, `window.close()` is synchronous. Most other
     // addon-invoked calls are asynchronous since they go through a proxy
     // context via the message manager. This includes event registrations such
     // as `tabs.onRemoved.addListener`.
     //
     // So, even if `window.close()` were to be called (in-process) after calling
     // `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});
+      this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
     }, Ci.nsIThread.DISPATCH_NORMAL);
   }
 
   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)
@@ -401,19 +401,19 @@ class TabTracker extends TabTrackerBase 
     };
 
     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) {
-        result.tabId = this.getId(tab);
+      let nativeTab = gBrowser.getTabForBrowser(browser);
+      if (nativeTab) {
+        result.tabId = this.getId(nativeTab);
       }
     }
 
     return result;
   }
 
   get activeTab() {
     let window = windowTracker.topWindow;
@@ -426,78 +426,78 @@ class TabTracker extends TabTrackerBase 
 
 windowTracker = new WindowTracker();
 tabTracker = new TabTracker();
 
 Object.assign(global, {tabTracker, windowTracker});
 
 class Tab extends TabBase {
   get _favIconUrl() {
-    return this.window.gBrowser.getIcon(this.tab);
+    return this.window.gBrowser.getIcon(this.nativeTab);
   }
 
   get audible() {
-    return this.tab.soundPlaying;
+    return this.nativeTab.soundPlaying;
   }
 
   get browser() {
-    return this.tab.linkedBrowser;
+    return this.nativeTab.linkedBrowser;
   }
 
   get cookieStoreId() {
-    return getCookieStoreIdForTab(this, this.tab);
+    return getCookieStoreIdForTab(this, this.nativeTab);
   }
 
   get height() {
     return this.browser.clientHeight;
   }
 
   get index() {
-    return this.tab._tPos;
+    return this.nativeTab._tPos;
   }
 
   get mutedInfo() {
-    let tab = this.tab;
+    let {nativeTab} = this;
 
-    let mutedInfo = {muted: tab.muted};
-    if (tab.muteReason === null) {
+    let mutedInfo = {muted: nativeTab.muted};
+    if (nativeTab.muteReason === null) {
       mutedInfo.reason = "user";
-    } else if (tab.muteReason) {
+    } else if (nativeTab.muteReason) {
       mutedInfo.reason = "extension";
-      mutedInfo.extensionId = tab.muteReason;
+      mutedInfo.extensionId = nativeTab.muteReason;
     }
 
     return mutedInfo;
   }
 
   get pinned() {
-    return this.tab.pinned;
+    return this.nativeTab.pinned;
   }
 
   get active() {
-    return this.tab.selected;
+    return this.nativeTab.selected;
   }
 
   get selected() {
-    return this.tab.selected;
+    return this.nativeTab.selected;
   }
 
   get status() {
-    if (this.tab.getAttribute("busy") === "true") {
+    if (this.nativeTab.getAttribute("busy") === "true") {
       return "loading";
     }
     return "complete";
   }
 
   get width() {
     return this.browser.clientWidth;
   }
 
   get window() {
-    return this.tab.ownerGlobal;
+    return this.nativeTab.ownerGlobal;
   }
 
   get windowId() {
     return windowTracker.getId(this.window);
   }
 
   /**
    * Converts session store data to an object compatible with the return value
@@ -660,18 +660,18 @@ class Window extends WindowBase {
       default:
         throw new Error(`Unexpected window state: ${state}`);
     }
   }
 
   * getTabs() {
     let {tabManager} = this.extension;
 
-    for (let tab of this.window.gBrowser.tabs) {
-      yield tabManager.getWrapper(tab);
+    for (let nativeTab of this.window.gBrowser.tabs) {
+      yield tabManager.getWrapper(nativeTab);
     }
   }
 
   /**
    * Converts session store data to an object compatible with the return value
    * of the convert() method, representing that data.
    *
    * @param {Extension} extension
@@ -690,47 +690,47 @@ class Window extends WindowBase {
       incognito: false,
       type: "normal", // this is always "normal" for a closed window
       // Surely this does not actually work?
       state: this.getState(windowData),
       alwaysOnTop: false,
     };
 
     if (windowData.tabs.length) {
-      result.tabs = windowData.tabs.map(tab => {
-        return Tab.convertFromSessionStoreClosedData(extension, tab);
+      result.tabs = windowData.tabs.map(tabData => {
+        return Tab.convertFromSessionStoreClosedData(extension, tabData);
       });
     }
 
     return result;
   }
 }
 
 Object.assign(global, {Tab, Window});
 
 class TabManager extends TabManagerBase {
   get(tabId, default_ = undefined) {
-    let tab = tabTracker.getTab(tabId, default_);
+    let nativeTab = tabTracker.getTab(tabId, default_);
 
-    if (tab) {
-      return this.getWrapper(tab);
+    if (nativeTab) {
+      return this.getWrapper(nativeTab);
     }
     return default_;
   }
 
-  addActiveTabPermission(tab = tabTracker.activeTab) {
-    return super.addActiveTabPermission(tab);
+  addActiveTabPermission(nativeTab = tabTracker.activeTab) {
+    return super.addActiveTabPermission(nativeTab);
   }
 
-  revokeActiveTabPermission(tab = tabTracker.activeTab) {
-    return super.revokeActiveTabPermission(tab);
+  revokeActiveTabPermission(nativeTab = tabTracker.activeTab) {
+    return super.revokeActiveTabPermission(nativeTab);
   }
 
-  wrapTab(tab) {
-    return new Tab(this.extension, tab, tabTracker.getId(tab));
+  wrapTab(nativeTab) {
+    return new Tab(this.extension, nativeTab, tabTracker.getId(nativeTab));
   }
 }
 
 class WindowManager extends WindowManagerBase {
   get(windowId, context) {
     let window = windowTracker.getWindow(windowId, context);
 
     return this.getWrapper(window);
--- a/mobile/android/components/extensions/ext-tabs.js
+++ b/mobile/android/components/extensions/ext-tabs.js
@@ -53,19 +53,19 @@ extensions.on("page-shutdown", (type, co
     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;
     }
     let {BrowserApp} = context.xulBrowser.ownerGlobal;
     if (BrowserApp) {
-      let tab = BrowserApp.getTabForBrowser(context.xulBrowser);
-      if (tab) {
-        BrowserApp.closeTab(tab);
+      let nativeTab = BrowserApp.getTabForBrowser(context.xulBrowser);
+      if (nativeTab) {
+        BrowserApp.closeTab(nativeTab);
       }
     }
   }
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 function getBrowserWindow(window) {
   return window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDocShell)
@@ -84,49 +84,50 @@ let tabListener = {
 
       this.tabReadyInitialized = true;
     }
   },
 
   onLocationChange(browser, webProgress, request, locationURI, flags) {
     if (webProgress.isTopLevel) {
       let {BrowserApp} = browser.ownerGlobal;
-      let tab = BrowserApp.getTabForBrowser(browser);
+      let nativeTab = BrowserApp.getTabForBrowser(browser);
 
       // Now we are certain that the first page in the tab was loaded.
-      this.initializingTabs.delete(tab);
+      this.initializingTabs.delete(nativeTab);
 
       // browser.innerWindowID is now set, resolve the promises if any.
-      let deferred = this.tabReadyPromises.get(tab);
+      let deferred = this.tabReadyPromises.get(nativeTab);
       if (deferred) {
-        deferred.resolve(tab);
-        this.tabReadyPromises.delete(tab);
+        deferred.resolve(nativeTab);
+        this.tabReadyPromises.delete(nativeTab);
       }
     }
   },
 
   /**
    * Returns a promise that resolves when the tab is ready.
    * Tabs created via the `tabs.create` method are "ready" once the location
    * changes to the requested URL. Other tabs are assumed to be ready once their
    * inner window ID is known.
    *
-   * @param {XULElement} tab The <tab> element.
+   * @param {NativeTab} nativeTab The native tab object.
    * @returns {Promise} Resolves with the given tab once ready.
    */
-  awaitTabReady(tab) {
-    let deferred = this.tabReadyPromises.get(tab);
+  awaitTabReady(nativeTab) {
+    let deferred = this.tabReadyPromises.get(nativeTab);
     if (!deferred) {
       deferred = PromiseUtils.defer();
-      if (!this.initializingTabs.has(tab) && (tab.browser.innerWindowID ||
-                                              tab.browser.currentURI.spec === "about:blank")) {
-        deferred.resolve(tab);
+      if (!this.initializingTabs.has(nativeTab) &&
+          (nativeTab.browser.innerWindowID ||
+           nativeTab.browser.currentURI.spec === "about:blank")) {
+        deferred.resolve(nativeTab);
       } else {
         this.initTabReady();
-        this.tabReadyPromises.set(tab, deferred);
+        this.tabReadyPromises.set(nativeTab, deferred);
       }
     }
     return deferred.promise;
   },
 };
 
 extensions.registerSchemaAPI("tabs", "addon_parent", context => {
   let {extension} = context;
@@ -143,32 +144,32 @@ extensions.registerSchemaAPI("tabs", "ad
   async function promiseTabWhenReady(tabId) {
     let tab;
     if (tabId !== null) {
       tab = tabManager.get(tabId);
     } else {
       tab = tabManager.getWrapper(tabTracker.activeTab);
     }
 
-    await tabListener.awaitTabReady(tab.tab);
+    await tabListener.awaitTabReady(tab.nativeTab);
 
     return tab;
   }
 
   let self = {
     tabs: {
       onActivated: new GlobalEventManager(context, "tabs.onActivated", "Tab:Selected", (fire, data) => {
         let tab = tabManager.get(data.id);
 
         fire.async({tabId: tab.id, windowId: tab.windowId});
       }).api(),
 
       onCreated: new SingletonEventManager(context, "tabs.onCreated", fire => {
         let listener = (eventName, event) => {
-          fire.async(tabManager.convert(event.tab));
+          fire.async(tabManager.convert(event.nativeTab));
         };
 
         tabTracker.on("tab-created", listener);
         return () => {
           tabTracker.off("tab-created", listener);
         };
       }).api(),
 
@@ -228,58 +229,58 @@ extensions.registerSchemaAPI("tabs", "ad
           let [needed, changeInfo] = sanitize(extension, changed);
           if (needed) {
             fire.async(tab.id, changeInfo, tab.convert());
           }
         };
 
         let listener = event => {
           let needed = [];
-          let tab;
+          let nativeTab;
           switch (event.type) {
             case "DOMTitleChanged": {
               let {BrowserApp} = getBrowserWindow(event.target.ownerGlobal);
 
-              tab = BrowserApp.getTabForWindow(event.target.ownerGlobal);
+              nativeTab = BrowserApp.getTabForWindow(event.target.ownerGlobal);
               needed.push("title");
               break;
             }
 
             case "DOMAudioPlaybackStarted":
             case "DOMAudioPlaybackStopped": {
               let {BrowserApp} = event.target.ownerGlobal;
-              tab = BrowserApp.getTabForBrowser(event.originalTarget);
+              nativeTab = BrowserApp.getTabForBrowser(event.originalTarget);
               needed.push("audible");
               break;
             }
           }
 
-          if (!tab) {
+          if (!nativeTab) {
             return;
           }
 
-          tab = tabManager.getWrapper(tab);
+          let tab = tabManager.getWrapper(nativeTab);
           let changeInfo = {};
           for (let prop of needed) {
             changeInfo[prop] = tab[prop];
           }
 
           fireForTab(tab, changeInfo);
         };
 
         let statusListener = ({browser, status, url}) => {
           let {BrowserApp} = browser.ownerGlobal;
-          let tab = BrowserApp.getTabForBrowser(browser);
-          if (tab) {
+          let nativeTab = BrowserApp.getTabForBrowser(browser);
+          if (nativeTab) {
             let changed = {status};
             if (url) {
               changed.url = url;
             }
 
-            fireForTab(tabManager.wrapTab(tab), changed);
+            fireForTab(tabManager.wrapTab(nativeTab), changed);
           }
         };
 
         windowTracker.addListener("status", statusListener);
         windowTracker.addListener("DOMTitleChanged", listener);
         return () => {
           windowTracker.removeListener("status", statusListener);
           windowTracker.removeListener("DOMTitleChanged", listener);
@@ -314,71 +315,71 @@ extensions.registerSchemaAPI("tabs", "ad
           options.tabIndex = createProperties.index;
         }
 
         // Make sure things like about:blank and data: URIs never inherit,
         // and instead always get a NullPrincipal.
         options.disallowInheritPrincipal = true;
 
         tabListener.initTabReady();
-        let tab = BrowserApp.addTab(url, options);
+        let nativeTab = BrowserApp.addTab(url, options);
 
         if (createProperties.url) {
-          tabListener.initializingTabs.add(tab);
+          tabListener.initializingTabs.add(nativeTab);
         }
 
-        return tabManager.convert(tab);
+        return tabManager.convert(nativeTab);
       },
 
       async remove(tabs) {
         if (!Array.isArray(tabs)) {
           tabs = [tabs];
         }
 
         for (let tabId of tabs) {
-          let tab = tabTracker.getTab(tabId);
-          tab.browser.ownerGlobal.BrowserApp.closeTab(tab);
+          let nativeTab = tabTracker.getTab(tabId);
+          nativeTab.browser.ownerGlobal.BrowserApp.closeTab(nativeTab);
         }
       },
 
       async update(tabId, updateProperties) {
-        let tab = getTabOrActive(tabId);
+        let nativeTab = getTabOrActive(tabId);
 
-        let {BrowserApp} = tab.browser.ownerGlobal;
+        let {BrowserApp} = nativeTab.browser.ownerGlobal;
 
         if (updateProperties.url !== null) {
           let url = context.uri.resolve(updateProperties.url);
 
           if (!context.checkLoadURL(url, {dontReportErrors: true})) {
             return Promise.reject({message: `Illegal URL: ${url}`});
           }
 
-          tab.browser.loadURI(url);
+          nativeTab.browser.loadURI(url);
         }
 
         if (updateProperties.active !== null) {
           if (updateProperties.active) {
-            BrowserApp.selectTab(tab);
+            BrowserApp.selectTab(nativeTab);
           } else {
             // Not sure what to do here? Which tab should we select?
           }
         }
         // FIXME: highlighted/selected, muted, pinned, openerTabId
 
-        return tabManager.convert(tab);
+        return tabManager.convert(nativeTab);
       },
 
       async reload(tabId, reloadProperties) {
-        let tab = getTabOrActive(tabId);
+        let nativeTab = getTabOrActive(tabId);
 
         let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
         if (reloadProperties && reloadProperties.bypassCache) {
           flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
         }
-        tab.browser.reloadWithFlags(flags);
+        nativeTab.browser.reloadWithFlags(flags);
       },
 
       async get(tabId) {
         return tabManager.get(tabId).convert();
       },
 
       async getCurrent() {
         if (context.tabId) {
@@ -401,17 +402,17 @@ extensions.registerSchemaAPI("tabs", "ad
       },
 
       async captureVisibleTab(windowId, options) {
         let window = windowId == null ?
           windowTracker.topWindow :
           windowTracker.getWindow(windowId, context);
 
         let tab = tabManager.wrapTab(window.BrowserApp.selectedTab);
-        await tabListener.awaitTabReady(tab.tab);
+        await tabListener.awaitTabReady(tab.nativeTab);
 
         return tab.capture(context, options);
       },
 
       async executeScript(tabId, details) {
         let tab = await promiseTabWhenReady(tabId);
 
         return tab.executeScript(context, details);
--- a/mobile/android/components/extensions/ext-utils.js
+++ b/mobile/android/components/extensions/ext-utils.js
@@ -61,28 +61,28 @@ class ProgressListenerWrapper {
   constructor(window, listener) {
     this.window = window;
     this.listener = listener;
     this.listeners = new WeakMap();
 
     this.flags = Ci.nsIWebProgress.NOTIFY_STATE_ALL |
                  Ci.nsIWebProgress.NOTIFY_LOCATION;
 
-    for (let tab of this.window.BrowserApp.tabs) {
-      this.addBrowserProgressListener(tab.browser);
+    for (let nativeTab of this.window.BrowserApp.tabs) {
+      this.addBrowserProgressListener(nativeTab.browser);
     }
 
     this.window.BrowserApp.deck.addEventListener("TabOpen", this);
   }
 
   destroy() {
     this.window.BrowserApp.deck.removeEventListener("TabOpen", this);
 
-    for (let tab of this.window.BrowserApp.tabs) {
-      this.removeProgressListener(tab.browser);
+    for (let nativeTab of this.window.BrowserApp.tabs) {
+      this.removeProgressListener(nativeTab.browser);
     }
   }
 
   addBrowserProgressListener(browser) {
     this.removeProgressListener(browser);
 
     let listener = new BrowserProgressListener(browser, this.listener, this.flags);
     this.listeners.set(browser, listener);
@@ -168,75 +168,75 @@ class TabTracker extends TabTrackerBase 
       return;
     }
     this.initialized = true;
 
     windowTracker.addListener("TabClose", this);
     windowTracker.addListener("TabOpen", this);
   }
 
-  getId(tab) {
-    return tab.id;
+  getId(nativeTab) {
+    return nativeTab.id;
   }
 
   getTab(id, default_ = undefined) {
     let win = windowTracker.topWindow;
     if (win) {
-      let tab = win.BrowserApp.getTabForId(id);
-      if (tab) {
-        return tab;
+      let nativeTab = win.BrowserApp.getTabForId(id);
+      if (nativeTab) {
+        return nativeTab;
       }
     }
     if (default_ !== undefined) {
       return default_;
     }
     throw new ExtensionError(`Invalid tab ID: ${id}`);
   }
 
   handleEvent(event) {
     const {BrowserApp} = event.target.ownerGlobal;
-    let tab = BrowserApp.getTabForBrowser(event.target);
+    let nativeTab = BrowserApp.getTabForBrowser(event.target);
 
     switch (event.type) {
       case "TabOpen":
-        this.emitCreated(tab);
+        this.emitCreated(nativeTab);
         break;
 
       case "TabClose":
-        this.emitRemoved(tab, false);
+        this.emitRemoved(nativeTab, false);
         break;
     }
   }
 
-  emitCreated(tab) {
-    this.emit("tab-created", {tab});
+  emitCreated(nativeTab) {
+    this.emit("tab-created", {nativeTab});
   }
 
-  emitRemoved(tab, isWindowClosing) {
-    let windowId = windowTracker.getId(tab.browser.ownerGlobal);
-    let tabId = this.getId(tab);
+  emitRemoved(nativeTab, isWindowClosing) {
+    let windowId = windowTracker.getId(nativeTab.browser.ownerGlobal);
+    let tabId = this.getId(nativeTab);
 
     Services.tm.mainThread.dispatch(() => {
-      this.emit("tab-removed", {tab, tabId, windowId, isWindowClosing});
+      this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
     }, Ci.nsIThread.DISPATCH_NORMAL);
   }
 
   getBrowserData(browser) {
     let result = {
       tabId: -1,
       windowId: -1,
     };
 
     let {BrowserApp} = browser.ownerGlobal;
     if (BrowserApp) {
       result.windowId = windowTracker.getId(browser.ownerGlobal);
 
-      let tab = BrowserApp.getTabForBrowser(browser);
-      if (tab) {
-        result.tabId = this.getId(tab);
+      let nativeTab = BrowserApp.getTabForBrowser(browser);
+      if (nativeTab) {
+        result.tabId = this.getId(nativeTab);
       }
     }
 
     return result;
   }
 
   get activeTab() {
     let window = windowTracker.topWindow;
@@ -253,53 +253,53 @@ tabTracker = new TabTracker();
 Object.assign(global, {tabTracker, windowTracker});
 
 class Tab extends TabBase {
   get _favIconUrl() {
     return undefined;
   }
 
   get audible() {
-    return this.tab.playingAudio;
+    return this.nativeTab.playingAudio;
   }
 
   get browser() {
-    return this.tab.browser;
+    return this.nativeTab.browser;
   }
 
   get cookieStoreId() {
-    return getCookieStoreIdForTab(this, this.tab);
+    return getCookieStoreIdForTab(this, this.nativeTab);
   }
 
   get height() {
     return this.browser.clientHeight;
   }
 
   get incognito() {
     return PrivateBrowsingUtils.isBrowserPrivate(this.browser);
   }
 
   get index() {
-    return this.window.BrowserApp.tabs.indexOf(this.tab);
+    return this.window.BrowserApp.tabs.indexOf(this.nativeTab);
   }
 
   get mutedInfo() {
     return {muted: false};
   }
 
   get pinned() {
     return false;
   }
 
   get active() {
-    return this.tab.getActive();
+    return this.nativeTab.getActive();
   }
 
   get selected() {
-    return this.tab.getActive();
+    return this.nativeTab.getActive();
   }
 
   get status() {
     if (this.browser.webProgress.isLoadingDocument) {
       return "loading";
     }
     return "complete";
   }
@@ -352,44 +352,44 @@ class Window extends WindowBase {
 
   get state() {
     return "fullscreen";
   }
 
   * getTabs() {
     let {tabManager} = this.extension;
 
-    for (let tab of this.window.BrowserApp.tabs) {
-      yield tabManager.getWrapper(tab);
+    for (let nativeTab of this.window.BrowserApp.tabs) {
+      yield tabManager.getWrapper(nativeTab);
     }
   }
 }
 
 Object.assign(global, {Tab, Window});
 
 class TabManager extends TabManagerBase {
   get(tabId, default_ = undefined) {
-    let tab = tabTracker.getTab(tabId, default_);
+    let nativeTab = tabTracker.getTab(tabId, default_);
 
-    if (tab) {
-      return this.getWrapper(tab);
+    if (nativeTab) {
+      return this.getWrapper(nativeTab);
     }
     return default_;
   }
 
-  addActiveTabPermission(tab = tabTracker.activeTab) {
-    return super.addActiveTabPermission(tab);
+  addActiveTabPermission(nativeTab = tabTracker.activeTab) {
+    return super.addActiveTabPermission(nativeTab);
   }
 
-  revokeActiveTabPermission(tab = tabTracker.activeTab) {
-    return super.revokeActiveTabPermission(tab);
+  revokeActiveTabPermission(nativeTab = tabTracker.activeTab) {
+    return super.revokeActiveTabPermission(nativeTab);
   }
 
-  wrapTab(tab) {
-    return new Tab(this.extension, tab, tab.id);
+  wrapTab(nativeTab) {
+    return new Tab(this.extension, nativeTab, nativeTab.id);
   }
 }
 
 class WindowManager extends WindowManagerBase {
   get(windowId, context) {
     let window = windowTracker.getWindow(windowId, context);
 
     return this.getWrapper(window);
--- a/toolkit/components/extensions/ExtensionTabs.jsm
+++ b/toolkit/components/extensions/ExtensionTabs.jsm
@@ -49,29 +49,29 @@ const {
 /**
  * A platform-independent base class for extension-specific wrappers around
  * native tab objects.
  *
  * @param {Extension} extension
  *        The extension object for which this wrapper is being created. Used to
  *        determine permissions for access to certain properties and
  *        functionality.
- * @param {NativeTab} tab
+ * @param {NativeTab} nativeTab
  *        The native tab object which is being wrapped. The type of this object
  *        varies by platform.
  * @param {integer} id
  *        The numeric ID of this tab object. This ID should be the same for
  *        every extension, and for the lifetime of the tab.
  */
 class TabBase {
-  constructor(extension, tab, id) {
+  constructor(extension, nativeTab, id) {
     this.extension = extension;
     this.tabManager = extension.tabManager;
     this.id = id;
-    this.tab = tab;
+    this.nativeTab = nativeTab;
     this.activeTabWindowID = null;
   }
 
   /**
    * Sends a message, via the given context, to the ExtensionContent running in
    * this tab. The tab's current innerWindowID is automatically added to the
    * recipient filter for the message, and is used to ensure that the message is
    * not processed if the content process navigates to a different content page
@@ -219,17 +219,17 @@ class TabBase {
 
   /**
    * @property {string} _title
    *        Returns the current title of this tab. Does not do any permission
    *        checks.
    *        @readonly
    */
   get _title() {
-    return this.browser.contentTitle || this.tab.label;
+    return this.browser.contentTitle || this.nativeTab.label;
   }
 
 
   /**
    * @property {nsIURI | null} title
    *        Returns the current title of this tab if the extension has permission
    *        to read it, or null otherwise.
    *        @readonly
@@ -1015,24 +1015,24 @@ class TabTrackerBase extends EventEmitte
   }
 
   // The JSDoc validator does not support @returns tags in abstract functions or
   // star functions without return statements.
   /* eslint-disable valid-jsdoc */
   /**
    * Returns the numeric ID for the given native tab.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The native tab for which to return an ID.
    *
    * @returns {integer}
    *        The tab's numeric ID.
    * @abstract
    */
-  getId(tab) {
+  getId(nativeTab) {
     throw new Error("Not implemented");
   }
 
   /**
    * Returns the native tab with the given numeric ID.
    *
    * @param {integer} tabId
    *        The numeric ID of the tab to return.
@@ -1551,95 +1551,95 @@ class TabManagerBase {
 
     this._tabs = new DefaultWeakMap(tab => this.wrapTab(tab));
   }
 
   /**
    * If the extension has requested activeTab permission, grant it those
    * permissions for the current inner window in the given native tab.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The native tab for which to grant permissions.
    */
-  addActiveTabPermission(tab) {
+  addActiveTabPermission(nativeTab) {
     if (this.extension.hasPermission("activeTab")) {
       // Note that, unlike Chrome, we don't currently clear this permission with
       // the tab navigates. If the inner window is revived from BFCache before
       // we've granted this permission to a new inner window, the extension
       // maintains its permissions for it.
-      tab = this.getWrapper(tab);
+      let tab = this.getWrapper(nativeTab);
       tab.activeTabWindowID = tab.innerWindowID;
     }
   }
 
   /**
    * Revoke the extension's activeTab permissions for the current inner window
    * of the given native tab.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The native tab for which to revoke permissions.
    */
-  revokeActiveTabPermission(tab) {
-    this.getWrapper(tab).activeTabWindowID = null;
+  revokeActiveTabPermission(nativeTab) {
+    this.getWrapper(nativeTab).activeTabWindowID = null;
   }
 
   /**
    * Returns true if the extension has requested activeTab permission, and has
    * been granted permissions for the current inner window if this tab.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The native tab for which to check permissions.
    * @returns {boolean}
    *        True if the extension has activeTab permissions for this tab.
    */
-  hasActiveTabPermission(tab) {
-    return this.getWrapper(tab).hasActiveTabPermission;
+  hasActiveTabPermission(nativeTab) {
+    return this.getWrapper(nativeTab).hasActiveTabPermission;
   }
 
   /**
    * Returns true if the extension has permissions to access restricted
    * properties of the given native tab. In practice, this means that it has
    * either requested the "tabs" permission or has activeTab permissions for the
    * given tab.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The native tab for which to check permissions.
    * @returns {boolean}
    *        True if the extension has permissions for this tab.
    */
-  hasTabPermission(tab) {
-    return this.getWrapper(tab).hasTabPermission;
+  hasTabPermission(nativeTab) {
+    return this.getWrapper(nativeTab).hasTabPermission;
   }
 
   /**
    * Returns this extension's TabBase wrapper for the given native tab. This
    * method will always return the same wrapper object for any given native tab.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The tab for which to return a wrapper.
    *
    * @returns {TabBase}
    *        The wrapper for this tab.
    */
-  getWrapper(tab) {
-    return this._tabs.get(tab);
+  getWrapper(nativeTab) {
+    return this._tabs.get(nativeTab);
   }
 
   /**
    * Converts the given native tab to a JSON-compatible object, in the format
    * requried to be returned by WebExtension APIs, which may be safely passed to
    * extension code.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The native tab to convert.
    *
    * @returns {Object}
    */
-  convert(tab) {
-    return this.getWrapper(tab).convert();
+  convert(nativeTab) {
+    return this.getWrapper(nativeTab).convert();
   }
 
   // The JSDoc validator does not support @returns tags in abstract functions or
   // star functions without return statements.
   /* eslint-disable valid-jsdoc */
   /**
    * Returns an iterator of TabBase objects which match the given query info.
    *
@@ -1676,25 +1676,25 @@ class TabManagerBase {
    */
   get(tabId) {
     throw new Error("Not implemented");
   }
 
   /**
    * Returns a new TabBase instance wrapping the given native tab.
    *
-   * @param {NativeTab} tab
+   * @param {NativeTab} nativeTab
    *        The native tab for which to return a wrapper.
    *
    * @returns {TabBase}
    * @protected
    * @abstract
    */
   /* eslint-enable valid-jsdoc */
-  wrapTab(tab) {
+  wrapTab(nativeTab) {
     throw new Error("Not implemented");
   }
 }
 
 /**
  * Manages native browser windows and their wrappers for a particular extension.
  *
  * @param {Extension} extension