tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 04285ccad74dc0766778495a5c6a486b2a1887ca
parent 457417d3eb61669e6495f6fc09a00d76fdb5a1ed
Author: Hiroyuki Ikezoe <hikezoe.birchill@mozilla.com>
Date:   Tue,  4 Nov 2025 04:43:42 +0000

Bug 1989868 - Cancel smooth scroll animation triggered by JS on touch move event. r=botond

And then restart a new touch event series to keep touch scrolling works.

Differential Revision: https://phabricator.services.mozilla.com/D269904

Diffstat:
Mgfx/layers/apz/src/AsyncPanZoomController.cpp | 18++++++++++++++++++
Mgfx/layers/apz/src/AsyncPanZoomController.h | 6++++++
Agfx/layers/apz/test/mochitest/helper_bug1989868.html | 45+++++++++++++++++++++++++++++++++++++++++++++
Mgfx/layers/apz/test/mochitest/test_group_touchevents-6.html | 2++
4 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -1446,6 +1446,14 @@ nsEventStatus AsyncPanZoomController::OnTouchMove( const MultiTouchInput& aEvent) { APZC_LOG_DETAIL("got a touch-move in state %s\n", this, ToString(mState).c_str()); + + if (InScrollAnimationTriggeredByScript()) { + // Cancel smooth animation triggered by script. + CancelAnimation(); + // Restart the touch event series. + return OnTouchStart(aEvent); + } + switch (mState) { case FLING: case SMOOTH_SCROLL: @@ -6726,6 +6734,16 @@ bool AsyncPanZoomController::InScrollAnimation( return smoothScroll && smoothScroll->Kind() == aKind; } +bool AsyncPanZoomController::InScrollAnimationTriggeredByScript() const { + RecursiveMutexAutoLock lock(mRecursiveMutex); + if (!mAnimation) { + return false; + } + RefPtr<SmoothScrollAnimation> smoothScroll = + mAnimation->AsSmoothScrollAnimation(); + return smoothScroll && smoothScroll->WasTriggeredByScript(); +} + void AsyncPanZoomController::UpdateZoomConstraints( const ZoomConstraints& aConstraints) { if ((MOZ_LOG_TEST(sApzCtlLog, LogLevel::Debug) && diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -1500,6 +1500,12 @@ class AsyncPanZoomController { bool InScrollAnimation(ScrollAnimationKind aKind) const; /** + * Check whether there is an ongoing smooth scroll animation triggered by + * script. + */ + bool InScrollAnimationTriggeredByScript() const; + + /** * Returns whether the specified PanZoomState does not need to be reset when * a scroll offset update is processed. */ diff --git a/gfx/layers/apz/test/mochitest/helper_bug1989868.html b/gfx/layers/apz/test/mochitest/helper_bug1989868.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html> +<meta name="viewport" content="width=device-width; initial-scale=1.0"> +<title>Test that touch scrolling keeps working with a smooth scroll operation by JS</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<script src="/tests/SimpleTest/paint_listener.js"></script> +<script src="apz_test_utils.js"></script> +<script src="apz_test_native_event_utils.js"></script> +<style> +body { + margin: 0px; + padding: 0px; +} +</style> +<div style="width: 100vw; height: 300vh;"></div> +<script> +async function test() { + let scrollYInEventHandler; + window.addEventListener("scroll", () => { + scrollYInEventHandler = window.scrollY; + // Trigger a smooth scroll. + window.scrollTo({top: 0, behavior: "smooth"}); + }, { once: true }); + + // Send touch events to scroll down the content. + // Note that each touch event needs to be sent in each frame to + // give a chance to receive a scroll event while sending the evets. + for (let y = 200; y > 0; y -= 10) { + await synthesizeNativeTouch(window, 100, y, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT); + await promiseFrame(); + } + + ok(scrollYInEventHandler * 2 <= window.scrollY, + `The last scroll position ${window.scrollY} should be greater than the + double of the position in scroll event handler ${scrollYInEventHandler}`); + + await synthesizeNativeTouch(window, 100, 0, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE); +} + +waitUntilApzStable() +.then(test) +.then(subtestDone, subtestFailed); +</script> +</html> diff --git a/gfx/layers/apz/test/mochitest/test_group_touchevents-6.html b/gfx/layers/apz/test/mochitest/test_group_touchevents-6.html @@ -53,6 +53,8 @@ var subtests = [ ["ui.click_hold_context_menus.delay", 1000000], ["test.events.async.enabled", true] ]}, + {"file": "helper_bug1989868.html", + "prefs": getPrefs("TOUCH_EVENTS:PAN")}, // Add new subtests here. If this starts timing out because it's taking too // long, create a test_group_touchevents-7.html file. Refer to 1423011#c57