Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: ffd2f37638743584a2eac91a88015e45848d2c9c
      
https://github.com/WebKit/WebKit/commit/ffd2f37638743584a2eac91a88015e45848d2c9c
  Author: Lily Spiniolas <[email protected]>
  Date:   2026-02-04 (Wed, 04 Feb 2026)

  Changed paths:
    M Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.h
    M Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm
    M Source/WebCore/platform/ScrollAnimator.h
    M Source/WebCore/platform/ScrollingEffectsController.h
    M Source/WebCore/platform/mac/ScrollAnimatorMac.h
    M Source/WebCore/platform/mac/ScrollAnimatorMac.mm
    M Source/WebCore/platform/mac/ScrollingEffectsController.mm

  Log Message:
  -----------
  [macOS] Scrolling in direction opposite to current stretch causes page to 
snap back
https://bugs.webkit.org/show_bug.cgi?id=306747
rdar://169220724

Reviewed by Simon Fraser.

When scroll stretching occurs, if the user switches scroll directions so that
the scroll now opposes the stretch direction rather than causing the stretch
to increase, instead of just scrolling with no resistance, the page immediately
snaps out of the stretch. If that same scroll continues, and the user then 
reverses
scroll direction once again to cause the page to stretch, the stretch will snap 
back
into the maximum stretch that occurred before changing direction.

The first bug occurs due to the following:
In `ScrollingEffectsController::applyScrollDeltaWithStretching`, an immediate 
scroll
is performed with an amount equal to the damped delta minus the current stretch 
amount.
This damped delta is also clamped by calling
`ScrollingEffectsController::clampDeltaForAllowedAxes`, which checks with the 
scroll
client to see if vertical or horizontal stretching are allowed. Inside this 
check
in `ScrollingTreeScrollingNodeDelegateMac::allowsVerticalStretching` (and the 
horizontal
equivalent), we take `ScrollableArea::targetSideForScrollDelta` and pass the 
side to
`shouldRubberBandOnSide`. When the scroll opposes the stretch direction,
`targetSideForScrollDelta` is set equal to the side opposite of the stretch, so 
when
`shouldRubberBandOnSide` sees the side is not contained in the pinned edges, it
immediately returns false. This causes `ScrollingEffectsController` to clamp 
the delta
to zero, so when we perform the immediate scroll (damped delta - current 
stretch), we
get an immediate scroll equal to opposite of the current stretch, and the page 
snaps
as a result.

As the scroll continues and the stretch ends, switching directions mid scroll 
back to
the edge that was previously stretched triggers the second bug (snapping back 
into the
largest stretch that occurred before changing direction) due to 
m_stretchScrollForce
retaining the previous maximum force, from which the damped delta is calculated.

Both bugs require us to determine when a scroll delta opposes the current 
stretch direction.
To determine this, we add a new method `isScrollDeltaOpposingStretch` to
`ScrollingEffectsController` which simply takes a `ScrollEventAxis` and the 
delta on that
axis. To resolve the first bug, we make
`ScrollingTreeScrollingNodeDelegateMac::shouldRubberBandOnSide` now consult this
method when making a decision. To fix the second bug, we check
`isScrollDeltaOpposingStretch` in 
`ScrollingEffectsController::applyScrollDeltaWithStretching`
for both axes. When true, that axis' component in `m_stretchScrollForce` is set 
to zero.

Additionally, `ScrollingTreeScrollingNodeDelegateMac::shouldRubberBandOnSide` 
does not dampen
scroll deltas when scrolling in a direction opposite of the stretch since there 
should be no
resistance.

* Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.h:
* Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm:
(WebCore::ScrollingTreeScrollingNodeDelegateMac::allowsHorizontalStretching 
const):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::allowsVerticalStretching 
const):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::isScrollDeltaOpposingStretch 
const):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::shouldRubberBandOnSide const):
* Source/WebCore/platform/ScrollAnimator.h:
* Source/WebCore/platform/ScrollingEffectsController.h:
* Source/WebCore/platform/mac/ScrollAnimatorMac.h:
* Source/WebCore/platform/mac/ScrollAnimatorMac.mm:
(WebCore::ScrollAnimatorMac::isScrollDeltaOpposingStretch const):
(WebCore::ScrollAnimatorMac::shouldRubberBandOnSide const):
* Source/WebCore/platform/mac/ScrollingEffectsController.mm:
(WebCore::ScrollingEffectsController::handleWheelEvent):
(WebCore::ScrollingEffectsController::applyScrollDeltaWithStretching):
(WebCore::ScrollingEffectsController::isScrollDeltaOpposingStretch):
(WebCore::ScrollingEffectsController::shouldRubberBandOnSide const):

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



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to