зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1580766 - Add a unique ID for the BrowsingContext tree inside a browser element. r=kmag
This adds a `browserId` property to all browsing contexts. This ID is the same for the entire tree of contexts inside a frame element. Each new top-level context created for a given frame also inherits this ID. This allows identifying the frame element for a given browsing context. Originally authored by :mossop in D56245. Differential Revision: https://phabricator.services.mozilla.com/D77911
This commit is contained in:
Родитель
92e1bc94a4
Коммит
1a71fed80e
|
@ -1,7 +1,35 @@
|
||||||
|
// Swaps the content of tab a into tab b and then closes tab a.
|
||||||
function swapTabsAndCloseOther(a, b) {
|
function swapTabsAndCloseOther(a, b) {
|
||||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.tabs[b], gBrowser.tabs[a]);
|
gBrowser.swapBrowsersAndCloseOther(gBrowser.tabs[b], gBrowser.tabs[a]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mirrors the effect of the above function on an array.
|
||||||
|
function swapArrayContentsAndRemoveOther(arr, a, b) {
|
||||||
|
arr[b] = arr[a];
|
||||||
|
arr.splice(a, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkBrowserIds(expected) {
|
||||||
|
is(
|
||||||
|
gBrowser.tabs.length,
|
||||||
|
expected.length,
|
||||||
|
"Should have the right number of tabs."
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let [i, tab] of gBrowser.tabs.entries()) {
|
||||||
|
is(
|
||||||
|
tab.linkedBrowser.browserId,
|
||||||
|
expected[i],
|
||||||
|
`Tab ${i} should have the right browser ID.`
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
tab.linkedBrowser.browserId,
|
||||||
|
tab.linkedBrowser.browsingContext.browserId,
|
||||||
|
`Browser for tab ${i} has the same browserId as its BrowsingContext`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var getClicks = function(tab) {
|
var getClicks = function(tab) {
|
||||||
return SpecialPowers.spawn(tab.linkedBrowser, [], function() {
|
return SpecialPowers.spawn(tab.linkedBrowser, [], function() {
|
||||||
return content.wrappedJSObject.clicks;
|
return content.wrappedJSObject.clicks;
|
||||||
|
@ -112,23 +140,40 @@ add_task(async function() {
|
||||||
);
|
);
|
||||||
await BrowserTestUtils.switchTab(gBrowser, tabs[3]);
|
await BrowserTestUtils.switchTab(gBrowser, tabs[3]);
|
||||||
|
|
||||||
swapTabsAndCloseOther(2, 3); // now: 0 1 2 4
|
let browserIds = tabs.map(t => t.linkedBrowser.browserId);
|
||||||
|
checkBrowserIds(browserIds);
|
||||||
|
|
||||||
is(gBrowser.tabs[1], tabs[1], "tab1");
|
is(gBrowser.tabs[1], tabs[1], "tab1");
|
||||||
is(gBrowser.tabs[2], tabs[3], "tab3");
|
is(gBrowser.tabs[2], tabs[2], "tab2");
|
||||||
is(gBrowser.tabs[3], tabs[4], "tab4");
|
is(gBrowser.tabs[3], tabs[3], "tab3");
|
||||||
delete tabs[2];
|
is(gBrowser.tabs[4], tabs[4], "tab4");
|
||||||
|
|
||||||
|
swapTabsAndCloseOther(2, 3); // now: 0 1 2 4
|
||||||
|
// Tab 2 is gone (what was tab 3 is displaying its content).
|
||||||
|
tabs.splice(2, 1);
|
||||||
|
swapArrayContentsAndRemoveOther(browserIds, 2, 3);
|
||||||
|
|
||||||
|
is(gBrowser.tabs[1], tabs[1], "tab1");
|
||||||
|
is(gBrowser.tabs[2], tabs[2], "tab2");
|
||||||
|
is(gBrowser.tabs[3], tabs[3], "tab4");
|
||||||
|
|
||||||
|
checkBrowserIds(browserIds);
|
||||||
|
|
||||||
info("about to cacheObjectValue");
|
info("about to cacheObjectValue");
|
||||||
await cacheObjectValue(tabs[4].linkedBrowser);
|
await cacheObjectValue(tabs[3].linkedBrowser);
|
||||||
info("just finished cacheObjectValue");
|
info("just finished cacheObjectValue");
|
||||||
|
|
||||||
swapTabsAndCloseOther(3, 2); // now: 0 1 4
|
swapTabsAndCloseOther(3, 2); // now: 0 1 4
|
||||||
|
tabs.splice(3, 1);
|
||||||
|
swapArrayContentsAndRemoveOther(browserIds, 3, 2);
|
||||||
|
|
||||||
is(
|
is(
|
||||||
Array.prototype.indexOf.call(gBrowser.tabs, gBrowser.selectedTab),
|
Array.prototype.indexOf.call(gBrowser.tabs, gBrowser.selectedTab),
|
||||||
2,
|
2,
|
||||||
"The third tab should be selected"
|
"The third tab should be selected"
|
||||||
);
|
);
|
||||||
delete tabs[4];
|
|
||||||
|
checkBrowserIds(browserIds);
|
||||||
|
|
||||||
ok(
|
ok(
|
||||||
await checkObjectValue(gBrowser.tabs[2].linkedBrowser),
|
await checkObjectValue(gBrowser.tabs[2].linkedBrowser),
|
||||||
|
@ -136,15 +181,19 @@ add_task(async function() {
|
||||||
);
|
);
|
||||||
|
|
||||||
is(gBrowser.tabs[1], tabs[1], "tab1");
|
is(gBrowser.tabs[1], tabs[1], "tab1");
|
||||||
is(gBrowser.tabs[2], tabs[3], "tab4");
|
is(gBrowser.tabs[2], tabs[2], "tab4");
|
||||||
|
|
||||||
let clicks = await getClicks(gBrowser.tabs[2]);
|
let clicks = await getClicks(gBrowser.tabs[2]);
|
||||||
is(clicks, 0, "no click on BODY so far");
|
is(clicks, 0, "no click on BODY so far");
|
||||||
await clickTest(gBrowser.tabs[2]);
|
await clickTest(gBrowser.tabs[2]);
|
||||||
|
|
||||||
swapTabsAndCloseOther(2, 1); // now: 0 4
|
swapTabsAndCloseOther(2, 1); // now: 0 4
|
||||||
is(gBrowser.tabs[1], tabs[1], "tab1");
|
tabs.splice(2, 1);
|
||||||
delete tabs[3];
|
swapArrayContentsAndRemoveOther(browserIds, 2, 1);
|
||||||
|
|
||||||
|
is(gBrowser.tabs[1], tabs[1], "tab4");
|
||||||
|
|
||||||
|
checkBrowserIds(browserIds);
|
||||||
|
|
||||||
ok(
|
ok(
|
||||||
await checkObjectValue(gBrowser.tabs[1].linkedBrowser),
|
await checkObjectValue(gBrowser.tabs[1].linkedBrowser),
|
||||||
|
@ -175,9 +224,14 @@ add_task(async function() {
|
||||||
await loadURI(tabs[1], "about:blank");
|
await loadURI(tabs[1], "about:blank");
|
||||||
let key = tabs[1].linkedBrowser.permanentKey;
|
let key = tabs[1].linkedBrowser.permanentKey;
|
||||||
|
|
||||||
|
checkBrowserIds(browserIds);
|
||||||
|
|
||||||
let win = gBrowser.replaceTabWithWindow(tabs[1]);
|
let win = gBrowser.replaceTabWithWindow(tabs[1]);
|
||||||
await new Promise(resolve => whenDelayedStartupFinished(win, resolve));
|
await new Promise(resolve => whenDelayedStartupFinished(win, resolve));
|
||||||
delete tabs[1];
|
|
||||||
|
let newWinBrowserId = browserIds[1];
|
||||||
|
browserIds.splice(1, 1);
|
||||||
|
checkBrowserIds(browserIds);
|
||||||
|
|
||||||
// Verify that the original window now only has the initial tab left in it.
|
// Verify that the original window now only has the initial tab left in it.
|
||||||
is(gBrowser.tabs[0], tabs[0], "tab0");
|
is(gBrowser.tabs[0], tabs[0], "tab0");
|
||||||
|
@ -185,6 +239,12 @@ add_task(async function() {
|
||||||
|
|
||||||
let tab = win.gBrowser.tabs[0];
|
let tab = win.gBrowser.tabs[0];
|
||||||
is(tab.linkedBrowser.permanentKey, key, "Should have kept the key");
|
is(tab.linkedBrowser.permanentKey, key, "Should have kept the key");
|
||||||
|
is(tab.linkedBrowser.browserId, newWinBrowserId, "Should have kept the ID");
|
||||||
|
is(
|
||||||
|
tab.linkedBrowser.browserId,
|
||||||
|
tab.linkedBrowser.browsingContext.browserId,
|
||||||
|
"Should have kept the ID"
|
||||||
|
);
|
||||||
|
|
||||||
let awaitPageShow = BrowserTestUtils.waitForContentEvent(
|
let awaitPageShow = BrowserTestUtils.waitForContentEvent(
|
||||||
tab.linkedBrowser,
|
tab.linkedBrowser,
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "mozilla/dom/WindowGlobalParent.h"
|
#include "mozilla/dom/WindowGlobalParent.h"
|
||||||
#include "mozilla/dom/WindowProxyHolder.h"
|
#include "mozilla/dom/WindowProxyHolder.h"
|
||||||
#include "mozilla/dom/SyncedContextInlines.h"
|
#include "mozilla/dom/SyncedContextInlines.h"
|
||||||
|
#include "mozilla/dom/XULFrameElement.h"
|
||||||
#include "mozilla/net/DocumentLoadListener.h"
|
#include "mozilla/net/DocumentLoadListener.h"
|
||||||
#include "mozilla/net/RequestContextService.h"
|
#include "mozilla/net/RequestContextService.h"
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
|
@ -50,6 +51,7 @@
|
||||||
#include "nsGlobalWindowOuter.h"
|
#include "nsGlobalWindowOuter.h"
|
||||||
#include "nsIObserverService.h"
|
#include "nsIObserverService.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsQueryObject.h"
|
||||||
#include "nsSandboxFlags.h"
|
#include "nsSandboxFlags.h"
|
||||||
#include "nsScriptError.h"
|
#include "nsScriptError.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
@ -187,10 +189,14 @@ bool BrowsingContext::SameOriginWithTop() {
|
||||||
/* static */
|
/* static */
|
||||||
already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
|
already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
|
||||||
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
|
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
|
||||||
const nsAString& aName, Type aType) {
|
const nsAString& aName, Type aType, uint64_t aBrowserId) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!aParent ||
|
if (aParent) {
|
||||||
aParent->GetBrowsingContext()->mType == aType);
|
MOZ_DIAGNOSTIC_ASSERT(aParent->GetWindowContext());
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->GetWindowContext());
|
MOZ_DIAGNOSTIC_ASSERT(aParent->GetBrowsingContext()->mType == aType);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(aParent->GetBrowsingContext()->GetBrowserId() == 0 ||
|
||||||
|
aParent->GetBrowsingContext()->GetBrowserId() ==
|
||||||
|
aBrowserId);
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aType != Type::Chrome || XRE_IsParentProcess());
|
MOZ_DIAGNOSTIC_ASSERT(aType != Type::Chrome || XRE_IsParentProcess());
|
||||||
|
|
||||||
|
@ -232,6 +238,7 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
|
||||||
context->mFields.SetWithoutSyncing<IDX_OpenerId>(aOpener->Id());
|
context->mFields.SetWithoutSyncing<IDX_OpenerId>(aOpener->Id());
|
||||||
context->mFields.SetWithoutSyncing<IDX_HadOriginalOpener>(true);
|
context->mFields.SetWithoutSyncing<IDX_HadOriginalOpener>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aParent) {
|
if (aParent) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(parentBC->Group() == context->Group());
|
MOZ_DIAGNOSTIC_ASSERT(parentBC->Group() == context->Group());
|
||||||
MOZ_DIAGNOSTIC_ASSERT(parentBC->mType == context->mType);
|
MOZ_DIAGNOSTIC_ASSERT(parentBC->mType == context->mType);
|
||||||
|
@ -244,6 +251,8 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
|
||||||
context->mFields.SetWithoutSyncing<IDX_OpenerPolicy>(
|
context->mFields.SetWithoutSyncing<IDX_OpenerPolicy>(
|
||||||
nsILoadInfo::OPENER_POLICY_UNSAFE_NONE);
|
nsILoadInfo::OPENER_POLICY_UNSAFE_NONE);
|
||||||
|
|
||||||
|
context->mFields.SetWithoutSyncing<IDX_BrowserId>(aBrowserId);
|
||||||
|
|
||||||
if (aOpener && aOpener->SameOriginWithTop()) {
|
if (aOpener && aOpener->SameOriginWithTop()) {
|
||||||
// We inherit the opener policy if there is a creator and if the creator's
|
// We inherit the opener policy if there is a creator and if the creator's
|
||||||
// origin is same origin with the creator's top-level origin.
|
// origin is same origin with the creator's top-level origin.
|
||||||
|
@ -327,8 +336,10 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
|
||||||
|
|
||||||
already_AddRefed<BrowsingContext> BrowsingContext::CreateIndependent(
|
already_AddRefed<BrowsingContext> BrowsingContext::CreateIndependent(
|
||||||
Type aType) {
|
Type aType) {
|
||||||
|
uint64_t browserId =
|
||||||
|
aType == Type::Content ? nsContentUtils::GenerateBrowserId() : 0;
|
||||||
RefPtr<BrowsingContext> bc(
|
RefPtr<BrowsingContext> bc(
|
||||||
CreateDetached(nullptr, nullptr, EmptyString(), aType));
|
CreateDetached(nullptr, nullptr, EmptyString(), aType, browserId));
|
||||||
bc->mWindowless = bc->IsContent();
|
bc->mWindowless = bc->IsContent();
|
||||||
bc->EnsureAttached();
|
bc->EnsureAttached();
|
||||||
return bc.forget();
|
return bc.forget();
|
||||||
|
@ -500,6 +511,29 @@ static bool OwnerAllowsFullscreen(const Element& aEmbedder) {
|
||||||
void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
|
void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
|
||||||
mEmbeddedByThisProcess = true;
|
mEmbeddedByThisProcess = true;
|
||||||
|
|
||||||
|
// Update the browser ID on the embedder if necessary. We currently don't care
|
||||||
|
// about browser IDs for chrome-type BrowsingContexts.
|
||||||
|
if (RefPtr<nsFrameLoaderOwner> owner = do_QueryObject(aEmbedder);
|
||||||
|
owner && !IsChrome()) {
|
||||||
|
uint64_t browserId = GetBrowserId();
|
||||||
|
uint64_t frameBrowserId = owner->GetBrowserId();
|
||||||
|
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(browserId != 0);
|
||||||
|
|
||||||
|
if (frameBrowserId == 0) {
|
||||||
|
// We'll arrive here if we're a top-level BrowsingContext for a window
|
||||||
|
// or tab that was opened in a content process. There should be no
|
||||||
|
// children to update at this point. This ID was generated in
|
||||||
|
// ContentChild::ProvideWindowCommon.
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(IsTopContent());
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(Children().IsEmpty());
|
||||||
|
owner->SetBrowserId(browserId);
|
||||||
|
} else {
|
||||||
|
// We would've inherited or generated an ID in CreateBrowsingContext.
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(browserId == frameBrowserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update embedder-element-specific fields in a shared transaction.
|
// Update embedder-element-specific fields in a shared transaction.
|
||||||
// Don't do this when clearing our embedder, as we're being destroyed either
|
// Don't do this when clearing our embedder, as we're being destroyed either
|
||||||
// way.
|
// way.
|
||||||
|
@ -2402,6 +2436,13 @@ void BrowsingContext::DidSet(FieldIndex<IDX_HasSessionHistory>,
|
||||||
CreateChildSHistory();
|
CreateChildSHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BrowsingContext::CanSet(FieldIndex<IDX_BrowserId>, const uint32_t& aValue,
|
||||||
|
ContentParent* aSource) {
|
||||||
|
// We should only be able to set this for toplevel contexts which don't have
|
||||||
|
// an ID yet.
|
||||||
|
return GetBrowserId() == 0 && IsTop() && Children().IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
|
|
@ -107,6 +107,13 @@ class WindowProxyHolder;
|
||||||
FIELD(FeaturePolicy, RefPtr<mozilla::dom::FeaturePolicy>) \
|
FIELD(FeaturePolicy, RefPtr<mozilla::dom::FeaturePolicy>) \
|
||||||
/* See nsSandboxFlags.h for the possible flags. */ \
|
/* See nsSandboxFlags.h for the possible flags. */ \
|
||||||
FIELD(SandboxFlags, uint32_t) \
|
FIELD(SandboxFlags, uint32_t) \
|
||||||
|
/* A unique identifier for the browser element that is hosting this \
|
||||||
|
* BrowsingContext tree. Every BrowsingContext in the element's tree will \
|
||||||
|
* return the same ID in all processes and it will remain stable \
|
||||||
|
* regardless of process changes. When a browser element's frameloader is \
|
||||||
|
* switched to another browser element this ID will remain the same but \
|
||||||
|
* hosted under the under the new browser element. */ \
|
||||||
|
FIELD(BrowserId, uint64_t) \
|
||||||
FIELD(HistoryID, nsID) \
|
FIELD(HistoryID, nsID) \
|
||||||
FIELD(InRDMPane, bool) \
|
FIELD(InRDMPane, bool) \
|
||||||
FIELD(Loading, bool) \
|
FIELD(Loading, bool) \
|
||||||
|
@ -198,7 +205,7 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||||
// DocShell, BrowserParent, or BrowserBridgeChild.
|
// DocShell, BrowserParent, or BrowserBridgeChild.
|
||||||
static already_AddRefed<BrowsingContext> CreateDetached(
|
static already_AddRefed<BrowsingContext> CreateDetached(
|
||||||
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
|
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
|
||||||
const nsAString& aName, Type aType);
|
const nsAString& aName, Type aType, uint64_t aBrowserId);
|
||||||
|
|
||||||
void EnsureAttached();
|
void EnsureAttached();
|
||||||
|
|
||||||
|
@ -396,6 +403,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||||
|
|
||||||
bool UseGlobalHistory() const { return GetUseGlobalHistory(); }
|
bool UseGlobalHistory() const { return GetUseGlobalHistory(); }
|
||||||
|
|
||||||
|
uint64_t BrowserId() const { return GetBrowserId(); }
|
||||||
|
|
||||||
bool IsLoading();
|
bool IsLoading();
|
||||||
|
|
||||||
// ScreenOrientation related APIs
|
// ScreenOrientation related APIs
|
||||||
|
@ -763,6 +772,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||||
|
|
||||||
void DidSet(FieldIndex<IDX_HasSessionHistory>, bool aOldValue);
|
void DidSet(FieldIndex<IDX_HasSessionHistory>, bool aOldValue);
|
||||||
|
|
||||||
|
bool CanSet(FieldIndex<IDX_BrowserId>, const uint32_t& aValue,
|
||||||
|
ContentParent* aSource);
|
||||||
|
|
||||||
template <size_t I, typename T>
|
template <size_t I, typename T>
|
||||||
bool CanSet(FieldIndex<I>, const T&, ContentParent*) {
|
bool CanSet(FieldIndex<I>, const T&, ContentParent*) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -28,7 +28,7 @@ add_task(async function() {
|
||||||
true,
|
true,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
await SpecialPowers.spawn(
|
let browserIds = await SpecialPowers.spawn(
|
||||||
browser,
|
browser,
|
||||||
[{ base1: BASE1, base2: BASE2 }],
|
[{ base1: BASE1, base2: BASE2 }],
|
||||||
async function({ base1, base2 }) {
|
async function({ base1, base2 }) {
|
||||||
|
@ -172,10 +172,58 @@ add_task(async function() {
|
||||||
}
|
}
|
||||||
await unreachable(start, seventh);
|
await unreachable(start, seventh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let topBrowserId = topBC.browserId;
|
||||||
|
ok(topBrowserId > 0, "Should have a browser ID.");
|
||||||
|
for (let [name, bc] of Object.entries({
|
||||||
|
first,
|
||||||
|
second,
|
||||||
|
third,
|
||||||
|
fourth,
|
||||||
|
fifth,
|
||||||
|
})) {
|
||||||
|
is(
|
||||||
|
bc.browserId,
|
||||||
|
topBrowserId,
|
||||||
|
`${name} frame should have the same browserId as top.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(sixth.browserId > 0, "sixth should have a browserId.");
|
||||||
|
isnot(
|
||||||
|
sixth.browserId,
|
||||||
|
topBrowserId,
|
||||||
|
"sixth frame should have a different browserId to top."
|
||||||
|
);
|
||||||
|
|
||||||
|
return [topBrowserId, sixth.browserId];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let tab of await Promise.all([sixth, seventh])) {
|
[sixth, seventh] = await Promise.all([sixth, seventh]);
|
||||||
|
|
||||||
|
is(
|
||||||
|
browser.browserId,
|
||||||
|
browserIds[0],
|
||||||
|
"browser should have the right browserId."
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
browser.browsingContext.browserId,
|
||||||
|
browserIds[0],
|
||||||
|
"browser's BrowsingContext should have the right browserId."
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
sixth.linkedBrowser.browserId,
|
||||||
|
browserIds[1],
|
||||||
|
"sixth should have the right browserId."
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
sixth.linkedBrowser.browsingContext.browserId,
|
||||||
|
browserIds[1],
|
||||||
|
"sixth's BrowsingContext should have the right browserId."
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let tab of [sixth, seventh]) {
|
||||||
BrowserTestUtils.removeTab(tab);
|
BrowserTestUtils.removeTab(tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9716,6 +9716,14 @@ uint64_t nsContentUtils::GenerateTabId() {
|
||||||
return GenerateProcessSpecificId(++gNextTabId);
|
return GenerateProcessSpecificId(++gNextTabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Next process-local Browser ID.
|
||||||
|
static uint64_t gNextBrowserId = 0;
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
uint64_t nsContentUtils::GenerateBrowserId() {
|
||||||
|
return GenerateProcessSpecificId(++gNextBrowserId);
|
||||||
|
}
|
||||||
|
|
||||||
// Next process-local Browsing Context ID.
|
// Next process-local Browsing Context ID.
|
||||||
static uint64_t gNextBrowsingContextId = 0;
|
static uint64_t gNextBrowsingContextId = 0;
|
||||||
|
|
||||||
|
|
|
@ -3142,6 +3142,11 @@ class nsContentUtils {
|
||||||
*/
|
*/
|
||||||
static uint64_t GenerateTabId();
|
static uint64_t GenerateTabId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose a browser id with process id and a serial number.
|
||||||
|
*/
|
||||||
|
static uint64_t GenerateBrowserId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an id for a BrowsingContext using a range of serial
|
* Generate an id for a BrowsingContext using a range of serial
|
||||||
* numbers reserved for the current process.
|
* numbers reserved for the current process.
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
#include "mozilla/dom/MozFrameLoaderOwnerBinding.h"
|
#include "mozilla/dom/MozFrameLoaderOwnerBinding.h"
|
||||||
#include "mozilla/dom/SessionStoreListener.h"
|
#include "mozilla/dom/SessionStoreListener.h"
|
||||||
#include "mozilla/dom/WindowGlobalParent.h"
|
#include "mozilla/dom/WindowGlobalParent.h"
|
||||||
|
#include "mozilla/dom/XULFrameElement.h"
|
||||||
#include "mozilla/gfx/CrossProcessPaint.h"
|
#include "mozilla/gfx/CrossProcessPaint.h"
|
||||||
#include "nsGenericHTMLFrameElement.h"
|
#include "nsGenericHTMLFrameElement.h"
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
|
@ -295,6 +296,10 @@ static already_AddRefed<BrowsingContext> CreateBrowsingContext(
|
||||||
nsAutoString frameName;
|
nsAutoString frameName;
|
||||||
GetFrameName(aOwner, frameName);
|
GetFrameName(aOwner, frameName);
|
||||||
|
|
||||||
|
// By default we just use the same browser ID as the parent.
|
||||||
|
uint64_t browserId = parentBC->GetBrowserId();
|
||||||
|
RefPtr<nsFrameLoaderOwner> owner = do_QueryObject(aOwner);
|
||||||
|
|
||||||
// Create our BrowsingContext without immediately attaching it. It's possible
|
// Create our BrowsingContext without immediately attaching it. It's possible
|
||||||
// that no DocShell or remote browser will ever be created for this
|
// that no DocShell or remote browser will ever be created for this
|
||||||
// FrameLoader, particularly if the document that we were created for is not
|
// FrameLoader, particularly if the document that we were created for is not
|
||||||
|
@ -302,16 +307,38 @@ static already_AddRefed<BrowsingContext> CreateBrowsingContext(
|
||||||
// it will wind up attached as a child of the currently active inner window
|
// it will wind up attached as a child of the currently active inner window
|
||||||
// for the BrowsingContext, and cause no end of trouble.
|
// for the BrowsingContext, and cause no end of trouble.
|
||||||
if (IsTopContent(parentBC, aOwner)) {
|
if (IsTopContent(parentBC, aOwner)) {
|
||||||
|
if (owner && owner->GetBrowserId() != 0) {
|
||||||
|
// This frame has already been assigned an ID. This can happen for example
|
||||||
|
// if a frame is re-inserted into the DOM (i.e. on a remoteness change).
|
||||||
|
browserId = owner->GetBrowserId();
|
||||||
|
|
||||||
|
// This implies that we do not support changing a frame's "type"
|
||||||
|
// attribute. Doing so would mean needing to change the browser ID for the
|
||||||
|
// frame and the intent is to never change this.
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(browserId != parentBC->GetBrowserId());
|
||||||
|
} else {
|
||||||
|
browserId = nsContentUtils::GenerateBrowserId();
|
||||||
|
if (owner) {
|
||||||
|
owner->SetBrowserId(browserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create toplevel content without a parent & as Type::Content.
|
// Create toplevel content without a parent & as Type::Content.
|
||||||
return BrowsingContext::CreateDetached(nullptr, opener, frameName,
|
return BrowsingContext::CreateDetached(
|
||||||
BrowsingContext::Type::Content);
|
nullptr, opener, frameName, BrowsingContext::Type::Content, browserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(!aOpenWindowInfo,
|
MOZ_ASSERT(!aOpenWindowInfo,
|
||||||
"Can't have openWindowInfo for non-toplevel context");
|
"Can't have openWindowInfo for non-toplevel context");
|
||||||
|
|
||||||
|
if (owner) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(owner->GetBrowserId() == 0 ||
|
||||||
|
owner->GetBrowserId() == browserId);
|
||||||
|
owner->SetBrowserId(browserId);
|
||||||
|
}
|
||||||
|
|
||||||
return BrowsingContext::CreateDetached(parentInner, nullptr, frameName,
|
return BrowsingContext::CreateDetached(parentInner, nullptr, frameName,
|
||||||
parentBC->GetType());
|
parentBC->GetType(), browserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool InitialLoadIsRemote(Element* aOwner) {
|
static bool InitialLoadIsRemote(Element* aOwner) {
|
||||||
|
@ -1294,6 +1321,13 @@ nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
|
||||||
MaybeUpdatePrimaryBrowserParent(eBrowserParentRemoved);
|
MaybeUpdatePrimaryBrowserParent(eBrowserParentRemoved);
|
||||||
aOther->MaybeUpdatePrimaryBrowserParent(eBrowserParentRemoved);
|
aOther->MaybeUpdatePrimaryBrowserParent(eBrowserParentRemoved);
|
||||||
|
|
||||||
|
// When embedding the frame in SetOwnerContent, we check that the
|
||||||
|
// BrowsingContext's browser ID matches that of the embedder element, so swap
|
||||||
|
// the IDs here.
|
||||||
|
uint64_t ourBrowserId = aThisOwner->GetBrowserId();
|
||||||
|
aThisOwner->SetBrowserId(aOtherOwner->GetBrowserId());
|
||||||
|
aOtherOwner->SetBrowserId(ourBrowserId);
|
||||||
|
|
||||||
SetOwnerContent(otherContent);
|
SetOwnerContent(otherContent);
|
||||||
aOther->SetOwnerContent(ourContent);
|
aOther->SetOwnerContent(ourContent);
|
||||||
|
|
||||||
|
@ -1708,6 +1742,13 @@ nsresult nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||||
otherDocshell, ourOwner,
|
otherDocshell, ourOwner,
|
||||||
ourBc->IsContent() ? ourChromeEventHandler.get() : nullptr);
|
ourBc->IsContent() ? ourChromeEventHandler.get() : nullptr);
|
||||||
|
|
||||||
|
// When embedding the frame in SetOwnerContent, we check that the
|
||||||
|
// BrowsingContext's browser ID matches that of the embedder element, so swap
|
||||||
|
// the IDs here.
|
||||||
|
uint64_t ourBrowserId = aThisOwner->GetBrowserId();
|
||||||
|
aThisOwner->SetBrowserId(aOtherOwner->GetBrowserId());
|
||||||
|
aOtherOwner->SetBrowserId(ourBrowserId);
|
||||||
|
|
||||||
// Switch the owner content before we start calling AddTreeItemToTreeOwner.
|
// Switch the owner content before we start calling AddTreeItemToTreeOwner.
|
||||||
// Note that we rely on this to deal with setting mObservingOwnerContent to
|
// Note that we rely on this to deal with setting mObservingOwnerContent to
|
||||||
// false and calling RemoveMutationObserver as needed.
|
// false and calling RemoveMutationObserver as needed.
|
||||||
|
|
|
@ -286,3 +286,9 @@ void nsFrameLoaderOwner::SubframeCrashed() {
|
||||||
/* inProgress */ false,
|
/* inProgress */ false,
|
||||||
/* isRemote */ false, frameLoaderInit, IgnoreErrors());
|
/* isRemote */ false, frameLoaderInit, IgnoreErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsFrameLoaderOwner::UnbindFromTree() {
|
||||||
|
// If we're being adopted into a different document, we'll want to inherit a
|
||||||
|
// browser ID from our new BrowsingContext, so clear our current ID here.
|
||||||
|
mBrowserId = 0;
|
||||||
|
}
|
||||||
|
|
|
@ -74,6 +74,12 @@ class nsFrameLoaderOwner : public nsISupports {
|
||||||
|
|
||||||
void SubframeCrashed();
|
void SubframeCrashed();
|
||||||
|
|
||||||
|
// Prepare for a frame to be removed from its current DOM tree.
|
||||||
|
void UnbindFromTree();
|
||||||
|
|
||||||
|
uint64_t GetBrowserId() { return mBrowserId; }
|
||||||
|
void SetBrowserId(uint64_t aBrowserId) { mBrowserId = aBrowserId; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool UseRemoteSubframes();
|
bool UseRemoteSubframes();
|
||||||
|
|
||||||
|
@ -99,6 +105,8 @@ class nsFrameLoaderOwner : public nsISupports {
|
||||||
std::function<void()>& aFrameLoaderInit,
|
std::function<void()>& aFrameLoaderInit,
|
||||||
mozilla::ErrorResult& aRv);
|
mozilla::ErrorResult& aRv);
|
||||||
|
|
||||||
|
uint64_t mBrowserId = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~nsFrameLoaderOwner() = default;
|
virtual ~nsFrameLoaderOwner() = default;
|
||||||
RefPtr<nsFrameLoader> mFrameLoader;
|
RefPtr<nsFrameLoader> mFrameLoader;
|
||||||
|
|
|
@ -568,6 +568,7 @@ nsresult nsObjectLoadingContent::BindToTree(BindContext& aContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsObjectLoadingContent::UnbindFromTree(bool aNullParent) {
|
void nsObjectLoadingContent::UnbindFromTree(bool aNullParent) {
|
||||||
|
nsFrameLoaderOwner::UnbindFromTree();
|
||||||
nsImageLoadingContent::UnbindFromTree(aNullParent);
|
nsImageLoadingContent::UnbindFromTree(aNullParent);
|
||||||
|
|
||||||
nsCOMPtr<Element> thisElement =
|
nsCOMPtr<Element> thisElement =
|
||||||
|
|
|
@ -105,6 +105,16 @@ interface BrowsingContext {
|
||||||
// The watchedByDevTools flag indicates whether or not DevTools are currently
|
// The watchedByDevTools flag indicates whether or not DevTools are currently
|
||||||
// debugging this browsing context.
|
// debugging this browsing context.
|
||||||
[SetterThrows] attribute boolean watchedByDevTools;
|
[SetterThrows] attribute boolean watchedByDevTools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique identifier for the browser element that is hosting this
|
||||||
|
* BrowsingContext tree. Every BrowsingContext in the element's tree will
|
||||||
|
* return the same ID in all processes and it will remain stable regardless of
|
||||||
|
* process changes. When a browser element's frameloader is switched to
|
||||||
|
* another browser element this ID will remain the same but hosted under the
|
||||||
|
* under the new browser element.
|
||||||
|
*/
|
||||||
|
attribute unsigned long long browserId;
|
||||||
};
|
};
|
||||||
|
|
||||||
BrowsingContext includes LoadContextMixin;
|
BrowsingContext includes LoadContextMixin;
|
||||||
|
|
|
@ -16,7 +16,9 @@ interface XULFrameElement : XULElement
|
||||||
readonly attribute nsIWebNavigation? webNavigation;
|
readonly attribute nsIWebNavigation? webNavigation;
|
||||||
|
|
||||||
readonly attribute WindowProxy? contentWindow;
|
readonly attribute WindowProxy? contentWindow;
|
||||||
readonly attribute Document? contentDocument;
|
readonly attribute Document? contentDocument;
|
||||||
|
|
||||||
|
readonly attribute unsigned long long browserId;
|
||||||
};
|
};
|
||||||
|
|
||||||
XULFrameElement includes MozFrameLoaderOwner;
|
XULFrameElement includes MozFrameLoaderOwner;
|
||||||
|
|
|
@ -208,6 +208,7 @@ void nsGenericHTMLFrameElement::UnbindFromTree(bool aNullParent) {
|
||||||
mFrameLoader = nullptr;
|
mFrameLoader = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsFrameLoaderOwner::UnbindFromTree();
|
||||||
nsGenericHTMLElement::UnbindFromTree(aNullParent);
|
nsGenericHTMLElement::UnbindFromTree(aNullParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -949,8 +949,9 @@ nsresult ContentChild::ProvideWindowCommon(
|
||||||
openerBC = parent;
|
openerBC = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t browserId(nsContentUtils::GenerateBrowserId());
|
||||||
RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateDetached(
|
RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateDetached(
|
||||||
nullptr, openerBC, aName, BrowsingContext::Type::Content);
|
nullptr, openerBC, aName, BrowsingContext::Type::Content, browserId);
|
||||||
MOZ_ALWAYS_SUCCEEDS(browsingContext->SetRemoteTabs(true));
|
MOZ_ALWAYS_SUCCEEDS(browsingContext->SetRemoteTabs(true));
|
||||||
MOZ_ALWAYS_SUCCEEDS(browsingContext->SetRemoteSubframes(useRemoteSubframes));
|
MOZ_ALWAYS_SUCCEEDS(browsingContext->SetRemoteSubframes(useRemoteSubframes));
|
||||||
MOZ_ALWAYS_SUCCEEDS(browsingContext->SetOriginAttributes(
|
MOZ_ALWAYS_SUCCEEDS(browsingContext->SetOriginAttributes(
|
||||||
|
|
|
@ -154,6 +154,7 @@ void XULFrameElement::UnbindFromTree(bool aNullParent) {
|
||||||
}
|
}
|
||||||
mFrameLoader = nullptr;
|
mFrameLoader = nullptr;
|
||||||
|
|
||||||
|
nsFrameLoaderOwner::UnbindFromTree();
|
||||||
nsXULElement::UnbindFromTree(aNullParent);
|
nsXULElement::UnbindFromTree(aNullParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ class XULFrameElement final : public nsXULElement, public nsFrameLoaderOwner {
|
||||||
already_AddRefed<nsIWebNavigation> GetWebNavigation();
|
already_AddRefed<nsIWebNavigation> GetWebNavigation();
|
||||||
Nullable<WindowProxyHolder> GetContentWindow();
|
Nullable<WindowProxyHolder> GetContentWindow();
|
||||||
Document* GetContentDocument();
|
Document* GetContentDocument();
|
||||||
|
uint64_t BrowserId() { return GetBrowserId(); }
|
||||||
|
|
||||||
void SwapFrameLoaders(mozilla::dom::HTMLIFrameElement& aOtherLoaderOwner,
|
void SwapFrameLoaders(mozilla::dom::HTMLIFrameElement& aOtherLoaderOwner,
|
||||||
mozilla::ErrorResult& rv);
|
mozilla::ErrorResult& rv);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче