tor-browser

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

commit 77d5e074eecb55cdb3d568a284f65913add22ee2
parent ef292b5ecbe5cec8aadeb61688b490871a34b912
Author: Botond Ballo <botond@mozilla.com>
Date:   Wed,  8 Oct 2025 21:54:49 +0000

Bug 1988043 - Use GetFrameTime() rather than the event timestamp when updating the destination of a keyboard scroll animation. r=hiro

This makes the handling of keyboard scroll animations consistent
with wheel scroll animations, for which a similar change was made
in bug 1926830.

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

Diffstat:
Mgfx/layers/apz/src/AsyncPanZoomController.cpp | 2+-
Mgfx/layers/apz/test/gtest/APZTestCommon.h | 5+++++
Mgfx/layers/apz/test/gtest/TestBasic.cpp | 76+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -2253,7 +2253,7 @@ nsEventStatus AsyncPanZoomController::OnKeyboard(const KeyboardInput& aEvent) { SmoothScrollAnimation* animation = mAnimation->AsSmoothScrollAnimation(); MOZ_ASSERT(animation); - animation->UpdateDestination(aEvent.mTimeStamp, + animation->UpdateDestination(GetFrameTime().Time(), CSSPixel::ToAppUnits(destination), nsSize(velocity.x, velocity.y)); diff --git a/gfx/layers/apz/test/gtest/APZTestCommon.h b/gfx/layers/apz/test/gtest/APZTestCommon.h @@ -400,6 +400,11 @@ class TestAsyncPanZoomController : public AsyncPanZoomController { EXPECT_TRUE(InScrollAnimation(ScrollAnimationKind::Wheel)); } + void AssertInKeyboardScroll() { + RecursiveMutexAutoLock lock(mRecursiveMutex); + EXPECT_TRUE(InScrollAnimation(ScrollAnimationKind::Keyboard)); + } + void AssertStateIsAutoscroll() { RecursiveMutexAutoLock lock(mRecursiveMutex); EXPECT_EQ(AUTOSCROLL, mState); diff --git a/gfx/layers/apz/test/gtest/TestBasic.cpp b/gfx/layers/apz/test/gtest/TestBasic.cpp @@ -9,6 +9,7 @@ #include "InputUtils.h" #include "mozilla/ScrollPositionUpdate.h" +#include "mozilla/layers/ScrollableLayerGuid.h" TEST_F(APZCBasicTester, Overzoom) { // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100 @@ -622,7 +623,7 @@ class APZCSmoothScrollTester : public APZCBasicTester { // Test that receiving a wheel event with a timestamp far in the future does // not cause scrolling to get stuck. - void TestEventWithFutureStamp() { + void TestWheelEventWithFutureStamp() { // Set up scroll frame. Starting scroll position is (0, 0). ScrollMetadata metadata; FrameMetrics& metrics = metadata.GetMetrics(); @@ -665,6 +666,59 @@ class APZCSmoothScrollTester : public APZCBasicTester { // Clean up by letting the animation run until completion. apzc->AdvanceAnimationsUntilEnd(); } + + // Test that receiving a key event with a timestamp far in the future does + // not cause scrolling to get stuck. + void TestKeyEventWithFutureStamp() { + // Set up scroll frame. Starting scroll position is (0, 0). + ScrollMetadata metadata; + FrameMetrics& metrics = metadata.GetMetrics(); + metrics.SetScrollableRect(CSSRect(0, 0, 1000, 10000)); + metrics.SetLayoutViewport(CSSRect(0, 0, 1000, 1000)); + metrics.SetZoom(CSSToParentLayerScale(1.0)); + metrics.SetCompositionBounds(ParentLayerRect(0, 0, 1000, 1000)); + metrics.SetVisualScrollOffset(CSSPoint(0, 0)); + metrics.SetScrollId(ScrollableLayerGuid::START_SCROLL_ID); + metrics.SetIsRootContent(true); + // Set the line scroll amount to 100 pixels. The key event we send + // will scroll by a multiple of this amount. + metadata.SetLineScrollAmount({100, 100}); + apzc->SetScrollMetadata(metadata); + + // Note that, since we are sending the key event to the APZC instance + // directly, we don't need to set up a keyboard map or focus state. + + // Send a key event to trigger smooth scrolling by a few lines (the number + // of lines is determined by toolkit.scrollbox.verticalScrollDistance). + WidgetKeyboardEvent keyEvent(true, eKeyDown, nullptr); + // Give the key event a timestamp "far" (here, 1 minute) into the future. + // This simulates a scenario, observed in bug 1926830, where a bug in the + // system toolkit or widget layers causes something to introduce a skew into + // the timestamps received from widget code. + TimeStamp futureTimeStamp = mcc->Time() + TimeDuration::FromSeconds(60); + keyEvent.mTimeStamp = futureTimeStamp; + KeyboardInput keyInput(keyEvent); + // The KeyboardScrollAction needs to be specified on the event explicitly, + // since the mapping from eKeyDown to it happens in APZCTreeManager which + // we are bypassing here. + keyInput.mAction = {KeyboardScrollAction::eScrollLine, /*aForward=*/true}; + Unused << apzc->ReceiveInputEvent(keyInput); + apzc->AssertInKeyboardScroll(); + + // Sample the animation 10 frames (a shorter overall duration than the + // timestamp skew). + for (int i = 0; i < 10; ++i) { + SampleAnimationOneFrame(); + } + + // Assert that we have scrolled. Without a mitigation in place for the + // timestamp skew, we may wait for the frame (vsync) time to catch up with + // the event's timestamp before doing any scrolling. + ASSERT_GT(apzc->GetFrameMetrics().GetVisualScrollOffset().y, 0); + + // Clean up by letting the animation run until completion. + apzc->AdvanceAnimationsUntilEnd(); + } }; TEST_F(APZCSmoothScrollTester, ContentShiftBezier) { @@ -703,16 +757,28 @@ TEST_F(APZCSmoothScrollTester, ContentShiftDoesNotCauseOvershootMsd) { TestContentShiftDoesNotCauseOvershoot(); } -TEST_F(APZCSmoothScrollTester, FutureTimestampBezier) { +TEST_F(APZCSmoothScrollTester, FutureWheelTimestampBezier) { + SCOPED_GFX_PREF_BOOL("general.smoothScroll", true); + SCOPED_GFX_PREF_BOOL("general.smoothScroll.msdPhysics.enabled", false); + TestWheelEventWithFutureStamp(); +} + +TEST_F(APZCSmoothScrollTester, FutureWheelTimestampMsd) { + SCOPED_GFX_PREF_BOOL("general.smoothScroll", true); + SCOPED_GFX_PREF_BOOL("general.smoothScroll.msdPhysics.enabled", true); + TestWheelEventWithFutureStamp(); +} + +TEST_F(APZCSmoothScrollTester, FutureKeyTimestampBezier) { SCOPED_GFX_PREF_BOOL("general.smoothScroll", true); SCOPED_GFX_PREF_BOOL("general.smoothScroll.msdPhysics.enabled", false); - TestEventWithFutureStamp(); + TestKeyEventWithFutureStamp(); } -TEST_F(APZCSmoothScrollTester, FutureTimestampMsd) { +TEST_F(APZCSmoothScrollTester, FutureKeyTimestampMsd) { SCOPED_GFX_PREF_BOOL("general.smoothScroll", true); SCOPED_GFX_PREF_BOOL("general.smoothScroll.msdPhysics.enabled", true); - TestEventWithFutureStamp(); + TestKeyEventWithFutureStamp(); } TEST_F(APZCBasicTester, ZoomAndScrollableRectChangeAfterZoomChange) {