зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1696175 - Call DisconnectChildListeners at a later time for BFCache in the parent. r=necko-reviewers,nika
Differential Revision: https://phabricator.services.mozilla.com/D112981
This commit is contained in:
Родитель
bd3999c92b
Коммит
3e785c9c12
|
@ -2745,6 +2745,10 @@ void BrowsingContext::DidSet(FieldIndex<IDX_IsInBFCache>) {
|
|||
[&](BrowsingContext* aContext) { aContext->mIsInBFCache = false; });
|
||||
}
|
||||
|
||||
if (isInBFCache && XRE_IsContentProcess() && mDocShell) {
|
||||
nsDocShell::Cast(mDocShell)->MaybeDisconnectChildListenersOnPageHide();
|
||||
}
|
||||
|
||||
PreOrderWalk([&](BrowsingContext* aContext) {
|
||||
nsCOMPtr<nsIDocShell> shell = aContext->GetDocShell();
|
||||
if (shell) {
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
#include "mozilla/dom/JSWindowActorChild.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/net/DocumentChannel.h"
|
||||
#include "mozilla/net/DocumentChannelChild.h"
|
||||
#include "mozilla/net/ParentChannelWrapper.h"
|
||||
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
||||
#include "ReferrerInfo.h"
|
||||
|
@ -383,6 +384,7 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
|
|||
mFailedLoadType(0),
|
||||
mJSRunToCompletionDepth(0),
|
||||
mMetaViewportOverride(nsIDocShell::META_VIEWPORT_OVERRIDE_NONE),
|
||||
mChannelToDisconnectOnPageHide(0),
|
||||
mCreatingDocument(false),
|
||||
#ifdef DEBUG
|
||||
mInEnsureScriptEnv(false),
|
||||
|
@ -4369,6 +4371,11 @@ nsDocShell::Stop(uint32_t aStopFlags) {
|
|||
// just call Stop() on us as an nsIDocumentLoader... We need fewer
|
||||
// redundant apis!
|
||||
Stop();
|
||||
|
||||
// Clear out mChannelToDisconnectOnPageHide. This page won't go in the
|
||||
// BFCache now, and the Stop above will have removed the DocumentChannel
|
||||
// from the loadgroup.
|
||||
mChannelToDisconnectOnPageHide = 0;
|
||||
}
|
||||
|
||||
for (auto* child : mChildList.ForwardRange()) {
|
||||
|
@ -13625,3 +13632,20 @@ nsDocShell::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
|
|||
RecordSingleChannelId();
|
||||
return nsDocLoader::OnStopRequest(aRequest, aStatusCode);
|
||||
}
|
||||
|
||||
void nsDocShell::MaybeDisconnectChildListenersOnPageHide() {
|
||||
MOZ_RELEASE_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
if (mChannelToDisconnectOnPageHide != 0 && mLoadGroup) {
|
||||
nsCOMPtr<nsISimpleEnumerator> requests;
|
||||
mLoadGroup->GetRequests(getter_AddRefs(requests));
|
||||
for (const auto& request : SimpleEnumerator<nsIRequest>(requests)) {
|
||||
RefPtr<DocumentChannel> channel = do_QueryObject(request);
|
||||
if (channel && channel->ChannelId() == mChannelToDisconnectOnPageHide) {
|
||||
static_cast<DocumentChannelChild*>(channel.get())
|
||||
->DisconnectChildListeners(NS_BINDING_ABORTED, NS_BINDING_ABORTED);
|
||||
}
|
||||
}
|
||||
mChannelToDisconnectOnPageHide = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1088,6 +1088,12 @@ class nsDocShell final : public nsDocLoader,
|
|||
|
||||
void RecordSingleChannelId();
|
||||
|
||||
void SetChannelToDisconnectOnPageHide(uint64_t aChannelId) {
|
||||
MOZ_ASSERT(mChannelToDisconnectOnPageHide == 0);
|
||||
mChannelToDisconnectOnPageHide = aChannelId;
|
||||
}
|
||||
void MaybeDisconnectChildListenersOnPageHide();
|
||||
|
||||
private: // data members
|
||||
nsString mTitle;
|
||||
nsCString mOriginalUriString;
|
||||
|
@ -1227,6 +1233,8 @@ class nsDocShell final : public nsDocLoader,
|
|||
// See WindowGlobalParent::mSingleChannelId.
|
||||
mozilla::Maybe<uint64_t> mSingleChannelId;
|
||||
|
||||
uint64_t mChannelToDisconnectOnPageHide;
|
||||
|
||||
// The following two fields cannot be declared as bit fields
|
||||
// because of uses with AutoRestore.
|
||||
bool mCreatingDocument; // (should be) debugging only
|
||||
|
|
|
@ -55,6 +55,9 @@ class DocumentChannel : public nsIIdentChannel {
|
|||
mInitialClientInfo = aInfo;
|
||||
}
|
||||
|
||||
void DisconnectChildListeners(const nsresult& aStatus,
|
||||
const nsresult& aLoadGroupStatus);
|
||||
|
||||
/**
|
||||
* Will create the appropriate document channel:
|
||||
* Either a DocumentChannelChild if called from the content process or
|
||||
|
@ -77,8 +80,6 @@ class DocumentChannel : public nsIIdentChannel {
|
|||
bool aIsXFOError);
|
||||
|
||||
void ShutdownListeners(nsresult aStatusCode);
|
||||
void DisconnectChildListeners(const nsresult& aStatus,
|
||||
const nsresult& aLoadGroupStatus);
|
||||
virtual void DeleteIPDL() {}
|
||||
|
||||
nsDocShell* GetDocShell();
|
||||
|
|
|
@ -192,20 +192,29 @@ IPCResult DocumentChannelChild::RecvFailedAsyncOpen(
|
|||
IPCResult DocumentChannelChild::RecvDisconnectChildListeners(
|
||||
const nsresult& aStatus, const nsresult& aLoadGroupStatus,
|
||||
bool aSwitchedProcess) {
|
||||
// If this is a normal failure, then we want to disconnect our listeners and
|
||||
// notify them of the failure. If this is a process switch, then we can just
|
||||
// ignore it silently, and trust that the switch will shut down our docshell
|
||||
// and cancel us when it's ready.
|
||||
// XXXBFCache This should be fixed in some better way.
|
||||
bool disconnectChildListeners = !aSwitchedProcess;
|
||||
if (!disconnectChildListeners && mozilla::BFCacheInParent()) {
|
||||
nsDocShell* shell = GetDocShell();
|
||||
disconnectChildListeners = shell && shell->GetBrowsingContext() &&
|
||||
shell->GetBrowsingContext()->IsTop();
|
||||
}
|
||||
if (disconnectChildListeners) {
|
||||
// If this disconnect is not due to a process switch, perform the disconnect
|
||||
// immediately.
|
||||
if (!aSwitchedProcess) {
|
||||
DisconnectChildListeners(aStatus, aLoadGroupStatus);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// Otherwise, the disconnect will occur later using some other mechanism,
|
||||
// depending on what's happening to the loading DocShell. If this is a
|
||||
// toplevel navigation, and this BrowsingContext enters the BFCache, we will
|
||||
// cancel this channel when the PageHide event is firing, whereas if it does
|
||||
// not enter BFCache (e.g. due to being an object, subframe or non-bfcached
|
||||
// toplevel navigation), we will cancel this channel when the DocShell is
|
||||
// destroyed.
|
||||
nsDocShell* shell = GetDocShell();
|
||||
if (mLoadInfo->GetExternalContentPolicyType() ==
|
||||
ExtContentPolicy::TYPE_DOCUMENT &&
|
||||
shell) {
|
||||
MOZ_ASSERT(shell->GetBrowsingContext()->IsTop());
|
||||
// Tell the DocShell which channel to cancel if it enters the BFCache.
|
||||
shell->SetChannelToDisconnectOnPageHide(mChannelId);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче