Changeset 176899 in webkit


Ignore:
Timestamp:
Dec 5, 2014 5:25:21 PM (9 years ago)
Author:
Simon Fraser
Message:

Programmatic scrolling and content changes are not always synchronized
https://bugs.webkit.org/show_bug.cgi?id=139245
rdar://problem/18833612

Reviewed by Anders Carlsson.

Manual test that tries to sync layout with programmatic scrolling.

  • ManualTests/programmatic-scroll-flicker.html: Added.

Source/WebCore:

For programmatic scrolls, AsyncScrollingCoordinator::requestScrollPositionUpdate()
calls updateScrollPositionAfterAsyncScroll(), then dispatches the requested
scroll position to the scrolling thread.

Once the scrolling thread commits, it calls back to the main thread via
scheduleUpdateScrollPositionAfterAsyncScroll(), which schedules a second
call to updateScrollPositionAfterAsyncScroll() on a timer. That's a problem,
because some other scroll may have happened in the meantime; when the timer
fires, it can sometimes restore a stale scroll position.

Fix by bailing early from scheduleUpdateScrollPositionAfterAsyncScroll()
for programmatic scrolls, since we know that requestScrollPositionUpdate()
already did the updateScrollPositionAfterAsyncScroll().

Test:

ManualTests/programmatic-scroll-flicker.html

  • page/FrameView.cpp:

(WebCore::FrameView::reset): nullptr.
(WebCore::FrameView::setScrollPosition): Ditto.
(WebCore::FrameView::setWasScrolledByUser): Ditto.

  • page/scrolling/AsyncScrollingCoordinator.cpp:

(WebCore::AsyncScrollingCoordinator::requestScrollPositionUpdate): Use a local variable for
isProgrammaticScroll just to make sure we use the same value for the duration of this function.
(WebCore::AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll): Do nothing
if this is a programmatic scroll.

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/ChangeLog

    r176787 r176899  
     12014-12-05  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Programmatic scrolling and content changes are not always synchronized
     4        https://bugs.webkit.org/show_bug.cgi?id=139245
     5        rdar://problem/18833612
     6
     7        Reviewed by Anders Carlsson.
     8       
     9        Manual test that tries to sync layout with programmatic scrolling.
     10
     11        * ManualTests/programmatic-scroll-flicker.html: Added.
     12
    1132014-12-04  Alberto Garcia  <berto@igalia.com>
    214
  • trunk/Source/WebCore/ChangeLog

    r176898 r176899  
     12014-12-05  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Programmatic scrolling and content changes are not always synchronized
     4        https://bugs.webkit.org/show_bug.cgi?id=139245
     5        rdar://problem/18833612
     6
     7        Reviewed by Anders Carlsson.
     8       
     9        For programmatic scrolls, AsyncScrollingCoordinator::requestScrollPositionUpdate()
     10        calls updateScrollPositionAfterAsyncScroll(), then dispatches the requested
     11        scroll position to the scrolling thread.
     12       
     13        Once the scrolling thread commits, it calls back to the main thread via
     14        scheduleUpdateScrollPositionAfterAsyncScroll(), which schedules a second
     15        call to updateScrollPositionAfterAsyncScroll() on a timer. That's a problem,
     16        because some other scroll may have happened in the meantime; when the timer
     17        fires, it can sometimes restore a stale scroll position.
     18       
     19        Fix by bailing early from scheduleUpdateScrollPositionAfterAsyncScroll()
     20        for programmatic scrolls, since we know that requestScrollPositionUpdate()
     21        already did the updateScrollPositionAfterAsyncScroll().
     22
     23        Test:
     24            ManualTests/programmatic-scroll-flicker.html
     25
     26        * page/FrameView.cpp:
     27        (WebCore::FrameView::reset): nullptr.
     28        (WebCore::FrameView::setScrollPosition): Ditto.
     29        (WebCore::FrameView::setWasScrolledByUser): Ditto.
     30        * page/scrolling/AsyncScrollingCoordinator.cpp:
     31        (WebCore::AsyncScrollingCoordinator::requestScrollPositionUpdate): Use a local variable for
     32        isProgrammaticScroll just to make sure we use the same value for the duration of this function.
     33        (WebCore::AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll): Do nothing
     34        if this is a programmatic scroll.
     35
    1362014-12-05  Timothy Horton  <timothy_horton@apple.com>
    237
  • trunk/Source/WebCore/page/FrameView.cpp

    r176798 r176899  
    290290    m_isVisuallyNonEmpty = false;
    291291    m_firstVisuallyNonEmptyLayoutCallbackPending = true;
    292     m_maintainScrollPositionAnchor = 0;
     292    m_maintainScrollPositionAnchor = nullptr;
    293293    m_throttledTimers.clear();
    294294}
     
    20242024{
    20252025    TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
    2026     m_maintainScrollPositionAnchor = 0;
     2026    m_maintainScrollPositionAnchor = nullptr;
    20272027    ScrollView::setScrollPosition(scrollPoint);
    20282028}
     
    37143714    if (m_inProgrammaticScroll)
    37153715        return;
    3716     m_maintainScrollPositionAnchor = 0;
     3716    m_maintainScrollPositionAnchor = nullptr;
    37173717    if (m_wasScrolledByUser == wasScrolledByUser)
    37183718        return;
  • trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp

    r176459 r176899  
    177177        return false;
    178178
    179     if (frameView->inProgrammaticScroll() || frameView->frame().document()->inPageCache())
    180         updateScrollPositionAfterAsyncScroll(frameView->scrollLayerID(), scrollPosition, frameView->inProgrammaticScroll(), SetScrollingLayerPosition);
     179    bool isProgrammaticScroll = frameView->inProgrammaticScroll();
     180    if (isProgrammaticScroll || frameView->frame().document()->inPageCache())
     181        updateScrollPositionAfterAsyncScroll(frameView->scrollLayerID(), scrollPosition, isProgrammaticScroll, SetScrollingLayerPosition);
    181182
    182183    // If this frame view's document is being put into the page cache, we don't want to update our
     
    189190        return false;
    190191
    191     stateNode->setRequestedScrollPosition(scrollPosition, frameView->inProgrammaticScroll());
     192    stateNode->setRequestedScrollPosition(scrollPosition, isProgrammaticScroll);
    192193    return true;
    193194}
     
    197198    ScheduledScrollUpdate scrollUpdate(nodeID, scrollPosition, programmaticScroll, scrollingLayerPositionAction);
    198199   
     200    // For programmatic scrolls, requestScrollPositionUpdate() has already called updateScrollPositionAfterAsyncScroll().
     201    if (programmaticScroll)
     202        return;
     203
    199204    if (m_updateNodeScrollPositionTimer.isActive()) {
    200205        if (m_scheduledScrollUpdate.matchesUpdateType(scrollUpdate)) {
Note: See TracChangeset for help on using the changeset viewer.