Title: [287641] trunk/Source
Revision
287641
Author
[email protected]
Date
2022-01-05 11:29:43 -0800 (Wed, 05 Jan 2022)

Log Message

Momentum Event Dispatcher: Momentum tails may get truncated if the duration runs longer than the system's
https://bugs.webkit.org/show_bug.cgi?id=234535
<rdar://problem/86338105>

Reviewed by Simon Fraser.

Source/WebKit:

Currently, synthetic momentum dispatch is strictly tied to the duration
of the real platform momentum phase, which has two unfortunate implications:

- if our phase runs shorter than the platform phase, we'll keep dispatching
  zero-delta events until the platform momentum ends

- more importantly, if our phase runs longer, it will be abruptly terminated
  when the platform momentum ends

In practice, our synthetic phase is very close in duration to the system one,
so the impact is minimal. But, to be safe, disentagle the two durations,
using a new bit from the platform to determine if the system momentum phase
was interrupted by the user (e.g. by tapping the trackpad) or naturally,
and ignoring the ended event in the natural case, allowing synthetic
events to continue being dispatched.

* Shared/WebWheelEvent.cpp:
(WebKit::WebWheelEvent::WebWheelEvent):
(WebKit::WebWheelEvent::encode const):
(WebKit::WebWheelEvent::decode):
* Shared/WebWheelEvent.h:
(WebKit::WebWheelEvent::momentumEndType const):
* Shared/WebWheelEventCoalescer.cpp:
(WebKit::WebWheelEventCoalescer::coalesce):
Plumb momentumEndType along on WebWheelEvent. Platforms that don't
provide information about the interruption reason will always say Unknown.

* Shared/mac/WebEventFactory.mm:
(WebKit::WebEventFactory::createWebWheelEvent):
Only bother looking up the CGEvent/IOHIDEvent once, and extract all
relevant details in one go.

* WebProcess/WebPage/MomentumEventDispatcher.cpp:
(WebKit::MomentumEventDispatcher::handleWheelEvent):
Don't interrupt the synthetic momentum phase if the momentum-ended event
comes from the natural end of the deceleration instead of an interruption
(or an unknown reason).

Keep track of whether we're in the middle of a platform momentum phase
that we chose (at momentum-begin time) to override. When deciding
whether to eat an incoming event, take *both* this new bit and whether
we are currently in the middle of a synthetic phase into account. It
is important to continue eating incoming events in the case where
the synthetic phase ended early (so `active` became false) but the
platform phase continues.

(WebKit::MomentumEventDispatcher::dispatchSyntheticMomentumEvent):
(WebKit::MomentumEventDispatcher::didEndMomentumPhase):
Adjust some logging wording to be more precise.

(WebKit::MomentumEventDispatcher::setScrollingAccelerationCurve):
Make this log public so that the curve value is visible in logs.

(WebKit::MomentumEventDispatcher::consumeDeltaForCurrentTime):
Make consumeDeltaForCurrentTime inform the client via an optional when
we are at the end of the delta table.

(WebKit::MomentumEventDispatcher::displayWasRefreshed):
Stop the synthetic momentum phase as soon as we run out of deltas.

(WebKit::MomentumEventDispatcher::computeNextDelta):
* WebProcess/WebPage/MomentumEventDispatcher.h:

Source/WTF:

* wtf/PlatformHave.h:
Add a HAVE for kIOHIDEventScrollMomentumInterrupted.

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (287640 => 287641)


--- trunk/Source/WTF/ChangeLog	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WTF/ChangeLog	2022-01-05 19:29:43 UTC (rev 287641)
@@ -1,3 +1,14 @@
+2022-01-05  Tim Horton  <[email protected]>
+
+        Momentum Event Dispatcher: Momentum tails may get truncated if the duration runs longer than the system's
+        https://bugs.webkit.org/show_bug.cgi?id=234535
+        <rdar://problem/86338105>
+
+        Reviewed by Simon Fraser.
+
+        * wtf/PlatformHave.h:
+        Add a HAVE for kIOHIDEventScrollMomentumInterrupted.
+
 2021-12-31  Yusuke Suzuki  <[email protected]>
 
         [JSC] Replace UDIS86 with Zydis

Modified: trunk/Source/WTF/wtf/PlatformHave.h (287640 => 287641)


--- trunk/Source/WTF/wtf/PlatformHave.h	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WTF/wtf/PlatformHave.h	2022-01-05 19:29:43 UTC (rev 287641)
@@ -1140,3 +1140,7 @@
 #if PLATFORM(COCOA)
 #define HAVE_CFAUTORELEASE 1
 #endif
+
+#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 120200
+#define HAVE_PLATFORM_SCROLL_MOMENTUM_INTERRUPTION_REASON 1
+#endif

Modified: trunk/Source/WebCore/PAL/pal/spi/mac/IOKitSPIMac.h (287640 => 287641)


--- trunk/Source/WebCore/PAL/pal/spi/mac/IOKitSPIMac.h	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WebCore/PAL/pal/spi/mac/IOKitSPIMac.h	2022-01-05 19:29:43 UTC (rev 287641)
@@ -81,7 +81,6 @@
     kIOHIDEventTypeDigitizer = 11,
     kIOHIDEventTypeNavigationSwipe = 16,
     kIOHIDEventTypeForce = 32,
-
 };
 typedef uint32_t IOHIDEventType;
 
@@ -88,6 +87,12 @@
 typedef uint32_t IOHIDEventField;
 typedef uint64_t IOHIDEventSenderID;
 
+
+enum {
+    kIOHIDEventScrollMomentumInterrupted = (1 << 4),
+};
+typedef uint8_t IOHIDEventScrollMomentumBits;
+
 #ifdef __LP64__
 typedef double IOHIDFloat;
 #else
@@ -103,6 +108,7 @@
 uint64_t IOHIDEventGetTimeStamp(IOHIDEventRef);
 IOHIDFloat IOHIDEventGetFloatValue(IOHIDEventRef, IOHIDEventField);
 IOHIDEventSenderID IOHIDEventGetSenderID(IOHIDEventRef);
+IOHIDEventScrollMomentumBits IOHIDEventGetScrollMomentum(IOHIDEventRef);
 
 WTF_EXTERN_C_END
 

Modified: trunk/Source/WebKit/ChangeLog (287640 => 287641)


--- trunk/Source/WebKit/ChangeLog	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WebKit/ChangeLog	2022-01-05 19:29:43 UTC (rev 287641)
@@ -1,3 +1,74 @@
+2022-01-05  Tim Horton  <[email protected]>
+
+        Momentum Event Dispatcher: Momentum tails may get truncated if the duration runs longer than the system's
+        https://bugs.webkit.org/show_bug.cgi?id=234535
+        <rdar://problem/86338105>
+
+        Reviewed by Simon Fraser.
+
+        Currently, synthetic momentum dispatch is strictly tied to the duration
+        of the real platform momentum phase, which has two unfortunate implications:
+
+        - if our phase runs shorter than the platform phase, we'll keep dispatching
+          zero-delta events until the platform momentum ends
+
+        - more importantly, if our phase runs longer, it will be abruptly terminated
+          when the platform momentum ends
+
+        In practice, our synthetic phase is very close in duration to the system one,
+        so the impact is minimal. But, to be safe, disentagle the two durations,
+        using a new bit from the platform to determine if the system momentum phase
+        was interrupted by the user (e.g. by tapping the trackpad) or naturally,
+        and ignoring the ended event in the natural case, allowing synthetic
+        events to continue being dispatched.
+
+        * Shared/WebWheelEvent.cpp:
+        (WebKit::WebWheelEvent::WebWheelEvent):
+        (WebKit::WebWheelEvent::encode const):
+        (WebKit::WebWheelEvent::decode):
+        * Shared/WebWheelEvent.h:
+        (WebKit::WebWheelEvent::momentumEndType const):
+        * Shared/WebWheelEventCoalescer.cpp:
+        (WebKit::WebWheelEventCoalescer::coalesce):
+        Plumb momentumEndType along on WebWheelEvent. Platforms that don't
+        provide information about the interruption reason will always say Unknown.
+
+        * Shared/mac/WebEventFactory.mm:
+        (WebKit::WebEventFactory::createWebWheelEvent):
+        Only bother looking up the CGEvent/IOHIDEvent once, and extract all
+        relevant details in one go.
+
+        * WebProcess/WebPage/MomentumEventDispatcher.cpp:
+        (WebKit::MomentumEventDispatcher::handleWheelEvent):
+        Don't interrupt the synthetic momentum phase if the momentum-ended event
+        comes from the natural end of the deceleration instead of an interruption
+        (or an unknown reason).
+
+        Keep track of whether we're in the middle of a platform momentum phase
+        that we chose (at momentum-begin time) to override. When deciding
+        whether to eat an incoming event, take *both* this new bit and whether
+        we are currently in the middle of a synthetic phase into account. It
+        is important to continue eating incoming events in the case where 
+        the synthetic phase ended early (so `active` became false) but the
+        platform phase continues.
+
+        (WebKit::MomentumEventDispatcher::dispatchSyntheticMomentumEvent):
+        (WebKit::MomentumEventDispatcher::didEndMomentumPhase):
+        Adjust some logging wording to be more precise.
+
+        (WebKit::MomentumEventDispatcher::setScrollingAccelerationCurve):
+        Make this log public so that the curve value is visible in logs.
+
+        (WebKit::MomentumEventDispatcher::consumeDeltaForCurrentTime):
+        Make consumeDeltaForCurrentTime inform the client via an optional when
+        we are at the end of the delta table.
+
+        (WebKit::MomentumEventDispatcher::displayWasRefreshed):
+        Stop the synthetic momentum phase as soon as we run out of deltas.
+
+        (WebKit::MomentumEventDispatcher::computeNextDelta):
+        * WebProcess/WebPage/MomentumEventDispatcher.h:
+
 2022-01-05  Per Arne Vollan  <[email protected]>
 
         [macCatalyst][GPUP][NetworkProcess] Block WindowServer connections

Modified: trunk/Source/WebKit/Shared/WebWheelEvent.cpp (287640 => 287641)


--- trunk/Source/WebKit/Shared/WebWheelEvent.cpp	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WebKit/Shared/WebWheelEvent.cpp	2022-01-05 19:29:43 UTC (rev 287641)
@@ -44,7 +44,7 @@
 }
 
 #if PLATFORM(COCOA)
-WebWheelEvent::WebWheelEvent(Type type, const IntPoint& position, const IntPoint& globalPosition, const FloatSize& delta, const FloatSize& wheelTicks, Granularity granularity, bool directionInvertedFromDevice, Phase phase, Phase momentumPhase, bool hasPreciseScrollingDeltas, uint32_t scrollCount, const WebCore::FloatSize& unacceleratedScrollingDelta, OptionSet<Modifier> modifiers, WallTime timestamp, WallTime ioHIDEventTimestamp, std::optional<WebCore::FloatSize> rawPlatformDelta)
+WebWheelEvent::WebWheelEvent(Type type, const IntPoint& position, const IntPoint& globalPosition, const FloatSize& delta, const FloatSize& wheelTicks, Granularity granularity, bool directionInvertedFromDevice, Phase phase, Phase momentumPhase, bool hasPreciseScrollingDeltas, uint32_t scrollCount, const WebCore::FloatSize& unacceleratedScrollingDelta, OptionSet<Modifier> modifiers, WallTime timestamp, WallTime ioHIDEventTimestamp, std::optional<WebCore::FloatSize> rawPlatformDelta, MomentumEndType momentumEndType)
     : WebEvent(type, modifiers, timestamp)
     , m_position(position)
     , m_globalPosition(globalPosition)
@@ -53,6 +53,7 @@
     , m_granularity(granularity)
     , m_phase(phase)
     , m_momentumPhase(momentumPhase)
+    , m_momentumEndType(momentumEndType)
     , m_directionInvertedFromDevice(directionInvertedFromDevice)
     , m_hasPreciseScrollingDeltas(hasPreciseScrollingDeltas)
     , m_ioHIDEventTimestamp(ioHIDEventTimestamp)
@@ -87,6 +88,7 @@
     encoder << m_delta;
     encoder << m_wheelTicks;
     encoder << m_granularity;
+    encoder << m_momentumEndType;
     encoder << m_directionInvertedFromDevice;
 #if PLATFORM(COCOA) || PLATFORM(GTK) || USE(LIBWPE)
     encoder << m_phase;
@@ -115,6 +117,8 @@
         return false;
     if (!decoder.decode(t.m_granularity))
         return false;
+    if (!decoder.decode(t.m_momentumEndType))
+        return false;
     if (!decoder.decode(t.m_directionInvertedFromDevice))
         return false;
 #if PLATFORM(COCOA) || PLATFORM(GTK) || USE(LIBWPE)

Modified: trunk/Source/WebKit/Shared/WebWheelEvent.h (287640 => 287641)


--- trunk/Source/WebKit/Shared/WebWheelEvent.h	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WebKit/Shared/WebWheelEvent.h	2022-01-05 19:29:43 UTC (rev 287641)
@@ -29,6 +29,7 @@
 #include "WebEvent.h"
 #include <WebCore/FloatSize.h>
 #include <WebCore/IntPoint.h>
+#include <wtf/EnumTraits.h>
 
 namespace WebKit {
 
@@ -49,11 +50,17 @@
         PhaseMayBegin    = 1 << 5,
     };
 
+    enum class MomentumEndType : uint8_t {
+        Unknown,
+        Interrupted,
+        Natural,
+    };
+
     WebWheelEvent() = default;
 
     WebWheelEvent(Type, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, const WebCore::FloatSize& delta, const WebCore::FloatSize& wheelTicks, Granularity, OptionSet<Modifier>, WallTime timestamp);
 #if PLATFORM(COCOA)
-    WebWheelEvent(Type, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, const WebCore::FloatSize& delta, const WebCore::FloatSize& wheelTicks, Granularity, bool directionInvertedFromDevice, Phase, Phase momentumPhase, bool hasPreciseScrollingDeltas, uint32_t scrollCount, const WebCore::FloatSize& unacceleratedScrollingDelta, OptionSet<Modifier>, WallTime timestamp, WallTime ioHIDEventTimestamp, std::optional<WebCore::FloatSize> rawPlatformDelta);
+    WebWheelEvent(Type, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, const WebCore::FloatSize& delta, const WebCore::FloatSize& wheelTicks, Granularity, bool directionInvertedFromDevice, Phase, Phase momentumPhase, bool hasPreciseScrollingDeltas, uint32_t scrollCount, const WebCore::FloatSize& unacceleratedScrollingDelta, OptionSet<Modifier>, WallTime timestamp, WallTime ioHIDEventTimestamp, std::optional<WebCore::FloatSize> rawPlatformDelta, MomentumEndType);
 #elif PLATFORM(GTK) || USE(LIBWPE)
     WebWheelEvent(Type, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, const WebCore::FloatSize& delta, const WebCore::FloatSize& wheelTicks, Phase, Phase momentumPhase, Granularity, bool hasPreciseScrollingDeltas, OptionSet<Modifier>, WallTime timestamp);
 #endif
@@ -66,6 +73,7 @@
     bool directionInvertedFromDevice() const { return m_directionInvertedFromDevice; }
     Phase phase() const { return static_cast<Phase>(m_phase); }
     Phase momentumPhase() const { return static_cast<Phase>(m_momentumPhase); }
+    MomentumEndType momentumEndType() const { return m_momentumEndType; }
 #if PLATFORM(COCOA) || PLATFORM(GTK) || USE(LIBWPE)
     bool hasPreciseScrollingDeltas() const { return m_hasPreciseScrollingDeltas; }
 #endif
@@ -90,6 +98,7 @@
     uint32_t m_phase { Phase::PhaseNone };
     uint32_t m_momentumPhase { Phase::PhaseNone };
 
+    MomentumEndType m_momentumEndType { MomentumEndType::Unknown };
     bool m_directionInvertedFromDevice { false };
 #if PLATFORM(COCOA) || PLATFORM(GTK) || USE(LIBWPE)
     bool m_hasPreciseScrollingDeltas { false };
@@ -103,3 +112,16 @@
 };
 
 } // namespace WebKit
+
+namespace WTF {
+
+template<> struct EnumTraits<WebKit::WebWheelEvent::MomentumEndType> {
+    using values = EnumValues<
+    WebKit::WebWheelEvent::MomentumEndType,
+    WebKit::WebWheelEvent::MomentumEndType::Unknown,
+    WebKit::WebWheelEvent::MomentumEndType::Interrupted,
+    WebKit::WebWheelEvent::MomentumEndType::Natural
+    >;
+};
+
+} // namespace WTF

Modified: trunk/Source/WebKit/Shared/WebWheelEventCoalescer.cpp (287640 => 287641)


--- trunk/Source/WebKit/Shared/WebWheelEventCoalescer.cpp	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WebKit/Shared/WebWheelEventCoalescer.cpp	2022-01-05 19:29:43 UTC (rev 287641)
@@ -81,7 +81,7 @@
     if (a.rawPlatformDelta() && b.rawPlatformDelta())
         mergedRawPlatformScrollingDelta = a.rawPlatformDelta().value() + b.rawPlatformDelta().value();
 
-    return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.directionInvertedFromDevice(), b.phase(), b.momentumPhase(), b.hasPreciseScrollingDeltas(), b.scrollCount(), mergedUnacceleratedScrollingDelta, b.modifiers(), b.timestamp(), b.ioHIDEventTimestamp(), mergedRawPlatformScrollingDelta);
+    return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.directionInvertedFromDevice(), b.phase(), b.momentumPhase(), b.hasPreciseScrollingDeltas(), b.scrollCount(), mergedUnacceleratedScrollingDelta, b.modifiers(), b.timestamp(), b.ioHIDEventTimestamp(), mergedRawPlatformScrollingDelta, b.momentumEndType());
 #elif PLATFORM(GTK) || USE(LIBWPE)
     return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.phase(), b.momentumPhase(), b.granularity(), b.hasPreciseScrollingDeltas(), b.modifiers(), b.timestamp());
 #else

Modified: trunk/Source/WebKit/Shared/mac/WebEventFactory.mm (287640 => 287641)


--- trunk/Source/WebKit/Shared/mac/WebEventFactory.mm	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WebKit/Shared/mac/WebEventFactory.mm	2022-01-05 19:29:43 UTC (rev 287641)
@@ -410,33 +410,31 @@
 
     auto modifiers = modifiersForEvent(event);
     auto timestamp = WebCore::eventTimeStampSince1970(event.timestamp);
-
-    auto ioHIDEventTimestamp = [&]() {
+    
+    auto ioHIDEventWallTime = timestamp;
+    std::optional<WebCore::FloatSize> rawPlatformDelta;
+    auto momentumEndType = WebWheelEvent::MomentumEndType::Unknown;
+    
+    ([&] {
         auto cgEvent = event.CGEvent;
         if (!cgEvent)
-            return event.timestamp;
+            return;
 
         auto ioHIDEvent = adoptCF(CGEventCopyIOHIDEvent(cgEvent));
         if (!ioHIDEvent)
-            return event.timestamp;
+            return;
 
         auto ioHIDEventTimestamp = IOHIDEventGetTimeStamp(ioHIDEvent.get()); // IOEventRef timestamp is mach_absolute_time units.
-        return MonotonicTime::fromMachAbsoluteTime(ioHIDEventTimestamp).secondsSinceEpoch().seconds();
-    }();
-
-    auto rawPlatformDelta = [&]() -> std::optional<WebCore::FloatSize> {
-        auto cgEvent = event.CGEvent;
-        if (!cgEvent)
-            return std::nullopt;
-
-        auto ioHIDEvent = adoptCF(CGEventCopyIOHIDEvent(cgEvent));
-        if (!ioHIDEvent)
-            return std::nullopt;
+        auto monotonicIOHIDEventTimestamp = MonotonicTime::fromMachAbsoluteTime(ioHIDEventTimestamp).secondsSinceEpoch().seconds();
+        ioHIDEventWallTime = WebCore::eventTimeStampSince1970(monotonicIOHIDEventTimestamp);
         
-        return { WebCore::FloatSize(-IOHIDEventGetFloatValue(ioHIDEvent.get(), kIOHIDEventFieldScrollX), -IOHIDEventGetFloatValue(ioHIDEvent.get(), kIOHIDEventFieldScrollY)) };
-    }();
+        rawPlatformDelta = { WebCore::FloatSize(-IOHIDEventGetFloatValue(ioHIDEvent.get(), kIOHIDEventFieldScrollX), -IOHIDEventGetFloatValue(ioHIDEvent.get(), kIOHIDEventFieldScrollY)) };
 
-    auto ioHIDEventWallTime = WebCore::eventTimeStampSince1970(ioHIDEventTimestamp);
+#if HAVE(PLATFORM_SCROLL_MOMENTUM_INTERRUPTION_REASON)
+        bool momentumWasInterrupted = IOHIDEventGetScrollMomentum(ioHIDEvent.get()) & kIOHIDEventScrollMomentumInterrupted;
+        momentumEndType = momentumWasInterrupted ? WebWheelEvent::MomentumEndType::Interrupted : WebWheelEvent::MomentumEndType::Natural;
+#endif
+    })();
 
     if (phase == WebWheelEvent::PhaseCancelled) {
         deltaX = 0;
@@ -449,7 +447,7 @@
 
     return WebWheelEvent(WebEvent::Wheel, WebCore::IntPoint(position), WebCore::IntPoint(globalPosition), WebCore::FloatSize(deltaX, deltaY), WebCore::FloatSize(wheelTicksX, wheelTicksY),
         granularity, directionInvertedFromDevice, phase, momentumPhase, hasPreciseScrollingDeltas,
-        scrollCount, unacceleratedScrollingDelta, modifiers, timestamp, ioHIDEventWallTime, rawPlatformDelta);
+        scrollCount, unacceleratedScrollingDelta, modifiers, timestamp, ioHIDEventWallTime, rawPlatformDelta, momentumEndType);
 }
 
 WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, bool replacesSoftSpace, const Vector<WebCore::KeypressCommand>& commands)

Modified: trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.cpp (287640 => 287641)


--- trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.cpp	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.cpp	2022-01-05 19:29:43 UTC (rev 287641)
@@ -87,8 +87,23 @@
         // momentumPhase == PhaseEnded that interrupts.
         bool eventShouldInterruptGesture = !isMomentumEvent || event.momentumPhase() != WebWheelEvent::PhaseChanged;
 
-        if (pageIdentifierChanged || eventShouldInterruptGesture)
+        if (event.momentumPhase() == WebWheelEvent::PhaseEnded) {
+#if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
+            RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher saw momentum ended phase, interrupted=%d", static_cast<int>(event.momentumEndType()));
+#endif
+
+            // Ignore momentumPhase == PhaseEnded if it was due to the natural
+            // end of the animation (as opposed to interruption by placing fingers
+            // on the trackpad), so that our momentum is not cut short if the
+            // deceleration runs longer than the system curve.
+            if (event.momentumEndType() == WebWheelEvent::MomentumEndType::Natural)
+                eventShouldInterruptGesture = false;
+        }
+
+        if (pageIdentifierChanged || eventShouldInterruptGesture) {
+            RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher interrupting synthetic momentum phase");
             didEndMomentumPhase();
+        }
     }
 
     if (event.phase() == WebWheelEvent::PhaseBegan || event.phase() == WebWheelEvent::PhaseChanged) {
@@ -100,18 +115,26 @@
 #endif
     }
 
-    if (eventShouldStartSyntheticMomentumPhase(pageIdentifier, event))
+    if (eventShouldStartSyntheticMomentumPhase(pageIdentifier, event)) {
         didStartMomentumPhase(pageIdentifier, event);
+        m_isInOverriddenPlatformMomentumGesture = true;
+    }
 
-    bool isMomentumEventDuringSyntheticGesture = isMomentumEvent && m_currentGesture.active;
+    // Consume any incoming momentum events while we're generating a synthetic
+    // momentum gesture *or* a platform momentum phase that was overridden
+    // is still running after we finished the synthetic gesture.
+    bool shouldIgnoreIncomingPlatformEvent = isMomentumEvent && (m_isInOverriddenPlatformMomentumGesture || m_currentGesture.active);
 
+    if (event.momentumPhase() == WebWheelEvent::PhaseEnded)
+        m_isInOverriddenPlatformMomentumGesture = false;
+
 #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
-    if (isMomentumEventDuringSyntheticGesture)
+    if (shouldIgnoreIncomingPlatformEvent)
         m_currentGesture.accumulatedEventOffset += event.delta();
 
     auto combinedPhase = (event.phase() << 8) | (event.momentumPhase());
     m_currentLogState.totalEventOffset += event.delta().height();
-    if (!isMomentumEventDuringSyntheticGesture) {
+    if (!shouldIgnoreIncomingPlatformEvent) {
         // Log events that we don't block to the generated offsets log as well,
         // even though we didn't technically generate them, just passed them through.
         m_currentLogState.totalGeneratedOffset += event.delta().height();
@@ -121,8 +144,7 @@
     
 #endif
 
-    // Consume any normal momentum events while we're inside a synthetic momentum gesture.
-    return isMomentumEventDuringSyntheticGesture;
+    return shouldIgnoreIncomingPlatformEvent;
 }
 
 static float appKitScrollMultiplierForEvent(const WebWheelEvent& event)
@@ -170,7 +192,8 @@
         m_lastIncomingEvent->modifiers(),
         time,
         time,
-        { });
+        { },
+        WebWheelEvent::MomentumEndType::Unknown);
     m_dispatcher.internalWheelEvent(m_currentGesture.pageIdentifier, syntheticEvent, m_lastRubberBandableEdges, EventDispatcher::WheelEventOrigin::MomentumEventDispatcher);
 
 #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
@@ -223,7 +246,7 @@
     dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseEnded, { });
 
 #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
-    RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher saw momentum end phase with total offset %.1f %.1f, duration %f (event offset would have been %.1f %.1f) (tail index %d of %zu)", m_currentGesture.currentOffset.width(), m_currentGesture.currentOffset.height(), (MonotonicTime::now() - m_currentGesture.startTime).seconds(), m_currentGesture.accumulatedEventOffset.width(), m_currentGesture.accumulatedEventOffset.height(), m_currentGesture.currentTailDeltaIndex, m_currentGesture.tailDeltaTable.size());
+    RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher ending synthetic momentum phase with total offset %.1f %.1f, duration %f (event offset would have been %.1f %.1f) (tail index %d of %zu)", m_currentGesture.currentOffset.width(), m_currentGesture.currentOffset.height(), (MonotonicTime::now() - m_currentGesture.startTime).seconds(), m_currentGesture.accumulatedEventOffset.width(), m_currentGesture.accumulatedEventOffset.height(), m_currentGesture.currentTailDeltaIndex, m_currentGesture.tailDeltaTable.size());
     m_dispatcher.queue().dispatchAfter(1_s, [this] {
         flushLog();
     });
@@ -242,7 +265,7 @@
 #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
     WTF::TextStream stream(WTF::TextStream::LineMode::SingleLine);
     stream << curve;
-    RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher set curve %s", stream.release().utf8().data());
+    RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher set curve %{public}s", stream.release().utf8().data());
 #endif
 }
 
@@ -299,7 +322,7 @@
         startDisplayLink();
 }
 
-WebCore::FloatSize MomentumEventDispatcher::consumeDeltaForCurrentTime()
+std::optional<WebCore::FloatSize> MomentumEventDispatcher::consumeDeltaForCurrentTime()
 {
     WebCore::FloatSize delta;
 
@@ -311,7 +334,7 @@
         if (m_currentGesture.currentTailDeltaIndex < m_currentGesture.tailDeltaTable.size())
             delta = -m_currentGesture.tailDeltaTable[m_currentGesture.currentTailDeltaIndex++];
         else
-            delta = { };
+            return std::nullopt;
     }
 
     m_currentGesture.currentOffset += delta;
@@ -331,7 +354,16 @@
     if (!displayProperties || displayID != displayProperties->displayID)
         return;
 
-    dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseChanged, consumeDeltaForCurrentTime());
+    auto delta = consumeDeltaForCurrentTime();
+    if (!delta) {
+#if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
+        RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher completed synthetic momentum phase");
+#endif
+        didEndMomentumPhase();
+        return;
+    }
+
+    dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseChanged, *delta);
 }
 
 void MomentumEventDispatcher::didReceiveScrollEventWithInterval(WebCore::FloatSize size, Seconds frameInterval)

Modified: trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.h (287640 => 287641)


--- trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.h	2022-01-05 19:19:35 UTC (rev 287640)
+++ trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.h	2022-01-05 19:29:43 UTC (rev 287641)
@@ -86,7 +86,7 @@
     void equalizeTailGaps();
 
     // Once consumed, this delta *must* be dispatched in an event.
-    WebCore::FloatSize consumeDeltaForCurrentTime();
+    std::optional<WebCore::FloatSize> consumeDeltaForCurrentTime();
 
     WebCore::FloatSize offsetAtTime(Seconds);
     std::pair<WebCore::FloatSize, WebCore::FloatSize> computeNextDelta(WebCore::FloatSize currentUnacceleratedDelta);
@@ -125,6 +125,7 @@
     std::optional<WallTime> m_lastScrollTimestamp;
     std::optional<WebWheelEvent> m_lastIncomingEvent;
     WebCore::RectEdges<bool> m_lastRubberBandableEdges;
+    bool m_isInOverriddenPlatformMomentumGesture { false };
 
     struct {
         bool active { false };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to