<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[286671] trunk/Source/WebKit</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/286671">286671</a></dd>
<dt>Author</dt> <dd>timothy_horton@apple.com</dd>
<dt>Date</dt> <dd>2021-12-08 11:58:13 -0800 (Wed, 08 Dec 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Momentum Event Dispatcher: Momentum tail should have montonically decreasing deltas and tail gaps
https://bugs.webkit.org/show_bug.cgi?id=233993
<rdar://problem/86118367>

Reviewed by Simon Fraser.

* WebProcess/WebPage/MomentumEventDispatcher.cpp:
(WebKit::MomentumEventDispatcher::consumeDeltaForCurrentTime):
(WebKit::MomentumEventDispatcher::buildOffsetTableWithInitialDelta):
(WebKit::MomentumEventDispatcher::computeNextDelta):
In order to avoid visual stutter due to integral rounding of the
deltas we dispatch in the momentum phase, switch to a table of
deltas instead of interpolating along the offset curve during the
tail end of the animation (when the rounding makes up a large
proportion of each delta).

(WebKit::MomentumEventDispatcher::equalizeTailGaps):
Sort the deltas up until the first zero to ensure a lack of unexpected
perceptual acceleration, and then inject skipped frames in order to
ensure that frames that have effective scroll movement (non-zero deltas)
are always spaced equally-or-further apart than earlier ones, but
never closer together (which, again, would be percieved as acceleration).

(WebKit::MomentumEventDispatcher::handleWheelEvent):
(WebKit::MomentumEventDispatcher::pushLogEntry):
(WebKit::MomentumEventDispatcher::flushLog):
Lastly, adjust some logging to make it easier to tell which row in
the output corresponds to an event delta or generated delta, so it's
easier to find skipped frames.
* WebProcess/WebPage/MomentumEventDispatcher.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebPageMomentumEventDispatchercpp">trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.cpp</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebPageMomentumEventDispatcherh">trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (286670 => 286671)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2021-12-08 19:46:15 UTC (rev 286670)
+++ trunk/Source/WebKit/ChangeLog       2021-12-08 19:58:13 UTC (rev 286671)
</span><span class="lines">@@ -1,3 +1,36 @@
</span><ins>+2021-12-08  Tim Horton  <timothy_horton@apple.com>
+
+        Momentum Event Dispatcher: Momentum tail should have montonically decreasing deltas and tail gaps
+        https://bugs.webkit.org/show_bug.cgi?id=233993
+        <rdar://problem/86118367>
+
+        Reviewed by Simon Fraser.
+
+        * WebProcess/WebPage/MomentumEventDispatcher.cpp:
+        (WebKit::MomentumEventDispatcher::consumeDeltaForCurrentTime):
+        (WebKit::MomentumEventDispatcher::buildOffsetTableWithInitialDelta):
+        (WebKit::MomentumEventDispatcher::computeNextDelta):
+        In order to avoid visual stutter due to integral rounding of the
+        deltas we dispatch in the momentum phase, switch to a table of
+        deltas instead of interpolating along the offset curve during the
+        tail end of the animation (when the rounding makes up a large
+        proportion of each delta).
+
+        (WebKit::MomentumEventDispatcher::equalizeTailGaps):
+        Sort the deltas up until the first zero to ensure a lack of unexpected
+        perceptual acceleration, and then inject skipped frames in order to
+        ensure that frames that have effective scroll movement (non-zero deltas)
+        are always spaced equally-or-further apart than earlier ones, but
+        never closer together (which, again, would be percieved as acceleration).
+
+        (WebKit::MomentumEventDispatcher::handleWheelEvent):
+        (WebKit::MomentumEventDispatcher::pushLogEntry):
+        (WebKit::MomentumEventDispatcher::flushLog):
+        Lastly, adjust some logging to make it easier to tell which row in
+        the output corresponds to an event delta or generated delta, so it's
+        easier to find skipped frames.
+        * WebProcess/WebPage/MomentumEventDispatcher.h:
+
</ins><span class="cx"> 2021-12-08  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Make KVO work for WKWebpagePreferences._captivePortalModeEnabled
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebPageMomentumEventDispatchercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.cpp (286670 => 286671)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.cpp       2021-12-08 19:46:15 UTC (rev 286670)
+++ trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.cpp  2021-12-08 19:58:13 UTC (rev 286671)
</span><span class="lines">@@ -113,15 +113,15 @@
</span><span class="cx">         m_currentGesture.accumulatedEventOffset += event.delta();
</span><span class="cx"> 
</span><span class="cx">     auto combinedPhase = (event.phase() << 8) | (event.momentumPhase());
</span><del>-    m_currentLogState.latestEventPhase = combinedPhase;
</del><span class="cx">     m_currentLogState.totalEventOffset += event.delta().height();
</span><span class="cx">     if (!isMomentumEventDuringSyntheticGesture) {
</span><span class="cx">         // Log events that we don't block to the generated offsets log as well,
</span><span class="cx">         // even though we didn't technically generate them, just passed them through.
</span><del>-        m_currentLogState.latestGeneratedPhase = combinedPhase;
</del><span class="cx">         m_currentLogState.totalGeneratedOffset += event.delta().height();
</span><del>-    }
-    pushLogEntry();
</del><ins>+        pushLogEntry(combinedPhase, combinedPhase);
+    } else
+        pushLogEntry(0, combinedPhase);
+    
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     // Consume any normal momentum events while we're inside a synthetic momentum gesture.
</span><span class="lines">@@ -177,9 +177,8 @@
</span><span class="cx">     m_dispatcher.internalWheelEvent(m_currentGesture.pageIdentifier, syntheticEvent, m_lastRubberBandableEdges, EventDispatcher::WheelEventOrigin::MomentumEventDispatcher);
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
</span><del>-    m_currentLogState.latestGeneratedPhase = phase;
</del><span class="cx">     m_currentLogState.totalGeneratedOffset += appKitAcceleratedDelta.height();
</span><del>-    pushLogEntry();
</del><ins>+    pushLogEntry(phase, 0);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -219,7 +218,7 @@
</span><span class="cx">     dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseEnded, { });
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
</span><del>-    RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher saw momentum end phase with total offset %.1f %.1f, duration %f (event offset would have been %.1f %.1f)", m_currentGesture.currentOffset.width(), m_currentGesture.currentOffset.height(), (MonotonicTime::now() - m_currentGesture.startTime).seconds(), m_currentGesture.accumulatedEventOffset.width(), m_currentGesture.accumulatedEventOffset.height());
</del><ins>+    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());
</ins><span class="cx">     m_dispatcher.queue().dispatchAfter(1_s, [this] {
</span><span class="cx">         flushLog();
</span><span class="cx">     });
</span><span class="lines">@@ -294,16 +293,19 @@
</span><span class="cx"> 
</span><span class="cx"> WebCore::FloatSize MomentumEventDispatcher::consumeDeltaForCurrentTime()
</span><span class="cx"> {
</span><ins>+    WebCore::FloatSize delta;
+
</ins><span class="cx">     auto animationTime = MonotonicTime::now() - m_currentGesture.startTime;
</span><del>-    auto desiredOffset = offsetAtTime(animationTime);
</del><ins>+    if (animationTime < m_currentGesture.tailStartDelay) {
+        auto desiredOffset = offsetAtTime(animationTime);
+        delta = roundedIntSize(desiredOffset - m_currentGesture.currentOffset);
+    } else {
+        if (m_currentGesture.currentTailDeltaIndex < m_currentGesture.tailDeltaTable.size())
+            delta = -m_currentGesture.tailDeltaTable[m_currentGesture.currentTailDeltaIndex++];
+        else
+            delta = { };
+    }
</ins><span class="cx"> 
</span><del>-#if !ENABLE(MOMENTUM_EVENT_DISPATCHER_PREMATURE_ROUNDING)
-    // Intentional delta rounding (but at the end!).
-    WebCore::FloatSize delta = roundedIntSize(desiredOffset - m_currentGesture.currentOffset);
-#else
-    WebCore::FloatSize delta = desiredOffset - m_currentGesture.currentOffset;
-#endif
-
</del><span class="cx">     m_currentGesture.currentOffset += delta;
</span><span class="cx"> 
</span><span class="cx">     if (m_currentGesture.initiatingEvent->directionInvertedFromDevice())
</span><span class="lines">@@ -363,27 +365,126 @@
</span><span class="cx"> 
</span><span class="cx"> void MomentumEventDispatcher::buildOffsetTableWithInitialDelta(WebCore::FloatSize initialUnacceleratedDelta)
</span><span class="cx"> {
</span><del>-#if ENABLE(MOMENTUM_EVENT_DISPATCHER_PREMATURE_ROUNDING)
-    m_currentGesture.carryOffset = { };
-#endif
</del><span class="cx">     m_currentGesture.offsetTable.clear();
</span><span class="cx"> 
</span><span class="cx">     WebCore::FloatSize accumulatedOffset;
</span><span class="cx">     WebCore::FloatSize unacceleratedDelta = initialUnacceleratedDelta;
</span><span class="cx"> 
</span><ins>+    float physicalCurveMultiplier = idealCurveFrameRate / m_currentGesture.accelerationCurve->frameRate();
+    bool inTail = false;
+    WebCore::FloatSize tailCarry;
+
</ins><span class="cx">     do {
</span><span class="cx">         WebCore::FloatSize acceleratedDelta;
</span><span class="cx">         std::tie(unacceleratedDelta, acceleratedDelta) = computeNextDelta(unacceleratedDelta);
</span><span class="cx"> 
</span><ins>+        const float tailStartUnacceleratedDelta = 6.f;
+        if (!inTail && std::abs(unacceleratedDelta.width()) < tailStartUnacceleratedDelta && std::abs(unacceleratedDelta.height()) < tailStartUnacceleratedDelta) {
+            inTail = true;
+            m_currentGesture.tailStartDelay = idealCurveFrameInterval * m_currentGesture.offsetTable.size();
+        }
+
+        if (inTail) {
+            auto tailDelta = acceleratedDelta * physicalCurveMultiplier;
+            auto deltaWithCarry = tailDelta + tailCarry;
+            auto quantizedDelta = roundedIntSize(deltaWithCarry);
+            tailCarry = deltaWithCarry - quantizedDelta;
+            m_currentGesture.tailDeltaTable.append(quantizedDelta);
+        }
+
</ins><span class="cx">         accumulatedOffset += acceleratedDelta;
</span><span class="cx">         m_currentGesture.offsetTable.append(accumulatedOffset);
</span><ins>+
</ins><span class="cx">     } while (std::abs(unacceleratedDelta.width()) > 0.5 || std::abs(unacceleratedDelta.height()) > 0.5);
</span><span class="cx"> 
</span><ins>+    equalizeTailGaps();
+
</ins><span class="cx"> #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
</span><del>-    RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher built table with %ld frames, initial delta %f %f, distance %f %f (initial delta from last changed event %f %f)", m_currentGesture.offsetTable.size(), initialUnacceleratedDelta.width(), initialUnacceleratedDelta.height(), accumulatedOffset.width(), accumulatedOffset.height(), m_lastActivePhaseDelta.width(), m_lastActivePhaseDelta.height());
</del><ins>+    RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher built table with %ld frames, %.1f seconds (%ld tail frames, %.1f seconds, starting at %.1f), initial delta %.1f %.1f, distance %.1f %.1f (initial delta from last changed event %.1f %.1f)", m_currentGesture.offsetTable.size(), idealCurveFrameInterval.seconds() * m_currentGesture.offsetTable.size(), m_currentGesture.tailDeltaTable.size(), m_currentGesture.tailDeltaTable.size() * (1.f / m_currentGesture.accelerationCurve->frameRate()), m_currentGesture.tailStartDelay.seconds(), initialUnacceleratedDelta.width(), initialUnacceleratedDelta.height(), accumulatedOffset.width(), accumulatedOffset.height(), m_lastActivePhaseDelta.width(), m_lastActivePhaseDelta.height());
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MomentumEventDispatcher::equalizeTailGaps()
+{
+    // Sort the deltas up until the first zero to ensure a lack of unexpected
+    // perceptual acceleration, and then inject skipped frames in order to
+    // ensure that frames that have effective scroll movement (non-zero deltas)
+    // are always spaced equally-or-further apart than earlier ones, but
+    // never closer together.
+
+    auto& table = m_currentGesture.tailDeltaTable;
+    size_t initialTableSize = table.size();
+
+    enum Axis { Horizontal, Vertical };
+    Vector<float> deltas[2];
+    unsigned firstZeroIndex[2] = { 0, 0 };
+    deltas[Horizontal].reserveInitialCapacity(initialTableSize);
+    deltas[Vertical].reserveInitialCapacity(initialTableSize);
+    for (unsigned i = 0; i < initialTableSize; i++) {
+        deltas[Horizontal].uncheckedAppend(table[i].width());
+        if (!firstZeroIndex[Horizontal] && !table[i].width())
+            firstZeroIndex[Horizontal] = i;
+
+        deltas[Vertical].uncheckedAppend(table[i].height());
+        if (!firstZeroIndex[Vertical] && !table[i].height())
+            firstZeroIndex[Vertical] = i;
+    }
+    
+    if (auto index = firstZeroIndex[Horizontal])
+        std::sort(deltas[Horizontal].begin(), std::next(deltas[Horizontal].begin(), index));
+    if (auto index = firstZeroIndex[Vertical])
+        std::sort(deltas[Vertical].begin(), std::next(deltas[Vertical].begin(), index));
+
+    // GapSize is a count of contiguous frames with zero deltas.
+    typedef unsigned GapSize[2];
+    GapSize minimumGap = { 0, 0 };
+    GapSize currentGap = { 0, 0 };
+    GapSize remainingGapToGenerate = { 0, 0 };
+    unsigned originalTableIndex[2] = { 0, 0 };
+
+    auto takeNextDelta = [&] (uint8_t axis) -> float {
+        if (originalTableIndex[axis] >= initialTableSize)
+            return 0.f;
+
+        if (remainingGapToGenerate[axis]) {
+            --remainingGapToGenerate[axis];
+            ++currentGap[axis];
+            return 0.f;
+        }
+
+        auto value = deltas[axis][originalTableIndex[axis]];
+        if (value) {
+            minimumGap[axis] = std::max(minimumGap[axis], currentGap[axis]);
+            remainingGapToGenerate[axis] = minimumGap[axis] - currentGap[axis];
+            if (remainingGapToGenerate[axis]) {
+                --remainingGapToGenerate[axis];
+                ++currentGap[axis];
+                return 0.f;
+            }
+
+            currentGap[axis] = 0;
+        } else
+            ++currentGap[axis];
+
+        ++originalTableIndex[axis];
+
+        return value;
+    };
+
+    size_t finalTableSize = 0;
+    table.shrink(0);
+
+    while (originalTableIndex[Horizontal] < initialTableSize || originalTableIndex[Vertical] < initialTableSize) {
+        WebCore::FloatSize delta(takeNextDelta(Horizontal), takeNextDelta(Vertical));
+        table.append(delta);
+
+        if (!delta.isZero())
+            finalTableSize = table.size();
+    }
+
+    table.shrink(finalTableSize);
+}
+
</ins><span class="cx"> static float interpolate(float a, float b, float t)
</span><span class="cx"> {
</span><span class="cx">     return a + t * (b - a);
</span><span class="lines">@@ -433,28 +534,8 @@
</span><span class="cx">     float decayRate = momentumDecayRate(unacceleratedDelta, idealCurveFrameInterval);
</span><span class="cx">     unacceleratedDelta.scale(decayRate);
</span><span class="cx"> 
</span><del>-    auto quantizedUnacceleratedDelta = unacceleratedDelta;
-
-#if ENABLE(MOMENTUM_EVENT_DISPATCHER_PREMATURE_ROUNDING)
-    // Round and carry.
-    int32_t quantizedX = std::round(quantizedUnacceleratedDelta.width());
-    int32_t quantizedY = std::round(quantizedUnacceleratedDelta.height());
-
-    if (std::abs(quantizedUnacceleratedDelta.width()) < 1 && std::abs(quantizedUnacceleratedDelta.height()) < 1) {
-        float deltaXIncludingCarry = quantizedUnacceleratedDelta.width() + m_currentGesture.carryOffset.width();
-        float deltaYIncludingCarry = quantizedUnacceleratedDelta.height() + m_currentGesture.carryOffset.height();
-
-        // Intentional truncation.
-        quantizedX = deltaXIncludingCarry;
-        quantizedY = deltaYIncludingCarry;
-        m_currentGesture.carryOffset = { deltaXIncludingCarry - quantizedX, deltaYIncludingCarry - quantizedY };
-    }
-
-    quantizedUnacceleratedDelta = { static_cast<float>(quantizedX), static_cast<float>(quantizedY) };
-#endif
-
</del><span class="cx">     // The delta queue operates on pre-acceleration deltas, so insert the new event *before* accelerating.
</span><del>-    didReceiveScrollEventWithInterval(quantizedUnacceleratedDelta, idealCurveFrameInterval);
</del><ins>+    didReceiveScrollEventWithInterval(unacceleratedDelta, idealCurveFrameInterval);
</ins><span class="cx"> 
</span><span class="cx">     auto accelerateAxis = [&] (HistoricalDeltas& deltas, float value) {
</span><span class="cx">         float totalDelta = 0;
</span><span class="lines">@@ -499,8 +580,8 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     WebCore::FloatSize acceleratedDelta(
</span><del>-        accelerateAxis(m_deltaHistoryX, quantizedUnacceleratedDelta.width()),
-        accelerateAxis(m_deltaHistoryY, quantizedUnacceleratedDelta.height())
</del><ins>+        accelerateAxis(m_deltaHistoryX, unacceleratedDelta.width()),
+        accelerateAxis(m_deltaHistoryY, unacceleratedDelta.height())
</ins><span class="cx">     );
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
</span><span class="lines">@@ -512,9 +593,11 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
</span><span class="cx"> 
</span><del>-void MomentumEventDispatcher::pushLogEntry()
</del><ins>+void MomentumEventDispatcher::pushLogEntry(uint32_t generatedPhase, uint32_t eventPhase)
</ins><span class="cx"> {
</span><span class="cx">     m_currentLogState.time = MonotonicTime::now();
</span><ins>+    m_currentLogState.generatedPhase = generatedPhase;
+    m_currentLogState.eventPhase = eventPhase;
</ins><span class="cx">     m_log.append(m_currentLogState);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -529,7 +612,7 @@
</span><span class="cx">     auto startTime = m_log[0].time;
</span><span class="cx">     RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher event log: time,generatedOffset,generatedPhase,eventOffset,eventPhase");
</span><span class="cx">     for (const auto& entry : m_log)
</span><del>-        RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher event log: %f,%f,%d,%f,%d", (entry.time - startTime).seconds(), entry.totalGeneratedOffset, entry.latestGeneratedPhase, entry.totalEventOffset, entry.latestEventPhase);
</del><ins>+        RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher event log: %f,%f,%d,%f,%d", (entry.time - startTime).seconds(), entry.totalGeneratedOffset, entry.generatedPhase, entry.totalEventOffset, entry.eventPhase);
</ins><span class="cx"> 
</span><span class="cx">     m_log.clear();
</span><span class="cx">     m_currentLogState = { };
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebPageMomentumEventDispatcherh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.h (286670 => 286671)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.h 2021-12-08 19:46:15 UTC (rev 286670)
+++ trunk/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.h    2021-12-08 19:58:13 UTC (rev 286671)
</span><span class="lines">@@ -27,8 +27,6 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MOMENTUM_EVENT_DISPATCHER)
</span><span class="cx"> 
</span><del>-// FIXME: Remove this once we decide which version we want.
-#define ENABLE_MOMENTUM_EVENT_DISPATCHER_PREMATURE_ROUNDING 0
</del><span class="cx"> #define ENABLE_MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING 1
</span><span class="cx"> 
</span><span class="cx"> #include "DisplayLinkObserverID.h"
</span><span class="lines">@@ -80,6 +78,7 @@
</span><span class="cx">     void dispatchSyntheticMomentumEvent(WebWheelEvent::Phase, WebCore::FloatSize delta);
</span><span class="cx"> 
</span><span class="cx">     void buildOffsetTableWithInitialDelta(WebCore::FloatSize);
</span><ins>+    void equalizeTailGaps();
</ins><span class="cx"> 
</span><span class="cx">     // Once consumed, this delta *must* be dispatched in an event.
</span><span class="cx">     WebCore::FloatSize consumeDeltaForCurrentTime();
</span><span class="lines">@@ -91,7 +90,7 @@
</span><span class="cx">     void didReceiveScrollEvent(const WebWheelEvent&);
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
</span><del>-    void pushLogEntry();
</del><ins>+    void pushLogEntry(uint32_t generatedPhase, uint32_t eventPhase);
</ins><span class="cx">     void flushLog();
</span><span class="cx"> 
</span><span class="cx">     WebCore::FloatSize m_lastActivePhaseDelta;
</span><span class="lines">@@ -102,8 +101,8 @@
</span><span class="cx">         float totalGeneratedOffset { 0 };
</span><span class="cx">         float totalEventOffset { 0 };
</span><span class="cx"> 
</span><del>-        uint32_t latestGeneratedPhase { 0 };
-        uint32_t latestEventPhase { 0 };
</del><ins>+        uint32_t generatedPhase { 0 };
+        uint32_t eventPhase { 0 };
</ins><span class="cx">     };
</span><span class="cx">     LogEntry m_currentLogState;
</span><span class="cx">     Vector<LogEntry> m_log;
</span><span class="lines">@@ -133,7 +132,10 @@
</span><span class="cx">         WebCore::FloatSize currentOffset;
</span><span class="cx">         MonotonicTime startTime;
</span><span class="cx"> 
</span><del>-        Vector<WebCore::FloatSize> offsetTable;
</del><ins>+        Vector<WebCore::FloatSize> offsetTable; // Always at 60Hz intervals.
+        Vector<WebCore::FloatSize> tailDeltaTable; // Always at event dispatch intervals.
+        Seconds tailStartDelay;
+        unsigned currentTailDeltaIndex { 0 };
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
</span><span class="cx">         WebCore::FloatSize accumulatedEventOffset;
</span></span></pre>
</div>
</div>

</body>
</html>