michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Local Includes michael@0: #include "nsSHEntry.h" michael@0: #include "nsIDocShellLoadInfo.h" michael@0: #include "nsIDocShellTreeItem.h" michael@0: #include "nsDocShellEditorData.h" michael@0: #include "nsSHEntryShared.h" michael@0: #include "nsILayoutHistoryState.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsISupportsArray.h" michael@0: #include "nsIStructuredCloneContainer.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsIURI.h" michael@0: #include michael@0: michael@0: namespace dom = mozilla::dom; michael@0: michael@0: static uint32_t gEntryID = 0; michael@0: michael@0: //***************************************************************************** michael@0: //*** nsSHEntry: Object Management michael@0: //***************************************************************************** michael@0: michael@0: michael@0: nsSHEntry::nsSHEntry() michael@0: : mLoadType(0) michael@0: , mID(gEntryID++) michael@0: , mScrollPositionX(0) michael@0: , mScrollPositionY(0) michael@0: , mParent(nullptr) michael@0: , mURIWasModified(false) michael@0: , mIsSrcdocEntry(false) michael@0: { michael@0: mShared = new nsSHEntryShared(); michael@0: } michael@0: michael@0: nsSHEntry::nsSHEntry(const nsSHEntry &other) michael@0: : mShared(other.mShared) michael@0: , mURI(other.mURI) michael@0: , mReferrerURI(other.mReferrerURI) michael@0: , mTitle(other.mTitle) michael@0: , mPostData(other.mPostData) michael@0: , mLoadType(0) // XXX why not copy? michael@0: , mID(other.mID) michael@0: , mScrollPositionX(0) // XXX why not copy? michael@0: , mScrollPositionY(0) // XXX why not copy? michael@0: , mParent(other.mParent) michael@0: , mURIWasModified(other.mURIWasModified) michael@0: , mStateData(other.mStateData) michael@0: , mIsSrcdocEntry(other.mIsSrcdocEntry) michael@0: , mSrcdocData(other.mSrcdocData) michael@0: , mBaseURI(other.mBaseURI) michael@0: { michael@0: } michael@0: michael@0: static bool michael@0: ClearParentPtr(nsISHEntry* aEntry, void* /* aData */) michael@0: { michael@0: if (aEntry) { michael@0: aEntry->SetParent(nullptr); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: nsSHEntry::~nsSHEntry() michael@0: { michael@0: // Null out the mParent pointers on all our kids. michael@0: mChildren.EnumerateForwards(ClearParentPtr, nullptr); michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsSHEntry: nsISupports michael@0: //***************************************************************************** michael@0: michael@0: NS_IMPL_ISUPPORTS(nsSHEntry, nsISHContainer, nsISHEntry, nsISHEntryInternal) michael@0: michael@0: //***************************************************************************** michael@0: // nsSHEntry: nsISHEntry michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetScrollPosition(int32_t x, int32_t y) michael@0: { michael@0: mScrollPositionX = x; michael@0: mScrollPositionY = y; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetScrollPosition(int32_t *x, int32_t *y) michael@0: { michael@0: *x = mScrollPositionX; michael@0: *y = mScrollPositionY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetURIWasModified(bool* aOut) michael@0: { michael@0: *aOut = mURIWasModified; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetURIWasModified(bool aIn) michael@0: { michael@0: mURIWasModified = aIn; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetURI(nsIURI** aURI) michael@0: { michael@0: *aURI = mURI; michael@0: NS_IF_ADDREF(*aURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetURI(nsIURI* aURI) michael@0: { michael@0: mURI = aURI; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetReferrerURI(nsIURI **aReferrerURI) michael@0: { michael@0: *aReferrerURI = mReferrerURI; michael@0: NS_IF_ADDREF(*aReferrerURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI) michael@0: { michael@0: mReferrerURI = aReferrerURI; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetContentViewer(nsIContentViewer *aViewer) michael@0: { michael@0: return mShared->SetContentViewer(aViewer); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetContentViewer(nsIContentViewer **aResult) michael@0: { michael@0: *aResult = mShared->mContentViewer; michael@0: NS_IF_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetAnyContentViewer(nsISHEntry **aOwnerEntry, michael@0: nsIContentViewer **aResult) michael@0: { michael@0: // Find a content viewer in the root node or any of its children, michael@0: // assuming that there is only one content viewer total in any one michael@0: // nsSHEntry tree michael@0: GetContentViewer(aResult); michael@0: if (*aResult) { michael@0: #ifdef DEBUG_PAGE_CACHE michael@0: printf("Found content viewer\n"); michael@0: #endif michael@0: *aOwnerEntry = this; michael@0: NS_ADDREF(*aOwnerEntry); michael@0: return NS_OK; michael@0: } michael@0: // The root SHEntry doesn't have a ContentViewer, so check child nodes michael@0: for (int32_t i = 0; i < mChildren.Count(); i++) { michael@0: nsISHEntry* child = mChildren[i]; michael@0: if (child) { michael@0: #ifdef DEBUG_PAGE_CACHE michael@0: printf("Evaluating SHEntry child %d\n", i); michael@0: #endif michael@0: child->GetAnyContentViewer(aOwnerEntry, aResult); michael@0: if (*aResult) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetSticky(bool aSticky) michael@0: { michael@0: mShared->mSticky = aSticky; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetSticky(bool *aSticky) michael@0: { michael@0: *aSticky = mShared->mSticky; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetTitle(char16_t** aTitle) michael@0: { michael@0: // Check for empty title... michael@0: if (mTitle.IsEmpty() && mURI) { michael@0: // Default title is the URL. michael@0: nsAutoCString spec; michael@0: if (NS_SUCCEEDED(mURI->GetSpec(spec))) michael@0: AppendUTF8toUTF16(spec, mTitle); michael@0: } michael@0: michael@0: *aTitle = ToNewUnicode(mTitle); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetTitle(const nsAString &aTitle) michael@0: { michael@0: mTitle = aTitle; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetPostData(nsIInputStream** aResult) michael@0: { michael@0: *aResult = mPostData; michael@0: NS_IF_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetPostData(nsIInputStream* aPostData) michael@0: { michael@0: mPostData = aPostData; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult) michael@0: { michael@0: *aResult = mShared->mLayoutHistoryState; michael@0: NS_IF_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState) michael@0: { michael@0: mShared->mLayoutHistoryState = aState; michael@0: if (mShared->mLayoutHistoryState) { michael@0: mShared->mLayoutHistoryState-> michael@0: SetScrollPositionOnly(!mShared->mSaveLayoutState); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetLoadType(uint32_t * aResult) michael@0: { michael@0: *aResult = mLoadType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetLoadType(uint32_t aLoadType) michael@0: { michael@0: mLoadType = aLoadType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetID(uint32_t * aResult) michael@0: { michael@0: *aResult = mID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetID(uint32_t aID) michael@0: { michael@0: mID = aID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsSHEntryShared* nsSHEntry::GetSharedState() michael@0: { michael@0: return mShared; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetIsSubFrame(bool * aFlag) michael@0: { michael@0: *aFlag = mShared->mIsFrameNavigation; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetIsSubFrame(bool aFlag) michael@0: { michael@0: mShared->mIsFrameNavigation = aFlag; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetCacheKey(nsISupports** aResult) michael@0: { michael@0: *aResult = mShared->mCacheKey; michael@0: NS_IF_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetCacheKey(nsISupports* aCacheKey) michael@0: { michael@0: mShared->mCacheKey = aCacheKey; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetSaveLayoutStateFlag(bool * aFlag) michael@0: { michael@0: *aFlag = mShared->mSaveLayoutState; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetSaveLayoutStateFlag(bool aFlag) michael@0: { michael@0: mShared->mSaveLayoutState = aFlag; michael@0: if (mShared->mLayoutHistoryState) { michael@0: mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetExpirationStatus(bool * aFlag) michael@0: { michael@0: *aFlag = mShared->mExpired; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetExpirationStatus(bool aFlag) michael@0: { michael@0: mShared->mExpired = aFlag; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::GetContentType(nsACString& aContentType) michael@0: { michael@0: aContentType = mShared->mContentType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsSHEntry::SetContentType(const nsACString& aContentType) michael@0: { michael@0: mShared->mContentType = aContentType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle, michael@0: nsIInputStream * aInputStream, michael@0: nsILayoutHistoryState * aLayoutHistoryState, michael@0: nsISupports * aCacheKey, const nsACString& aContentType, michael@0: nsISupports* aOwner, michael@0: uint64_t aDocShellID, bool aDynamicCreation) michael@0: { michael@0: mURI = aURI; michael@0: mTitle = aTitle; michael@0: mPostData = aInputStream; michael@0: michael@0: // Set the LoadType by default to loadHistory during creation michael@0: mLoadType = (uint32_t) nsIDocShellLoadInfo::loadHistory; michael@0: michael@0: mShared->mCacheKey = aCacheKey; michael@0: mShared->mContentType = aContentType; michael@0: mShared->mOwner = aOwner; michael@0: mShared->mDocShellID = aDocShellID; michael@0: mShared->mDynamicallyCreated = aDynamicCreation; michael@0: michael@0: // By default all entries are set false for subframe flag. michael@0: // nsDocShell::CloneAndReplace() which creates entries for michael@0: // all subframe navigations, sets the flag to true. michael@0: mShared->mIsFrameNavigation = false; michael@0: michael@0: // By default we save LayoutHistoryState michael@0: mShared->mSaveLayoutState = true; michael@0: mShared->mLayoutHistoryState = aLayoutHistoryState; michael@0: michael@0: //By default the page is not expired michael@0: mShared->mExpired = false; michael@0: michael@0: mIsSrcdocEntry = false; michael@0: mSrcdocData = NullString(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::Clone(nsISHEntry ** aResult) michael@0: { michael@0: *aResult = new nsSHEntry(*this); michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetParent(nsISHEntry ** aResult) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aResult); michael@0: *aResult = mParent; michael@0: NS_IF_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetParent(nsISHEntry * aParent) michael@0: { michael@0: /* parent not Addrefed on purpose to avoid cyclic reference michael@0: * Null parent is OK michael@0: * michael@0: * XXX this method should not be scriptable if this is the case!! michael@0: */ michael@0: mParent = aParent; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetWindowState(nsISupports *aState) michael@0: { michael@0: mShared->mWindowState = aState; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetWindowState(nsISupports **aState) michael@0: { michael@0: NS_IF_ADDREF(*aState = mShared->mWindowState); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetViewerBounds(const nsIntRect &aBounds) michael@0: { michael@0: mShared->mViewerBounds = aBounds; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetViewerBounds(nsIntRect &aBounds) michael@0: { michael@0: aBounds = mShared->mViewerBounds; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetOwner(nsISupports **aOwner) michael@0: { michael@0: NS_IF_ADDREF(*aOwner = mShared->mOwner); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetOwner(nsISupports *aOwner) michael@0: { michael@0: mShared->mOwner = aOwner; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetBFCacheEntry(nsIBFCacheEntry **aEntry) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEntry); michael@0: NS_IF_ADDREF(*aEntry = mShared); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry *aEntry) michael@0: { michael@0: return static_cast(mShared) == aEntry; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::AdoptBFCacheEntry(nsISHEntry *aEntry) michael@0: { michael@0: nsCOMPtr shEntry = do_QueryInterface(aEntry); michael@0: NS_ENSURE_STATE(shEntry); michael@0: michael@0: nsSHEntryShared *shared = shEntry->GetSharedState(); michael@0: NS_ENSURE_STATE(shared); michael@0: michael@0: mShared = shared; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SharesDocumentWith(nsISHEntry *aEntry, bool *aOut) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aOut); michael@0: michael@0: nsCOMPtr internal = do_QueryInterface(aEntry); michael@0: NS_ENSURE_STATE(internal); michael@0: michael@0: *aOut = mShared == internal->GetSharedState(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::AbandonBFCacheEntry() michael@0: { michael@0: mShared = nsSHEntryShared::Duplicate(mShared); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetIsSrcdocEntry(bool* aIsSrcdocEntry) michael@0: { michael@0: *aIsSrcdocEntry = mIsSrcdocEntry; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetSrcdocData(nsAString &aSrcdocData) michael@0: { michael@0: aSrcdocData = mSrcdocData; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetSrcdocData(const nsAString &aSrcdocData) michael@0: { michael@0: mSrcdocData = aSrcdocData; michael@0: mIsSrcdocEntry = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetBaseURI(nsIURI **aBaseURI) michael@0: { michael@0: *aBaseURI = mBaseURI; michael@0: NS_IF_ADDREF(*aBaseURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetBaseURI(nsIURI *aBaseURI) michael@0: { michael@0: mBaseURI = aBaseURI; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsSHEntry: nsISHContainer michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetChildCount(int32_t * aCount) michael@0: { michael@0: *aCount = mChildren.Count(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::AddChild(nsISHEntry * aChild, int32_t aOffset) michael@0: { michael@0: if (aChild) { michael@0: NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE); michael@0: } michael@0: michael@0: if (aOffset < 0) { michael@0: mChildren.AppendObject(aChild); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // Bug 52670: Ensure children are added in order. michael@0: // michael@0: // Later frames in the child list may load faster and get appended michael@0: // before earlier frames, causing session history to be scrambled. michael@0: // By growing the list here, they are added to the right position. michael@0: // michael@0: // Assert that aOffset will not be so high as to grow us a lot. michael@0: // michael@0: NS_ASSERTION(aOffset < (mChildren.Count()+1023), "Large frames array!\n"); michael@0: michael@0: bool newChildIsDyn = false; michael@0: if (aChild) { michael@0: aChild->IsDynamicallyAdded(&newChildIsDyn); michael@0: } michael@0: michael@0: // If the new child is dynamically added, try to add it to aOffset, but if michael@0: // there are non-dynamically added children, the child must be after those. michael@0: if (newChildIsDyn) { michael@0: int32_t lastNonDyn = aOffset - 1; michael@0: for (int32_t i = aOffset; i < mChildren.Count(); ++i) { michael@0: nsISHEntry* entry = mChildren[i]; michael@0: if (entry) { michael@0: bool dyn = false; michael@0: entry->IsDynamicallyAdded(&dyn); michael@0: if (dyn) { michael@0: break; michael@0: } else { michael@0: lastNonDyn = i; michael@0: } michael@0: } michael@0: } michael@0: // InsertObjectAt allows only appending one object. michael@0: // If aOffset is larger than Count(), we must first manually michael@0: // set the capacity. michael@0: if (aOffset > mChildren.Count()) { michael@0: mChildren.SetCount(aOffset); michael@0: } michael@0: if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) { michael@0: NS_WARNING("Adding a child failed!"); michael@0: aChild->SetParent(nullptr); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } else { michael@0: // If the new child isn't dynamically added, it should be set to aOffset. michael@0: // If there are dynamically added children before that, those must be michael@0: // moved to be after aOffset. michael@0: if (mChildren.Count() > 0) { michael@0: int32_t start = std::min(mChildren.Count() - 1, aOffset); michael@0: int32_t dynEntryIndex = -1; michael@0: nsISHEntry* dynEntry = nullptr; michael@0: for (int32_t i = start; i >= 0; --i) { michael@0: nsISHEntry* entry = mChildren[i]; michael@0: if (entry) { michael@0: bool dyn = false; michael@0: entry->IsDynamicallyAdded(&dyn); michael@0: if (dyn) { michael@0: dynEntryIndex = i; michael@0: dynEntry = entry; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (dynEntry) { michael@0: nsCOMArray tmp; michael@0: tmp.SetCount(aOffset - dynEntryIndex + 1); michael@0: mChildren.InsertObjectsAt(tmp, dynEntryIndex); michael@0: NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?"); michael@0: } michael@0: } michael@0: michael@0: michael@0: // Make sure there isn't anything at aOffset. michael@0: if (aOffset < mChildren.Count()) { michael@0: nsISHEntry* oldChild = mChildren[aOffset]; michael@0: if (oldChild && oldChild != aChild) { michael@0: NS_ERROR("Adding a child where we already have a child? This may misbehave"); michael@0: oldChild->SetParent(nullptr); michael@0: } michael@0: } michael@0: michael@0: if (!mChildren.ReplaceObjectAt(aChild, aOffset)) { michael@0: NS_WARNING("Adding a child failed!"); michael@0: aChild->SetParent(nullptr); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::RemoveChild(nsISHEntry * aChild) michael@0: { michael@0: NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE); michael@0: bool childRemoved = false; michael@0: bool dynamic = false; michael@0: aChild->IsDynamicallyAdded(&dynamic); michael@0: if (dynamic) { michael@0: childRemoved = mChildren.RemoveObject(aChild); michael@0: } else { michael@0: int32_t index = mChildren.IndexOfObject(aChild); michael@0: if (index >= 0) { michael@0: childRemoved = mChildren.ReplaceObjectAt(nullptr, index); michael@0: } michael@0: } michael@0: if (childRemoved) { michael@0: aChild->SetParent(nullptr); michael@0: michael@0: // reduce the child count, i.e. remove empty children at the end michael@0: for (int32_t i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) { michael@0: if (!mChildren.RemoveObjectAt(i)) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetChildAt(int32_t aIndex, nsISHEntry ** aResult) michael@0: { michael@0: if (aIndex >= 0 && aIndex < mChildren.Count()) { michael@0: *aResult = mChildren[aIndex]; michael@0: // yes, mChildren can have holes in it. AddChild's offset parameter makes michael@0: // that possible. michael@0: NS_IF_ADDREF(*aResult); michael@0: } else { michael@0: *aResult = nullptr; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell) michael@0: { michael@0: NS_ASSERTION(aShell, "Null child shell added to history entry"); michael@0: mShared->mChildShells.AppendObject(aShell); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::ChildShellAt(int32_t aIndex, nsIDocShellTreeItem **aShell) michael@0: { michael@0: NS_IF_ADDREF(*aShell = mShared->mChildShells.SafeObjectAt(aIndex)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::ClearChildShells() michael@0: { michael@0: mShared->mChildShells.Clear(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetRefreshURIList(nsISupportsArray **aList) michael@0: { michael@0: NS_IF_ADDREF(*aList = mShared->mRefreshURIList); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetRefreshURIList(nsISupportsArray *aList) michael@0: { michael@0: mShared->mRefreshURIList = aList; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SyncPresentationState() michael@0: { michael@0: return mShared->SyncPresentationState(); michael@0: } michael@0: michael@0: void michael@0: nsSHEntry::RemoveFromBFCacheSync() michael@0: { michael@0: mShared->RemoveFromBFCacheSync(); michael@0: } michael@0: michael@0: void michael@0: nsSHEntry::RemoveFromBFCacheAsync() michael@0: { michael@0: mShared->RemoveFromBFCacheAsync(); michael@0: } michael@0: michael@0: nsDocShellEditorData* michael@0: nsSHEntry::ForgetEditorData() michael@0: { michael@0: // XXX jlebar Check how this is used. michael@0: return mShared->mEditorData.forget(); michael@0: } michael@0: michael@0: void michael@0: nsSHEntry::SetEditorData(nsDocShellEditorData* aData) michael@0: { michael@0: NS_ASSERTION(!(aData && mShared->mEditorData), michael@0: "We're going to overwrite an owning ref!"); michael@0: if (mShared->mEditorData != aData) { michael@0: mShared->mEditorData = aData; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsSHEntry::HasDetachedEditor() michael@0: { michael@0: return mShared->mEditorData != nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetStateData(nsIStructuredCloneContainer **aContainer) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aContainer); michael@0: NS_IF_ADDREF(*aContainer = mStateData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetStateData(nsIStructuredCloneContainer *aContainer) michael@0: { michael@0: mStateData = aContainer; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::IsDynamicallyAdded(bool* aAdded) michael@0: { michael@0: *aAdded = mShared->mDynamicallyCreated; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::HasDynamicallyAddedChild(bool* aAdded) michael@0: { michael@0: *aAdded = false; michael@0: for (int32_t i = 0; i < mChildren.Count(); ++i) { michael@0: nsISHEntry* entry = mChildren[i]; michael@0: if (entry) { michael@0: entry->IsDynamicallyAdded(aAdded); michael@0: if (*aAdded) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetDocshellID(uint64_t* aID) michael@0: { michael@0: *aID = mShared->mDocShellID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetDocshellID(uint64_t aID) michael@0: { michael@0: mShared->mDocShellID = aID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::GetLastTouched(uint32_t *aLastTouched) michael@0: { michael@0: *aLastTouched = mShared->mLastTouched; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSHEntry::SetLastTouched(uint32_t aLastTouched) michael@0: { michael@0: mShared->mLastTouched = aLastTouched; michael@0: return NS_OK; michael@0: }