diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index d55882ba50286..9f924c1464bbf 100755
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -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
@@ -5213,7 +5213,8 @@ nsBrowserAccess.prototype = {
fromExternal: aIsExternal,
inBackground: loadInBackground,
forceNotRemote: aForceNotRemote,
- opener: aOpener,
+ opener: aOpenerWindow,
+ openerBrowser: aOpenerBrowser,
nextTabParentId: aNextTabParentId,
name: aName,
});
@@ -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;
@@ -5335,7 +5336,7 @@ nsBrowserAccess.prototype = {
aParams.referrerPolicy,
aParams.isPrivate,
isExternal, false,
- userContextId, null,
+ userContextId, null, aParams.openerBrowser,
aParams.triggeringPrincipal,
aNextTabParentId, aName);
if (browser)
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index 358781c2d4347..83ff34fcad7d4 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -82,8 +82,8 @@
null
-
- null
+
+ new WeakMap();
null
@@ -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;
@@ -1623,6 +1624,7 @@
var aSameProcessAsFrameLoader;
var aOriginPrincipal;
var aOpener;
+ var aOpenerBrowser;
var aIsPrerendered;
var aCreateLazyBrowser;
var aNextTabParentId;
@@ -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;
@@ -1681,6 +1684,7 @@
originPrincipal: aOriginPrincipal,
sameProcessAsFrameLoader: aSameProcessAsFrameLoader,
opener: aOpener,
+ openerBrowser: aOpenerBrowser,
isPrerendered: aIsPrerendered,
nextTabParentId: aNextTabParentId,
focusUrlBar: aFocusUrlBar,
@@ -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")) {
@@ -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());
}
@@ -2424,6 +2431,7 @@
var aOriginPrincipal;
var aDisallowInheritPrincipal;
var aOpener;
+ var aOpenerBrowser;
var aIsPrerendered;
var aCreateLazyBrowser;
var aSkipBackgroundNotify;
@@ -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;
@@ -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 {
@@ -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) {
@@ -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.
@@ -2586,7 +2620,7 @@
uriIsAboutBlank,
userContextId: aUserContextId,
sameProcessAsFrameLoader: aSameProcessAsFrameLoader,
- opener: aOpener,
+ openerWindow: aOpener,
isPrerendered: aIsPrerendered,
nextTabParentId: aNextTabParentId,
name: aName });
@@ -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) {
@@ -3058,7 +3090,7 @@
aNewTab = false;
}
- this._lastRelatedTab = null;
+ this._lastRelatedTabMap = new WeakMap();
// update the UI early for responsiveness
aTab.collapsed = true;
@@ -3708,6 +3740,7 @@
+
.
+ */
+ 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.
@@ -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;
}
diff --git a/browser/components/extensions/schemas/tabs.json b/browser/components/extensions/schemas/tabs.json
index f57cb07a74a8b..bf33481066706 100644
--- a/browser/components/extensions/schemas/tabs.json
+++ b/browser/components/extensions/schemas/tabs.json
@@ -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.)"},
@@ -485,7 +485,6 @@
"description": "Whether the tab should be pinned. Defaults to false"
},
"openerTabId": {
- "unsupported": true,
"type": "integer",
"minimum": 0,
"optional": true,
@@ -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."
}
}
},
@@ -733,7 +738,6 @@
"description": "Whether the tab should be muted."
},
"openerTabId": {
- "unsupported": true,
"type": "integer",
"minimum": 0,
"optional": true,
diff --git a/browser/components/extensions/test/browser/browser-common.ini b/browser/components/extensions/test/browser/browser-common.ini
index 18030c0cbd3f2..50075b7dc933d 100644
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -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]
diff --git a/browser/components/extensions/test/browser/browser_ext_tabs_opener.js b/browser/components/extensions/test/browser/browser_ext_tabs_opener.js
new file mode 100644
index 0000000000000..e1049358873ee
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_opener.js
@@ -0,0 +1,78 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(async function() {
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank?1");
+ let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank?2");
+
+ gBrowser.selectedTab = tab1;
+
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ "permissions": ["tabs"],
+ },
+
+ background() {
+ let activeTab;
+ let tabId;
+ let tabIds;
+ browser.tabs.query({lastFocusedWindow: true}).then(tabs => {
+ browser.test.assertEq(3, tabs.length, "We have three tabs");
+
+ browser.test.assertTrue(tabs[1].active, "Tab 1 is active");
+ activeTab = tabs[1];
+
+ tabIds = tabs.map(tab => tab.id);
+
+ return browser.tabs.create({openerTabId: activeTab.id, active: false});
+ }).then(tab => {
+ browser.test.assertEq(activeTab.id, tab.openerTabId, "Tab opener ID is correct");
+ browser.test.assertEq(activeTab.index + 1, tab.index, "Tab was inserted after the related current tab");
+
+ tabId = tab.id;
+ return browser.tabs.get(tabId);
+ }).then(tab => {
+ browser.test.assertEq(activeTab.id, tab.openerTabId, "Tab opener ID is still correct");
+
+ return browser.tabs.update(tabId, {openerTabId: tabIds[0]});
+ }).then(tab => {
+ browser.test.assertEq(tabIds[0], tab.openerTabId, "Updated tab opener ID is correct");
+
+ return browser.tabs.get(tabId);
+ }).then(tab => {
+ browser.test.assertEq(tabIds[0], tab.openerTabId, "Updated tab opener ID is still correct");
+
+ return browser.tabs.create({openerTabId: tabId, active: false});
+ }).then(tab => {
+ browser.test.assertEq(tabId, tab.openerTabId, "New tab opener ID is correct");
+ browser.test.assertEq(tabIds.length, tab.index, "New tab was not inserted after the unrelated current tab");
+
+ let promise = browser.tabs.remove(tabId);
+
+ tabId = tab.id;
+ return promise;
+ }).then(() => {
+ return browser.tabs.get(tabId);
+ }).then(tab => {
+ browser.test.assertEq(undefined, tab.openerTabId, "Tab opener ID was cleared after opener tab closed");
+
+ return browser.tabs.remove(tabId);
+ }).then(() => {
+ browser.test.notifyPass("tab-opener");
+ }).catch(e => {
+ browser.test.fail(`${e} :: ${e.stack}`);
+ browser.test.notifyFail("tab-opener");
+ });
+ },
+ });
+
+ await extension.startup();
+
+ await extension.awaitFinish("tab-opener");
+
+ await extension.unload();
+
+ await BrowserTestUtils.removeTab(tab1);
+ await BrowserTestUtils.removeTab(tab2);
+});
diff --git a/dom/base/nsOpenURIInFrameParams.cpp b/dom/base/nsOpenURIInFrameParams.cpp
index 0297caa4f1fa0..5d6696880a99f 100644
--- a/dom/base/nsOpenURIInFrameParams.cpp
+++ b/dom/base/nsOpenURIInFrameParams.cpp
@@ -8,10 +8,20 @@
#include "mozilla/BasePrincipal.h"
#include "mozilla/dom/ToJSValue.h"
-NS_IMPL_ISUPPORTS(nsOpenURIInFrameParams, nsIOpenURIInFrameParams)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsOpenURIInFrameParams)
+ NS_INTERFACE_MAP_ENTRY(nsIOpenURIInFrameParams)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
-nsOpenURIInFrameParams::nsOpenURIInFrameParams(const mozilla::OriginAttributes& aOriginAttributes)
+NS_IMPL_CYCLE_COLLECTION(nsOpenURIInFrameParams, mOpenerBrowser)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsOpenURIInFrameParams)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsOpenURIInFrameParams)
+
+nsOpenURIInFrameParams::nsOpenURIInFrameParams(const mozilla::OriginAttributes& aOriginAttributes,
+ nsIFrameLoaderOwner* aOpener)
: mOpenerOriginAttributes(aOriginAttributes)
+ , mOpenerBrowser(aOpener)
{
}
@@ -55,6 +65,14 @@ nsOpenURIInFrameParams::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipa
return NS_OK;
}
+NS_IMETHODIMP
+nsOpenURIInFrameParams::GetOpenerBrowser(nsIFrameLoaderOwner** aOpenerBrowser)
+{
+ nsCOMPtr owner = mOpenerBrowser;
+ owner.forget(aOpenerBrowser);
+ return NS_OK;
+}
+
NS_IMETHODIMP
nsOpenURIInFrameParams::GetOpenerOriginAttributes(JSContext* aCx,
JS::MutableHandle aValue)
diff --git a/dom/base/nsOpenURIInFrameParams.h b/dom/base/nsOpenURIInFrameParams.h
index f00ee3d47aa11..4eefec623c805 100644
--- a/dom/base/nsOpenURIInFrameParams.h
+++ b/dom/base/nsOpenURIInFrameParams.h
@@ -5,7 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/BasePrincipal.h"
+#include "nsCycleCollectionParticipant.h"
#include "nsIBrowserDOMWindow.h"
+#include "nsIFrameLoader.h"
#include "nsString.h"
namespace mozilla {
@@ -15,15 +17,18 @@ class OriginAttributes;
class nsOpenURIInFrameParams final : public nsIOpenURIInFrameParams
{
public:
- NS_DECL_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS(nsOpenURIInFrameParams)
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIOPENURIINFRAMEPARAMS
- explicit nsOpenURIInFrameParams(const mozilla::OriginAttributes& aOriginAttributes);
+ explicit nsOpenURIInFrameParams(const mozilla::OriginAttributes& aOriginAttributes,
+ nsIFrameLoaderOwner* aOpener);
private:
~nsOpenURIInFrameParams();
mozilla::OriginAttributes mOpenerOriginAttributes;
+ nsCOMPtr mOpenerBrowser;
nsString mReferrer;
nsCOMPtr mTriggeringPrincipal;
};
diff --git a/dom/interfaces/base/nsIBrowserDOMWindow.idl b/dom/interfaces/base/nsIBrowserDOMWindow.idl
index 29142f8a17d61..1dc15586e70c4 100644
--- a/dom/interfaces/base/nsIBrowserDOMWindow.idl
+++ b/dom/interfaces/base/nsIBrowserDOMWindow.idl
@@ -18,6 +18,10 @@ interface nsIOpenURIInFrameParams : nsISupports
readonly attribute boolean isPrivate;
attribute nsIPrincipal triggeringPrincipal;
+ // The browser or frame element in the parent process which holds the
+ // opener window in the content process. May be null.
+ readonly attribute nsIFrameLoaderOwner openerBrowser;
+
[implicit_jscontext]
readonly attribute jsval openerOriginAttributes;
};
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index 51676ed3f0bbe..88466d9483030 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1146,6 +1146,12 @@ ContentParent::CreateBrowser(const TabContext& aContext,
return nullptr;
}
+ nsAutoString remoteType;
+ if (!aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
+ remoteType)) {
+ remoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
+ }
+
if (aNextTabParentId) {
if (TabParent* parent =
sNextTabParents.GetAndRemove(aNextTabParentId).valueOr(nullptr)) {
@@ -1166,12 +1172,6 @@ ContentParent::CreateBrowser(const TabContext& aContext,
openerTabId = TabParent::GetTabIdFrom(docShell);
}
- nsAutoString remoteType;
- if (!aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
- remoteType)) {
- remoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
- }
-
RefPtr constructorSender;
if (isInContentProcess) {
MOZ_ASSERT(aContext.IsMozBrowserElement() || aContext.IsJSPlugin());
@@ -4531,8 +4531,10 @@ ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
return IPC_OK();
}
+ nsCOMPtr opener = do_QueryInterface(frame);
+
nsCOMPtr params =
- new nsOpenURIInFrameParams(openerOriginAttributes);
+ new nsOpenURIInFrameParams(openerOriginAttributes, opener);
params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI));
MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal");
params->SetTriggeringPrincipal(aTriggeringPrincipal);
diff --git a/toolkit/components/extensions/ExtensionTabs.jsm b/toolkit/components/extensions/ExtensionTabs.jsm
index f2d55266a52a1..4f139991840fa 100644
--- a/toolkit/components/extensions/ExtensionTabs.jsm
+++ b/toolkit/components/extensions/ExtensionTabs.jsm
@@ -315,6 +315,15 @@ class TabBase {
throw new Error("Not implemented");
}
+ /**
+ * @property {integer} openerTabId
+ * Returns the ID of the tab which opened this one.
+ * @readonly
+ */
+ get openerTabId() {
+ return null;
+ }
+
/**
* @property {integer} height
* Returns the pixel height of the visible area of the tab.
@@ -451,9 +460,9 @@ class TabBase {
* True if the tab matches the query.
*/
matches(queryInfo) {
- const PROPS = ["active", "audible", "cookieStoreId", "highlighted", "index", "pinned", "status", "title"];
+ const PROPS = ["active", "audible", "cookieStoreId", "highlighted", "index", "openerTabId", "pinned", "status", "title"];
- if (PROPS.some(prop => queryInfo[prop] !== null && queryInfo[prop] !== this[prop])) {
+ if (PROPS.some(prop => queryInfo[prop] != null && queryInfo[prop] !== this[prop])) {
return false;
}
@@ -504,6 +513,11 @@ class TabBase {
result.height = fallbackTab.height;
}
+ let opener = this.openerTabId;
+ if (opener) {
+ result.openerTabId = opener;
+ }
+
if (this.extension.hasPermission("cookies")) {
result.cookieStoreId = this.cookieStoreId;
}
diff --git a/toolkit/components/extensions/test/mochitest/mochitest-common.ini b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
index 7779a9ed15d74..ba2adbb71b40e 100644
--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
@@ -78,6 +78,7 @@ skip-if = os == 'android' # bug 1369440
[test_ext_generate.html]
[test_ext_geolocation.html]
skip-if = os == 'android' # Android support Bug 1336194
+[test_ext_new_tab_processType.html]
[test_ext_notifications.html]
[test_ext_permission_xhr.html]
[test_ext_proxy.html]
diff --git a/toolkit/components/extensions/test/mochitest/test_ext_new_tab_processType.html b/toolkit/components/extensions/test/mochitest/test_ext_new_tab_processType.html
new file mode 100644
index 0000000000000..2e2da2cbf8af5
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_new_tab_processType.html
@@ -0,0 +1,89 @@
+
+
+
+ Test for opening links in new tabs from extension frames
+
+
+
+
+
+
+
+
+
+
+
+