示例#1
0
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();
      }
    }
  }
}
void ScrollAnimatorCompositorCoordinator::compositorAnimationFinished(
    int groupId)
{
    if (m_compositorAnimationGroupId != groupId)
        return;

    m_compositorAnimationId = 0;
    m_compositorAnimationGroupId = 0;

    switch (m_runState) {
    case RunState::Idle:
    case RunState::PostAnimationCleanup:
    case RunState::RunningOnMainThread:
        ASSERT_NOT_REACHED();
        break;
    case RunState::WaitingToSendToCompositor:
        break;
    case RunState::RunningOnCompositor:
    case RunState::RunningOnCompositorButNeedsUpdate:
    case RunState::RunningOnCompositorButNeedsTakeover:
    case RunState::WaitingToCancelOnCompositor:
        m_runState = RunState::PostAnimationCleanup;
        // Get serviced the next time compositor updates are allowed.
        if (scrollableArea())
            scrollableArea()->registerForAnimation();
        else
            resetAnimationState();
    }
}
void ScrollAnimatorCompositorCoordinator::cancelAnimation()
{
    switch (m_runState) {
    case RunState::Idle:
    case RunState::WaitingToCancelOnCompositor:
    case RunState::PostAnimationCleanup:
        break;
    case RunState::RunningOnCompositorButNeedsTakeover:
    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:
        m_runState = RunState::PostAnimationCleanup;
        break;
    case RunState::RunningOnCompositorButNeedsUpdate:
    case RunState::RunningOnCompositor:
        m_runState = RunState::WaitingToCancelOnCompositor;

        // Get serviced the next time compositor updates are allowed.
        scrollableArea()->registerForAnimation();
    }
}
示例#4
0
void ScrollAnimator::postAnimationCleanupAndReset() {
  // Remove the temporary main thread scrolling reason that was added while
  // main thread had scheduled an animation.
  removeMainThreadScrollingReason();

  resetAnimationState();
}
示例#5
0
void ScrollAnimator::tickAnimation(double monotonicTime)
{
    if (m_runState != RunState::RunningOnMainThread)
        return;

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

    offset = FloatPoint(m_scrollableArea->clampScrollPosition(offset));

    m_currentPosX = offset.x();
    m_currentPosY = offset.y();

    if (isFinished)
        resetAnimationState();
    else
        scrollableArea()->scheduleAnimation();

    TRACE_EVENT0("blink", "ScrollAnimator::notifyPositionChanged");
    notifyPositionChanged();
}
示例#6
0
void ScrollAnimator::scrollToOffsetWithoutAnimation(
    const ScrollOffset& offset) {
  m_currentOffset = offset;

  resetAnimationState();
  notifyOffsetChanged();
}
示例#7
0
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;
}
示例#8
0
void ScrollAnimator::scrollToOffsetWithoutAnimation(const FloatPoint& offset)
{
    m_currentPosX = offset.x();
    m_currentPosY = offset.y();

    resetAnimationState();
    notifyPositionChanged();
}
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);

        removeAnimation();

        m_compositorAnimationId = 0;
        m_compositorAnimationGroupId = 0;
        if (m_runState == RunState::WaitingToCancelOnCompositor) {
            resetAnimationState();
            return;
        }
    }

    if (m_runState == RunState::WaitingToSendToCompositor) {
        bool sentToCompositor = false;

        if (!m_scrollableArea->shouldScrollOnMainThread()) {
            OwnPtr<WebCompositorAnimation> animation = adoptPtr(Platform::current()->compositorSupport()->createAnimation(*m_animationCurve, WebCompositorAnimation::TargetPropertyScrollOffset));

            int animationId = animation->id();
            int animationGroupId = animation->group();

            if (addAnimation(animation.release())) {
                sentToCompositor = true;
                m_runState = RunState::RunningOnCompositor;
                m_compositorAnimationId = animationId;
                m_compositorAnimationGroupId = animationGroupId;
            }
        }

        if (!sentToCompositor) {
            m_runState = RunState::RunningOnMainThread;
            m_animationCurve->setInitialValue(FloatPoint(m_scrollableArea->scrollPosition()));
            if (!m_scrollableArea->scheduleAnimation()) {
                notifyPositionChanged(IntPoint(m_targetOffset.x(), m_targetOffset.y()));
                resetAnimationState();
            }
        }
    }
}
示例#10
0
bool ScrollAnimator::registerAndScheduleAnimation() {
  getScrollableArea()->registerForAnimation();
  if (!m_scrollableArea->scheduleAnimation()) {
    scrollToOffsetWithoutAnimation(m_targetOffset);
    resetAnimationState();
    return false;
  }
  return true;
}
void ProgrammaticScrollAnimator::tickAnimation(double monotonicTime)
{
    if (m_runState != RunState::RunningOnMainThread)
        return;

    if (!m_startTime)
        m_startTime = monotonicTime;
    double elapsedTime = monotonicTime - m_startTime;
    bool isFinished = (elapsedTime > m_animationCurve->duration());
    FloatPoint offset = m_animationCurve->getValue(elapsedTime);
    notifyPositionChanged(IntPoint(offset.x(), offset.y()));

    if (isFinished) {
        resetAnimationState();
    } else if (!m_scrollableArea->scheduleAnimation()) {
        notifyPositionChanged(IntPoint(m_targetOffset.x(), m_targetOffset.y()));
        resetAnimationState();
    }
}
示例#12
0
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(FloatPoint offset)
{
    m_startTime = 0.0;
    m_targetOffset = offset;
    m_animationCurve = adoptPtr(Platform::current()->compositorSupport()->createScrollOffsetAnimationCurve(
                                    m_targetOffset,
                                    WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut,
                                    WebScrollOffsetAnimationCurve::ScrollDurationDeltaBased));

    m_scrollableArea->registerForAnimation();
    if (!m_scrollableArea->scheduleAnimation()) {
        resetAnimationState();
        notifyPositionChanged(IntPoint(offset.x(), offset.y()));
    }
    m_runState = RunState::WaitingToSendToCompositor;
}
void ProgrammaticScrollAnimator::layerForCompositedScrollingDidChange(WebCompositorAnimationTimeline* 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(FloatPoint(m_scrollableArea->scrollPosition()));
        m_scrollableArea->registerForAnimation();
        if (!m_scrollableArea->scheduleAnimation()) {
            resetAnimationState();
            notifyPositionChanged(IntPoint(m_targetOffset.x(), m_targetOffset.y()));
        }
    }
}
示例#15
0
void ProgrammaticScrollAnimator::tickAnimation(double monotonicTime) {
  if (m_runState != RunState::RunningOnMainThread)
    return;

  if (!m_startTime)
    m_startTime = monotonicTime;
  double elapsedTime = monotonicTime - m_startTime;
  bool isFinished = (elapsedTime > m_animationCurve->duration());
  ScrollOffset offset =
      blinkOffsetFromCompositorOffset(m_animationCurve->getValue(elapsedTime));
  notifyOffsetChanged(offset);

  if (isFinished) {
    m_runState = RunState::PostAnimationCleanup;
  } else if (!m_scrollableArea->scheduleAnimation()) {
    notifyOffsetChanged(offset);
    resetAnimationState();
  }
}
示例#16
0
ScrollResult ScrollAnimator::userScroll(ScrollGranularity granularity,
                                        const ScrollOffset& delta) {
  if (!m_scrollableArea->scrollAnimatorEnabled())
    return ScrollAnimatorBase::userScroll(granularity, delta);

  TRACE_EVENT0("blink", "ScrollAnimator::scroll");

  if (granularity == ScrollByPrecisePixel) {
    // Cancel scroll animation because asked to instant scroll.
    if (hasRunningAnimation())
      cancelAnimation();
    return ScrollAnimatorBase::userScroll(granularity, delta);
  }

  bool needsPostAnimationCleanup = m_runState == RunState::PostAnimationCleanup;
  if (m_runState == RunState::PostAnimationCleanup)
    resetAnimationState();

  ScrollOffset consumedDelta = computeDeltaToConsume(delta);
  ScrollOffset targetOffset = desiredTargetOffset();
  targetOffset += consumedDelta;

  if (willAnimateToOffset(targetOffset)) {
    m_lastGranularity = granularity;
    // Report unused delta only if there is no animation running. See
    // comment below regarding scroll latching.
    // TODO(bokan): Need to standardize how ScrollAnimators report
    // unusedDelta. This differs from ScrollAnimatorMac currently.
    return ScrollResult(true, true, 0, 0);
  }

  // If the run state when this method was called was PostAnimationCleanup and
  // we're not starting an animation, stay in PostAnimationCleanup state so
  // that the main thread scrolling reason can be removed.
  if (needsPostAnimationCleanup)
    m_runState = RunState::PostAnimationCleanup;

  // Report unused delta only if there is no animation and we are not
  // starting one. This ensures we latch for the duration of the
  // animation rather than animating multiple scrollers at the same time.
  return ScrollResult(false, false, delta.width(), delta.height());
}
示例#17
0
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_timeFunction() - m_startTime,
                m_targetOffset);
            m_runState = RunState::WaitingToSendToCompositor;
        }

        if (!m_animationCurve) {
            m_animationCurve = adoptPtr(Platform::current()->compositorSupport()
                ->createScrollOffsetAnimationCurve(
                    m_targetOffset,
                    WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut,
                    m_lastGranularity == ScrollByPixel ?
                        WebScrollOffsetAnimationCurve::ScrollDurationInverseDelta :
                        WebScrollOffsetAnimationCurve::ScrollDurationConstant));
            m_animationCurve->setInitialValue(currentPosition());
        }

        bool sentToCompositor = false;
        if (!m_scrollableArea->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) {
            if (registerAndScheduleAnimation())
                m_runState = RunState::RunningOnMainThread;
        }
    }
}
示例#18
0
ScrollResultOneDimensional ScrollAnimator::userScroll(
    ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta)
{
    if (!m_scrollableArea->scrollAnimatorEnabled())
        return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta);

    TRACE_EVENT0("blink", "ScrollAnimator::scroll");

    if (granularity == ScrollByPrecisePixel) {
        if (hasRunningAnimation()) {
            abortAnimation();
            resetAnimationState();
        }
        return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta);
    }

    float usedPixelDelta = computeDeltaToConsume(orientation, step * delta);
    FloatPoint pixelDelta = (orientation == VerticalScrollbar
        ? FloatPoint(0, usedPixelDelta) : FloatPoint(usedPixelDelta, 0));

    FloatPoint targetPos = desiredTargetPosition();
    targetPos.moveBy(pixelDelta);

    if (m_animationCurve) {
        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) {
            if (registerAndScheduleAnimation())
                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);
    }

    if ((targetPos - currentPosition()).isZero()) {
        // Report unused delta only if there is no animation and we are not
        // starting one. This ensures we latch for the duration of the
        // animation rather than animating multiple scrollers at the same time.
        return ScrollResultOneDimensional(/* didScroll */ false, delta);
    }

    m_targetOffset = targetPos;
    m_startTime = m_timeFunction();
    m_lastGranularity = granularity;

    if (registerAndScheduleAnimation())
        m_runState = RunState::WaitingToSendToCompositor;

    return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0);
}