Bug 1658341 - Copy nsSHentry::AddChild/RemoveChild/ReplaceChild to SessionHistoryEntry. r=smaug

This copies the code as is, so won't compile. The next patch changes the implementation so it compiles.

Differential Revision: https://phabricator.services.mozilla.com/D86573
This commit is contained in:
Peter Van der Beken 2020-08-13 08:48:45 +00:00
parent d7c6b2974f
commit a35af34bfa

View File

@ -686,14 +686,132 @@ SessionHistoryEntry::SetLoadTypeAsHistory() {
NS_IMETHODIMP
SessionHistoryEntry::AddChild(nsISHEntry* aChild, int32_t aOffset,
bool aUseRemoteSubframes) {
MOZ_CRASH("Need to implement this");
return NS_ERROR_NOT_IMPLEMENTED;
if (aChild) {
NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
}
if (aOffset < 0) {
mChildren.AppendObject(aChild);
return NS_OK;
}
//
// Bug 52670: Ensure children are added in order.
//
// Later frames in the child list may load faster and get appended
// before earlier frames, causing session history to be scrambled.
// By growing the list here, they are added to the right position.
//
// Assert that aOffset will not be so high as to grow us a lot.
//
NS_ASSERTION(aOffset < (mChildren.Count() + 1023), "Large frames array!\n");
bool newChildIsDyn = aChild ? aChild->IsDynamicallyAdded() : false;
// If the new child is dynamically added, try to add it to aOffset, but if
// there are non-dynamically added children, the child must be after those.
if (newChildIsDyn) {
int32_t lastNonDyn = aOffset - 1;
for (int32_t i = aOffset; i < mChildren.Count(); ++i) {
nsISHEntry* entry = mChildren[i];
if (entry) {
if (entry->IsDynamicallyAdded()) {
break;
} else {
lastNonDyn = i;
}
}
}
// InsertObjectAt allows only appending one object.
// If aOffset is larger than Count(), we must first manually
// set the capacity.
if (aOffset > mChildren.Count()) {
mChildren.SetCount(aOffset);
}
if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) {
NS_WARNING("Adding a child failed!");
aChild->SetParent(nullptr);
return NS_ERROR_FAILURE;
}
} else {
// If the new child isn't dynamically added, it should be set to aOffset.
// If there are dynamically added children before that, those must be
// moved to be after aOffset.
if (mChildren.Count() > 0) {
int32_t start = std::min(mChildren.Count() - 1, aOffset);
int32_t dynEntryIndex = -1;
nsISHEntry* dynEntry = nullptr;
for (int32_t i = start; i >= 0; --i) {
nsISHEntry* entry = mChildren[i];
if (entry) {
if (entry->IsDynamicallyAdded()) {
dynEntryIndex = i;
dynEntry = entry;
} else {
break;
}
}
}
if (dynEntry) {
nsCOMArray<nsISHEntry> tmp;
tmp.SetCount(aOffset - dynEntryIndex + 1);
mChildren.InsertObjectsAt(tmp, dynEntryIndex);
NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?");
}
}
// Make sure there isn't anything at aOffset.
if (aOffset < mChildren.Count()) {
nsISHEntry* oldChild = mChildren[aOffset];
if (oldChild && oldChild != aChild) {
// Under Fission, this can happen when a network-created iframe starts
// out in-process, moves out-of-process, and then switches back. At that
// point, we'll create a new network-created DocShell at the same index
// where we already have an entry for the original network-created
// DocShell.
//
// This should ideally stop being an issue once the Fission-aware
// session history rewrite is complete.
NS_ASSERTION(
aUseRemoteSubframes,
"Adding a child where we already have a child? This may misbehave");
oldChild->SetParent(nullptr);
}
}
mChildren.ReplaceObjectAt(aChild, aOffset);
}
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::RemoveChild(nsISHEntry* aChild) {
MOZ_CRASH("Need to implement this");
return NS_ERROR_NOT_IMPLEMENTED;
NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
bool childRemoved = false;
if (aChild->IsDynamicallyAdded()) {
childRemoved = mChildren.RemoveObject(aChild);
} else {
int32_t index = mChildren.IndexOfObject(aChild);
if (index >= 0) {
// Other alive non-dynamic child docshells still keep mChildOffset,
// so we don't want to change the indices here.
mChildren.ReplaceObjectAt(nullptr, index);
childRemoved = true;
}
}
if (childRemoved) {
aChild->SetParent(nullptr);
// reduce the child count, i.e. remove empty children at the end
for (int32_t i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) {
if (!mChildren.RemoveObjectAt(i)) {
break;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
@ -711,8 +829,24 @@ SessionHistoryEntry::GetChildSHEntryIfHasNoDynamicallyAddedChild(
NS_IMETHODIMP
SessionHistoryEntry::ReplaceChild(nsISHEntry* aNewChild) {
MOZ_CRASH("Need to implement this");
return NS_ERROR_NOT_IMPLEMENTED;
NS_ENSURE_STATE(aNewEntry);
nsID docshellID;
aNewEntry->GetDocshellID(docshellID);
for (int32_t i = 0; i < mChildren.Count(); ++i) {
if (mChildren[i]) {
nsID childDocshellID;
nsresult rv = mChildren[i]->GetDocshellID(childDocshellID);
NS_ENSURE_SUCCESS(rv, rv);
if (docshellID == childDocshellID) {
mChildren[i]->SetParent(nullptr);
mChildren.ReplaceObjectAt(aNewEntry, i);
return aNewEntry->SetParent(this);
}
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP_(void)