mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1515073 - Part 2 - Allow nsIWebNavigation::{goBack,goForward} to skip entries without user interaction. r=Gijs,peterv
Depends on D27585 Differential Revision: https://phabricator.services.mozilla.com/D27586
This commit is contained in:
parent
2121e27531
commit
2133bb8e2c
@ -3076,7 +3076,7 @@ nsDocShell::GetCanGoForward(bool* aCanGoForward) {
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GoBack() {
|
||||
nsDocShell::GoBack(bool aRequireUserInteraction) {
|
||||
if (!IsNavigationAllowed()) {
|
||||
return NS_OK; // JS may not handle returning of an error code
|
||||
}
|
||||
@ -3087,12 +3087,12 @@ nsDocShell::GoBack() {
|
||||
RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
|
||||
NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE);
|
||||
ErrorResult rv;
|
||||
rootSH->Go(-1, rv);
|
||||
rootSH->Go(-1, aRequireUserInteraction, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GoForward() {
|
||||
nsDocShell::GoForward(bool aRequireUserInteraction) {
|
||||
if (!IsNavigationAllowed()) {
|
||||
return NS_OK; // JS may not handle returning of an error code
|
||||
}
|
||||
@ -3103,7 +3103,7 @@ nsDocShell::GoForward() {
|
||||
RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
|
||||
NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE);
|
||||
ErrorResult rv;
|
||||
rootSH->Go(1, rv);
|
||||
rootSH->Go(1, aRequireUserInteraction, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
|
@ -50,11 +50,19 @@ interface nsIWebNavigation : nsISupports
|
||||
* (if available) and page state (such as form values and scroll position) is
|
||||
* restored.
|
||||
*
|
||||
* @param {boolean} aRequireUserInteraction
|
||||
* Tells goBack to skip history items that did not record any user
|
||||
* interaction on their corresponding document while they were active.
|
||||
* This means in case of multiple entries mapping to the same document,
|
||||
* each entry has to have been flagged with user interaction separately.
|
||||
* If no items have user interaction, the function will fall back
|
||||
* to the first session history entry.
|
||||
*
|
||||
* @throw NS_ERROR_UNEXPECTED
|
||||
* Indicates that the call was unexpected at this time, which implies
|
||||
* that canGoBack is false.
|
||||
*/
|
||||
void goBack();
|
||||
void goBack([optional] in boolean aRequireUserInteraction);
|
||||
|
||||
/**
|
||||
* Tells the object to navigate to the next session history item. When a
|
||||
@ -62,11 +70,19 @@ interface nsIWebNavigation : nsISupports
|
||||
* (if available) and page state (such as form values and scroll position) is
|
||||
* restored.
|
||||
*
|
||||
* @param {boolean} aRequireUserInteraction
|
||||
* Tells goForward to skip history items that did not record any user
|
||||
* interaction on their corresponding document while they were active.
|
||||
* This means in case of multiple entries mapping to the same document,
|
||||
* each entry has to have been flagged with user interaction separately.
|
||||
* If no items have user interaction, the function will fall back
|
||||
* to the latest session history entry.
|
||||
*
|
||||
* @throw NS_ERROR_UNEXPECTED
|
||||
* Indicates that the call was unexpected at this time, which implies
|
||||
* that canGoForward is false.
|
||||
*/
|
||||
void goForward();
|
||||
void goForward([optional] in boolean aRequireUserInteraction);
|
||||
|
||||
/**
|
||||
* Tells the object to navigate to the session history item at a given index.
|
||||
|
@ -61,13 +61,35 @@ bool ChildSHistory::CanGo(int32_t aOffset) {
|
||||
return index.value() < Count() && index.value() >= 0;
|
||||
}
|
||||
|
||||
void ChildSHistory::Go(int32_t aOffset, ErrorResult& aRv) {
|
||||
CheckedInt<int32_t> index = Index();
|
||||
index += aOffset;
|
||||
if (!index.isValid()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
void ChildSHistory::Go(int32_t aOffset, bool aRequireUserInteraction,
|
||||
ErrorResult& aRv) {
|
||||
if (aRequireUserInteraction && aOffset != -1 && aOffset != 1) {
|
||||
NS_ERROR(
|
||||
"aRequireUserInteraction may only be used with an offset of -1 or 1");
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
}
|
||||
|
||||
CheckedInt<int32_t> index = Index();
|
||||
while (true) {
|
||||
index += aOffset;
|
||||
if (!index.isValid()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for user interaction if desired, except for the first and last
|
||||
// history entries. We compare with >= to account for the case where
|
||||
// aOffset >= Count().
|
||||
if (!aRequireUserInteraction || index.value() >= Count() - 1 ||
|
||||
index.value() <= 0) {
|
||||
break;
|
||||
}
|
||||
if (mHistory->HasUserInteractionAtIndex(index.value())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (StaticPrefs::fission_sessionHistoryInParent()) {
|
||||
nsCOMPtr<nsISHistory> shistory = mHistory;
|
||||
ContentChild::GetSingleton()->SendHistoryGo(
|
||||
@ -83,13 +105,13 @@ void ChildSHistory::Go(int32_t aOffset, ErrorResult& aRv) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChildSHistory::AsyncGo(int32_t aOffset) {
|
||||
void ChildSHistory::AsyncGo(int32_t aOffset, bool aRequireUserInteraction) {
|
||||
if (!CanGo(aOffset)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<PendingAsyncHistoryNavigation> asyncNav =
|
||||
new PendingAsyncHistoryNavigation(this, aOffset);
|
||||
new PendingAsyncHistoryNavigation(this, aOffset, aRequireUserInteraction);
|
||||
mPendingNavigations.insertBack(asyncNav);
|
||||
NS_DispatchToCurrentThread(asyncNav.forget());
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ class ChildSHistory : public nsISupports, public nsWrapperCache {
|
||||
* backwards.
|
||||
*/
|
||||
bool CanGo(int32_t aOffset);
|
||||
void Go(int32_t aOffset, ErrorResult& aRv);
|
||||
void AsyncGo(int32_t aOffset);
|
||||
void Go(int32_t aOffset, bool aRequireUserInteraction, ErrorResult& aRv);
|
||||
void AsyncGo(int32_t aOffset, bool aRequireUserInteraction);
|
||||
|
||||
void RemovePendingHistoryNavigations();
|
||||
|
||||
@ -84,21 +84,24 @@ class ChildSHistory : public nsISupports, public nsWrapperCache {
|
||||
: public Runnable,
|
||||
public mozilla::LinkedListElement<PendingAsyncHistoryNavigation> {
|
||||
public:
|
||||
PendingAsyncHistoryNavigation(ChildSHistory* aHistory, int32_t aOffset)
|
||||
PendingAsyncHistoryNavigation(ChildSHistory* aHistory, int32_t aOffset,
|
||||
bool aRequireUserInteraction)
|
||||
: Runnable("PendingAsyncHistoryNavigation"),
|
||||
mHistory(aHistory),
|
||||
mRequireUserInteraction(aRequireUserInteraction),
|
||||
mOffset(aOffset) {}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
if (isInList()) {
|
||||
remove();
|
||||
mHistory->Go(mOffset, IgnoreErrors());
|
||||
mHistory->Go(mOffset, mRequireUserInteraction, IgnoreErrors());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<ChildSHistory> mHistory;
|
||||
bool mRequireUserInteraction;
|
||||
int32_t mOffset;
|
||||
};
|
||||
|
||||
|
@ -126,6 +126,13 @@ interface nsISHistory: nsISupports
|
||||
[noscript]
|
||||
void gotoIndex(in long aIndex);
|
||||
|
||||
/**
|
||||
* If an element exists at the particular index and
|
||||
* whether it has user interaction.
|
||||
*/
|
||||
[noscript,notxpcom]
|
||||
boolean hasUserInteractionAtIndex(in long aIndex);
|
||||
|
||||
/**
|
||||
* Called to obtain the index to a given history entry.
|
||||
*
|
||||
|
@ -1505,6 +1505,16 @@ nsresult nsSHistory::GotoIndex(int32_t aIndex,
|
||||
return LoadEntry(aIndex, LOAD_HISTORY, HIST_CMD_GOTOINDEX, aLoadResults);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
nsSHistory::HasUserInteractionAtIndex(int32_t aIndex) {
|
||||
nsCOMPtr<nsISHEntry> entry;
|
||||
GetEntryAtIndex(aIndex, getter_AddRefs(entry));
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
return entry->GetHasUserInteraction();
|
||||
}
|
||||
|
||||
nsresult nsSHistory::LoadNextPossibleEntry(
|
||||
int32_t aNewIndex, long aLoadType, uint32_t aHistCmd,
|
||||
nsTArray<LoadEntryResult>& aLoadResults) {
|
||||
|
@ -158,9 +158,9 @@ void nsHistory::Go(int32_t aDelta, ErrorResult& aRv) {
|
||||
// Ignore the return value from Go(), since returning errors from Go() can
|
||||
// lead to exceptions and a possible leak of history length
|
||||
if (StaticPrefs::dom_window_history_async()) {
|
||||
session_history->AsyncGo(aDelta);
|
||||
session_history->AsyncGo(aDelta, /* aRequireUserInteraction = */ false);
|
||||
} else {
|
||||
session_history->Go(aDelta, IgnoreErrors());
|
||||
session_history->Go(aDelta, /* aRequireUserInteraction = */ false, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,9 +180,9 @@ void nsHistory::Back(ErrorResult& aRv) {
|
||||
}
|
||||
|
||||
if (StaticPrefs::dom_window_history_async()) {
|
||||
sHistory->AsyncGo(-1);
|
||||
sHistory->AsyncGo(-1, /* aRequireUserInteraction = */ false);
|
||||
} else {
|
||||
sHistory->Go(-1, IgnoreErrors());
|
||||
sHistory->Go(-1, /* aRequireUserInteraction = */ false, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,9 +202,9 @@ void nsHistory::Forward(ErrorResult& aRv) {
|
||||
}
|
||||
|
||||
if (StaticPrefs::dom_window_history_async()) {
|
||||
sHistory->AsyncGo(1);
|
||||
sHistory->AsyncGo(1, /* aRequireUserInteraction = */ false);
|
||||
} else {
|
||||
sHistory->Go(1, IgnoreErrors());
|
||||
sHistory->Go(1, /* aRequireUserInteraction = */ false, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2228,10 +2228,12 @@ void EventStateManager::DoScrollHistory(int32_t direction) {
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
|
||||
if (webNav) {
|
||||
// positive direction to go back one step, nonpositive to go forward
|
||||
// This is doing user-initiated history traversal, hence we want
|
||||
// to require that history entries we navigate to have user interaction.
|
||||
if (direction > 0)
|
||||
webNav->GoBack();
|
||||
webNav->GoBack(/* aRequireUserInteraction = */ true);
|
||||
else
|
||||
webNav->GoForward();
|
||||
webNav->GoForward(/* aRequireUserInteraction = */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,7 @@ interface ChildSHistory {
|
||||
readonly attribute long index;
|
||||
|
||||
boolean canGo(long aOffset);
|
||||
[Throws]
|
||||
void go(long aOffset);
|
||||
[Throws] void go(long aOffset, optional boolean aRequireUserInteraction = false);
|
||||
|
||||
/**
|
||||
* Reload the current entry. The flags which should be passed to this
|
||||
|
@ -46,7 +46,7 @@ class WebNavigationChild extends JSWindowActorChild {
|
||||
let wn = this.webNavigation;
|
||||
if (wn.canGoBack) {
|
||||
this.docShell.setCancelContentJSEpoch(params.cancelContentJSEpoch);
|
||||
this._wrapURIChangeCall(() => wn.goBack());
|
||||
this._wrapURIChangeCall(() => wn.goBack(params.requireUserInteraction));
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +54,9 @@ class WebNavigationChild extends JSWindowActorChild {
|
||||
let wn = this.webNavigation;
|
||||
if (wn.canGoForward) {
|
||||
this.docShell.setCancelContentJSEpoch(params.cancelContentJSEpoch);
|
||||
this._wrapURIChangeCall(() => wn.goForward());
|
||||
this._wrapURIChangeCall(() =>
|
||||
wn.goForward(params.requireUserInteraction)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,17 +465,17 @@ nsWebBrowser::GetCanGoForward(bool* aCanGoForward) {
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWebBrowser::GoBack() {
|
||||
nsWebBrowser::GoBack(bool aRequireUserInteraction) {
|
||||
NS_ENSURE_STATE(mDocShell);
|
||||
|
||||
return mDocShellAsNav->GoBack();
|
||||
return mDocShellAsNav->GoBack(aRequireUserInteraction);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWebBrowser::GoForward() {
|
||||
nsWebBrowser::GoForward(bool aRequireUserInteraction) {
|
||||
NS_ENSURE_STATE(mDocShell);
|
||||
|
||||
return mDocShellAsNav->GoForward();
|
||||
return mDocShellAsNav->GoForward(aRequireUserInteraction);
|
||||
}
|
||||
|
||||
nsresult nsWebBrowser::LoadURI(const nsAString& aURI,
|
||||
|
@ -38,17 +38,23 @@ class RemoteWebNavigation {
|
||||
return epoch;
|
||||
}
|
||||
|
||||
goBack() {
|
||||
goBack(requireUserInteraction = false) {
|
||||
let cancelContentJSEpoch = this.maybeCancelContentJSExecution(
|
||||
Ci.nsIRemoteTab.NAVIGATE_BACK
|
||||
);
|
||||
this._sendMessage("WebNavigation:GoBack", { cancelContentJSEpoch });
|
||||
this._sendMessage("WebNavigation:GoBack", {
|
||||
cancelContentJSEpoch,
|
||||
requireUserInteraction,
|
||||
});
|
||||
}
|
||||
goForward() {
|
||||
goForward(requireUserInteraction = false) {
|
||||
let cancelContentJSEpoch = this.maybeCancelContentJSExecution(
|
||||
Ci.nsIRemoteTab.NAVIGATE_FORWARD
|
||||
);
|
||||
this._sendMessage("WebNavigation:GoForward", { cancelContentJSEpoch });
|
||||
this._sendMessage("WebNavigation:GoForward", {
|
||||
cancelContentJSEpoch,
|
||||
requireUserInteraction,
|
||||
});
|
||||
}
|
||||
gotoIndex(aIndex) {
|
||||
let cancelContentJSEpoch = this.maybeCancelContentJSExecution(
|
||||
|
@ -855,17 +855,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
goBack() {
|
||||
goBack(requireUserInteraction = false) {
|
||||
var webNavigation = this.webNavigation;
|
||||
if (webNavigation.canGoBack) {
|
||||
this._wrapURIChangeCall(() => webNavigation.goBack());
|
||||
this._wrapURIChangeCall(() =>
|
||||
webNavigation.goBack(requireUserInteraction)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
goForward() {
|
||||
goForward(requireUserInteraction = false) {
|
||||
var webNavigation = this.webNavigation;
|
||||
if (webNavigation.canGoForward) {
|
||||
this._wrapURIChangeCall(() => webNavigation.goForward());
|
||||
this._wrapURIChangeCall(() =>
|
||||
webNavigation.goForward(requireUserInteraction)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user