summaryrefslogtreecommitdiffstats
path: root/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp')
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp191
1 files changed, 155 insertions, 36 deletions
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
index e9610b0..fa45f0f 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
@@ -31,12 +31,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 {
@@ -49,21 +50,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();
@@ -71,7 +73,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);
@@ -82,14 +93,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);
}
@@ -100,16 +130,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);
}
@@ -118,34 +149,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));
@@ -153,7 +173,7 @@ void ScrollAnimator::animationTimerFired()
m_currentPosY = offset.y();
if (isFinished)
- m_animationCurve.clear();
+ resetAnimationState();
else
scrollableArea()->scheduleAnimation();
@@ -161,6 +181,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);