Bug 1774537 - Skip re-snapping if there's any async scroll is running. r=botond

Depends on D149497

Differential Revision: https://phabricator.services.mozilla.com/D150929
This commit is contained in:
Hiroyuki Ikezoe 2022-07-14 02:19:12 +00:00
Родитель b300a9f04f
Коммит 251e2e49ef
4 изменённых файлов: 67 добавлений и 7 удалений

Просмотреть файл

@ -8,6 +8,9 @@
<script src="apz_test_native_event_utils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<style>
body {
margin: 0;
}
div {
position: absolute;
}
@ -15,7 +18,7 @@
width: 100%;
height: 500px;
overflow-y: scroll;
scroll-snap-type: y mandatory;
scroll-snap-type: y proximity; /* to escape from the last snap point */
}
.child {
width: 100%;
@ -29,10 +32,13 @@
<div id="scroller">
<div class="child" style="top: 0px;"></div>
<div class="child" style="top: 200px;"></div>
<div style="width: 100%; height: 2000px;"></div>
<div id="spacer" style="width: 100%; height: 2000px;"></div>
</div>
<script type="application/javascript">
async function test() {
const proximityThreshold =
SpecialPowers.getIntPref("layout.css.scroll-snap.proximity-threshold");
let transformEndPromise = promiseTransformEnd();
await promiseMoveMouseAndScrollWheelOver(scroller, 100, 100);
@ -43,6 +49,28 @@
document.querySelectorAll(".child")[1].style.top = "400px";
is(scroller.scrollTop, 400, "re-snap to 400px");
// Make sure the new snap position has been reflected in APZ side.
await promiseApzFlushedRepaints();
// Now trigger another wheel scroll to escape from the last snap point.
transformEndPromise = promiseTransformEnd();
// With a small `layout.css.scroll-behavior.spring-constant` preference
// value (it's set in test_group_scroll_snap.html), an async scroll
// operation, e.g. a wheel scroll operation, fires multiple scroll events
// so that here we wait the first scroll event here by specifying
// `waitForScroll=true`, there should be other scroll events after the
// first one.
await promiseMoveMouseAndScrollWheelOver(scroller, 100, 100,
true /* waitForScroll */, proximityThreshold + 1000);
// Expand the scrollable region during the wheel scroll.
spacer.style.height = "2200px";
await transformEndPromise;
await promiseApzFlushedRepaints();
isnot(scroller.scrollTop, 400, "Do not re-snap to the original 400px point");
}
waitUntilApzStable()

Просмотреть файл

@ -8,6 +8,9 @@
<script src="apz_test_native_event_utils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<style>
body {
margin: 0;
}
div {
position: absolute;
}
@ -15,7 +18,7 @@
width: 100%;
height: 500px;
overflow-y: scroll;
scroll-snap-type: y mandatory;
scroll-snap-type: y proximity; /* to escape from the last snap point */
}
.child {
width: 100%;
@ -29,10 +32,13 @@
<div id="scroller">
<div class="child" style="top: 0px;"></div>
<div class="child" style="top: 200px;"></div>
<div style="width: 100%; height: 2000px;"></div>
<div id="spacer" style="width: 100%; height: 2000px;"></div>
</div>
<script type="application/javascript">
async function test() {
const proximityThreshold =
SpecialPowers.getIntPref("layout.css.scroll-snap.proximity-threshold");
let transformEndPromise = promiseTransformEnd();
scroller.scrollBy({left: 0, top: 100, behavior: "smooth"});
@ -43,6 +49,19 @@
document.querySelectorAll(".child")[1].style.top = "400px";
is(scroller.scrollTop, 400, "re-snap to 400px");
// Now trigger another async scroll to escape from the last snap point.
transformEndPromise = promiseTransformEnd();
scroller.scrollBy({left: 0, top: proximityThreshold + 100,
behavior: "smooth"});
// Expand the scrollable region during the async scroll.
spacer.style.height = "2200px";
await transformEndPromise;
await promiseApzFlushedRepaints();
isnot(scroller.scrollTop, 400, "Do not re-snap to the original 400px point");
}
waitUntilApzStable()

Просмотреть файл

@ -19,10 +19,18 @@ const prefs = [
const subtests = [
{"file": "helper_scroll_snap_no_valid_snap_position.html", "prefs": prefs},
{"file": "helper_scroll_snap_resnap_after_async_scroll.html"},
{"file": "helper_scroll_snap_resnap_after_async_scroll.html",
"prefs": [["general.smoothScroll", false]]},
{"file": "helper_scroll_snap_resnap_after_async_scrollBy.html"},
// Specify a small `layout.css.scroll-behavior.spring-constant` value to
// keep the smooth scroll animation running long enough so that we can
// trigger a reflow during the animation.
"prefs": [["layout.css.scroll-behavior.spring-constant", 10],
["apz.test.mac.synth_wheel_input", true]]},
{"file": "helper_scroll_snap_resnap_after_async_scroll.html",
"prefs": [["general.smoothScroll", false],
["apz.test.mac.synth_wheel_input", true]]},
{"file": "helper_scroll_snap_resnap_after_async_scrollBy.html",
// Same as above helper_scroll_snap_resnap_after_async_scroll.html.
"prefs": [["layout.css.scroll-behavior.spring-constant", 10]]},
];
if (isApzEnabled()) {

Просмотреть файл

@ -8041,6 +8041,11 @@ bool ScrollFrameHelper::IsLastSnappedTarget(const nsIFrame* aFrame) const {
}
void ScrollFrameHelper::TryResnap() {
// If there's any async scroll is running, don't clobber the scroll.
if (!ScrollAnimationState().isEmpty()) {
return;
}
if (auto snapTarget = GetSnapPointForResnap()) {
// We are going to re-snap so that we need to clobber scroll anchoring.
mAnchor.UserScrolled();