Bug 1529684 - Part 1: Allow Attaching BrowsingContext from parent to child, r=farre

This is important to allow creating BrowsingContexts outside of the process
where they are going to be used. This is largely a re-arrangement of existing
code.

There is currently no way to do this type of attaching for browsing contexts in
existing BrowsingContextGroups, which creates some limitations, but happens to
be sufficient for us in the current situation.

Differential Revision: https://phabricator.services.mozilla.com/D21095

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nika Layzell 2019-03-05 17:33:19 +00:00
Родитель c6a1e051a4
Коммит 95cc8c68c0
6 изменённых файлов: 90 добавлений и 64 удалений

Просмотреть файл

@ -58,20 +58,6 @@ static void Register(BrowsingContext* aBrowsingContext) {
aBrowsingContext->Group()->Register(aBrowsingContext);
}
static void Sync(BrowsingContext* aBrowsingContext) {
if (!XRE_IsContentProcess()) {
return;
}
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
BrowsingContext* opener = aBrowsingContext->GetOpener();
cc->SendAttachBrowsingContext(parent, opener,
BrowsingContextId(aBrowsingContext->Id()),
aBrowsingContext->Name());
}
BrowsingContext* BrowsingContext::TopLevelBrowsingContext() {
BrowsingContext* bc = this;
while (bc->mParent) {
@ -161,7 +147,7 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateFromIPC(
Register(context);
context->Attach();
// Caller handles attaching us to the tree.
return context.forget();
}
@ -197,7 +183,7 @@ void BrowsingContext::SetDocShell(nsIDocShell* aDocShell) {
mDocShell = aDocShell;
}
void BrowsingContext::Attach() {
void BrowsingContext::Attach(bool aFromIPC) {
MOZ_LOG(GetLog(), LogLevel::Debug,
("%s: %s 0x%08" PRIx64 " to 0x%08" PRIx64,
XRE_IsParentProcess() ? "Parent" : "Child",
@ -211,10 +197,16 @@ void BrowsingContext::Attach() {
children->AppendElement(this);
Sync(this);
// Send attach to our parent if we need to.
if (!aFromIPC && XRE_IsContentProcess()) {
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendAttachBrowsingContext(
mParent, mOpener, BrowsingContextId(mBrowsingContextId), Name());
}
}
void BrowsingContext::Detach() {
void BrowsingContext::Detach(bool aFromIPC) {
MOZ_LOG(GetLog(), LogLevel::Debug,
("%s: Detaching 0x%08" PRIx64 " from 0x%08" PRIx64,
XRE_IsParentProcess() ? "Parent" : "Child", Id(),
@ -242,16 +234,14 @@ void BrowsingContext::Detach() {
Group()->Unregister(this);
if (!XRE_IsContentProcess()) {
return;
if (!aFromIPC && XRE_IsContentProcess()) {
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendDetachBrowsingContext(this, false /* aMoveToBFCache */);
}
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendDetachBrowsingContext(this, false /* aMoveToBFCache */);
}
void BrowsingContext::CacheChildren() {
void BrowsingContext::CacheChildren(bool aFromIPC) {
if (mChildren.IsEmpty()) {
return;
}
@ -267,13 +257,11 @@ void BrowsingContext::CacheChildren() {
}
mChildren.Clear();
if (!XRE_IsContentProcess()) {
return;
if (!aFromIPC && XRE_IsContentProcess()) {
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendDetachBrowsingContext(this, true /* aMoveToBFCache */);
}
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendDetachBrowsingContext(this, true /* aMoveToBFCache */);
}
bool BrowsingContext::IsCached() { return sCachedBrowsingContexts->has(Id()); }

Просмотреть файл

@ -178,15 +178,15 @@ class BrowsingContext : public nsWrapperCache,
// parent process. BrowsingContext objects are created attached by default, so
// this method need only be called when restoring cached BrowsingContext
// objects.
void Attach();
void Attach(bool aFromIPC = false);
// Detach the current BrowsingContext from its parent, in both the
// child and the parent process.
void Detach();
void Detach(bool aFromIPC = false);
// Remove all children from the current BrowsingContext and cache
// them to allow them to be attached again.
void CacheChildren();
void CacheChildren(bool aFromIPC = false);
// Determine if the current BrowsingContext was 'cached' by the logic in
// CacheChildren.

Просмотреть файл

@ -3679,6 +3679,35 @@ PContentChild::Result ContentChild::OnMessageReceived(const Message& aMsg,
return result;
}
mozilla::ipc::IPCResult ContentChild::RecvAttachBrowsingContext(
BrowsingContext* aParent, BrowsingContext* aOpener,
BrowsingContextId aChildId, const nsString& aName) {
RefPtr<BrowsingContext> child = BrowsingContext::Get(aChildId);
MOZ_RELEASE_ASSERT(!child || child->IsCached());
if (!child) {
child = BrowsingContext::CreateFromIPC(aParent, aOpener, aName,
(uint64_t)aChildId, nullptr);
}
child->Attach(/* aFromIPC */ true);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvDetachBrowsingContext(
BrowsingContext* aContext, bool aMoveToBFCache) {
MOZ_RELEASE_ASSERT(aContext);
if (aMoveToBFCache) {
aContext->CacheChildren(/* aFromIPC */ true);
} else {
aContext->Detach(/* aFromIPC */ true);
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvWindowClose(BrowsingContext* aContext,
bool aTrustedCaller) {
if (!aContext) {

Просмотреть файл

@ -712,6 +712,13 @@ class ContentChild final : public PContentChild,
virtual void OnChannelReceivedMessage(const Message& aMsg) override;
mozilla::ipc::IPCResult RecvAttachBrowsingContext(
BrowsingContext* aParentContext, BrowsingContext* aOpener,
BrowsingContextId aContextId, const nsString& aName);
mozilla::ipc::IPCResult RecvDetachBrowsingContext(BrowsingContext* aContext,
bool aMoveToBFCache);
mozilla::ipc::IPCResult RecvWindowClose(BrowsingContext* aContext,
bool aTrustedCaller);
mozilla::ipc::IPCResult RecvWindowFocus(BrowsingContext* aContext);

Просмотреть файл

@ -5708,6 +5708,8 @@ mozilla::ipc::IPCResult ContentParent::RecvAttachBrowsingContext(
(uint64_t)aChildId, this);
}
child->Attach(/* aFromIPC */ true);
return IPC_OK();
}
@ -5734,9 +5736,9 @@ mozilla::ipc::IPCResult ContentParent::RecvDetachBrowsingContext(
}
if (aMoveToBFCache) {
aContext->CacheChildren();
aContext->CacheChildren(/* aFromIPC */ true);
} else {
aContext->Detach();
aContext->Detach(/* aFromIPC */ true);
}
return IPC_OK();

Просмотреть файл

@ -1227,34 +1227,6 @@ parent:
async StoreUserInteractionAsPermission(Principal aPrincipal);
/**
* Sync the BrowsingContext with id 'aContextId' and name 'aName' to the
* parent, and attach it to the BrowsingContext 'aParentContext'. If
* 'aParentContext' is 'nullptr' the BrowsingContext is a root in the
* BrowsingContext tree. AttachBrowsingContext must only be called at most
* once for any child BrowsingContext, and only for BrowsingContexts where
* the parent and the child context contains their nsDocShell.
*/
async AttachBrowsingContext(BrowsingContext aParentContext,
BrowsingContext aOpener,
BrowsingContextId aContextId,
nsString aName);
/**
* Remove the synced BrowsingContext 'aContext' from the parent.
* DetachBrowsingContext is only needed to be called once for any
* BrowsingContext, since detaching a node in the BrowsingContext detaches
* the entire sub-tree rooted at that node. Calling DetachBrowsingContext
* with an already detached BrowsingContext effectively does nothing. Note
* that it is not an error to call DetachBrowsingContext on a
* BrowsingContext belonging to an already detached subtree. The
* 'aMoveToBFCache' paramater controls if detaching a BrowsingContext
* should move it to the bfcache allowing it to be re-attached if navigated
* to.
*/
async DetachBrowsingContext(BrowsingContext aContext,
bool aMoveToBFCache);
/**
* Set the opener of browsing context 'aContext' to the browsing context
* with id 'aOpenerId'.
@ -1288,6 +1260,34 @@ both:
async PushError(nsCString scope, Principal principal, nsString message,
uint32_t flags);
/**
* Sync the BrowsingContext with id 'aContextId' and name 'aName' to the
* parent, and attach it to the BrowsingContext 'aParentContext'. If
* 'aParentContext' is 'nullptr' the BrowsingContext is a root in the
* BrowsingContext tree. AttachBrowsingContext must only be called at most
* once for any child BrowsingContext, and only for BrowsingContexts where
* the parent and the child context contains their nsDocShell.
*/
async AttachBrowsingContext(BrowsingContext aParentContext,
BrowsingContext aOpener,
BrowsingContextId aContextId,
nsString aName);
/**
* Remove the synced BrowsingContext 'aContext' from the parent.
* DetachBrowsingContext is only needed to be called once for any
* BrowsingContext, since detaching a node in the BrowsingContext detaches
* the entire sub-tree rooted at that node. Calling DetachBrowsingContext
* with an already detached BrowsingContext effectively does nothing. Note
* that it is not an error to call DetachBrowsingContext on a
* BrowsingContext belonging to an already detached subtree. The
* 'aMoveToBFCache' paramater controls if detaching a BrowsingContext
* should move it to the bfcache allowing it to be re-attached if navigated
* to.
*/
async DetachBrowsingContext(BrowsingContext aContext,
bool aMoveToBFCache);
async WindowClose(BrowsingContext aContext, bool aTrustedCaller);
async WindowFocus(BrowsingContext aContext);
async WindowBlur(BrowsingContext aContext);