[webkit-changes] [WebKit/WebKit] 025262: [macOS] Performing layout when scroll snapping wit...

Wenson Hsieh noreply at github.com
Tue Apr 18 16:45:10 PDT 2023


  Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 02526276204938ef6d32be0f75f1bdb076469963
      https://github.com/WebKit/WebKit/commit/02526276204938ef6d32be0f75f1bdb076469963
  Author: Wenson Hsieh <wenson_hsieh at apple.com>
  Date:   2023-04-18 (Tue, 18 Apr 2023)

  Changed paths:
    A LayoutTests/css3/scroll-snap/scroll-snap-discrete-wheel-events-with-layout-expected.txt
    A LayoutTests/css3/scroll-snap/scroll-snap-discrete-wheel-events-with-layout.html
    M LayoutTests/platform/glib/TestExpectations
    M LayoutTests/platform/ios-wk2/TestExpectations
    M Source/WebCore/page/scrolling/ScrollingTree.cpp
    M Source/WebCore/page/scrolling/ScrollingTree.h
    M Source/WebCore/platform/mac/ScrollingEffectsController.mm
    M Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h
    M Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingTree.cpp
    M Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingTree.h
    M Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingCoordinatorProxyMac.h
    M Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingCoordinatorProxyMac.mm

  Log Message:
  -----------
  [macOS] Performing layout when scroll snapping with a physical mouse wheel snaps to the last snap position
https://bugs.webkit.org/show_bug.cgi?id=255603

Reviewed by Tim Horton.

Currently, when `resnapAfterLayout()` is called after a layout pass while scrolling with a physical
mouse wheel in a scroll snapping container, we end up erroneously re-snapping to the last active
snap position. This doesn't happen when using a trackpad to scroll because we bail here:

```
void ScrollableArea::resnapAfterLayout()
{
…
    if (!scrollAnimator || isScrollSnapInProgress() || isUserScrollInProgress())
        return;
```

…due to the fact that `isUserScrollInProgress()` is `true`, since this flag is set over the course
of both user-driven and momentum scrolling phases. Importantly, note that `isScrollSnapInProgress()`
is only `true` in this case where UI-side compositing is *disabled* — this is because nothing
currently calls `{add|remove}NodeWithActiveScrollSnap` on `RemoteScrollingUIState`, which means that
we never end up propagating `m_nodesWithActiveScrollSnap` to the web process when UI-side
compositing is enabled, so from the web-process' perspective, `isScrollSnapInProgress()` is always
`false`.

As such, in order to make physical mouse wheel scrolling work well when there are interleaved layout
passes, the fix is two-fold:

1.  Consider `isScrollSnapInProgress()` to be true if the discrete wheel event timer is scheduled.
2.  Add plumbing to deliver `isScrollSnapInProgress()` state from the UI process to the web process
    through the scrolling state tree, to ensure that this bug fix is also effective when UI-side
    compositing is enabled.

Test: css3/scroll-snap/scroll-snap-discrete-wheel-events-with-layout.html

* LayoutTests/css3/scroll-snap/scroll-snap-discrete-wheel-events-with-layout-expected.txt: Added.
* LayoutTests/css3/scroll-snap/scroll-snap-discrete-wheel-events-with-layout.html: Added.

Add a new test case to exercise the bug fix.

* LayoutTests/platform/glib/TestExpectations:
* LayoutTests/platform/ios-wk2/TestExpectations:
* Source/WebCore/page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::setNodeScrollSnapInProgress):
* Source/WebCore/page/scrolling/ScrollingTree.h:
(WebCore::ScrollingTree::scrollingTreeNodeDidBeginScrollSnapping):
(WebCore::ScrollingTree::scrollingTreeNodeDidEndScrollSnapping):

Add new override hooks to allow the client layer to know when scrolling tree nodes change "scroll
snap in progress" state. See WebKit2 changes below for more information.

* Source/WebCore/platform/mac/ScrollingEffectsController.mm:
(WebCore::ScrollingEffectsController::stopAllTimers):
(WebCore::ScrollingEffectsController::isScrollSnapInProgress const):

Consider scroll snap in progress if we've scheduled a scroll snap while handling discrete wheel
events.

(WebCore::ScrollingEffectsController::discreteSnapTransitionTimerFired):

Add a couple of call sites to `m_client.didStopScrollSnapAnimation()` in the case where the timer
is either stopped early or without triggering a scroll snap animation, such that we don't end up
with a node being stuck indefinitely in `nodesWithActiveScrollSnap`.

* Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
(WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidBeginScrollSnapping):
(WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidEndScrollSnapping):
* Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingTree.cpp:
(WebKit::RemoteScrollingTree::scrollingTreeNodeDidBeginScrollSnapping):
(WebKit::RemoteScrollingTree::scrollingTreeNodeDidEndScrollSnapping):

Add plumbing from `RemoteScrollingTree` -> `RemoteScrollingCoordinatorProxy` ->
`RemoteScrollingUIState` whenever a scrolling node begins or ends scroll snapping progress.

* Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingTree.h:
* Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingCoordinatorProxyMac.h:
* Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingCoordinatorProxyMac.mm:
(WebKit::RemoteScrollingCoordinatorProxyMac::scrollingTreeNodeDidBeginScrollSnapping):
(WebKit::RemoteScrollingCoordinatorProxyMac::scrollingTreeNodeDidEndScrollSnapping):

Canonical link: https://commits.webkit.org/263108@main




More information about the webkit-changes mailing list