Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port openerTabId #3

Merged
merged 4 commits into from
Feb 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions browser/base/content/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -5180,8 +5180,8 @@ nsBrowserAccess.prototype = {
_openURIInNewTab(aURI, aReferrer, aReferrerPolicy, aIsPrivate,
aIsExternal, aForceNotRemote = false,
aUserContextId = Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID,
aOpener = null, aTriggeringPrincipal = null,
aNextTabParentId = 0, aName = "") {
aOpenerWindow = null, aOpenerBrowser = null,
aTriggeringPrincipal = null, aNextTabParentId = 0, aName = "") {
let win, needToFocusWin;

// try the current window. if we're in a popup, fall back on the most recent browser window
Expand Down Expand Up @@ -5213,7 +5213,8 @@ nsBrowserAccess.prototype = {
fromExternal: aIsExternal,
inBackground: loadInBackground,
forceNotRemote: aForceNotRemote,
opener: aOpener,
opener: aOpenerWindow,
openerBrowser: aOpenerBrowser,
nextTabParentId: aNextTabParentId,
name: aName,
});
Expand Down Expand Up @@ -5293,7 +5294,7 @@ nsBrowserAccess.prototype = {
let browser = this._openURIInNewTab(aURI, referrer, referrerPolicy,
isPrivate, isExternal,
forceNotRemote, userContextId,
openerWindow, aTriggeringPrincipal);
openerWindow, null, aTriggeringPrincipal);
if (browser)
newWindow = browser.contentWindow;
break;
Expand Down Expand Up @@ -5335,7 +5336,7 @@ nsBrowserAccess.prototype = {
aParams.referrerPolicy,
aParams.isPrivate,
isExternal, false,
userContextId, null,
userContextId, null, aParams.openerBrowser,
aParams.triggeringPrincipal,
aNextTabParentId, aName);
if (browser)
Expand Down
89 changes: 62 additions & 27 deletions browser/base/content/tabbrowser.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
<field name="mCurrentTab">
null
</field>
<field name="_lastRelatedTab">
null
<field name="_lastRelatedTabMap">
new WeakMap();
</field>
<field name="mCurrentBrowser">
null
Expand Down Expand Up @@ -1133,11 +1133,12 @@
if (!this._previewMode && !oldTab.selected)
oldTab.owner = null;

if (this._lastRelatedTab) {
if (!this._lastRelatedTab.selected)
this._lastRelatedTab.owner = null;
this._lastRelatedTab = null;
let lastRelatedTab = this._lastRelatedTabMap.get(oldTab);
if (lastRelatedTab) {
if (!lastRelatedTab.selected)
lastRelatedTab.owner = null;
}
this._lastRelatedTabMap = new WeakMap();

var oldBrowser = this.mCurrentBrowser;

Expand Down Expand Up @@ -1623,6 +1624,7 @@
var aSameProcessAsFrameLoader;
var aOriginPrincipal;
var aOpener;
var aOpenerBrowser;
var aIsPrerendered;
var aCreateLazyBrowser;
var aNextTabParentId;
Expand Down Expand Up @@ -1650,6 +1652,7 @@
aSameProcessAsFrameLoader = params.sameProcessAsFrameLoader;
aOriginPrincipal = params.originPrincipal;
aOpener = params.opener;
aOpenerBrowser = params.openerBrowser;
aIsPrerendered = params.isPrerendered;
aCreateLazyBrowser = params.createLazyBrowser;
aNextTabParentId = params.nextTabParentId;
Expand Down Expand Up @@ -1681,6 +1684,7 @@
originPrincipal: aOriginPrincipal,
sameProcessAsFrameLoader: aSameProcessAsFrameLoader,
opener: aOpener,
openerBrowser: aOpenerBrowser,
isPrerendered: aIsPrerendered,
nextTabParentId: aNextTabParentId,
focusUrlBar: aFocusUrlBar,
Expand Down Expand Up @@ -2117,11 +2121,11 @@
b.setAttribute("remote", "true");
}

if (aParams.opener) {
if (aParams.openerWindow) {
if (aParams.remoteType) {
throw new Error("Cannot set opener window on a remote browser!");
}
b.QueryInterface(Ci.nsIFrameLoaderOwner).presetOpenerWindow(aParams.opener);
b.QueryInterface(Ci.nsIFrameLoaderOwner).presetOpenerWindow(aParams.openerWindow);
}

if (!aParams.isPreloadBrowser && this.hasAttribute("autocompletepopup")) {
Expand All @@ -2138,6 +2142,9 @@
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);

if (aParams.nextTabParentId) {
if (!aParams.remoteType) {
throw new Error("Cannot have nextTabParentId without a remoteType");
}
// Gecko is going to read this attribute and use it.
b.setAttribute("nextTabParentId", aParams.nextTabParentId.toString());
}
Expand Down Expand Up @@ -2424,6 +2431,7 @@
var aOriginPrincipal;
var aDisallowInheritPrincipal;
var aOpener;
var aOpenerBrowser;
var aIsPrerendered;
var aCreateLazyBrowser;
var aSkipBackgroundNotify;
Expand Down Expand Up @@ -2455,6 +2463,7 @@
aOriginPrincipal = params.originPrincipal;
aDisallowInheritPrincipal = params.disallowInheritPrincipal;
aOpener = params.opener;
aOpenerBrowser = params.openerBrowser;
aIsPrerendered = params.isPrerendered;
aCreateLazyBrowser = params.createLazyBrowser;
aSkipBackgroundNotify = params.skipBackgroundNotify;
Expand All @@ -2468,8 +2477,28 @@
if (this.mCurrentTab.owner)
this.mCurrentTab.owner = null;

// Find the tab that opened this one, if any. This is used for
// determining positioning, and inherited attributes such as the
// user context ID.
//
// If we have a browser opener (which is usually the browser
// element from a remote window.open() call), use that.
//
// Otherwise, if the tab is related to the current tab (e.g.,
// because it was opened by a link click), use the selected tab as
// the owner. If aReferrerURI is set, and we don't have an
// explicit relatedToCurrent arg, we assume that the tab is
// related to the current tab, since aReferrerURI is null or
// undefined if the tab is opened from an external application or
// bookmark (i.e. somewhere other than an existing tab).
let relatedToCurrent = aRelatedToCurrent == null ? !!aReferrerURI : aRelatedToCurrent;
let openerTab = ((aOpenerBrowser && this.getTabForBrowser(aOpenerBrowser)) ||
(relatedToCurrent && this.selectedTab));

var t = document.createElementNS(NS_XUL, "tab");

t.openerTab = openerTab;

aURI = aURI || "about:blank";
let aURIObject = null;
try {
Expand Down Expand Up @@ -2499,9 +2528,8 @@

// Related tab inherits current tab's user context unless a different
// usercontextid is specified
if (aUserContextId == null &&
(aRelatedToCurrent == null ? aReferrerURI : aRelatedToCurrent)) {
aUserContextId = this.mCurrentTab.getAttribute("usercontextid") || 0;
if (aUserContextId == null && openerTab) {
aUserContextId = openerTab.getAttribute("usercontextid") || 0;
}

if (aUserContextId) {
Expand Down Expand Up @@ -2550,6 +2578,12 @@

this.tabContainer.updateVisibility();

// If we don't have a preferred remote type, and we have a remote
// opener, use the opener's remote type.
if (!aPreferredRemoteType && aOpenerBrowser) {
aPreferredRemoteType = aOpenerBrowser.remoteType;
}

// If URI is about:blank and we don't have a preferred remote type,
// then we need to use the referrer, if we have one, to get the
// correct remote type for the new tab.
Expand Down Expand Up @@ -2586,7 +2620,7 @@
uriIsAboutBlank,
userContextId: aUserContextId,
sameProcessAsFrameLoader: aSameProcessAsFrameLoader,
opener: aOpener,
openerWindow: aOpener,
isPrerendered: aIsPrerendered,
nextTabParentId: aNextTabParentId,
name: aName });
Expand Down Expand Up @@ -2668,21 +2702,19 @@
}
}

// Check if we're opening a tab related to the current tab and
// move it to after the current tab.
// aReferrerURI is null or undefined if the tab is opened from
// an external application or bookmark, i.e. somewhere other
// than the current tab.
if ((aRelatedToCurrent == null ? aReferrerURI : aRelatedToCurrent) &&
// If we're opening a tab related to the an existing tab, move it
// to a position after that tab.
if (openerTab &&
Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")) {
let newTabPos = (this._lastRelatedTab ||
this.selectedTab)._tPos + 1;
if (this._lastRelatedTab)
this._lastRelatedTab.owner = null;

let lastRelatedTab = this._lastRelatedTabMap.get(openerTab);
let newTabPos = (lastRelatedTab || openerTab)._tPos + 1;
if (lastRelatedTab)
lastRelatedTab.owner = null;
else
t.owner = this.selectedTab;
this.moveTabTo(t, newTabPos);
this._lastRelatedTab = t;
t.owner = openerTab;
this.moveTabTo(t, newTabPos, true);
this._lastRelatedTabMap.set(openerTab, t);
}

if (animate) {
Expand Down Expand Up @@ -3058,7 +3090,7 @@
aNewTab = false;
}

this._lastRelatedTab = null;
this._lastRelatedTabMap = new WeakMap();

// update the UI early for responsiveness
aTab.collapsed = true;
Expand Down Expand Up @@ -3708,6 +3740,7 @@
<method name="moveTabTo">
<parameter name="aTab"/>
<parameter name="aIndex"/>
<parameter name="aKeepRelatedTabs"/>
<body>
<![CDATA[
var oldPosition = aTab._tPos;
Expand All @@ -3722,7 +3755,9 @@
if (oldPosition == aIndex)
return;

this._lastRelatedTab = null;
if (!aKeepRelatedTabs) {
this._lastRelatedTabMap = new WeakMap();
}

let wasFocused = (document.activeElement == this.mCurrentTab);

Expand Down
17 changes: 16 additions & 1 deletion browser/components/extensions/ext-tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,15 @@ this.tabs = class extends ExtensionAPI {

tabListener.initTabReady();
let currentTab = window.gBrowser.selectedTab;

if (createProperties.openerTabId !== null) {
options.ownerTab = tabTracker.getTab(createProperties.openerTabId);
options.openerBrowser = options.ownerTab.linkedBrowser;
if (options.ownerTab.ownerGlobal !== window) {
return Promise.reject({message: "Opener tab must be in the same window as the tab being created"});
}
}

let nativeTab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);

let active = true;
Expand Down Expand Up @@ -450,7 +459,13 @@ this.tabs = class extends ExtensionAPI {
tabbrowser.unpinTab(nativeTab);
}
}
// FIXME: highlighted/selected, openerTabId
if (updateProperties.openerTabId !== null) {
let opener = tabTracker.getTab(updateProperties.openerTabId);
if (opener.ownerDocument !== nativeTab.ownerDocument) {
return Promise.reject({message: "Opener tab must be in the same window as the tab being updated"});
}
tabTracker.setOpener(nativeTab, opener);
}

return tabManager.convert(nativeTab);
},
Expand Down
22 changes: 22 additions & 0 deletions browser/components/extensions/ext-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,20 @@ class TabTracker extends TabTrackerBase {
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
}

/**
* Sets the opener of `tab` to the ID `openerTab`. Both tabs must be in the
* same window, or this function will throw a type error.
*
* @param {Element} tab The tab for which to set the owner.
* @param {Element} openerTab The opener of <tab>.
*/
setOpener(tab, openerTab) {
if (tab.ownerDocument !== openerTab.ownerDocument) {
throw new Error("Tab must be in the same window as its opener");
}
tab.openerTab = openerTab;
}

/**
* @param {Event} event
* The DOM Event to handle.
Expand Down Expand Up @@ -500,6 +514,14 @@ class Tab extends TabBase {
return getCookieStoreIdForTab(this, this.nativeTab);
}

get openerTabId() {
let opener = this.nativeTab.openerTab;
if (opener && opener.parentNode && opener.ownerDocument == this.nativeTab.ownerDocument) {
return tabTracker.getId(opener);
}
return null;
}

get height() {
return this.frameLoader.lazyHeight;
}
Expand Down
10 changes: 7 additions & 3 deletions browser/components/extensions/schemas/tabs.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"id": {"type": "integer", "minimum": -1, "optional": true, "description": "The ID of the tab. Tab IDs are unique within a browser session. Under some circumstances a Tab may not be assigned an ID, for example when querying foreign tabs using the $(ref:sessions) API, in which case a session ID may be present. Tab ID can also be set to $(ref:tabs.TAB_ID_NONE) for apps and devtools windows."},
"index": {"type": "integer", "minimum": -1, "description": "The zero-based index of the tab within its window."},
"windowId": {"type": "integer", "optional": true, "minimum": 0, "description": "The ID of the window the tab is contained within."},
"openerTabId": {"unsupported": true, "type": "integer", "minimum": 0, "optional": true, "description": "The ID of the tab that opened this tab, if any. This property is only present if the opener tab still exists."},
"openerTabId": {"type": "integer", "minimum": 0, "optional": true, "description": "The ID of the tab that opened this tab, if any. This property is only present if the opener tab still exists."},
"selected": {"type": "boolean", "description": "Whether the tab is selected.", "deprecated": "Please use $(ref:tabs.Tab.highlighted).", "unsupported": true},
"highlighted": {"type": "boolean", "description": "Whether the tab is highlighted. Works as an alias of active"},
"active": {"type": "boolean", "description": "Whether the tab is active in its window. (Does not necessarily mean the window is focused.)"},
Expand Down Expand Up @@ -485,7 +485,6 @@
"description": "Whether the tab should be pinned. Defaults to <var>false</var>"
},
"openerTabId": {
"unsupported": true,
"type": "integer",
"minimum": 0,
"optional": true,
Expand Down Expand Up @@ -624,6 +623,12 @@
"type": "string",
"optional": true,
"description": "The CookieStoreId used for the tab."
},
"openerTabId": {
"type": "integer",
"minimum": 0,
"optional": true,
"description": "The ID of the tab that opened this tab. If specified, the opener tab must be in the same window as this tab."
}
}
},
Expand Down Expand Up @@ -733,7 +738,6 @@
"description": "Whether the tab should be muted."
},
"openerTabId": {
"unsupported": true,
"type": "integer",
"minimum": 0,
"optional": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ skip-if = debug || asan # Bug 1354681
[browser_ext_tabs_move_window_pinned.js]
[browser_ext_tabs_onHighlighted.js]
[browser_ext_tabs_onUpdated.js]
[browser_ext_tabs_opener.js]
[browser_ext_tabs_printPreview.js]
[browser_ext_tabs_query.js]
[browser_ext_tabs_reload.js]
Expand Down
Loading