Bug 1039500 - Created a field with a WeakMap to record the tab for each browser and made _getTabForBrowser non-private. r=dao
authorVikneshwar <lviknesh@gmail.com>
Sun, 05 Oct 2014 12:57:00 +0200
changeset 232154 047f52c44212642d3c3910936c14f08775ea8b8d
parent 232153 3d6d136be24ff0294d12692cebc862b8ab641683
child 232155 0e85dd2b1635f8ce164936e013ce8424fe3c1bdd
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao
bugs1039500
milestone35.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 1039500 - Created a field with a WeakMap to record the tab for each browser and made _getTabForBrowser non-private. r=dao
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2946,26 +2946,26 @@ const DOMLinkHandler = {
         break;
     }
   },
 
   setIcon: function(aBrowser, aURL) {
     if (gBrowser.isFailedIcon(aURL))
       return false;
 
-    let tab = gBrowser._getTabForBrowser(aBrowser);
+    let tab = gBrowser.getTabForBrowser(aBrowser);
     if (!tab)
       return false;
 
     gBrowser.setIcon(tab, aURL);
     return true;
   },
 
   addSearch: function(aBrowser, aEngine, aURL) {
-    let tab = gBrowser._getTabForBrowser(aBrowser);
+    let tab = gBrowser.getTabForBrowser(aBrowser);
     if (!tab)
       return false;
 
     BrowserSearch.addEngine(aBrowser, aEngine, makeURI(aURL));
   },
 }
 
 const BrowserSearch = {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -398,25 +398,41 @@
             if (this.browsers[i].contentWindowAsCPOW == aWindow)
               return this.tabs[i];
           }
           return null;
         ]]>
         </body>
       </method>
 
+      <!-- Binding from browser to tab -->
+      <field name="_tabForBrowser" readonly="true">
+      <![CDATA[
+        new WeakMap();
+      ]]>
+      </field>
+
       <method name="_getTabForBrowser">
+        <parameter name="aBrowser" />
+        <body>
+        <![CDATA[
+          let Deprecated = Components.utils.import("resource://gre/modules/Deprecated.jsm", {}).Deprecated;
+          let text = "_getTabForBrowser` is now deprecated, please use `getTabForBrowser";
+          let url = "https://developer.mozilla.org/docs/Mozilla/Tech/XUL/Method/getTabForBrowser";
+          Deprecated.warning(text, url);
+          return this.getTabForBrowser(aBrowser);
+        ]]>
+        </body>
+      </method>
+
+      <method name="getTabForBrowser">
         <parameter name="aBrowser"/>
         <body>
         <![CDATA[
-          for (let i = 0; i < this.tabs.length; i++) {
-            if (this.tabs[i].linkedBrowser == aBrowser)
-              return this.tabs[i];
-          }
-          return null;
+          return this._tabForBrowser.get(aBrowser);
         ]]>
         </body>
       </method>
 
       <method name="getNotificationBox">
         <parameter name="aBrowser"/>
         <body>
           <![CDATA[
@@ -455,17 +471,17 @@
             let promptBox = {
               appendPrompt : function(args, onCloseCallback) {
                 let newPrompt = document.createElementNS(XUL_NS, "tabmodalprompt");
                 stack.appendChild(newPrompt);
                 browser.setAttribute("tabmodalPromptShowing", true);
 
                 newPrompt.clientTop; // style flush to assure binding is attached
 
-                let tab = self._getTabForBrowser(browser);
+                let tab = self.getTabForBrowser(browser);
                 newPrompt.init(args, tab, onCloseCallback);
                 return newPrompt;
               },
 
               removePrompt : function(aPrompt) {
                 stack.removeChild(aPrompt);
 
                 let prompts = this.listPrompts();
@@ -1437,17 +1453,17 @@
           <![CDATA[
             let isRemote = aBrowser.getAttribute("remote") == "true";
             if (isRemote == aShouldBeRemote)
               return false;
 
             let wasActive = document.activeElement == aBrowser;
 
             // Unhook our progress listener.
-            let tab = this._getTabForBrowser(aBrowser);
+            let tab = this.getTabForBrowser(aBrowser);
             let index = tab._tPos;
             let filter = this.mTabFilters[index];
             aBrowser.webProgress.removeProgressListener(filter);
 
             // Change the "remote" attribute.
             let parent = aBrowser.parentNode;
             let permanentKey = aBrowser.permanentKey;
             parent.removeChild(aBrowser);
@@ -1604,16 +1620,17 @@
             notificationbox.setAttribute("flex", "1");
             notificationbox.appendChild(browserSidebarContainer);
 
             var position = this.tabs.length - 1;
             var uniqueId = this._generateUniquePanelID();
             notificationbox.id = uniqueId;
             t.linkedPanel = uniqueId;
             t.linkedBrowser = b;
+            this._tabForBrowser.set(b, t);
             t._tPos = position;
             this.tabContainer._setPositionalAttributes();
 
             // Prevent the superfluous initial load of a blank document
             // if we're going to load something other than about:blank.
             if (!uriIsAboutBlank) {
               b.setAttribute("nodefaultsrc", "true");
             }
@@ -2119,16 +2136,17 @@
 
             // This will unload the document. An unload handler could remove
             // dependant tabs, so it's important that the tabbrowser is now in
             // a consistent state (tab removed, tab positions updated, etc.).
             browser.parentNode.removeChild(browser);
 
             // Release the browser in case something is erroneously holding a
             // reference to the tab after its removal.
+            this._tabForBrowser.delete(aTab.linkedBrowser);
             aTab.linkedBrowser = null;
 
             // As the browser is removed, the removal of a dependent document can
             // cause the whole window to close. So at this point, it's possible
             // that the binding is destructed.
             if (this.mTabBox) {
               this.mPanelContainer.removeChild(panel);
             }
@@ -3023,31 +3041,31 @@
       <method name="receiveMessage">
         <parameter name="aMessage"/>
         <body><![CDATA[
           let json = aMessage.json;
           let browser = aMessage.target;
 
           switch (aMessage.name) {
             case "DOMTitleChanged": {
-              let tab = this._getTabForBrowser(browser);
+              let tab = this.getTabForBrowser(browser);
               if (!tab || tab.hasAttribute("pending"))
                 return;
               let titleChanged = this.setTabTitle(tab);
               if (titleChanged && !tab.selected && !tab.hasAttribute("busy"))
                 tab.setAttribute("titlechanged", "true");
               break;
             }
             case "DOMWindowClose": {
               if (this.tabs.length == 1) {
                 window.close();
                 return;
               }
 
-              let tab = this._getTabForBrowser(browser);
+              let tab = this.getTabForBrowser(browser);
               if (tab) {
                 this.removeTab(tab);
               }
               break;
             }
             case "contextmenu": {
               let spellInfo = aMessage.data.spellInfo;
               if (spellInfo)
@@ -3058,17 +3076,17 @@
                                           spellInfo: spellInfo };
               let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
               let event = gContextMenuContentData.event;
               let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY);
               popup.openPopupAtScreen(pos.x, pos.y, true);
               break;
             }
             case "DOMWebNotificationClicked": {
-              let tab = this._getTabForBrowser(browser);
+              let tab = this.getTabForBrowser(browser);
               if (!tab)
                 return;
               this.selectedTab = tab;
               window.focus();
               break;
             }
           }
         ]]></body>
@@ -3089,16 +3107,17 @@
           window.addEventListener("sizemodechange", this, false);
 
           var uniqueId = this._generateUniquePanelID();
           this.mPanelContainer.childNodes[0].id = uniqueId;
           this.mCurrentTab.linkedPanel = uniqueId;
           this.mCurrentTab._tPos = 0;
           this.mCurrentTab._fullyOpen = true;
           this.mCurrentTab.linkedBrowser = this.mCurrentBrowser;
+          this._tabForBrowser.set(this.mCurrentBrowser, this.mCurrentTab);
 
           // set up the shared autoscroll popup
           this._autoScrollPopup = this.mCurrentBrowser._createAutoScrollPopup();
           this._autoScrollPopup.id = "autoscroller";
           this.appendChild(this._autoScrollPopup);
           this.mCurrentBrowser.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
           this.mCurrentBrowser.droppedLinkHandler = handleDroppedLink;
           this.updateWindowResizers();
@@ -3377,17 +3396,17 @@
           // We're about to open a modal dialog, make sure the opening
           // tab is brought to the front.
           // If this is a same-process modal dialog, then we're given its DOM
           // window as the event's target. For remote dialogs, we're given the
           // browser, but that's in the originalTarget.
           // XXX Why originalTarget for the browser?
           this.selectedTab = (event.target instanceof Window) ?
                                this._getTabForContentWindow(event.target.top) :
-                               this._getTabForBrowser(event.originalTarget);
+                               this.getTabForBrowser(event.originalTarget);
         ]]>
       </handler>
       <handler event="DOMTitleChanged">
         <![CDATA[
           if (!event.isTrusted)
             return;
 
           var contentWin = event.target.defaultView;
@@ -3413,17 +3432,17 @@
           let uri = browser.currentURI;
           let icon = browser.mIconURL;
 
           this.updateBrowserRemotenessByURL(browser, "about:tabcrashed");
 
           browser.setAttribute("crashedPageTitle", title);
           browser.docShell.displayLoadError(Cr.NS_ERROR_CONTENT_CRASHED, uri, null);
           browser.removeAttribute("crashedPageTitle");
-          let tab = this._getTabForBrowser(browser);
+          let tab = this.getTabForBrowser(browser);
           this.setIcon(tab, icon);
         ]]>
       </handler>
     </handlers>
   </binding>
 
   <binding id="tabbrowser-tabbox"
            extends="chrome://global/content/bindings/tabbox.xml#tabbox">