mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Backed out 2 changesets (bug 1582716, bug 1575051) for gv-junit failures, new exception. CLOSED TREE
Backed out changeset b5aa3ac4483e (bug 1582716) Backed out changeset c385531b4ee3 (bug 1575051)
This commit is contained in:
parent
41aaf2b98d
commit
203fbcd6c8
@ -16,7 +16,6 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Location.h"
|
||||
#include "mozilla/dom/LocationBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/UserActivationIPCUtils.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
@ -472,14 +471,8 @@ void BrowsingContext::GetChildren(Children& aChildren) {
|
||||
//
|
||||
// See
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
|
||||
BrowsingContext* BrowsingContext::FindWithName(const nsAString& aName) {
|
||||
RefPtr<BrowsingContext> requestingContext = this;
|
||||
if (nsCOMPtr<nsIDocShell> caller = do_GetInterface(GetEntryGlobal())) {
|
||||
if (caller->GetBrowsingContext()) {
|
||||
requestingContext = caller->GetBrowsingContext();
|
||||
}
|
||||
}
|
||||
|
||||
BrowsingContext* BrowsingContext::FindWithName(
|
||||
const nsAString& aName, BrowsingContext& aRequestingContext) {
|
||||
BrowsingContext* found = nullptr;
|
||||
if (aName.IsEmpty()) {
|
||||
// You can't find a browsing context with an empty name.
|
||||
@ -489,9 +482,9 @@ BrowsingContext* BrowsingContext::FindWithName(const nsAString& aName) {
|
||||
// a blank name.
|
||||
found = nullptr;
|
||||
} else if (IsSpecialName(aName)) {
|
||||
found = FindWithSpecialName(aName, *requestingContext);
|
||||
found = FindWithSpecialName(aName, aRequestingContext);
|
||||
} else if (BrowsingContext* child =
|
||||
FindWithNameInSubtree(aName, *requestingContext)) {
|
||||
FindWithNameInSubtree(aName, aRequestingContext)) {
|
||||
found = child;
|
||||
} else {
|
||||
BrowsingContext* current = this;
|
||||
@ -505,7 +498,7 @@ BrowsingContext* BrowsingContext::FindWithName(const nsAString& aName) {
|
||||
// contexts in the same browsing context group.
|
||||
siblings = &mGroup->Toplevels();
|
||||
} else if (parent->NameEquals(aName) &&
|
||||
requestingContext->CanAccess(parent) &&
|
||||
aRequestingContext.CanAccess(parent) &&
|
||||
parent->IsTargetable()) {
|
||||
found = parent;
|
||||
break;
|
||||
@ -519,7 +512,7 @@ BrowsingContext* BrowsingContext::FindWithName(const nsAString& aName) {
|
||||
}
|
||||
|
||||
if (BrowsingContext* relative =
|
||||
sibling->FindWithNameInSubtree(aName, *requestingContext)) {
|
||||
sibling->FindWithNameInSubtree(aName, aRequestingContext)) {
|
||||
found = relative;
|
||||
// Breaks the outer loop
|
||||
parent = nullptr;
|
||||
@ -533,7 +526,7 @@ BrowsingContext* BrowsingContext::FindWithName(const nsAString& aName) {
|
||||
|
||||
// Helpers should perform access control checks, which means that we
|
||||
// only need to assert that we can access found.
|
||||
MOZ_DIAGNOSTIC_ASSERT(!found || requestingContext->CanAccess(found));
|
||||
MOZ_DIAGNOSTIC_ASSERT(!found || aRequestingContext.CanAccess(found));
|
||||
|
||||
return found;
|
||||
}
|
||||
|
@ -259,7 +259,8 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
|
||||
// BrowsingContext::FindWithName(const nsAString&) is equivalent to
|
||||
// calling nsIDocShellTreeItem::FindItemWithName(aName, nullptr,
|
||||
// nullptr, false, <return value>).
|
||||
BrowsingContext* FindWithName(const nsAString& aName);
|
||||
BrowsingContext* FindWithName(const nsAString& aName,
|
||||
BrowsingContext& aRequestingContext);
|
||||
|
||||
// Find a browsing context in this context's list of
|
||||
// children. Doesn't consider the special names, '_self', '_parent',
|
||||
|
@ -133,19 +133,6 @@ JSObject* BrowsingContextGroup::WrapObject(JSContext* aCx,
|
||||
return BrowsingContextGroup_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
static StaticRefPtr<BrowsingContextGroup> sChromeGroup;
|
||||
|
||||
/* static */
|
||||
BrowsingContextGroup* BrowsingContextGroup::GetChromeGroup() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
||||
if (!sChromeGroup && XRE_IsParentProcess()) {
|
||||
sChromeGroup = new BrowsingContextGroup();
|
||||
ClearOnShutdown(&sChromeGroup);
|
||||
}
|
||||
|
||||
return sChromeGroup;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BrowsingContextGroup, mContexts,
|
||||
mToplevels, mSubscribers, mCachedContexts)
|
||||
|
||||
|
@ -108,8 +108,6 @@ class BrowsingContextGroup final : public nsWrapperCache {
|
||||
}
|
||||
}
|
||||
|
||||
static BrowsingContextGroup* GetChromeGroup();
|
||||
|
||||
private:
|
||||
friend class CanonicalBrowsingContext;
|
||||
|
||||
|
@ -2888,6 +2888,65 @@ static bool ItemIsActive(nsIDocShellTreeItem* aItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::FindItemWithName(const nsAString& aName,
|
||||
nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
bool aSkipTabGroup,
|
||||
nsIDocShellTreeItem** aResult) {
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
// If we don't find one, we return NS_OK and a null result
|
||||
*aResult = nullptr;
|
||||
|
||||
if (aName.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aRequestor) {
|
||||
// If aRequestor is not null we don't need to check special names, so
|
||||
// just hand straight off to the search by actual name function.
|
||||
return DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
|
||||
aSkipTabGroup, aResult);
|
||||
} else {
|
||||
// This is the entry point into the target-finding algorithm. Check
|
||||
// for special names. This should only be done once, hence the check
|
||||
// for a null aRequestor.
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> foundItem;
|
||||
if (aName.LowerCaseEqualsLiteral("_self")) {
|
||||
foundItem = this;
|
||||
} else if (aName.LowerCaseEqualsLiteral("_blank")) {
|
||||
// Just return null. Caller must handle creating a new window with
|
||||
// a blank name himself.
|
||||
return NS_OK;
|
||||
} else if (aName.LowerCaseEqualsLiteral("_parent")) {
|
||||
GetInProcessSameTypeParent(getter_AddRefs(foundItem));
|
||||
if (!foundItem) {
|
||||
foundItem = this;
|
||||
}
|
||||
} else if (aName.LowerCaseEqualsLiteral("_top")) {
|
||||
GetInProcessSameTypeRootTreeItem(getter_AddRefs(foundItem));
|
||||
NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
|
||||
} else {
|
||||
// Do the search for item by an actual name.
|
||||
DoFindItemWithName(aName, aRequestor, aOriginalRequestor, aSkipTabGroup,
|
||||
getter_AddRefs(foundItem));
|
||||
}
|
||||
|
||||
if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
|
||||
foundItem = nullptr;
|
||||
}
|
||||
|
||||
// DoFindItemWithName only returns active items and we don't check if
|
||||
// the item is active for the special cases.
|
||||
if (foundItem) {
|
||||
foundItem.swap(*aResult);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void nsDocShell::AssertOriginAttributesMatchPrivateBrowsing() {
|
||||
// Chrome docshells must not have a private browsing OriginAttribute
|
||||
// Content docshells must maintain the equality:
|
||||
@ -2900,6 +2959,64 @@ void nsDocShell::AssertOriginAttributesMatchPrivateBrowsing() {
|
||||
}
|
||||
}
|
||||
|
||||
nsresult nsDocShell::DoFindItemWithName(const nsAString& aName,
|
||||
nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
bool aSkipTabGroup,
|
||||
nsIDocShellTreeItem** aResult) {
|
||||
// First we check our name.
|
||||
if (mBrowsingContext->NameEquals(aName) && ItemIsActive(this) &&
|
||||
CanAccessItem(this, aOriginalRequestor)) {
|
||||
NS_ADDREF(*aResult = this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Second we check our children making sure not to ask a child if
|
||||
// it is the aRequestor.
|
||||
#ifdef DEBUG
|
||||
nsresult rv =
|
||||
#endif
|
||||
FindChildWithName(aName, true, true, aRequestor, aOriginalRequestor,
|
||||
aResult);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"FindChildWithName should not be failing here.");
|
||||
if (*aResult) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Third if we have a parent and it isn't the requestor then we
|
||||
// should ask it to do the search. If it is the requestor we
|
||||
// should just stop here and let the parent do the rest. If we
|
||||
// don't have a parent, then we should ask the
|
||||
// docShellTreeOwner to do the search.
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
|
||||
do_QueryInterface(GetAsSupports(mParent));
|
||||
if (parentAsTreeItem) {
|
||||
if (parentAsTreeItem == aRequestor) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we have a same-type parent, respecting browser and app boundaries.
|
||||
// NOTE: Could use GetInProcessSameTypeParent if the issues described in
|
||||
// bug 1310344 are fixed.
|
||||
if (!GetIsMozBrowser() && parentAsTreeItem->ItemType() == mItemType) {
|
||||
return parentAsTreeItem->FindItemWithName(aName, this, aOriginalRequestor,
|
||||
/* aSkipTabGroup = */ false,
|
||||
aResult);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a null parent or the parent is not of the same type, we need to
|
||||
// give up on finding it in our tree, and start looking in our TabGroup.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
|
||||
if (window && !aSkipTabGroup) {
|
||||
RefPtr<mozilla::dom::TabGroup> tabGroup = window->TabGroup();
|
||||
tabGroup->FindItemWithName(aName, this, aOriginalRequestor, aResult);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool nsDocShell::IsSandboxedFrom(BrowsingContext* aTargetBC) {
|
||||
// If no target then not sandboxed.
|
||||
if (!aTargetBC) {
|
||||
@ -8587,9 +8704,11 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState,
|
||||
MOZ_ASSERT(aLoadState, "need a load state!");
|
||||
MOZ_ASSERT(!aLoadState->Target().IsEmpty(), "should have a target here!");
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDocShell> targetDocShell;
|
||||
|
||||
// Locate the target DocShell.
|
||||
nsCOMPtr<nsIDocShellTreeItem> targetItem;
|
||||
// Only _self, _parent, and _top are supported in noopener case. But we
|
||||
// have to be careful to not apply that to the noreferrer case. See bug
|
||||
// 1358469.
|
||||
@ -8600,12 +8719,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState,
|
||||
aLoadState->Target().LowerCaseEqualsLiteral("_self") ||
|
||||
aLoadState->Target().LowerCaseEqualsLiteral("_parent") ||
|
||||
aLoadState->Target().LowerCaseEqualsLiteral("_top")) {
|
||||
if (BrowsingContext* context =
|
||||
mBrowsingContext->FindWithName(aLoadState->Target())) {
|
||||
targetDocShell = context->GetDocShell();
|
||||
}
|
||||
rv = FindItemWithName(aLoadState->Target(), nullptr, this, false,
|
||||
getter_AddRefs(targetItem));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
targetDocShell = do_QueryInterface(targetItem);
|
||||
if (!targetDocShell) {
|
||||
// If the targetDocShell doesn't exist, then this is a new docShell
|
||||
// and we should consider this a TYPE_DOCUMENT load
|
||||
@ -13464,6 +13583,35 @@ nsCommandManager* nsDocShell::GetCommandManager() {
|
||||
return mCommandManager;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetIsOnlyToplevelInTabGroup(bool* aResult) {
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
nsPIDOMWindowOuter* outer = GetWindow();
|
||||
MOZ_ASSERT(outer);
|
||||
|
||||
// If we are not toplevel then we are not the only toplevel window in the
|
||||
// tab group.
|
||||
if (outer->GetInProcessScriptableParentOrNull()) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we have any other toplevel windows in our tab group, then we are not
|
||||
// the only toplevel window in the tab group.
|
||||
nsTArray<nsPIDOMWindowOuter*> toplevelWindows =
|
||||
outer->TabGroup()->GetTopLevelWindows();
|
||||
if (toplevelWindows.Length() > 1) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(toplevelWindows.Length() == 1);
|
||||
MOZ_ASSERT(toplevelWindows[0] == outer);
|
||||
|
||||
*aResult = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetAwaitingLargeAlloc(bool* aResult) {
|
||||
MOZ_ASSERT(aResult);
|
||||
|
@ -942,6 +942,14 @@ class nsDocShell final : public nsDocLoader,
|
||||
MOZ_MUST_USE bool MaybeInitTiming();
|
||||
void MaybeResetInitTiming(bool aReset);
|
||||
|
||||
// Separate function to do the actual name (i.e. not _top, _self etc.)
|
||||
// searching for FindItemWithName.
|
||||
nsresult DoFindItemWithName(const nsAString& aName,
|
||||
nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
bool aSkipTabGroup,
|
||||
nsIDocShellTreeItem** aResult);
|
||||
|
||||
// Convenience method for getting our parent docshell. Can return null
|
||||
already_AddRefed<nsDocShell> GetInProcessParentDocshell();
|
||||
|
||||
|
@ -1055,6 +1055,20 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
*/
|
||||
[infallible] attribute nsIDocShell_MetaViewportOverride metaViewportOverride;
|
||||
|
||||
/**
|
||||
* This value is `true` if its corresponding unit of related browsing contexts
|
||||
* (TabGroup) contains only 1 toplevel window, and that window is the outer
|
||||
* window corresponding to this docshell.
|
||||
*
|
||||
* The value is `false` otherwise. This is the case if the docshell is an
|
||||
* iframe, has window.opener set, or another window with window.opener
|
||||
* referring to this window exists.
|
||||
*
|
||||
* If this value is `false`, it would be web content visible for a load
|
||||
* occuring in this docshell to be performed within a different docshell.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isOnlyToplevelInTabGroup;
|
||||
|
||||
/**
|
||||
* Returns `true` if this docshell was created due to a Large-Allocation
|
||||
* header, and has not seen the initiating load yet.
|
||||
|
@ -92,6 +92,39 @@ interface nsIDocShellTreeItem : nsISupports
|
||||
[binaryname(InProcessSameTypeRootTreeItem)]
|
||||
readonly attribute nsIDocShellTreeItem sameTypeRootTreeItem;
|
||||
|
||||
/*
|
||||
Returns the docShellTreeItem with the specified name. Search order is as
|
||||
follows...
|
||||
1.) Check name of self, if it matches return it.
|
||||
2.) For each immediate child.
|
||||
a.) Check name of child and if it matches return it.
|
||||
b.) Ask the child to perform the check
|
||||
i.) Do not ask a child if it is the aRequestor
|
||||
ii.) Do not ask a child if it is of a different item type.
|
||||
3.) If there is a parent of the same item type ask parent to perform the check
|
||||
a.) Do not ask parent if it is the aRequestor
|
||||
4.) If there is a tab group ask the tab group to perform the check
|
||||
a.) Do not ask the tab group if aSkipTabGroup
|
||||
b.) This should only be done if there is no parent of the same type.
|
||||
|
||||
Return the child DocShellTreeItem with the specified name.
|
||||
name - This is the name of the item that is trying to be found.
|
||||
aRequestor - This is the object that is requesting the find. This
|
||||
parameter is used to identify when the child is asking its parent to find
|
||||
a child with the specific name. The parent uses this parameter to ensure
|
||||
a resursive state does not occur by not again asking the requestor to find
|
||||
a shell by the specified name. Inversely the child uses it to ensure it
|
||||
does not ask its parent to do the search if its parent is the one that
|
||||
asked it to search. Children also use this to test against the treeOwner;
|
||||
aOriginalRequestor - The original treeitem that made the request, if any.
|
||||
This is used to ensure that we don't run into cross-site issues.
|
||||
aSkipTabGroup - Whether the tab group should be checked.
|
||||
*/
|
||||
nsIDocShellTreeItem findItemWithName(in AString name,
|
||||
in nsIDocShellTreeItem aRequestor,
|
||||
in nsIDocShellTreeItem aOriginalRequestor,
|
||||
in bool aSkipTabGroup);
|
||||
|
||||
/*
|
||||
The owner of the DocShell Tree. This interface will be called upon when
|
||||
the docshell has things it needs to tell to the owner of the docshell.
|
||||
@ -189,3 +222,4 @@ interface nsIDocShellTreeItem : nsISupports
|
||||
[noscript,nostdcall,notxpcom] Document getDocument();
|
||||
[noscript,nostdcall,notxpcom] nsPIDOMWindowOuter getWindow();
|
||||
};
|
||||
|
||||
|
@ -136,6 +136,8 @@ skip-if = true # Bug 1220415
|
||||
[browser_click_link_within_view_source.js]
|
||||
[browser_browsingContext-01.js]
|
||||
[browser_browsingContext-02.js]
|
||||
[browser_browsingContext-03.js]
|
||||
skip-if = fission # Cross-process postMessage
|
||||
[browser_browsingContext-embedder.js]
|
||||
[browser_csp_uir.js]
|
||||
support-files =
|
||||
|
@ -110,12 +110,11 @@ add_task(async function() {
|
||||
// docShell.
|
||||
function findWithName(bc, name) {
|
||||
return content.SpecialPowers.spawn(bc, [bc, name], (bc, name) => {
|
||||
return bc.findWithName(name);
|
||||
return bc.findWithName(name, bc);
|
||||
});
|
||||
}
|
||||
|
||||
async function reachable(start, target) {
|
||||
info(start.name, target.name);
|
||||
is(
|
||||
await findWithName(start, target.name),
|
||||
target,
|
||||
|
194
docshell/test/browser/browser_browsingContext-03.js
Normal file
194
docshell/test/browser/browser_browsingContext-03.js
Normal file
@ -0,0 +1,194 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(async function() {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:blank" },
|
||||
async function(browser) {
|
||||
const BASE1 = getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"http://example.com"
|
||||
);
|
||||
const BASE2 = getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"http://test1.example.com"
|
||||
);
|
||||
const URL = BASE1 + "onload_message.html";
|
||||
let sixth = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
URL + "#sixth",
|
||||
true,
|
||||
true
|
||||
);
|
||||
await ContentTask.spawn(
|
||||
browser,
|
||||
{ base1: BASE1, base2: BASE2 },
|
||||
async function({ base1, base2 }) {
|
||||
let top = content;
|
||||
top.name = "top";
|
||||
top.location.href += "#top";
|
||||
|
||||
let contexts = {
|
||||
top: top.location.href,
|
||||
first: base1 + "dummy_page.html#first",
|
||||
third: base2 + "dummy_page.html#third",
|
||||
second: base1 + "dummy_page.html#second",
|
||||
fourth: base2 + "dummy_page.html#fourth",
|
||||
fifth: base1 + "dummy_page.html#fifth",
|
||||
sixth: base1 + "onload_message.html#sixth",
|
||||
};
|
||||
|
||||
function addFrame(target, name) {
|
||||
return content.SpecialPowers.spawn(
|
||||
target,
|
||||
[name, contexts[name]],
|
||||
async (name, context) => {
|
||||
let doc = this.content.document;
|
||||
|
||||
let frame = doc.createElement("iframe");
|
||||
doc.body.appendChild(frame);
|
||||
frame.name = name;
|
||||
frame.src = context;
|
||||
await new Promise(resolve => {
|
||||
frame.addEventListener("load", resolve, { once: true });
|
||||
});
|
||||
return frame.browsingContext;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function addWindow(target, name) {
|
||||
return content.SpecialPowers.spawn(
|
||||
target,
|
||||
[name, contexts[name]],
|
||||
(name, context) => {
|
||||
let win = this.content.open(context, name);
|
||||
let bc = win && win.docShell.browsingContext;
|
||||
|
||||
return new Promise(resolve =>
|
||||
this.content.addEventListener("message", () => resolve(bc))
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Generate all lists of length length with every combination of
|
||||
// values in input
|
||||
function* generate(input, length) {
|
||||
let list = new Array(length);
|
||||
|
||||
function* values(pos) {
|
||||
if (pos >= list.length) {
|
||||
yield list;
|
||||
} else {
|
||||
for (let v of input) {
|
||||
list[pos] = v;
|
||||
yield* values(pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
yield* values(0);
|
||||
}
|
||||
|
||||
// We're going to create a tree that looks like the
|
||||
// follwing.
|
||||
//
|
||||
// top sixth
|
||||
// / \
|
||||
// / \ /
|
||||
// first second
|
||||
// / \ /
|
||||
// / \
|
||||
// third fourth - - -
|
||||
// /
|
||||
// /
|
||||
// fifth
|
||||
//
|
||||
// The idea is to have one top level non-auxiliary browsing
|
||||
// context, five nested, one top level auxiliary with an
|
||||
// opener. Given that set of related browsing contexts we
|
||||
// wish to confirm that targeting is semantically equivalent
|
||||
// with how nsIDocShellTreeItem.findItemWithName works. The
|
||||
// trick to ensure that is to give all frames the same name!
|
||||
// and ensure that the find algorithms return the same nodes
|
||||
// in the same order.
|
||||
|
||||
let first = await addFrame(top, "first");
|
||||
let second = await addFrame(top, "second");
|
||||
let third = await addFrame(first, "third");
|
||||
let fourth = await addFrame(first, "fourth");
|
||||
let fifth = await addFrame(fourth, "fifth");
|
||||
let sixth = await addWindow(fourth, "sixth");
|
||||
|
||||
let browsingContexts = [
|
||||
BrowsingContext.getFromWindow(top),
|
||||
first,
|
||||
second,
|
||||
third,
|
||||
fourth,
|
||||
fifth,
|
||||
sixth,
|
||||
];
|
||||
let docShells = browsingContexts.map(context => context.docShell);
|
||||
|
||||
ok(
|
||||
top.docShell instanceof Ci.nsIDocShellTreeItem,
|
||||
"When we remove nsIDocShellTreeItem this test should be removed"
|
||||
);
|
||||
|
||||
// For every browsing context we generate all possible
|
||||
// combinations of names for these browsing contexts using
|
||||
// "dummy" and "target" as possible name.
|
||||
for (let names of generate(["dummy", "target"], docShells.length)) {
|
||||
for (let i = names.length - 1; i >= 0; --i) {
|
||||
docShells[i].name = names[i];
|
||||
}
|
||||
|
||||
for (let i = 0; i < docShells.length; ++i) {
|
||||
let docShell = docShells[i].findItemWithName(
|
||||
"target",
|
||||
null,
|
||||
docShells[i],
|
||||
false
|
||||
);
|
||||
let browsingContext = browsingContexts[i].findWithName(
|
||||
"target",
|
||||
browsingContexts[i]
|
||||
);
|
||||
is(
|
||||
docShell ? docShell.browsingContext : null,
|
||||
browsingContext,
|
||||
"findItemWithName should find same browsing context as findWithName"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (let target of ["_self", "_top", "_parent", "_blank"]) {
|
||||
for (let i = 0; i < docShells.length; ++i) {
|
||||
let docShell = docShells[i].findItemWithName(
|
||||
target,
|
||||
null,
|
||||
docShells[i],
|
||||
false
|
||||
);
|
||||
let browsingContext = browsingContexts[i].findWithName(
|
||||
target,
|
||||
browsingContexts[i]
|
||||
);
|
||||
is(
|
||||
docShell ? docShell.browsingContext : null,
|
||||
browsingContext,
|
||||
"findItemWithName should find same browsing context as findWithName for " +
|
||||
target
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(await sixth);
|
||||
}
|
||||
);
|
||||
});
|
@ -204,6 +204,64 @@ void TabGroup::MaybeDestroy() {
|
||||
}
|
||||
}
|
||||
|
||||
nsresult TabGroup::FindItemWithName(const nsAString& aName,
|
||||
nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem** aFoundItem) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG_POINTER(aFoundItem);
|
||||
*aFoundItem = nullptr;
|
||||
|
||||
MOZ_ASSERT(!aName.LowerCaseEqualsLiteral("_blank") &&
|
||||
!aName.LowerCaseEqualsLiteral("_top") &&
|
||||
!aName.LowerCaseEqualsLiteral("_parent") &&
|
||||
!aName.LowerCaseEqualsLiteral("_self"));
|
||||
|
||||
for (nsPIDOMWindowOuter* outerWindow : mWindows) {
|
||||
// Ignore non-toplevel windows
|
||||
if (outerWindow->GetInProcessScriptableParentOrNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> docshell = outerWindow->GetDocShell();
|
||||
if (!docshell) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BrowsingContext* bc = outerWindow->GetBrowsingContext();
|
||||
if (!bc || !bc->IsTargetable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
docshell->GetInProcessSameTypeRootTreeItem(getter_AddRefs(root));
|
||||
MOZ_RELEASE_ASSERT(docshell == root);
|
||||
if (root && aRequestor != root) {
|
||||
root->FindItemWithName(aName, aRequestor, aOriginalRequestor,
|
||||
/* aSkipTabGroup = */ true, aFoundItem);
|
||||
if (*aFoundItem) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTArray<nsPIDOMWindowOuter*> TabGroup::GetTopLevelWindows() const {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsTArray<nsPIDOMWindowOuter*> array;
|
||||
|
||||
for (nsPIDOMWindowOuter* outerWindow : mWindows) {
|
||||
if (outerWindow->GetDocShell() &&
|
||||
!outerWindow->GetInProcessScriptableParentOrNull()) {
|
||||
array.AppendElement(outerWindow);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
TabGroup::HashEntry::HashEntry(const nsACString* aKey)
|
||||
: nsCStringHashKey(aKey), mDocGroup(nullptr) {}
|
||||
|
||||
|
@ -101,6 +101,22 @@ class TabGroup final : public SchedulerGroup,
|
||||
// Count with 'aActiveOnly' = true
|
||||
uint32_t Count(bool aActiveOnly = false) const;
|
||||
|
||||
// Returns the nsIDocShellTreeItem with the given name, searching each of the
|
||||
// docShell trees which are within this TabGroup. It will pass itself as
|
||||
// aRequestor to each docShellTreeItem which it asks to search for the name,
|
||||
// and will not search the docShellTreeItem which is passed as aRequestor.
|
||||
//
|
||||
// This method is used in order to correctly namespace named windows based on
|
||||
// their unit of related browsing contexts.
|
||||
//
|
||||
// It is illegal to pass in the special case-insensitive names "_blank",
|
||||
// "_self", "_parent" or "_top", as those should be handled elsewhere.
|
||||
nsresult FindItemWithName(const nsAString& aName,
|
||||
nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem** aFoundItem);
|
||||
|
||||
nsTArray<nsPIDOMWindowOuter*> GetTopLevelWindows() const;
|
||||
const nsTArray<nsPIDOMWindowOuter*>& GetWindows() { return mWindows; }
|
||||
|
||||
// This method is always safe to call off the main thread. The nsIEventTarget
|
||||
|
@ -45,8 +45,6 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/dom/BlobURLProtocolHandler.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/BrowsingContextGroup.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/CustomElementRegistry.h"
|
||||
@ -9245,11 +9243,7 @@ bool nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel) {
|
||||
}
|
||||
|
||||
nsIDocShell* docShell = outer->GetDocShell();
|
||||
BrowsingContext* browsingContext = docShell->GetBrowsingContext();
|
||||
bool isOnlyToplevelBrowsingContext =
|
||||
!browsingContext->GetParent() &&
|
||||
browsingContext->Group()->Toplevels().Length() == 1;
|
||||
if (!isOnlyToplevelBrowsingContext) {
|
||||
if (!docShell->GetIsOnlyToplevelInTabGroup()) {
|
||||
outer->SetLargeAllocStatus(LargeAllocStatus::NOT_ONLY_TOPLEVEL_IN_TABGROUP);
|
||||
return false;
|
||||
}
|
||||
|
@ -4026,6 +4026,13 @@ bool nsGlobalWindowOuter::DispatchResizeEvent(const CSSIntSize& aSize) {
|
||||
return target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIDocShellTreeItem> GetCallerDocShellTreeItem() {
|
||||
nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
|
||||
nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
|
||||
|
||||
return callerItem.forget();
|
||||
}
|
||||
|
||||
bool nsGlobalWindowOuter::WindowExists(const nsAString& aName,
|
||||
bool aForceNoOpener,
|
||||
bool aLookForCallerOnJSStack) {
|
||||
@ -4037,7 +4044,20 @@ bool nsGlobalWindowOuter::WindowExists(const nsAString& aName,
|
||||
aName.LowerCaseEqualsLiteral("_parent");
|
||||
}
|
||||
|
||||
return !!mBrowsingContext->FindWithName(aName);
|
||||
nsCOMPtr<nsIDocShellTreeItem> caller;
|
||||
if (aLookForCallerOnJSStack) {
|
||||
caller = GetCallerDocShellTreeItem();
|
||||
}
|
||||
|
||||
if (!caller) {
|
||||
caller = mDocShell;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> namedItem;
|
||||
mDocShell->FindItemWithName(aName, nullptr, caller,
|
||||
/* aSkipTabGroup = */ false,
|
||||
getter_AddRefs(namedItem));
|
||||
return namedItem != nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIWidget> nsGlobalWindowOuter::GetMainWidget() {
|
||||
|
@ -12,7 +12,7 @@ interface BrowsingContext {
|
||||
static BrowsingContext? getFromWindow(WindowProxy window);
|
||||
|
||||
BrowsingContext? findChildWithName(DOMString name, BrowsingContext accessor);
|
||||
BrowsingContext? findWithName(DOMString name);
|
||||
BrowsingContext? findWithName(DOMString name, BrowsingContext accessor);
|
||||
|
||||
readonly attribute DOMString name;
|
||||
|
||||
|
@ -405,6 +405,20 @@ nsWebBrowser::GetInProcessSameTypeRootTreeItem(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWebBrowser::FindItemWithName(const nsAString& aName,
|
||||
nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
bool aSkipTabGroup,
|
||||
nsIDocShellTreeItem** aResult) {
|
||||
NS_ENSURE_STATE(mDocShell);
|
||||
NS_ASSERTION(mDocShellTreeOwner,
|
||||
"This should always be set when in this situation");
|
||||
|
||||
return mDocShell->FindItemWithName(aName, aRequestor, aOriginalRequestor,
|
||||
aSkipTabGroup, aResult);
|
||||
}
|
||||
|
||||
dom::Document* nsWebBrowser::GetDocument() {
|
||||
return mDocShell ? mDocShell->GetDocument() : nullptr;
|
||||
}
|
||||
|
@ -26,8 +26,6 @@
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "nsIDocumentLoader.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/BrowsingContextGroup.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
@ -1612,17 +1610,34 @@ nsWindowWatcher::GetWindowByName(const nsAString& aTargetName,
|
||||
|
||||
*aResult = nullptr;
|
||||
|
||||
BrowsingContext* currentContext =
|
||||
aCurrentWindow
|
||||
? nsPIDOMWindowOuter::From(aCurrentWindow)->GetBrowsingContext()
|
||||
: nullptr;
|
||||
nsPIDOMWindowOuter* currentWindow =
|
||||
aCurrentWindow ? nsPIDOMWindowOuter::From(aCurrentWindow) : nullptr;
|
||||
|
||||
RefPtr<BrowsingContext> context =
|
||||
GetBrowsingContextByName(aTargetName, false, currentContext);
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
||||
|
||||
if (context) {
|
||||
*aResult = context->GetDOMWindow();
|
||||
MOZ_ASSERT(*aResult);
|
||||
nsCOMPtr<nsIDocShellTreeItem> startItem;
|
||||
GetWindowTreeItem(currentWindow, getter_AddRefs(startItem));
|
||||
if (startItem) {
|
||||
// Note: original requestor is null here, per idl comments
|
||||
startItem->FindItemWithName(aTargetName, nullptr, nullptr,
|
||||
/* aSkipTabGroup = */ false,
|
||||
getter_AddRefs(treeItem));
|
||||
} else {
|
||||
if (aTargetName.LowerCaseEqualsLiteral("_blank") ||
|
||||
aTargetName.LowerCaseEqualsLiteral("_top") ||
|
||||
aTargetName.LowerCaseEqualsLiteral("_parent") ||
|
||||
aTargetName.LowerCaseEqualsLiteral("_self")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: original requestor is null here, per idl comments
|
||||
Unused << TabGroup::GetChromeTabGroup()->FindItemWithName(
|
||||
aTargetName, nullptr, nullptr, getter_AddRefs(treeItem));
|
||||
}
|
||||
|
||||
if (treeItem) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> domWindow = treeItem->GetWindow();
|
||||
domWindow.forget(aResult);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -2013,6 +2028,25 @@ int32_t nsWindowWatcher::WinHasOption(const nsACString& aOptions,
|
||||
return found;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocShellTreeItem> nsWindowWatcher::GetCallerTreeItem(
|
||||
nsIDocShellTreeItem* aParentItem) {
|
||||
nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
|
||||
nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
|
||||
if (!callerItem) {
|
||||
callerItem = aParentItem;
|
||||
}
|
||||
|
||||
return callerItem.forget();
|
||||
}
|
||||
|
||||
BrowsingContext* nsWindowWatcher::GetCallerBrowsingContext(
|
||||
BrowsingContext* aParentItem) {
|
||||
if (nsCOMPtr<nsIDocShell> caller = do_GetInterface(GetEntryGlobal())) {
|
||||
return caller->GetBrowsingContext();
|
||||
}
|
||||
return aParentItem;
|
||||
}
|
||||
|
||||
already_AddRefed<BrowsingContext> nsWindowWatcher::GetBrowsingContextByName(
|
||||
const nsAString& aName, bool aForceNoOpener,
|
||||
BrowsingContext* aCurrentContext) {
|
||||
@ -2029,8 +2063,12 @@ already_AddRefed<BrowsingContext> nsWindowWatcher::GetBrowsingContextByName(
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> currentContext(aCurrentContext);
|
||||
if (!currentContext) {
|
||||
RefPtr<BrowsingContext> caller = GetCallerBrowsingContext(aCurrentContext);
|
||||
|
||||
RefPtr<BrowsingContext> foundContext;
|
||||
if (aCurrentContext) {
|
||||
foundContext = aCurrentContext->FindWithName(aName, *caller);
|
||||
} else {
|
||||
if (aName.LowerCaseEqualsLiteral("_blank") ||
|
||||
aName.LowerCaseEqualsLiteral("_top") ||
|
||||
aName.LowerCaseEqualsLiteral("_parent") ||
|
||||
@ -2040,14 +2078,15 @@ already_AddRefed<BrowsingContext> nsWindowWatcher::GetBrowsingContextByName(
|
||||
|
||||
// If we are looking for an item and we don't have a docshell we are
|
||||
// checking on, let's just look in the chrome tab group!
|
||||
currentContext =
|
||||
BrowsingContextGroup::GetChromeGroup()->Toplevels().SafeElementAt(0);
|
||||
nsCOMPtr<nsIDocShellTreeItem> foundItem;
|
||||
Unused << TabGroup::GetChromeTabGroup()->FindItemWithName(
|
||||
aName, nullptr, caller ? caller->GetDocShell() : nullptr,
|
||||
getter_AddRefs(foundItem));
|
||||
if (foundItem) {
|
||||
foundContext = foundItem->GetBrowsingContext();
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> foundContext;
|
||||
if (currentContext) {
|
||||
foundContext = currentContext->FindWithName(aName);
|
||||
}
|
||||
return foundContext.forget();
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,14 @@ class nsWindowWatcher : public nsIWindowWatcher,
|
||||
nsWatcherWindowEntry* FindWindowEntry(mozIDOMWindowProxy* aWindow);
|
||||
nsresult RemoveWindow(nsWatcherWindowEntry* aInfo);
|
||||
|
||||
// Get the caller tree item. Look on the JS stack, then fall back
|
||||
// to the parent if there's nothing there.
|
||||
already_AddRefed<nsIDocShellTreeItem> GetCallerTreeItem(
|
||||
nsIDocShellTreeItem* aParentItem);
|
||||
|
||||
mozilla::dom::BrowsingContext* GetCallerBrowsingContext(
|
||||
mozilla::dom::BrowsingContext* aParent);
|
||||
|
||||
// Will first look for a caller on the JS stack, and then fall back on
|
||||
// aCurrentContext if it can't find one.
|
||||
// It also knows to not look for things if aForceNoOpener is set.
|
||||
|
@ -659,14 +659,11 @@ var E10SUtils = {
|
||||
// to change processes, we want to load into a new process so that we can throw
|
||||
// this one out. We don't want to move into a new process if we have post data,
|
||||
// because we would accidentally throw out that data.
|
||||
let isOnlyToplevelBrowsingContext =
|
||||
!aDocShell.browsingContext.parent &&
|
||||
aDocShell.browsingContext.group.getToplevels().length == 1;
|
||||
if (
|
||||
!aHasPostData &&
|
||||
Services.appinfo.remoteType == LARGE_ALLOCATION_REMOTE_TYPE &&
|
||||
!aDocShell.awaitingLargeAlloc &&
|
||||
isOnlyToplevelBrowsingContext
|
||||
aDocShell.isOnlyToplevelInTabGroup
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user