diff options
Diffstat (limited to 'third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp')
-rw-r--r-- | third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp | 191 |
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); |