| 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);
|
|
|