Bug 229697

Summary: keyboard scrolling spring damping animation doesn't finish and leads to endless flickering scrolling
Product: WebKit Reporter: Fujii Hironori <Hironori.Fujii>
Component: ScrollingAssignee: Fujii Hironori <Hironori.Fujii>
Status: RESOLVED FIXED    
Severity: Normal CC: bdakin, clord, dana.estra, destra, richard_robinson2, simon.fraser, thorton, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=228009
Attachments:
Description Flags
log
none
Patch none

Description Fujii Hironori 2021-08-30 21:13:55 PDT
keyboard scrolling spring damping animation doesn't finish in WinCairo Debug with debug logging

1. Start WinCairo Debug with enabling some debug logging
   $env:WebCoreLogging = "Scrolling"
   devenv -debugexe .\WebKitBuild\Debug\bin64\MiniBrowser.exe
   Turn "Enable child process debugging" on
   Start Debugging
2. Go to a heavy and long page. For example, https://news.google.com/ and https://edition.cnn.com/
3. Press Page-Down key

Expected: The scrolling animation stops.
Actual: The scrolling animation never stops. It goes back and forth.
Comment 1 Fujii Hironori 2021-08-30 21:17:28 PDT
https://github.com/WebKit/WebKit/blob/b736c55b81845e8e159eb97b3fcba1a8315da7d1/Source/WebCore/platform/KeyboardScrollingAnimator.cpp#L125,L127

>  FloatSize acceleration = force.scaled(1. / params.springMass);
>  m_velocity += acceleration.scaled(frameDuration);
>  FloatPoint newPosition = m_scrollAnimator.currentPosition() + m_velocity.scaled(frameDuration);

This expressions are assuming that frameDuration is short.
Comment 3 Tim Horton 2021-08-31 00:38:53 PDT
This feature isn't ready yet, how did it get turned on?
Comment 4 Tim Horton 2021-08-31 00:39:26 PDT
That said, I don't think we were aware of this particular problem.
Comment 5 Fujii Hironori 2021-08-31 13:42:32 PDT
(In reply to Tim Horton from comment #3)
> This feature isn't ready yet, how did it get turned on?

Good to know. Then, it's another bug.
Filed: Bug 229733 – REGRESSION(r280928) The smooth keyboard scrolling is enabled only for PageUp and PageDown keys
Comment 6 Fujii Hironori 2021-11-04 13:01:04 PDT
Epiphany (WebKitGTK) has a bug report.

Bug 232701 – [GTK] Pressing "End" keyboard key on instagram.com leads to endless flickering scrolling
Comment 7 Radar WebKit Bug Importer 2022-03-10 10:21:57 PST
<rdar://problem/90106824>
Comment 8 Fujii Hironori 2022-10-02 13:41:47 PDT
255031@main (bug#228159) enabled EventHandlerDrivenSmoothKeyboardScrollingEnabled by default.
Now, I can reproduce this issue even with WinCairo MiniBrowser Release build.
Comment 9 Tim Horton 2022-10-02 16:05:18 PDT
Oops, sorry. We probably should have only enabled for cocoa ports. Richard?
Comment 10 Richard Robinson 2022-10-02 16:11:09 PDT
(In reply to Tim Horton from comment #9)
> Oops, sorry. We probably should have only enabled for cocoa ports. Richard?

Yup, I'm on it.
Comment 11 Richard Robinson 2022-10-02 16:15:31 PDT
Pull request: https://github.com/WebKit/WebKit/pull/4914
Comment 12 Fujii Hironori 2022-10-02 17:06:12 PDT
It's assuming that frameDuration is short (comment#1). I think we should choose more robust algorithm.
Comment 13 Tim Horton 2022-10-02 23:02:16 PDT
(In reply to Fujii Hironori from comment #12)
> It's assuming that frameDuration is short (comment#1). I think we should
> choose more robust algorithm.

This has been shipping for years on iOS.
Why is frameDuration *not* short for you?
Comment 14 Fujii Hironori 2022-10-03 01:01:35 PDT
Created attachment 462767 [details]
log

I added the following log. I pressed down arrow key and page down key in https://webkit.org/ .
The sprint went into divergent vibration.

diff --git a/Source/WebCore/platform/KeyboardScrollingAnimator.cpp b/Source/WebCore/platform/KeyboardScrollingAnimator.cpp
index 9863ebac3fd6..d604c3e15560 100644
--- a/Source/WebCore/platform/KeyboardScrollingAnimator.cpp
+++ b/Source/WebCore/platform/KeyboardScrollingAnimator.cpp
@@ -218,6 +218,7 @@ void KeyboardScrollingAnimator::updateKeyboardScrollPosition(MonotonicTime curre
 
     m_scrollAnimator.scrollToPositionWithoutAnimation(newPosition);
 
+    ALWAYS_LOG_WITH_STREAM(stream << "frameDuration:" << frameDuration << " newPosition:" << newPosition << " m_velocity:" << m_velocity);
     if (!m_scrollTriggeringKeyIsPressed && m_velocity.diagonalLengthSquared() < 1) {
         m_scrollController.didStopKeyboardScrolling();
         m_velocity = { };
Comment 15 EWS 2022-10-03 14:46:54 PDT
Committed 255099@main (5f888cf9998e): <https://commits.webkit.org/255099@main>

Reviewed commits have been landed. Closing PR #4914 and removing active labels.
Comment 16 Fujii Hironori 2022-10-03 14:56:08 PDT
I misunderstood a little. The problem reproducible by Release build + PageDown is a bit different issue.
I filed bug#245982 to the bug.
Comment 17 Fujii Hironori 2022-10-03 15:03:20 PDT
I tried comment#0 step. I just pressed a single down arrow key in this case.

frameDuration:0.01 newPosition:(0,0.05) m_velocity:width=0 height=7.30
frameDuration:0.04 newPosition:(0,1.69) m_velocity:width=0 height=44.33
frameDuration:0.14 newPosition:(0,73.07) m_velocity:width=0 height=507.16
frameDuration:0.20 newPosition:(0,-375.81) m_velocity:width=0 height=-2243.49
frameDuration:0.09 newPosition:(0,193.07) m_velocity:width=0 height=2158.95
frameDuration:0.33 newPosition:(0,-5452.72) m_velocity:width=0 height=-17336.29
frameDuration:0.14 newPosition:(0,4149.97) m_velocity:width=0 height=30474.31
frameDuration:3.10 newPosition:(0,-9244337) m_velocity:width=0 height=-2981108.50
frameDuration:1.02 newPosition:(0,58668016) m_velocity:width=0 height=57673556
frameDuration:1.92 newPosition:(0,-4164551680.00) m_velocity:width=0 height=-2163899648.00
frameDuration:0.98 newPosition:(0,39856992256.00) m_velocity:width=0 height=40464424960.00
frameDuration:0.72 newPosition:(0,-385372749824.00) m_velocity:width=0 height=-538594639872.00
frameDuration:1.12 newPosition:(0,12795050459136.00) m_velocity:width=0 height=11473761861632.00
Comment 18 Fujii Hironori 2022-10-03 21:41:06 PDT
This bug is reproducible for Mac port MiniBrowser (Debug build) on my Mac mini (2018).
1. Enable "Scrolling" debug log channel
2. Start MiniBrowser (Debug build)
3. Go to https://edition.cnn.com/
4. Press arrow keys and PageUp and Page Down keys to scroll
Not 100% reproducible. But, it's easy to reproduce.
Comment 19 Fujii Hironori 2022-10-06 15:07:48 PDT
Created attachment 462846 [details]
Patch
Comment 20 Tim Horton 2022-10-07 09:34:47 PDT
Comment on attachment 462846 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=462846&action=review

> Source/WebCore/platform/KeyboardScrollingAnimator.cpp:223
> +    if (axesToApplySpring.width() && displacement.width() * newDisplacement.width() < 0)

This is fine, though I bet you want an areEssentiallyEqual / FLT_EPSILON / whatever?

(Also separately super confused about what's going on with your frame times, and why this was never necessary on iOS (not sure if there was a mistake when the code got moved here, or what)). But that's ok!

Thank you for fixing.
Comment 21 Fujii Hironori 2022-10-07 14:36:16 PDT
Comment on attachment 462846 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=462846&action=review

Thank you very much for the review.

>> Source/WebCore/platform/KeyboardScrollingAnimator.cpp:223
>> +    if (axesToApplySpring.width() && displacement.width() * newDisplacement.width() < 0)
> 
> This is fine, though I bet you want an areEssentiallyEqual / FLT_EPSILON / whatever?
> 
> (Also separately super confused about what's going on with your frame times, and why this was never necessary on iOS (not sure if there was a mistake when the code got moved here, or what)). But that's ok!
> 
> Thank you for fixing.

The first condition "axesToApplySpring.width()" is checking if x-axis is to apply spring.
The second condition "displacement.width() * newDisplacement.width() < 0" is checking if either of the previous or next x-axis displacement is negative and the other is positive.
I don't think areEssentiallyEqual is needed here.

It should be reproducible even for iOS if we can slow down the scrolling somehow or if we use a stronger spring (bigger params.springStiffness).
Comment 22 Tim Horton 2022-10-07 15:06:12 PDT
(In reply to Fujii Hironori from comment #21)
> Comment on attachment 462846 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=462846&action=review
> 
> 
> The first condition "axesToApplySpring.width()" is checking if x-axis is to
> apply spring.
> The second condition "displacement.width() * newDisplacement.width() < 0" is
> checking if either of the previous or next x-axis displacement is negative
> and the other is positive.
> I don't think areEssentiallyEqual is needed here.

Right! I misread. Apologies.
Comment 23 EWS 2022-10-07 19:10:30 PDT
Committed 255306@main (367b4c1a2c7f): <https://commits.webkit.org/255306@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 462846 [details].