From 112d2693c3206cadc1fa047c4611874a05678381 Mon Sep 17 00:00:00 2001 From: Samael Wang Date: Tue, 19 Dec 2017 18:26:36 +0800 Subject: [PATCH] Bug 1406161 - Part 6: Move shistory related static functions to nsSHistory. r=smaug MozReview-Commit-ID: 7rqo2rISCB5 --HG-- extra : rebase_source : 3de7a21b24ce526f45424a2f1aad4329a8758f78 --- docshell/base/nsDocShell.cpp | 236 ++----------------------------- docshell/base/nsDocShell.h | 61 ++------ docshell/shistory/nsSHistory.cpp | 217 ++++++++++++++++++++++++++++ docshell/shistory/nsSHistory.h | 53 +++++++ 4 files changed, 289 insertions(+), 278 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 6a35cfdfdd5d..398b7c52ccb7 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -282,8 +282,6 @@ FavorPerformanceHint(bool aPerfOverStarvation) } } -static nsISHEntry* GetRootSHEntry(nsISHEntry* aEntry); - static void IncreasePrivateDocShellCount() { @@ -3977,8 +3975,8 @@ nsDocShell::AddChildSHEntryInternal(nsISHEntry* aCloneRef, uint32_t cloneID = 0; nsCOMPtr nextEntry; aCloneRef->GetID(&cloneID); - rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry, - aCloneChildren, getter_AddRefs(nextEntry)); + rv = nsSHistory::CloneAndReplace(currentEntry, this, cloneID, + aNewEntry, aCloneChildren, getter_AddRefs(nextEntry)); if (NS_SUCCEEDED(rv)) { nsCOMPtr shPrivate = @@ -11966,7 +11964,7 @@ nsDocShell::AddState(JS::Handle aData, const nsAString& aTitle, internalSH->EvictOutOfRangeContentViewers(curIndex); } } else { - nsCOMPtr rootSHEntry = GetRootSHEntry(newSHEntry); + nsCOMPtr rootSHEntry = nsSHistory::GetRootSHEntry(newSHEntry); int32_t index = -1; rv = rootSH->GetIndexOfEntry(rootSHEntry, &index); @@ -12266,8 +12264,8 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel, uint32_t cloneID; mOSHE->GetID(&cloneID); nsCOMPtr newEntry; - CloneAndReplace(mOSHE, this, cloneID, entry, true, - getter_AddRefs(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"); } @@ -12512,144 +12510,6 @@ nsDocShell::PersistLayoutHistoryState() return rv; } -/* static */ nsresult -nsDocShell::WalkHistoryEntries(nsISHEntry* aRootEntry, - nsDocShell* aRootShell, - WalkHistoryEntriesFunc aCallback, - void* aData) -{ - NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE); - - nsCOMPtr container(do_QueryInterface(aRootEntry)); - if (!container) { - return NS_ERROR_FAILURE; - } - - int32_t childCount; - container->GetChildCount(&childCount); - for (int32_t i = 0; i < childCount; i++) { - nsCOMPtr childEntry; - container->GetChildAt(i, getter_AddRefs(childEntry)); - if (!childEntry) { - // childEntry can be null for valid reasons, for example if the - // docshell at index i never loaded anything useful. - // Remember to clone also nulls in the child array (bug 464064). - aCallback(nullptr, nullptr, i, aData); - continue; - } - - nsDocShell* childShell = nullptr; - if (aRootShell) { - // Walk the children of aRootShell and see if one of them - // has srcChild as a SHEntry. - nsTObserverArray::ForwardIterator iter( - aRootShell->mChildList); - while (iter.HasMore()) { - nsDocShell* child = static_cast(iter.GetNext()); - - if (child->HasHistoryEntry(childEntry)) { - childShell = child; - break; - } - } - } - nsresult rv = aCallback(childEntry, childShell, i, aData); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} - -// callback data for WalkHistoryEntries -struct MOZ_STACK_CLASS CloneAndReplaceData -{ - CloneAndReplaceData(uint32_t aCloneID, nsISHEntry* aReplaceEntry, - bool aCloneChildren, nsISHEntry* aDestTreeParent) - : cloneID(aCloneID) - , cloneChildren(aCloneChildren) - , replaceEntry(aReplaceEntry) - , destTreeParent(aDestTreeParent) - { - } - - uint32_t cloneID; - bool cloneChildren; - nsISHEntry* replaceEntry; - nsISHEntry* destTreeParent; - nsCOMPtr resultEntry; -}; - -/* static */ nsresult -nsDocShell::CloneAndReplaceChild(nsISHEntry* aEntry, nsDocShell* aShell, - int32_t aEntryIndex, void* aData) -{ - nsCOMPtr dest; - - CloneAndReplaceData* data = static_cast(aData); - uint32_t cloneID = data->cloneID; - nsISHEntry* replaceEntry = data->replaceEntry; - - nsCOMPtr container = do_QueryInterface(data->destTreeParent); - if (!aEntry) { - if (container) { - container->AddChild(nullptr, aEntryIndex); - } - return NS_OK; - } - - uint32_t srcID; - aEntry->GetID(&srcID); - - nsresult rv = NS_OK; - if (srcID == cloneID) { - // Replace the entry - dest = replaceEntry; - } else { - // Clone the SHEntry... - rv = aEntry->Clone(getter_AddRefs(dest)); - NS_ENSURE_SUCCESS(rv, rv); - } - dest->SetIsSubFrame(true); - - if (srcID != cloneID || data->cloneChildren) { - // Walk the children - CloneAndReplaceData childData(cloneID, replaceEntry, - data->cloneChildren, dest); - rv = WalkHistoryEntries(aEntry, aShell, - CloneAndReplaceChild, &childData); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (srcID != cloneID && aShell) { - aShell->SwapHistoryEntries(aEntry, dest); - } - - if (container) { - container->AddChild(dest, aEntryIndex); - } - - data->resultEntry = dest; - return rv; -} - -/* static */ nsresult -nsDocShell::CloneAndReplace(nsISHEntry* aSrcEntry, - nsDocShell* aSrcShell, - uint32_t aCloneID, - nsISHEntry* aReplaceEntry, - bool aCloneChildren, - nsISHEntry** aResultEntry) -{ - NS_ENSURE_ARG_POINTER(aResultEntry); - NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE); - - CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr); - nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data); - - data.resultEntry.swap(*aResultEntry); - return rv; -} - void nsDocShell::SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry) { @@ -12662,84 +12522,6 @@ nsDocShell::SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry) } } -struct SwapEntriesData -{ - nsDocShell* ignoreShell; // constant; the shell to ignore - nsISHEntry* destTreeRoot; // constant; the root of the dest tree - nsISHEntry* destTreeParent; // constant; the node under destTreeRoot - // whose children will correspond to aEntry -}; - -nsresult -nsDocShell::SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell, - int32_t aEntryIndex, void* aData) -{ - SwapEntriesData* data = static_cast(aData); - nsDocShell* ignoreShell = data->ignoreShell; - - if (!aShell || aShell == ignoreShell) { - return NS_OK; - } - - nsISHEntry* destTreeRoot = data->destTreeRoot; - - nsCOMPtr destEntry; - nsCOMPtr container = do_QueryInterface(data->destTreeParent); - - if (container) { - // aEntry is a clone of some child of destTreeParent, but since the - // trees aren't necessarily in sync, we'll have to locate it. - // Note that we could set aShell's entry to null if we don't find a - // corresponding entry under destTreeParent. - - uint32_t targetID, id; - aEntry->GetID(&targetID); - - // First look at the given index, since this is the common case. - nsCOMPtr entry; - container->GetChildAt(aEntryIndex, getter_AddRefs(entry)); - if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) { - destEntry.swap(entry); - } else { - int32_t childCount; - container->GetChildCount(&childCount); - for (int32_t i = 0; i < childCount; ++i) { - container->GetChildAt(i, getter_AddRefs(entry)); - if (!entry) { - continue; - } - - entry->GetID(&id); - if (id == targetID) { - destEntry.swap(entry); - break; - } - } - } - } else { - destEntry = destTreeRoot; - } - - aShell->SwapHistoryEntries(aEntry, destEntry); - - // Now handle the children of aEntry. - SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry }; - return WalkHistoryEntries(aEntry, aShell, SetChildHistoryEntry, &childData); -} - -static nsISHEntry* -GetRootSHEntry(nsISHEntry* aEntry) -{ - nsCOMPtr rootEntry = aEntry; - nsISHEntry* result = nullptr; - while (rootEntry) { - result = rootEntry; - result->GetParent(getter_AddRefs(rootEntry)); - } - - return result; -} - void nsDocShell::SetHistoryEntry(nsCOMPtr* aPtr, nsISHEntry* aEntry) { @@ -12750,27 +12532,27 @@ nsDocShell::SetHistoryEntry(nsCOMPtr* aPtr, nsISHEntry* aEntry) // 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 = GetRootSHEntry(aEntry); + 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 oldRootEntry = GetRootSHEntry(*aPtr); + nsCOMPtr oldRootEntry = nsSHistory::GetRootSHEntry(*aPtr); if (oldRootEntry) { nsCOMPtr rootAsItem; GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); nsCOMPtr rootShell = do_QueryInterface(rootAsItem); if (rootShell) { // if we're the root just set it, nothing to swap - SwapEntriesData data = { this, newRootEntry }; + nsSHistory::SwapEntriesData data = { this, newRootEntry }; nsIDocShell* rootIDocShell = static_cast(rootShell); nsDocShell* rootDocShell = static_cast(rootIDocShell); #ifdef DEBUG nsresult rv = #endif - SetChildHistoryEntry(oldRootEntry, rootDocShell, 0, &data); + nsSHistory::SetChildHistoryEntry(oldRootEntry, rootDocShell, 0, &data); NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed"); } } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index d7eec477fea1..6f74bdf33340 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -357,6 +357,16 @@ public: return mOriginAttributes; } + // Determine whether this docshell corresponds to the given history entry, + // via having a pointer to it in mOSHE or mLSHE. + bool HasHistoryEntry(nsISHEntry* aEntry) const + { + return aEntry && (aEntry == mOSHE || aEntry == mLSHE); + } + + // Update any pointers (mOSHE or mLSHE) to aOldEntry to point to aNewEntry + void SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry); + static bool SandboxFlagsImplyCookies(const uint32_t &aSandboxFlags); // Tell the favicon service that aNewURI has the same favicon as aOldURI. @@ -392,47 +402,6 @@ private: // member functions friend void mozilla::TimelineConsumers::PopMarkers(nsDocShell*, JSContext*, nsTArray&); - // 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. - typedef nsresult(*WalkHistoryEntriesFunc)(nsISHEntry* aEntry, - nsDocShell* aShell, - int32_t aChildIndex, - void* aData); - - // Clone a session history tree for subframe navigation. - // The tree rooted at |aSrcEntry| will be cloned into |aDestEntry|, except - // for the entry with id |aCloneID|, which will be replaced with - // |aReplaceEntry|. |aSrcShell| is a (possibly null) docshell which - // corresponds to |aSrcEntry| via its mLSHE or mOHE pointers, and will - // 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); - - // Child-walking callback for CloneAndReplace - static nsresult CloneAndReplaceChild(nsISHEntry* aEntry, nsDocShell* aShell, - int32_t aChildIndex, void* aData); - - - // Child-walking callback for SetHistoryEntry - static nsresult SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell, - 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 - // is passed to the callback. - static nsresult WalkHistoryEntries(nsISHEntry* aRootEntry, - nsDocShell* aRootShell, - WalkHistoryEntriesFunc aCallback, - void* aData); - // Security checks to prevent frameset spoofing. See comments at // implementation sites. static bool CanAccessItem(nsIDocShellTreeItem* aTargetItem, @@ -528,16 +497,6 @@ private: // member functions int32_t aChildOffset, uint32_t aLoadType, bool aCloneChildren); - // Determine whether this docshell corresponds to the given history entry, - // via having a pointer to it in mOSHE or mLSHE. - bool HasHistoryEntry(nsISHEntry* aEntry) const - { - return aEntry && (aEntry == mOSHE || aEntry == mLSHE); - } - - // Update any pointers (mOSHE or mLSHE) to aOldEntry to point to aNewEntry - void SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry); - // Call this method to swap in a new history entry to m[OL]SHE, rather than // setting it directly. This completes the navigation in all docshells // in the case of a subframe navigation. diff --git a/docshell/shistory/nsSHistory.cpp b/docshell/shistory/nsSHistory.cpp index 70a349dcbf14..81a6c0249c31 100644 --- a/docshell/shistory/nsSHistory.cpp +++ b/docshell/shistory/nsSHistory.cpp @@ -377,6 +377,223 @@ nsSHistory::Shutdown() } } +// static +nsISHEntry* +nsSHistory::GetRootSHEntry(nsISHEntry* aEntry) +{ + nsCOMPtr rootEntry = aEntry; + nsISHEntry* result = nullptr; + while (rootEntry) { + result = rootEntry; + result->GetParent(getter_AddRefs(rootEntry)); + } + + return result; +} + +// static +nsresult +nsSHistory::WalkHistoryEntries(nsISHEntry* aRootEntry, + nsDocShell* aRootShell, + WalkHistoryEntriesFunc aCallback, + void* aData) +{ + NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE); + + nsCOMPtr container(do_QueryInterface(aRootEntry)); + if (!container) { + return NS_ERROR_FAILURE; + } + + int32_t childCount; + container->GetChildCount(&childCount); + for (int32_t i = 0; i < childCount; i++) { + nsCOMPtr childEntry; + container->GetChildAt(i, getter_AddRefs(childEntry)); + if (!childEntry) { + // childEntry can be null for valid reasons, for example if the + // docshell at index i never loaded anything useful. + // Remember to clone also nulls in the child array (bug 464064). + aCallback(nullptr, nullptr, i, aData); + 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->GetChildCount(&length); + for (int32_t i = 0; i < length; i++) { + nsCOMPtr item; + nsresult rv = aRootShell->GetChildAt(i, getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, rv); + nsDocShell* child = static_cast(item.get()); + if (child->HasHistoryEntry(childEntry)) { + childShell = child; + break; + } + } + } + nsresult rv = aCallback(childEntry, childShell, i, aData); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + +// callback data for WalkHistoryEntries +struct MOZ_STACK_CLASS CloneAndReplaceData +{ + CloneAndReplaceData(uint32_t aCloneID, nsISHEntry* aReplaceEntry, + bool aCloneChildren, nsISHEntry* aDestTreeParent) + : cloneID(aCloneID) + , cloneChildren(aCloneChildren) + , replaceEntry(aReplaceEntry) + , destTreeParent(aDestTreeParent) + { + } + + uint32_t cloneID; + bool cloneChildren; + nsISHEntry* replaceEntry; + nsISHEntry* destTreeParent; + nsCOMPtr resultEntry; +}; + +// static +nsresult +nsSHistory::CloneAndReplaceChild(nsISHEntry* aEntry, + nsDocShell* aShell, + int32_t aEntryIndex, + void* aData) +{ + nsCOMPtr dest; + + CloneAndReplaceData* data = static_cast(aData); + uint32_t cloneID = data->cloneID; + nsISHEntry* replaceEntry = data->replaceEntry; + + nsCOMPtr container = do_QueryInterface(data->destTreeParent); + if (!aEntry) { + if (container) { + container->AddChild(nullptr, aEntryIndex); + } + return NS_OK; + } + + uint32_t srcID; + aEntry->GetID(&srcID); + + nsresult rv = NS_OK; + if (srcID == cloneID) { + // Replace the entry + dest = replaceEntry; + } else { + // Clone the SHEntry... + rv = aEntry->Clone(getter_AddRefs(dest)); + NS_ENSURE_SUCCESS(rv, rv); + } + dest->SetIsSubFrame(true); + + if (srcID != cloneID || data->cloneChildren) { + // Walk the children + CloneAndReplaceData childData(cloneID, replaceEntry, + data->cloneChildren, dest); + rv = WalkHistoryEntries(aEntry, aShell, + CloneAndReplaceChild, &childData); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (srcID != cloneID && aShell) { + aShell->SwapHistoryEntries(aEntry, dest); + } + + if (container) { + container->AddChild(dest, aEntryIndex); + } + + 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); + NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE); + + CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr); + nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data); + + data.resultEntry.swap(*aResultEntry); + return rv; +} + +// static +nsresult +nsSHistory::SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell, + int32_t aEntryIndex, void* aData) +{ + SwapEntriesData* data = static_cast(aData); + nsDocShell* ignoreShell = data->ignoreShell; + + if (!aShell || aShell == ignoreShell) { + return NS_OK; + } + + nsISHEntry* destTreeRoot = data->destTreeRoot; + + nsCOMPtr destEntry; + nsCOMPtr container = do_QueryInterface(data->destTreeParent); + + if (container) { + // aEntry is a clone of some child of destTreeParent, but since the + // trees aren't necessarily in sync, we'll have to locate it. + // Note that we could set aShell's entry to null if we don't find a + // corresponding entry under destTreeParent. + + uint32_t targetID, id; + aEntry->GetID(&targetID); + + // First look at the given index, since this is the common case. + nsCOMPtr entry; + container->GetChildAt(aEntryIndex, getter_AddRefs(entry)); + if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) { + destEntry.swap(entry); + } else { + int32_t childCount; + container->GetChildCount(&childCount); + for (int32_t i = 0; i < childCount; ++i) { + container->GetChildAt(i, getter_AddRefs(entry)); + if (!entry) { + continue; + } + + entry->GetID(&id); + if (id == targetID) { + destEntry.swap(entry); + break; + } + } + } + } else { + destEntry = destTreeRoot; + } + + aShell->SwapHistoryEntries(aEntry, destEntry); + + // Now handle the children of aEntry. + SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry }; + return WalkHistoryEntries(aEntry, aShell, SetChildHistoryEntry, &childData); +} + /* Add an entry to the History list at mIndex and * increment the index to point to the new entry */ diff --git a/docshell/shistory/nsSHistory.h b/docshell/shistory/nsSHistory.h index 41d0186e771b..9839c5cd3d57 100644 --- a/docshell/shistory/nsSHistory.h +++ b/docshell/shistory/nsSHistory.h @@ -61,6 +61,15 @@ public: nsSHistory* mSHistory; }; + // Structure used in SetChildHistoryEntry + struct SwapEntriesData + { + nsDocShell* ignoreShell; // constant; the shell to ignore + nsISHEntry* destTreeRoot; // constant; the root of the dest tree + nsISHEntry* destTreeParent; // constant; the node under destTreeRoot + // whose children will correspond to aEntry + }; + nsSHistory(); NS_DECL_ISUPPORTS NS_DECL_NSISHISTORY @@ -78,6 +87,50 @@ public: // Otherwise, it comes straight from the pref. static uint32_t GetMaxTotalViewers() { return sHistoryMaxTotalViewers; } + // Get the root SHEntry from a given entry. + static 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. + typedef nsresult(*WalkHistoryEntriesFunc)(nsISHEntry* aEntry, + nsDocShell* aShell, + int32_t aChildIndex, + void* aData); + + // Clone a session history tree for subframe navigation. + // The tree rooted at |aSrcEntry| will be cloned into |aDestEntry|, except + // for the entry with id |aCloneID|, which will be replaced with + // |aReplaceEntry|. |aSrcShell| is a (possibly null) docshell which + // corresponds to |aSrcEntry| via its mLSHE or mOHE pointers, and will + // 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); + + // Child-walking callback for CloneAndReplace + static nsresult CloneAndReplaceChild(nsISHEntry* aEntry, nsDocShell* aShell, + int32_t aChildIndex, void* aData); + + + // Child-walking callback for SetHistoryEntry + static nsresult SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell, + 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 + // is passed to the callback. + static nsresult WalkHistoryEntries(nsISHEntry* aRootEntry, + nsDocShell* aRootShell, + WalkHistoryEntriesFunc aCallback, + void* aData); + private: virtual ~nsSHistory(); friend class nsSHEnumerator;