diff options
author | ajuma@chromium.org <ajuma@chromium.org> | 2015-01-19 15:47:20 +0000 |
---|---|---|
committer | ajuma@chromium.org <ajuma@chromium.org> | 2015-01-19 15:47:20 +0000 |
commit | f150188c9839c45490d28ec2a0459f7bbf634360 (patch) | |
tree | 6c0aa79cedf887b699e69774af6cc3c9513c7095 /third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp | |
parent | 0e5cf152c2d43e5296722c1bebf5e2f038773727 (diff) | |
download | chromium_src-f150188c9839c45490d28ec2a0459f7bbf634360.zip chromium_src-f150188c9839c45490d28ec2a0459f7bbf634360.tar.gz chromium_src-f150188c9839c45490d28ec2a0459f7bbf634360.tar.bz2 |
Run CSSOM smooth scroll animations on the compositor when possible
This runs smooth scroll animations on the compositor when a composited
layer for scrolling already exists and main-thread scrolling isn't required.
This also adds a virtual test suite that runs the fast/scroll-behavior tests
with --enable-threaded-compositing and --enable-prefer-compositing-to-lcd-text.
Smooth scrolling is behind a runtime flag.
BUG=243871
Review URL: https://codereview.chromium.org/802383003
git-svn-id: svn://svn.chromium.org/blink/trunk@188634 bbb929c8-8fbe-4397-9dbb-9b2b20218538
Diffstat (limited to 'third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp')
-rw-r--r-- | third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp | 135 |
1 files changed, 121 insertions, 14 deletions
diff --git a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp index 5740180..7b23329 100644 --- a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp +++ b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp @@ -6,8 +6,10 @@ #include "platform/scroll/ProgrammaticScrollAnimator.h" #include "platform/geometry/IntPoint.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 "public/platform/WebScrollOffsetAnimationCurve.h" @@ -21,6 +23,9 @@ PassOwnPtr<ProgrammaticScrollAnimator> ProgrammaticScrollAnimator::create(Scroll ProgrammaticScrollAnimator::ProgrammaticScrollAnimator(ScrollableArea* scrollableArea) : m_scrollableArea(scrollableArea) , m_startTime(0.0) + , m_runState(RunState::Idle) + , m_compositorAnimationId(0) + , m_compositorAnimationGroupId(0) { } @@ -32,6 +37,9 @@ void ProgrammaticScrollAnimator::resetAnimationState() { m_animationCurve.clear(); m_startTime = 0.0; + m_runState = RunState::Idle; + m_compositorAnimationId = 0; + m_compositorAnimationGroupId = 0; } void ProgrammaticScrollAnimator::animateToOffset(FloatPoint offset) @@ -46,35 +54,134 @@ void ProgrammaticScrollAnimator::animateToOffset(FloatPoint offset) resetAnimationState(); m_scrollableArea->notifyScrollPositionChanged(IntPoint(offset.x(), offset.y())); } + m_runState = RunState::WaitingToSendToCompositor; } void ProgrammaticScrollAnimator::cancelAnimation() { - resetAnimationState(); + switch (m_runState) { + case RunState::Idle: + case RunState::WaitingToCancelOnCompositor: + break; + case RunState::WaitingToSendToCompositor: + if (m_compositorAnimationId) { + // We still have a previous animation running on the compositor. + m_runState = RunState::WaitingToCancelOnCompositor; + } else { + resetAnimationState(); + } + break; + case RunState::RunningOnMainThread: + resetAnimationState(); + break; + case RunState::RunningOnCompositor: + m_runState = RunState::WaitingToCancelOnCompositor; + + // Get serviced the next time compositor updates are allowed. + m_scrollableArea->registerForAnimation(); + } } void ProgrammaticScrollAnimator::tickAnimation(double monotonicTime) { - if (m_animationCurve) { - if (!m_startTime) - m_startTime = monotonicTime; - double elapsedTime = monotonicTime - m_startTime; - bool isFinished = (elapsedTime > m_animationCurve->duration()); - FloatPoint offset = m_animationCurve->getValue(elapsedTime); - m_scrollableArea->notifyScrollPositionChanged(IntPoint(offset.x(), offset.y())); + if (m_runState != RunState::RunningOnMainThread) + return; - if (isFinished) { - resetAnimationState(); - } else if (!m_scrollableArea->scheduleAnimation()) { - m_scrollableArea->notifyScrollPositionChanged(IntPoint(m_targetOffset.x(), m_targetOffset.y())); + if (!m_startTime) + m_startTime = monotonicTime; + double elapsedTime = monotonicTime - m_startTime; + bool isFinished = (elapsedTime > m_animationCurve->duration()); + FloatPoint offset = m_animationCurve->getValue(elapsedTime); + m_scrollableArea->notifyScrollPositionChanged(IntPoint(offset.x(), offset.y())); + + if (isFinished) { + resetAnimationState(); + } else if (!m_scrollableArea->scheduleAnimation()) { + m_scrollableArea->notifyScrollPositionChanged(IntPoint(m_targetOffset.x(), m_targetOffset.y())); + resetAnimationState(); + } +} + +bool ProgrammaticScrollAnimator::hasAnimationThatRequiresService() const +{ + switch (m_runState) { + case RunState::Idle: + case RunState::RunningOnCompositor: + return false; + case RunState::WaitingToSendToCompositor: + case RunState::RunningOnMainThread: + case RunState::WaitingToCancelOnCompositor: + return true; + } + ASSERT_NOT_REACHED(); + return false; +} + +void ProgrammaticScrollAnimator::updateCompositorAnimations() +{ + if (m_compositorAnimationId && m_runState != RunState::RunningOnCompositor) { + // 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); + if (GraphicsLayer* layer = m_scrollableArea->layerForScrolling()) + layer->removeAnimation(m_compositorAnimationId); + m_compositorAnimationId = 0; + m_compositorAnimationGroupId = 0; + if (m_runState == RunState::WaitingToCancelOnCompositor) { resetAnimationState(); + return; + } + } + + if (m_runState == RunState::WaitingToSendToCompositor) { + bool sentToCompositor = false; + + if (GraphicsLayer* layer = m_scrollableArea->layerForScrolling()) { + if (!layer->platformLayer()->shouldScrollOnMainThread()) { + OwnPtr<WebCompositorAnimation> animation = adoptPtr(Platform::current()->compositorSupport()->createAnimation(*m_animationCurve, WebCompositorAnimation::TargetPropertyScrollOffset)); + + int animationId = animation->id(); + int animationGroupId = animation->group(); + if (m_scrollableArea->layerForScrolling()->addAnimation(animation.release())) { + sentToCompositor = true; + m_runState = RunState::RunningOnCompositor; + m_compositorAnimationId = animationId; + m_compositorAnimationGroupId = animationGroupId; + } + } + } + + if (!sentToCompositor) { + m_runState = RunState::RunningOnMainThread; + if (!m_scrollableArea->scheduleAnimation()) { + m_scrollableArea->notifyScrollPositionChanged(IntPoint(m_targetOffset.x(), m_targetOffset.y())); + resetAnimationState(); + } } } } -bool ProgrammaticScrollAnimator::hasRunningAnimation() const +void ProgrammaticScrollAnimator::notifyCompositorAnimationFinished(int groupId) { - return !!m_animationCurve; + if (m_compositorAnimationGroupId != groupId) + return; + + m_compositorAnimationId = 0; + m_compositorAnimationGroupId = 0; + + switch (m_runState) { + case RunState::Idle: + case RunState::RunningOnMainThread: + ASSERT_NOT_REACHED(); + break; + case RunState::WaitingToSendToCompositor: + break; + case RunState::RunningOnCompositor: + case RunState::WaitingToCancelOnCompositor: + resetAnimationState(); + } } } // namespace blink |