Changeset 258679 in webkit


Ignore:
Timestamp:
Mar 18, 2020 9:06:37 PM (4 years ago)
Author:
Simon Fraser
Message:

eventSender.monitorWheelEvents() is very fragile
https://bugs.webkit.org/show_bug.cgi?id=197819
<rdar://problem/51319456>

Reviewed by Tim Horton.

Source/WebCore:

Deflake tests using eventSender.monitorWheelEvents() by fixing several causes of flakiness,
adding back changes from r257844 that were reverted in r258558.

First, have EventSendingController keep track of whether it's seen then "end" event
for the scrolling and momentum phases, and pass this down to WheelEventTestMonitor, which
now waits until it sees these, which prevents premature triggering which was a common cause of
failure before.

Second, remove WheelEventTestMonitor's 1/60s timer and instead have WheelEventTestMonitor test
for completion in a callout from the end of Page::updateRendering(), which makes it test
and fire at a more consistent time.

Third, push WheelEventTestMonitor to the ScrollingTree, so that reasons for deferral
can be added on the scrolling thread. This fixes an issue where the RunLoop::main().dispatch()
used to send the "ScrollingThreadSyncNeeded" reason to the main thread would get delayed,
also resulting in a premature trigger.

  • Modules/applepay/ApplePaySession.cpp: Unified sources!
  • dom/WindowEventLoop.cpp: Unified sources!
  • page/EventHandler.cpp:

(WebCore::EventHandler::handleWheelEvent):

  • page/FrameView.cpp:

(WebCore::FrameView::scrollOffsetChangedViaPlatformWidgetImpl):

  • page/Page.cpp:

(WebCore::Page::doAfterUpdateRendering):
(WebCore::Page::wheelEventTestMonitor const):
(WebCore::Page::clearWheelEventTestMonitor):
(WebCore::Page::isMonitoringWheelEvents const):
(WebCore::Page::ensureWheelEventTestMonitor):

  • page/Page.h:

(WebCore::Page::wheelEventTestMonitor const): Deleted.
(WebCore::Page::clearWheelEventTestMonitor): Deleted.
(WebCore::Page::isMonitoringWheelEvents const): Deleted.

  • page/WheelEventTestMonitor.cpp:

(WebCore::WheelEventTestMonitor::WheelEventTestMonitor):
(WebCore::WheelEventTestMonitor::clearAllTestDeferrals):
(WebCore::WheelEventTestMonitor::setTestCallbackAndStartMonitoring):
(WebCore::WheelEventTestMonitor::deferForReason):
(WebCore::WheelEventTestMonitor::removeDeferralForReason):
(WebCore::WheelEventTestMonitor::receivedWheelEvent):
(WebCore::WheelEventTestMonitor::scheduleCallbackCheck):
(WebCore::WheelEventTestMonitor::checkShouldFireCallbacks):
(WebCore::operator<<):
(WebCore::WheelEventTestMonitor::setTestCallbackAndStartNotificationTimer): Deleted.
(WebCore::WheelEventTestMonitor::triggerTestTimerFired): Deleted.

  • page/WheelEventTestMonitor.h:

(WebCore::WheelEventTestMonitorCompletionDeferrer::WheelEventTestMonitorCompletionDeferrer):
(WebCore::WheelEventTestMonitorCompletionDeferrer::~WheelEventTestMonitorCompletionDeferrer):

  • page/scrolling/AsyncScrollingCoordinator.cpp:

(WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated):
(WebCore::AsyncScrollingCoordinator::deferWheelEventTestCompletionForReason const): Deleted.
(WebCore::AsyncScrollingCoordinator::removeWheelEventTestCompletionDeferralForReason const): Deleted.

  • page/scrolling/AsyncScrollingCoordinator.h:
  • page/scrolling/ScrollingCoordinator.h:

(WebCore::ScrollingCoordinator::startMonitoringWheelEvents):
(WebCore::ScrollingCoordinator::stopMonitoringWheelEvents):

  • page/scrolling/ScrollingTree.cpp:

(WebCore::ScrollingTree::handleWheelEvent):

  • page/scrolling/ScrollingTree.h:

(WebCore::ScrollingTree::setWheelEventTestMonitor):
(WebCore::ScrollingTree::receivedWheelEvent):

  • page/scrolling/ThreadedScrollingTree.cpp:

(WebCore::ThreadedScrollingTree::scrollingTreeNodeDidScroll):
(WebCore::ThreadedScrollingTree::deferWheelEventTestCompletionForReason): Deleted.
(WebCore::ThreadedScrollingTree::removeWheelEventTestCompletionDeferralForReason): Deleted.

  • page/scrolling/ThreadedScrollingTree.h:
  • page/scrolling/mac/ScrollingCoordinatorMac.h:
  • page/scrolling/mac/ScrollingCoordinatorMac.mm:

(WebCore::ScrollingCoordinatorMac::startMonitoringWheelEvents):
(WebCore::ScrollingCoordinatorMac::stopMonitoringWheelEvents):

  • page/scrolling/mac/ScrollingTreeMac.h:
  • page/scrolling/mac/ScrollingTreeMac.mm:

(ScrollingTreeMac::setWheelEventTestMonitor):
(ScrollingTreeMac::receivedWheelEvent):
(ScrollingTreeMac::deferWheelEventTestCompletionForReason):
(ScrollingTreeMac::removeWheelEventTestCompletionDeferralForReason):

  • page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm:

(WebCore::ScrollingTreeScrollingNodeDelegateMac::deferWheelEventTestCompletionForReason const):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::removeWheelEventTestCompletionDeferralForReason const):

  • testing/js/WebCoreTestSupport.cpp:

(WebCoreTestSupport::setWheelEventMonitorTestCallbackAndStartMonitoring):
(WebCoreTestSupport::setTestCallbackAndStartNotificationTimer): Deleted.

  • testing/js/WebCoreTestSupport.h:

Source/WebKit:

Deflake tests using eventSender.monitorWheelEvents() by fixing several causes of flakiness,
adding back changes from r257844 that were reverted in r258558.

First, have EventSendingController keep track of whether it's seen then "end" event
for the scrolling and momentum phases, and pass this down to WheelEventTestMonitor, which
now waits until it sees these, which prevents premature triggering which was a common cause of
failure before.

Second, remove WheelEventTestMonitor's 1/60s timer and instead have WheelEventTestMonitor test
for completion in a callout from the end of Page::updateRendering(), which makes it test
and fire at a more consistent time.

Third, push WheelEventTestMonitor to the ScrollingTree, so that reasons for deferral
can be added on the scrolling thread. This fixes an issue where the RunLoop::main().dispatch()
used to send the "ScrollingThreadSyncNeeded" reason to the main thread would get delayed,
also resulting in a premature trigger.

  • WebProcess/InjectedBundle/API/c/WKBundlePage.cpp:

(WKBundlePageRegisterScrollOperationCompletionCallback):

  • WebProcess/InjectedBundle/API/c/WKBundlePage.h:

Tools:

Deflake tests using eventSender.monitorWheelEvents() by fixing several causes of flakiness,
adding back changes from r257844 that were reverted in r258558.

First, have EventSendingController keep track of whether it's seen then "end" event
for the scrolling and momentum phases, and pass this down to WheelEventTestMonitor, which
now waits until it sees these, which prevents premature triggering which was a common cause of
failure before.

Second, remove WheelEventTestMonitor's 1/60s timer and instead have WheelEventTestMonitor test
for completion in a callout from the end of Page::updateRendering(), which makes it test
and fire at a more consistent time.

Third, push WheelEventTestMonitor to the ScrollingTree, so that reasons for deferral
can be added on the scrolling thread. This fixes an issue where the RunLoop::main().dispatch()
used to send the "ScrollingThreadSyncNeeded" reason to the main thread would get delayed,
also resulting in a premature trigger.

  • DumpRenderTree/mac/EventSendingController.h:
  • DumpRenderTree/mac/EventSendingController.mm:

(-[EventSendingController mouseScrollByX:andY:withWheel:andMomentumPhases:]):
(-[EventSendingController monitorWheelEvents]):
(-[EventSendingController callAfterScrollingCompletes:]):

  • DumpRenderTree/win/EventSender.cpp:

(mouseScrollBy):

  • WebKitTestRunner/InjectedBundle/EventSendingController.cpp:

(WTR::EventSendingController::mouseScrollByWithWheelAndMomentumPhases):
(WTR::EventSendingController::monitorWheelEvents):
(WTR::EventSendingController::callAfterScrollingCompletes):

  • WebKitTestRunner/InjectedBundle/EventSendingController.h:

LayoutTests:

  • platform/mac-wk2/TestExpectations:
  • platform/win/TestExpectations:
  • tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-2d-overflow.html: Need to call eventSender.monitorWheelEvents()

for each subtest.

Location:
trunk
Files:
36 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r258674 r258679  
     12020-03-18  Simon Fraser  <simon.fraser@apple.com>
     2
     3        eventSender.monitorWheelEvents() is very fragile
     4        https://bugs.webkit.org/show_bug.cgi?id=197819
     5        <rdar://problem/51319456>
     6
     7        Reviewed by Tim Horton.
     8
     9        * platform/mac-wk2/TestExpectations:
     10        * platform/win/TestExpectations:
     11        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-2d-overflow.html: Need to call eventSender.monitorWheelEvents()
     12        for each subtest.
     13
    1142020-03-18  Said Abou-Hallawa  <sabouhallawa@apple.com>
    215
  • trunk/LayoutTests/platform/mac-wk2/TestExpectations

    r258649 r258679  
    10601060webkit.org/b/208062 http/wpt/fetch/disable-speculative-for-reload.html [ Pass Failure ]
    10611061
    1062 webkit.org/b/208160 fast/scrolling/overflow-scroll-past-max.html [ Pass Failure ]
    1063 
    10641062webkit.org/b/208222 [ Release ] imported/w3c/web-platform-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html [ Pass Failure ]
    10651063
  • trunk/LayoutTests/platform/win/TestExpectations

    r258613 r258679  
    277277fast/events/wheelevent-in-vertical-scrollbar-in-rtl.html [ Failure ]
    278278scrollbars/scroll-rtl-or-bt-layer.html [ Timeout ]
     279webkit.org/b/208559 fast/scrolling/arrow-key-scroll-in-rtl-document.html [ Skip ]
     280webkit.org/b/208559 fast/scrolling/programmatic-scroll-to-zero-zero.html [ Skip ]
    279281
    280282# TODO Needs testRunner.enableAutoResizeMode()
  • trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-2d-overflow.html

    r243359 r258679  
    5757                y: divTarget.scrollTop
    5858            };
     59
     60            eventSender.monitorWheelEvents();
    5961            eventSender.mouseMoveTo(100, 100);
    6062            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, "began", "none");
     
    8587            };
    8688
     89            eventSender.monitorWheelEvents();
    8790            eventSender.mouseMoveTo(100, 100);
    8891            eventSender.mouseScrollByWithWheelAndMomentumPhases(1, 1, "began", "none");
     
    109112            };
    110113
     114            eventSender.monitorWheelEvents();
    111115            eventSender.mouseMoveTo(100, 100);
    112116            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, -1, "began", "none");
     
    123127        function onLoad() {
    124128            if (window.eventSender) {
    125                 eventSender.monitorWheelEvents();
    126129                internals.setPlatformMomentumScrollingPredictionEnabled(false);
    127130                setTimeout(scrollGlideTest, 0);
  • trunk/Source/WebCore/ChangeLog

    r258676 r258679  
     12020-03-18  Simon Fraser  <simon.fraser@apple.com>
     2
     3        eventSender.monitorWheelEvents() is very fragile
     4        https://bugs.webkit.org/show_bug.cgi?id=197819
     5        <rdar://problem/51319456>
     6
     7        Reviewed by Tim Horton.
     8
     9        Deflake tests using eventSender.monitorWheelEvents() by fixing several causes of flakiness,
     10        adding back changes from r257844 that were reverted in r258558.
     11       
     12        First, have EventSendingController keep track of whether it's seen then "end" event
     13        for the scrolling and momentum phases, and pass this down to WheelEventTestMonitor, which
     14        now waits until it sees these, which prevents premature triggering which was a common cause of
     15        failure before.
     16       
     17        Second, remove WheelEventTestMonitor's 1/60s timer and instead have WheelEventTestMonitor test
     18        for completion in a callout from the end of Page::updateRendering(), which makes it test
     19        and fire at a more consistent time.
     20       
     21        Third, push WheelEventTestMonitor to the ScrollingTree, so that reasons for deferral
     22        can be added on the scrolling thread. This fixes an issue where the RunLoop::main().dispatch()
     23        used to send the "ScrollingThreadSyncNeeded" reason to the main thread would get delayed,
     24        also resulting in a premature trigger.
     25
     26        * Modules/applepay/ApplePaySession.cpp: Unified sources!
     27        * dom/WindowEventLoop.cpp: Unified sources!
     28        * page/EventHandler.cpp:
     29        (WebCore::EventHandler::handleWheelEvent):
     30        * page/FrameView.cpp:
     31        (WebCore::FrameView::scrollOffsetChangedViaPlatformWidgetImpl):
     32        * page/Page.cpp:
     33        (WebCore::Page::doAfterUpdateRendering):
     34        (WebCore::Page::wheelEventTestMonitor const):
     35        (WebCore::Page::clearWheelEventTestMonitor):
     36        (WebCore::Page::isMonitoringWheelEvents const):
     37        (WebCore::Page::ensureWheelEventTestMonitor):
     38        * page/Page.h:
     39        (WebCore::Page::wheelEventTestMonitor const): Deleted.
     40        (WebCore::Page::clearWheelEventTestMonitor): Deleted.
     41        (WebCore::Page::isMonitoringWheelEvents const): Deleted.
     42        * page/WheelEventTestMonitor.cpp:
     43        (WebCore::WheelEventTestMonitor::WheelEventTestMonitor):
     44        (WebCore::WheelEventTestMonitor::clearAllTestDeferrals):
     45        (WebCore::WheelEventTestMonitor::setTestCallbackAndStartMonitoring):
     46        (WebCore::WheelEventTestMonitor::deferForReason):
     47        (WebCore::WheelEventTestMonitor::removeDeferralForReason):
     48        (WebCore::WheelEventTestMonitor::receivedWheelEvent):
     49        (WebCore::WheelEventTestMonitor::scheduleCallbackCheck):
     50        (WebCore::WheelEventTestMonitor::checkShouldFireCallbacks):
     51        (WebCore::operator<<):
     52        (WebCore::WheelEventTestMonitor::setTestCallbackAndStartNotificationTimer): Deleted.
     53        (WebCore::WheelEventTestMonitor::triggerTestTimerFired): Deleted.
     54        * page/WheelEventTestMonitor.h:
     55        (WebCore::WheelEventTestMonitorCompletionDeferrer::WheelEventTestMonitorCompletionDeferrer):
     56        (WebCore::WheelEventTestMonitorCompletionDeferrer::~WheelEventTestMonitorCompletionDeferrer):
     57        * page/scrolling/AsyncScrollingCoordinator.cpp:
     58        (WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated):
     59        (WebCore::AsyncScrollingCoordinator::deferWheelEventTestCompletionForReason const): Deleted.
     60        (WebCore::AsyncScrollingCoordinator::removeWheelEventTestCompletionDeferralForReason const): Deleted.
     61        * page/scrolling/AsyncScrollingCoordinator.h:
     62        * page/scrolling/ScrollingCoordinator.h:
     63        (WebCore::ScrollingCoordinator::startMonitoringWheelEvents):
     64        (WebCore::ScrollingCoordinator::stopMonitoringWheelEvents):
     65        * page/scrolling/ScrollingTree.cpp:
     66        (WebCore::ScrollingTree::handleWheelEvent):
     67        * page/scrolling/ScrollingTree.h:
     68        (WebCore::ScrollingTree::setWheelEventTestMonitor):
     69        (WebCore::ScrollingTree::receivedWheelEvent):
     70        * page/scrolling/ThreadedScrollingTree.cpp:
     71        (WebCore::ThreadedScrollingTree::scrollingTreeNodeDidScroll):
     72        (WebCore::ThreadedScrollingTree::deferWheelEventTestCompletionForReason): Deleted.
     73        (WebCore::ThreadedScrollingTree::removeWheelEventTestCompletionDeferralForReason): Deleted.
     74        * page/scrolling/ThreadedScrollingTree.h:
     75        * page/scrolling/mac/ScrollingCoordinatorMac.h:
     76        * page/scrolling/mac/ScrollingCoordinatorMac.mm:
     77        (WebCore::ScrollingCoordinatorMac::startMonitoringWheelEvents):
     78        (WebCore::ScrollingCoordinatorMac::stopMonitoringWheelEvents):
     79        * page/scrolling/mac/ScrollingTreeMac.h:
     80        * page/scrolling/mac/ScrollingTreeMac.mm:
     81        (ScrollingTreeMac::setWheelEventTestMonitor):
     82        (ScrollingTreeMac::receivedWheelEvent):
     83        (ScrollingTreeMac::deferWheelEventTestCompletionForReason):
     84        (ScrollingTreeMac::removeWheelEventTestCompletionDeferralForReason):
     85        * page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm:
     86        (WebCore::ScrollingTreeScrollingNodeDelegateMac::deferWheelEventTestCompletionForReason const):
     87        (WebCore::ScrollingTreeScrollingNodeDelegateMac::removeWheelEventTestCompletionDeferralForReason const):
     88        * testing/js/WebCoreTestSupport.cpp:
     89        (WebCoreTestSupport::setWheelEventMonitorTestCallbackAndStartMonitoring):
     90        (WebCoreTestSupport::setTestCallbackAndStartNotificationTimer): Deleted.
     91        * testing/js/WebCoreTestSupport.h:
     92
    1932020-03-18  Fujii Hironori  <Hironori.Fujii@sony.com>
    294
  • trunk/Source/WebCore/Modules/applepay/ApplePaySession.cpp

    r252057 r258679  
    6464#include "UserGestureIndicator.h"
    6565#include <wtf/IsoMallocInlines.h>
     66#include <wtf/RunLoop.h>
    6667
    6768#if USE(APPLE_INTERNAL_SDK)
  • trunk/Source/WebCore/dom/WindowEventLoop.cpp

    r257199 r258679  
    3535#include "SecurityOrigin.h"
    3636#include "ThreadGlobalData.h"
     37#include <wtf/RunLoop.h>
    3738
    3839namespace WebCore {
  • trunk/Source/WebCore/page/EventHandler.cpp

    r258558 r258679  
    104104#include "WheelEvent.h"
    105105#include "WheelEventDeltaFilter.h"
     106#include "WheelEventTestMonitor.h"
    106107#include "WindowsKeyboardCodes.h"
    107108#include <wtf/Assertions.h>
     
    28262827#endif
    28272828
     2829#if PLATFORM(COCOA)
     2830    LOG_WITH_STREAM(WheelEventTestMonitor, stream << "EventHandler::handleWheelEvent on main thread, phase " << event.phase() << " momentum phase " << event.momentumPhase());
     2831    if (auto monitor = m_frame.page()->wheelEventTestMonitor())
     2832        monitor->receivedWheelEvent(event);
     2833
     2834    WheelEventTestMonitorCompletionDeferrer deferrer(m_frame.page()->wheelEventTestMonitor().get(), this, WheelEventTestMonitor::DeferReason::HandlingWheelEventOnMainThread);
     2835#endif
     2836
    28282837    m_isHandlingWheelEvent = true;
    28292838    setFrameWasScrolledByUser();
  • trunk/Source/WebCore/page/FrameView.cpp

    r258558 r258679  
    24462446void FrameView::scrollOffsetChangedViaPlatformWidgetImpl(const ScrollOffset& oldOffset, const ScrollOffset& newOffset)
    24472447{
     2448#if PLATFORM(COCOA)
     2449    WheelEventTestMonitorCompletionDeferrer deferrer(frame().page()->wheelEventTestMonitor().get(), this, WheelEventTestMonitor::DeferReason::ContentScrollInProgress);
     2450#endif
     2451
    24482452    updateLayerPositionsAfterScrolling();
    24492453    updateCompositingLayersAfterScrolling();
  • trunk/Source/WebCore/page/Page.cpp

    r258628 r258679  
    131131#include "VoidCallback.h"
    132132#include "WheelEventDeltaFilter.h"
     133#include "WheelEventTestMonitor.h"
    133134#include "Widget.h"
    134135#include <wtf/FileSystem.h>
     
    13901391        document->updateTouchEventRegions();
    13911392#endif
     1393
     1394    if (UNLIKELY(isMonitoringWheelEvents()))
     1395        wheelEventTestMonitor()->checkShouldFireCallbacks();
    13921396
    13931397#if ASSERT_ENABLED
     
    26222626#endif
    26232627
     2628RefPtr<WheelEventTestMonitor> Page::wheelEventTestMonitor() const
     2629{
     2630    return m_wheelEventTestMonitor;
     2631}
     2632
     2633void Page::clearWheelEventTestMonitor()
     2634{
     2635    if (m_scrollingCoordinator)
     2636        m_scrollingCoordinator->stopMonitoringWheelEvents();
     2637
     2638    m_wheelEventTestMonitor = nullptr;
     2639}
     2640
     2641bool Page::isMonitoringWheelEvents() const
     2642{
     2643    return !!m_wheelEventTestMonitor;
     2644}
     2645
    26242646WheelEventTestMonitor& Page::ensureWheelEventTestMonitor()
    26252647{
    26262648    if (!m_wheelEventTestMonitor) {
    2627         m_wheelEventTestMonitor = adoptRef(new WheelEventTestMonitor());
     2649        m_wheelEventTestMonitor = adoptRef(new WheelEventTestMonitor(*this));
    26282650        // We need to update the scrolling coordinator so that the mainframe scrolling node can expect wheel event test triggers.
    26292651        if (auto* frameView = mainFrame().view()) {
    2630             if (m_scrollingCoordinator)
     2652            if (m_scrollingCoordinator) {
     2653                m_scrollingCoordinator->startMonitoringWheelEvents();
    26312654                m_scrollingCoordinator->updateIsMonitoringWheelEventsForFrameView(*frameView);
     2655            }
    26322656        }
    26332657    }
  • trunk/Source/WebCore/page/Page.h

    r258528 r258679  
    4141#include "ViewportArguments.h"
    4242#include "VisibilityState.h"
    43 #include "WheelEventTestMonitor.h"
    4443#include <memory>
    4544#include <pal/SessionID.h>
     
    148147class WebGLStateTracker;
    149148class WheelEventDeltaFilter;
     149class WheelEventTestMonitor;
    150150
    151151using SharedStringHash = uint32_t;
     
    650650#endif
    651651
    652     RefPtr<WheelEventTestMonitor> wheelEventTestMonitor() const { return m_wheelEventTestMonitor; }
     652    WEBCORE_EXPORT RefPtr<WheelEventTestMonitor> wheelEventTestMonitor() const;
    653653    WEBCORE_EXPORT WheelEventTestMonitor& ensureWheelEventTestMonitor();
    654     void clearWheelEventTestMonitor() { m_wheelEventTestMonitor = nullptr; }
    655     bool isMonitoringWheelEvents() const { return !!m_wheelEventTestMonitor; }
     654    WEBCORE_EXPORT void clearWheelEventTestMonitor();
     655    WEBCORE_EXPORT bool isMonitoringWheelEvents() const;
    656656
    657657#if ENABLE(VIDEO)
  • trunk/Source/WebCore/page/WheelEventTestMonitor.cpp

    r258558 r258679  
    3131
    3232#include "Logging.h"
     33#include "Page.h"
    3334#include <wtf/OptionSet.h>
     35#include <wtf/RunLoop.h>
    3436#include <wtf/text/TextStream.h>
    3537
     
    4143namespace WebCore {
    4244
    43 WheelEventTestMonitor::WheelEventTestMonitor()
    44     : m_testForCompletionTimer(RunLoop::current(), this, &WheelEventTestMonitor::triggerTestTimerFired)
     45WheelEventTestMonitor::WheelEventTestMonitor(Page& page)
     46    : m_page(page)
    4547{
    4648}
     
    4850void WheelEventTestMonitor::clearAllTestDeferrals()
    4951{
     52    LockHolder lock(m_mutex);
     53
    5054    ASSERT(isMainThread());
    5155    m_deferCompletionReasons.clear();
    5256    m_completionCallback = nullptr;
    53     m_testForCompletionTimer.stop();
    54     LOG_WITH_STREAM(WheelEventTestMonitor, stream << "      (=) WheelEventTestMonitor::clearAllTestDeferrals: cleared all test state.");
     57    m_everHadDeferral = false;
     58    m_receivedWheelEndOrCancel = false;
     59    m_receivedMomentumEnd = false;
     60    LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::clearAllTestDeferrals: cleared all test state.");
    5561}
    5662
    57 void WheelEventTestMonitor::setTestCallbackAndStartNotificationTimer(WTF::Function<void()>&& functionCallback)
     63void WheelEventTestMonitor::setTestCallbackAndStartMonitoring(bool expectWheelEndOrCancel, bool expectMomentumEnd, WTF::Function<void()>&& functionCallback)
    5864{
    5965    ASSERT(isMainThread());
    6066    m_completionCallback = WTFMove(functionCallback);
    61    
    62     if (!m_testForCompletionTimer.isActive())
    63         m_testForCompletionTimer.startRepeating(1_s / 60.);
     67#if ENABLE(KINETIC_SCROLLING)
     68    m_expectWheelEndOrCancel = expectWheelEndOrCancel;
     69    m_expectMomentumEnd = expectMomentumEnd;
     70#else
     71    UNUSED_PARAM(expectWheelEndOrCancel);
     72    UNUSED_PARAM(expectMomentumEnd);
     73#endif
     74
     75    LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::setTestCallbackAndStartMonitoring - expect end/cancel " << expectWheelEndOrCancel << ", expect momenum end " << expectMomentumEnd);
    6476}
    6577
    6678void WheelEventTestMonitor::deferForReason(ScrollableAreaIdentifier identifier, DeferReason reason)
    6779{
    68     ASSERT(isMainThread());
     80    LockHolder lock(m_mutex);
     81
    6982    m_deferCompletionReasons.ensure(identifier, [] {
    7083        return OptionSet<DeferReason>();
    7184    }).iterator->value.add(reason);
    72    
     85
     86    m_everHadDeferral = true;
     87
    7388    LOG_WITH_STREAM(WheelEventTestMonitor, stream << "      (=) WheelEventTestMonitor::deferForReason: id=" << identifier << ", reason=" << reason);
    7489}
     
    7691void WheelEventTestMonitor::removeDeferralForReason(ScrollableAreaIdentifier identifier, DeferReason reason)
    7792{
    78     ASSERT(isMainThread());
     93    LockHolder lock(m_mutex);
     94
    7995    auto it = m_deferCompletionReasons.find(identifier);
    8096    if (it == m_deferCompletionReasons.end())
     
    86102    if (it->value.isEmpty())
    87103        m_deferCompletionReasons.remove(it);
     104
     105    scheduleCallbackCheck();
    88106}
    89    
    90 void WheelEventTestMonitor::triggerTestTimerFired()
     107
     108void WheelEventTestMonitor::receivedWheelEvent(const PlatformWheelEvent& event)
    91109{
    92     ASSERT(isMainThread());
    93     if (!m_deferCompletionReasons.isEmpty()) {
    94         LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::triggerTestTimerFired - scrolling still active, reasons " << m_deferCompletionReasons);
     110#if ENABLE(KINETIC_SCROLLING)
     111    if (event.phase() == PlatformWheelEventPhaseEnded || event.phase() == PlatformWheelEventPhaseCancelled)
     112        m_receivedWheelEndOrCancel = true;
     113
     114    if (event.momentumPhase() == PlatformWheelEventPhaseEnded)
     115        m_receivedMomentumEnd = true;
     116#endif
     117}
     118
     119void WheelEventTestMonitor::scheduleCallbackCheck()
     120{
     121    if (isMainThread()) {
     122        m_page.scheduleRenderingUpdate();
    95123        return;
    96124    }
    97125
    98     auto functionCallback = WTFMove(m_completionCallback);
    99     m_testForCompletionTimer.stop();
     126    RunLoop::main().dispatch([weakPage = makeWeakPtr(m_page)] {
     127        if (weakPage)
     128            weakPage->scheduleRenderingUpdate();
     129    });
     130}
    100131
    101     LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::triggerTestTimerFired: scrolling is idle, FIRING TEST");
    102     if (functionCallback)
     132void WheelEventTestMonitor::checkShouldFireCallbacks()
     133{
     134    ASSERT(isMainThread());
     135    {
     136        LockHolder lock(m_mutex);
     137
     138        if (!m_deferCompletionReasons.isEmpty()) {
     139            LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::checkShouldFireCallbacks - scrolling still active, reasons " << m_deferCompletionReasons);
     140            return;
     141        }
     142
     143        if (!m_everHadDeferral) {
     144            LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::checkShouldFireCallbacks - have not yet seen any deferral reasons");
     145            return;
     146        }
     147       
     148        if (m_expectWheelEndOrCancel && !m_receivedWheelEndOrCancel) {
     149            LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::checkShouldFireCallbacks - have not seen end of of wheel phase");
     150            return;
     151        }
     152
     153        if (m_expectMomentumEnd && !m_receivedMomentumEnd) {
     154            LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::checkShouldFireCallbacks - have not seen end of of momentum phase");
     155            return;
     156        }
     157    }
     158
     159    if (auto functionCallback = WTFMove(m_completionCallback)) {
     160        LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::checkShouldFireCallbacks: scrolling is idle, FIRING TEST");
    103161        functionCallback();
     162    } else
     163        LOG_WITH_STREAM(WheelEventTestMonitor, stream << "  WheelEventTestMonitor::checkShouldFireCallbacks - no callback");
    104164}
    105165
     
    108168    switch (reason) {
    109169    case WheelEventTestMonitor::HandlingWheelEvent: ts << "handling wheel event"; break;
     170    case WheelEventTestMonitor::HandlingWheelEventOnMainThread: ts << "handling wheel event on main thread"; break;
    110171    case WheelEventTestMonitor::RubberbandInProgress: ts << "rubberbanding"; break;
    111172    case WheelEventTestMonitor::ScrollSnapInProgress: ts << "scroll-snapping"; break;
  • trunk/Source/WebCore/page/WheelEventTestMonitor.h

    r258558 r258679  
    2929#pragma once
    3030
     31#include "PlatformWheelEvent.h"
    3132#include <functional>
    3233#include <wtf/Function.h>
    3334#include <wtf/HashMap.h>
    3435#include <wtf/Lock.h>
    35 #include <wtf/RunLoop.h>
    36 #include <wtf/StdSet.h>
    3736#include <wtf/ThreadSafeRefCounted.h>
    3837
    3938namespace WebCore {
    4039
     40class Page;
     41
    4142class WheelEventTestMonitor : public ThreadSafeRefCounted<WheelEventTestMonitor> {
    4243    WTF_MAKE_NONCOPYABLE(WheelEventTestMonitor); WTF_MAKE_FAST_ALLOCATED;
    4344public:
    44     WheelEventTestMonitor();
     45    WheelEventTestMonitor(Page&);
    4546
    46     WEBCORE_EXPORT void setTestCallbackAndStartNotificationTimer(WTF::Function<void()>&&);
     47    WEBCORE_EXPORT void setTestCallbackAndStartMonitoring(bool expectWheelEndOrCancel, bool expectMomentumEnd, WTF::Function<void()>&&);
    4748    WEBCORE_EXPORT void clearAllTestDeferrals();
    4849   
    4950    enum DeferReason {
    50         HandlingWheelEvent          = 1 << 0,
    51         RubberbandInProgress        = 1 << 1,
    52         ScrollSnapInProgress        = 1 << 2,
    53         ScrollingThreadSyncNeeded   = 1 << 3,
    54         ContentScrollInProgress     = 1 << 4,
     51        HandlingWheelEvent              = 1 << 0,
     52        HandlingWheelEventOnMainThread  = 1 << 1,
     53        RubberbandInProgress            = 1 << 2,
     54        ScrollSnapInProgress            = 1 << 3,
     55        ScrollingThreadSyncNeeded       = 1 << 4,
     56        ContentScrollInProgress         = 1 << 5,
    5557    };
    5658    typedef const void* ScrollableAreaIdentifier;
    5759
     60    WEBCORE_EXPORT void receivedWheelEvent(const PlatformWheelEvent&);
    5861    WEBCORE_EXPORT void deferForReason(ScrollableAreaIdentifier, DeferReason);
    5962    WEBCORE_EXPORT void removeDeferralForReason(ScrollableAreaIdentifier, DeferReason);
    6063   
    61     void triggerTestTimerFired();
     64    void checkShouldFireCallbacks();
    6265
    6366    using ScrollableAreaReasonMap = WTF::HashMap<ScrollableAreaIdentifier, OptionSet<DeferReason>>;
    6467
    6568private:
     69    void scheduleCallbackCheck();
     70
    6671    WTF::Function<void()> m_completionCallback;
    67     RunLoop::Timer<WheelEventTestMonitor> m_testForCompletionTimer;
     72    Page& m_page;
    6873
     74    Lock m_mutex;
    6975    ScrollableAreaReasonMap m_deferCompletionReasons;
     76    bool m_expectWheelEndOrCancel { false };
     77    bool m_receivedWheelEndOrCancel { false };
     78    bool m_expectMomentumEnd { false };
     79    bool m_receivedMomentumEnd { false };
     80    bool m_everHadDeferral { false };
     81};
     82
     83class WheelEventTestMonitorCompletionDeferrer {
     84public:
     85    WheelEventTestMonitorCompletionDeferrer(WheelEventTestMonitor* monitor, WheelEventTestMonitor::ScrollableAreaIdentifier identifier, WheelEventTestMonitor::DeferReason reason)
     86        : m_monitor(monitor)
     87        , m_identifier(identifier)
     88        , m_reason(reason)
     89    {
     90        if (m_monitor)
     91            m_monitor->deferForReason(m_identifier, m_reason);
     92    }
     93   
     94    ~WheelEventTestMonitorCompletionDeferrer()
     95    {
     96        if (m_monitor)
     97            m_monitor->removeDeferralForReason(m_identifier, m_reason);
     98    }
     99
     100private:
     101    RefPtr<WheelEventTestMonitor> m_monitor;
     102    WheelEventTestMonitor::ScrollableAreaIdentifier m_identifier;
     103    WheelEventTestMonitor::DeferReason m_reason;
    70104};
    71105
  • trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp

    r258098 r258679  
    139139    auto* page = frameView.frame().page();
    140140    if (page && page->isMonitoringWheelEvents()) {
    141         LOG_WITH_STREAM(WheelEventTestMonitor, stream << "    AsyncScrollingCoordinator::frameViewLayoutUpdated: Expects wheel event test trigger: " << page->isMonitoringWheelEvents());
    142 
    143141        auto* node = m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID());
    144142        if (!is<ScrollingStateFrameScrollingNode>(node))
     
    827825}
    828826
    829 void AsyncScrollingCoordinator::deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier identifier, WheelEventTestMonitor::DeferReason reason) const
    830 {
    831     ASSERT(isMainThread());
    832     if (!m_page || !m_page->isMonitoringWheelEvents())
    833         return;
    834 
    835     if (const auto& trigger = m_page->wheelEventTestMonitor()) {
    836         LOG_WITH_STREAM(WheelEventTestMonitor, stream << "    (!) AsyncScrollingCoordinator::deferForReason: Deferring " << identifier << " for reason " << reason);
    837         trigger->deferForReason(identifier, reason);
    838     }
    839 }
    840 
    841 void AsyncScrollingCoordinator::removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier identifier, WheelEventTestMonitor::DeferReason reason) const
    842 {
    843     ASSERT(isMainThread());
    844     if (!m_page || !m_page->isMonitoringWheelEvents())
    845         return;
    846 
    847     if (const auto& trigger = m_page->wheelEventTestMonitor()) {
    848         LOG_WITH_STREAM(WheelEventTestMonitor, stream << "    (!) AsyncScrollingCoordinator::removeWheelEventTestCompletionDeferralForReason: Deferring " << identifier << " for reason " << reason);
    849         trigger->removeDeferralForReason(identifier, reason);
    850     }
    851 }
    852827#endif
    853828
  • trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h

    r258098 r258679  
    5656#if PLATFORM(COCOA)
    5757    WEBCORE_EXPORT void setActiveScrollSnapIndices(ScrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex);
    58     void deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) const;
    59     void removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) const;
    6058#endif
    6159
  • trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h

    r258098 r258679  
    181181    virtual void updateIsMonitoringWheelEventsForFrameView(const FrameView&) { }
    182182
     183    virtual void startMonitoringWheelEvents() { }
     184    virtual void stopMonitoringWheelEvents() { }
     185
    183186protected:
    184187    explicit ScrollingCoordinator(Page*);
  • trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp

    r258055 r258679  
    9797    LockHolder locker(m_treeMutex);
    9898
     99    if (isMonitoringWheelEvents())
     100        receivedWheelEvent(wheelEvent);
     101
    99102    if (!asyncFrameOrOverflowScrollingEnabled()) {
    100103        if (m_rootNode)
  • trunk/Source/WebCore/page/scrolling/ScrollingTree.h

    r258044 r258679  
    3434#include <wtf/HashMap.h>
    3535#include <wtf/Lock.h>
     36#include <wtf/MonotonicTime.h>
    3637#include <wtf/ThreadSafeRefCounted.h>
    3738#include <wtf/TypeCasts.h>
     
    108109    virtual void setActiveScrollSnapIndices(ScrollingNodeID, unsigned /*horizontalIndex*/, unsigned /*verticalIndex*/) { }
    109110
     111    virtual void setWheelEventTestMonitor(RefPtr<WheelEventTestMonitor>&&) { }
     112
    110113    virtual void deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) { }
    111114    virtual void removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) { }
     
    179182
    180183    WEBCORE_EXPORT virtual RefPtr<ScrollingTreeNode> scrollingNodeForPoint(FloatPoint);
     184    virtual void receivedWheelEvent(const PlatformWheelEvent&) { }
    181185
    182186    Lock m_treeMutex; // Protects the scrolling tree.
  • trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp

    r257996 r258679  
    100100
    101101    auto scrollPosition = node.currentScrollPosition();
    102 
    103102    if (node.isRootNode())
    104103        setMainFrameScrollPosition(scrollPosition);
     
    117116        deferWheelEventTestCompletionForReason(reinterpret_cast<WheelEventTestMonitor::ScrollableAreaIdentifier>(node.scrollingNodeID()), WheelEventTestMonitor::ScrollingThreadSyncNeeded);
    118117#endif
    119     RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, nodeID = node.scrollingNodeID(), scrollPosition, layoutViewportOrigin, scrollingLayerPositionAction, monitoringWheelEvents] {
    120         scrollingCoordinator->scheduleUpdateScrollPositionAfterAsyncScroll(nodeID, scrollPosition, layoutViewportOrigin, scrollingLayerPositionAction);
     118
     119    RunLoop::main().dispatch([strongThis = makeRef(*this), nodeID = node.scrollingNodeID(), scrollPosition, layoutViewportOrigin, scrollingLayerPositionAction, monitoringWheelEvents] {
     120        strongThis->m_scrollingCoordinator->scheduleUpdateScrollPositionAfterAsyncScroll(nodeID, scrollPosition, layoutViewportOrigin, scrollingLayerPositionAction);
    121121#if PLATFORM(MAC)
    122122        if (monitoringWheelEvents)
    123             scrollingCoordinator->removeWheelEventTestCompletionDeferralForReason(reinterpret_cast<WheelEventTestMonitor::ScrollableAreaIdentifier>(nodeID), WheelEventTestMonitor::ScrollingThreadSyncNeeded);
     123            strongThis->removeWheelEventTestCompletionDeferralForReason(reinterpret_cast<WheelEventTestMonitor::ScrollableAreaIdentifier>(nodeID), WheelEventTestMonitor::ScrollingThreadSyncNeeded);
    124124#else
    125125        UNUSED_PARAM(monitoringWheelEvents);
     
    204204}
    205205
    206 void ThreadedScrollingTree::deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier identifier, WheelEventTestMonitor::DeferReason reason)
    207 {
    208     if (!m_scrollingCoordinator)
    209         return;
    210 
    211     RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, identifier, reason] {
    212         scrollingCoordinator->deferWheelEventTestCompletionForReason(identifier, reason);
    213     });
    214 }
    215 
    216 void ThreadedScrollingTree::removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier identifier, WheelEventTestMonitor::DeferReason reason)
    217 {
    218     if (!m_scrollingCoordinator)
    219         return;
    220    
    221     RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, identifier, reason] {
    222         scrollingCoordinator->removeWheelEventTestCompletionDeferralForReason(identifier, reason);
    223     });
    224 }
    225 
    226206#endif
    227207
  • trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h

    r257996 r258679  
    6666    void handleWheelEventPhase(PlatformWheelEventPhase) override;
    6767    void setActiveScrollSnapIndices(ScrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex) override;
    68 
    69     void deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) override;
    70     void removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) override;
    7168#endif
    7269
  • trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h

    r258541 r258679  
    4848
    4949    void updateTiledScrollingIndicator();
     50
     51    void startMonitoringWheelEvents() final;
     52    void stopMonitoringWheelEvents() final;
    5053};
    5154
  • trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm

    r258541 r258679  
    137137}
    138138
     139void ScrollingCoordinatorMac::startMonitoringWheelEvents()
     140{
     141    auto monitor = m_page->wheelEventTestMonitor();
     142    scrollingTree()->setWheelEventTestMonitor(WTFMove(monitor));
     143}
     144
     145void ScrollingCoordinatorMac::stopMonitoringWheelEvents()
     146{
     147    scrollingTree()->setWheelEventTestMonitor(nullptr);
     148}
     149
    139150} // namespace WebCore
    140151
  • trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.h

    r258044 r258679  
    3232namespace WebCore {
    3333
     34class WheelEventTestMonitor;
     35
    3436class ScrollingTreeMac final : public ThreadedScrollingTree {
    3537public:
     
    4345    RefPtr<ScrollingTreeNode> scrollingNodeForPoint(FloatPoint) final;
    4446
     47    void setWheelEventTestMonitor(RefPtr<WheelEventTestMonitor>&&) final;
     48
     49    void receivedWheelEvent(const PlatformWheelEvent&) final;
     50
     51    void deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) final;
     52    void removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) final;
     53
    4554    void lockLayersForHitTesting() final;
    4655    void unlockLayersForHitTesting() final;
     
    4857    // This lock protects the CALayer/PlatformCALayer tree.
    4958    Lock m_layerHitTestMutex;
     59   
     60    RefPtr<WheelEventTestMonitor> m_wheelEventTestMonitor;
    5061};
    5162
  • trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.mm

    r258044 r258679  
    2727#include "ScrollingTreeMac.h"
    2828
     29#include "Logging.h"
    2930#include "PlatformCALayer.h"
    3031#include "ScrollingTreeFixedNode.h"
     
    3637#include "ScrollingTreeStickyNode.h"
    3738#include "WebLayer.h"
     39#include "WheelEventTestMonitor.h"
     40#include <wtf/text/TextStream.h>
    3841
    3942#if ENABLE(ASYNC_SCROLLING) && ENABLE(SCROLLING_THREAD)
     
    189192}
    190193
     194void ScrollingTreeMac::setWheelEventTestMonitor(RefPtr<WheelEventTestMonitor>&& monitor)
     195{
     196    m_wheelEventTestMonitor = WTFMove(monitor);
     197}
     198
     199void ScrollingTreeMac::receivedWheelEvent(const PlatformWheelEvent& event)
     200{
     201    auto monitor = m_wheelEventTestMonitor;
     202    if (monitor)
     203        monitor->receivedWheelEvent(event);
     204}
     205
     206void ScrollingTreeMac::deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier identifier, WheelEventTestMonitor::DeferReason reason)
     207{
     208    auto monitor = m_wheelEventTestMonitor;
     209    if (!monitor)
     210        return;
     211
     212    LOG_WITH_STREAM(WheelEventTestMonitor, stream << "    (!) ScrollingTreeMac::deferForReason: Deferring on " << identifier << " for reason " << reason);
     213    monitor->deferForReason(identifier, reason);
     214}
     215
     216void ScrollingTreeMac::removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier identifier, WheelEventTestMonitor::DeferReason reason)
     217{
     218    auto monitor = m_wheelEventTestMonitor;
     219    if (!monitor)
     220        return;
     221
     222    LOG_WITH_STREAM(WheelEventTestMonitor, stream << "    (!) ScrollingTreeMac::removeDeferralForReason: Removing deferral on " << identifier << " for reason " << reason);
     223    monitor->removeDeferralForReason(identifier, reason);
     224}
     225
    191226#endif // ENABLE(ASYNC_SCROLLING) && ENABLE(SCROLLING_THREAD)
  • trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm

    r255037 r258679  
    308308        return;
    309309
    310     LOG_WITH_STREAM(WheelEventTestMonitor, stream << isMainThread() << "  ScrollingTreeScrollingNodeDelegateMac::deferForReason: STARTING deferral for " << identifier << " because of " << reason);
    311310    scrollingTree().deferWheelEventTestCompletionForReason(identifier, reason);
    312311}
     
    317316        return;
    318317   
    319     LOG_WITH_STREAM(WheelEventTestMonitor, stream << isMainThread() << "  ScrollingTreeScrollingNodeDelegateMac::deferForReason: ENDING deferral for " << identifier << " because of " << reason);
    320318    scrollingTree().removeWheelEventTestCompletionDeferralForReason(identifier, reason);
    321319}
  • trunk/Source/WebCore/testing/js/WebCoreTestSupport.cpp

    r258044 r258679  
    8989}
    9090
    91 void setTestCallbackAndStartNotificationTimer(WebCore::Frame& frame, JSContextRef context, JSObjectRef jsCallbackFunction)
     91void setWheelEventMonitorTestCallbackAndStartMonitoring(bool expectWheelEndOrCancel, bool expectMomentumEnd, WebCore::Frame& frame, JSContextRef context, JSObjectRef jsCallbackFunction)
    9292{
    9393    Page* page = frame.page();
     
    9797    JSValueProtect(context, jsCallbackFunction);
    9898   
    99     page->ensureWheelEventTestMonitor().setTestCallbackAndStartNotificationTimer([=](void) {
     99    page->ensureWheelEventTestMonitor().setTestCallbackAndStartMonitoring(expectWheelEndOrCancel, expectMomentumEnd, [=](void) {
    100100        JSObjectCallAsFunction(context, jsCallbackFunction, nullptr, 0, nullptr, nullptr);
    101101        JSValueUnprotect(context, jsCallbackFunction);
  • trunk/Source/WebCore/testing/js/WebCoreTestSupport.h

    r256215 r258679  
    4848void resetInternalsObject(JSContextRef) TEST_SUPPORT_EXPORT;
    4949void monitorWheelEvents(WebCore::Frame&) TEST_SUPPORT_EXPORT;
    50 void setTestCallbackAndStartNotificationTimer(WebCore::Frame&, JSContextRef, JSObjectRef) TEST_SUPPORT_EXPORT;
     50void setWheelEventMonitorTestCallbackAndStartMonitoring(bool expectWheelEndOrCancel, bool expectMomentumEnd, WebCore::Frame&, JSContextRef, JSObjectRef) TEST_SUPPORT_EXPORT;
    5151void clearWheelEventTestMonitor(WebCore::Frame&) TEST_SUPPORT_EXPORT;
    5252
  • trunk/Source/WebKit/ChangeLog

    r258678 r258679  
     12020-03-18  Simon Fraser  <simon.fraser@apple.com>
     2
     3        eventSender.monitorWheelEvents() is very fragile
     4        https://bugs.webkit.org/show_bug.cgi?id=197819
     5        <rdar://problem/51319456>
     6
     7        Reviewed by Tim Horton.
     8
     9        Deflake tests using eventSender.monitorWheelEvents() by fixing several causes of flakiness,
     10        adding back changes from r257844 that were reverted in r258558.
     11       
     12        First, have EventSendingController keep track of whether it's seen then "end" event
     13        for the scrolling and momentum phases, and pass this down to WheelEventTestMonitor, which
     14        now waits until it sees these, which prevents premature triggering which was a common cause of
     15        failure before.
     16       
     17        Second, remove WheelEventTestMonitor's 1/60s timer and instead have WheelEventTestMonitor test
     18        for completion in a callout from the end of Page::updateRendering(), which makes it test
     19        and fire at a more consistent time.
     20       
     21        Third, push WheelEventTestMonitor to the ScrollingTree, so that reasons for deferral
     22        can be added on the scrolling thread. This fixes an issue where the RunLoop::main().dispatch()
     23        used to send the "ScrollingThreadSyncNeeded" reason to the main thread would get delayed,
     24        also resulting in a premature trigger.
     25
     26        * WebProcess/InjectedBundle/API/c/WKBundlePage.cpp:
     27        (WKBundlePageRegisterScrollOperationCompletionCallback):
     28        * WebProcess/InjectedBundle/API/c/WKBundlePage.h:
     29
    1302020-03-18  Alex Christensen  <achristensen@webkit.org>
    231
  • trunk/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp

    r258663 r258679  
    705705}
    706706
    707 bool WKBundlePageRegisterScrollOperationCompletionCallback(WKBundlePageRef pageRef, WKBundlePageTestNotificationCallback callback, void* context)
     707bool WKBundlePageRegisterScrollOperationCompletionCallback(WKBundlePageRef pageRef, WKBundlePageTestNotificationCallback callback, bool expectWheelEndOrCancel, bool expectMomentumEnd, void* context)
    708708{
    709709    if (!callback)
     
    715715        return false;
    716716   
    717     page->ensureWheelEventTestMonitor().setTestCallbackAndStartNotificationTimer([=]() {
     717    page->ensureWheelEventTestMonitor().setTestCallbackAndStartMonitoring(expectWheelEndOrCancel, expectMomentumEnd, [=]() {
    718718        callback(context);
    719719    });
  • trunk/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.h

    r239719 r258679  
    122122typedef void (*WKBundlePageTestNotificationCallback)(void* context);
    123123// Returns true  if the callback function will be called, else false.
    124 WK_EXPORT bool WKBundlePageRegisterScrollOperationCompletionCallback(WKBundlePageRef, WKBundlePageTestNotificationCallback, void* context);
     124WK_EXPORT bool WKBundlePageRegisterScrollOperationCompletionCallback(WKBundlePageRef, WKBundlePageTestNotificationCallback, bool expectWheelEndOrCancel, bool expectMomentumEnd, void* context);
    125125
    126126// Call the given callback after both a postTask() on the page's document's ScriptExecutionContext, and a zero-delay timer.
  • trunk/Tools/ChangeLog

    r258672 r258679  
     12020-03-18  Simon Fraser  <simon.fraser@apple.com>
     2
     3        eventSender.monitorWheelEvents() is very fragile
     4        https://bugs.webkit.org/show_bug.cgi?id=197819
     5        <rdar://problem/51319456>
     6
     7        Reviewed by Tim Horton.
     8
     9        Deflake tests using eventSender.monitorWheelEvents() by fixing several causes of flakiness,
     10        adding back changes from r257844 that were reverted in r258558.
     11       
     12        First, have EventSendingController keep track of whether it's seen then "end" event
     13        for the scrolling and momentum phases, and pass this down to WheelEventTestMonitor, which
     14        now waits until it sees these, which prevents premature triggering which was a common cause of
     15        failure before.
     16       
     17        Second, remove WheelEventTestMonitor's 1/60s timer and instead have WheelEventTestMonitor test
     18        for completion in a callout from the end of Page::updateRendering(), which makes it test
     19        and fire at a more consistent time.
     20       
     21        Third, push WheelEventTestMonitor to the ScrollingTree, so that reasons for deferral
     22        can be added on the scrolling thread. This fixes an issue where the RunLoop::main().dispatch()
     23        used to send the "ScrollingThreadSyncNeeded" reason to the main thread would get delayed,
     24        also resulting in a premature trigger.
     25
     26        * DumpRenderTree/mac/EventSendingController.h:
     27        * DumpRenderTree/mac/EventSendingController.mm:
     28        (-[EventSendingController mouseScrollByX:andY:withWheel:andMomentumPhases:]):
     29        (-[EventSendingController monitorWheelEvents]):
     30        (-[EventSendingController callAfterScrollingCompletes:]):
     31        * DumpRenderTree/win/EventSender.cpp:
     32        (mouseScrollBy):
     33        * WebKitTestRunner/InjectedBundle/EventSendingController.cpp:
     34        (WTR::EventSendingController::mouseScrollByWithWheelAndMomentumPhases):
     35        (WTR::EventSendingController::monitorWheelEvents):
     36        (WTR::EventSendingController::callAfterScrollingCompletes):
     37        * WebKitTestRunner/InjectedBundle/EventSendingController.h:
     38
    1392020-03-18  John Wilander  <wilander@apple.com>
    240
  • trunk/Tools/DumpRenderTree/mac/EventSendingController.h

    r257161 r258679  
    3939    int eventNumber;
    4040    double timeOffset;
     41#if PLATFORM(MAC)
     42    BOOL _sentWheelPhaseEndOrCancel;
     43    BOOL _sentMomentumPhaseEnd;
     44#endif
    4145#if PLATFORM(IOS_FAMILY)
    4246    NSMutableArray* touches;
  • trunk/Tools/DumpRenderTree/mac/EventSendingController.mm

    r258558 r258679  
    853853{
    854854#if PLATFORM(MAC)
     855    [[[mainFrame frameView] documentView] layout];
     856
    855857    uint32_t phase = 0;
    856858    if ([phaseName isEqualToString: @"none"])
    857859        phase = 0;
    858860    else if ([phaseName isEqualToString: @"began"])
    859         phase = 1; // kCGScrollPhaseBegan
     861        phase = kCGScrollPhaseBegan;
    860862    else if ([phaseName isEqualToString: @"changed"])
    861         phase = 2; // kCGScrollPhaseChanged;
     863        phase = kCGScrollPhaseChanged;
    862864    else if ([phaseName isEqualToString: @"ended"])
    863         phase = 4; // kCGScrollPhaseEnded
     865        phase = kCGScrollPhaseEnded;
    864866    else if ([phaseName isEqualToString: @"cancelled"])
    865         phase = 8; // kCGScrollPhaseCancelled
     867        phase = kCGScrollPhaseCancelled;
    866868    else if ([phaseName isEqualToString: @"maybegin"])
    867         phase = 128; // kCGScrollPhaseMayBegin
     869        phase = kCGScrollPhaseMayBegin;
    868870
    869871    uint32_t momentum = 0;
    870872    if ([momentumName isEqualToString: @"none"])
    871         momentum = 0; //kCGMomentumScrollPhaseNone;
     873        momentum = kCGMomentumScrollPhaseNone;
    872874    else if ([momentumName isEqualToString:@"begin"])
    873         momentum = 1; // kCGMomentumScrollPhaseBegin;
     875        momentum = kCGMomentumScrollPhaseBegin;
    874876    else if ([momentumName isEqualToString:@"continue"])
    875         momentum = 2; // kCGMomentumScrollPhaseContinue;
     877        momentum = kCGMomentumScrollPhaseContinue;
    876878    else if ([momentumName isEqualToString:@"end"])
    877         momentum = 3; // kCGMomentumScrollPhaseEnd;
     879        momentum = kCGMomentumScrollPhaseEnd;
     880
     881    if (phase == kCGScrollPhaseEnded || phase == kCGScrollPhaseCancelled)
     882        _sentWheelPhaseEndOrCancel = YES;
     883
     884    if (momentum == kCGMomentumScrollPhaseEnd)
     885        _sentMomentumPhaseEnd = YES;
    878886
    879887    CGEventRef cgScrollEvent = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitLine, 2, y, x);
     
    13881396        return;
    13891397
     1398    _sentWheelPhaseEndOrCancel = NO;
     1399    _sentMomentumPhaseEnd = NO;
    13901400    WebCoreTestSupport::monitorWheelEvents(*frame);
    13911401#endif
     
    14041414
    14051415    JSGlobalContextRef globalContext = [mainFrame globalContext];
    1406     WebCoreTestSupport::setTestCallbackAndStartNotificationTimer(*frame, globalContext, jsCallbackFunction);
     1416    WebCoreTestSupport::setWheelEventMonitorTestCallbackAndStartMonitoring(_sentWheelPhaseEndOrCancel, _sentMomentumPhaseEnd, *frame, globalContext, jsCallbackFunction);
    14071417#endif
    14081418}
  • trunk/Tools/DumpRenderTree/win/EventSender.cpp

    r258558 r258679  
    833833    ::GetWindowRect(webViewWindow, &rect);
    834834
     835    COMPtr<IWebFramePrivate> framePrivate;
     836    if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
     837        framePrivate->layout();
     838
    835839    if (x) {
    836840        UINT scrollChars = 1;
     
    924928
    925929    WebCore::Frame* coreFrame = core(static_cast<WebFrame*>(frame2.get()));
    926     WebCoreTestSupport::setTestCallbackAndStartNotificationTimer(*coreFrame, globalContext, jsCallbackFunction);
     930    WebCoreTestSupport::setWheelEventMonitorTestCallbackAndStartMonitoring(false, false, *coreFrame, globalContext, jsCallbackFunction);
    927931
    928932    return JSValueMakeUndefined(context);
  • trunk/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp

    r248846 r258679  
    493493    uint64_t phase = cgEventPhaseFromString(phaseStr);
    494494    uint64_t momentum = cgEventMomentumPhaseFromString(momentumStr);
     495   
     496    if (phase == 4 /* kCGScrollPhaseEnded */ || phase == 8 /* kCGScrollPhaseCancelled */)
     497        m_sentWheelPhaseEndOrCancel = true;
     498   
     499    if (momentum == 3 /* kCGMomentumScrollPhaseEnd */)
     500        m_sentWheelMomentumPhaseEnd = true;
    495501
    496502    WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
     
    609615    WKBundlePageRef page = InjectedBundle::singleton().page()->page();
    610616   
     617    m_sentWheelPhaseEndOrCancel = false;
     618    m_sentWheelMomentumPhaseEnd = false;
    611619    WKBundlePageStartMonitoringScrollOperations(page);
    612620}
     
    651659    auto scrollCompletionCallbackData = makeUnique<ScrollCompletionCallbackData>(context, functionCallbackObject);
    652660    auto scrollCompletionCallbackDataPtr = scrollCompletionCallbackData.release();
    653     bool callbackWillBeCalled = WKBundlePageRegisterScrollOperationCompletionCallback(page, executeCallback, scrollCompletionCallbackDataPtr);
     661    bool callbackWillBeCalled = WKBundlePageRegisterScrollOperationCompletionCallback(page, executeCallback, m_sentWheelPhaseEndOrCancel, m_sentWheelMomentumPhaseEnd, scrollCompletionCallbackDataPtr);
    654662    if (!callbackWillBeCalled) {
    655663        // Reassign raw pointer to std::unique_ptr<> so it will not be leaked.
  • trunk/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h

    r214586 r258679  
    8888    EventSendingController();
    8989    WKPoint m_position;
     90    bool m_sentWheelPhaseEndOrCancel { false };
     91    bool m_sentWheelMomentumPhaseEnd { false };
    9092};
    9193
Note: See TracChangeset for help on using the changeset viewer.