Bug 1039500 - Created a field with a WeakMap to record the tab for each browser and made _getTabForBrowser non-private. r=dao
--- 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">