Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Unified Diff: third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp

Issue 1534813004: Run smooth scroll animations on the compositor when possible (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: nit Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
index c3b47315630a09445668430e1400f374fa7d5225..a7fb64b8ffc490b41ffdd4b3cca7192fe8a02213 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
@@ -32,12 +32,13 @@
#include "platform/scroll/ScrollAnimator.h"
#include "platform/TraceEvent.h"
+#include "platform/graphics/GraphicsLayer.h"
#include "platform/scroll/ScrollableArea.h"
#include "public/platform/Platform.h"
+#include "public/platform/WebCompositorAnimation.h"
#include "public/platform/WebCompositorSupport.h"
#include "wtf/CurrentTime.h"
#include "wtf/PassRefPtr.h"
-#include <algorithm>
namespace blink {
@@ -50,21 +51,22 @@ PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(Scrollable
ScrollAnimator::ScrollAnimator(ScrollableArea* scrollableArea, WTF::TimeFunction timeFunction)
: ScrollAnimatorBase(scrollableArea)
+ , m_lastTickTime(0.0)
, m_timeFunction(timeFunction)
{
}
ScrollAnimator::~ScrollAnimator()
{
- cancelAnimations();
}
FloatPoint ScrollAnimator::desiredTargetPosition() const
{
- return m_animationCurve ? FloatPoint(m_animationCurve->targetValue()) : currentPosition();
+ return m_animationCurve ? m_targetOffset : currentPosition();
}
-float ScrollAnimator::computeDeltaToConsume(ScrollbarOrientation orientation, float pixelDelta) const
+float ScrollAnimator::computeDeltaToConsume(
+ ScrollbarOrientation orientation, float pixelDelta) const
{
FloatPoint pos = desiredTargetPosition();
float currentPos = (orientation == HorizontalScrollbar) ? pos.x() : pos.y();
@@ -72,7 +74,16 @@ float ScrollAnimator::computeDeltaToConsume(ScrollbarOrientation orientation, fl
return (currentPos == newPos) ? 0.0f : (newPos - currentPos);
}
-ScrollResultOneDimensional ScrollAnimator::userScroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta)
+void ScrollAnimator::resetAnimationState()
+{
+ ScrollAnimatorCompositorCoordinator::resetAnimationState();
+ if (m_animationCurve)
+ m_animationCurve.clear();
+ m_startTime = 0.0;
+}
+
+ScrollResultOneDimensional ScrollAnimator::userScroll(
+ ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta)
{
if (!m_scrollableArea->scrollAnimatorEnabled())
return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta);
@@ -83,14 +94,33 @@ ScrollResultOneDimensional ScrollAnimator::userScroll(ScrollbarOrientation orien
return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta);
float usedPixelDelta = computeDeltaToConsume(orientation, step * delta);
- FloatPoint pixelDelta = (orientation == VerticalScrollbar ? FloatPoint(0, usedPixelDelta) : FloatPoint(usedPixelDelta, 0));
+ FloatPoint pixelDelta = (orientation == VerticalScrollbar
+ ? FloatPoint(0, usedPixelDelta) : FloatPoint(usedPixelDelta, 0));
FloatPoint targetPos = desiredTargetPosition();
targetPos.moveBy(pixelDelta);
if (m_animationCurve) {
- if (!(targetPos - m_animationCurve->targetValue()).isZero())
- m_animationCurve->updateTarget(m_timeFunction() - m_startTime, targetPos);
+ if ((targetPos - m_targetOffset).isZero()) {
+ // Report unused delta only if there is no animation running. See
+ // comment below regarding scroll latching.
+ return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0);
+ }
+
+ m_targetOffset = targetPos;
+ ASSERT(m_runState == RunState::RunningOnMainThread
+ || m_runState == RunState::RunningOnCompositor
+ || m_runState == RunState::RunningOnCompositorButNeedsUpdate);
+
+ if (m_runState == RunState::RunningOnCompositor
+ || m_runState == RunState::RunningOnCompositorButNeedsUpdate) {
+ m_runState = RunState::RunningOnCompositorButNeedsUpdate;
+ return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0);
+ }
+
+ // Running on the main thread, simply update the target offset instead
+ // of sending to the compositor.
+ m_animationCurve->updateTarget(m_timeFunction() - m_startTime, targetPos);
return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0);
}
@@ -101,16 +131,17 @@ ScrollResultOneDimensional ScrollAnimator::userScroll(ScrollbarOrientation orien
return ScrollResultOneDimensional(/* didScroll */ false, delta);
}
- m_animationCurve = adoptPtr(Platform::current()->compositorSupport()->createScrollOffsetAnimationCurve(
- targetPos,
- WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut,
- WebScrollOffsetAnimationCurve::ScrollDurationConstant));
-
- m_animationCurve->setInitialValue(currentPosition());
+ m_targetOffset = targetPos;
m_startTime = m_timeFunction();
scrollableArea()->registerForAnimation();
- animationTimerFired();
+ if (!m_scrollableArea->scheduleAnimation()) {
+ scrollToOffsetWithoutAnimation(targetPos);
+ resetAnimationState();
+ return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0);
+ }
+
+ m_runState = RunState::WaitingToSendToCompositor;
return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0);
}
@@ -119,34 +150,23 @@ void ScrollAnimator::scrollToOffsetWithoutAnimation(const FloatPoint& offset)
m_currentPosX = offset.x();
m_currentPosY = offset.y();
- cancelAnimations();
+ resetAnimationState();
notifyPositionChanged();
}
-void ScrollAnimator::cancelAnimations()
+void ScrollAnimator::tickAnimation(double monotonicTime)
{
- if (m_animationCurve)
- m_animationCurve.clear();
-}
+ m_lastTickTime = monotonicTime;
-void ScrollAnimator::serviceScrollAnimations()
-{
- if (hasRunningAnimation())
- animationTimerFired();
-}
+ if (m_runState != RunState::RunningOnMainThread)
+ return;
-bool ScrollAnimator::hasRunningAnimation() const
-{
- return m_animationCurve;
-}
-
-void ScrollAnimator::animationTimerFired()
-{
- TRACE_EVENT0("blink", "ScrollAnimator::animationTimerFired");
- double elapsedTime = m_timeFunction() - m_startTime;
+ TRACE_EVENT0("blink", "ScrollAnimator::tickAnimation");
+ double elapsedTime = monotonicTime - m_startTime;
bool isFinished = (elapsedTime > m_animationCurve->duration());
- FloatPoint offset = isFinished ? m_animationCurve->targetValue() : m_animationCurve->getValue(elapsedTime);
+ FloatPoint offset = isFinished ? m_animationCurve->targetValue()
+ : m_animationCurve->getValue(elapsedTime);
offset = FloatPoint(m_scrollableArea->clampScrollPosition(offset));
@@ -154,7 +174,7 @@ void ScrollAnimator::animationTimerFired()
m_currentPosY = offset.y();
if (isFinished)
- m_animationCurve.clear();
+ resetAnimationState();
else
scrollableArea()->scheduleAnimation();
@@ -162,6 +182,105 @@ void ScrollAnimator::animationTimerFired()
notifyPositionChanged();
}
+void ScrollAnimator::updateCompositorAnimations()
+{
+ if (m_compositorAnimationId && m_runState != RunState::RunningOnCompositor
+ && m_runState != RunState::RunningOnCompositorButNeedsUpdate) {
+ // If the current run state is WaitingToSendToCompositor but we have a
+ // non-zero compositor animation id, there's a currently running
+ // compositor animation that needs to be removed here before the new
+ // animation is added below.
+ ASSERT(m_runState == RunState::WaitingToCancelOnCompositor
+ || m_runState == RunState::WaitingToSendToCompositor);
+
+ abortAnimation();
+
+ m_compositorAnimationId = 0;
+ m_compositorAnimationGroupId = 0;
+ if (m_runState == RunState::WaitingToCancelOnCompositor) {
+ resetAnimationState();
+ return;
+ }
+ }
+
+ if (m_runState == RunState::WaitingToSendToCompositor
+ || m_runState == RunState::RunningOnCompositorButNeedsUpdate) {
+ if (m_runState == RunState::RunningOnCompositorButNeedsUpdate) {
+ // Abort the running animation before a new one with an updated
+ // target is added.
+ abortAnimation();
+
+ m_compositorAnimationId = 0;
+ m_compositorAnimationGroupId = 0;
+
+ m_animationCurve->updateTarget(m_lastTickTime - m_startTime,
+ m_targetOffset);
+ m_runState = RunState::WaitingToSendToCompositor;
+ }
+
+ if (!m_animationCurve) {
+ m_animationCurve = adoptPtr(Platform::current()->compositorSupport()
+ ->createScrollOffsetAnimationCurve(
+ m_targetOffset,
+ WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut,
+ WebScrollOffsetAnimationCurve::ScrollDurationConstant));
+ m_animationCurve->setInitialValue(currentPosition());
+ }
+
+ bool sentToCompositor = false;
+ if (GraphicsLayer* layer = m_scrollableArea->layerForScrolling()) {
+ ASSERT(layer->scrollableArea() == m_scrollableArea);
+ if (!layer->platformLayer()->shouldScrollOnMainThread()) {
+ OwnPtr<WebCompositorAnimation> animation = adoptPtr(
+ Platform::current()->compositorSupport()->createAnimation(
+ *m_animationCurve,
+ WebCompositorAnimation::TargetPropertyScrollOffset));
+ // Being here means that either there is an animation that needs
+ // to be sent to the compositor, or an animation that needs to
+ // be updated (a new scroll event before the previous animation
+ // is finished). In either case, the start time is when the
+ // first animation was initiated. This re-targets the animation
+ // using the current time on main thread.
+ animation->setStartTime(m_startTime);
+
+ int animationId = animation->id();
+ int animationGroupId = animation->group();
+
+ sentToCompositor = addAnimation(animation.release());
+ if (sentToCompositor) {
+ m_runState = RunState::RunningOnCompositor;
+ m_compositorAnimationId = animationId;
+ m_compositorAnimationGroupId = animationGroupId;
+ }
+ }
+ }
+
+ if (!sentToCompositor) {
+ m_runState = RunState::RunningOnMainThread;
+ if (!m_scrollableArea->scheduleAnimation()) {
+ scrollToOffsetWithoutAnimation(m_targetOffset);
+ resetAnimationState();
+ }
+ }
+ }
+}
+
+void ScrollAnimator::notifyCompositorAnimationFinished(int groupId)
+{
+ ScrollAnimatorCompositorCoordinator::compositorAnimationFinished(groupId);
+}
+
+void ScrollAnimator::cancelAnimation()
+{
+ ScrollAnimatorCompositorCoordinator::cancelAnimation();
+}
+
+void ScrollAnimator::layerForCompositedScrollingDidChange(
+ WebCompositorAnimationTimeline* timeline)
+{
+ reattachCompositorPlayerIfNeeded(timeline);
+}
+
DEFINE_TRACE(ScrollAnimator)
{
ScrollAnimatorBase::trace(visitor);

Powered by Google App Engine
This is Rietveld 408576698