void AnimationEffect::getComputedTiming(ComputedTimingProperties& computedTiming) { // ComputedTimingProperties members. computedTiming.setEndTime(endTimeInternal() * 1000); computedTiming.setActiveDuration(activeDurationInternal() * 1000); if (ensureCalculated().isInEffect) { computedTiming.setLocalTime(ensureCalculated().localTime * 1000); computedTiming.setProgress(ensureCalculated().progress); computedTiming.setCurrentIteration(ensureCalculated().currentIteration); } else { computedTiming.setLocalTimeToNull(); computedTiming.setProgressToNull(); computedTiming.setCurrentIterationToNull(); } // KeyframeEffectOptions members. computedTiming.setDelay(specifiedTiming().startDelay * 1000); computedTiming.setEndDelay(specifiedTiming().endDelay * 1000); computedTiming.setFill(Timing::fillModeString(resolvedFillMode(specifiedTiming().fillMode, isKeyframeEffect()))); computedTiming.setIterationStart(specifiedTiming().iterationStart); computedTiming.setIterations(specifiedTiming().iterationCount); UnrestrictedDoubleOrString duration; duration.setUnrestrictedDouble(iterationDuration() * 1000); computedTiming.setDuration(duration); computedTiming.setPlaybackRate(specifiedTiming().playbackRate); computedTiming.setDirection(Timing::playbackDirectionString(specifiedTiming().direction)); computedTiming.setEasing(specifiedTiming().timingFunction->toString()); }
double Animation::calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const { const double start = startTimeInternal() + specifiedTiming().startDelay; const double end = start + activeDurationInternal(); switch (phase()) { case PhaseBefore: ASSERT(start >= localTime); return forwards ? start - localTime : std::numeric_limits<double>::infinity(); case PhaseActive: return 0; case PhaseAfter: ASSERT(localTime >= end); // If this Animation is still in effect then it will need to update // when its parent goes out of effect. We have no way of knowing when // that will be, however, so the parent will need to supply it. return forwards ? std::numeric_limits<double>::infinity() : localTime - end; default: ASSERT_NOT_REACHED(); return std::numeric_limits<double>::infinity(); } }
bool Animation::isCandidateForAnimationOnCompositor(double playerPlaybackRate) const { if (!effect() || !m_target || (m_target->renderStyle() && m_target->renderStyle()->hasMotionPath())) return false; return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *effect(), playerPlaybackRate); }
bool KeyframeEffect::isCandidateForAnimationOnCompositor(double animationPlaybackRate) const { if (!model() || !m_target || (m_target->computedStyle() && m_target->computedStyle()->hasMotionPath())) return false; return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *m_target, animation(), *model(), animationPlaybackRate); }
bool KeyframeEffect::isCandidateForAnimationOnCompositor(double animationPlaybackRate) const { // Do not put transforms on compositor if more than one of them are defined // in computed style because they need to be explicitly ordered if (!model() || !m_target || (m_target->computedStyle() && m_target->computedStyle()->hasMotionPath()) || hasMultipleTransformProperties()) return false; return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *m_target, animation(), *model(), animationPlaybackRate); }
double KeyframeEffectReadOnly::calculateTimeToEffectChange( bool forwards, double localTime, double timeToNextIteration) const { const double startTime = specifiedTiming().startDelay; const double endTimeMinusEndDelay = startTime + activeDurationInternal(); const double endTime = endTimeMinusEndDelay + specifiedTiming().endDelay; const double afterTime = std::min(endTimeMinusEndDelay, endTime); switch (getPhase()) { case PhaseNone: return std::numeric_limits<double>::infinity(); case PhaseBefore: DCHECK_GE(startTime, localTime); return forwards ? startTime - localTime : std::numeric_limits<double>::infinity(); case PhaseActive: if (forwards) { // Need service to apply fill / fire events. const double timeToEnd = afterTime - localTime; if (requiresIterationEvents()) { return std::min(timeToEnd, timeToNextIteration); } return timeToEnd; } return 0; case PhaseAfter: DCHECK_GE(localTime, afterTime); // If this KeyframeEffect is still in effect then it will need to update // when its parent goes out of effect. We have no way of knowing when // that will be, however, so the parent will need to supply it. return forwards ? std::numeric_limits<double>::infinity() : localTime - afterTime; default: NOTREACHED(); return std::numeric_limits<double>::infinity(); } }
double Animation::calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const { const double start = startTimeInternal() + specifiedTiming().startDelay; const double end = start + activeDurationInternal(); switch (phase()) { case PhaseBefore: ASSERT(start >= localTime); return forwards ? start - localTime : std::numeric_limits<double>::infinity(); case PhaseActive: if (forwards && hasActiveAnimationsOnCompositor()) { ASSERT(specifiedTiming().playbackRate == 1); // Need service to apply fill / fire events. const double timeToEnd = end - localTime; if (hasEvents()) { return std::min(timeToEnd, timeToNextIteration); } else { return timeToEnd; } } return 0; case PhaseAfter: ASSERT(localTime >= end); // If this Animation is still in effect then it will need to update // when its parent goes out of effect. We have no way of knowing when // that will be, however, so the parent will need to supply it. return forwards ? std::numeric_limits<double>::infinity() : localTime - end; default: ASSERT_NOT_REACHED(); return std::numeric_limits<double>::infinity(); } }
bool KeyframeEffectReadOnly::maybeStartAnimationOnCompositor( int group, double startTime, double currentTime, double animationPlaybackRate) { DCHECK(!hasActiveAnimationsOnCompositor()); if (!isCandidateForAnimationOnCompositor(animationPlaybackRate)) return false; if (!CompositorAnimations::canStartAnimationOnCompositor(*m_target)) return false; CompositorAnimations::startAnimationOnCompositor( *m_target, group, startTime, currentTime, specifiedTiming(), *animation(), *model(), m_compositorAnimationIds, animationPlaybackRate); DCHECK(!m_compositorAnimationIds.isEmpty()); return true; }
bool Animation::maybeStartAnimationOnCompositor(double startTime, double currentTime) { ASSERT(!hasActiveAnimationsOnCompositor()); if (!isCandidateForAnimationOnCompositor()) return false; if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_target)) return false; if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target, startTime, currentTime, specifiedTiming(), *effect(), m_compositorAnimationIds)) return false; ASSERT(!m_compositorAnimationIds.isEmpty()); return true; }
bool Animation::isCandidateForAnimationOnCompositor() const { if (!effect() || !m_target) return false; return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *effect()); }