double Animation::timeToEffectChange()
{
    ASSERT(!m_outdated);
    if (!hasStartTime())
        return std::numeric_limits<double>::infinity();

    double currentTime = calculateCurrentTime();
    if (m_held) {
        if (limited(currentTime)) {
            if (m_playbackRate > 0 && m_endClip + effectEnd() > currentTime)
                return m_endClip + effectEnd() - currentTime;
            if (m_playbackRate < 0 && m_startClip <= currentTime)
                return m_startClip - currentTime;
        }
        return std::numeric_limits<double>::infinity();
    }

    if (!m_content)
        return -currentTimeInternal() / m_playbackRate;
    double result = m_playbackRate > 0
        ? m_content->timeToForwardsEffectChange() / m_playbackRate
        : m_content->timeToReverseEffectChange() / -m_playbackRate;

    return !hasActiveAnimationsOnCompositor() && m_content->phase() == AnimationEffect::PhaseActive
        ? 0
        : clipTimeToEffectChange(result);
}
Exemple #2
0
void AnimationPlayer::unpauseInternal()
{
    if (!m_paused)
        return;
    m_paused = false;
    setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
}
void AnimationTimeline::serviceAnimations(TimingUpdateReason reason)
{
    TRACE_EVENT0("blink", "AnimationTimeline::serviceAnimations");

    m_lastCurrentTimeInternal = currentTimeInternal();

    m_timing->cancelWake();

    WillBeHeapVector<RawPtrWillBeMember<Animation>> animations;
    animations.reserveInitialCapacity(m_animationsNeedingUpdate.size());
    for (RefPtrWillBeMember<Animation> animation : m_animationsNeedingUpdate)
        animations.append(animation.get());

    std::sort(animations.begin(), animations.end(), Animation::hasLowerPriority);

    for (Animation* animation : animations) {
        if (!animation->update(reason))
            m_animationsNeedingUpdate.remove(animation);
    }

    ASSERT(m_outdatedAnimationCount == 0);

#if ENABLE(ASSERT)
    for (const auto& animation : m_animationsNeedingUpdate)
        ASSERT(!animation->outdated());
#endif
}
bool AnimationTimeline::needsAnimationTimingUpdate()
{
    if (currentTimeInternal() == m_lastCurrentTimeInternal)
        return false;

    if (std::isnan(currentTimeInternal()) && std::isnan(m_lastCurrentTimeInternal))
        return false;

    // We allow m_lastCurrentTimeInternal to advance here when there
    // are no animations to allow animations spawned during style
    // recalc to not invalidate this flag.
    if (m_animationsNeedingUpdate.isEmpty())
        m_lastCurrentTimeInternal = currentTimeInternal();

    return !m_animationsNeedingUpdate.isEmpty();
}
Exemple #5
0
void AnimationPlayer::reverse()
{
    if (!m_playbackRate) {
        return;
    }
    if (m_content) {
        if (m_playbackRate > 0 && currentTimeInternal() > sourceEnd()) {
            setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand);
            ASSERT(finished());
        } else if (m_playbackRate < 0 && currentTimeInternal() < 0) {
            setCurrentTimeInternal(0, TimingUpdateOnDemand);
            ASSERT(finished());
        }
    }
    setPlaybackRate(-m_playbackRate);
    unpauseInternal();
}
double Animation::currentTime()
{
    PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);

    if (m_currentTimePending || playStateInternal() == Idle)
        return std::numeric_limits<double>::quiet_NaN();

    return currentTimeInternal() * 1000;
}
Exemple #7
0
void AnimationPlayer::pauseForTesting(double pauseTime)
{
    RELEASE_ASSERT(!paused());
    setCurrentTimeInternal(pauseTime, TimingUpdateOnDemand);
    if (hasActiveAnimationsOnCompositor())
        toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
    m_isPausedForTesting = true;
    pause();
}
Exemple #8
0
double AnimationPlayer::currentTime()
{
    PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);

    UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetCurrentTime);
    if (m_currentTimePending || playStateInternal() == Idle)
        return std::numeric_limits<double>::quiet_NaN();

    return currentTimeInternal() * 1000;
}
Exemple #9
0
void AnimationPlayer::pause()
{
    if (m_paused)
        return;
    if (playing()) {
        setCompositorPending();
        m_currentTimePending = true;
    }
    m_paused = true;
    setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
}
Exemple #10
0
double AnimationPlayer::timeToEffectChange()
{
    ASSERT(!m_outdated);
    if (m_held || !hasStartTime())
        return std::numeric_limits<double>::infinity();
    if (!m_content)
        return -currentTimeInternal() / m_playbackRate;
    if (m_playbackRate > 0)
        return m_content->timeToForwardsEffectChange() / m_playbackRate;
    return m_content->timeToReverseEffectChange() / -m_playbackRate;
}
Exemple #11
0
bool AnimationPlayer::maybeStartAnimationOnCompositor()
{
    if (!canStartAnimationOnCompositor())
        return false;

    bool reversed = m_playbackRate < 0;

    double startTime = timeline()->zeroTime() + startTimeInternal();
    if (reversed) {
        startTime -= sourceEnd() / fabs(m_playbackRate);
    }

    double timeOffset = 0;
    if (std::isnan(startTime)) {
        timeOffset = reversed ? sourceEnd() - currentTimeInternal() : currentTimeInternal();
        timeOffset = timeOffset / fabs(m_playbackRate);
    }
    ASSERT(m_compositorGroup != 0);
    return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(m_compositorGroup, startTime, timeOffset, m_playbackRate);
}
Exemple #12
0
bool AnimationPlayer::maybeStartAnimationOnCompositor()
{
    if (!canStartAnimationOnCompositor())
        return false;

    double startTime = timeline()->zeroTime() + startTimeInternal();
    double timeOffset = 0;
    if (std::isnan(startTime)) {
        timeOffset = currentTimeInternal();
    }
    return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(startTime, timeOffset);
}
Exemple #13
0
void AnimationPlayer::pause()
{
    if (m_paused)
        return;

    PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);

    if (playing()) {
        m_currentTimePending = true;
    }
    m_paused = true;
    setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
}
void Animation::cancel()
{
    PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);

    if (playStateInternal() == Idle)
        return;

    m_holdTime = currentTimeInternal();
    m_held = true;
    // TODO
    m_playState = Idle;
    m_startTime = nullValue();
    m_currentTimePending = false;
}
Exemple #15
0
double AnimationPlayer::timeToEffectChange()
{
    ASSERT(!m_outdated);
    if (m_held || !hasStartTime())
        return std::numeric_limits<double>::infinity();
    if (!m_content)
        return -currentTimeInternal() / m_playbackRate;
    double result = m_playbackRate > 0
        ? m_content->timeToForwardsEffectChange() / m_playbackRate
        : m_content->timeToReverseEffectChange() / -m_playbackRate;
    return !hasActiveAnimationsOnCompositor() && m_content->phase() == AnimationNode::PhaseActive
        ? 0
        : result;
}
Exemple #16
0
void AnimationTimeline::setPlaybackRate(double playbackRate) {
    if (!isActive())
        return;
    double currentTime = currentTimeInternal();
    m_playbackRate = playbackRate;
    m_zeroTime = playbackRate == 0 ? currentTime
                 : document()->animationClock().currentTime() -
                 currentTime / playbackRate;
    m_zeroTimeInitialized = true;

    // Corresponding compositor animation may need to be restarted to pick up
    // the new playback rate. Marking the effect changed forces this.
    setAllCompositorPending(true);
}
Exemple #17
0
void AnimationPlayer::setPlaybackRateInternal(double playbackRate)
{
    ASSERT(std::isfinite(playbackRate));
    ASSERT(playbackRate != m_playbackRate);

    if (!finished() && !paused() && hasStartTime())
        m_currentTimePending = true;

    double storedCurrentTime = currentTimeInternal();
    if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0))
        m_finished = false;

    m_playbackRate = playbackRate;
    m_startTime = std::numeric_limits<double>::quiet_NaN();
    setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
}
void Animation::notifyStartTime(double timelineTime)
{
    if (playing()) {
        ASSERT(std::isnan(m_startTime));
        ASSERT(m_held);

        if (m_playbackRate == 0) {
            setStartTimeInternal(timelineTime);
        } else {
            setStartTimeInternal(timelineTime + currentTimeInternal() / -m_playbackRate);
        }

        // FIXME: This avoids marking this animation as outdated needlessly when a start time
        // is notified, but we should refactor how outdating works to avoid this.
        clearOutdated();
        m_currentTimePending = false;
    }
}
Exemple #19
0
void AnimationPlayer::setSource(AnimationNode* newSource)
{
    if (m_content == newSource)
        return;

    setCompositorPending(true);

    double storedCurrentTime = currentTimeInternal();
    if (m_content)
        m_content->detach();
    m_content = newSource;
    if (newSource) {
        // FIXME: This logic needs to be updated once groups are implemented
        if (newSource->player())
            newSource->player()->cancel();
        newSource->attach(this);
        setOutdated();
    }
    setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
}
Exemple #20
0
void AnimationPlayer::cancel()
{
    PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);

    if (playStateInternal() == Idle)
        return;

    m_holdTime = currentTimeInternal();
    m_held = true;
    // TODO
    m_playState = Idle;
    m_startTime = nullValue();
    m_currentTimePending = false;

    // after cancelation, transitions must be downgraded or they'll fail
    // to be considered when retriggering themselves. This can happen if
    // the transition is captured through getAnimationPlayers then played.
    if (m_content && m_content->isAnimation())
        toAnimation(m_content.get())->downgradeToNormalAnimation();
}
void Animation::setEffect(AnimationEffect* newEffect)
{
    if (m_content == newEffect)
        return;
    PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, SetCompositorPendingWithEffectChanged);

    double storedCurrentTime = currentTimeInternal();
    if (m_content)
        m_content->detach();
    m_content = newEffect;
    if (newEffect) {
        // FIXME: This logic needs to be updated once groups are implemented
        if (newEffect->animation()) {
            newEffect->animation()->cancel();
            newEffect->animation()->setEffect(0);
        }
        newEffect->attach(this);
        setOutdated();
    }
    setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
}
Exemple #22
0
void AnimationTimeline::serviceAnimations(TimingUpdateReason reason)
{
    TRACE_EVENT0("blink", "AnimationTimeline::serviceAnimations");

    m_lastCurrentTimeInternal = currentTimeInternal();

    m_timing->cancelWake();

    WillBeHeapVector<RawPtrWillBeMember<AnimationPlayer>> players;
    players.reserveInitialCapacity(m_playersNeedingUpdate.size());
    for (RefPtrWillBeMember<AnimationPlayer> player : m_playersNeedingUpdate)
        players.append(player.get());

    std::sort(players.begin(), players.end(), AnimationPlayer::hasLowerPriority);

    for (AnimationPlayer* player : players) {
        if (!player->update(reason))
            m_playersNeedingUpdate.remove(player);
    }

    ASSERT(!hasOutdatedAnimationPlayer());
}
double AnimationTimeline::currentTime()
{
    return currentTimeInternal() * 1000;
}
Exemple #24
0
bool AnimationPlayer::update(TimingUpdateReason reason)
{
    if (!m_timeline)
        return false;

    updateCurrentTimingState(reason);
    m_outdated = false;

    if (m_content) {
        double inheritedTime = isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
        m_content->updateInheritedTime(inheritedTime, reason);
    }

    if (finished() && !m_finished) {
        if (reason == TimingUpdateForAnimationFrame && hasStartTime()) {
            const AtomicString& eventType = EventTypeNames::finish;
            if (executionContext() && hasEventListeners(eventType)) {
                m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, currentTime(), timeline()->currentTime());
                m_pendingFinishedEvent->setTarget(this);
                m_pendingFinishedEvent->setCurrentTarget(this);
                m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent);
            }
            m_finished = true;
        }
    }
    ASSERT(!m_outdated);
    return !m_finished || !finished();
}
Exemple #25
0
bool AnimationTimeline::needsAnimationTimingUpdate()
{
    return m_playersNeedingUpdate.size() && currentTimeInternal() != m_lastCurrentTimeInternal;
}
double AnimationTimeline::currentTime(bool& isNull)
{
    return currentTimeInternal(isNull) * 1000;
}
double AnimationTimeline::effectiveTime()
{
    double time = currentTimeInternal();
    return std::isnan(time) ? 0 : time;
}
double AnimationTimeline::currentTimeInternal()
{
    bool isNull;
    return currentTimeInternal(isNull);
}
Exemple #29
0
double AnimationPlayer::currentTime()
{
    if (m_currentTimePending)
        return std::numeric_limits<double>::quiet_NaN();
    return currentTimeInternal() * 1000;
}