Commit 1d35a2c8 authored by Peter Van der Beken's avatar Peter Van der Beken
Browse files

Bug 1438272 - Part 3: move session history to parent process. r=nika

Differential Revision:

extra : source : 29cc55878945008fdc4f356969fe528c85f34d41
extra : amend_source : fb5a3bb318346ec6fc02bcdac51f1588b6e87634
parent b5ab2639
......@@ -3593,7 +3593,7 @@ void nsDocShell::ClearFrameHistory(nsISHEntry* aEntry) {
nsCOMPtr<nsISHEntry> child;
aEntry->GetChildAt(i, getter_AddRefs(child));
if (child) {
int32_t index = rootSH->Index();
......@@ -8893,7 +8893,9 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
if (mOSHE) {
/* save current position of scroller(s) (bug 59774) */
mOSHE->SetScrollPosition(scrollPos.x, scrollPos.y);
scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
DebugOnly<nsresult> rv =
MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
// Get the postdata and page ident from the current page, if
// the new load is being done via normal means. Note that
// "normal means" can be checked for just by checking for
......@@ -8920,8 +8922,10 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
// If we're doing a history load, use its scroll restoration state.
if (aLoadState->SHEntry()) {
scrollRestorationIsManual =
DebugOnly<nsresult> rv =
MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
/* Assign mLSHE to mOSHE. This will either be a new entry created
......@@ -9397,8 +9401,8 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
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.
mHistoryID = aLoadState->SHEntry()->DocshellID();
......@@ -11164,15 +11168,18 @@ nsresult nsDocShell::UpdateURLAndHistory(Document* aDocument, nsIURI* aNewURI,
nsPoint scrollPos = GetCurScrollPos();
mOSHE->SetScrollPosition(scrollPos.x, scrollPos.y);
bool scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
bool scrollRestorationIsManual;
nsresult rv =
MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
nsCOMPtr<nsIContentSecurityPolicy> csp = aDocument->GetCsp();
// Since we're not changing which page we have loaded, pass
// true for aCloneChildren.
nsresult rv = AddToSessionHistory(
aNewURI, nullptr,
aDocument->NodePrincipal(), // triggeringPrincipal
nullptr, nullptr, csp, true, getter_AddRefs(newSHEntry));
rv = AddToSessionHistory(aNewURI, nullptr,
aDocument->NodePrincipal(), // triggeringPrincipal
nullptr, nullptr, csp, true, getter_AddRefs(newSHEntry));
......@@ -11301,7 +11308,7 @@ NS_IMETHODIMP
nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual) {
*aIsManual = false;
if (mOSHE) {
*aIsManual = mOSHE->GetScrollRestorationIsManual();
return mOSHE->GetScrollRestorationIsManual(aIsManual);
return NS_OK;
......@@ -11495,7 +11502,6 @@ nsresult nsDocShell::AddToSessionHistory(
entry->Create(aURI, // uri
EmptyString(), // Title
inputStream, // Post data stream
nullptr, // LayoutHistory state
cacheKey, // CacheKey
mContentTypeHint, // Content-type
triggeringPrincipal, // Channel or provided principal
......@@ -11726,7 +11732,8 @@ nsresult nsDocShell::PersistLayoutHistoryState() {
nsresult rv = NS_OK;
if (mOSHE) {
bool scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
bool scrollRestorationIsManual;
Unused << mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
nsCOMPtr<nsILayoutHistoryState> layoutState;
if (RefPtr<PresShell> presShell = GetPresShell()) {
rv = presShell->CaptureHistoryState(getter_AddRefs(layoutState));
......@@ -11764,7 +11771,7 @@ void nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr,
// 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.
nsISHEntry* newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
nsCOMPtr<nsISHEntry> newRootEntry = nsSHistory::GetRootSHEntry(aEntry);
if (newRootEntry) {
// newRootEntry is now the new root entry.
// Find the old root entry as well.
......@@ -47,8 +47,12 @@ Classes = [
'name': 'SHEntry',
'cid': '{bfd1a791-ad9f-11d3-bdc7-0050040a9b44}',
'contract_ids': [';1'],
'type': 'nsSHEntry',
'headers': ['/docshell/shistory/nsSHEntry.h'],
'type': 'nsISHEntry',
'constructor': 'mozilla::dom::CreateSHEntry',
'headers': [
'name': 'DocLoader',
......@@ -6,6 +6,7 @@
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/SHEntryChild.h"
// session history
#include "nsSHEntryShared.h"
......@@ -18,6 +19,7 @@ nsresult InitDocShellModule() {
nsresult rv = nsSHistory::Startup();
return NS_OK;
......@@ -6,9 +6,14 @@
#include "mozilla/dom/ChildSHistory.h"
#include "mozilla/dom/ChildSHistoryBinding.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/SHEntryChild.h"
#include "mozilla/dom/SHistoryChild.h"
#include "mozilla/StaticPrefs_fission.h"
#include "nsIMessageManager.h"
#include "nsComponentManagerUtils.h"
#include "nsSHEntry.h"
#include "nsSHistory.h"
#include "nsDocShell.h"
#include "nsISHEntry.h"
......@@ -17,9 +22,20 @@
namespace mozilla {
namespace dom {
static already_AddRefed<nsISHistory> CreateSHistory(nsDocShell* aDocShell) {
if (XRE_IsContentProcess() && StaticPrefs::fission_sessionHistoryInParent()) {
return do_AddRef(static_cast<SHistoryChild*>(
nsCOMPtr<nsISHistory> history =
new nsSHistory(aDocShell->GetBrowsingContext(), aDocShell->HistoryID());
return history.forget();
ChildSHistory::ChildSHistory(nsDocShell* aDocShell)
: mDocShell(aDocShell), mHistory(new nsSHistory(aDocShell->GetBrowsingContext(),
aDocShell->HistoryID())) {}
: mDocShell(aDocShell), mHistory(CreateSHistory(aDocShell)) {}
ChildSHistory::~ChildSHistory() {}
......@@ -109,5 +125,16 @@ nsISupports* ChildSHistory::GetParentObject() const {
return ToSupports(mm);
already_AddRefed<nsISHEntry> CreateSHEntry() {
uint64_t sharedID = SHEntryChildShared::CreateSharedID();
if (XRE_IsContentProcess() && StaticPrefs::fission_sessionHistoryInParent()) {
return do_AddRef(static_cast<SHEntryChild*>(
nsCOMPtr<nsISHEntry> entry = new nsLegacySHEntry(sharedID);
return entry.forget();
} // namespace dom
} // namespace mozilla
......@@ -28,6 +28,7 @@
class nsSHistory;
class nsDocShell;
class nsISHEntry;
class nsISHistory;
class nsIWebNavigation;
class nsIGlobalObject;
......@@ -103,10 +104,12 @@ class ChildSHistory : public nsISupports, public nsWrapperCache {
RefPtr<nsDocShell> mDocShell;
RefPtr<nsSHistory> mHistory;
nsCOMPtr<nsISHistory> mHistory;
mozilla::LinkedList<PendingAsyncHistoryNavigation> mPendingNavigations;
already_AddRefed<nsISHEntry> CreateSHEntry();
} // namespace dom
} // namespace mozilla
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at */
include protocol PSHEntry;
namespace mozilla {
namespace dom {
union PSHEntryOrSharedID
struct NewPSHEntry {
ManagedEndpoint<PSHEntryChild> endpoint;
uint64_t sharedID;
union MaybeNewPSHEntry {
nullable PSHEntry;
} // namespace dom
} // namespace mozilla
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at */
include protocol PContent;
include protocol PSHistory;
include DOMTypes;
include NewPSHEntry;
using refcounted class nsIInputStream from "mozilla/ipc/IPCStreamUtils.h";
using struct nsID from "nsID.h";
using nsIntRect from "nsRect.h";
namespace mozilla {
namespace dom {
sync protocol PSHEntry {
manager PContent;
sync GetURI() returns (nsIURI uri);
sync SetURI(nsIURI uri);
sync GetOriginalURI() returns (nsIURI originalUri);
sync SetOriginalURI(nsIURI originalUri);
sync GetResultPrincipalURI() returns (nsIURI resultPrincipalUri);
sync SetResultPrincipalURI(nsIURI resultPrincipalUri);
sync GetLoadReplace() returns (bool loadReplace);
sync SetLoadReplace(bool loadReplace);
sync GetTitle() returns (nsString title);
sync SetTitle(nsString title);
sync GetIsSubFrame() returns (bool isSubFrame);
sync SetIsSubFrame(bool isSubFrame);
sync GetReferrerInfo() returns (nsIReferrerInfo referrerInfo);
sync SetReferrerInfo(nsIReferrerInfo referrerInfo);
sync GetSticky() returns (bool sticky);
sync SetSticky(bool sticky);
sync GetPostData() returns (nsIInputStream postData);
sync SetPostData(nsIInputStream postData);
sync GetParent() returns (MaybeNewPSHEntry parentEntry);
sync SetParent(nullable PSHEntry parentEntry);
sync GetLoadType() returns (uint32_t loadType);
sync SetLoadType(uint32_t loadType);
sync GetID() returns (uint32_t id);
sync SetID(uint32_t id);
sync GetCacheKey() returns (uint32_t cacheKey);
sync SetCacheKey(uint32_t cacheKey);
sync GetExpirationStatus() returns (bool expirationStatus);
sync SetExpirationStatus(bool expirationStatus);
sync GetContentType() returns (nsCString contentType);
sync SetContentType(nsCString contentType);
sync GetURIWasModified() returns (bool uriWasModified);
sync SetURIWasModified(bool uriWasModified);
sync GetTriggeringPrincipal() returns (nsIPrincipal triggeringPrincipal);
sync SetTriggeringPrincipal(nsIPrincipal triggeringPrincipal);
sync GetPrincipalToInherit() returns (nsIPrincipal principalToInherit);
sync SetPrincipalToInherit(nsIPrincipal principalToInherit);
sync GetStoragePrincipalToInherit()
returns (nsIPrincipal storagePrincipalToInherit);
sync SetStoragePrincipalToInherit(nsIPrincipal storagePrincipalToInherit);
sync GetCsp() returns (nsIContentSecurityPolicy csp);
sync SetCsp(nsIContentSecurityPolicy csp);
sync GetStateData() returns (ClonedMessageData stateData);
sync SetStateData(ClonedMessageData stateData);
sync GetDocshellID() returns (nsID docshellId);
sync SetDocshellID(nsID docshellId);
sync GetIsSrcdocEntry() returns (bool isSrcdocEntry);
sync GetSrcdocData() returns (nsString srcdocData);
sync SetSrcdocData(nsString srcdocData);
sync GetBaseURI() returns (nsIURI baseUri);
sync SetBaseURI(nsIURI baseUri);
sync GetScrollRestorationIsManual() returns (bool scrollRestorationIsManual);
sync SetScrollRestorationIsManual(bool scrollRestorationIsManual);
sync GetLoadedInThisProcess() returns (bool loadedInThisProcess);
sync GetLastTouched() returns (uint32_t lastTouched);
sync SetLastTouched(uint32_t lastTouched);
sync GetChildCount() returns (int32_t childCount);
sync GetPersist() returns (bool persist);
sync SetPersist(bool persist);
sync SetScrollPosition(int32_t x, int32_t y);
sync GetScrollPosition() returns (int32_t x, int32_t y);
sync GetViewerBounds() returns (nsIntRect bounds);
sync SetViewerBounds(nsIntRect bounds);
sync Create(nsIURI URI, nsString title, nsIInputStream inputStream,
uint32_t cacheKey, nsCString contentType,
nsIPrincipal triggeringPrincipal, nsIPrincipal principalToInherit,
nsIContentSecurityPolicy csp, nsID docshellID,
bool dynamicCreation);
sync HasDetachedEditor() returns (bool hasDetachedEditor);
sync IsDynamicallyAdded() returns (bool isDynamicallyAdded);
sync HasDynamicallyAddedChild() returns (bool hasDynamicallyAddedChild);
sync AdoptBFCacheEntry(PSHEntry entry) returns (nsresult result);
sync AbandonBFCacheEntry(uint64_t aNewSharedID);
sync SharesDocumentWith(PSHEntry entry) returns (bool sharesDocumentWith,
nsresult result);
sync SetLoadTypeAsHistory();
sync AddChild(nullable PSHEntry childEntry, int32_t offset, bool useRemoteSubframes) returns (nsresult result);
sync RemoveChild(PSHEntry childEntry) returns (nsresult result);
sync GetChildAt(int32_t index) returns (MaybeNewPSHEntry childEntry);
sync ReplaceChild(PSHEntry newChildEntry) returns (nsresult result);
sync __delete__();
} // namespace dom
} // namespace mozilla
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at */
include protocol PContent;
include protocol PSHEntry;
include DOMTypes;
include NewPSHEntry;
using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
using refcounted class nsDocShellLoadState from "mozilla/dom/DocShellMessageUtils.h";
using struct nsID from "nsID.h";
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace dom {
struct LoadSHEntryData
MaybeNewPSHEntry shEntry;
BrowsingContext browsingContext;
nsDocShellLoadState loadState;
union LoadSHEntryResult {
sync protocol PSHistory {
manager PContent;
sync GetCount() returns (int32_t count);
sync GetIndex() returns (int32_t index);
sync SetIndex(int32_t index) returns (nsresult result);
sync GetRequestedIndex() returns (int32_t index);
sync InternalSetRequestedIndex(int32_t index);
sync GetEntryAtIndex(int32_t index) returns (nsresult result, MaybeNewPSHEntry entry);
sync PurgeHistory(int32_t numEntries) returns (nsresult result);
sync ReloadCurrentEntry() returns (LoadSHEntryResult load);
sync GotoIndex(int32_t index) returns (LoadSHEntryResult load);
sync GetIndexOfEntry(PSHEntry entry) returns (int32_t index);
sync AddEntry(PSHEntry entry, bool persist) returns (nsresult result, int32_t entriesPurged);
sync UpdateIndex();
sync ReplaceEntry(int32_t index, PSHEntry entry) returns (nsresult result);
sync NotifyOnHistoryReload() returns (bool ok);
sync EvictOutOfRangeContentViewers(int32_t index);
sync EvictAllContentViewers();
sync RemoveDynEntries(int32_t index, PSHEntry entry);
sync RemoveEntries(nsID[] ids, int32_t index) returns (bool didRemove);
sync Reload(uint32_t reloadFlags) returns (LoadSHEntryResult load);
sync GetAllEntries() returns (MaybeNewPSHEntry[] entries);
sync FindEntryForBFCache(uint64_t sharedID, bool includeCurrentEntry) returns (MaybeNewPSHEntry entries, int32_t startIndex);
sync Evict(PSHEntry[] entry);
async __delete__();
} // namespace dom
} // namespace mozilla
This diff is collapsed.
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#ifndef mozilla_dom_SHEntryChild_h
#define mozilla_dom_SHEntryChild_h
#include "mozilla/dom/PSHEntryChild.h"
#include "nsContentUtils.h"
#include "nsExpirationTracker.h"
#include "nsIBFCacheEntry.h"
#include "nsISHEntry.h"
#include "nsRect.h"
#include "nsSHEntryShared.h"
#include "nsStubMutationObserver.h"
class nsDocShellEditorData;
class nsIContentViewer;
class nsILayoutHistoryState;
class nsIMutableArray;
namespace mozilla {
namespace dom {
class SHistoryChild;
* Implementation of the shared state for session history entries in the child
* process.
class SHEntryChildShared final : public nsIBFCacheEntry,
public nsStubMutationObserver,
public SHEntrySharedChildState {
static void Init();
static SHEntryChildShared* GetOrCreate(uint64_t aSharedID);
static void Remove(uint64_t aSharedID);
static uint64_t CreateSharedID() {
return nsContentUtils::GenerateProcessSpecificId(++sNextSharedID);
// The nsIMutationObserver bits we actually care about.
nsExpirationState* GetExpirationState() { return &mExpirationState; }
uint64_t GetID() { return mID; }
static uint64_t sNextSharedID;
explicit SHEntryChildShared(uint64_t aID);
friend class SHEntryChild;
already_AddRefed<SHEntryChildShared> Duplicate();
void RemoveFromExpirationTracker();
void SyncPresentationState();
void DropPresentationState();
nsresult SetContentViewer(nsIContentViewer* aViewer);
uint64_t mID;
RefPtr<SHistoryChild> mSHistory;
* Session history entry actor for the child process.
class SHEntryChild final : public PSHEntryChild, public nsISHEntry {
friend class PSHEntryChild;
explicit SHEntryChild(const SHEntryChild* aClone)
: mShared(aClone->mShared.get()), mIPCActorDeleted(false) {}
explicit SHEntryChild(uint64_t aSharedID)
: mShared(SHEntryChildShared::GetOrCreate(aSharedID)),
mIPCActorDeleted(false) {}
void EvictContentViewer();
static already_AddRefed<SHEntryChild> GetOrCreate(MaybeNewPSHEntry& aEntry);
void ActorDestroy(ActorDestroyReason aWhy) override {
mIPCActorDeleted = true;
~SHEntryChild() = default;
RefPtr<SHEntryChildShared> mShared;
bool mIPCActorDeleted;
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_SHEntryChild_h */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#include "SHEntryParent.h"
#include "SHistoryParent.h"
#include "mozilla/dom/ContentParent.h"
#include "nsStructuredCloneContainer.h"
namespace mozilla {
namespace dom {
SHEntrySharedParent::SHEntrySharedParent(PContentParent* aContentParent,
uint64_t aSharedID)
: SHEntrySharedParentState(aSharedID), mContentParent(aContentParent) {}
void SHEntrySharedParent::Destroy() {
if (mContentParent &&
!static_cast<ContentParent*>(mContentParent.get())->IsDestroyed()) {
Unused << mContentParent->SendDestroySHEntrySharedState(mID);
SHEntryParent* LegacySHEntry::CreateActor() {
mActor = new SHEntryParent(this);
return mActor;
void LegacySHEntry::GetOrCreateActor(PContentParent* aContentParent,
MaybeNewPSHEntry& aEntry) {
if (!mActor) {
mActor = new SHEntryParent(this);
aEntry =
NewPSHEntry(aContentParent->OpenPSHEntryEndpoint(mActor), mShared->mID);
} else {
aEntry = mActor;
void LegacySHEntry::AbandonBFCacheEntry(uint64_t aNewSharedID) {
PContentParent* contentParent =
RefPtr<SHEntrySharedParent> shared =
new SHEntrySharedParent(contentParent, aNewSharedID);
mShared = shared.forget();
void SHEntryParent::ActorDestroy(ActorDestroyReason aWhy) {
mEntry->mActor = nullptr;
bool SHEntryParent::RecvGetURI(RefPtr<nsIURI>* aURI) {
*aURI = mEntry->GetURI();
return true;
bool SHEntryParent::RecvSetURI(nsIURI* aURI) {
DebugOnly<nsresult> rv = mEntry->SetURI(aURI);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
return true;
bool SHEntryParent::RecvGetOriginalURI(RefPtr<nsIURI>* aOriginalURI) {
*aOriginalURI = mEntry->GetOriginalURI();
return true;
bool SHEntryParent::RecvSetOriginalURI(nsIURI* aOriginalURI) {
DebugOnly<nsresult> rv = mEntry->SetOriginalURI(aOriginalURI);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
return true;
bool SHEntryParent::RecvGetResultPrincipalURI(
RefPtr<nsIURI>* aResultPrincipalURI) {
*aResultPrincipalURI = mEntry->GetResultPrincipalURI();
return true;
bool SHEntryParent::RecvSetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
DebugOnly<nsresult> rv = mEntry->SetResultPrincipalURI(aResultPrincipalURI);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
return true;
bool SHEntryParent::RecvGetLoadReplace(bool* aLoadReplace) {
*aLoadReplace = mEntry->GetLoadReplace();
return true;