зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1602115
, make it possible to test async history.length handling even when session history lives in the child process, r=peterv
Differential Revision: https://phabricator.services.mozilla.com/D79198
This commit is contained in:
Родитель
c142af0f58
Коммит
e702898d75
|
@ -2502,6 +2502,35 @@ bool BrowsingContext::CanSet(FieldIndex<IDX_BrowserId>, const uint32_t& aValue,
|
|||
return GetBrowserId() == 0 && IsTop() && Children().IsEmpty();
|
||||
}
|
||||
|
||||
void BrowsingContext::SessionHistoryChanged(int32_t aIndexDelta,
|
||||
int32_t aLengthDelta) {
|
||||
if (XRE_IsParentProcess() || StaticPrefs::fission_sessionHistoryInParent()) {
|
||||
// This method is used to test index and length for the session history
|
||||
// in child process only.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsTop()) {
|
||||
// Some tests have unexpected setup while Fission shistory is being
|
||||
// implemented.
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ChildSHistory> shistory = GetChildSessionHistory();
|
||||
if (!shistory || !shistory->AsyncHistoryLength()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsID changeID = shistory->AddPendingHistoryChange(aIndexDelta, aLengthDelta);
|
||||
uint32_t index = shistory->Index();
|
||||
uint32_t length = shistory->Count();
|
||||
|
||||
// Do artificial history update through parent process to test asynchronous
|
||||
// history.length handling.
|
||||
ContentChild::GetSingleton()->SendSessionHistoryUpdate(this, index, length,
|
||||
changeID);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
namespace ipc {
|
||||
|
|
|
@ -657,6 +657,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
|
||||
bool CrossOriginIsolated();
|
||||
|
||||
void SessionHistoryChanged(int32_t aIndexDelta, int32_t aLengthDelta);
|
||||
|
||||
protected:
|
||||
virtual ~BrowsingContext();
|
||||
BrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup,
|
||||
|
|
|
@ -36,22 +36,38 @@ void ChildSHistory::SetIsInProcess(bool aIsInProcess) {
|
|||
}
|
||||
|
||||
int32_t ChildSHistory::Count() {
|
||||
if (StaticPrefs::fission_sessionHistoryInParent()) {
|
||||
if (StaticPrefs::fission_sessionHistoryInParent() || mAsyncHistoryLength) {
|
||||
uint32_t length = mLength;
|
||||
for (uint32_t i = 0; i < mPendingSHistoryChanges.Length(); ++i) {
|
||||
length += mPendingSHistoryChanges[i].mLengthDelta;
|
||||
}
|
||||
|
||||
if (mAsyncHistoryLength) {
|
||||
MOZ_ASSERT(!StaticPrefs::fission_sessionHistoryInParent());
|
||||
// XXX The assertion may be too strong here, but it fires only
|
||||
// when the pref is enabled.
|
||||
MOZ_ASSERT(mHistory->GetCount() == int32_t(length));
|
||||
}
|
||||
return length;
|
||||
}
|
||||
return mHistory->GetCount();
|
||||
}
|
||||
|
||||
int32_t ChildSHistory::Index() {
|
||||
if (StaticPrefs::fission_sessionHistoryInParent()) {
|
||||
if (StaticPrefs::fission_sessionHistoryInParent() || mAsyncHistoryLength) {
|
||||
uint32_t index = mIndex;
|
||||
for (uint32_t i = 0; i < mPendingSHistoryChanges.Length(); ++i) {
|
||||
index += mPendingSHistoryChanges[i].mIndexDelta;
|
||||
}
|
||||
|
||||
if (mAsyncHistoryLength) {
|
||||
MOZ_ASSERT(!StaticPrefs::fission_sessionHistoryInParent());
|
||||
int32_t realIndex;
|
||||
mHistory->GetIndex(&realIndex);
|
||||
// XXX The assertion may be too strong here, but it fires only
|
||||
// when the pref is enabled.
|
||||
MOZ_ASSERT(realIndex == int32_t(index));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
int32_t index;
|
||||
|
@ -60,11 +76,16 @@ int32_t ChildSHistory::Index() {
|
|||
}
|
||||
|
||||
nsID ChildSHistory::AddPendingHistoryChange() {
|
||||
int32_t indexOffset = 1;
|
||||
int32_t lengthOffset = (Index() + indexOffset) - (Count() - 1);
|
||||
int32_t indexDelta = 1;
|
||||
int32_t lengthDelta = (Index() + indexDelta) - (Count() - 1);
|
||||
return AddPendingHistoryChange(indexDelta, lengthDelta);
|
||||
}
|
||||
|
||||
nsID ChildSHistory::AddPendingHistoryChange(int32_t aIndexDelta,
|
||||
int32_t aLengthDelta) {
|
||||
nsID changeID = {};
|
||||
nsContentUtils::GenerateUUIDInPlace(changeID);
|
||||
PendingSHistoryChange change = {changeID, indexOffset, lengthOffset};
|
||||
PendingSHistoryChange change = {changeID, aIndexDelta, aLengthDelta};
|
||||
mPendingSHistoryChanges.AppendElement(change);
|
||||
return changeID;
|
||||
}
|
||||
|
@ -179,5 +200,26 @@ nsISupports* ChildSHistory::GetParentObject() const {
|
|||
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
||||
}
|
||||
|
||||
void ChildSHistory::SetAsyncHistoryLength(bool aEnable, ErrorResult& aRv) {
|
||||
if (StaticPrefs::fission_sessionHistoryInParent() || !mHistory) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAsyncHistoryLength == aEnable) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAsyncHistoryLength = aEnable;
|
||||
if (mAsyncHistoryLength) {
|
||||
mHistory->GetIndex(&mIndex);
|
||||
mLength = mHistory->GetCount();
|
||||
} else {
|
||||
mIndex = -1;
|
||||
mLength = 0;
|
||||
mPendingSHistoryChanges.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -79,6 +79,11 @@ class ChildSHistory : public nsISupports, public nsWrapperCache {
|
|||
void SetIndexAndLength(uint32_t aIndex, uint32_t aLength,
|
||||
const nsID& aChangeId);
|
||||
nsID AddPendingHistoryChange();
|
||||
nsID AddPendingHistoryChange(int32_t aIndexDelta, int32_t aLengthDelta);
|
||||
|
||||
// AsyncHistoryLength is for testing.
|
||||
void SetAsyncHistoryLength(bool aEnable, ErrorResult& aRv);
|
||||
bool AsyncHistoryLength() { return mAsyncHistoryLength; }
|
||||
|
||||
private:
|
||||
virtual ~ChildSHistory() = default;
|
||||
|
@ -120,6 +125,8 @@ class ChildSHistory : public nsISupports, public nsWrapperCache {
|
|||
int32_t mLengthDelta;
|
||||
};
|
||||
AutoTArray<PendingSHistoryChange, 2> mPendingSHistoryChanges;
|
||||
|
||||
bool mAsyncHistoryLength = false;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -135,6 +135,36 @@ extern mozilla::LazyLogModule gPageCacheLog;
|
|||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
class SHistoryChangeNotifier {
|
||||
public:
|
||||
explicit SHistoryChangeNotifier(nsSHistory* aHistory) {
|
||||
// If we're already in an update, the outermost change notifier will
|
||||
// update browsing context in the destructor.
|
||||
if (!aHistory->HasOngoingUpdate()) {
|
||||
aHistory->SetHasOngoingUpdate(true);
|
||||
mSHistory = aHistory;
|
||||
mInitialIndex = aHistory->Index();
|
||||
mInitialLength = aHistory->Length();
|
||||
}
|
||||
}
|
||||
|
||||
~SHistoryChangeNotifier() {
|
||||
if (mSHistory) {
|
||||
MOZ_ASSERT(mSHistory->HasOngoingUpdate());
|
||||
mSHistory->SetHasOngoingUpdate(false);
|
||||
if (mSHistory->GetBrowsingContext()) {
|
||||
mSHistory->GetBrowsingContext()->SessionHistoryChanged(
|
||||
mSHistory->Index() - mInitialIndex,
|
||||
mSHistory->Length() - mInitialLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<nsSHistory> mSHistory;
|
||||
int32_t mInitialIndex;
|
||||
int32_t mInitialLength;
|
||||
};
|
||||
|
||||
enum HistCmd { HIST_CMD_GOTOINDEX, HIST_CMD_RELOAD };
|
||||
|
||||
class nsSHistoryObserver final : public nsIObserver {
|
||||
|
@ -202,6 +232,7 @@ void nsSHistory::EvictContentViewerForEntry(nsISHEntry* aEntry) {
|
|||
|
||||
nsSHistory::nsSHistory(BrowsingContext* aRootBC)
|
||||
: mRootBC(aRootBC),
|
||||
mHasOngoingUpdate(false),
|
||||
mIsRemote(false),
|
||||
mIndex(-1),
|
||||
mRequestedIndex(-1),
|
||||
|
@ -685,6 +716,8 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist) {
|
|||
}
|
||||
}
|
||||
|
||||
SHistoryChangeNotifier change(this);
|
||||
|
||||
nsCOMPtr<nsIURI> uri = aSHEntry->GetURI();
|
||||
NOTIFY_LISTENERS(OnHistoryNewEntry, (uri, mIndex));
|
||||
|
||||
|
@ -807,6 +840,8 @@ nsSHistory::PurgeHistory(int32_t aNumEntries) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
SHistoryChangeNotifier change(this);
|
||||
|
||||
aNumEntries = std::min(aNumEntries, Length());
|
||||
|
||||
NOTIFY_LISTENERS(OnHistoryPurge, ());
|
||||
|
@ -1372,6 +1407,8 @@ bool nsSHistory::RemoveDuplicate(int32_t aIndex, bool aKeepNext) {
|
|||
return false;
|
||||
}
|
||||
|
||||
SHistoryChangeNotifier change(this);
|
||||
|
||||
if (IsSameTree(root1, root2)) {
|
||||
mEntries.RemoveElementAt(aIndex);
|
||||
|
||||
|
@ -1417,6 +1454,8 @@ nsSHistory::RemoveEntries(nsTArray<nsID>& aIDs, int32_t aStartIndex) {
|
|||
|
||||
void nsSHistory::RemoveEntries(nsTArray<nsID>& aIDs, int32_t aStartIndex,
|
||||
bool* aDidRemove) {
|
||||
SHistoryChangeNotifier change(this);
|
||||
|
||||
int32_t index = aStartIndex;
|
||||
while (index >= 0 && RemoveChildEntries(this, --index, aIDs)) {
|
||||
}
|
||||
|
@ -1475,6 +1514,8 @@ void nsSHistory::RemoveDynEntriesForBFCacheEntry(nsIBFCacheEntry* aBFEntry) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsSHistory::UpdateIndex() {
|
||||
SHistoryChangeNotifier change(this);
|
||||
|
||||
// Update the actual index with the right value.
|
||||
if (mIndex != mRequestedIndex && mRequestedIndex != -1) {
|
||||
mIndex = mRequestedIndex;
|
||||
|
|
|
@ -162,6 +162,12 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
|
|||
int32_t* aOutEndIndex);
|
||||
void NotifyListenersContentViewerEvicted(uint32_t aNumEvicted);
|
||||
|
||||
int32_t Length() { return int32_t(mEntries.Length()); }
|
||||
int32_t Index() { return mIndex; }
|
||||
mozilla::dom::BrowsingContext* GetBrowsingContext() { return mRootBC; }
|
||||
bool HasOngoingUpdate() { return mHasOngoingUpdate; }
|
||||
void SetHasOngoingUpdate(bool aVal) { mHasOngoingUpdate = aVal; }
|
||||
|
||||
protected:
|
||||
virtual ~nsSHistory();
|
||||
|
||||
|
@ -225,9 +231,8 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
|
|||
nsISHEntry* aNewEntry);
|
||||
|
||||
protected:
|
||||
// Length of mEntries.
|
||||
int32_t Length() { return int32_t(mEntries.Length()); }
|
||||
|
||||
bool mHasOngoingUpdate;
|
||||
bool mIsRemote;
|
||||
nsTArray<nsCOMPtr<nsISHEntry>> mEntries; // entries are never null
|
||||
private:
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
<head>
|
||||
<script>
|
||||
function loadNextPage() {
|
||||
if (location.search.includes("testAsyncLength=true")) {
|
||||
var shell = SpecialPowers.wrap(window).docShell;
|
||||
var shistory = SpecialPowers.do_QueryInterface(shell, "nsIWebNavigation").sessionHistory;
|
||||
shistory.asyncHistoryLength = true;
|
||||
}
|
||||
opener.postMessage({ initialLength: history.length}, "*");
|
||||
location.href = 'file_history_length_during_pageload_2.html';
|
||||
}
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
function done() {
|
||||
// Ensure history.length doesn't change after load event has fired.
|
||||
opener.postMessage({ length: history.length}, "*");
|
||||
|
||||
var shell = SpecialPowers.wrap(window).docShell;
|
||||
var shistory = SpecialPowers.do_QueryInterface(shell, "nsIWebNavigation").sessionHistory;
|
||||
if (shistory.asyncHistoryLength) {
|
||||
shistory.asyncHistoryLength = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
function runTest(testAsyncLength) {
|
||||
return new Promise(function(resolve) {
|
||||
var initialLength;
|
||||
var messageCount = 0;
|
||||
|
@ -25,15 +25,15 @@
|
|||
resolve();
|
||||
}
|
||||
}
|
||||
win = window.open("file_history_length_during_pageload.html");
|
||||
win = window.open("file_history_length_during_pageload.html?testAsyncLength=" + testAsyncLength);
|
||||
});
|
||||
}
|
||||
|
||||
async function runTests() {
|
||||
await SpecialPowers.pushPrefEnv({set: [["fission.sessionHistoryInParent", false]]});
|
||||
await runTest();
|
||||
await runTest(true);
|
||||
await SpecialPowers.pushPrefEnv({set: [["fission.sessionHistoryInParent", true]]});
|
||||
await runTest();
|
||||
await runTest(false);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -6830,6 +6830,24 @@ mozilla::ipc::IPCResult ContentParent::RecvHistoryGo(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryUpdate(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aIndex,
|
||||
const int32_t& aLength, const nsID& aChangeID) {
|
||||
if (aContext.IsNullOrDiscarded()) {
|
||||
MOZ_LOG(
|
||||
BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
CanonicalBrowsingContext* context = aContext.get_canonical();
|
||||
context->Group()->EachParent([&](ContentParent* aParent) {
|
||||
Unused << aParent->SendHistoryCommitIndexAndLength(aContext, aIndex,
|
||||
aLength, aChangeID);
|
||||
});
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvCommitWindowContextTransaction(
|
||||
const MaybeDiscarded<WindowContext>& aContext,
|
||||
WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
|
||||
|
|
|
@ -1315,6 +1315,10 @@ class ContentParent final
|
|||
const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset,
|
||||
HistoryGoResolver&& aResolveRequestedIndex);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSessionHistoryUpdate(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aIndex,
|
||||
const int32_t& aLength, const nsID& aChangeID);
|
||||
|
||||
// Notify the ContentChild to enable the input event prioritization when
|
||||
// initializing.
|
||||
void MaybeEnableRemoteInputEventQueue();
|
||||
|
|
|
@ -913,6 +913,13 @@ child:
|
|||
uint32_t aIndex, uint32_t aLength,
|
||||
nsID aChangeID);
|
||||
parent:
|
||||
/**
|
||||
* This is a temporary way to pass index and length through parent process.
|
||||
* Used for testing.
|
||||
*/
|
||||
async SessionHistoryUpdate(MaybeDiscardedBrowsingContext aTopContext,
|
||||
int32_t aIndex, int32_t aLength, nsID aChangeID);
|
||||
|
||||
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
|
||||
|
||||
async CreateGMPService();
|
||||
|
|
|
@ -36,4 +36,12 @@ interface ChildSHistory {
|
|||
* process on ChildSHistory.
|
||||
*/
|
||||
readonly attribute nsISHistory legacySHistory;
|
||||
|
||||
/**
|
||||
* asyncHistoryLength can be enabled to test Fission-like asynchronous
|
||||
* history.length handling with non-Fission session history implementation.
|
||||
* Throws if session history is running in the parent process.
|
||||
*/
|
||||
[SetterThrows]
|
||||
attribute boolean asyncHistoryLength;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче