<!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>[282721] trunk/Source/WebCore</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/282721">282721</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2021-09-17 23:03:19 -0700 (Fri, 17 Sep 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Replace all the complex math in ScrollAnimationSmooth with a single call into a CubicBezierTimingFunction
https://bugs.webkit.org/show_bug.cgi?id=230436

Reviewed by Tim Horton.

ScrollAnimationSmooth had a lot of math that computed velocities for attack, drift and
release phases, but they resulted in odd-feeling animations for long scrolls. We can replace
it all, and get nice-feeling scrolls, by just using an ease-in-out timing function.

Duration is compusted from distance with a max of 200ms, matching macOS behavior.

* platform/ScrollAnimationSmooth.cpp:
(WebCore::ScrollAnimationSmooth::ScrollAnimationSmooth):
(WebCore::ScrollAnimationSmooth::startAnimatedScroll):
(WebCore::ScrollAnimationSmooth::startAnimatedScrollToDestination):
(WebCore::ScrollAnimationSmooth::startOrRetargetAnimation):
(WebCore::ScrollAnimationSmooth::updateScrollExtents):
(WebCore::linearInterpolation):
(WebCore::ScrollAnimationSmooth::animateScroll):
(WebCore::ScrollAnimationSmooth::animationTimerFired):
(WebCore::ScrollAnimationSmooth::initializeAxesData): Deleted.
(WebCore::curveAt): Deleted.
(WebCore::attackCurve): Deleted.
(WebCore::releaseCurve): Deleted.
(WebCore::coastCurve): Deleted.
(WebCore::curveIntegralAt): Deleted.
(WebCore::attackArea): Deleted.
(WebCore::releaseArea): Deleted.
(WebCore::getAnimationParametersForGranularity): Deleted.
(WebCore::ScrollAnimationSmooth::updatePerAxisData): Deleted.
* platform/ScrollAnimationSmooth.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformScrollAnimationSmoothcpp">trunk/Source/WebCore/platform/ScrollAnimationSmooth.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformScrollAnimationSmoothh">trunk/Source/WebCore/platform/ScrollAnimationSmooth.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsGeometryUtilitiescpp">trunk/Source/WebCore/platform/graphics/GeometryUtilities.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsGeometryUtilitiesh">trunk/Source/WebCore/platform/graphics/GeometryUtilities.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (282720 => 282721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-09-18 04:24:53 UTC (rev 282720)
+++ trunk/Source/WebCore/ChangeLog      2021-09-18 06:03:19 UTC (rev 282721)
</span><span class="lines">@@ -1,5 +1,39 @@
</span><span class="cx"> 2021-09-17  Simon Fraser  <simon.fraser@apple.com>
</span><span class="cx"> 
</span><ins>+        Replace all the complex math in ScrollAnimationSmooth with a single call into a CubicBezierTimingFunction
+        https://bugs.webkit.org/show_bug.cgi?id=230436
+
+        Reviewed by Tim Horton.
+
+        ScrollAnimationSmooth had a lot of math that computed velocities for attack, drift and
+        release phases, but they resulted in odd-feeling animations for long scrolls. We can replace
+        it all, and get nice-feeling scrolls, by just using an ease-in-out timing function.
+
+        Duration is compusted from distance with a max of 200ms, matching macOS behavior.
+
+        * platform/ScrollAnimationSmooth.cpp:
+        (WebCore::ScrollAnimationSmooth::ScrollAnimationSmooth):
+        (WebCore::ScrollAnimationSmooth::startAnimatedScroll):
+        (WebCore::ScrollAnimationSmooth::startAnimatedScrollToDestination):
+        (WebCore::ScrollAnimationSmooth::startOrRetargetAnimation):
+        (WebCore::ScrollAnimationSmooth::updateScrollExtents):
+        (WebCore::linearInterpolation):
+        (WebCore::ScrollAnimationSmooth::animateScroll):
+        (WebCore::ScrollAnimationSmooth::animationTimerFired):
+        (WebCore::ScrollAnimationSmooth::initializeAxesData): Deleted.
+        (WebCore::curveAt): Deleted.
+        (WebCore::attackCurve): Deleted.
+        (WebCore::releaseCurve): Deleted.
+        (WebCore::coastCurve): Deleted.
+        (WebCore::curveIntegralAt): Deleted.
+        (WebCore::attackArea): Deleted.
+        (WebCore::releaseArea): Deleted.
+        (WebCore::getAnimationParametersForGranularity): Deleted.
+        (WebCore::ScrollAnimationSmooth::updatePerAxisData): Deleted.
+        * platform/ScrollAnimationSmooth.h:
+
+2021-09-17  Simon Fraser  <simon.fraser@apple.com>
+
</ins><span class="cx">         Move scrollbar-related code out of ScrollAnimator and into ScrollbarsController
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=230295
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformScrollAnimationSmoothcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ScrollAnimationSmooth.cpp (282720 => 282721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/ScrollAnimationSmooth.cpp  2021-09-18 04:24:53 UTC (rev 282720)
+++ trunk/Source/WebCore/platform/ScrollAnimationSmooth.cpp     2021-09-18 06:03:19 UTC (rev 282721)
</span><span class="lines">@@ -29,7 +29,9 @@
</span><span class="cx"> #include "ScrollAnimationSmooth.h"
</span><span class="cx"> 
</span><span class="cx"> #include "FloatPoint.h"
</span><ins>+#include "GeometryUtilities.h"
</ins><span class="cx"> #include "ScrollableArea.h"
</span><ins>+#include "TimingFunction.h"
</ins><span class="cx"> 
</span><span class="cx"> #if USE(GLIB_EVENT_LOOP)
</span><span class="cx"> #include <wtf/glib/RunLoopSourcePriority.h>
</span><span class="lines">@@ -37,14 +39,13 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-static const double frameRate = 60;
-static const Seconds tickTime = 1_s / frameRate;
-static const Seconds minimumTimerInterval { 1_ms };
-static const double smoothFactorForProgrammaticScroll = 1;
</del><ins>+static const float animationSpeed { 1000.0f };
+static const Seconds maxAnimationDuration { 200_ms };
</ins><span class="cx"> 
</span><span class="cx"> ScrollAnimationSmooth::ScrollAnimationSmooth(ScrollAnimationClient& client)
</span><span class="cx">     : ScrollAnimation(client)
</span><span class="cx">     , m_animationTimer(RunLoop::current(), this, &ScrollAnimationSmooth::animationTimerFired)
</span><ins>+    , m_easeInOutTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::TimingFunctionPreset::EaseInOut))
</ins><span class="cx"> {
</span><span class="cx"> #if USE(GLIB_EVENT_LOOP)
</span><span class="cx">     m_animationTimer.setPriority(WTF::RunLoopSourcePriority::DisplayRefreshMonitorTimer);
</span><span class="lines">@@ -53,34 +54,34 @@
</span><span class="cx"> 
</span><span class="cx"> ScrollAnimationSmooth::~ScrollAnimationSmooth() = default;
</span><span class="cx"> 
</span><del>-bool ScrollAnimationSmooth::startAnimatedScroll(ScrollbarOrientation orientation, ScrollGranularity granularity, const FloatPoint& fromPosition, float step, float multiplier)
</del><ins>+bool ScrollAnimationSmooth::startAnimatedScroll(ScrollbarOrientation orientation, ScrollGranularity, const FloatPoint& fromPosition, float step, float multiplier)
</ins><span class="cx"> {
</span><del>-    float minScrollPosition;
-    float maxScrollPosition;
</del><ins>+    m_startPosition = fromPosition;
+    auto destinationPosition = fromPosition;
+    switch (orientation) {
+    case HorizontalScrollbar:
+        destinationPosition.setX(destinationPosition.x() + step * multiplier);
+        break;
+    case VerticalScrollbar:
+        destinationPosition.setY(destinationPosition.y() + step * multiplier);
+        break;
+    }
+
+    m_duration = durationFromDistance(destinationPosition - m_startPosition);
+    WTFLogAlways("Animation duration: %.2fms", m_duration.milliseconds());
+
</ins><span class="cx">     auto extents = m_client.scrollExtentsForAnimation(*this);
</span><del>-    initializeAxesData(extents, fromPosition);
-
-    if (orientation == HorizontalScrollbar) {
-        minScrollPosition = extents.minimumScrollPosition.x();
-        maxScrollPosition = extents.maximumScrollPosition.x();
-    } else {
-        minScrollPosition = extents.minimumScrollPosition.y();
-        maxScrollPosition = extents.maximumScrollPosition.y();
-    }
-    auto& data = orientation == HorizontalScrollbar ? m_horizontalData : m_verticalData;
-    bool needToScroll = updatePerAxisData(data, granularity, data.desiredPosition + (step * multiplier), minScrollPosition, maxScrollPosition);
-    if (needToScroll && !isActive()) {
-        m_startTime = orientation == HorizontalScrollbar ? m_horizontalData.startTime : m_verticalData.startTime;
-        animationTimerFired();
-    }
-    return needToScroll;
</del><ins>+    return startOrRetargetAnimation(extents, destinationPosition);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool ScrollAnimationSmooth::startAnimatedScrollToDestination(const FloatPoint& fromPosition, const FloatPoint& destinationPosition)
</span><span class="cx"> {
</span><ins>+    m_startPosition = fromPosition;
+    m_duration = durationFromDistance(destinationPosition - m_startPosition);
+
+    WTFLogAlways("Animation duration: %.2fms", m_duration.milliseconds());
+
</ins><span class="cx">     auto extents = m_client.scrollExtentsForAnimation(*this);
</span><del>-    initializeAxesData(extents, fromPosition);
-    
</del><span class="cx">     return startOrRetargetAnimation(extents, destinationPosition);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -95,12 +96,11 @@
</span><span class="cx"> 
</span><span class="cx"> bool ScrollAnimationSmooth::startOrRetargetAnimation(const ScrollExtents& extents, const FloatPoint& destinationPosition)
</span><span class="cx"> {
</span><del>-    auto granularity = ScrollByPage;
-    bool needToScroll = updatePerAxisData(m_horizontalData, granularity, destinationPosition.x(), extents.minimumScrollPosition.x(), extents.maximumScrollPosition.x(), smoothFactorForProgrammaticScroll);
-    needToScroll |=
-        updatePerAxisData(m_verticalData, granularity, destinationPosition.y(), extents.minimumScrollPosition.y(), extents.maximumScrollPosition.y(), smoothFactorForProgrammaticScroll);
</del><ins>+    m_destinationPosition = destinationPosition.constrainedBetween(extents.minimumScrollPosition, extents.maximumScrollPosition);
+    bool needToScroll = m_startPosition != m_destinationPosition;
+
</ins><span class="cx">     if (needToScroll && !isActive()) {
</span><del>-        m_startTime = m_verticalData.startTime;
</del><ins>+        m_startTime = MonotonicTime::now();
</ins><span class="cx">         animationTimerFired();
</span><span class="cx">     }
</span><span class="cx">     return needToScroll;
</span><span class="lines">@@ -115,311 +115,37 @@
</span><span class="cx"> void ScrollAnimationSmooth::updateScrollExtents()
</span><span class="cx"> {
</span><span class="cx">     auto extents = m_client.scrollExtentsForAnimation(*this);
</span><del>-    m_horizontalData.visibleLength = extents.visibleSize.width();
-    m_verticalData.visibleLength = extents.visibleSize.height();
</del><ins>+    // FIXME: Ideally fix up m_startPosition so m_currentPosition doesn't go backwards.
+    m_destinationPosition = m_destinationPosition.constrainedBetween(extents.minimumScrollPosition, extents.maximumScrollPosition);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ScrollAnimationSmooth::initializeAxesData(const ScrollExtents& extents, const FloatPoint& startPosition)
</del><ins>+Seconds ScrollAnimationSmooth::durationFromDistance(const FloatSize& delta) const
</ins><span class="cx"> {
</span><del>-    m_horizontalData = PerAxisData(startPosition.x(), extents.visibleSize.width());
-    m_verticalData = PerAxisData(startPosition.y(), extents.visibleSize.height());
</del><ins>+    float distance = euclidianDistance(delta);
+    return std::min(Seconds(distance / animationSpeed), maxAnimationDuration);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline double curveAt(ScrollAnimationSmooth::Curve curve, double t)
</del><ins>+inline float linearInterpolation(float progress, float a, float b)
</ins><span class="cx"> {
</span><del>-    switch (curve) {
-    case ScrollAnimationSmooth::Curve::Linear:
-        return t;
-    case ScrollAnimationSmooth::Curve::Quadratic:
-        return t * t;
-    case ScrollAnimationSmooth::Curve::Cubic:
-        return t * t * t;
-    case ScrollAnimationSmooth::Curve::Quartic:
-        return t * t * t * t;
-    case ScrollAnimationSmooth::Curve::Bounce:
-        // Time base is chosen to keep the bounce points simpler:
-        // 1 (half bounce coming in) + 1 + .5 + .25
-        static const double timeBase = 2.75;
-        static const double timeBaseSquared = timeBase * timeBase;
-        if (t < 1 / timeBase)
-            return timeBaseSquared * t * t;
-        if (t < 2 / timeBase) {
-            // Invert a [-.5,.5] quadratic parabola, center it in [1,2].
-            double t1 = t - 1.5 / timeBase;
-            const double parabolaAtEdge = 1 - .5 * .5;
-            return timeBaseSquared * t1 * t1 + parabolaAtEdge;
-        }
-        if (t < 2.5 / timeBase) {
-            // Invert a [-.25,.25] quadratic parabola, center it in [2,2.5].
-            double t2 = t - 2.25 / timeBase;
-            const double parabolaAtEdge = 1 - .25 * .25;
-            return timeBaseSquared * t2 * t2 + parabolaAtEdge;
-        }
-        // Invert a [-.125,.125] quadratic parabola, center it in [2.5,2.75].
-        const double parabolaAtEdge = 1 - .125 * .125;
-        t -= 2.625 / timeBase;
-        return timeBaseSquared * t * t + parabolaAtEdge;
-    }
-    ASSERT_NOT_REACHED();
-    return 0;
</del><ins>+    return a + progress * (b - a);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline double attackCurve(ScrollAnimationSmooth::Curve curve, double deltaTime, double curveT, double startPosition, double attackPosition)
</del><ins>+bool ScrollAnimationSmooth::animateScroll(MonotonicTime currentTime)
</ins><span class="cx"> {
</span><del>-    double t = deltaTime / curveT;
-    double positionFactor = curveAt(curve, t);
-    return startPosition + positionFactor * (attackPosition - startPosition);
-}
</del><ins>+    MonotonicTime endTime = m_startTime + m_duration;
+    currentTime = std::min(currentTime, endTime);
</ins><span class="cx"> 
</span><del>-static inline double releaseCurve(ScrollAnimationSmooth::Curve curve, double deltaTime, double curveT, double releasePosition, double desiredPosition)
-{
-    double t = deltaTime / curveT;
-    double positionFactor = 1 - curveAt(curve, 1 - t);
-    return releasePosition + (positionFactor * (desiredPosition - releasePosition));
-}
</del><ins>+    double fractionComplete = (currentTime - m_startTime) / m_duration;
+    double progress = m_easeInOutTimingFunction->transformTime(fractionComplete, m_duration.value());
</ins><span class="cx"> 
</span><del>-static inline double coastCurve(ScrollAnimationSmooth::Curve curve, double factor)
-{
-    return 1 - curveAt(curve, 1 - factor);
-}
</del><ins>+    m_currentPosition = {
+        linearInterpolation(progress, m_startPosition.x(), m_destinationPosition.x()),
+        linearInterpolation(progress, m_startPosition.y(), m_destinationPosition.y()),
+    };
</ins><span class="cx"> 
</span><del>-static inline double curveIntegralAt(ScrollAnimationSmooth::Curve curve, double t)
-{
-    switch (curve) {
-    case ScrollAnimationSmooth::Curve::Linear:
-        return t * t / 2;
-    case ScrollAnimationSmooth::Curve::Quadratic:
-        return t * t * t / 3;
-    case ScrollAnimationSmooth::Curve::Cubic:
-        return t * t * t * t / 4;
-    case ScrollAnimationSmooth::Curve::Quartic:
-        return t * t * t * t * t / 5;
-    case ScrollAnimationSmooth::Curve::Bounce:
-        static const double timeBase = 2.75;
-        static const double timeBaseSquared = timeBase * timeBase;
-        static const double timeBaseSquaredOverThree = timeBaseSquared / 3;
-        double area;
-        double t1 = std::min(t, 1 / timeBase);
-        area = timeBaseSquaredOverThree * t1 * t1 * t1;
-        if (t < 1 / timeBase)
-            return area;
-
-        t1 = std::min(t - 1 / timeBase, 1 / timeBase);
-        // The integral of timeBaseSquared * (t1 - .5 / timeBase) * (t1 - .5 / timeBase) + parabolaAtEdge
-        static const double secondInnerOffset = timeBaseSquared * .5 / timeBase;
-        double bounceArea = t1 * (t1 * (timeBaseSquaredOverThree * t1 - secondInnerOffset) + 1);
-        area += bounceArea;
-        if (t < 2 / timeBase)
-            return area;
-
-        t1 = std::min(t - 2 / timeBase, 0.5 / timeBase);
-        // The integral of timeBaseSquared * (t1 - .25 / timeBase) * (t1 - .25 / timeBase) + parabolaAtEdge
-        static const double thirdInnerOffset = timeBaseSquared * .25 / timeBase;
-        bounceArea =  t1 * (t1 * (timeBaseSquaredOverThree * t1 - thirdInnerOffset) + 1);
-        area += bounceArea;
-        if (t < 2.5 / timeBase)
-            return area;
-
-        t1 = t - 2.5 / timeBase;
-        // The integral of timeBaseSquared * (t1 - .125 / timeBase) * (t1 - .125 / timeBase) + parabolaAtEdge
-        static const double fourthInnerOffset = timeBaseSquared * .125 / timeBase;
-        bounceArea = t1 * (t1 * (timeBaseSquaredOverThree * t1 - fourthInnerOffset) + 1);
-        area += bounceArea;
-        return area;
-    }
-    ASSERT_NOT_REACHED();
-    return 0;
</del><ins>+    return currentTime < endTime;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline double attackArea(ScrollAnimationSmooth::Curve curve, double startT, double endT)
-{
-    double startValue = curveIntegralAt(curve, startT);
-    double endValue = curveIntegralAt(curve, endT);
-    return endValue - startValue;
-}
-
-static inline double releaseArea(ScrollAnimationSmooth::Curve curve, double startT, double endT)
-{
-    double startValue = curveIntegralAt(curve, 1 - endT);
-    double endValue = curveIntegralAt(curve, 1 - startT);
-    return endValue - startValue;
-}
-
-static inline void getAnimationParametersForGranularity(ScrollGranularity granularity, Seconds& animationDuration, Seconds& repeatMinimumSustainTime, Seconds& attackDuration, Seconds& releaseDuration, ScrollAnimationSmooth::Curve& coastTimeCurve, Seconds& maximumCoastTime)
-{
-    switch (granularity) {
-    case ScrollByDocument:
-        animationDuration = tickTime * 10;
-        repeatMinimumSustainTime = tickTime * 10;
-        attackDuration = tickTime * 10;
-        releaseDuration = tickTime * 10;
-        coastTimeCurve = ScrollAnimationSmooth::Curve::Linear;
-        maximumCoastTime = 1_s;
-        break;
-    case ScrollByLine:
-        animationDuration = tickTime * 10;
-        repeatMinimumSustainTime = tickTime * 7;
-        attackDuration = tickTime * 3;
-        releaseDuration = tickTime * 3;
-        coastTimeCurve = ScrollAnimationSmooth::Curve::Linear;
-        maximumCoastTime = 1_s;
-        break;
-    case ScrollByPage:
-        animationDuration = tickTime * 15;
-        repeatMinimumSustainTime = tickTime * 10;
-        attackDuration = tickTime * 5;
-        releaseDuration = tickTime * 5;
-        coastTimeCurve = ScrollAnimationSmooth::Curve::Linear;
-        maximumCoastTime = 1_s;
-        break;
-    case ScrollByPixel:
-        animationDuration = tickTime * 11;
-        repeatMinimumSustainTime = tickTime * 2;
-        attackDuration = tickTime * 3;
-        releaseDuration = tickTime * 3;
-        coastTimeCurve = ScrollAnimationSmooth::Curve::Quadratic;
-        maximumCoastTime = 1250_ms;
-        break;
-    default:
-        ASSERT_NOT_REACHED();
-    }
-}
-
-bool ScrollAnimationSmooth::updatePerAxisData(PerAxisData& data, ScrollGranularity granularity, float newPosition, float minScrollPosition, float maxScrollPosition, double smoothFactor)
-{
-    if (!data.startTime || newPosition == data.currentPosition) {
-        data.desiredPosition = data.currentPosition;
-        data.startTime = { };
-    }
-
-    newPosition = std::max(std::min(newPosition, maxScrollPosition), minScrollPosition);
-    if (newPosition == data.desiredPosition)
-        return false;
-
-    Seconds animationDuration, repeatMinimumSustainTime, attackDuration, releaseDuration, maximumCoastTime;
-    Curve coastTimeCurve;
-    getAnimationParametersForGranularity(granularity, animationDuration, repeatMinimumSustainTime, attackDuration, releaseDuration, coastTimeCurve, maximumCoastTime);
-
-    animationDuration *= smoothFactor;
-    repeatMinimumSustainTime *= smoothFactor;
-    attackDuration *= smoothFactor;
-    releaseDuration *= smoothFactor;
-    maximumCoastTime *= smoothFactor;
-
-    data.desiredPosition = newPosition;
-    if (!data.startTime)
-        data.attackDuration = attackDuration;
-    data.animationDuration = animationDuration;
-    data.releaseDuration = releaseDuration;
-
-    // Prioritize our way out of over constraint.
-    if (data.attackDuration + data.releaseDuration > data.animationDuration) {
-        if (data.releaseDuration > data.animationDuration)
-            data.releaseDuration = data.animationDuration;
-        data.attackDuration = data.animationDuration - data.releaseDuration;
-    }
-
-    if (!data.startTime) {
-        // FIXME: This should be the time from the event that got us here.
-        data.startTime = MonotonicTime::now() - tickTime / 2.;
-        data.startPosition = data.currentPosition;
-        data.lastAnimationTime = data.startTime;
-    }
-    data.startVelocity = data.currentVelocity;
-
-    double remainingDelta = data.desiredPosition - data.currentPosition;
-    double attackAreaLeft = 0;
-    Seconds deltaTime = data.lastAnimationTime - data.startTime;
-    Seconds attackTimeLeft = std::max(0_s, data.attackDuration - deltaTime);
-    Seconds timeLeft = data.animationDuration - deltaTime;
-    Seconds minTimeLeft = data.releaseDuration + std::min(repeatMinimumSustainTime, data.animationDuration - data.releaseDuration - attackTimeLeft);
-    if (timeLeft < minTimeLeft) {
-        data.animationDuration = deltaTime + minTimeLeft;
-        timeLeft = minTimeLeft;
-    }
-
-    if (maximumCoastTime > (repeatMinimumSustainTime + releaseDuration)) {
-        double targetMaxCoastVelocity = data.visibleLength * .25 * frameRate;
-        // This needs to be as minimal as possible while not being intrusive to page up/down.
-        double minCoastDelta = data.visibleLength;
-
-        if (fabs(remainingDelta) > minCoastDelta) {
-            double maxCoastDelta = maximumCoastTime.value() * targetMaxCoastVelocity;
-            double coastFactor = std::min(1., (fabs(remainingDelta) - minCoastDelta) / (maxCoastDelta - minCoastDelta));
-
-            // We could play with the curve here - linear seems a little soft. Initial testing makes me want to feed into the sustain time more aggressively.
-            Seconds coastMinTimeLeft = std::min(maximumCoastTime, minTimeLeft + (maximumCoastTime - minTimeLeft) * coastCurve(coastTimeCurve, coastFactor));
-
-            if (Seconds additionalTime = std::max(0_s, coastMinTimeLeft - minTimeLeft)) {
-                Seconds additionalReleaseTime = std::min(additionalTime, additionalTime * (releaseDuration / (releaseDuration + repeatMinimumSustainTime)));
-                data.releaseDuration = releaseDuration + additionalReleaseTime;
-                data.animationDuration = deltaTime + coastMinTimeLeft;
-                timeLeft = coastMinTimeLeft;
-            }
-        }
-    }
-
-    Seconds releaseTimeLeft = std::min(timeLeft, data.releaseDuration);
-    Seconds sustainTimeLeft = std::max(0_s, timeLeft - releaseTimeLeft - attackTimeLeft);
-    if (attackTimeLeft) {
-        double attackSpot = deltaTime / data.attackDuration;
-        attackAreaLeft = attackArea(Curve::Cubic, attackSpot, 1) * data.attackDuration.value();
-    }
-
-    double releaseSpot = (data.releaseDuration - releaseTimeLeft) / data.releaseDuration;
-    double releaseAreaLeft = releaseArea(Curve::Cubic, releaseSpot, 1) * data.releaseDuration.value();
-
-    data.desiredVelocity = remainingDelta / (attackAreaLeft + sustainTimeLeft.value() + releaseAreaLeft);
-    data.releasePosition = data.desiredPosition - data.desiredVelocity * releaseAreaLeft;
-    if (attackAreaLeft)
-        data.attackPosition = data.startPosition + data.desiredVelocity * attackAreaLeft;
-    else
-        data.attackPosition = data.releasePosition - (data.animationDuration - data.releaseDuration - data.attackDuration).value() * data.desiredVelocity;
-
-    if (sustainTimeLeft) {
-        double roundOff = data.releasePosition - ((attackAreaLeft ? data.attackPosition : data.currentPosition) + data.desiredVelocity * sustainTimeLeft.value());
-        data.desiredVelocity += roundOff / sustainTimeLeft.value();
-    }
-
-    return true;
-}
-
-bool ScrollAnimationSmooth::animateScroll(PerAxisData& data, MonotonicTime currentTime)
-{
-    if (!data.startTime)
-        return false;
-
-    Seconds lastScrollInterval = currentTime - data.lastAnimationTime;
-    if (lastScrollInterval < minimumTimerInterval)
-        return true;
-
-    data.lastAnimationTime = currentTime;
-
-    Seconds deltaTime = currentTime - data.startTime;
-    double newPosition = data.currentPosition;
-
-    if (deltaTime > data.animationDuration) {
-        data = PerAxisData(data.desiredPosition, data.visibleLength);
-        return false;
-    }
-    if (deltaTime < data.attackDuration)
-        newPosition = attackCurve(Curve::Cubic, deltaTime.value(), data.attackDuration.value(), data.startPosition, data.attackPosition);
-    else if (deltaTime < (data.animationDuration - data.releaseDuration))
-        newPosition = data.attackPosition + (deltaTime - data.attackDuration).value() * data.desiredVelocity;
-    else {
-        // release is based on targeting the exact final position.
-        Seconds releaseDeltaT = deltaTime - (data.animationDuration - data.releaseDuration);
-        newPosition = releaseCurve(Curve::Cubic, releaseDeltaT.value(), data.releaseDuration.value(), data.releasePosition, data.desiredPosition);
-    }
-
-    // Normalize velocity to a per second amount. Could be used to check for jank.
-    if (lastScrollInterval > 0_s)
-        data.currentVelocity = (newPosition - data.currentPosition) / lastScrollInterval.value();
-    data.currentPosition = newPosition;
-
-    return true;
-}
-
</del><span class="cx"> void ScrollAnimationSmooth::animationTimerFired()
</span><span class="cx"> {
</span><span class="cx">     MonotonicTime currentTime = MonotonicTime::now();
</span><span class="lines">@@ -426,16 +152,11 @@
</span><span class="cx">     Seconds deltaToNextFrame = 1_s * ceil((currentTime - m_startTime).value() * frameRate) / frameRate - (currentTime - m_startTime);
</span><span class="cx">     currentTime += deltaToNextFrame;
</span><span class="cx"> 
</span><del>-    bool continueAnimation = false;
-    if (animateScroll(m_horizontalData, currentTime))
-        continueAnimation = true;
-    if (animateScroll(m_verticalData, currentTime))
-        continueAnimation = true;
-
</del><ins>+    bool continueAnimation = animateScroll(currentTime);
</ins><span class="cx">     if (continueAnimation)
</span><span class="cx">         startNextTimer(std::max(minimumTimerInterval, deltaToNextFrame));
</span><span class="cx"> 
</span><del>-    m_client.scrollAnimationDidUpdate(*this, { m_horizontalData.currentPosition, m_verticalData.currentPosition });
</del><ins>+    m_client.scrollAnimationDidUpdate(*this, m_currentPosition);
</ins><span class="cx">     if (!continueAnimation)
</span><span class="cx">         m_client.scrollAnimationDidEnd(*this);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformScrollAnimationSmoothh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ScrollAnimationSmooth.h (282720 => 282721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/ScrollAnimationSmooth.h    2021-09-18 04:24:53 UTC (rev 282720)
+++ trunk/Source/WebCore/platform/ScrollAnimationSmooth.h       2021-09-18 06:03:19 UTC (rev 282721)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class FloatPoint;
</span><del>-enum class ScrollClamping : bool;
</del><ins>+class TimingFunction;
</ins><span class="cx"> 
</span><span class="cx"> class ScrollAnimationSmooth final: public ScrollAnimation {
</span><span class="cx"> public:
</span><span class="lines">@@ -40,14 +40,6 @@
</span><span class="cx">     ScrollAnimationSmooth(ScrollAnimationClient&);
</span><span class="cx">     virtual ~ScrollAnimationSmooth();
</span><span class="cx"> 
</span><del>-    enum class Curve {
-        Linear,
-        Quadratic,
-        Cubic,
-        Quartic,
-        Bounce
-    };
-
</del><span class="cx">     bool startAnimatedScroll(ScrollbarOrientation, ScrollGranularity, const FloatPoint& fromPosition, float step, float multiplier);
</span><span class="cx">     bool startAnimatedScrollToDestination(const FloatPoint& fromPosition, const FloatPoint& destinationPosition);
</span><span class="cx"> 
</span><span class="lines">@@ -56,57 +48,28 @@
</span><span class="cx">     void updateScrollExtents() final;
</span><span class="cx">     bool isActive() const final;
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> private:
</span><del>-    struct PerAxisData {
-        PerAxisData() = default;
-        PerAxisData(float position, int length)
-            : currentPosition(position)
-            , desiredPosition(position)
-            , visibleLength(length)
-        {
-        }
-
-        float currentPosition { 0 };
-        double currentVelocity { 0 };
-
-        double desiredPosition { 0 };
-        double desiredVelocity { 0 };
-
-        double startPosition { 0 };
-        MonotonicTime startTime;
-        double startVelocity { 0 };
-
-        Seconds animationDuration;
-        MonotonicTime lastAnimationTime;
-
-        double attackPosition { 0 };
-        Seconds attackDuration;
-        Curve attackCurve { Curve::Quadratic };
-
-        double releasePosition { 0 };
-        Seconds releaseDuration;
-        Curve releaseCurve { Curve::Quadratic };
-
-        int visibleLength { 0 };
-    };
-
</del><span class="cx">     bool startOrRetargetAnimation(const ScrollExtents&, const FloatPoint& destination);
</span><span class="cx"> 
</span><del>-    bool updatePerAxisData(PerAxisData&, ScrollGranularity, float newPosition, float minScrollPosition, float maxScrollPosition, double smoothFactor = 1);
-    bool animateScroll(PerAxisData&, MonotonicTime currentTime);
-    
-    void initializeAxesData(const ScrollExtents&, const FloatPoint& startPosition);
-
</del><span class="cx">     void requestAnimationTimerFired();
</span><span class="cx">     void startNextTimer(Seconds delay);
</span><span class="cx">     void animationTimerFired();
</span><ins>+    
+    Seconds durationFromDistance(const FloatSize&) const;
+    
+    bool animateScroll(MonotonicTime);
</ins><span class="cx"> 
</span><del>-    PerAxisData m_horizontalData;
-    PerAxisData m_verticalData;
</del><ins>+    MonotonicTime m_startTime;
+    Seconds m_duration;
</ins><span class="cx"> 
</span><del>-    MonotonicTime m_startTime;
</del><ins>+    FloatPoint m_startPosition;
+    FloatPoint m_destinationPosition;
+    FloatPoint m_currentPosition;
+    
</ins><span class="cx">     // FIXME: Should not have timer here, and instead use serviceAnimation().
</span><span class="cx">     RunLoop::Timer<ScrollAnimationSmooth> m_animationTimer;
</span><ins>+    RefPtr<TimingFunction> m_easeInOutTimingFunction;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsGeometryUtilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/GeometryUtilities.cpp (282720 => 282721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/GeometryUtilities.cpp     2021-09-18 04:24:53 UTC (rev 282720)
+++ trunk/Source/WebCore/platform/graphics/GeometryUtilities.cpp        2021-09-18 06:03:19 UTC (rev 282721)
</span><span class="lines">@@ -32,12 +32,16 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-float euclidianDistance(const FloatPoint& p1, const FloatPoint& p2)
</del><ins>+float euclidianDistance(const FloatSize& delta)
</ins><span class="cx"> {
</span><del>-    FloatSize delta = p1 - p2;
</del><span class="cx">     return std::hypot(delta.width(), delta.height());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+float euclidianDistance(const FloatPoint& p1, const FloatPoint& p2)
+{
+    return euclidianDistance(p1 - p2);
+}
+
</ins><span class="cx"> float findSlope(const FloatPoint& p1, const FloatPoint& p2, float& c)
</span><span class="cx"> {
</span><span class="cx">     if (p2.x() == p1.x())
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsGeometryUtilitiesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/GeometryUtilities.h (282720 => 282721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/GeometryUtilities.h       2021-09-18 04:24:53 UTC (rev 282720)
+++ trunk/Source/WebCore/platform/graphics/GeometryUtilities.h  2021-09-18 06:03:19 UTC (rev 282721)
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> 
</span><span class="cx"> class FloatQuad;
</span><span class="cx"> 
</span><ins>+float euclidianDistance(const FloatSize&);
</ins><span class="cx"> float euclidianDistance(const FloatPoint&, const FloatPoint&);
</span><span class="cx"> 
</span><span class="cx"> float findSlope(const FloatPoint& p1, const FloatPoint& p2, float& c);
</span></span></pre>
</div>
</div>

</body>
</html>