gecko-dev/docshell/shistory/SHEntryChild.cpp

1055 lines
30 KiB
C++

/* -*- 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 http://mozilla.org/MPL/2.0/. */
#include "SHEntryChild.h"
#include "SHistoryChild.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/MaybeNewPSHEntry.h"
#include "mozilla/StaticPrefs_docshell.h"
#include "nsDocShell.h"
#include "nsDocShellEditorData.h"
#include "nsDocShellLoadState.h"
#include "nsIContentViewer.h"
#include "nsILayoutHistoryState.h"
#include "nsIMutableArray.h"
#include "nsStructuredCloneContainer.h"
namespace mozilla {
namespace dom {
StaticAutoPtr<nsRefPtrHashtable<nsUint64HashKey, SHEntryChildShared>>
sSHEntryChildSharedTable;
uint64_t SHEntryChildShared::sNextSharedID = 0;
/* static */
void SHEntryChildShared::Init() {
sSHEntryChildSharedTable =
new nsRefPtrHashtable<nsUint64HashKey, SHEntryChildShared>();
ClearOnShutdown(&sSHEntryChildSharedTable);
}
/* static */
SHEntryChildShared* SHEntryChildShared::GetOrCreate(SHistoryChild* aSHistory,
uint64_t aSharedID) {
MOZ_DIAGNOSTIC_ASSERT(
sSHEntryChildSharedTable,
"SHEntryChildShared::Init should have created the table.");
RefPtr<SHEntryChildShared>& shared =
sSHEntryChildSharedTable->GetOrInsert(aSharedID);
if (!shared) {
shared = new SHEntryChildShared(aSHistory, aSharedID);
}
return shared;
}
void SHEntryChildShared::Remove(uint64_t aSharedID) {
if (sSHEntryChildSharedTable) {
sSHEntryChildSharedTable->Remove(aSharedID);
}
}
void SHEntryChildShared::EvictContentViewers(
const nsTArray<uint64_t>& aToEvictSharedStateIDs) {
MOZ_ASSERT(sSHEntryChildSharedTable,
"we have content viewers to evict, but the table hasn't been "
"initialized yet");
uint32_t numEvictedSoFar = 0;
for (auto iter = aToEvictSharedStateIDs.begin();
iter != aToEvictSharedStateIDs.end(); ++iter) {
RefPtr<SHEntryChildShared> shared = sSHEntryChildSharedTable->Get(*iter);
if (!shared) {
// This can happen if we've created an entry in the parent, and have never
// sent it over IPC to the child.
continue;
}
nsCOMPtr<nsIContentViewer> viewer = shared->mContentViewer;
if (viewer) {
numEvictedSoFar++;
shared->SetContentViewer(nullptr);
shared->SyncPresentationState();
viewer->Destroy();
}
if (std::next(iter) == aToEvictSharedStateIDs.end() &&
numEvictedSoFar > 0) {
// This is the last shared object, so we should notify our
// listeners about any content viewers that were evicted.
// It does not matter which shared entry we will use for notifying.
shared->NotifyListenersContentViewerEvicted(numEvictedSoFar);
}
}
}
SHEntryChildShared::SHEntryChildShared(SHistoryChild* aSHistory, uint64_t aID)
: mID(aID), mSHistory(aSHistory) {}
SHEntryChildShared::~SHEntryChildShared() {
// The destruction can be caused by either the entry is removed from session
// history and no one holds the reference, or the whole session history is on
// destruction. We want to ensure that we invoke
// shistory->RemoveFromExpirationTracker for the former case.
RemoveFromExpirationTracker();
// Calling RemoveDynEntriesForBFCacheEntry on destruction is unnecessary since
// there couldn't be any SHEntry holding this shared entry, and we noticed
// that calling RemoveDynEntriesForBFCacheEntry in the middle of
// nsSHistory::Release can cause a crash, so set mSHistory to null explicitly
// before RemoveFromBFCacheSync.
mSHistory = nullptr;
if (mContentViewer) {
RemoveFromBFCacheSync();
}
}
NS_IMPL_ISUPPORTS(SHEntryChildShared, nsIBFCacheEntry, nsIMutationObserver)
already_AddRefed<SHEntryChildShared> SHEntryChildShared::Duplicate() {
RefPtr<SHEntryChildShared> newEntry = new SHEntryChildShared(
mSHistory, mozilla::dom::SHEntryChildShared::CreateSharedID());
newEntry->CopyFrom(this);
return newEntry.forget();
}
void SHEntryChildShared::RemoveFromExpirationTracker() {
if (mSHistory && GetExpirationState()->IsTracked()) {
mSHistory->RemoveFromExpirationTracker(this);
}
}
void SHEntryChildShared::SyncPresentationState() {
if (mContentViewer && mWindowState) {
// If we have a content viewer and a window state, we should be ok.
return;
}
DropPresentationState();
}
void SHEntryChildShared::DropPresentationState() {
RefPtr<SHEntryChildShared> kungFuDeathGrip = this;
if (mDocument) {
mDocument->SetBFCacheEntry(nullptr);
mDocument->RemoveMutationObserver(this);
mDocument = nullptr;
}
if (mContentViewer) {
mContentViewer->ClearHistoryEntry();
}
RemoveFromExpirationTracker();
mContentViewer = nullptr;
// FIXME Bug 1547735
// mSticky = true;
mWindowState = nullptr;
// FIXME Bug 1547735
// mViewerBounds.SetRect(0, 0, 0, 0);
mChildShells.Clear();
mRefreshURIList = nullptr;
mEditorData = nullptr;
}
void SHEntryChildShared::NotifyListenersContentViewerEvicted(
uint32_t aNumEvicted) {
if (StaticPrefs::docshell_shistory_testing_bfevict() && mSHistory) {
mSHistory->SendNotifyListenersContentViewerEvicted(aNumEvicted);
}
}
nsresult SHEntryChildShared::SetContentViewer(nsIContentViewer* aViewer) {
MOZ_ASSERT(!aViewer || !mContentViewer,
"SHEntryShared already contains viewer");
if (mContentViewer || !aViewer) {
DropPresentationState();
}
// If we're setting mContentViewer to null, state should already be cleared
// in the DropPresentationState() call above; If we're setting it to a
// non-null content viewer, the entry shouldn't have been tracked either.
MOZ_ASSERT(!GetExpirationState()->IsTracked());
mContentViewer = aViewer;
if (mContentViewer) {
// mSHistory is only set for root entries, but in general bfcache only
// applies to root entries as well. BFCache for subframe navigation has been
// disabled since 2005 in bug 304860.
if (mSHistory) {
mSHistory->AddToExpirationTracker(this);
}
// Store observed document in strong pointer in case it is removed from
// the contentviewer
mDocument = mContentViewer->GetDocument();
if (mDocument) {
mDocument->SetBFCacheEntry(this);
mDocument->AddMutationObserver(this);
}
}
return NS_OK;
}
NS_IMETHODIMP SHEntryChildShared::RemoveFromBFCacheSync() {
MOZ_ASSERT(mContentViewer && mDocument, "we're not in the bfcache!");
// The call to DropPresentationState could drop the last reference, so hold
// |this| until RemoveDynEntriesForBFCacheEntry finishes.
RefPtr<SHEntryChildShared> kungFuDeathGrip = this;
// DropPresentationState would clear mContentViewer.
nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
DropPresentationState();
if (viewer) {
viewer->Destroy();
}
// Now that we've dropped the viewer, we have to clear associated dynamic
// subframe entries.
if (mSHistory) {
mSHistory->RemoveDynEntriesForBFCacheEntry(this);
}
return NS_OK;
}
NS_IMETHODIMP SHEntryChildShared::RemoveFromBFCacheAsync() {
MOZ_ASSERT(mContentViewer && mDocument, "we're not in the bfcache!");
// Check it again to play safe in release builds.
if (!mDocument) {
return NS_ERROR_UNEXPECTED;
}
// DropPresentationState would clear mContentViewer & mDocument. Capture and
// release the references asynchronously so that the document doesn't get
// nuked mid-mutation.
nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
RefPtr<dom::Document> _document = mDocument;
RefPtr<SHEntryChildShared> self = this;
nsresult rv = mDocument->Dispatch(
mozilla::TaskCategory::Other,
NS_NewRunnableFunction(
"SHEntryChildShared::RemoveFromBFCacheAsync",
// _document isn't used in the closure, but just keeps mDocument
// alive until the closure runs.
[self, viewer, _document]() {
if (viewer) {
viewer->Destroy();
}
if (self->mSHistory) {
self->mSHistory->RemoveDynEntriesForBFCacheEntry(self);
}
}));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch RemoveFromBFCacheAsync runnable.");
} else {
// Drop presentation. Only do this if we succeeded in posting the event
// since otherwise the document could be torn down mid-mutation, causing
// crashes.
DropPresentationState();
}
return NS_OK;
}
void SHEntryChildShared::CharacterDataChanged(nsIContent* aContent,
const CharacterDataChangeInfo&) {
RemoveFromBFCacheAsync();
}
void SHEntryChildShared::AttributeChanged(dom::Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue) {
RemoveFromBFCacheAsync();
}
void SHEntryChildShared::ContentAppended(nsIContent* aFirstNewContent) {
RemoveFromBFCacheAsync();
}
void SHEntryChildShared::ContentInserted(nsIContent* aChild) {
RemoveFromBFCacheAsync();
}
void SHEntryChildShared::ContentRemoved(nsIContent* aChild,
nsIContent* aPreviousSibling) {
RemoveFromBFCacheAsync();
}
NS_IMPL_ADDREF(SHEntryChild)
NS_IMETHODIMP_(MozExternalRefCountType) SHEntryChild::Release() {
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
NS_ASSERT_OWNINGTHREAD(SHEntryChild);
nsrefcnt count = --mRefCnt;
NS_LOG_RELEASE(this, count, "SHEntryChild");
if (count == 0) {
mRefCnt = 1; /* stabilize */
delete this;
return 0;
}
if (count == 1 && !mIPCActorDeleted) {
Send__delete__(this);
}
return count;
}
NS_IMPL_QUERY_INTERFACE(SHEntryChild, nsISHEntry)
NS_IMETHODIMP
SHEntryChild::SetScrollPosition(int32_t aX, int32_t aY) {
return SendSetScrollPosition(aX, aY) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetScrollPosition(int32_t* aX, int32_t* aY) {
return SendGetScrollPosition(aX, aY) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetURIWasModified(bool* aURIWasModified) {
return SendGetURIWasModified(aURIWasModified) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetURIWasModified(bool aURIWasModified) {
return SendSetURIWasModified(aURIWasModified) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetURI(nsIURI** aURI) {
RefPtr<nsIURI> uri;
if (!SendGetURI(&uri)) {
return NS_ERROR_FAILURE;
}
uri.forget(aURI);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetURI(nsIURI* aURI) {
return SendSetURI(aURI) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetOriginalURI(nsIURI** aOriginalURI) {
RefPtr<nsIURI> originalURI;
if (!SendGetOriginalURI(&originalURI)) {
return NS_ERROR_FAILURE;
}
originalURI.forget(aOriginalURI);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetOriginalURI(nsIURI* aOriginalURI) {
return SendSetOriginalURI(aOriginalURI) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetResultPrincipalURI(nsIURI** aResultPrincipalURI) {
RefPtr<nsIURI> resultPrincipalURI;
if (!SendGetResultPrincipalURI(&resultPrincipalURI)) {
return NS_ERROR_FAILURE;
}
resultPrincipalURI.forget(aResultPrincipalURI);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
return SendSetResultPrincipalURI(aResultPrincipalURI) ? NS_OK
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetLoadReplace(bool* aLoadReplace) {
return SendGetLoadReplace(aLoadReplace) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetLoadReplace(bool aLoadReplace) {
return SendSetLoadReplace(aLoadReplace) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetReferrerInfo(nsIReferrerInfo** aReferrerInfo) {
RefPtr<nsIReferrerInfo> referrerInfo;
if (SendGetReferrerInfo(&referrerInfo)) {
referrerInfo.forget(aReferrerInfo);
}
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
return SendSetReferrerInfo(aReferrerInfo) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetContentViewer(nsIContentViewer* aViewer) {
return mShared->SetContentViewer(aViewer);
}
NS_IMETHODIMP
SHEntryChild::GetContentViewer(nsIContentViewer** aResult) {
NS_IF_ADDREF(*aResult = mShared->mContentViewer);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetSticky(bool aSticky) {
return SendSetSticky(aSticky) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetSticky(bool* aSticky) {
return SendGetSticky(aSticky) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetTitle(nsAString& aTitle) {
nsString title;
if (!SendGetTitle(&title)) {
return NS_ERROR_FAILURE;
}
aTitle = std::move(title);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetTitle(const nsAString& aTitle) {
return SendSetTitle(nsString(aTitle)) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetPostData(nsIInputStream** aPostData) {
RefPtr<nsIInputStream> postData;
if (!SendGetPostData(&postData)) {
return NS_ERROR_FAILURE;
}
postData.forget(aPostData);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetPostData(nsIInputStream* aPostData) {
return SendSetPostData(aPostData) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetLayoutHistoryState(nsILayoutHistoryState** aResult) {
NS_IF_ADDREF(*aResult = mShared->mLayoutHistoryState);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetLayoutHistoryState(nsILayoutHistoryState* aState) {
mShared->mLayoutHistoryState = aState;
if (mShared->mLayoutHistoryState) {
mShared->mLayoutHistoryState->SetScrollPositionOnly(
!mShared->mSaveLayoutState);
}
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::InitLayoutHistoryState(nsILayoutHistoryState** aState) {
nsCOMPtr<nsILayoutHistoryState> historyState;
if (mShared->mLayoutHistoryState) {
historyState = mShared->mLayoutHistoryState;
} else {
historyState = NS_NewLayoutHistoryState();
SetLayoutHistoryState(historyState);
}
historyState.forget(aState);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SynchronizeLayoutHistoryState() {
if (!mShared->mLayoutHistoryState) {
return NS_OK;
}
bool scrollPositionOnly = false;
nsTArray<nsCString> keys;
nsTArray<mozilla::PresState> states;
mShared->mLayoutHistoryState->GetContents(&scrollPositionOnly, keys, states);
Unused << SendUpdateLayoutHistoryState(scrollPositionOnly, keys, states);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::GetLoadType(uint32_t* aResult) {
return SendGetLoadType(aResult) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetLoadType(uint32_t aLoadType) {
return SendSetLoadType(aLoadType) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetID(uint32_t* aResult) {
return SendGetID(aResult) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetID(uint32_t aID) {
return SendSetID(aID) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetIsSubFrame(bool* aFlag) {
return SendGetIsSubFrame(aFlag) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetIsSubFrame(bool aFlag) {
return SendSetIsSubFrame(aFlag) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetCacheKey(uint32_t* aResult) {
return SendGetCacheKey(aResult) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetCacheKey(uint32_t aCacheKey) {
return SendSetCacheKey(aCacheKey) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetSaveLayoutStateFlag(bool* aFlag) {
*aFlag = mShared->mSaveLayoutState;
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetSaveLayoutStateFlag(bool aFlag) {
mShared->mSaveLayoutState = aFlag;
if (mShared->mLayoutHistoryState) {
mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag);
}
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::GetExpirationStatus(bool* aFlag) {
return SendGetExpirationStatus(aFlag) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetExpirationStatus(bool aFlag) {
return SendSetExpirationStatus(aFlag) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetContentType(nsACString& aContentType) {
nsCString contentType;
if (!SendGetContentType(&contentType)) {
return NS_ERROR_FAILURE;
}
aContentType = contentType;
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetContentType(const nsACString& aContentType) {
return SendSetContentType(nsCString(aContentType)) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::Create(
nsIURI* aURI, const nsAString& aTitle, nsIInputStream* aInputStream,
uint32_t aCacheKey, const nsACString& aContentType,
nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
nsIPrincipal* aStoragePrincipalToInherit, nsIContentSecurityPolicy* aCsp,
const nsID& aDocShellID, bool aDynamicCreation, nsIURI* aOriginalURI,
nsIURI* aResultPrincipalURI, bool aLoadReplace,
nsIReferrerInfo* aReferrerInfo, const nsAString& srcdoc, bool srcdocEntry,
nsIURI* aBaseURI, bool aSaveLayoutState, bool aExpired) {
mShared->mLayoutHistoryState = nullptr;
mShared->mSaveLayoutState = aSaveLayoutState;
return SendCreate(aURI, nsString(aTitle), aInputStream, aCacheKey,
nsCString(aContentType), aTriggeringPrincipal,
aPrincipalToInherit, aStoragePrincipalToInherit, aCsp,
aDocShellID, aDynamicCreation, aOriginalURI,
aResultPrincipalURI, aLoadReplace, aReferrerInfo,
nsString(srcdoc), srcdocEntry, aBaseURI, aSaveLayoutState,
aExpired)
? NS_OK
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::Clone(nsISHEntry** aResult) {
RefPtr<CrossProcessSHEntry> result;
if (!SendClone(&result)) {
return NS_ERROR_FAILURE;
}
*aResult = result ? do_AddRef(result->ToSHEntryChild()).take() : nullptr;
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::GetParent(nsISHEntry** aResult) {
RefPtr<CrossProcessSHEntry> parent;
if (!SendGetParent(&parent)) {
return NS_ERROR_FAILURE;
}
*aResult = parent ? do_AddRef(parent->ToSHEntryChild()).take() : nullptr;
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetParent(nsISHEntry* aParent) {
return SendSetParent(static_cast<SHEntryChild*>(aParent)) ? NS_OK
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetWindowState(nsISupports* aState) {
mShared->mWindowState = aState;
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::GetWindowState(nsISupports** aState) {
NS_IF_ADDREF(*aState = mShared->mWindowState);
return NS_OK;
}
NS_IMETHODIMP_(void)
SHEntryChild::SetViewerBounds(const nsIntRect& aBounds) {
Unused << SendSetViewerBounds(aBounds);
}
NS_IMETHODIMP_(void)
SHEntryChild::GetViewerBounds(nsIntRect& aBounds) {
Unused << SendGetViewerBounds(&aBounds);
}
NS_IMETHODIMP
SHEntryChild::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal) {
RefPtr<nsIPrincipal> triggeringPrincipal;
if (!SendGetTriggeringPrincipal(&triggeringPrincipal)) {
return NS_ERROR_FAILURE;
}
triggeringPrincipal.forget(aTriggeringPrincipal);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal) {
return SendSetTriggeringPrincipal(aTriggeringPrincipal) ? NS_OK
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit) {
RefPtr<nsIPrincipal> principalToInherit;
if (!SendGetPrincipalToInherit(&principalToInherit)) {
return NS_ERROR_FAILURE;
}
principalToInherit.forget(aPrincipalToInherit);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit) {
return SendSetPrincipalToInherit(aPrincipalToInherit) ? NS_OK
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetStoragePrincipalToInherit(
nsIPrincipal** aStoragePrincipalToInherit) {
RefPtr<nsIPrincipal> storagePrincipalToInherit;
if (!SendGetStoragePrincipalToInherit(&storagePrincipalToInherit)) {
return NS_ERROR_FAILURE;
}
storagePrincipalToInherit.forget(aStoragePrincipalToInherit);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetStoragePrincipalToInherit(
nsIPrincipal* aStoragePrincipalToInherit) {
return SendSetStoragePrincipalToInherit(aStoragePrincipalToInherit)
? NS_OK
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetCsp(nsIContentSecurityPolicy** aCsp) {
RefPtr<nsIContentSecurityPolicy> csp;
if (!SendGetCsp(&csp)) {
return NS_ERROR_FAILURE;
}
csp.forget(aCsp);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetCsp(nsIContentSecurityPolicy* aCsp) {
return SendSetCsp(aCsp) ? NS_OK : NS_ERROR_FAILURE;
}
bool SHEntryChild::HasBFCacheEntry(nsIBFCacheEntry* aEntry) {
return mShared == aEntry;
}
NS_IMETHODIMP
SHEntryChild::AdoptBFCacheEntry(nsISHEntry* aEntry) {
RefPtr<SHEntryChild> entry = static_cast<SHEntryChild*>(aEntry);
nsresult rv;
if (!SendAdoptBFCacheEntry(entry, &rv)) {
return NS_ERROR_FAILURE;
}
NS_ENSURE_SUCCESS(rv, rv);
mShared = entry->mShared;
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SharesDocumentWith(nsISHEntry* aEntry, bool* aOut) {
nsresult rv;
// FIXME Maybe check local shared state instead?
return SendSharesDocumentWith(static_cast<SHEntryChild*>(aEntry), aOut, &rv)
? rv
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::AbandonBFCacheEntry() {
RefPtr<SHEntryChildShared> shared = mShared->Duplicate();
if (!SendAbandonBFCacheEntry(shared->GetID())) {
return NS_ERROR_FAILURE;
}
shared.swap(mShared);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::GetIsSrcdocEntry(bool* aIsSrcdocEntry) {
return SendGetIsSrcdocEntry(aIsSrcdocEntry) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetSrcdocData(nsAString& aSrcdocData) {
nsString srcdocData;
if (!SendGetSrcdocData(&srcdocData)) {
return NS_ERROR_FAILURE;
}
aSrcdocData = srcdocData;
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetSrcdocData(const nsAString& aSrcdocData) {
return SendSetSrcdocData(nsString(aSrcdocData)) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetBaseURI(nsIURI** aBaseURI) {
RefPtr<nsIURI> baseURI;
if (!SendGetBaseURI(&baseURI)) {
return NS_ERROR_FAILURE;
}
baseURI.forget(aBaseURI);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetBaseURI(nsIURI* aBaseURI) {
return SendSetBaseURI(aBaseURI) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetScrollRestorationIsManual(bool* aIsManual) {
return SendGetScrollRestorationIsManual(aIsManual) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetScrollRestorationIsManual(bool aIsManual) {
return SendSetScrollRestorationIsManual(aIsManual) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetLoadedInThisProcess(bool* aLoadedInThisProcess) {
return SendGetLoadedInThisProcess(aLoadedInThisProcess) ? NS_OK
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetChildCount(int32_t* aCount) {
return SendGetChildCount(aCount) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::AddChild(nsISHEntry* aChild, int32_t aOffset,
bool aUseRemoteSubframes) {
nsresult rv;
return SendAddChild(static_cast<SHEntryChild*>(aChild), aOffset,
aUseRemoteSubframes, &rv)
? rv
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::RemoveChild(nsISHEntry* aChild) {
nsresult rv;
return aChild && SendRemoveChild(static_cast<SHEntryChild*>(aChild), &rv)
? rv
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetChildAt(int32_t aIndex, nsISHEntry** aResult) {
RefPtr<CrossProcessSHEntry> child;
if (!SendGetChildAt(aIndex, &child)) {
return NS_ERROR_FAILURE;
}
*aResult = child ? do_AddRef(child->ToSHEntryChild()).take() : nullptr;
return NS_OK;
}
NS_IMETHODIMP_(void)
SHEntryChild::GetChildSHEntryIfHasNoDynamicallyAddedChild(int32_t aChildOffset,
nsISHEntry** aChild) {
RefPtr<CrossProcessSHEntry> child;
SendGetChildSHEntryIfHasNoDynamicallyAddedChild(aChildOffset, &child);
*aChild = child ? do_AddRef(child->ToSHEntryChild()).take() : nullptr;
}
NS_IMETHODIMP
SHEntryChild::ReplaceChild(nsISHEntry* aNewEntry) {
nsresult rv;
return SendReplaceChild(static_cast<SHEntryChild*>(aNewEntry), &rv)
? rv
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP_(void)
SHEntryChild::ClearEntry() {
// We want to call AbandonBFCacheEntry in SHEntryParent,
// hence the need for duplciating the shared entry here
RefPtr<SHEntryChildShared> shared = mShared->Duplicate();
SendClearEntry(shared->GetID());
shared.swap(mShared);
}
NS_IMETHODIMP_(void)
SHEntryChild::AddChildShell(nsIDocShellTreeItem* aShell) {
mShared->mChildShells.AppendObject(aShell);
}
NS_IMETHODIMP
SHEntryChild::ChildShellAt(int32_t aIndex, nsIDocShellTreeItem** aShell) {
NS_IF_ADDREF(*aShell = mShared->mChildShells.SafeObjectAt(aIndex));
return NS_OK;
}
NS_IMETHODIMP_(void)
SHEntryChild::ClearChildShells() { mShared->mChildShells.Clear(); }
NS_IMETHODIMP
SHEntryChild::GetRefreshURIList(nsIMutableArray** aList) {
// FIXME Move to parent.
NS_IF_ADDREF(*aList = mShared->mRefreshURIList);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetRefreshURIList(nsIMutableArray* aList) {
// FIXME Move to parent.
mShared->mRefreshURIList = aList;
return NS_OK;
}
NS_IMETHODIMP_(void)
SHEntryChild::SyncPresentationState() { mShared->SyncPresentationState(); }
nsDocShellEditorData* SHEntryChild::ForgetEditorData() {
return mShared->mEditorData.release();
}
void SHEntryChild::SetEditorData(nsDocShellEditorData* aData) {
NS_ASSERTION(!(aData && mShared->mEditorData),
"We're going to overwrite an owning ref!");
if (mShared->mEditorData != aData) {
mShared->mEditorData = WrapUnique(aData);
}
}
bool SHEntryChild::HasDetachedEditor() {
return mShared->mEditorData != nullptr;
}
NS_IMETHODIMP
SHEntryChild::GetStateData(nsIStructuredCloneContainer** aContainer) {
ClonedMessageData data;
if (!SendGetStateData(&data)) {
return NS_ERROR_FAILURE;
}
// FIXME Should we signal null separately from the ClonedMessageData?
if (data.data().data.Size() == 0) {
*aContainer = nullptr;
} else {
RefPtr<nsStructuredCloneContainer> container =
new nsStructuredCloneContainer();
container->StealFromClonedMessageDataForParent(data);
container.forget(aContainer);
}
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetStateData(nsIStructuredCloneContainer* aContainer) {
// FIXME nsIStructuredCloneContainer is not builtin_class
ClonedMessageData data;
if (aContainer) {
static_cast<nsStructuredCloneContainer*>(aContainer)
->BuildClonedMessageDataForChild(ContentChild::GetSingleton(), data);
}
return SendSetStateData(data) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP_(bool)
SHEntryChild::IsDynamicallyAdded() {
bool isDynamicallyAdded;
return SendIsDynamicallyAdded(&isDynamicallyAdded) && isDynamicallyAdded;
}
NS_IMETHODIMP
SHEntryChild::HasDynamicallyAddedChild(bool* aAdded) {
return SendHasDynamicallyAddedChild(aAdded) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetDocshellID(nsID& aID) {
if (!SendGetDocshellID(&aID)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetDocshellID(const nsID& aID) {
return SendSetDocshellID(aID) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetLastTouched(uint32_t* aLastTouched) {
return SendGetLastTouched(aLastTouched) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetLastTouched(uint32_t aLastTouched) {
return SendSetLastTouched(aLastTouched) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetShistory(nsISHistory** aSHistory) {
*aSHistory = do_AddRef(mShared->mSHistory).take();
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::SetLoadTypeAsHistory() {
return SendSetLoadTypeAsHistory() ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::GetPersist(bool* aPersist) {
return SendGetPersist(aPersist) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::SetPersist(bool aPersist) {
return SendSetPersist(aPersist) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SHEntryChild::CreateLoadInfo(nsDocShellLoadState** aLoadState) {
*aLoadState = nullptr;
RefPtr<nsDocShellLoadState> loadState;
if (!SendCreateLoadInfo(&loadState)) {
return NS_ERROR_FAILURE;
}
loadState.forget(aLoadState);
return NS_OK;
}
NS_IMETHODIMP
SHEntryChild::GetBfcacheID(uint64_t* aBFCacheID) {
*aBFCacheID = mShared->GetID();
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) {
// Drop the presentation state before destroying the viewer, so that
// document teardown is able to correctly persist the state.
mShared->NotifyListenersContentViewerEvicted();
SetContentViewer(nullptr);
SyncPresentationState();
viewer->Destroy();
}
}
} // namespace dom
} // namespace mozilla