Bug 1540839 - Add ability to preserve browsing contexts between FrameLoaders; r=nika

When changing processes and therefore destroying/rebuilding
frameloaders, add ability to keep the browsing context around and add
it to the new frameloader.

Differential Revision: https://phabricator.services.mozilla.com/D26267
This commit is contained in:
Kyle Machulis
2019-04-03 15:40:28 -07:00
parent 0a2f35d5bc
commit d29c67c357
14 changed files with 87 additions and 13 deletions

View File

@@ -385,7 +385,8 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext)
mHasLoadedNonBlankURI(false), mHasLoadedNonBlankURI(false),
mBlankTiming(false), mBlankTiming(false),
mTitleValidForCurrentURI(false), mTitleValidForCurrentURI(false),
mIsFrame(false) { mIsFrame(false),
mSkipBrowsingContextDetachOnDestroy(false) {
mHistoryID.m0 = 0; mHistoryID.m0 = 0;
mHistoryID.m1 = 0; mHistoryID.m1 = 0;
mHistoryID.m2 = 0; mHistoryID.m2 = 0;
@@ -5036,7 +5037,11 @@ nsDocShell::Destroy() {
mSessionHistory = nullptr; mSessionHistory = nullptr;
} }
mBrowsingContext->Detach(); // This will be skipped in cases where we want to preserve the browsing
// context between loads.
if (!mSkipBrowsingContextDetachOnDestroy) {
mBrowsingContext->Detach();
}
SetTreeOwner(nullptr); SetTreeOwner(nullptr);

View File

@@ -405,6 +405,10 @@ class nsDocShell final : public nsDocLoader,
// Clear the document's storage access flag if needed. // Clear the document's storage access flag if needed.
void MaybeClearStorageAccessFlag(); void MaybeClearStorageAccessFlag();
void SkipBrowsingContextDetach() {
mSkipBrowsingContextDetachOnDestroy = true;
}
private: // member functions private: // member functions
friend class nsDSURIContentListener; friend class nsDSURIContentListener;
friend class FramingChecker; friend class FramingChecker;
@@ -1205,6 +1209,11 @@ class nsDocShell final : public nsDocLoader,
bool mTitleValidForCurrentURI : 1; bool mTitleValidForCurrentURI : 1;
bool mIsFrame : 1; bool mIsFrame : 1;
// If mSkipBrowsingContextDetachOnDestroy is set to true, then when the
// docshell is destroyed, the browsing context will not be detached. This is
// for cases where we want to preserve the BC for future use.
bool mSkipBrowsingContextDetachOnDestroy : 1;
}; };
#endif /* nsDocShell_h__ */ #endif /* nsDocShell_h__ */

View File

@@ -364,7 +364,7 @@ nsFrameLoader* nsFrameLoader::Create(Element* aOwner, BrowsingContext* aOpener,
/* static */ /* static */
nsFrameLoader* nsFrameLoader::Create( nsFrameLoader* nsFrameLoader::Create(
mozilla::dom::Element* aOwner, mozilla::dom::Element* aOwner, BrowsingContext* aPreservedBrowsingContext,
const mozilla::dom::RemotenessOptions& aOptions) { const mozilla::dom::RemotenessOptions& aOptions) {
NS_ENSURE_TRUE(aOwner, nullptr); NS_ENSURE_TRUE(aOwner, nullptr);
// This version of Create is only called for Remoteness updates, so we can // This version of Create is only called for Remoteness updates, so we can
@@ -381,7 +381,12 @@ nsFrameLoader* nsFrameLoader::Create(
if (hasOpener) { if (hasOpener) {
opener = aOptions.mOpener.Value().Value().get(); opener = aOptions.mOpener.Value().Value().get();
} }
RefPtr<BrowsingContext> context = CreateBrowsingContext(aOwner, opener); RefPtr<BrowsingContext> context;
if (aPreservedBrowsingContext) {
context = aPreservedBrowsingContext;
} else {
context = CreateBrowsingContext(aOwner, opener);
}
NS_ENSURE_TRUE(context, nullptr); NS_ENSURE_TRUE(context, nullptr);
return new nsFrameLoader(aOwner, context, aOptions); return new nsFrameLoader(aOwner, context, aOptions);
} }
@@ -3490,3 +3495,22 @@ JSObject* nsFrameLoader::WrapObject(JSContext* cx,
FrameLoader_Binding::Wrap(cx, this, this, aGivenProto, &result); FrameLoader_Binding::Wrap(cx, this, this, aGivenProto, &result);
return result; return result;
} }
void nsFrameLoader::SkipBrowsingContextDetach() {
if (IsRemoteFrame()) {
// OOP Browser - Go directly over Browser Parent
if (mBrowserParent) {
Unused << mBrowserParent->SendSkipBrowsingContextDetach();
}
// OOP IFrame - Through Browser Bridge Parent, set on browser child
else if (mBrowserBridgeChild) {
Unused << mBrowserBridgeChild->SendSkipBrowsingContextDetach();
}
return;
}
// In process
RefPtr<nsDocShell> docshell = GetDocShell();
MOZ_ASSERT(docshell);
docshell->SkipBrowsingContextDetach();
}

View File

@@ -95,6 +95,7 @@ class nsFrameLoader final : public nsStubMutationObserver,
typedef mozilla::dom::PBrowserParent PBrowserParent; typedef mozilla::dom::PBrowserParent PBrowserParent;
typedef mozilla::dom::Document Document; typedef mozilla::dom::Document Document;
typedef mozilla::dom::BrowserParent BrowserParent; typedef mozilla::dom::BrowserParent BrowserParent;
typedef mozilla::dom::BrowsingContext BrowsingContext;
typedef mozilla::layout::RenderFrame RenderFrame; typedef mozilla::layout::RenderFrame RenderFrame;
public: public:
@@ -106,6 +107,7 @@ class nsFrameLoader final : public nsStubMutationObserver,
// Called by nsFrameLoaderOwner::ChangeRemoteness when switching out // Called by nsFrameLoaderOwner::ChangeRemoteness when switching out
// FrameLoaders. // FrameLoaders.
static nsFrameLoader* Create(mozilla::dom::Element* aOwner, static nsFrameLoader* Create(mozilla::dom::Element* aOwner,
BrowsingContext* aPreservedBrowsingContext,
const mozilla::dom::RemotenessOptions& aOptions); const mozilla::dom::RemotenessOptions& aOptions);
NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID)
@@ -385,6 +387,8 @@ class nsFrameLoader final : public nsStubMutationObserver,
virtual JSObject* WrapObject(JSContext* cx, virtual JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> aGivenProto) override; JS::Handle<JSObject*> aGivenProto) override;
void SkipBrowsingContextDetach();
private: private:
nsFrameLoader(mozilla::dom::Element* aOwner, nsFrameLoader(mozilla::dom::Element* aOwner,
mozilla::dom::BrowsingContext* aBrowsingContext, mozilla::dom::BrowsingContext* aBrowsingContext,

View File

@@ -32,8 +32,14 @@ nsFrameLoaderOwner::GetBrowsingContext() {
void nsFrameLoaderOwner::ChangeRemoteness( void nsFrameLoaderOwner::ChangeRemoteness(
const mozilla::dom::RemotenessOptions& aOptions, mozilla::ErrorResult& rv) { const mozilla::dom::RemotenessOptions& aOptions, mozilla::ErrorResult& rv) {
RefPtr<mozilla::dom::BrowsingContext> bc;
// If we already have a Frameloader, destroy it. // If we already have a Frameloader, destroy it.
if (mFrameLoader) { if (mFrameLoader) {
bc = mFrameLoader->GetBrowsingContext();
// TODO pass in Cross-Origin-Load-Policy rules
mFrameLoader->SkipBrowsingContextDetach();
mFrameLoader->Destroy(); mFrameLoader->Destroy();
mFrameLoader = nullptr; mFrameLoader = nullptr;
} }
@@ -43,7 +49,8 @@ void nsFrameLoaderOwner::ChangeRemoteness(
// owner. // owner.
RefPtr<Element> owner = do_QueryObject(this); RefPtr<Element> owner = do_QueryObject(this);
MOZ_ASSERT(owner); MOZ_ASSERT(owner);
mFrameLoader = nsFrameLoader::Create(owner, aOptions); mFrameLoader = nsFrameLoader::Create(owner, bc, aOptions);
if (NS_WARN_IF(!mFrameLoader)) { if (NS_WARN_IF(!mFrameLoader)) {
return; return;
} }
@@ -70,9 +77,8 @@ void nsFrameLoaderOwner::ChangeRemoteness(
// FrameLoader, fire an event to act like we've recreated ourselves, similar // FrameLoader, fire an event to act like we've recreated ourselves, similar
// to what XULFrameElement does after rebinding to the tree. // to what XULFrameElement does after rebinding to the tree.
// ChromeOnlyDispatch is turns on to make sure this isn't fired into content. // ChromeOnlyDispatch is turns on to make sure this isn't fired into content.
(new mozilla::AsyncEventDispatcher(owner, (new mozilla::AsyncEventDispatcher(
NS_LITERAL_STRING("XULFrameLoaderCreated"), owner, NS_LITERAL_STRING("XULFrameLoaderCreated"),
mozilla::CanBubble::eYes, mozilla::CanBubble::eYes, mozilla::ChromeOnlyDispatch::eYes))
mozilla::ChromeOnlyDispatch::eYes))
->RunDOMEventWhenSafe(); ->RunDOMEventWhenSafe();
} }

View File

@@ -182,6 +182,11 @@ IPCResult BrowserBridgeParent::RecvDispatchSynthesizedMouseEvent(
return IPC_OK(); return IPC_OK();
} }
IPCResult BrowserBridgeParent::RecvSkipBrowsingContextDetach() {
mBrowserParent->SkipBrowsingContextDetach();
return IPC_OK();
}
IPCResult BrowserBridgeParent::RecvActivate() { IPCResult BrowserBridgeParent::RecvActivate() {
mBrowserParent->Activate(); mBrowserParent->Activate();
return IPC_OK(); return IPC_OK();

View File

@@ -59,6 +59,8 @@ class BrowserBridgeParent : public PBrowserBridgeParent {
mozilla::ipc::IPCResult RecvDispatchSynthesizedMouseEvent( mozilla::ipc::IPCResult RecvDispatchSynthesizedMouseEvent(
const WidgetMouseEvent& aEvent); const WidgetMouseEvent& aEvent);
mozilla::ipc::IPCResult RecvSkipBrowsingContextDetach();
mozilla::ipc::IPCResult RecvActivate(); mozilla::ipc::IPCResult RecvActivate();
mozilla::ipc::IPCResult RecvDeactivate(); mozilla::ipc::IPCResult RecvDeactivate();

View File

@@ -1052,6 +1052,17 @@ BrowserChild::~BrowserChild() {
mozilla::DropJSObjects(this); mozilla::DropJSObjects(this);
} }
mozilla::ipc::IPCResult BrowserChild::RecvSkipBrowsingContextDetach() {
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
if (!docShell) {
return IPC_OK();
}
RefPtr<nsDocShell> docshell = nsDocShell::Cast(docShell);
MOZ_ASSERT(docshell);
docshell->SkipBrowsingContextDetach();
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvLoadURL(const nsCString& aURI, mozilla::ipc::IPCResult BrowserChild::RecvLoadURL(const nsCString& aURI,
const ShowInfo& aInfo) { const ShowInfo& aInfo) {
if (!mDidLoadURLInit) { if (!mDidLoadURLInit) {

View File

@@ -555,6 +555,7 @@ class BrowserChild final : public BrowserChildBase,
mozilla::ipc::IPCResult RecvUpdateNativeWindowHandle( mozilla::ipc::IPCResult RecvUpdateNativeWindowHandle(
const uintptr_t& aNewHandle); const uintptr_t& aNewHandle);
virtual mozilla::ipc::IPCResult RecvSkipBrowsingContextDetach() override;
/** /**
* Native widget remoting protocol for use with windowed plugins with e10s. * Native widget remoting protocol for use with windowed plugins with e10s.
*/ */

View File

@@ -3744,6 +3744,12 @@ BrowserParent::StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId) {
return NS_OK; return NS_OK;
} }
void BrowserParent::SkipBrowsingContextDetach() {
RefPtr<nsFrameLoader> fl = GetFrameLoader();
MOZ_ASSERT(fl);
fl->SkipBrowsingContextDetach();
}
mozilla::ipc::IPCResult BrowserParent::RecvLookUpDictionary( mozilla::ipc::IPCResult BrowserParent::RecvLookUpDictionary(
const nsString& aText, nsTArray<FontRange>&& aFontRangeArray, const nsString& aText, nsTArray<FontRange>&& aFontRangeArray,
const bool& aIsVertical, const LayoutDeviceIntPoint& aPoint) { const bool& aIsVertical, const LayoutDeviceIntPoint& aPoint) {

View File

@@ -678,6 +678,8 @@ class BrowserParent final : public PBrowserParent,
void NavigateByKey(bool aForward, bool aForDocumentNavigation); void NavigateByKey(bool aForward, bool aForDocumentNavigation);
void SkipBrowsingContextDetach();
protected: protected:
bool ReceiveMessage( bool ReceiveMessage(
const nsString& aMessage, bool aSync, ipc::StructuredCloneData* aData, const nsString& aMessage, bool aSync, ipc::StructuredCloneData* aData,

View File

@@ -948,6 +948,7 @@ child:
*/ */
async GetContentBlockingLog() returns(nsCString log, bool success); async GetContentBlockingLog() returns(nsCString log, bool success);
async SkipBrowsingContextDetach();
parent: parent:
/** Records a history visit. */ /** Records a history visit. */
async VisitURI(URIParams aURI, URIParams? aLastVisitedURI, async VisitURI(URIParams aURI, URIParams? aLastVisitedURI,

View File

@@ -74,6 +74,8 @@ parent:
async Deactivate(); async Deactivate();
async SetIsUnderHiddenEmbedderElement(bool aIsUnderHiddenEmbedderElement); async SetIsUnderHiddenEmbedderElement(bool aIsUnderHiddenEmbedderElement);
async SkipBrowsingContextDetach();
}; };
} // namespace dom } // namespace dom

View File

@@ -82,10 +82,6 @@ void WindowGlobalParent::Init(const WindowGlobalInit& aInit) {
mBrowsingContext = CanonicalBrowsingContext::Cast(aInit.browsingContext()); mBrowsingContext = CanonicalBrowsingContext::Cast(aInit.browsingContext());
MOZ_ASSERT(mBrowsingContext); MOZ_ASSERT(mBrowsingContext);
// XXX(nika): This won't be the case soon, but for now this is a good
// assertion as we can't switch processes. We should relax this eventually.
MOZ_ASSERT(mBrowsingContext->IsOwnedByProcess(processId));
// Attach ourself to the browsing context. // Attach ourself to the browsing context.
mBrowsingContext->RegisterWindowGlobal(this); mBrowsingContext->RegisterWindowGlobal(this);