mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1546759 - Change nsSHistory::WalkHistoryEntries to walk browsing context tree instead of doc shell tree, r=peterv,nika
WalkHistoryEntries function gets called by nsSHistory::CloneAndReplaceChild and nsSHistory::SetChildHistoryEntry recursively, so those have to be moved into the parent process. This eliminates many sync IPC calls. To facilitate transition to a new session history design, we are mirroring mOSHE and mLSHE SH entries from docshell to browsing context. Whenever we update those entries in docshell, we will also update those in BC, and vice versa. Differential Revision: https://phabricator.services.mozilla.com/D56201 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
9542f19af8
commit
5986a2de44
@ -16,6 +16,7 @@
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsISHistory.h"
|
||||
#include "nsISHEntry.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -110,6 +111,25 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
||||
// if the top-level browsing context has been discarded.
|
||||
MediaController* GetMediaController();
|
||||
|
||||
bool HasHistoryEntry(nsISHEntry* aEntry) const {
|
||||
return aEntry && (aEntry == mOSHE || aEntry == mLSHE);
|
||||
}
|
||||
|
||||
void UpdateSHEntries(nsISHEntry* aNewLSHE, nsISHEntry* aNewOSHE) {
|
||||
mLSHE = aNewLSHE;
|
||||
mOSHE = aNewOSHE;
|
||||
}
|
||||
|
||||
void SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry) {
|
||||
if (aOldEntry == mOSHE) {
|
||||
mOSHE = aNewEntry;
|
||||
}
|
||||
|
||||
if (aOldEntry == mLSHE) {
|
||||
mLSHE = aNewEntry;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// Called when the browsing context is being discarded.
|
||||
void CanonicalDiscard();
|
||||
@ -171,6 +191,10 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
||||
// browsing context tree, so it would only exist in the top level browsing
|
||||
// context.
|
||||
RefPtr<MediaController> mTabMediaController;
|
||||
|
||||
// These are being mirrored from docshell
|
||||
nsCOMPtr<nsISHEntry> mOSHE;
|
||||
nsCOMPtr<nsISHEntry> mLSHE;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "mozilla/StaticPrefs_extensions.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/StaticPrefs_ui.h"
|
||||
#include "mozilla/StaticPrefs_fission.h"
|
||||
#include "mozilla/StartupTimeline.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
@ -71,8 +72,8 @@
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/dom/LoadURIOptionsBinding.h"
|
||||
#include "mozilla/dom/JSWindowActorChild.h"
|
||||
|
||||
#include "mozilla/net/DocumentChannel.h"
|
||||
#include "nsSHEntry.h"
|
||||
#include "mozilla/net/DocumentChannelChild.h"
|
||||
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
||||
#include "ReferrerInfo.h"
|
||||
@ -194,6 +195,7 @@
|
||||
#include "nsRefreshTimer.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
#include "nsSHistory.h"
|
||||
#include "SHEntryChild.h"
|
||||
#include "nsStructuredCloneContainer.h"
|
||||
#include "nsSubDocumentFrame.h"
|
||||
#include "nsView.h"
|
||||
@ -3192,35 +3194,8 @@ nsresult nsDocShell::AddChildSHEntryInternal(nsISHEntry* aCloneRef,
|
||||
bool aCloneChildren) {
|
||||
nsresult rv = NS_OK;
|
||||
if (mSessionHistory) {
|
||||
/* You are currently in the rootDocShell.
|
||||
* You will get here when a subframe has a new url
|
||||
* to load and you have walked up the tree all the
|
||||
* way to the top to clone the current SHEntry hierarchy
|
||||
* and replace the subframe where a new url was loaded with
|
||||
* a new entry.
|
||||
*/
|
||||
nsCOMPtr<nsISHEntry> currentHE;
|
||||
int32_t index = mSessionHistory->Index();
|
||||
if (index < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = mSessionHistory->LegacySHistory()->GetEntryAtIndex(
|
||||
index, getter_AddRefs(currentHE));
|
||||
NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISHEntry> currentEntry(currentHE);
|
||||
if (currentEntry) {
|
||||
nsCOMPtr<nsISHEntry> nextEntry;
|
||||
uint32_t cloneID = aCloneRef->GetID();
|
||||
rv = nsSHistory::CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
|
||||
aCloneChildren,
|
||||
getter_AddRefs(nextEntry));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = mSessionHistory->LegacySHistory()->AddEntry(nextEntry, true);
|
||||
}
|
||||
}
|
||||
rv = mSessionHistory->LegacySHistory()->AddChildSHEntryHelper(
|
||||
aCloneRef, aNewEntry, mBrowsingContext, aCloneChildren);
|
||||
} else {
|
||||
/* Just pass this along */
|
||||
nsCOMPtr<nsIDocShell> parent =
|
||||
@ -4258,8 +4233,7 @@ nsDocShell::Stop(uint32_t aStopFlags) {
|
||||
if (mLoadType == LOAD_ERROR_PAGE) {
|
||||
if (mLSHE) {
|
||||
// Since error page loads never unset mLSHE, do so now
|
||||
SetHistoryEntry(&mOSHE, mLSHE);
|
||||
SetHistoryEntry(&mLSHE, nullptr);
|
||||
SetHistoryEntryAndUpdateBC(Some(nullptr), Some<nsISHEntry*>(mLSHE));
|
||||
}
|
||||
|
||||
mFailedChannel = nullptr;
|
||||
@ -5799,7 +5773,7 @@ nsresult nsDocShell::Embed(nsIContentViewer* aContentViewer,
|
||||
// Set history.state
|
||||
SetDocCurrentStateObj(mLSHE);
|
||||
|
||||
SetHistoryEntry(&mOSHE, mLSHE);
|
||||
SetHistoryEntryAndUpdateBC(Nothing(), Some<nsISHEntry*>(mLSHE));
|
||||
}
|
||||
|
||||
bool updateHistory = true;
|
||||
@ -6018,7 +5992,7 @@ void nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
|
||||
if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) &&
|
||||
mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
|
||||
mLoadType = LOAD_NORMAL_REPLACE;
|
||||
SetHistoryEntry(&mLSHE, nullptr);
|
||||
SetHistoryEntryAndUpdateBC(Some(nullptr), Nothing());
|
||||
}
|
||||
}
|
||||
|
||||
@ -6153,7 +6127,7 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
|
||||
|
||||
// Clear the mLSHE reference to indicate document loading is done one
|
||||
// way or another.
|
||||
SetHistoryEntry(&mLSHE, nullptr);
|
||||
SetHistoryEntryAndUpdateBC(Some(nullptr), Nothing());
|
||||
}
|
||||
// if there's a refresh header in the channel, this method
|
||||
// will set it up for us.
|
||||
@ -6637,7 +6611,7 @@ nsresult nsDocShell::CreateAboutBlankContentViewer(
|
||||
}
|
||||
|
||||
// The transient about:blank viewer doesn't have a session history entry.
|
||||
SetHistoryEntry(&mOSHE, nullptr);
|
||||
SetHistoryEntryAndUpdateBC(Nothing(), Some(nullptr));
|
||||
|
||||
// Clear out our mTiming like we would in EndPageLoad, if we didn't
|
||||
// have one before entering this function.
|
||||
@ -7057,7 +7031,7 @@ nsresult nsDocShell::RestorePresentation(nsISHEntry* aSHEntry,
|
||||
MOZ_LOG(gPageCacheLog, LogLevel::Debug,
|
||||
("restoring presentation from session history: %s", spec.get()));
|
||||
|
||||
SetHistoryEntry(&mLSHE, aSHEntry);
|
||||
SetHistoryEntryAndUpdateBC(Some(aSHEntry), Nothing());
|
||||
|
||||
// Post an event that will remove the request after we've returned
|
||||
// to the event loop. This mimics the way it is called by nsIChannel
|
||||
@ -7361,7 +7335,7 @@ nsresult nsDocShell::RestoreFromHistory() {
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// mLSHE is now our currently-loaded document.
|
||||
SetHistoryEntry(&mOSHE, mLSHE);
|
||||
SetHistoryEntryAndUpdateBC(Nothing(), Some<nsISHEntry*>(mLSHE));
|
||||
|
||||
// We aren't going to restore any items from the LayoutHistoryState,
|
||||
// but we don't want them to stay around in case the page is reloaded.
|
||||
@ -8613,7 +8587,8 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
|
||||
// History loads, SetCurrentURI() called from OnNewURI() will send proper
|
||||
// onLocationChange() notifications to the browser to update back/forward
|
||||
// buttons.
|
||||
SetHistoryEntry(&mLSHE, aLoadState->SHEntry());
|
||||
SetHistoryEntryAndUpdateBC(Some<nsISHEntry*>(aLoadState->SHEntry()),
|
||||
Nothing());
|
||||
|
||||
// Set the doc's URI according to the new history entry's URI.
|
||||
RefPtr<Document> doc = GetDocument();
|
||||
@ -8697,7 +8672,7 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
|
||||
* loads.
|
||||
*/
|
||||
if (mLSHE) {
|
||||
SetHistoryEntry(&mOSHE, mLSHE);
|
||||
SetHistoryEntryAndUpdateBC(Nothing(), Some<nsISHEntry*>(mLSHE));
|
||||
// Save the postData obtained from the previous page
|
||||
// in to the session history entry created for the
|
||||
// anchor page, so that any history load of the anchor
|
||||
@ -8716,7 +8691,7 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
|
||||
/* Restore the original LSHE if we were loading something
|
||||
* while same document navigation was initiated.
|
||||
*/
|
||||
SetHistoryEntry(&mLSHE, oldLSHE);
|
||||
SetHistoryEntryAndUpdateBC(Some<nsISHEntry*>(oldLSHE), Nothing());
|
||||
/* Set the title for the SH entry for this target url. so that
|
||||
* SH menus in go/back/forward buttons won't be empty for this.
|
||||
*/
|
||||
@ -9128,7 +9103,8 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
|
||||
// been called. But when loading an error page, do not clear the
|
||||
// mLSHE for the real page.
|
||||
if (mLoadType != LOAD_ERROR_PAGE) {
|
||||
SetHistoryEntry(&mLSHE, aLoadState->SHEntry());
|
||||
SetHistoryEntryAndUpdateBC(Some<nsISHEntry*>(aLoadState->SHEntry()),
|
||||
Nothing());
|
||||
if (aLoadState->SHEntry()) {
|
||||
// We're making history navigation or a reload. Make sure our history ID
|
||||
// points to the same ID as SHEntry's docshell ID.
|
||||
@ -10543,7 +10519,7 @@ bool nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
|
||||
// If this is a refresh to the currently loaded url, we don't
|
||||
// have to update session or global history.
|
||||
if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
|
||||
SetHistoryEntry(&mLSHE, mOSHE);
|
||||
SetHistoryEntryAndUpdateBC(Some<nsISHEntry*>(mOSHE), Nothing());
|
||||
}
|
||||
|
||||
/* If the user pressed shift-reload, cache will create a new cache key
|
||||
@ -11253,48 +11229,19 @@ nsresult nsDocShell::AddToSessionHistory(
|
||||
saveLayoutState, expired);
|
||||
|
||||
if (root == static_cast<nsIDocShellTreeItem*>(this) && mSessionHistory) {
|
||||
// If we need to clone our children onto the new session
|
||||
// history entry, do so now.
|
||||
if (aCloneChildren && mOSHE) {
|
||||
uint32_t cloneID = mOSHE->GetID();
|
||||
nsCOMPtr<nsISHEntry> newEntry;
|
||||
nsSHistory::CloneAndReplace(mOSHE, this, cloneID, entry, true,
|
||||
getter_AddRefs(newEntry));
|
||||
NS_ASSERTION(entry == newEntry,
|
||||
"The new session history should be in the new entry");
|
||||
bool shouldPersist = ShouldAddToSessionHistory(aURI, aChannel);
|
||||
Maybe<int32_t> previousEntryIndex;
|
||||
Maybe<int32_t> loadedEntryIndex;
|
||||
rv = mSessionHistory->LegacySHistory()->AddToRootSessionHistory(
|
||||
aCloneChildren, mOSHE, mBrowsingContext, entry, mLoadType,
|
||||
shouldPersist, &previousEntryIndex, &loadedEntryIndex);
|
||||
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Could not add entry to root session history");
|
||||
if (previousEntryIndex.isSome()) {
|
||||
mPreviousEntryIndex = previousEntryIndex.value();
|
||||
}
|
||||
|
||||
// This is the root docshell
|
||||
bool addToSHistory =
|
||||
!LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY);
|
||||
if (!addToSHistory) {
|
||||
// Replace current entry in session history; If the requested index is
|
||||
// valid, it indicates the loading was triggered by a history load, and
|
||||
// we should replace the entry at requested index instead.
|
||||
int32_t index = mSessionHistory->LegacySHistory()->GetRequestedIndex();
|
||||
if (index == -1) {
|
||||
index = mSessionHistory->Index();
|
||||
}
|
||||
|
||||
// Replace the current entry with the new entry
|
||||
if (index >= 0) {
|
||||
rv = mSessionHistory->LegacySHistory()->ReplaceEntry(index, entry);
|
||||
} else {
|
||||
// If we're trying to replace an inexistant shistory entry, append.
|
||||
addToSHistory = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (addToSHistory) {
|
||||
// Add to session history
|
||||
mPreviousEntryIndex = mSessionHistory->Index();
|
||||
|
||||
bool shouldPersist = ShouldAddToSessionHistory(aURI, aChannel);
|
||||
rv = mSessionHistory->LegacySHistory()->AddEntry(entry, shouldPersist);
|
||||
mLoadedEntryIndex = mSessionHistory->Index();
|
||||
MOZ_LOG(gPageCacheLog, LogLevel::Verbose,
|
||||
("Previous index: %d, Loaded index: %d", mPreviousEntryIndex,
|
||||
mLoadedEntryIndex));
|
||||
if (loadedEntryIndex.isSome()) {
|
||||
mLoadedEntryIndex = loadedEntryIndex.value();
|
||||
}
|
||||
} else {
|
||||
// This is a subframe.
|
||||
@ -11427,6 +11374,36 @@ void nsDocShell::SwapHistoryEntries(nsISHEntry* aOldEntry,
|
||||
}
|
||||
}
|
||||
|
||||
void nsDocShell::SetHistoryEntryAndUpdateBC(const Maybe<nsISHEntry*>& aLSHE,
|
||||
const Maybe<nsISHEntry*>& aOSHE) {
|
||||
if (aLSHE.isSome()) {
|
||||
SetHistoryEntry(&mLSHE, aLSHE.value());
|
||||
MOZ_ASSERT(mLSHE.get() == aLSHE.value());
|
||||
}
|
||||
if (aOSHE.isSome()) {
|
||||
SetHistoryEntry(&mOSHE, aOSHE.value());
|
||||
MOZ_ASSERT(mOSHE.get() == aOSHE.value());
|
||||
}
|
||||
|
||||
// If the SH pref is off and we are not a parent process do not update
|
||||
// canonical BC
|
||||
if (!StaticPrefs::fission_sessionHistoryInParent() &&
|
||||
XRE_IsContentProcess()) {
|
||||
return;
|
||||
}
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
RefPtr<BrowsingContext> bc =
|
||||
mBrowsingContext->IsDiscarded() ? nullptr : mBrowsingContext;
|
||||
if (XRE_IsParentProcess()) {
|
||||
// We are in the parent process, thus we can update the entries directly
|
||||
mBrowsingContext->Canonical()->UpdateSHEntries(mLSHE, mOSHE);
|
||||
} else {
|
||||
// We can't update canonical BC directly, so do it over IPC call
|
||||
cc->SendUpdateSHEntriesInBC(static_cast<SHEntryChild*>(mLSHE.get()),
|
||||
static_cast<SHEntryChild*>(mOSHE.get()), bc);
|
||||
}
|
||||
}
|
||||
|
||||
void nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr,
|
||||
nsISHEntry* aEntry) {
|
||||
// We need to sync up the docshell and session history trees for
|
||||
@ -11435,32 +11412,14 @@ void nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr,
|
||||
// to their corresponding entries in the new session history tree.
|
||||
// If we don't do this, then we can cache a content viewer on the wrong
|
||||
// cloned entry, and subsequently restore it at the wrong time.
|
||||
|
||||
nsCOMPtr<nsISHEntry> newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
|
||||
if (newRootEntry) {
|
||||
// newRootEntry is now the new root entry.
|
||||
// Find the old root entry as well.
|
||||
|
||||
// Need a strong ref. on |oldRootEntry| so it isn't destroyed when
|
||||
// SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
|
||||
nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(*aPtr);
|
||||
if (oldRootEntry) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
|
||||
GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
|
||||
nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
|
||||
if (rootShell) { // if we're the root just set it, nothing to swap
|
||||
nsSHistory::SwapEntriesData data = {this, newRootEntry};
|
||||
nsIDocShell* rootIDocShell = static_cast<nsIDocShell*>(rootShell);
|
||||
nsDocShell* rootDocShell = static_cast<nsDocShell*>(rootIDocShell);
|
||||
|
||||
#ifdef DEBUG
|
||||
nsresult rv =
|
||||
#endif
|
||||
nsSHistory::SetChildHistoryEntry(oldRootEntry, rootDocShell, 0,
|
||||
&data);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
|
||||
}
|
||||
}
|
||||
RefPtr<BrowsingContext> topBC = mBrowsingContext->Top();
|
||||
if (topBC->IsDiscarded()) {
|
||||
topBC = nullptr;
|
||||
}
|
||||
RefPtr<BrowsingContext> currBC =
|
||||
mBrowsingContext->IsDiscarded() ? nullptr : mBrowsingContext;
|
||||
if (topBC && *aPtr) {
|
||||
(*aPtr)->SyncTreesForSubframeNavigation(aEntry, topBC, currBC);
|
||||
}
|
||||
|
||||
*aPtr = aEntry;
|
||||
|
@ -661,6 +661,11 @@ class nsDocShell final : public nsDocLoader,
|
||||
// in the case of a subframe navigation.
|
||||
void SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr, nsISHEntry* aEntry);
|
||||
|
||||
// This method calls SetHistoryEntry and updates mOSHE and mLSHE in BC to be
|
||||
// the same as in docshell
|
||||
void SetHistoryEntryAndUpdateBC(const Maybe<nsISHEntry*>& aLSHE,
|
||||
const Maybe<nsISHEntry*>& aOSHE);
|
||||
|
||||
//
|
||||
// URI Load
|
||||
//
|
||||
|
@ -108,6 +108,10 @@ parent:
|
||||
sync ReplaceChild(PSHEntry newChildEntry) returns (nsresult result);
|
||||
async ClearEntry(uint64_t aNewSharedID);
|
||||
sync CreateLoadInfo() returns (nsDocShellLoadState loadState);
|
||||
sync Clone() returns (CrossProcessSHEntry result);
|
||||
sync SyncTreesForSubframeNavigation(nullable PSHEntry entry, MaybeDiscardedBrowsingContext BC,
|
||||
MaybeDiscardedBrowsingContext ignoreBC)
|
||||
returns (SwapEntriesDocshellData[] entriesToUpdate);
|
||||
|
||||
async UpdateLayoutHistoryState(bool scrollPositionOnly,
|
||||
nsCString[] keys, PresState[] states);
|
||||
|
@ -62,6 +62,22 @@ parent:
|
||||
async EnsureCorrectEntryAtCurrIndex(PSHEntry entry);
|
||||
async EvictContentViewersOrReplaceEntry(nullable PSHEntry newSHEntry, bool replace);
|
||||
async NotifyListenersContentViewerEvicted(uint32_t numEvicted);
|
||||
// See below for some explanation
|
||||
sync AddToRootSessionHistory(bool cloneChildren, nullable PSHEntry OSHE, MaybeDiscardedBrowsingContext BC, PSHEntry entry,
|
||||
uint32_t loadType, bool shouldPersist) returns (int32_t? previousEntryIndex, int32_t? loadedEntryIndex,
|
||||
SwapEntriesDocshellData[] entriesToUpdate, int32_t entriesPurged, nsresult result);
|
||||
// In CloneAndReplaceChild and SetChildHistoryEntry methods (which get called within this
|
||||
// and above function) there are calls to SwapHistoryEntries to update entries in the docshell.
|
||||
// We don't have access to the docshell in the parent
|
||||
// process so we have to either wait to update the docshell or update it via an IPC call.
|
||||
// We pass in the ChildID of the process who invoked the IPC to make decisions
|
||||
// about whether we should update entries in the docshell via an IPC call -
|
||||
// if the caller is a process different from where the docshell lives.
|
||||
// Else, we return entries that we need to update in entriesToUpdate array
|
||||
// and update the docshell with such entries in the child process.
|
||||
sync AddChildSHEntryHelper(PSHEntry cloneRef, PSHEntry newEntry, MaybeDiscardedBrowsingContext BC,
|
||||
bool cloneChildren) returns (SwapEntriesDocshellData[] entriesToUpdate,
|
||||
int32_t entriesPurged, CrossProcessSHEntry entry, nsresult result);
|
||||
async __delete__();
|
||||
|
||||
child:
|
||||
|
@ -604,9 +604,11 @@ SHEntryChild::Create(
|
||||
|
||||
NS_IMETHODIMP
|
||||
SHEntryChild::Clone(nsISHEntry** aResult) {
|
||||
NS_IF_ADDREF(*aResult = static_cast<SHEntryChild*>(
|
||||
ContentChild::GetSingleton()->SendPSHEntryConstructor(
|
||||
mShared->mSHistory, this)));
|
||||
RefPtr<CrossProcessSHEntry> result;
|
||||
if (!SendClone(&result)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aResult = result ? do_AddRef(result->ToSHEntryChild()).take() : nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1009,6 +1011,31 @@ SHEntryChild::GetBfcacheID(uint64_t* aBFCacheID) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
SHEntryChild::SyncTreesForSubframeNavigation(nsISHEntry* aEntry,
|
||||
BrowsingContext* aBC,
|
||||
BrowsingContext* aIgnoreBC) {
|
||||
nsTArray<SwapEntriesDocshellData> entriesToUpdate;
|
||||
Unused << SendSyncTreesForSubframeNavigation(
|
||||
static_cast<SHEntryChild*>(aEntry), aBC, aIgnoreBC, &entriesToUpdate);
|
||||
for (auto& data : entriesToUpdate) {
|
||||
// data.context() is a MaybeDiscardedBrowsingContext
|
||||
// It can't be null, but if it has been discarded we will update
|
||||
// the docshell anyway
|
||||
MOZ_ASSERT(!data.context().IsNull(), "Browsing context cannot be null");
|
||||
nsDocShell* docshell = static_cast<nsDocShell*>(
|
||||
data.context().GetMaybeDiscarded()->GetDocShell());
|
||||
if (docshell) {
|
||||
RefPtr<SHEntryChild> oldEntry = data.oldEntry()->ToSHEntryChild();
|
||||
RefPtr<SHEntryChild> newEntry;
|
||||
if (data.newEntry()) {
|
||||
newEntry = data.newEntry()->ToSHEntryChild();
|
||||
}
|
||||
docshell->SwapHistoryEntries(oldEntry, newEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHEntryChild::EvictContentViewer() {
|
||||
nsCOMPtr<nsIContentViewer> viewer = GetContentViewer();
|
||||
if (viewer) {
|
||||
|
@ -64,6 +64,13 @@ LegacySHEntry::GetBfcacheID(uint64_t* aBFCacheID) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LegacySHEntry::Clone(nsISHEntry** aResult) {
|
||||
nsCOMPtr<nsISHEntry> entry = new LegacySHEntry(*this);
|
||||
entry.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void SHEntryParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
mEntry->mActor = nullptr;
|
||||
}
|
||||
@ -582,5 +589,31 @@ bool SHEntryParent::RecvUpdateLayoutHistoryState(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHEntryParent::RecvClone(RefPtr<CrossProcessSHEntry>* aResult) {
|
||||
nsCOMPtr<nsISHEntry> result;
|
||||
DebugOnly<nsresult> rv =
|
||||
static_cast<LegacySHEntry*>(mEntry)->Clone(getter_AddRefs(result));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
|
||||
*aResult = result.forget().downcast<LegacySHEntry>();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHEntryParent::RecvSyncTreesForSubframeNavigation(
|
||||
PSHEntryParent* aSHEntry, const MaybeDiscarded<BrowsingContext>& aBC,
|
||||
const MaybeDiscarded<BrowsingContext>& aIgnoreBC,
|
||||
nsTArray<SwapEntriesDocshellData>* aEntriesToUpdate) {
|
||||
nsTArray<EntriesAndBrowsingContextData> entriesToSendOverIPC;
|
||||
// aBC or aIgnoreBC can be discarded but we can update them anyway if they are
|
||||
// not null
|
||||
mEntry->SyncTreesForSubframeNavigation(
|
||||
static_cast<ContentParent*>(Manager())->ChildID(),
|
||||
aSHEntry ? static_cast<SHEntryParent*>(aSHEntry)->mEntry.get() : nullptr,
|
||||
aBC.GetMaybeDiscarded(), aIgnoreBC.GetMaybeDiscarded(),
|
||||
&entriesToSendOverIPC);
|
||||
SHistoryParent::CreateActorsForSwapEntries(entriesToSendOverIPC,
|
||||
aEntriesToUpdate, Manager());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -77,6 +77,8 @@ class LegacySHEntry final : public nsSHEntry, public CrossProcessSHEntry {
|
||||
return mShared.get();
|
||||
}
|
||||
|
||||
NS_IMETHOD Clone(nsISHEntry** aResult) override;
|
||||
|
||||
private:
|
||||
friend class SHEntryParent;
|
||||
friend class SHistoryParent;
|
||||
@ -203,6 +205,12 @@ class SHEntryParent final : public PSHEntryParent {
|
||||
bool RecvClearEntry(const uint64_t& aNewSharedID);
|
||||
|
||||
bool RecvCreateLoadInfo(RefPtr<nsDocShellLoadState>* aLoadState);
|
||||
bool RecvClone(RefPtr<CrossProcessSHEntry>* aResult);
|
||||
|
||||
bool RecvSyncTreesForSubframeNavigation(
|
||||
PSHEntryParent* aSHEntry, const MaybeDiscarded<BrowsingContext>& aBC,
|
||||
const MaybeDiscarded<BrowsingContext>& aIgnoreBC,
|
||||
nsTArray<SwapEntriesDocshellData>* aEntriesToUpdate);
|
||||
|
||||
bool RecvUpdateLayoutHistoryState(const bool& aScrollPositionOnly,
|
||||
nsTArray<nsCString>&& aKeys,
|
||||
|
@ -8,6 +8,11 @@
|
||||
#include "SHEntryChild.h"
|
||||
#include "nsISHistoryListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class SwapEntriesDocshellData;
|
||||
}
|
||||
} // namespace mozilla
|
||||
#define CONTENT_VIEWER_TIMEOUT_SECONDS \
|
||||
"browser.sessionhistory.contentViewerTimeout"
|
||||
|
||||
@ -392,5 +397,70 @@ nsresult SHistoryChild::LoadURI(nsTArray<LoadSHEntryData>& aLoadData) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SHistoryChild::AddToRootSessionHistory(bool aCloneChildren, nsISHEntry* aOSHE,
|
||||
BrowsingContext* aBC, nsISHEntry* aEntry,
|
||||
uint32_t aLoadType, bool aShouldPersist,
|
||||
Maybe<int32_t>* aPreviousEntryIndex,
|
||||
Maybe<int32_t>* aLoadedEntryIndex) {
|
||||
nsresult rv;
|
||||
int32_t entriesPurged;
|
||||
nsTArray<SwapEntriesDocshellData> entriesToUpdate;
|
||||
if (!SendAddToRootSessionHistory(
|
||||
aCloneChildren, static_cast<SHEntryChild*>(aOSHE), aBC,
|
||||
static_cast<SHEntryChild*>(aEntry), aLoadType, aShouldPersist,
|
||||
aPreviousEntryIndex, aLoadedEntryIndex, &entriesToUpdate,
|
||||
&entriesPurged, &rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
for (auto& data : entriesToUpdate) {
|
||||
MOZ_ASSERT(!data.context().IsNull(), "Browsing context cannot be null");
|
||||
nsDocShell* docshell = static_cast<nsDocShell*>(
|
||||
data.context().GetMaybeDiscarded()->GetDocShell());
|
||||
if (docshell) {
|
||||
docshell->SwapHistoryEntries(data.oldEntry()->ToSHEntryChild(),
|
||||
data.newEntry()->ToSHEntryChild());
|
||||
}
|
||||
}
|
||||
if (NS_SUCCEEDED(rv) && mRootDocShell && entriesPurged > 0) {
|
||||
mRootDocShell->HistoryPurged(entriesPurged);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SHistoryChild::AddChildSHEntryHelper(nsISHEntry* aCloneRef,
|
||||
nsISHEntry* aNewEntry,
|
||||
BrowsingContext* aBC,
|
||||
bool aCloneChildren) {
|
||||
nsresult rv;
|
||||
RefPtr<CrossProcessSHEntry> child;
|
||||
int32_t entriesPurged;
|
||||
nsTArray<SwapEntriesDocshellData> entriesToUpdate;
|
||||
if (!SendAddChildSHEntryHelper(static_cast<SHEntryChild*>(aCloneRef),
|
||||
static_cast<SHEntryChild*>(aNewEntry), aBC,
|
||||
aCloneChildren, &entriesToUpdate,
|
||||
&entriesPurged, &child, &rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
for (auto& data : entriesToUpdate) {
|
||||
MOZ_ASSERT(!data.context().IsNull(), "Browsing context cannot be null");
|
||||
nsDocShell* docshell = static_cast<nsDocShell*>(
|
||||
data.context().GetMaybeDiscarded()->GetDocShell());
|
||||
if (docshell) {
|
||||
docshell->SwapHistoryEntries(data.oldEntry()->ToSHEntryChild(),
|
||||
data.newEntry()->ToSHEntryChild());
|
||||
}
|
||||
}
|
||||
if (!child) {
|
||||
return rv;
|
||||
}
|
||||
if (NS_SUCCEEDED(rv) && mRootDocShell && entriesPurged > 0) {
|
||||
mRootDocShell->HistoryPurged(entriesPurged);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -47,19 +47,12 @@ SHistoryParent::SHistoryParent(CanonicalBrowsingContext* aContext)
|
||||
|
||||
SHistoryParent::~SHistoryParent() { mHistory->mSHistoryParent = nullptr; }
|
||||
|
||||
SHEntryParent* SHistoryParent::CreateEntry(
|
||||
PContentParent* aContentParent, PSHistoryParent* aSHistoryParent,
|
||||
const PSHEntryOrSharedID& aEntryOrSharedID) {
|
||||
RefPtr<LegacySHEntry> entry;
|
||||
if (aEntryOrSharedID.type() == PSHEntryOrSharedID::Tuint64_t) {
|
||||
entry = new LegacySHEntry(
|
||||
aContentParent, static_cast<SHistoryParent*>(aSHistoryParent)->mHistory,
|
||||
aEntryOrSharedID.get_uint64_t());
|
||||
} else {
|
||||
entry = new LegacySHEntry(*(
|
||||
static_cast<const SHEntryParent*>(aEntryOrSharedID.get_PSHEntryParent())
|
||||
->mEntry));
|
||||
}
|
||||
SHEntryParent* SHistoryParent::CreateEntry(PContentParent* aContentParent,
|
||||
PSHistoryParent* aSHistoryParent,
|
||||
uint64_t aSharedID) {
|
||||
RefPtr<LegacySHEntry> entry = new LegacySHEntry(
|
||||
aContentParent, static_cast<SHistoryParent*>(aSHistoryParent)->mHistory,
|
||||
aSharedID);
|
||||
return entry->CreateActor();
|
||||
}
|
||||
|
||||
@ -375,5 +368,65 @@ LegacySHistory::ReloadCurrentEntry() {
|
||||
: NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool SHistoryParent::RecvAddToRootSessionHistory(
|
||||
bool aCloneChildren, PSHEntryParent* aOSHE,
|
||||
const MaybeDiscarded<BrowsingContext>& aBC, PSHEntryParent* aEntry,
|
||||
uint32_t aLoadType, bool aShouldPersist,
|
||||
Maybe<int32_t>* aPreviousEntryIndex, Maybe<int32_t>* aLoadedEntryIndex,
|
||||
nsTArray<SwapEntriesDocshellData>* aEntriesToUpdate,
|
||||
int32_t* aEntriesPurged, nsresult* aResult) {
|
||||
MOZ_ASSERT(!aBC.IsNull(), "Browsing context cannot be null");
|
||||
nsTArray<EntriesAndBrowsingContextData> entriesToSendOverIDL;
|
||||
*aResult = mHistory->AddToRootSessionHistory(
|
||||
aCloneChildren,
|
||||
aOSHE ? static_cast<SHEntryParent*>(aOSHE)->mEntry.get() : nullptr,
|
||||
aBC.GetMaybeDiscarded(),
|
||||
static_cast<SHEntryParent*>(aEntry)->mEntry.get(), aLoadType,
|
||||
aShouldPersist, static_cast<ContentParent*>(Manager())->ChildID(),
|
||||
aPreviousEntryIndex, aLoadedEntryIndex, &entriesToSendOverIDL,
|
||||
aEntriesPurged);
|
||||
SHistoryParent::CreateActorsForSwapEntries(entriesToSendOverIDL,
|
||||
aEntriesToUpdate, Manager());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHistoryParent::RecvAddChildSHEntryHelper(
|
||||
PSHEntryParent* aCloneRef, PSHEntryParent* aNewEntry,
|
||||
const MaybeDiscarded<BrowsingContext>& aBC, bool aCloneChildren,
|
||||
nsTArray<SwapEntriesDocshellData>* aEntriesToUpdate,
|
||||
int32_t* aEntriesPurged, RefPtr<CrossProcessSHEntry>* aChild,
|
||||
nsresult* aResult) {
|
||||
MOZ_ASSERT(!aBC.IsNull(), "Browsing context cannot be null");
|
||||
nsCOMPtr<nsISHEntry> child;
|
||||
nsTArray<EntriesAndBrowsingContextData> entriesToSendOverIPC;
|
||||
*aResult = mHistory->AddChildSHEntryHelper(
|
||||
static_cast<SHEntryParent*>(aCloneRef)->mEntry.get(),
|
||||
aNewEntry ? static_cast<SHEntryParent*>(aNewEntry)->mEntry.get()
|
||||
: nullptr,
|
||||
aBC.GetMaybeDiscarded(), aCloneChildren,
|
||||
static_cast<ContentParent*>(Manager())->ChildID(), &entriesToSendOverIPC,
|
||||
aEntriesPurged, getter_AddRefs(child));
|
||||
SHistoryParent::CreateActorsForSwapEntries(entriesToSendOverIPC,
|
||||
aEntriesToUpdate, Manager());
|
||||
*aChild = child.forget().downcast<LegacySHEntry>();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHistoryParent::CreateActorsForSwapEntries(
|
||||
const nsTArray<EntriesAndBrowsingContextData>& aEntriesToSendOverIPC,
|
||||
nsTArray<SwapEntriesDocshellData>* aEntriesToUpdate,
|
||||
PContentParent* aContentParent) {
|
||||
for (auto& data : aEntriesToSendOverIPC) {
|
||||
SwapEntriesDocshellData* toUpdate = aEntriesToUpdate->AppendElement();
|
||||
|
||||
// Old entry
|
||||
toUpdate->oldEntry() = static_cast<LegacySHEntry*>(data.oldEntry.get());
|
||||
|
||||
// New entry
|
||||
toUpdate->newEntry() = static_cast<LegacySHEntry*>(data.newEntry.get());
|
||||
toUpdate->context() = data.context;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -59,7 +59,14 @@ class SHistoryParent final : public PSHistoryParent {
|
||||
|
||||
static SHEntryParent* CreateEntry(PContentParent* aContentParent,
|
||||
PSHistoryParent* aSHistoryParent,
|
||||
const PSHEntryOrSharedID& aEntryOrSharedID);
|
||||
uint64_t aSharedID);
|
||||
|
||||
// We have a list of entries we would like to return from
|
||||
// the IPC call and we need to create actors for all of them
|
||||
static void CreateActorsForSwapEntries(
|
||||
const nsTArray<EntriesAndBrowsingContextData>& aEntriesToSendOverIPC,
|
||||
nsTArray<SwapEntriesDocshellData>* aEntriesToUpdate,
|
||||
PContentParent* aContentParent);
|
||||
|
||||
protected:
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
@ -99,7 +106,21 @@ class SHistoryParent final : public PSHistoryParent {
|
||||
bool RecvEvictContentViewersOrReplaceEntry(PSHEntryParent* aNewSHEntry,
|
||||
bool aReplace);
|
||||
bool RecvNotifyListenersContentViewerEvicted(uint32_t aNumEvicted);
|
||||
bool RecvAddToRootSessionHistory(
|
||||
bool aCloneChildren, PSHEntryParent* aOSHE,
|
||||
const MaybeDiscarded<BrowsingContext>& aBC, PSHEntryParent* aEntry,
|
||||
uint32_t aLoadType, bool aShouldPersist,
|
||||
Maybe<int32_t>* aPreviousEntryIndex, Maybe<int32_t>* aLoadedEntryIndex,
|
||||
nsTArray<SwapEntriesDocshellData>* aEntriesToUpdate,
|
||||
int32_t* aEntriesPurged, nsresult* aResult);
|
||||
bool RecvAddChildSHEntryHelper(
|
||||
PSHEntryParent* aCloneRef, PSHEntryParent* aNewEntry,
|
||||
const MaybeDiscarded<BrowsingContext>& aBC, bool aCloneChildren,
|
||||
nsTArray<SwapEntriesDocshellData>* aEntriesToUpdate,
|
||||
int32_t* aEntriesPurged, RefPtr<CrossProcessSHEntry>* aChild,
|
||||
nsresult* aResult);
|
||||
|
||||
RefPtr<CanonicalBrowsingContext> mContext;
|
||||
RefPtr<LegacySHistory> mHistory;
|
||||
};
|
||||
|
||||
|
@ -37,10 +37,12 @@ class SHEntrySharedParentState;
|
||||
}
|
||||
class nsSHEntryShared;
|
||||
class nsDocShellLoadState;
|
||||
struct EntriesAndBrowsingContextData;
|
||||
%}
|
||||
[ref] native nsIntRect(nsIntRect);
|
||||
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
|
||||
[ptr] native nsDocShellLoadStatePtr(nsDocShellLoadState);
|
||||
webidl BrowsingContext;
|
||||
|
||||
[builtinclass, scriptable, uuid(0dad26b8-a259-42c7-93f1-2fa7fc076e45)]
|
||||
interface nsISHEntry : nsISupports
|
||||
@ -429,5 +431,17 @@ interface nsISHEntry : nsISupports
|
||||
* lives there. With in-process session history this method is no-op.
|
||||
*/
|
||||
void synchronizeLayoutHistoryState();
|
||||
|
||||
/**
|
||||
* Sync up the docshell and session history trees for subframe navigation.
|
||||
*
|
||||
* @param aEntry new entry
|
||||
* @param aTopBC top BC corresponding to the root ancestor
|
||||
of the docshell that called this method
|
||||
* @param aIgnoreBC current BC
|
||||
*/
|
||||
[notxpcom] void SyncTreesForSubframeNavigation(in nsISHEntry aEntry,
|
||||
in BrowsingContext aTopBC,
|
||||
in BrowsingContext aIgnoreBC);
|
||||
};
|
||||
|
||||
|
@ -9,13 +9,16 @@ interface nsIBFCacheEntry;
|
||||
interface nsISHEntry;
|
||||
interface nsISHistoryListener;
|
||||
interface nsIURI;
|
||||
webidl BrowsingContext;
|
||||
|
||||
%{C++
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
struct EntriesAndBrowsingContextData;
|
||||
%}
|
||||
|
||||
[ref] native nsDocshellIDArray(nsTArray<nsID>);
|
||||
|
||||
native MaybeInt32(Maybe<int32_t>);
|
||||
/**
|
||||
* An interface to the primary properties of the Session History
|
||||
* component. In an embedded browser environment, the nsIWebBrowser
|
||||
@ -266,4 +269,14 @@ interface nsISHistory: nsISupports
|
||||
[notxpcom] void EvictContentViewersOrReplaceEntry(in nsISHEntry aNewSHEntry, in bool aReplace);
|
||||
|
||||
nsISHEntry createEntry();
|
||||
|
||||
[noscript] void AddToRootSessionHistory(in bool aCloneChildren, in nsISHEntry aOSHE,
|
||||
in BrowsingContext aBC, in nsISHEntry aEntry,
|
||||
in unsigned long aLoadType,
|
||||
in bool aShouldPersist,
|
||||
out MaybeInt32 aPreviousEntryIndex,
|
||||
out MaybeInt32 aLoadedEntryIndex);
|
||||
|
||||
[noscript] void AddChildSHEntryHelper(in nsISHEntry aCloneRef, in nsISHEntry aNewEntry,
|
||||
in BrowsingContext aBC, in bool aCloneChildren);
|
||||
};
|
||||
|
@ -1020,6 +1020,48 @@ nsSHEntry::GetBfcacheID(uint64_t* aBFCacheID) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsSHEntry::SyncTreesForSubframeNavigation(
|
||||
uint64_t aOtherPid, nsISHEntry* aEntry,
|
||||
mozilla::dom::BrowsingContext* aTopBC,
|
||||
mozilla::dom::BrowsingContext* aIgnoreBC,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate) {
|
||||
MOZ_ASSERT(aEntriesToUpdate || aOtherPid == 0,
|
||||
"our entries to update is null");
|
||||
|
||||
// We need to sync up the browsing context and session history trees for
|
||||
// subframe navigation. If the load was in a subframe, we forward up to
|
||||
// the top browsing context, which will then recursively sync up all browsing
|
||||
// contexts to their corresponding entries in the new session history tree. If
|
||||
// we don't do this, then we can cache a content viewer on the wrong cloned
|
||||
// entry, and subsequently restore it at the wrong time.
|
||||
nsCOMPtr<nsISHEntry> newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
|
||||
if (newRootEntry) {
|
||||
// newRootEntry is now the new root entry.
|
||||
// Find the old root entry as well.
|
||||
|
||||
// Need a strong ref. on |oldRootEntry| so it isn't destroyed when
|
||||
// SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
|
||||
nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(this);
|
||||
|
||||
if (oldRootEntry) {
|
||||
nsSHistory::SwapEntriesData data = {aIgnoreBC, newRootEntry, nullptr,
|
||||
aOtherPid, aEntriesToUpdate};
|
||||
nsSHistory::SetChildHistoryEntry(oldRootEntry, aTopBC, 0, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsSHEntry::SyncTreesForSubframeNavigation(
|
||||
nsISHEntry* aEntry, mozilla::dom::BrowsingContext* aTopBC,
|
||||
mozilla::dom::BrowsingContext* aIgnoreBC) {
|
||||
SyncTreesForSubframeNavigation(
|
||||
0 /* unused, this will be set in SHEntryParent::RecvSyncTrees */,
|
||||
aEntry, aTopBC, aIgnoreBC,
|
||||
nullptr /* this will be given in SHEntryCHild::SyncTrees if we
|
||||
are going over IPC, else, it is not needed */);
|
||||
}
|
||||
|
||||
void nsSHEntry::EvictContentViewer() {
|
||||
nsCOMPtr<nsIContentViewer> viewer = GetContentViewer();
|
||||
if (viewer) {
|
||||
|
@ -28,6 +28,17 @@ class nsIInputStream;
|
||||
class nsIURI;
|
||||
class nsIReferrerInfo;
|
||||
|
||||
// Structure for passing around entries via XPCOM from methods such as
|
||||
// nsSHistory::CloneAndReplaceChild, nsSHistory::SetChildHistoryEntry and
|
||||
// nsSHEntry::SyncTreesForSubframeNavigation, that need to swap entries in
|
||||
// docshell, to corresponding Recv methods so that we don't have to create
|
||||
// actors until we are about to return from the parent process
|
||||
struct EntriesAndBrowsingContextData {
|
||||
nsCOMPtr<nsISHEntry> oldEntry;
|
||||
nsCOMPtr<nsISHEntry> newEntry;
|
||||
mozilla::dom::BrowsingContext* context;
|
||||
};
|
||||
|
||||
class nsSHEntry : public nsISHEntry {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -37,6 +48,11 @@ class nsSHEntry : public nsISHEntry {
|
||||
|
||||
static nsresult Startup();
|
||||
static void Shutdown();
|
||||
void SyncTreesForSubframeNavigation(
|
||||
uint64_t aOtherPid, nsISHEntry* aEntry,
|
||||
mozilla::dom::BrowsingContext* aTopBC,
|
||||
mozilla::dom::BrowsingContext* aIgnoreBC,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate);
|
||||
|
||||
protected:
|
||||
explicit nsSHEntry(mozilla::dom::SHEntrySharedParentState* aState);
|
||||
|
@ -32,6 +32,9 @@
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsDocShellLoadTypes.h"
|
||||
#include "base/process.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -63,6 +66,8 @@ LazyLogModule gSHistoryLog("nsSHistory");
|
||||
|
||||
#define LOG(format) MOZ_LOG(gSHistoryLog, mozilla::LogLevel::Debug, format)
|
||||
|
||||
extern mozilla::LazyLogModule gPageCacheLog;
|
||||
|
||||
// This macro makes it easier to print a log message which includes a URI's
|
||||
// spec. Example use:
|
||||
//
|
||||
@ -363,7 +368,7 @@ already_AddRefed<nsISHEntry> nsSHistory::GetRootSHEntry(nsISHEntry* aEntry) {
|
||||
|
||||
// static
|
||||
nsresult nsSHistory::WalkHistoryEntries(nsISHEntry* aRootEntry,
|
||||
nsDocShell* aRootShell,
|
||||
BrowsingContext* aBC,
|
||||
WalkHistoryEntriesFunc aCallback,
|
||||
void* aData) {
|
||||
NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
|
||||
@ -380,24 +385,30 @@ nsresult nsSHistory::WalkHistoryEntries(nsISHEntry* aRootEntry,
|
||||
continue;
|
||||
}
|
||||
|
||||
nsDocShell* childShell = nullptr;
|
||||
if (aRootShell) {
|
||||
// Walk the children of aRootShell and see if one of them
|
||||
// has srcChild as a SHEntry.
|
||||
int32_t length;
|
||||
aRootShell->GetInProcessChildCount(&length);
|
||||
for (int32_t i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> item;
|
||||
nsresult rv = aRootShell->GetInProcessChildAt(i, getter_AddRefs(item));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsDocShell* child = static_cast<nsDocShell*>(item.get());
|
||||
if (child->HasHistoryEntry(childEntry)) {
|
||||
childShell = child;
|
||||
break;
|
||||
BrowsingContext* childBC = nullptr;
|
||||
if (aBC) {
|
||||
for (BrowsingContext* child : aBC->GetChildren()) {
|
||||
// If the SH pref is on, or we are in the parent process, update
|
||||
// canonical BC directly
|
||||
if (StaticPrefs::fission_sessionHistoryInParent() ||
|
||||
XRE_IsParentProcess()) {
|
||||
// Walk the children of the browsing context and see if one of them
|
||||
// has childEntry as mOSHE or mLSHE
|
||||
if (child->Canonical()->HasHistoryEntry(childEntry)) {
|
||||
childBC = child;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
nsDocShell* docshell = static_cast<nsDocShell*>(child->GetDocShell());
|
||||
if (docshell && docshell->HasHistoryEntry(childEntry)) {
|
||||
childBC = docshell->GetBrowsingContext();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nsresult rv = aCallback(childEntry, childShell, i, aData);
|
||||
|
||||
nsresult rv = aCallback(childEntry, childBC, i, aData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
@ -407,32 +418,42 @@ nsresult nsSHistory::WalkHistoryEntries(nsISHEntry* aRootEntry,
|
||||
// callback data for WalkHistoryEntries
|
||||
struct MOZ_STACK_CLASS CloneAndReplaceData {
|
||||
CloneAndReplaceData(uint32_t aCloneID, nsISHEntry* aReplaceEntry,
|
||||
bool aCloneChildren, nsISHEntry* aDestTreeParent)
|
||||
bool aCloneChildren, nsISHEntry* aDestTreeParent,
|
||||
uint64_t aOtherPid,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate)
|
||||
: cloneID(aCloneID),
|
||||
cloneChildren(aCloneChildren),
|
||||
replaceEntry(aReplaceEntry),
|
||||
destTreeParent(aDestTreeParent) {}
|
||||
destTreeParent(aDestTreeParent),
|
||||
otherPid(aOtherPid),
|
||||
entriesToUpdate(aEntriesToUpdate) {}
|
||||
|
||||
uint32_t cloneID;
|
||||
bool cloneChildren;
|
||||
nsISHEntry* replaceEntry;
|
||||
nsISHEntry* destTreeParent;
|
||||
nsCOMPtr<nsISHEntry> resultEntry;
|
||||
uint64_t otherPid;
|
||||
// see comment for WalkHistoryEntriesFunc
|
||||
nsTArray<EntriesAndBrowsingContextData>* entriesToUpdate;
|
||||
};
|
||||
|
||||
// static
|
||||
nsresult nsSHistory::CloneAndReplaceChild(nsISHEntry* aEntry,
|
||||
nsDocShell* aShell,
|
||||
int32_t aEntryIndex, void* aData) {
|
||||
BrowsingContext* aOwnerBC,
|
||||
int32_t aChildIndex, void* aData) {
|
||||
MOZ_ASSERT(
|
||||
XRE_IsParentProcess() || !StaticPrefs::fission_sessionHistoryInParent(),
|
||||
"We should be in the parent process, or SH pref should be off");
|
||||
nsCOMPtr<nsISHEntry> dest;
|
||||
|
||||
CloneAndReplaceData* data = static_cast<CloneAndReplaceData*>(aData);
|
||||
uint32_t cloneID = data->cloneID;
|
||||
nsISHEntry* replaceEntry = data->replaceEntry;
|
||||
base::ProcessId otherPid = data->otherPid;
|
||||
|
||||
if (!aEntry) {
|
||||
if (data->destTreeParent) {
|
||||
data->destTreeParent->AddChild(nullptr, aEntryIndex);
|
||||
data->destTreeParent->AddChild(nullptr, aChildIndex);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -453,47 +474,108 @@ nsresult nsSHistory::CloneAndReplaceChild(nsISHEntry* aEntry,
|
||||
if (srcID != cloneID || data->cloneChildren) {
|
||||
// Walk the children
|
||||
CloneAndReplaceData childData(cloneID, replaceEntry, data->cloneChildren,
|
||||
dest);
|
||||
rv = WalkHistoryEntries(aEntry, aShell, CloneAndReplaceChild, &childData);
|
||||
dest, otherPid, data->entriesToUpdate);
|
||||
rv = nsSHistory::WalkHistoryEntries(aEntry, aOwnerBC, CloneAndReplaceChild,
|
||||
&childData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (srcID != cloneID && aShell) {
|
||||
aShell->SwapHistoryEntries(aEntry, dest);
|
||||
if (srcID != cloneID && aOwnerBC) {
|
||||
nsSHistory::HandleEntriesToSwapInDocShell(aOwnerBC, aEntry, dest,
|
||||
data->entriesToUpdate, otherPid);
|
||||
}
|
||||
|
||||
if (data->destTreeParent) {
|
||||
data->destTreeParent->AddChild(dest, aEntryIndex);
|
||||
data->destTreeParent->AddChild(dest, aChildIndex);
|
||||
}
|
||||
|
||||
data->resultEntry = dest;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult nsSHistory::CloneAndReplace(nsISHEntry* aSrcEntry,
|
||||
nsDocShell* aSrcShell, uint32_t aCloneID,
|
||||
nsISHEntry* aReplaceEntry,
|
||||
bool aCloneChildren,
|
||||
nsISHEntry** aResultEntry) {
|
||||
NS_ENSURE_ARG_POINTER(aResultEntry);
|
||||
nsresult nsSHistory::CloneAndReplace(
|
||||
nsISHEntry* aSrcEntry, BrowsingContext* aOwnerBC, uint32_t aCloneID,
|
||||
nsISHEntry* aReplaceEntry, bool aCloneChildren, nsISHEntry** aDestEntry,
|
||||
uint64_t aOtherPid,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate) {
|
||||
NS_ENSURE_ARG_POINTER(aDestEntry);
|
||||
NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
|
||||
|
||||
CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr);
|
||||
nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
|
||||
|
||||
data.resultEntry.swap(*aResultEntry);
|
||||
CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr,
|
||||
aOtherPid, aEntriesToUpdate);
|
||||
nsresult rv = CloneAndReplaceChild(aSrcEntry, aOwnerBC, 0, &data);
|
||||
data.resultEntry.swap(*aDestEntry);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult nsSHistory::SetChildHistoryEntry(nsISHEntry* aEntry,
|
||||
nsDocShell* aShell,
|
||||
int32_t aEntryIndex, void* aData) {
|
||||
SwapEntriesData* data = static_cast<SwapEntriesData*>(aData);
|
||||
nsDocShell* ignoreShell = data->ignoreShell;
|
||||
NS_IMETHODIMP
|
||||
nsSHistory::AddChildSHEntryHelper(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
|
||||
BrowsingContext* aBC, bool aCloneChildren) {
|
||||
nsCOMPtr<nsISHEntry> child;
|
||||
int32_t entriesPurged;
|
||||
nsresult rv = AddChildSHEntryHelper(
|
||||
aCloneRef, aNewEntry, aBC, aCloneChildren,
|
||||
0 /*unused, passed in by SHEntryParent::RecvAddChildSHEntryHelper
|
||||
*/
|
||||
,
|
||||
nullptr /* array - this will be set in
|
||||
SHistory::RecvAddChildSHEntryHelper if we are going over IPC,
|
||||
else, it is not needed */
|
||||
,
|
||||
&entriesPurged /*used by SHEntryChild::AddToRootSessionHistory but
|
||||
not here */
|
||||
,
|
||||
getter_AddRefs(child));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
child->SetDocshellID(aBC->GetHistoryID());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!aShell || aShell == ignoreShell) {
|
||||
nsresult nsSHistory::AddChildSHEntryHelper(
|
||||
nsISHEntry* aCloneRef, nsISHEntry* aNewEntry, BrowsingContext* aBC,
|
||||
bool aCloneChildren, uint64_t aOtherPid,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate,
|
||||
int32_t* aEntriesPurged, nsISHEntry** aNextEntry) {
|
||||
/* You are currently in the rootDocShell.
|
||||
* You will get here when a subframe has a new url
|
||||
* to load and you have walked up the tree all the
|
||||
* way to the top to clone the current SHEntry hierarchy
|
||||
* and replace the subframe where a new url was loaded with
|
||||
* a new entry.
|
||||
*/
|
||||
nsCOMPtr<nsISHEntry> currentHE;
|
||||
int32_t index = mIndex;
|
||||
if (index < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
GetEntryAtIndex(index, getter_AddRefs(currentHE));
|
||||
NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
uint32_t cloneID = aCloneRef->GetID();
|
||||
rv = nsSHistory::CloneAndReplace(currentHE, aBC, cloneID, aNewEntry,
|
||||
aCloneChildren, aNextEntry, aOtherPid,
|
||||
aEntriesToUpdate);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = AddEntry(*aNextEntry, true, aEntriesPurged);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsSHistory::SetChildHistoryEntry(nsISHEntry* aEntry,
|
||||
BrowsingContext* aBC,
|
||||
int32_t aEntryIndex, void* aData) {
|
||||
MOZ_ASSERT(
|
||||
XRE_IsParentProcess() || !StaticPrefs::fission_sessionHistoryInParent(),
|
||||
"We should be in the parent process, or 'SH in parent' pref should be "
|
||||
"off");
|
||||
SwapEntriesData* data = static_cast<SwapEntriesData*>(aData);
|
||||
uint64_t otherPid = data->otherPid;
|
||||
MOZ_ASSERT(data->entriesToUpdate || otherPid == 0,
|
||||
"entriesToUpdate can't be null if we were called over IPC");
|
||||
|
||||
if (!aBC || aBC == data->ignoreBC) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -533,11 +615,125 @@ nsresult nsSHistory::SetChildHistoryEntry(nsISHEntry* aEntry,
|
||||
destEntry = destTreeRoot;
|
||||
}
|
||||
|
||||
aShell->SwapHistoryEntries(aEntry, destEntry);
|
||||
|
||||
nsSHistory::HandleEntriesToSwapInDocShell(aBC, aEntry, destEntry,
|
||||
data->entriesToUpdate, otherPid);
|
||||
// Now handle the children of aEntry.
|
||||
SwapEntriesData childData = {ignoreShell, destTreeRoot, destEntry};
|
||||
return WalkHistoryEntries(aEntry, aShell, SetChildHistoryEntry, &childData);
|
||||
SwapEntriesData childData = {data->ignoreBC, destTreeRoot, destEntry,
|
||||
otherPid, data->entriesToUpdate};
|
||||
return nsSHistory::WalkHistoryEntries(aEntry, aBC, SetChildHistoryEntry,
|
||||
&childData);
|
||||
}
|
||||
|
||||
// static
|
||||
void nsSHistory::HandleEntriesToSwapInDocShell(
|
||||
mozilla::dom::BrowsingContext* aBC, nsISHEntry* aOldEntry,
|
||||
nsISHEntry* aNewEntry,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate,
|
||||
uint64_t aOtherPid) {
|
||||
bool shPref = StaticPrefs::fission_sessionHistoryInParent();
|
||||
if (XRE_IsParentProcess()) {
|
||||
aBC->Canonical()->SwapHistoryEntries(aOldEntry, aNewEntry);
|
||||
}
|
||||
if (aBC->IsInProcess() || !shPref) {
|
||||
nsDocShell* docshell = static_cast<nsDocShell*>(aBC->GetDocShell());
|
||||
if (docshell) {
|
||||
docshell->SwapHistoryEntries(aOldEntry, aNewEntry);
|
||||
}
|
||||
} else if (aBC->Canonical()->IsOwnedByProcess(aOtherPid)) {
|
||||
EntriesAndBrowsingContextData* toUpdate = aEntriesToUpdate->AppendElement();
|
||||
toUpdate->oldEntry = aOldEntry;
|
||||
toUpdate->newEntry = aNewEntry;
|
||||
toUpdate->context = aBC;
|
||||
} else {
|
||||
// XXX anny: this is currently not working! see bug 1581970
|
||||
|
||||
// This BC is owned by a process different from the caller,
|
||||
// so we can send the entries right away to a different process
|
||||
ContentParent* cp = aBC->Canonical()->GetContentParent();
|
||||
|
||||
auto convert = [](auto entry) {
|
||||
return static_cast<CrossProcessSHEntry*>(
|
||||
static_cast<LegacySHEntry*>(static_cast<nsSHEntry*>(entry)));
|
||||
};
|
||||
|
||||
// We are performing a nested IPC call to a different process
|
||||
Unused << cp->SendUpdateSHEntriesInDocShell(convert(aOldEntry),
|
||||
convert(aNewEntry), aBC);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSHistory::AddToRootSessionHistory(bool aCloneChildren, nsISHEntry* aOSHE,
|
||||
BrowsingContext* aBC, nsISHEntry* aEntry,
|
||||
uint32_t aLoadType, bool aShouldPersist,
|
||||
Maybe<int32_t>* aPreviousEntryIndex,
|
||||
Maybe<int32_t>* aLoadedEntryIndex) {
|
||||
int32_t entriesPurged;
|
||||
nsresult rv = AddToRootSessionHistory(
|
||||
aCloneChildren, aOSHE, aBC, aEntry, aLoadType, aShouldPersist,
|
||||
0 /* unused, passed in by SHEntryParent::RecvAddToRootSessionHistory */,
|
||||
aPreviousEntryIndex, aLoadedEntryIndex,
|
||||
nullptr /* array - this will be set in RecvAddToRootSessionHistory if we
|
||||
are going over IPC, else, it is not needed */
|
||||
,
|
||||
&entriesPurged
|
||||
/* used by SHEntryChild::AddToRootSessionHistory but not here */);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aEntry->SetDocshellID(aBC->GetHistoryID());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
nsresult nsSHistory::AddToRootSessionHistory(
|
||||
bool aCloneChildren, nsISHEntry* aOSHE, BrowsingContext* aBC,
|
||||
nsISHEntry* aEntry, uint32_t aLoadType, bool aShouldPersist,
|
||||
uint64_t aOtherPid, Maybe<int32_t>* previousEntryIndex,
|
||||
Maybe<int32_t>* aLoadedEntryIndex,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate,
|
||||
int32_t* aEntriesPurged) {
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// If we need to clone our children onto the new session
|
||||
// history entry, do so now.
|
||||
if (aCloneChildren && aOSHE) {
|
||||
uint32_t cloneID = aOSHE->GetID();
|
||||
nsCOMPtr<nsISHEntry> newEntry;
|
||||
nsSHistory::CloneAndReplace(aOSHE, aBC, cloneID, aEntry, true,
|
||||
getter_AddRefs(newEntry), aOtherPid,
|
||||
aEntriesToUpdate);
|
||||
NS_ASSERTION(aEntry == newEntry,
|
||||
"The new session history should be in the new entry");
|
||||
}
|
||||
// This is the root docshell
|
||||
bool addToSHistory = !LOAD_TYPE_HAS_FLAGS(
|
||||
aLoadType, nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY);
|
||||
if (!addToSHistory) {
|
||||
// Replace current entry in session history; If the requested index is
|
||||
// valid, it indicates the loading was triggered by a history load, and
|
||||
// we should replace the entry at requested index instead.
|
||||
int32_t index = mRequestedIndex;
|
||||
if (index == -1) {
|
||||
index = mIndex;
|
||||
}
|
||||
|
||||
// Replace the current entry with the new entry
|
||||
if (index >= 0) {
|
||||
rv = ReplaceEntry(index, aEntry);
|
||||
} else {
|
||||
// If we're trying to replace an inexistant shistory entry, append.
|
||||
addToSHistory = true;
|
||||
}
|
||||
}
|
||||
if (addToSHistory) {
|
||||
// Add to session history
|
||||
*previousEntryIndex = Some(mIndex);
|
||||
rv = AddEntry(aEntry, aShouldPersist, aEntriesPurged);
|
||||
*aLoadedEntryIndex = Some(mIndex);
|
||||
MOZ_LOG(gPageCacheLog, LogLevel::Verbose,
|
||||
("Previous index: %d, Loaded index: %d",
|
||||
previousEntryIndex->value(), aLoadedEntryIndex->value()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Add an entry to the History list at mIndex and
|
||||
@ -552,6 +748,7 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist) {
|
||||
nsresult nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist,
|
||||
int32_t* aEntriesPurged) {
|
||||
NS_ENSURE_ARG(aSHEntry);
|
||||
*aEntriesPurged = 0;
|
||||
|
||||
nsCOMPtr<nsISHistory> shistoryOfEntry = aSHEntry->GetShistory();
|
||||
if (shistoryOfEntry != this) {
|
||||
|
@ -58,10 +58,15 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
|
||||
|
||||
// Structure used in SetChildHistoryEntry
|
||||
struct SwapEntriesData {
|
||||
nsDocShell* ignoreShell; // constant; the shell to ignore
|
||||
mozilla::dom::BrowsingContext*
|
||||
ignoreBC; // constant; the browsing context to ignore
|
||||
nsISHEntry* destTreeRoot; // constant; the root of the dest tree
|
||||
nsISHEntry* destTreeParent; // constant; the node under destTreeRoot
|
||||
// whose children will correspond to aEntry
|
||||
uint64_t otherPid; // constant; pid of the process which indirectly called
|
||||
// SetChildHistoryEntry
|
||||
// see comment for WalkHistoryEntriesFunc
|
||||
nsTArray<EntriesAndBrowsingContextData>* entriesToUpdate;
|
||||
};
|
||||
|
||||
nsSHistory(mozilla::dom::BrowsingContext* aRootBC, const nsID& aDocShellID);
|
||||
@ -83,11 +88,15 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
|
||||
static already_AddRefed<nsISHEntry> GetRootSHEntry(nsISHEntry* aEntry);
|
||||
|
||||
// Callback prototype for WalkHistoryEntries.
|
||||
// aEntry is the child history entry, aShell is its corresponding docshell,
|
||||
// aChildIndex is the child's index in its parent entry, and aData is
|
||||
// the opaque pointer passed to WalkHistoryEntries.
|
||||
// `aEntry` is the child history entry, `aBC` is its corresponding browsing
|
||||
// context, `aChildIndex` is the child's index in its parent entry, and
|
||||
// `aData` is the opaque pointer passed to WalkHistoryEntries. Both structs
|
||||
// that are passed as `aData` to this function have a field
|
||||
// `aEntriesToUpdate`, which is an array of entries we need to update in
|
||||
// docshell, if the 'SH in parent' pref is on (which implies that this method
|
||||
// is executed in the parent)
|
||||
typedef nsresult (*WalkHistoryEntriesFunc)(nsISHEntry* aEntry,
|
||||
nsDocShell* aShell,
|
||||
mozilla::dom::BrowsingContext* aBC,
|
||||
int32_t aChildIndex, void* aData);
|
||||
|
||||
// Clone a session history tree for subframe navigation.
|
||||
@ -98,26 +107,45 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
|
||||
// have that pointer updated to point to the cloned history entry.
|
||||
// If aCloneChildren is true then the children of the entry with id
|
||||
// |aCloneID| will be cloned into |aReplaceEntry|.
|
||||
static nsresult CloneAndReplace(nsISHEntry* aSrcEntry, nsDocShell* aSrcShell,
|
||||
uint32_t aCloneID, nsISHEntry* aReplaceEntry,
|
||||
bool aCloneChildren, nsISHEntry** aDestEntry);
|
||||
static nsresult CloneAndReplace(
|
||||
nsISHEntry* aSrcEntry, mozilla::dom::BrowsingContext* aOwnerBC,
|
||||
uint32_t aCloneID, nsISHEntry* aReplaceEntry, bool aCloneChildren,
|
||||
nsISHEntry** aDestEntry, uint64_t aOtherPid,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate);
|
||||
|
||||
// Child-walking callback for CloneAndReplace
|
||||
static nsresult CloneAndReplaceChild(nsISHEntry* aEntry, nsDocShell* aShell,
|
||||
static nsresult CloneAndReplaceChild(nsISHEntry* aEntry,
|
||||
mozilla::dom::BrowsingContext* aOwnerBC,
|
||||
int32_t aChildIndex, void* aData);
|
||||
|
||||
// Child-walking callback for SetHistoryEntry
|
||||
static nsresult SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell,
|
||||
static nsresult SetChildHistoryEntry(nsISHEntry* aEntry,
|
||||
mozilla::dom::BrowsingContext* aBC,
|
||||
int32_t aEntryIndex, void* aData);
|
||||
|
||||
// For each child of aRootEntry, find the corresponding docshell which is
|
||||
// a child of aRootShell, and call aCallback. The opaque pointer aData
|
||||
// For each child of aRootEntry, find the corresponding shell which is
|
||||
// a child of aBC, and call aCallback. The opaque pointer aData
|
||||
// is passed to the callback.
|
||||
static nsresult WalkHistoryEntries(nsISHEntry* aRootEntry,
|
||||
nsDocShell* aRootShell,
|
||||
mozilla::dom::BrowsingContext* aBC,
|
||||
WalkHistoryEntriesFunc aCallback,
|
||||
void* aData);
|
||||
|
||||
nsresult AddToRootSessionHistory(
|
||||
bool aCloneChildren, nsISHEntry* aOSHE,
|
||||
mozilla::dom::BrowsingContext* aBC, nsISHEntry* aEntry,
|
||||
uint32_t aLoadType, bool aShouldPersist, uint64_t aOtherPid,
|
||||
Maybe<int32_t>* aPreviousEntryIndex, Maybe<int32_t>* aLoadedEntryIndex,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate,
|
||||
int32_t* aEntriesPurged);
|
||||
|
||||
nsresult AddChildSHEntryHelper(
|
||||
nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
|
||||
mozilla::dom::BrowsingContext* aBC, bool aCloneChildren,
|
||||
uint64_t aOtherPid,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate,
|
||||
int32_t* aEntriesPurged, nsISHEntry** aNextEntry);
|
||||
|
||||
nsTArray<nsCOMPtr<nsISHEntry>>& Entries() { return mEntries; }
|
||||
|
||||
nsresult AddEntry(nsISHEntry* aSHEntry, bool aPersist,
|
||||
@ -198,6 +226,21 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
|
||||
// otherwise comparison is done to aIndex - 1.
|
||||
bool RemoveDuplicate(int32_t aIndex, bool aKeepNext);
|
||||
|
||||
// We need to update entries in docshell and browsing context.
|
||||
// If our docshell is located in parent or 'SH in parent' pref is off we can
|
||||
// update it directly, Otherwise, we have two choices. If the browsing context
|
||||
// that owns the docshell is in the same process as the process who called us
|
||||
// over IPC, then we save entries that need to be updated in a list, and once
|
||||
// we have returned from the IPC call, we update the docshell in the child
|
||||
// process. Otherwise, if the browsing context is in a different process, we
|
||||
// do a nested IPC call to that process to update the docshell in that
|
||||
// process.
|
||||
static void HandleEntriesToSwapInDocShell(
|
||||
mozilla::dom::BrowsingContext* aBC, nsISHEntry* aOldEntry,
|
||||
nsISHEntry* aNewEntry,
|
||||
nsTArray<EntriesAndBrowsingContextData>* aEntriesToUpdate,
|
||||
uint64_t aOtherPid);
|
||||
|
||||
protected:
|
||||
// Length of mEntries.
|
||||
int32_t Length() { return int32_t(mEntries.Length()); }
|
||||
|
@ -3433,19 +3433,13 @@ bool ContentChild::DeallocPSessionStorageObserverChild(
|
||||
return true;
|
||||
}
|
||||
|
||||
PSHEntryChild* ContentChild::AllocPSHEntryChild(
|
||||
PSHistoryChild* aSHistory, const PSHEntryOrSharedID& aEntryOrSharedID) {
|
||||
PSHEntryChild* ContentChild::AllocPSHEntryChild(PSHistoryChild* aSHistory,
|
||||
uint64_t aSharedID) {
|
||||
// We take a strong reference for the IPC layer. The Release implementation
|
||||
// for SHEntryChild will ask the IPC layer to release it (through
|
||||
// DeallocPSHEntryChild) if that is the only remaining reference.
|
||||
RefPtr<SHEntryChild> child;
|
||||
if (aEntryOrSharedID.type() == PSHEntryOrSharedID::Tuint64_t) {
|
||||
child = new SHEntryChild(static_cast<SHistoryChild*>(aSHistory),
|
||||
aEntryOrSharedID.get_uint64_t());
|
||||
} else {
|
||||
child = new SHEntryChild(
|
||||
static_cast<const SHEntryChild*>(aEntryOrSharedID.get_PSHEntryChild()));
|
||||
}
|
||||
child = new SHEntryChild(static_cast<SHistoryChild*>(aSHistory), aSharedID);
|
||||
return child.forget().take();
|
||||
}
|
||||
|
||||
@ -3764,6 +3758,19 @@ mozilla::ipc::IPCResult ContentChild::RecvSessionStorageData(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvUpdateSHEntriesInDocShell(
|
||||
CrossProcessSHEntry* aOldEntry, CrossProcessSHEntry* aNewEntry,
|
||||
const MaybeDiscarded<BrowsingContext>& aContext) {
|
||||
MOZ_ASSERT(!aContext.IsNull(), "Browsing context cannot be null");
|
||||
nsDocShell* docshell =
|
||||
static_cast<nsDocShell*>(aContext.GetMaybeDiscarded()->GetDocShell());
|
||||
if (docshell) {
|
||||
docshell->SwapHistoryEntries(aOldEntry->ToSHEntryChild(),
|
||||
aNewEntry->ToSHEntryChild());
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIEventTarget> ContentChild::GetSpecificMessageEventTarget(
|
||||
const Message& aMsg) {
|
||||
switch (aMsg.type()) {
|
||||
|
@ -622,7 +622,8 @@ class ContentChild final
|
||||
PSessionStorageObserverChild* aActor);
|
||||
|
||||
PSHEntryChild* AllocPSHEntryChild(PSHistoryChild* aSHistory,
|
||||
const PSHEntryOrSharedID& aEntryOrSharedID);
|
||||
uint64_t aSharedID);
|
||||
|
||||
void DeallocPSHEntryChild(PSHEntryChild*);
|
||||
|
||||
PSHistoryChild* AllocPSHistoryChild(
|
||||
@ -696,6 +697,10 @@ class ContentChild final
|
||||
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
|
||||
const nsTArray<KeyValuePair>& aSessionData);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateSHEntriesInDocShell(
|
||||
CrossProcessSHEntry* aOldEntry, CrossProcessSHEntry* aNewEntry,
|
||||
const MaybeDiscarded<BrowsingContext>& aContext);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Fetch the current number of pending input events.
|
||||
//
|
||||
|
@ -5732,9 +5732,9 @@ bool ContentParent::DeallocPSessionStorageObserverParent(
|
||||
return mozilla::dom::DeallocPSessionStorageObserverParent(aActor);
|
||||
}
|
||||
|
||||
PSHEntryParent* ContentParent::AllocPSHEntryParent(
|
||||
PSHistoryParent* aSHistory, const PSHEntryOrSharedID& aEntryOrSharedID) {
|
||||
return SHistoryParent::CreateEntry(this, aSHistory, aEntryOrSharedID);
|
||||
PSHEntryParent* ContentParent::AllocPSHEntryParent(PSHistoryParent* aSHistory,
|
||||
uint64_t aSharedID) {
|
||||
return SHistoryParent::CreateEntry(this, aSHistory, aSharedID);
|
||||
}
|
||||
|
||||
void ContentParent::DeallocPSHEntryParent(PSHEntryParent* aEntry) {
|
||||
@ -5743,12 +5743,8 @@ void ContentParent::DeallocPSHEntryParent(PSHEntryParent* aEntry) {
|
||||
|
||||
PSHistoryParent* ContentParent::AllocPSHistoryParent(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext) {
|
||||
if (NS_WARN_IF(aContext.IsNullOrDiscarded())) {
|
||||
// FIXME: What should we do here?
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new SHistoryParent(aContext.get_canonical());
|
||||
MOZ_ASSERT(!aContext.IsNull());
|
||||
return new SHistoryParent(aContext.GetMaybeDiscarded()->Canonical());
|
||||
}
|
||||
|
||||
void ContentParent::DeallocPSHistoryParent(PSHistoryParent* aActor) {
|
||||
@ -5866,6 +5862,35 @@ mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaAudibleChanged(
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
mozilla::ipc::IPCResult ContentParent::RecvUpdateSHEntriesInBC(
|
||||
PSHEntryParent* aNewLSHE, PSHEntryParent* aNewOSHE,
|
||||
const MaybeDiscarded<BrowsingContext>& aMaybeContext) {
|
||||
if (aMaybeContext.IsNull()) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to update a browsing context that does not "
|
||||
"exist or has been discarded"));
|
||||
return IPC_OK();
|
||||
}
|
||||
// if aContext has been discarded we can still update the entries
|
||||
auto aContext = aMaybeContext.GetMaybeDiscarded()->Canonical();
|
||||
MOZ_ASSERT(aContext);
|
||||
if (!aContext->IsOwnedByProcess(ChildID())) {
|
||||
// We are trying to update a child BrowsingContext in another child
|
||||
// process. This is illegal since the owner of the BrowsingContext
|
||||
// is the proccess with the in-process docshell, which is tracked
|
||||
// by OwnerProcessId.
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
false,
|
||||
"Trying to update a child BrowsingContext in another child process");
|
||||
return IPC_OK();
|
||||
}
|
||||
SHEntryParent* newLSHEparent = static_cast<SHEntryParent*>(aNewLSHE);
|
||||
SHEntryParent* newOSHEparent = static_cast<SHEntryParent*>(aNewOSHE);
|
||||
nsISHEntry* lshe = newLSHEparent ? newLSHEparent->mEntry.get() : nullptr;
|
||||
nsISHEntry* oshe = newOSHEparent ? newOSHEparent->mEntry.get() : nullptr;
|
||||
aContext->UpdateSHEntries(lshe, oshe);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaSessionUpdated(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext, bool aIsCreated) {
|
||||
|
@ -586,8 +586,8 @@ class ContentParent final
|
||||
bool DeallocPSessionStorageObserverParent(
|
||||
PSessionStorageObserverParent* aActor);
|
||||
|
||||
PSHEntryParent* AllocPSHEntryParent(
|
||||
PSHistoryParent* aSHistory, const PSHEntryOrSharedID& aEntryOrSharedID);
|
||||
PSHEntryParent* AllocPSHEntryParent(PSHistoryParent* aSHistory,
|
||||
uint64_t aSharedID);
|
||||
|
||||
void DeallocPSHEntryParent(PSHEntryParent*);
|
||||
|
||||
@ -1271,6 +1271,10 @@ class ContentParent final
|
||||
uint32_t aShutdownStateId,
|
||||
ServiceWorkerShutdownState::Progress aProgress);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateSHEntriesInBC(
|
||||
PSHEntryParent* aNewLSHE, PSHEntryParent* aNewOSHE,
|
||||
const MaybeDiscarded<BrowsingContext>& aMaybeContext);
|
||||
|
||||
// Notify the ContentChild to enable the input event prioritization when
|
||||
// initializing.
|
||||
void MaybeEnableRemoteInputEventQueue();
|
||||
|
@ -41,6 +41,7 @@ using refcounted class nsIReferrerInfo from "mozilla/dom/ReferrerInfoUtils.h";
|
||||
using refcounted class nsIVariant from "mozilla/dom/PropertyBagUtils.h";
|
||||
using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
|
||||
using refcounted class nsISHEntry from "nsISHEntry.h";
|
||||
using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
|
||||
using refcounted class mozilla::dom::CrossProcessSHEntry from "mozilla/dom/MaybeNewPSHEntry.h";
|
||||
|
||||
namespace mozilla {
|
||||
@ -380,5 +381,11 @@ struct OwnerShowInfo {
|
||||
nsSizeMode sizeMode;
|
||||
};
|
||||
|
||||
struct SwapEntriesDocshellData {
|
||||
CrossProcessSHEntry oldEntry;
|
||||
CrossProcessSHEntry newEntry;
|
||||
MaybeDiscardedBrowsingContext context;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -123,6 +123,7 @@ using mozilla::dom::ControlledMediaState from "ipc/MediaControlIPC.h";
|
||||
using mozilla::dom::MaybeMediaMetadataBase from "mozilla/dom/MediaSessionIPCUtils.h";
|
||||
using refcounted class nsDocShellLoadState from "nsDocShellLoadState.h";
|
||||
using mozilla::dom::ServiceWorkerShutdownState::Progress from "mozilla/dom/ServiceWorkerShutdownState.h";
|
||||
using refcounted class mozilla::dom::CrossProcessSHEntry from "mozilla/dom/MaybeNewPSHEntry.h";
|
||||
|
||||
union ChromeRegistryItem
|
||||
{
|
||||
@ -344,12 +345,6 @@ struct PostMessageData
|
||||
uint64_t innerWindowId;
|
||||
};
|
||||
|
||||
union PSHEntryOrSharedID
|
||||
{
|
||||
PSHEntry;
|
||||
uint64_t;
|
||||
};
|
||||
|
||||
struct KeyValuePair
|
||||
{
|
||||
nsString key;
|
||||
@ -874,6 +869,11 @@ child:
|
||||
|
||||
async DisplayLoadError(MaybeDiscardedBrowsingContext aContext, nsString aURI);
|
||||
|
||||
// Tell aContext's docshell to update its mOSHE and mLSHE entries
|
||||
async UpdateSHEntriesInDocShell(CrossProcessSHEntry aOldEntry,
|
||||
CrossProcessSHEntry aNewEntry,
|
||||
MaybeDiscardedBrowsingContext aContext);
|
||||
|
||||
parent:
|
||||
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
|
||||
|
||||
@ -949,8 +949,8 @@ parent:
|
||||
|
||||
async PSHistory(MaybeDiscardedBrowsingContext aContext);
|
||||
|
||||
// Clone from entry or use shared id.
|
||||
sync PSHEntry(nullable PSHistory shistory, PSHEntryOrSharedID entryOrSharedID);
|
||||
// Clone using shared id.
|
||||
sync PSHEntry(nullable PSHistory shistory, uint64_t sharedID);
|
||||
|
||||
async PBenchmarkStorage();
|
||||
|
||||
@ -1538,6 +1538,13 @@ parent:
|
||||
async ReportServiceWorkerShutdownProgress(uint32_t aShutdownStateId,
|
||||
Progress aProgress);
|
||||
|
||||
/**
|
||||
* Whenever docshell updates its SH entries, we need to update them in
|
||||
* the corresponding BrowsingContext
|
||||
*/
|
||||
async UpdateSHEntriesInBC(nullable PSHEntry aNewLSHE, nullable
|
||||
PSHEntry aNewOSHE, MaybeDiscardedBrowsingContext aContext);
|
||||
|
||||
both:
|
||||
async ScriptError(nsString message, nsString sourceName, nsString sourceLine,
|
||||
uint32_t lineNumber, uint32_t colNumber, uint32_t flags,
|
||||
|
@ -837,6 +837,10 @@ description = Standing up Fission
|
||||
description = Standing up Fission
|
||||
[PSHistory::NotifyOnHistoryReload]
|
||||
description = Standing up Fission
|
||||
[PSHistory::AddToRootSessionHistory]
|
||||
description = Standing up Fission
|
||||
[PSHistory::AddChildSHEntryHelper]
|
||||
description = Standing up Fission
|
||||
[PSHistory::RemoveEntries]
|
||||
description = Standing up Fission
|
||||
[PSHistory::Reload]
|
||||
@ -847,6 +851,8 @@ description = Standing up Fission
|
||||
description = Standing up Fission
|
||||
[PContent::PSHEntry]
|
||||
description = Standing up Fission
|
||||
[PSHEntry::Clone]
|
||||
description = Standing up Fission
|
||||
[PSHEntry::GetURI]
|
||||
description = Standing up Fission
|
||||
[PSHEntry::GetOriginalURI]
|
||||
@ -935,6 +941,8 @@ description = Standing up Fission
|
||||
description = Standing up Fission
|
||||
[PSHEntry::CreateLoadInfo]
|
||||
description = Standing up Fission
|
||||
[PSHEntry::SyncTreesForSubframeNavigation]
|
||||
description = Standing up Fission
|
||||
|
||||
# The rest
|
||||
[PHeapSnapshotTempFileHelper::OpenHeapSnapshotTempFile]
|
||||
|
Loading…
Reference in New Issue
Block a user