diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 2a43dc91e07d..3723e937f09e 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -953,7 +953,7 @@ class nsDocShell final : public nsDocLoader, bool IsFrame() { return mBrowsingContext->IsFrame(); } bool CanSetOriginAttributes(); bool ShouldBlockLoadingForBackButton(); - bool ShouldDiscardLayoutState(nsIHttpChannel* aChannel); + static bool ShouldDiscardLayoutState(nsIHttpChannel* aChannel); bool HasUnloadedParent(); bool JustStartedNetworkLoad(); bool NavigationBlockedByPrinting(bool aDisplayErrorDialog = true); diff --git a/docshell/shistory/SessionHistoryEntry.cpp b/docshell/shistory/SessionHistoryEntry.cpp index 611d3bdb636c..2b6e058531b8 100644 --- a/docshell/shistory/SessionHistoryEntry.cpp +++ b/docshell/shistory/SessionHistoryEntry.cpp @@ -199,6 +199,12 @@ bool SessionHistoryInfo::IsSubFrame() const { return mSharedState.Get()->mIsFrameNavigation; } +void SessionHistoryInfo::SetSaveLayoutStateFlag(bool aSaveLayoutStateFlag) { + MOZ_ASSERT(XRE_IsParentProcess()); + static_cast(mSharedState.Get())->mSaveLayoutState = + aSaveLayoutStateFlag; +} + void SessionHistoryInfo::FillLoadInfo(nsDocShellLoadState& aLoadState) const { aLoadState.SetOriginalURI(mOriginalURI); aLoadState.SetMaybeResultPrincipalURI(Some(mResultPrincipalURI)); diff --git a/docshell/shistory/SessionHistoryEntry.h b/docshell/shistory/SessionHistoryEntry.h index 2fa44557f8e4..8ec0d4ba3020 100644 --- a/docshell/shistory/SessionHistoryEntry.h +++ b/docshell/shistory/SessionHistoryEntry.h @@ -135,6 +135,8 @@ class SessionHistoryInfo { uint32_t LoadType() { return mLoadType; } + void SetSaveLayoutStateFlag(bool aSaveLayoutStateFlag); + private: friend class SessionHistoryEntry; friend struct mozilla::ipc::IPDLParamTraits; diff --git a/docshell/shistory/nsSHistory.cpp b/docshell/shistory/nsSHistory.cpp index e81fa796ddb9..d3528a8cff32 100644 --- a/docshell/shistory/nsSHistory.cpp +++ b/docshell/shistory/nsSHistory.cpp @@ -1199,6 +1199,71 @@ void nsSHistory::LoadURIOrBFCache(LoadEntryResult& aLoadEntry) { RefPtr frameLoader = she->GetFrameLoader(); if (canonicalBC->Group()->Toplevels().Length() == 1 && frameLoader && (!currentShe || she->SharedInfo() != currentShe->SharedInfo())) { + auto restore = [canonicalBC, loadState, + she](const nsTArray aCanSaves) { + bool canSave = !aCanSaves.Contains(false); + MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, + ("nsSHistory::LoadURIOrBFCache " + "saving presentation=%i", + canSave)); + + nsCOMPtr frameLoaderOwner = + do_QueryInterface(canonicalBC->GetEmbedderElement()); + if (frameLoaderOwner) { + RefPtr fl = she->GetFrameLoader(); + if (fl) { + she->SetFrameLoader(nullptr); + RefPtr loadingBC = + fl->GetMaybePendingBrowsingContext(); + if (loadingBC) { + RefPtr currentFrameLoader = + frameLoaderOwner->GetFrameLoader(); + // The current page can be bfcached, store the + // nsFrameLoader in the current SessionHistoryEntry. + if (canSave && canonicalBC->GetActiveSessionHistoryEntry()) { + canonicalBC->GetActiveSessionHistoryEntry()->SetFrameLoader( + currentFrameLoader); + Unused << canonicalBC->SetIsInBFCache(true); + } + + // ReplacedBy will swap the entry back. + canonicalBC->SetActiveSessionHistoryEntry(she); + loadingBC->Canonical()->SetActiveSessionHistoryEntry(nullptr); + RemotenessChangeOptions options; + canonicalBC->ReplacedBy(loadingBC->Canonical(), options); + frameLoaderOwner->ReplaceFrameLoader(fl); + + // The old page can't be stored in the bfcache, + // destroy the nsFrameLoader. + if (!canSave && currentFrameLoader) { + currentFrameLoader->Destroy(); + } + // The current active entry should not store + // nsFrameLoader. + loadingBC->Canonical()->GetSessionHistory()->UpdateIndex(); + loadingBC->Canonical()->HistoryCommitIndexAndLength(); + Unused << loadingBC->SetIsInBFCache(false); + // ResetSHEntryHasUserInteractionCache(); ? + // browser.navigation.requireUserInteraction is still + // disabled everywhere. + return; + } + } + } + + // Fall back to do a normal load. + canonicalBC->LoadURI(loadState, false); + }; + + if (currentShe && !currentShe->GetSaveLayoutStateFlag()) { + // Current page can't enter bfcache because of + // SaveLayoutStateFlag, just run the restore immediately. + nsTArray canSaves; + canSaves.AppendElement(false); + restore(std::move(canSaves)); + return; + } + nsTArray> canSavePromises; canonicalBC->Group()->EachParent([&](ContentParent* aParent) { @@ -1210,72 +1275,13 @@ void nsSHistory::LoadURIOrBFCache(LoadEntryResult& aLoadEntry) { // Check if the current page can enter bfcache. PContentParent::CanSavePresentationPromise::All( GetCurrentSerialEventTarget(), canSavePromises) - ->Then( - GetMainThreadSerialEventTarget(), __func__, - [canonicalBC, loadState, she](const nsTArray aCanSaves) { - bool canSave = !aCanSaves.Contains(false); - MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, - ("nsSHistory::LoadURIOrBFCache " - "saving presentation=%i", - canSave)); - - nsCOMPtr frameLoaderOwner = - do_QueryInterface(canonicalBC->GetEmbedderElement()); - if (frameLoaderOwner) { - RefPtr fl = she->GetFrameLoader(); - if (fl) { - she->SetFrameLoader(nullptr); - RefPtr loadingBC = - fl->GetMaybePendingBrowsingContext(); - if (loadingBC) { - RefPtr currentFrameLoader = - frameLoaderOwner->GetFrameLoader(); - // The current page can be bfcached, store the - // nsFrameLoader in the current SessionHistoryEntry. - if (canSave && - canonicalBC->GetActiveSessionHistoryEntry()) { - canonicalBC->GetActiveSessionHistoryEntry() - ->SetFrameLoader(currentFrameLoader); - Unused << canonicalBC->SetIsInBFCache(true); - } - - // ReplacedBy will swap the entry back. - canonicalBC->SetActiveSessionHistoryEntry(she); - loadingBC->Canonical()->SetActiveSessionHistoryEntry( - nullptr); - RemotenessChangeOptions options; - canonicalBC->ReplacedBy(loadingBC->Canonical(), options); - frameLoaderOwner->ReplaceFrameLoader(fl); - - // The old page can't be stored in the bfcache, - // destroy the nsFrameLoader. - if (!canSave && currentFrameLoader) { - currentFrameLoader->Destroy(); - } - // The current active entry should not store - // nsFrameLoader. - loadingBC->Canonical() - ->GetSessionHistory() - ->UpdateIndex(); - loadingBC->Canonical()->HistoryCommitIndexAndLength(); - Unused << loadingBC->SetIsInBFCache(false); - // ResetSHEntryHasUserInteractionCache(); ? - // browser.navigation.requireUserInteraction is still - // disabled everywhere. - return; - } - } - } - - // Fall back to do a normal load. - canonicalBC->LoadURI(loadState, false); - }, - [canonicalBC, loadState](mozilla::ipc::ResponseRejectReason) { - MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, - ("nsSHistory::LoadURIOrBFCache " - "error in trying to save presentation")); - canonicalBC->LoadURI(loadState, false); - }); + ->Then(GetMainThreadSerialEventTarget(), __func__, std::move(restore), + [canonicalBC, loadState](mozilla::ipc::ResponseRejectReason) { + MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, + ("nsSHistory::LoadURIOrBFCache " + "error in trying to save presentation")); + canonicalBC->LoadURI(loadState, false); + }); return; } if (frameLoader) { diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp index 296433c9cd22..0f5d2939cb36 100644 --- a/netwerk/ipc/DocumentLoadListener.cpp +++ b/netwerk/ipc/DocumentLoadListener.cpp @@ -1634,7 +1634,10 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch( (mLoadStateLoadType == LOAD_NORMAL || mLoadStateLoadType == LOAD_HISTORY || mLoadStateLoadType == LOAD_LINK || mLoadStateLoadType == LOAD_STOP_CONTENT || - mLoadStateLoadType == LOAD_STOP_CONTENT_AND_REPLACE)) { + mLoadStateLoadType == LOAD_STOP_CONTENT_AND_REPLACE) && + (!browsingContext->GetActiveSessionHistoryEntry() || + browsingContext->GetActiveSessionHistoryEntry() + ->GetSaveLayoutStateFlag())) { options.mReplaceBrowsingContext = true; options.mTryUseBFCache = true; } @@ -2134,6 +2137,11 @@ DocumentLoadListener::OnStartRequest(nsIRequest* aRequest) { httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS; loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus); } + + if (mLoadingSessionHistoryInfo && + nsDocShell::ShouldDiscardLayoutState(httpChannel)) { + mLoadingSessionHistoryInfo->mInfo.SetSaveLayoutStateFlag(false); + } } auto* loadingContext = GetLoadingBrowsingContext();