Changeset 279564 in webkit


Ignore:
Timestamp:
Jul 5, 2021 2:21:05 AM (13 months ago)
Author:
Martin Robinson
Message:

[css-scroll-snap] Triggering a layout during scroll causes jittery scrolling on Mac when dragging the scrollbar
https://bugs.webkit.org/show_bug.cgi?id=227478

Reviewed by Simon Fraser.

Source/WebCore:

When dragging the scrollbar thumb, wait to resnap after layout for a
given axis until the mouse button is up on the scrollbar. This prevents
the layout and the scrollbar from fighting to set the scroll position
which causes some pretty terrible jitter in this case.

Test: css3/scroll-snap/scroll-snap-drag-scrollbar-thumb-with-relayouts.html

  • platform/ScrollAnimationSmooth.cpp:

(WebCore::ScrollAnimationSmooth::updatePerAxisData): Fix an issue where the new position
was calculated incorrectly. This did not cause the animation to land on the wrong place,
but did cause a very janky animation progression when retriggering animations to the
same location.

  • platform/ScrollAnimator.cpp:

(WebCore::ScrollAnimator::retargetRunningAnimation): Added this helper, which retargets a
a running animation to allow for a smooth transition during relayouts.

  • platform/ScrollAnimator.h: Added new method definition.
  • platform/ScrollableArea.cpp:

(WebCore::ScrollableArea::resnapAfterLayout): Only snap after layout when the user is not
currently interacting with the scrollbar. Once the scrollbar isn't being interacted with,
snapping will occur already. When there is already some sort of animation in progress,
smoothly transition that animation to land on the new position instead of snapping there
immediately.

LayoutTests:

  • css3/scroll-snap/scroll-snap-drag-scrollbar-thumb-with-relayouts-expected.txt: Added.
  • css3/scroll-snap/scroll-snap-drag-scrollbar-thumb-with-relayouts.html: Added.
  • platform/ios/TestExpectations: Skip this test on iOS since it uses a scrollbar thumb drag.
Location:
trunk
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r279562 r279564  
     12021-07-05  Martin Robinson  <mrobinson@webkit.org>
     2
     3        [css-scroll-snap] Triggering a layout during scroll causes jittery scrolling on Mac when dragging the scrollbar
     4        https://bugs.webkit.org/show_bug.cgi?id=227478
     5
     6        Reviewed by Simon Fraser.
     7
     8        * css3/scroll-snap/scroll-snap-drag-scrollbar-thumb-with-relayouts-expected.txt: Added.
     9        * css3/scroll-snap/scroll-snap-drag-scrollbar-thumb-with-relayouts.html: Added.
     10        * platform/ios/TestExpectations: Skip this test on iOS since it uses a scrollbar thumb drag.
     11
    1122021-07-04  Wenson Hsieh  <wenson_hsieh@apple.com>
    213
  • trunk/LayoutTests/platform/ios/TestExpectations

    r279516 r279564  
    22882288webkit.org/b/157201 fast/scrolling/rtl-drag-vertical-scroller.html [ Failure ]
    22892289webkit.org/b/157201 css3/scroll-snap/scroll-snap-drag-scrollbar-thumb.html [ Failure ]
     2290webkit.org/b/157201 css3/scroll-snap/scroll-snap-drag-scrollbar-thumb-with-relayouts.html [ Failure ]
    22902291
    22912292# DumpRenderTree doesn't support logging calls to runOpenPanel and iOS's WebKitTestRunner doesn't support eventSender.mouseDown.
  • trunk/Source/WebCore/ChangeLog

    r279558 r279564  
     12021-07-05  Martin Robinson  <mrobinson@webkit.org>
     2
     3        [css-scroll-snap] Triggering a layout during scroll causes jittery scrolling on Mac when dragging the scrollbar
     4        https://bugs.webkit.org/show_bug.cgi?id=227478
     5
     6        Reviewed by Simon Fraser.
     7
     8        When dragging the scrollbar thumb, wait to resnap after layout for a
     9        given axis until the mouse button is up on the scrollbar. This prevents
     10        the layout and the scrollbar from fighting to set the scroll position
     11        which causes some pretty terrible jitter in this case.
     12
     13        Test: css3/scroll-snap/scroll-snap-drag-scrollbar-thumb-with-relayouts.html
     14
     15        * platform/ScrollAnimationSmooth.cpp:
     16        (WebCore::ScrollAnimationSmooth::updatePerAxisData): Fix an issue where the new position
     17        was calculated incorrectly. This did not cause the animation to land on the wrong place,
     18        but did cause a very janky animation progression when retriggering animations to the
     19        same location.
     20        * platform/ScrollAnimator.cpp:
     21        (WebCore::ScrollAnimator::retargetRunningAnimation): Added this helper, which retargets a
     22        a running animation to allow for a smooth transition during relayouts.
     23        * platform/ScrollAnimator.h: Added new method definition.
     24        * platform/ScrollableArea.cpp:
     25        (WebCore::ScrollableArea::resnapAfterLayout): Only snap after layout when the user is not
     26        currently interacting with the scrollbar. Once the scrollbar isn't being interacted with,
     27        snapping will occur already. When there is already some sort of animation in progress,
     28        smoothly transition that animation to land on the new position instead of snapping there
     29        immediately.
     30
    1312021-07-04  Alexey Shvayka  <shvaikalesh@gmail.com>
    232
  • trunk/Source/WebCore/platform/ScrollAnimationSmooth.cpp

    r273690 r279564  
    294294        data.startTime = { };
    295295    }
    296     float newPosition = data.desiredPosition + delta;
    297 
     296
     297    float newPosition = data.currentPosition + delta;
    298298    newPosition = std::max(std::min(newPosition, maxScrollPosition), minScrollPosition);
    299 
    300299    if (newPosition == data.desiredPosition)
    301300        return false;
     301
    302302
    303303    Seconds animationTime, repeatMinimumSustainTime, attackTime, releaseTime, maximumCoastTime;
  • trunk/Source/WebCore/platform/ScrollAnimator.cpp

    r279218 r279564  
    147147}
    148148
     149void ScrollAnimator::retargetRunningAnimation(const FloatPoint& newPosition)
     150{
     151    ASSERT(scrollableArea().currentScrollBehaviorStatus() == ScrollBehaviorStatus::InNonNativeAnimation);
     152    ASSERT(m_scrollAnimation->isActive());
     153    m_scrollAnimation->scroll(newPosition);
     154}
     155
    149156FloatPoint ScrollAnimator::offsetFromPosition(const FloatPoint& position)
    150157{
  • trunk/Source/WebCore/platform/ScrollAnimator.h

    r279218 r279564  
    7373    bool scrollToOffsetWithoutAnimation(const FloatPoint&, ScrollClamping = ScrollClamping::Clamped);
    7474    virtual bool scrollToPositionWithoutAnimation(const FloatPoint& position, ScrollClamping = ScrollClamping::Clamped);
     75    virtual void retargetRunningAnimation(const FloatPoint&);
    7576
    7677    bool scrollToOffsetWithAnimation(const FloatPoint&);
  • trunk/Source/WebCore/platform/ScrollableArea.cpp

    r279218 r279564  
    530530    auto currentOffset = scrollOffset();
    531531    auto correctedOffset = currentOffset;
    532     const auto& horizontal = info->horizontalSnapOffsets;
    533     auto activeHorizontalIndex = currentHorizontalSnapPointIndex();
    534     if (activeHorizontalIndex)
    535         correctedOffset.setX(horizontal[*activeHorizontalIndex].offset.toInt());
    536 
    537     const auto& vertical = info->verticalSnapOffsets;
    538     auto activeVerticalIndex = currentVerticalSnapPointIndex();
    539     if (activeVerticalIndex)
    540         correctedOffset.setY(vertical[*activeVerticalIndex].offset.toInt());
     532
     533    if (!horizontalScrollbar() || horizontalScrollbar()->pressedPart() == ScrollbarPart::NoPart) {
     534        const auto& horizontal = info->horizontalSnapOffsets;
     535        auto activeHorizontalIndex = currentHorizontalSnapPointIndex();
     536        if (activeHorizontalIndex)
     537            correctedOffset.setX(horizontal[*activeHorizontalIndex].offset.toInt());
     538    }
     539
     540    if (!verticalScrollbar() || verticalScrollbar()->pressedPart() == ScrollbarPart::NoPart) {
     541        const auto& vertical = info->verticalSnapOffsets;
     542        auto activeVerticalIndex = currentVerticalSnapPointIndex();
     543        if (activeVerticalIndex)
     544            correctedOffset.setY(vertical[*activeVerticalIndex].offset.toInt());
     545    }
    541546
    542547    if (correctedOffset != currentOffset) {
    543548        LOG_WITH_STREAM(ScrollSnap, stream << " adjusting offset from " << currentOffset << " to " << correctedOffset);
    544         scrollToOffsetWithoutAnimation(correctedOffset);
     549        auto position = scrollPositionFromOffset(correctedOffset);
     550        if (currentScrollBehaviorStatus() == ScrollBehaviorStatus::NotInAnimation)
     551            scrollToOffsetWithoutAnimation(correctedOffset);
     552        else
     553            scrollAnimator->retargetRunningAnimation(position);
    545554    }
    546555}
Note: See TracChangeset for help on using the changeset viewer.