bool AnimationPlayer::update(TimingUpdateReason reason) { if (!m_timeline) return false; PlayStateUpdateScope updateScope(*this, reason, DoNotSetCompositorPending); m_outdated = false; bool idle = playStateInternal() == Idle; if (m_content) { double inheritedTime = idle || isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal(); // Special case for end-exclusivity when playing backwards. if (inheritedTime == 0 && m_playbackRate < 0) inheritedTime = -1; m_content->updateInheritedTime(inheritedTime, reason); } if ((idle || finished()) && !m_finished) { if (reason == TimingUpdateForAnimationFrame && (idle || hasStartTime())) { 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; }
void AnimationPlayer::play() { PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); if (!playing()) m_startTime = nullValue(); if (playStateInternal() == Idle) { // We may not go into the pending state, but setting it to something other // than Idle here will force an update. ASSERT(isNull(m_startTime)); m_playState = Pending; m_held = true; m_holdTime = 0; } m_finished = false; unpauseInternal(); if (!m_content) return; double currentTime = this->currentTimeInternal(); if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd())) setCurrentTimeInternal(0, TimingUpdateOnDemand); else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEnd())) setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand); }
ScriptPromise Animation::finished(ScriptState* scriptState) { if (!m_finishedPromise) { m_finishedPromise = new AnimationPromise(scriptState->executionContext(), this, AnimationPromise::Finished); if (playStateInternal() == Finished) m_finishedPromise->resolve(this); } return m_finishedPromise->promise(scriptState->world()); }
ScriptPromise Animation::ready(ScriptState* scriptState) { if (!m_readyPromise) { m_readyPromise = new AnimationPromise(scriptState->executionContext(), this, AnimationPromise::Ready); if (playStateInternal() != Pending) m_readyPromise->resolve(this); } return m_readyPromise->promise(scriptState->world()); }
double Animation::unlimitedCurrentTimeInternal() const { #if ENABLE(ASSERT) currentTimeInternal(); #endif return playStateInternal() == Paused || isNull(m_startTime) ? currentTimeInternal() : calculateCurrentTime(); }
double Animation::currentTime() { PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); if (m_currentTimePending || playStateInternal() == Idle) return std::numeric_limits<double>::quiet_NaN(); return currentTimeInternal() * 1000; }
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; }
void Animation::setStartTime(double startTime) { PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); if (m_paused || playStateInternal() == Idle) return; if (startTime == m_startTime) return; m_currentTimePending = false; setStartTimeInternal(startTime / 1000); }
void Animation::finish(ExceptionState& exceptionState) { PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); if (!m_playbackRate || playStateInternal() == Idle) { return; } if (m_playbackRate > 0 && effectEnd() == std::numeric_limits<double>::infinity()) { exceptionState.throwDOMException(InvalidStateError, "Animation has effect whose end time is infinity."); return; } double newCurrentTime = m_playbackRate < 0 ? 0 : effectEnd(); setCurrentTimeInternal(newCurrentTime, TimingUpdateOnDemand); if (!paused()) { m_startTime = calculateStartTime(newCurrentTime); } m_currentTimePending = false; ASSERT(playStateInternal() != Idle); ASSERT(limited()); }
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; }
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()); }
void AnimationPlayer::setStartTime(double startTime) { PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand); UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetStartTime); if (m_paused || playStateInternal() == Idle) return; if (!std::isfinite(startTime)) return; if (startTime == m_startTime) return; m_currentTimePending = false; setStartTimeInternal(startTime / 1000); }
String AnimationPlayer::playState() { switch (playStateInternal()) { case Idle: return "idle"; case Pending: return "pending"; case Running: return "running"; case Paused: return "paused"; case Finished: return "finished"; default: ASSERT_NOT_REACHED(); return ""; } }
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(); }
// 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(); } }