double AnimationPlayer::currentTimeInternal() const { double result = m_held ? m_holdTime : calculateCurrentTime(); #if ENABLE(ASSERT) const_cast<AnimationPlayer*>(this)->updateCurrentTimingState(TimingUpdateOnDemand); ASSERT(result == (m_held ? m_holdTime : calculateCurrentTime())); #endif return result; }
void AnimationPlayer::setStartTimeInternal(double newStartTime) { ASSERT(!m_paused); ASSERT(std::isfinite(newStartTime)); ASSERT(newStartTime != m_startTime); bool hadStartTime = hasStartTime(); double previousCurrentTime = currentTimeInternal(); m_startTime = newStartTime; if (m_held && m_playbackRate) { // If held, the start time would still be derrived from the hold time. // Force a new, limited, current time. m_held = false; double currentTime = calculateCurrentTime(); if (m_playbackRate > 0 && currentTime > sourceEnd()) { currentTime = sourceEnd(); } else if (m_playbackRate < 0 && currentTime < 0) { currentTime = 0; } setCurrentTimeInternal(currentTime, TimingUpdateOnDemand); } updateCurrentTimingState(TimingUpdateOnDemand); double newCurrentTime = currentTimeInternal(); if (previousCurrentTime != newCurrentTime) { setOutdated(); } else if (!hadStartTime && m_timeline) { // Even though this player is not outdated, time to effect change is // infinity until start time is set. m_timeline->wake(); } }
double AnimationPlayer::currentTimeInternal() { updateCurrentTimingState(TimingUpdateOnDemand); if (m_held) return m_holdTime; return calculateCurrentTime(); }
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); }
double Animation::unlimitedCurrentTimeInternal() const { #if ENABLE(ASSERT) currentTimeInternal(); #endif return playStateInternal() == Paused || isNull(m_startTime) ? currentTimeInternal() : calculateCurrentTime(); }
// Update timing to reflect updated animation clock due to tick void AnimationPlayer::updateCurrentTimingState(TimingUpdateReason reason) { if (m_held) { setCurrentTimeInternal(m_holdTime, reason); return; } if (!limited(calculateCurrentTime())) return; m_held = true; m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd(); }
// Update timing to reflect updated animation clock due to tick void Animation::updateCurrentTimingState(TimingUpdateReason reason) { if (m_held) { double newCurrentTime = m_holdTime; if (playStateInternal() == Finished && !isNull(m_startTime) && m_timeline) { // Add hystersis due to floating point error accumulation if (!limited(calculateCurrentTime() + 0.001 * m_playbackRate)) { // The current time became unlimited, eg. due to a backwards // seek of the timeline. newCurrentTime = calculateCurrentTime(); } else if (!limited(m_holdTime)) { // The hold time became unlimited, eg. due to the effect // becoming longer. newCurrentTime = clampTo<double>(calculateCurrentTime(), 0, effectEnd()); } } setCurrentTimeInternal(newCurrentTime, reason); } else if (limited(calculateCurrentTime())) { m_held = true; m_holdTime = m_playbackRate < 0 ? 0 : effectEnd(); } }
bool Animation::update(TimingUpdateReason reason) { if (!m_timeline) return false; PlayStateUpdateScope updateScope(*this, reason, DoNotSetCompositorPending); clearOutdated(); bool idle = playStateInternal() == Idle; if (m_content) { double inheritedTime = idle || isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal(); if (!isNull(inheritedTime)) { double timeForClipping = m_held && (!limited(inheritedTime) || isNull(m_startTime)) // Use hold time when there is no start time. ? inheritedTime // Use calculated current time when the animation is limited. : calculateCurrentTime(); if (clipped(timeForClipping)) inheritedTime = nullValue(); } // Special case for end-exclusivity when playing backwards. if (inheritedTime == 0 && m_playbackRate < 0) inheritedTime = -1; m_content->updateInheritedTime(inheritedTime, reason); } if ((idle || limited()) && !m_finished) { if (reason == TimingUpdateForAnimationFrame && (idle || hasStartTime())) { if (idle) { // TODO(dstockwell): Fire the cancel event. } else { const AtomicString& eventType = EventTypeNames::finish; if (executionContext() && hasEventListeners(eventType)) { double eventCurrentTime = currentTimeInternal() * 1000; m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, eventCurrentTime, 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 || std::isfinite(timeToEffectChange()); }
double Animation::clipTimeToEffectChange(double result) const { double currentTime = calculateCurrentTime(); if (m_playbackRate > 0) { if (currentTime <= m_startClip) result = std::min(result, (m_startClip - currentTime) / m_playbackRate); else if (currentTime < m_endClip + effectEnd()) result = std::min(result, (m_endClip + effectEnd() - currentTime) / m_playbackRate); } else { if (currentTime >= m_endClip + effectEnd()) result = std::min(result, (currentTime - m_endClip + effectEnd()) / -m_playbackRate); else if (currentTime > m_startClip) result = std::min(result, (currentTime - m_startClip) / -m_playbackRate); } return result; }