Diff
Modified: trunk/LayoutTests/ChangeLog (270424 => 270425)
--- trunk/LayoutTests/ChangeLog 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/LayoutTests/ChangeLog 2020-12-04 07:10:03 UTC (rev 270425)
@@ -1,3 +1,14 @@
+2020-12-03 Simon Fraser <[email protected]>
+
+ Only the first wheel event in a gesture should be cancelable
+ https://bugs.webkit.org/show_bug.cgi?id=218764
+ <rdar://problem/71248946>
+
+ Reviewed by Tim Horton.
+
+ * fast/scrolling/mac/rubberband-overflow-in-wheel-region-root-jiggle.html: Make more robust.
+ * platform/mac-wk2/fast/events/wheel/wheel-events-become-non-cancelable-expected.txt: Test now passes in WK2.
+
2020-12-03 Lauro Moura <[email protected]>
[GTK] Gardening anchor download failures after r270422
Modified: trunk/LayoutTests/fast/scrolling/latching/scroll-latched-nested-div.html (270424 => 270425)
--- trunk/LayoutTests/fast/scrolling/latching/scroll-latched-nested-div.html 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/LayoutTests/fast/scrolling/latching/scroll-latched-nested-div.html 2020-12-04 07:10:03 UTC (rev 270425)
@@ -10,6 +10,7 @@
background-image: repeating-linear-gradient(silver, white 200px);
}
</style>
+<script src=""
<script src=""
<script>
jsTestIsAsync = true;
@@ -43,11 +44,9 @@
testFailed("div received wheel events during the second gesture.");
else
testPassed("div did not receive wheel events during the second gesture.");
-
- finishJSTest();
}
- function checkForFirstScroll()
+ async function doSecondScroll()
{
// 'parent' should not have scrolled, and the content of 'target' should
// not have moved. However, 'wrapper' should have moved.
@@ -81,10 +80,11 @@
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'none', 'begin');
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'none', 'continue');
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'none', 'end');
- eventSender.callAfterScrollingCompletes(checkForSecondScroll);
+
+ await UIHelper.waitForScrollCompletion();
}
- function scrollTest()
+ async function doFirstScroll()
{
pageScrollPositionBefore = document.scrollingElement.scrollTop;
@@ -110,9 +110,18 @@
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -5, 'none', 'begin');
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -10, 'none', 'continue');
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'none', 'end');
- eventSender.callAfterScrollingCompletes(checkForFirstScroll);
+
+ await UIHelper.waitForScrollCompletion();
}
+ async function scrollTest()
+ {
+ await doFirstScroll();
+ await doSecondScroll();
+ checkForSecondScroll();
+ finishJSTest();
+ }
+
function setupTopLevel()
{
description("Tests that a scrollable div nested inside another scrollable div properly handles wheel events under sub-pixel conditions.");
Modified: trunk/LayoutTests/fast/scrolling/mac/rubberband-overflow-in-wheel-region-root-jiggle.html (270424 => 270425)
--- trunk/LayoutTests/fast/scrolling/mac/rubberband-overflow-in-wheel-region-root-jiggle.html 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/LayoutTests/fast/scrolling/mac/rubberband-overflow-in-wheel-region-root-jiggle.html 2020-12-04 07:10:03 UTC (rev 270425)
@@ -51,10 +51,17 @@
// Scroll down to latch, then up to rubberband.
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, "began", "none");
- eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -10, "changed", "none");
- eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -10, "changed", "none");
- eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 12, "changed", "none");
- eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 12, "changed", "none");
+ await UIHelper.renderingUpdate();
+ eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -5, "changed", "none");
+ await UIHelper.renderingUpdate();
+ eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -5, "changed", "none");
+ await UIHelper.renderingUpdate();
+ eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 5, "changed", "none");
+ await UIHelper.renderingUpdate();
+ eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 5, "changed", "none");
+ await UIHelper.renderingUpdate();
+ eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 5, "changed", "none");
+ await UIHelper.renderingUpdate();
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, "ended", "none");
await UIHelper.renderingUpdate();
Modified: trunk/Source/WebCore/ChangeLog (270424 => 270425)
--- trunk/Source/WebCore/ChangeLog 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/ChangeLog 2020-12-04 07:10:03 UTC (rev 270425)
@@ -1,3 +1,75 @@
+2020-12-03 Simon Fraser <[email protected]>
+
+ Only the first wheel event in a gesture should be cancelable
+ https://bugs.webkit.org/show_bug.cgi?id=218764
+ <rdar://problem/71248946>
+
+ Reviewed by Tim Horton.
+
+ Implement the WebKit2 version of r270312, where only the first wheel event in a gesture is
+ cancelable.
+
+ When scrolling over an element with handlers, we do event handling on the main thread,
+ so we can take the compute value of EventHandler's Optional<WheelScrollGestureState>
+ from the first event and send it back to the scrolling thread.
+
+ However, the scrolling thread needs to block until this first event comes back from
+ the main thread. To achieve this, EventDispatcher::wheelEvent() now dispaches
+ main thread scrolls from the scrolling thread (not the dispatcher thread), and
+ waits on m_waitingForBeganEventCondition with a 50ms timeout for that first event to
+ come back.
+
+ In the normal case, main thread handling dispatches the event back to the scrolling
+ thread for scrolling via handleWheelEventAfterMainThread(), and then calls
+ wheelEventWasProcessedByMainThread() to signal the condition. If for some reason
+ handleWheelEventAfterMainThread() doesn't get called (e.g. nothing was scrollable),
+ then wheelEventWasProcessedByMainThread() still gets called to signal.
+
+ If m_waitingForBeganEventCondition times out, then the scrolling thread falls back
+ to non-blocking behaviour (as if the first event was not canceled).
+
+ Finally, when we know the gesture will become non-blocking, we transition to running
+ the scroll from the scrolling thread, which requires that we set up latching, hence
+ the changes in ScrollingTreeLatchingController.
+
+ Tested by existing tests in fast/events/wheel.
+
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::wheelEventWasProcessedByMainThread):
+ (WebCore::EventHandler::handleWheelEventInScrollableArea):
+ * page/WheelEventTestMonitor.cpp:
+ (WebCore::operator<<):
+ * page/WheelEventTestMonitor.h:
+ * page/mac/EventHandlerMac.mm:
+ (WebCore::EventHandler::processWheelEventForScrolling):
+ * page/scrolling/ScrollingTree.cpp:
+ (WebCore::ScrollingTree::determineWheelEventProcessing):
+ (WebCore::ScrollingTree::setGestureState):
+ (WebCore::ScrollingTree::gestureState):
+ * page/scrolling/ScrollingTree.h:
+ (WebCore::ScrollingTree::willSendEventToMainThread):
+ (WebCore::ScrollingTree::waitForEventToBeProcessedByMainThread):
+ * page/scrolling/ScrollingTreeLatchingController.cpp:
+ (WebCore::ScrollingTreeLatchingController::receivedWheelEvent):
+ (WebCore::ScrollingTreeLatchingController::nodeDidHandleEvent):
+ * page/scrolling/ScrollingTreeLatchingController.h:
+ * page/scrolling/ThreadedScrollingTree.cpp:
+ (WebCore::ThreadedScrollingTree::handleWheelEventAfterMainThread):
+ (WebCore::ThreadedScrollingTree::wheelEventWasProcessedByMainThread):
+ (WebCore::ThreadedScrollingTree::willSendEventToMainThread):
+ (WebCore::ThreadedScrollingTree::waitForEventToBeProcessedByMainThread):
+ * page/scrolling/ThreadedScrollingTree.h:
+ * page/scrolling/mac/ScrollingCoordinatorMac.mm:
+ (WebCore::ScrollingCoordinatorMac::handleWheelEventForScrolling): Need to track deferral
+ for WheelEventTestMonitor.
+ (WebCore::ScrollingCoordinatorMac::wheelEventWasProcessedByMainThread): This is now synchronous
+ to the scrolling thread so no need for the deferrer.
+ (WebCore::nextDeferIdentifier): Deleted.
+ * page/scrolling/nicosia/ScrollingCoordinatorNicosia.cpp:
+ (WebCore::ScrollingCoordinatorNicosia::wheelEventWasProcessedByMainThread):
+ * platform/cocoa/ScrollController.mm:
+ (WebCore::ScrollController::handleWheelEvent):
+
2020-12-03 Kate Cheney <[email protected]>
Issue logging in to Microsoft Teams if logged into other Microsoft accounts and navigating directly to teams.microsoft.com
Modified: trunk/Source/WebCore/page/EventHandler.cpp (270424 => 270425)
--- trunk/Source/WebCore/page/EventHandler.cpp 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/EventHandler.cpp 2020-12-04 07:10:03 UTC (rev 270425)
@@ -2722,8 +2722,17 @@
return didHandleEvent;
}
-void EventHandler::wheelEventWasProcessedByMainThread(const PlatformWheelEvent&, OptionSet<EventHandling>)
+void EventHandler::wheelEventWasProcessedByMainThread(const PlatformWheelEvent& wheelEvent, OptionSet<EventHandling> eventHandling)
{
+ updateWheelGestureState(wheelEvent, eventHandling);
+
+#if ENABLE(ASYNC_SCROLLING)
+ FrameView* view = m_frame.view();
+ if (auto scrollingCoordinator = m_frame.page()->scrollingCoordinator()) {
+ if (scrollingCoordinator->coordinatesScrollingForFrameView(*view))
+ scrollingCoordinator->wheelEventWasProcessedByMainThread(wheelEvent, m_wheelScrollGestureState);
+ }
+#endif
}
bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&, const Widget&, const WeakPtr<ScrollableArea>&)
@@ -2982,7 +2991,7 @@
bool EventHandler::handleWheelEventInScrollableArea(const PlatformWheelEvent& wheelEvent, ScrollableArea& scrollableArea, OptionSet<EventHandling> eventHandling)
{
auto gestureState = updateWheelGestureState(wheelEvent, eventHandling);
- LOG_WITH_STREAM(Scrolling, stream << "EventHandler::handleWheelEventInScrollableArea() - eventHandling " << eventHandling << " -> gesture state " << gestureState);
+ LOG_WITH_STREAM(Scrolling, stream << "EventHandler::handleWheelEventInScrollableArea() " << scrollableArea << " - eventHandling " << eventHandling << " -> gesture state " << gestureState);
return scrollableArea.handleWheelEventForScrolling(wheelEvent, gestureState);
}
Modified: trunk/Source/WebCore/page/WheelEventTestMonitor.cpp (270424 => 270425)
--- trunk/Source/WebCore/page/WheelEventTestMonitor.cpp 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/WheelEventTestMonitor.cpp 2020-12-04 07:10:03 UTC (rev 270425)
@@ -172,7 +172,7 @@
switch (reason) {
case WheelEventTestMonitor::HandlingWheelEvent: ts << "handling wheel event"; break;
case WheelEventTestMonitor::HandlingWheelEventOnMainThread: ts << "handling wheel event on main thread"; break;
- case WheelEventTestMonitor::ReportDOMEventHandling: ts << "report DOM event handling"; break;
+ case WheelEventTestMonitor::PostMainThreadWheelEventHandling: ts << "post-main thread event handling"; break;
case WheelEventTestMonitor::RubberbandInProgress: ts << "rubberbanding"; break;
case WheelEventTestMonitor::ScrollSnapInProgress: ts << "scroll-snapping"; break;
case WheelEventTestMonitor::ScrollingThreadSyncNeeded: ts << "scrolling thread sync needed"; break;
Modified: trunk/Source/WebCore/page/WheelEventTestMonitor.h (270424 => 270425)
--- trunk/Source/WebCore/page/WheelEventTestMonitor.h 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/WheelEventTestMonitor.h 2020-12-04 07:10:03 UTC (rev 270425)
@@ -48,14 +48,14 @@
WEBCORE_EXPORT void clearAllTestDeferrals();
enum DeferReason {
- HandlingWheelEvent = 1 << 0,
- HandlingWheelEventOnMainThread = 1 << 1,
- ReportDOMEventHandling = 1 << 2,
- RubberbandInProgress = 1 << 3,
- ScrollSnapInProgress = 1 << 4,
- ScrollingThreadSyncNeeded = 1 << 5,
- ContentScrollInProgress = 1 << 6,
- RequestedScrollPosition = 1 << 7,
+ HandlingWheelEvent = 1 << 0,
+ HandlingWheelEventOnMainThread = 1 << 1,
+ PostMainThreadWheelEventHandling = 1 << 2,
+ RubberbandInProgress = 1 << 3,
+ ScrollSnapInProgress = 1 << 4,
+ ScrollingThreadSyncNeeded = 1 << 5,
+ ContentScrollInProgress = 1 << 6,
+ RequestedScrollPosition = 1 << 7,
};
typedef const void* ScrollableAreaIdentifier;
Modified: trunk/Source/WebCore/page/mac/EventHandlerMac.mm (270424 => 270425)
--- trunk/Source/WebCore/page/mac/EventHandlerMac.mm 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/mac/EventHandlerMac.mm 2020-12-04 07:10:03 UTC (rev 270425)
@@ -954,7 +954,7 @@
LOG_WITH_STREAM(ScrollLatching, stream << " EventHandler::processWheelEventForScrolling returning " << didHandleWheelEvent);
return didHandleWheelEvent;
}
-
+
bool didHandleEvent = handleWheelEventInScrollableArea(wheelEvent, *view, eventHandling);
m_isHandlingWheelEvent = false;
return didHandleEvent;
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp (270424 => 270425)
--- trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp 2020-12-04 07:10:03 UTC (rev 270425)
@@ -73,6 +73,8 @@
LOG_WITH_STREAM(ScrollLatching, stream << "ScrollingTree::determineWheelEventProcessing " << wheelEvent << " have latched node " << latchedNodeAndSteps->scrollingNodeID << " steps " << latchedNodeAndSteps->processingSteps);
return latchedNodeAndSteps->processingSteps;
}
+ if (wheelEvent.isGestureStart() || wheelEvent.isNonGestureEvent())
+ m_treeState.gestureState = WTF::nullopt;
auto processingSteps = [&]() -> OptionSet<WheelEventProcessingSteps> {
if (!m_rootNode)
@@ -96,8 +98,12 @@
#if ENABLE(WHEEL_EVENT_REGIONS)
auto eventListenerTypes = eventListenerRegionTypesForPoint(position);
- if (eventListenerTypes.contains(EventListenerRegionType::NonPassiveWheel))
+ if (eventListenerTypes.contains(EventListenerRegionType::NonPassiveWheel)) {
+ if (m_treeState.gestureState.valueOr(WheelScrollGestureState::Blocking) == WheelScrollGestureState::NonBlocking)
+ return { WheelEventProcessingSteps::ScrollingThread, WheelEventProcessingSteps::MainThreadForNonBlockingDOMEventDispatch };
+
return { WheelEventProcessingSteps::MainThreadForScrolling, WheelEventProcessingSteps::MainThreadForBlockingDOMEventDispatch };
+ }
if (eventListenerTypes.contains(EventListenerRegionType::Wheel))
return { WheelEventProcessingSteps::ScrollingThread, WheelEventProcessingSteps::MainThreadForNonBlockingDOMEventDispatch };
@@ -482,6 +488,18 @@
m_treeState.mainFrameScrollPosition = position;
}
+void ScrollingTree::setGestureState(Optional<WheelScrollGestureState> gestureState)
+{
+ LockHolder lock(m_treeStateMutex);
+ m_treeState.gestureState = gestureState;
+}
+
+Optional<WheelScrollGestureState> ScrollingTree::gestureState()
+{
+ LockHolder lock(m_treeStateMutex);
+ return m_treeState.gestureState;
+}
+
TrackingType ScrollingTree::eventTrackingTypeForPoint(const AtomString& eventName, IntPoint p)
{
LockHolder lock(m_treeStateMutex);
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.h (270424 => 270425)
--- trunk/Source/WebCore/page/scrolling/ScrollingTree.h 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.h 2020-12-04 07:10:03 UTC (rev 270425)
@@ -210,6 +210,9 @@
virtual void lockLayersForHitTesting() { }
virtual void unlockLayersForHitTesting() { }
+ virtual void willSendEventToMainThread(const PlatformWheelEvent&) { }
+ virtual void waitForEventToBeProcessedByMainThread(const PlatformWheelEvent&) { };
+
Lock& treeMutex() { return m_treeMutex; }
void windowScreenDidChange(PlatformDisplayID, Optional<unsigned> nominalFramesPerSecond);
@@ -245,6 +248,9 @@
FloatPoint mainFrameScrollPosition() const;
void setMainFrameScrollPosition(FloatPoint);
+ void setGestureState(Optional<WheelScrollGestureState>);
+ Optional<WheelScrollGestureState> gestureState();
+
Optional<unsigned> nominalFramesPerSecond();
void applyLayerPositionsInternal();
@@ -285,6 +291,7 @@
FloatPoint mainFrameScrollPosition;
PlatformDisplayID displayID { 0 };
Optional<unsigned> nominalFramesPerSecond;
+ Optional<WheelScrollGestureState> gestureState;
HashSet<ScrollingNodeID> nodesWithActiveRubberBanding;
HashSet<ScrollingNodeID> nodesWithActiveScrollSnap;
HashSet<ScrollingNodeID> nodesWithActiveUserScrolls;
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeLatchingController.cpp (270424 => 270425)
--- trunk/Source/WebCore/page/scrolling/ScrollingTreeLatchingController.cpp 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeLatchingController.cpp 2020-12-04 07:10:03 UTC (rev 270425)
@@ -41,15 +41,18 @@
ScrollingTreeLatchingController::ScrollingTreeLatchingController() = default;
-void ScrollingTreeLatchingController::receivedWheelEvent(const PlatformWheelEvent& wheelEvent, OptionSet<WheelEventProcessingSteps>, bool allowLatching)
+void ScrollingTreeLatchingController::receivedWheelEvent(const PlatformWheelEvent& wheelEvent, OptionSet<WheelEventProcessingSteps> processingSteps, bool allowLatching)
{
if (!allowLatching)
return;
LockHolder locker(m_latchedNodeMutex);
- if (wheelEvent.isGestureStart() && m_latchedNodeAndSteps && !latchedNodeIsRelevant()) {
- LOG_WITH_STREAM(ScrollLatching, stream << "ScrollingTreeLatchingController " << this << " receivedWheelEvent - " << (MonotonicTime::now() - m_lastLatchedNodeInterationTime).milliseconds() << "ms since last event, clearing latched node");
- m_latchedNodeAndSteps.reset();
+ if (wheelEvent.isGestureStart() && !latchedNodeIsRelevant()) {
+ if (m_latchedNodeAndSteps) {
+ LOG_WITH_STREAM(ScrollLatching, stream << "ScrollingTreeLatchingController " << this << " receivedWheelEvent - " << (MonotonicTime::now() - m_lastLatchedNodeInterationTime).milliseconds() << "ms since last event, clearing latched node");
+ m_latchedNodeAndSteps.reset();
+ }
+ m_processingStepsForCurrentGesture = processingSteps;
}
}
@@ -96,9 +99,27 @@
return;
}
- if (wheelEvent.delta().isZero() || !wheelEvent.isGestureStart())
+ auto shouldLatch = [&]() {
+ if (wheelEvent.delta().isZero())
+ return false;
+
+ if (wheelEvent.isGestureStart())
+ return true;
+
+ if (!wheelEvent.isGestureContinuation())
+ return false;
+
+ if (m_processingStepsForCurrentGesture.valueOr(OptionSet<WheelEventProcessingSteps> { }).contains(WheelEventProcessingSteps::MainThreadForScrolling) && processingSteps.contains(WheelEventProcessingSteps::ScrollingThread))
+ return true;
+
+ return false;
+ };
+
+ if (!shouldLatch())
return;
+ m_processingStepsForCurrentGesture = processingSteps;
+
LOG_WITH_STREAM(ScrollLatching, stream << "ScrollingTreeLatchingController " << this << " nodeDidHandleEvent: latching to " << scrollingNodeID);
m_latchedNodeAndSteps = ScrollingNodeAndProcessingSteps { scrollingNodeID, processingSteps };
m_lastLatchedNodeInterationTime = MonotonicTime::now();
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeLatchingController.h (270424 => 270425)
--- trunk/Source/WebCore/page/scrolling/ScrollingTreeLatchingController.h 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeLatchingController.h 2020-12-04 07:10:03 UTC (rev 270425)
@@ -64,6 +64,7 @@
mutable Lock m_latchedNodeMutex;
Optional<ScrollingNodeAndProcessingSteps> m_latchedNodeAndSteps;
+ Optional<OptionSet<WheelEventProcessingSteps>> m_processingStepsForCurrentGesture;
MonotonicTime m_lastLatchedNodeInterationTime;
};
Modified: trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp (270424 => 270425)
--- trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp 2020-12-04 07:10:03 UTC (rev 270425)
@@ -64,23 +64,76 @@
return ScrollingTree::handleWheelEvent(wheelEvent, processingSteps);
}
-bool ThreadedScrollingTree::handleWheelEventAfterMainThread(const PlatformWheelEvent& wheelEvent, ScrollingNodeID targetNodeID, Optional<WheelScrollGestureState>)
+bool ThreadedScrollingTree::handleWheelEventAfterMainThread(const PlatformWheelEvent& wheelEvent, ScrollingNodeID targetNodeID, Optional<WheelScrollGestureState> gestureState)
{
- LOG_WITH_STREAM(Scrolling, stream << "ThreadedScrollingTree::handleWheelEventAfterMainThread " << wheelEvent << " node " << targetNodeID);
+ ASSERT(ScrollingThread::isCurrentThread());
+ LOG_WITH_STREAM(Scrolling, stream << "ThreadedScrollingTree::handleWheelEventAfterMainThread " << wheelEvent << " node " << targetNodeID << " gestureState " << gestureState);
+
LockHolder locker(m_treeMutex);
- SetForScope<bool> disallowLatchingScope(m_allowLatching, false);
+ bool allowLatching = false;
+ OptionSet<WheelEventProcessingSteps> processingSteps;
+ if (gestureState.valueOr(WheelScrollGestureState::Blocking) == WheelScrollGestureState::NonBlocking) {
+ allowLatching = true;
+ processingSteps = { WheelEventProcessingSteps::ScrollingThread, WheelEventProcessingSteps::MainThreadForNonBlockingDOMEventDispatch };
+ }
+
+ SetForScope<bool> disallowLatchingScope(m_allowLatching, allowLatching);
RefPtr<ScrollingTreeNode> targetNode = nodeForID(targetNodeID);
- auto result = handleWheelEventWithNode(wheelEvent, { }, targetNode.get(), EventTargeting::NodeOnly);
+ auto result = handleWheelEventWithNode(wheelEvent, processingSteps, targetNode.get(), EventTargeting::NodeOnly);
return result.wasHandled;
}
-void ThreadedScrollingTree::wheelEventWasProcessedByMainThread(const PlatformWheelEvent&, Optional<WheelScrollGestureState>)
+void ThreadedScrollingTree::wheelEventWasProcessedByMainThread(const PlatformWheelEvent& wheelEvent, Optional<WheelScrollGestureState> gestureState)
{
- // FIXME: Set state based on EventHandling flags.
+ LOG_WITH_STREAM(Scrolling, stream << "ThreadedScrollingTree::wheelEventWasProcessedByMainThread - gestureState " << gestureState);
+
+ ASSERT(isMainThread());
+
+ LockHolder locker(m_treeMutex);
+ if (m_receivedBeganEventFromMainThread || !wheelEvent.isGestureStart())
+ return;
+
+ setGestureState(gestureState);
+
+ m_receivedBeganEventFromMainThread = true;
+ m_waitingForBeganEventCondition.notifyOne();
}
+void ThreadedScrollingTree::willSendEventToMainThread(const PlatformWheelEvent&)
+{
+ ASSERT(ScrollingThread::isCurrentThread());
+
+ LockHolder locker(m_treeMutex);
+ m_receivedBeganEventFromMainThread = false;
+}
+
+void ThreadedScrollingTree::waitForEventToBeProcessedByMainThread(const PlatformWheelEvent& wheelEvent)
+{
+ ASSERT(ScrollingThread::isCurrentThread());
+
+ if (!wheelEvent.isGestureStart())
+ return;
+
+ LockHolder locker(m_treeMutex);
+
+ static constexpr auto maxAllowableMainThreadDelay = 50_ms;
+ auto startTime = MonotonicTime::now();
+ auto timeoutTime = startTime + maxAllowableMainThreadDelay;
+
+ bool receivedEvent = m_waitingForBeganEventCondition.waitUntil(m_treeMutex, timeoutTime, [&] {
+ return m_receivedBeganEventFromMainThread;
+ });
+
+ if (!receivedEvent) {
+ // Timed out, go asynchronous.
+ setGestureState(WheelScrollGestureState::NonBlocking);
+ }
+
+ LOG_WITH_STREAM(Scrolling, stream << "ThreadedScrollingTree::waitForBeganEventFromMainThread done - timed out " << !receivedEvent << " gesture state is " << gestureState());
+}
+
void ThreadedScrollingTree::invalidate()
{
// Invalidate is dispatched by the ScrollingCoordinator class on the ScrollingThread
Modified: trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h (270424 => 270425)
--- trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h 2020-12-04 07:10:03 UTC (rev 270425)
@@ -50,6 +50,9 @@
bool handleWheelEventAfterMainThread(const PlatformWheelEvent&, ScrollingNodeID, Optional<WheelScrollGestureState>);
void wheelEventWasProcessedByMainThread(const PlatformWheelEvent&, Optional<WheelScrollGestureState>);
+ WEBCORE_EXPORT void willSendEventToMainThread(const PlatformWheelEvent&) final;
+ WEBCORE_EXPORT void waitForEventToBeProcessedByMainThread(const PlatformWheelEvent&) final;
+
void invalidate() override;
WEBCORE_EXPORT void displayDidRefresh(PlatformDisplayID);
@@ -85,7 +88,7 @@
void displayDidRefreshOnScrollingThread();
void waitForRenderingUpdateCompletionOrTimeout();
-
+
bool canUpdateLayersOnScrollingThread() const;
void scheduleDelayedRenderingUpdateDetectionTimer(Seconds);
@@ -103,6 +106,9 @@
SynchronizationState m_state { SynchronizationState::Idle };
Condition m_stateCondition;
+ bool m_receivedBeganEventFromMainThread { false };
+ Condition m_waitingForBeganEventCondition;
+
// Dynamically allocated because it has to use the ScrollingThread's runloop.
std::unique_ptr<RunLoop::Timer<ThreadedScrollingTree>> m_delayedRenderingUpdateDetectionTimer;
Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm (270424 => 270425)
--- trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm 2020-12-04 07:10:03 UTC (rev 270425)
@@ -81,29 +81,23 @@
if (scrollingTree()->willWheelEventStartSwipeGesture(wheelEvent))
return false;
- LOG_WITH_STREAM(Scrolling, stream << "ScrollingCoordinatorMac::handleWheelEventForScrolling - sending event to scrolling thread, node " << targetNodeID << " gestureState " << gestureState);
-
+ LOG_WITH_STREAM(Scrolling, stream << "ScrollingCoordinatorMac::handleWheelEventForScrolling " << wheelEvent << " - sending event to scrolling thread, node " << targetNodeID << " gestureState " << gestureState);
+
+ auto deferrer = WheelEventTestMonitorCompletionDeferrer { m_page->wheelEventTestMonitor().get(), reinterpret_cast<WheelEventTestMonitor::ScrollableAreaIdentifier>(targetNodeID), WheelEventTestMonitor::PostMainThreadWheelEventHandling };
+
RefPtr<ThreadedScrollingTree> threadedScrollingTree = downcast<ThreadedScrollingTree>(scrollingTree());
- ScrollingThread::dispatch([threadedScrollingTree, wheelEvent, targetNodeID, gestureState] {
+ ScrollingThread::dispatch([threadedScrollingTree, wheelEvent, targetNodeID, gestureState, deferrer = WTFMove(deferrer)] {
threadedScrollingTree->handleWheelEventAfterMainThread(wheelEvent, targetNodeID, gestureState);
});
return true;
}
-static uint64_t nextDeferIdentifier()
-{
- static uint64_t deferIdentifier;
- return ++deferIdentifier;
-}
-
void ScrollingCoordinatorMac::wheelEventWasProcessedByMainThread(const PlatformWheelEvent& wheelEvent, Optional<WheelScrollGestureState> gestureState)
{
- auto deferrer = WheelEventTestMonitorCompletionDeferrer { m_page->wheelEventTestMonitor().get(), reinterpret_cast<WheelEventTestMonitor::ScrollableAreaIdentifier>(nextDeferIdentifier()), WheelEventTestMonitor::ReportDOMEventHandling };
+ LOG_WITH_STREAM(Scrolling, stream << "ScrollingCoordinatorMac::wheelEventWasProcessedByMainThread " << gestureState);
RefPtr<ThreadedScrollingTree> threadedScrollingTree = downcast<ThreadedScrollingTree>(scrollingTree());
- ScrollingThread::dispatch([threadedScrollingTree, wheelEvent, gestureState, deferrer = WTFMove(deferrer)] {
- threadedScrollingTree->wheelEventWasProcessedByMainThread(wheelEvent, gestureState);
- });
+ threadedScrollingTree->wheelEventWasProcessedByMainThread(wheelEvent, gestureState);
}
void ScrollingCoordinatorMac::scheduleTreeStateCommit()
Modified: trunk/Source/WebCore/page/scrolling/nicosia/ScrollingCoordinatorNicosia.cpp (270424 => 270425)
--- trunk/Source/WebCore/page/scrolling/nicosia/ScrollingCoordinatorNicosia.cpp 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/page/scrolling/nicosia/ScrollingCoordinatorNicosia.cpp 2020-12-04 07:10:03 UTC (rev 270425)
@@ -83,9 +83,8 @@
void ScrollingCoordinatorNicosia::wheelEventWasProcessedByMainThread(const PlatformWheelEvent& wheelEvent, Optional<WheelScrollGestureState> gestureState)
{
- ScrollingThread::dispatch([threadedScrollingTree = makeRef(downcast<ThreadedScrollingTree>(*scrollingTree())), wheelEvent, gestureState] {
- threadedScrollingTree->wheelEventWasProcessedByMainThread(wheelEvent, gestureState);
- });
+ RefPtr<ThreadedScrollingTree> threadedScrollingTree = downcast<ThreadedScrollingTree>(scrollingTree());
+ threadedScrollingTree->wheelEventWasProcessedByMainThread(wheelEvent, gestureState);
}
void ScrollingCoordinatorNicosia::scheduleTreeStateCommit()
Modified: trunk/Source/WebCore/platform/PlatformWheelEvent.h (270424 => 270425)
--- trunk/Source/WebCore/platform/PlatformWheelEvent.h 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebCore/platform/PlatformWheelEvent.h 2020-12-04 07:10:03 UTC (rev 270425)
@@ -208,7 +208,8 @@
|| m_phase == PlatformWheelEventPhase::Changed
|| m_momentumPhase == PlatformWheelEventPhase::Began
|| m_momentumPhase == PlatformWheelEventPhase::Changed
- || (m_phase == PlatformWheelEventPhase::Ended && m_momentumPhase == PlatformWheelEventPhase::None);
+ || (m_phase == PlatformWheelEventPhase::Ended && m_momentumPhase == PlatformWheelEventPhase::None)
+ || (m_phase == PlatformWheelEventPhase::None && m_momentumPhase == PlatformWheelEventPhase::Ended);
}
inline bool PlatformWheelEvent::isGestureContinuation() const
Modified: trunk/Source/WebKit/ChangeLog (270424 => 270425)
--- trunk/Source/WebKit/ChangeLog 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebKit/ChangeLog 2020-12-04 07:10:03 UTC (rev 270425)
@@ -1,3 +1,20 @@
+2020-12-03 Simon Fraser <[email protected]>
+
+ Only the first wheel event in a gesture should be cancelable
+ https://bugs.webkit.org/show_bug.cgi?id=218764
+ <rdar://problem/71248946>
+
+ Reviewed by Tim Horton.
+
+ In EventDispatcher::wheelEvent(), all wheel events now bounce through the scrolling
+ thread, even those destined for main thread scrolling. This allows the scrolling thread
+ to wait on a condition for the event to come back to the scrolling thread via
+ handleWheelEventAfterMainThread(), since we have to know whether content called
+ preventDefault() on the first event before sending subsequent events.
+
+ * WebProcess/WebPage/EventDispatcher.cpp:
+ (WebKit::EventDispatcher::wheelEvent):
+
2020-12-03 Alex Christensen <[email protected]>
Introduce new download API
Modified: trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.cpp (270424 => 270425)
--- trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.cpp 2020-12-04 06:45:17 UTC (rev 270424)
+++ trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.cpp 2020-12-04 07:10:03 UTC (rev 270425)
@@ -136,12 +136,17 @@
scrollingTree->setMainFrameCanRubberBand({ canRubberBandAtTop, canRubberBandAtRight, canRubberBandAtBottom, canRubberBandAtLeft });
auto processingSteps = scrollingTree->determineWheelEventProcessing(platformWheelEvent);
- if (!processingSteps.contains(WheelEventProcessingSteps::ScrollingThread))
- return processingSteps;
scrollingTree->willProcessWheelEvent();
ScrollingThread::dispatch([scrollingTree, wheelEvent, platformWheelEvent, processingSteps, pageID, protectedThis = makeRef(*this)] {
+ if (processingSteps.contains(WheelEventProcessingSteps::MainThreadForScrolling)) {
+ scrollingTree->willSendEventToMainThread(platformWheelEvent);
+ protectedThis->dispatchWheelEventViaMainThread(pageID, wheelEvent, processingSteps);
+ scrollingTree->waitForEventToBeProcessedByMainThread(platformWheelEvent);
+ return;
+ }
+
auto result = scrollingTree->handleWheelEvent(platformWheelEvent, processingSteps);
if (result.needsMainThreadProcessing()) {
@@ -157,18 +162,14 @@
return processingSteps;
}();
-
- if (processingSteps.contains(WheelEventProcessingSteps::ScrollingThread))
- return;
-
#else
UNUSED_PARAM(canRubberBandAtLeft);
UNUSED_PARAM(canRubberBandAtRight);
UNUSED_PARAM(canRubberBandAtTop);
UNUSED_PARAM(canRubberBandAtBottom);
-#endif
dispatchWheelEventViaMainThread(pageID, wheelEvent, processingSteps);
+#endif
}
#if ENABLE(MAC_GESTURE_EVENTS)