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