void ScrollAnimator::createAnimationCurve() { DCHECK(!m_animationCurve); m_animationCurve = CompositorScrollOffsetAnimationCurve::create( compositorOffsetFromBlinkOffset(m_targetOffset), m_lastGranularity == ScrollByPixel ? CompositorScrollOffsetAnimationCurve::ScrollDurationInverseDelta : CompositorScrollOffsetAnimationCurve::ScrollDurationConstant); m_animationCurve->setInitialValue( compositorOffsetFromBlinkOffset(currentOffset())); }
void ProgrammaticScrollAnimator::updateCompositorAnimations() { if (m_runState == RunState::PostAnimationCleanup) { // No special cleanup, simply reset animation state. We have this state // here because the state machine is shared with ScrollAnimator which // has to do some cleanup that requires the compositing state to be clean. return resetAnimationState(); } 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); removeAnimation(); m_compositorAnimationId = 0; m_compositorAnimationGroupId = 0; if (m_runState == RunState::WaitingToCancelOnCompositor) { resetAnimationState(); return; } } if (m_runState == RunState::WaitingToSendToCompositor) { if (!m_compositorAnimationAttachedToElementId) reattachCompositorPlayerIfNeeded( getScrollableArea()->compositorAnimationTimeline()); bool sentToCompositor = false; if (!m_scrollableArea->shouldScrollOnMainThread()) { std::unique_ptr<CompositorAnimation> animation = CompositorAnimation::create( *m_animationCurve, CompositorTargetProperty::SCROLL_OFFSET, 0, 0); int animationId = animation->id(); int animationGroupId = animation->group(); if (addAnimation(std::move(animation))) { sentToCompositor = true; m_runState = RunState::RunningOnCompositor; m_compositorAnimationId = animationId; m_compositorAnimationGroupId = animationGroupId; } } if (!sentToCompositor) { m_runState = RunState::RunningOnMainThread; m_animationCurve->setInitialValue( compositorOffsetFromBlinkOffset(m_scrollableArea->getScrollOffset())); if (!m_scrollableArea->scheduleAnimation()) { notifyOffsetChanged(m_targetOffset); resetAnimationState(); } } } }
bool ScrollAnimator::willAnimateToOffset(const ScrollOffset& targetOffset) { if (m_runState == RunState::PostAnimationCleanup) resetAnimationState(); if (m_runState == RunState::WaitingToCancelOnCompositor || m_runState == RunState::WaitingToCancelOnCompositorButNewScroll) { ASSERT(m_animationCurve); m_targetOffset = targetOffset; if (registerAndScheduleAnimation()) m_runState = RunState::WaitingToCancelOnCompositorButNewScroll; return true; } if (m_animationCurve) { if ((targetOffset - m_targetOffset).isZero()) return true; m_targetOffset = targetOffset; ASSERT(m_runState == RunState::RunningOnMainThread || m_runState == RunState::RunningOnCompositor || m_runState == RunState::RunningOnCompositorButNeedsUpdate || m_runState == RunState::RunningOnCompositorButNeedsTakeover); // Running on the main thread, simply update the target offset instead // of sending to the compositor. if (m_runState == RunState::RunningOnMainThread) { m_animationCurve->updateTarget( m_timeFunction() - m_startTime, compositorOffsetFromBlinkOffset(targetOffset)); return true; } if (registerAndScheduleAnimation()) m_runState = RunState::RunningOnCompositorButNeedsUpdate; return true; } if ((targetOffset - currentOffset()).isZero()) return false; m_targetOffset = targetOffset; m_startTime = m_timeFunction(); if (registerAndScheduleAnimation()) m_runState = RunState::WaitingToSendToCompositor; return true; }
void ProgrammaticScrollAnimator::animateToOffset(const ScrollOffset& offset) { if (m_runState == RunState::PostAnimationCleanup) resetAnimationState(); m_startTime = 0.0; m_targetOffset = offset; m_animationCurve = CompositorScrollOffsetAnimationCurve::create( compositorOffsetFromBlinkOffset(m_targetOffset), CompositorScrollOffsetAnimationCurve::ScrollDurationDeltaBased); m_scrollableArea->registerForAnimation(); if (!m_scrollableArea->scheduleAnimation()) { resetAnimationState(); notifyOffsetChanged(offset); } m_runState = RunState::WaitingToSendToCompositor; }
void ProgrammaticScrollAnimator::layerForCompositedScrollingDidChange( CompositorAnimationTimeline* timeline) { reattachCompositorPlayerIfNeeded(timeline); // If the composited scrolling layer is lost during a composited animation, // continue the animation on the main thread. if (m_runState == RunState::RunningOnCompositor && !m_scrollableArea->layerForScrolling()) { m_runState = RunState::RunningOnMainThread; m_compositorAnimationId = 0; m_compositorAnimationGroupId = 0; m_animationCurve->setInitialValue( compositorOffsetFromBlinkOffset(m_scrollableArea->getScrollOffset())); m_scrollableArea->registerForAnimation(); if (!m_scrollableArea->scheduleAnimation()) { resetAnimationState(); notifyOffsetChanged(m_targetOffset); } } }
void ScrollAnimator::updateCompositorAnimations() { ScrollAnimatorCompositorCoordinator::updateCompositorAnimations(); if (m_runState == RunState::PostAnimationCleanup) { postAnimationCleanupAndReset(); return; } if (m_runState == RunState::WaitingToCancelOnCompositor) { DCHECK(m_compositorAnimationId); abortAnimation(); postAnimationCleanupAndReset(); return; } if (m_runState == RunState::RunningOnCompositorButNeedsTakeover) { // The call to ::takeOverCompositorAnimation aborted the animation and // put us in this state. The assumption is that takeOver is called // because a main thread scrolling reason is added, and simply trying // to ::sendAnimationToCompositor will fail and we will run on the main // thread. resetAnimationIds(); m_runState = RunState::WaitingToSendToCompositor; } if (m_runState == RunState::RunningOnCompositorButNeedsUpdate || m_runState == RunState::WaitingToCancelOnCompositorButNewScroll || m_runState == RunState::RunningOnCompositorButNeedsAdjustment) { // Abort the running animation before a new one with an updated // target is added. abortAnimation(); resetAnimationIds(); if (m_runState != RunState::RunningOnCompositorButNeedsAdjustment) { // When in RunningOnCompositorButNeedsAdjustment, the call to // ::adjustScrollOffsetAnimation should have made the necessary // adjustment to the curve. m_animationCurve->updateTarget( m_timeFunction() - m_startTime, compositorOffsetFromBlinkOffset(m_targetOffset)); } if (m_runState == RunState::WaitingToCancelOnCompositorButNewScroll) { m_animationCurve->setInitialValue( compositorOffsetFromBlinkOffset(currentOffset())); } m_runState = RunState::WaitingToSendToCompositor; } if (m_runState == RunState::WaitingToSendToCompositor) { if (!m_compositorAnimationAttachedToElementId) reattachCompositorPlayerIfNeeded( getScrollableArea()->compositorAnimationTimeline()); if (!m_animationCurve) createAnimationCurve(); bool runningOnMainThread = false; bool sentToCompositor = sendAnimationToCompositor(); if (!sentToCompositor) { runningOnMainThread = registerAndScheduleAnimation(); if (runningOnMainThread) m_runState = RunState::RunningOnMainThread; } // Main thread should deal with the scroll animations it started. if (sentToCompositor || runningOnMainThread) addMainThreadScrollingReason(); else removeMainThreadScrollingReason(); } }