зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1406161 - Part 6: Move shistory related static functions to nsSHistory. r=smaug
MozReview-Commit-ID: 7rqo2rISCB5 --HG-- extra : rebase_source : 3de7a21b24ce526f45424a2f1aad4329a8758f78
This commit is contained in:
Родитель
3899149f41
Коммит
112d2693c3
|
@ -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<nsISHEntry> 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<nsISHistoryInternal> shPrivate =
|
||||
|
@ -11966,7 +11964,7 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
|
|||
internalSH->EvictOutOfRangeContentViewers(curIndex);
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsISHEntry> rootSHEntry = GetRootSHEntry(newSHEntry);
|
||||
nsCOMPtr<nsISHEntry> 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<nsISHEntry> 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<nsISHContainer> 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<nsISHEntry> 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<nsDocLoader*>::ForwardIterator iter(
|
||||
aRootShell->mChildList);
|
||||
while (iter.HasMore()) {
|
||||
nsDocShell* child = static_cast<nsDocShell*>(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<nsISHEntry> resultEntry;
|
||||
};
|
||||
|
||||
/* static */ nsresult
|
||||
nsDocShell::CloneAndReplaceChild(nsISHEntry* aEntry, nsDocShell* aShell,
|
||||
int32_t aEntryIndex, void* aData)
|
||||
{
|
||||
nsCOMPtr<nsISHEntry> dest;
|
||||
|
||||
CloneAndReplaceData* data = static_cast<CloneAndReplaceData*>(aData);
|
||||
uint32_t cloneID = data->cloneID;
|
||||
nsISHEntry* replaceEntry = data->replaceEntry;
|
||||
|
||||
nsCOMPtr<nsISHContainer> 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<SwapEntriesData*>(aData);
|
||||
nsDocShell* ignoreShell = data->ignoreShell;
|
||||
|
||||
if (!aShell || aShell == ignoreShell) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsISHEntry* destTreeRoot = data->destTreeRoot;
|
||||
|
||||
nsCOMPtr<nsISHEntry> destEntry;
|
||||
nsCOMPtr<nsISHContainer> 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<nsISHEntry> 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<nsISHEntry> rootEntry = aEntry;
|
||||
nsISHEntry* result = nullptr;
|
||||
while (rootEntry) {
|
||||
result = rootEntry;
|
||||
result->GetParent(getter_AddRefs(rootEntry));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr, nsISHEntry* aEntry)
|
||||
{
|
||||
|
@ -12750,27 +12532,27 @@ nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* 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<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr);
|
||||
nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(*aPtr);
|
||||
if (oldRootEntry) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
|
||||
GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
|
||||
nsCOMPtr<nsIDocShell> 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<nsIDocShell*>(rootShell);
|
||||
nsDocShell* rootDocShell = static_cast<nsDocShell*>(rootIDocShell);
|
||||
|
||||
#ifdef DEBUG
|
||||
nsresult rv =
|
||||
#endif
|
||||
SetChildHistoryEntry(oldRootEntry, rootDocShell, 0, &data);
|
||||
nsSHistory::SetChildHistoryEntry(oldRootEntry, rootDocShell, 0, &data);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<dom::ProfileTimelineMarker>&);
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -377,6 +377,223 @@ nsSHistory::Shutdown()
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
nsISHEntry*
|
||||
nsSHistory::GetRootSHEntry(nsISHEntry* aEntry)
|
||||
{
|
||||
nsCOMPtr<nsISHEntry> 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<nsISHContainer> 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<nsISHEntry> 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<nsIDocShellTreeItem> item;
|
||||
nsresult rv = aRootShell->GetChildAt(i, getter_AddRefs(item));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsDocShell* child = static_cast<nsDocShell*>(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<nsISHEntry> resultEntry;
|
||||
};
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsSHistory::CloneAndReplaceChild(nsISHEntry* aEntry,
|
||||
nsDocShell* aShell,
|
||||
int32_t aEntryIndex,
|
||||
void* aData)
|
||||
{
|
||||
nsCOMPtr<nsISHEntry> dest;
|
||||
|
||||
CloneAndReplaceData* data = static_cast<CloneAndReplaceData*>(aData);
|
||||
uint32_t cloneID = data->cloneID;
|
||||
nsISHEntry* replaceEntry = data->replaceEntry;
|
||||
|
||||
nsCOMPtr<nsISHContainer> 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<SwapEntriesData*>(aData);
|
||||
nsDocShell* ignoreShell = data->ignoreShell;
|
||||
|
||||
if (!aShell || aShell == ignoreShell) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsISHEntry* destTreeRoot = data->destTreeRoot;
|
||||
|
||||
nsCOMPtr<nsISHEntry> destEntry;
|
||||
nsCOMPtr<nsISHContainer> 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<nsISHEntry> 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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче