Commit f1b25aae authored by Stephen McGruer's avatar Stephen McGruer Committed by Commit Bot

Cleanup of Animations timing function-related code

This is a code health CL which makes a number of changes:
  * Renames AnimationEffect::RepeatedDuration to ActiveDuration to align
    with the spec.
  * Adds a few links/descriptions to the AnimationEffect header.
  * Moves two functions in timing_calculations.h to the end, to properly
    group all spec-related functions and differentiate them from
    non-spec related.
  * Documents said moved functions.

No behavior changes should be seen from this CL, its purely renames +
comments.

Bug: 630915
Change-Id: I8c9618212722d650ea009f54af0fa910214d3452
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1678719Reviewed-by: default avatarKevin Ellis <kevers@chromium.org>
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672630}
parent b6115c34
...@@ -70,7 +70,7 @@ AnimationTimeDelta AnimationEffect::IterationDuration() const { ...@@ -70,7 +70,7 @@ AnimationTimeDelta AnimationEffect::IterationDuration() const {
return result; return result;
} }
double AnimationEffect::RepeatedDuration() const { double AnimationEffect::ActiveDuration() const {
const double result = const double result =
MultiplyZeroAlwaysGivesZero(IterationDuration(), timing_.iteration_count); MultiplyZeroAlwaysGivesZero(IterationDuration(), timing_.iteration_count);
DCHECK_GE(result, 0); DCHECK_GE(result, 0);
...@@ -80,7 +80,7 @@ double AnimationEffect::RepeatedDuration() const { ...@@ -80,7 +80,7 @@ double AnimationEffect::RepeatedDuration() const {
double AnimationEffect::EndTimeInternal() const { double AnimationEffect::EndTimeInternal() const {
// Per the spec, the end time has a lower bound of 0.0: // Per the spec, the end time has a lower bound of 0.0:
// https://drafts.csswg.org/web-animations-1/#end-time // https://drafts.csswg.org/web-animations-1/#end-time
return std::max(timing_.start_delay + RepeatedDuration() + timing_.end_delay, return std::max(timing_.start_delay + ActiveDuration() + timing_.end_delay,
0.0); 0.0);
} }
...@@ -99,7 +99,7 @@ ComputedEffectTiming* AnimationEffect::getComputedTiming() const { ...@@ -99,7 +99,7 @@ ComputedEffectTiming* AnimationEffect::getComputedTiming() const {
// ComputedEffectTiming members. // ComputedEffectTiming members.
computed_timing->setEndTime(EndTimeInternal() * 1000); computed_timing->setEndTime(EndTimeInternal() * 1000);
computed_timing->setActiveDuration(RepeatedDuration() * 1000); computed_timing->setActiveDuration(ActiveDuration() * 1000);
if (IsNull(EnsureCalculated().local_time)) { if (IsNull(EnsureCalculated().local_time)) {
computed_timing->setLocalTimeToNull(); computed_timing->setLocalTimeToNull();
...@@ -159,7 +159,7 @@ void AnimationEffect::UpdateInheritedTime(double inherited_time, ...@@ -159,7 +159,7 @@ void AnimationEffect::UpdateInheritedTime(double inherited_time,
const double local_time = inherited_time; const double local_time = inherited_time;
double time_to_next_iteration = std::numeric_limits<double>::infinity(); double time_to_next_iteration = std::numeric_limits<double>::infinity();
if (needs_update) { if (needs_update) {
const double active_duration = RepeatedDuration(); const double active_duration = ActiveDuration();
// TODO(yigu): Direction of WorkletAnimation is always forwards based on // TODO(yigu): Direction of WorkletAnimation is always forwards based on
// the calculation. Need to unify the logic to handle it correctly. // the calculation. Need to unify the logic to handle it correctly.
// https://crbug.com/896249. // https://crbug.com/896249.
......
...@@ -120,8 +120,12 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable { ...@@ -120,8 +120,12 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
} }
double LocalTime() const { return EnsureCalculated().local_time; } double LocalTime() const { return EnsureCalculated().local_time; }
// https://drafts.csswg.org/web-animations-1/#iteration-duration
AnimationTimeDelta IterationDuration() const; AnimationTimeDelta IterationDuration() const;
double RepeatedDuration() const;
// https://drafts.csswg.org/web-animations-1/#active-duration
double ActiveDuration() const;
double EndTimeInternal() const; double EndTimeInternal() const;
const Timing& SpecifiedTiming() const { return timing_; } const Timing& SpecifiedTiming() const { return timing_; }
...@@ -159,6 +163,11 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable { ...@@ -159,6 +163,11 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
void ClearEventDelegate() { event_delegate_ = nullptr; } void ClearEventDelegate() { event_delegate_ = nullptr; }
virtual void UpdateChildrenAndEffects() const = 0; virtual void UpdateChildrenAndEffects() const = 0;
// This is the value of the iteration duration when it is specified as 'auto'.
// In web-animations-1, auto is treated as "the value zero for the purpose of
// timing model calculations and for the result of the duration member
// returned from getComputedTiming()".
virtual AnimationTimeDelta IntrinsicIterationDuration() const { virtual AnimationTimeDelta IntrinsicIterationDuration() const {
return AnimationTimeDelta(); return AnimationTimeDelta();
} }
......
...@@ -135,7 +135,7 @@ TEST(AnimationAnimationEffectTest, Sanity) { ...@@ -135,7 +135,7 @@ TEST(AnimationAnimationEffectTest, Sanity) {
EXPECT_TRUE(animation_node->IsCurrent()); EXPECT_TRUE(animation_node->IsCurrent());
EXPECT_TRUE(animation_node->IsInEffect()); EXPECT_TRUE(animation_node->IsInEffect());
EXPECT_EQ(0, animation_node->CurrentIteration()); EXPECT_EQ(0, animation_node->CurrentIteration());
EXPECT_EQ(2, animation_node->RepeatedDuration()); EXPECT_EQ(2, animation_node->ActiveDuration());
EXPECT_EQ(0, animation_node->Progress()); EXPECT_EQ(0, animation_node->Progress());
animation_node->UpdateInheritedTime(1); animation_node->UpdateInheritedTime(1);
...@@ -145,7 +145,7 @@ TEST(AnimationAnimationEffectTest, Sanity) { ...@@ -145,7 +145,7 @@ TEST(AnimationAnimationEffectTest, Sanity) {
EXPECT_TRUE(animation_node->IsCurrent()); EXPECT_TRUE(animation_node->IsCurrent());
EXPECT_TRUE(animation_node->IsInEffect()); EXPECT_TRUE(animation_node->IsInEffect());
EXPECT_EQ(0, animation_node->CurrentIteration()); EXPECT_EQ(0, animation_node->CurrentIteration());
EXPECT_EQ(2, animation_node->RepeatedDuration()); EXPECT_EQ(2, animation_node->ActiveDuration());
EXPECT_EQ(0.5, animation_node->Progress()); EXPECT_EQ(0.5, animation_node->Progress());
animation_node->UpdateInheritedTime(2); animation_node->UpdateInheritedTime(2);
...@@ -155,7 +155,7 @@ TEST(AnimationAnimationEffectTest, Sanity) { ...@@ -155,7 +155,7 @@ TEST(AnimationAnimationEffectTest, Sanity) {
EXPECT_FALSE(animation_node->IsCurrent()); EXPECT_FALSE(animation_node->IsCurrent());
EXPECT_TRUE(animation_node->IsInEffect()); EXPECT_TRUE(animation_node->IsInEffect());
EXPECT_EQ(0, animation_node->CurrentIteration()); EXPECT_EQ(0, animation_node->CurrentIteration());
EXPECT_EQ(2, animation_node->RepeatedDuration()); EXPECT_EQ(2, animation_node->ActiveDuration());
EXPECT_EQ(1, animation_node->Progress()); EXPECT_EQ(1, animation_node->Progress());
animation_node->UpdateInheritedTime(3); animation_node->UpdateInheritedTime(3);
...@@ -165,7 +165,7 @@ TEST(AnimationAnimationEffectTest, Sanity) { ...@@ -165,7 +165,7 @@ TEST(AnimationAnimationEffectTest, Sanity) {
EXPECT_FALSE(animation_node->IsCurrent()); EXPECT_FALSE(animation_node->IsCurrent());
EXPECT_TRUE(animation_node->IsInEffect()); EXPECT_TRUE(animation_node->IsInEffect());
EXPECT_EQ(0, animation_node->CurrentIteration()); EXPECT_EQ(0, animation_node->CurrentIteration());
EXPECT_EQ(2, animation_node->RepeatedDuration()); EXPECT_EQ(2, animation_node->ActiveDuration());
EXPECT_EQ(1, animation_node->Progress()); EXPECT_EQ(1, animation_node->Progress());
} }
...@@ -245,12 +245,12 @@ TEST(AnimationAnimationEffectTest, ZeroIteration) { ...@@ -245,12 +245,12 @@ TEST(AnimationAnimationEffectTest, ZeroIteration) {
auto* animation_node = MakeGarbageCollected<TestAnimationEffect>(timing); auto* animation_node = MakeGarbageCollected<TestAnimationEffect>(timing);
animation_node->UpdateInheritedTime(-1); animation_node->UpdateInheritedTime(-1);
EXPECT_EQ(0, animation_node->RepeatedDuration()); EXPECT_EQ(0, animation_node->ActiveDuration());
EXPECT_TRUE(IsNull(animation_node->CurrentIteration())); EXPECT_TRUE(IsNull(animation_node->CurrentIteration()));
EXPECT_FALSE(animation_node->Progress()); EXPECT_FALSE(animation_node->Progress());
animation_node->UpdateInheritedTime(0); animation_node->UpdateInheritedTime(0);
EXPECT_EQ(0, animation_node->RepeatedDuration()); EXPECT_EQ(0, animation_node->ActiveDuration());
EXPECT_EQ(0, animation_node->CurrentIteration()); EXPECT_EQ(0, animation_node->CurrentIteration());
EXPECT_EQ(0, animation_node->Progress()); EXPECT_EQ(0, animation_node->Progress());
} }
...@@ -267,7 +267,7 @@ TEST(AnimationAnimationEffectTest, InfiniteIteration) { ...@@ -267,7 +267,7 @@ TEST(AnimationAnimationEffectTest, InfiniteIteration) {
EXPECT_FALSE(animation_node->Progress()); EXPECT_FALSE(animation_node->Progress());
EXPECT_EQ(std::numeric_limits<double>::infinity(), EXPECT_EQ(std::numeric_limits<double>::infinity(),
animation_node->RepeatedDuration()); animation_node->ActiveDuration());
animation_node->UpdateInheritedTime(0); animation_node->UpdateInheritedTime(0);
EXPECT_EQ(0, animation_node->CurrentIteration()); EXPECT_EQ(0, animation_node->CurrentIteration());
...@@ -373,7 +373,7 @@ TEST(AnimationAnimationEffectTest, ZeroDurationSanity) { ...@@ -373,7 +373,7 @@ TEST(AnimationAnimationEffectTest, ZeroDurationSanity) {
EXPECT_FALSE(animation_node->IsCurrent()); EXPECT_FALSE(animation_node->IsCurrent());
EXPECT_TRUE(animation_node->IsInEffect()); EXPECT_TRUE(animation_node->IsInEffect());
EXPECT_EQ(0, animation_node->CurrentIteration()); EXPECT_EQ(0, animation_node->CurrentIteration());
EXPECT_EQ(0, animation_node->RepeatedDuration()); EXPECT_EQ(0, animation_node->ActiveDuration());
EXPECT_EQ(1, animation_node->Progress()); EXPECT_EQ(1, animation_node->Progress());
animation_node->UpdateInheritedTime(1); animation_node->UpdateInheritedTime(1);
...@@ -383,7 +383,7 @@ TEST(AnimationAnimationEffectTest, ZeroDurationSanity) { ...@@ -383,7 +383,7 @@ TEST(AnimationAnimationEffectTest, ZeroDurationSanity) {
EXPECT_FALSE(animation_node->IsCurrent()); EXPECT_FALSE(animation_node->IsCurrent());
EXPECT_TRUE(animation_node->IsInEffect()); EXPECT_TRUE(animation_node->IsInEffect());
EXPECT_EQ(0, animation_node->CurrentIteration()); EXPECT_EQ(0, animation_node->CurrentIteration());
EXPECT_EQ(0, animation_node->RepeatedDuration()); EXPECT_EQ(0, animation_node->ActiveDuration());
EXPECT_EQ(1, animation_node->Progress()); EXPECT_EQ(1, animation_node->Progress());
} }
...@@ -474,12 +474,12 @@ TEST(AnimationAnimationEffectTest, ZeroDurationInfiniteIteration) { ...@@ -474,12 +474,12 @@ TEST(AnimationAnimationEffectTest, ZeroDurationInfiniteIteration) {
auto* animation_node = MakeGarbageCollected<TestAnimationEffect>(timing); auto* animation_node = MakeGarbageCollected<TestAnimationEffect>(timing);
animation_node->UpdateInheritedTime(-1); animation_node->UpdateInheritedTime(-1);
EXPECT_EQ(0, animation_node->RepeatedDuration()); EXPECT_EQ(0, animation_node->ActiveDuration());
EXPECT_TRUE(IsNull(animation_node->CurrentIteration())); EXPECT_TRUE(IsNull(animation_node->CurrentIteration()));
EXPECT_FALSE(animation_node->Progress()); EXPECT_FALSE(animation_node->Progress());
animation_node->UpdateInheritedTime(0); animation_node->UpdateInheritedTime(0);
EXPECT_EQ(0, animation_node->RepeatedDuration()); EXPECT_EQ(0, animation_node->ActiveDuration());
EXPECT_EQ(std::numeric_limits<double>::infinity(), EXPECT_EQ(std::numeric_limits<double>::infinity(),
animation_node->CurrentIteration()); animation_node->CurrentIteration());
EXPECT_EQ(1, animation_node->Progress()); EXPECT_EQ(1, animation_node->Progress());
...@@ -573,7 +573,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationSanity) { ...@@ -573,7 +573,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationSanity) {
animation_node->UpdateInheritedTime(0); animation_node->UpdateInheritedTime(0);
EXPECT_EQ(std::numeric_limits<double>::infinity(), EXPECT_EQ(std::numeric_limits<double>::infinity(),
animation_node->RepeatedDuration()); animation_node->ActiveDuration());
EXPECT_EQ(AnimationEffect::kPhaseActive, animation_node->GetPhase()); EXPECT_EQ(AnimationEffect::kPhaseActive, animation_node->GetPhase());
EXPECT_TRUE(animation_node->IsInPlay()); EXPECT_TRUE(animation_node->IsInPlay());
EXPECT_TRUE(animation_node->IsCurrent()); EXPECT_TRUE(animation_node->IsCurrent());
...@@ -584,7 +584,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationSanity) { ...@@ -584,7 +584,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationSanity) {
animation_node->UpdateInheritedTime(1); animation_node->UpdateInheritedTime(1);
EXPECT_EQ(std::numeric_limits<double>::infinity(), EXPECT_EQ(std::numeric_limits<double>::infinity(),
animation_node->RepeatedDuration()); animation_node->ActiveDuration());
EXPECT_EQ(AnimationEffect::kPhaseActive, animation_node->GetPhase()); EXPECT_EQ(AnimationEffect::kPhaseActive, animation_node->GetPhase());
EXPECT_TRUE(animation_node->IsInPlay()); EXPECT_TRUE(animation_node->IsInPlay());
EXPECT_TRUE(animation_node->IsCurrent()); EXPECT_TRUE(animation_node->IsCurrent());
...@@ -602,7 +602,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationZeroIterations) { ...@@ -602,7 +602,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationZeroIterations) {
animation_node->UpdateInheritedTime(0); animation_node->UpdateInheritedTime(0);
EXPECT_EQ(0, animation_node->RepeatedDuration()); EXPECT_EQ(0, animation_node->ActiveDuration());
EXPECT_EQ(AnimationEffect::kPhaseAfter, animation_node->GetPhase()); EXPECT_EQ(AnimationEffect::kPhaseAfter, animation_node->GetPhase());
EXPECT_FALSE(animation_node->IsInPlay()); EXPECT_FALSE(animation_node->IsInPlay());
EXPECT_FALSE(animation_node->IsCurrent()); EXPECT_FALSE(animation_node->IsCurrent());
...@@ -630,7 +630,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationInfiniteIterations) { ...@@ -630,7 +630,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationInfiniteIterations) {
animation_node->UpdateInheritedTime(0); animation_node->UpdateInheritedTime(0);
EXPECT_EQ(std::numeric_limits<double>::infinity(), EXPECT_EQ(std::numeric_limits<double>::infinity(),
animation_node->RepeatedDuration()); animation_node->ActiveDuration());
EXPECT_EQ(AnimationEffect::kPhaseActive, animation_node->GetPhase()); EXPECT_EQ(AnimationEffect::kPhaseActive, animation_node->GetPhase());
EXPECT_TRUE(animation_node->IsInPlay()); EXPECT_TRUE(animation_node->IsInPlay());
EXPECT_TRUE(animation_node->IsCurrent()); EXPECT_TRUE(animation_node->IsCurrent());
...@@ -641,7 +641,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationInfiniteIterations) { ...@@ -641,7 +641,7 @@ TEST(AnimationAnimationEffectTest, InfiniteDurationInfiniteIterations) {
animation_node->UpdateInheritedTime(1); animation_node->UpdateInheritedTime(1);
EXPECT_EQ(std::numeric_limits<double>::infinity(), EXPECT_EQ(std::numeric_limits<double>::infinity(),
animation_node->RepeatedDuration()); animation_node->ActiveDuration());
EXPECT_EQ(AnimationEffect::kPhaseActive, animation_node->GetPhase()); EXPECT_EQ(AnimationEffect::kPhaseActive, animation_node->GetPhase());
EXPECT_TRUE(animation_node->IsInPlay()); EXPECT_TRUE(animation_node->IsInPlay());
EXPECT_TRUE(animation_node->IsCurrent()); EXPECT_TRUE(animation_node->IsCurrent());
......
...@@ -1175,7 +1175,7 @@ void CSSAnimations::AnimationEventDelegate::OnEventCondition( ...@@ -1175,7 +1175,7 @@ void CSSAnimations::AnimationEventDelegate::OnEventCondition(
previous_phase_ != AnimationEffect::kPhaseAfter) { previous_phase_ != AnimationEffect::kPhaseAfter) {
MaybeDispatch(Document::kAnimationEndListener, MaybeDispatch(Document::kAnimationEndListener,
event_type_names::kAnimationend, event_type_names::kAnimationend,
animation_node.RepeatedDuration()); animation_node.ActiveDuration());
} }
previous_phase_ = current_phase; previous_phase_ = current_phase;
...@@ -1249,7 +1249,7 @@ void CSSAnimations::TransitionEventDelegate::OnEventCondition( ...@@ -1249,7 +1249,7 @@ void CSSAnimations::TransitionEventDelegate::OnEventCondition(
// "active time of the animation at the moment it was cancelled, // "active time of the animation at the moment it was cancelled,
// calculated using a fill mode of both". // calculated using a fill mode of both".
double cancel_active_time = CalculateActiveTime( double cancel_active_time = CalculateActiveTime(
animation_node.RepeatedDuration(), Timing::FillMode::BOTH, animation_node.ActiveDuration(), Timing::FillMode::BOTH,
animation_node.LocalTime(), previous_phase_, animation_node.LocalTime(), previous_phase_,
animation_node.SpecifiedTiming()); animation_node.SpecifiedTiming());
EnqueueEvent(event_type_names::kTransitioncancel, cancel_active_time); EnqueueEvent(event_type_names::kTransitioncancel, cancel_active_time);
......
...@@ -436,7 +436,7 @@ double KeyframeEffect::CalculateTimeToEffectChange( ...@@ -436,7 +436,7 @@ double KeyframeEffect::CalculateTimeToEffectChange(
double local_time, double local_time,
double time_to_next_iteration) const { double time_to_next_iteration) const {
const double start_time = SpecifiedTiming().start_delay; const double start_time = SpecifiedTiming().start_delay;
const double end_time_minus_end_delay = start_time + RepeatedDuration(); const double end_time_minus_end_delay = start_time + ActiveDuration();
const double end_time = const double end_time =
end_time_minus_end_delay + SpecifiedTiming().end_delay; end_time_minus_end_delay + SpecifiedTiming().end_delay;
const double after_time = std::min(end_time_minus_end_delay, end_time); const double after_time = std::min(end_time_minus_end_delay, end_time);
......
...@@ -48,6 +48,12 @@ inline bool IsWithinEpsilon(double a, double b) { ...@@ -48,6 +48,12 @@ inline bool IsWithinEpsilon(double a, double b) {
inline bool LessThanOrEqualToWithinEpsilon(double a, double b) { inline bool LessThanOrEqualToWithinEpsilon(double a, double b) {
return a <= b || IsWithinEpsilon(a, b); return a <= b || IsWithinEpsilon(a, b);
} }
inline bool EndsOnIterationBoundary(double iteration_count,
double iteration_start) {
DCHECK(std::isfinite(iteration_count));
return !fmod(iteration_count + iteration_start, 1);
}
} // namespace } // namespace
static inline double MultiplyZeroAlwaysGivesZero(double x, double y) { static inline double MultiplyZeroAlwaysGivesZero(double x, double y) {
...@@ -90,6 +96,7 @@ static inline AnimationEffect::Phase CalculatePhase( ...@@ -90,6 +96,7 @@ static inline AnimationEffect::Phase CalculatePhase(
return AnimationEffect::kPhaseActive; return AnimationEffect::kPhaseActive;
} }
// https://drafts.csswg.org/web-animations/#calculating-the-active-time
static inline double CalculateActiveTime(double active_duration, static inline double CalculateActiveTime(double active_duration,
Timing::FillMode fill_mode, Timing::FillMode fill_mode,
double local_time, double local_time,
...@@ -121,69 +128,6 @@ static inline double CalculateActiveTime(double active_duration, ...@@ -121,69 +128,6 @@ static inline double CalculateActiveTime(double active_duration,
} }
} }
static inline double CalculateOffsetActiveTime(double active_duration,
double active_time,
double start_offset) {
DCHECK_GE(active_duration, 0);
DCHECK_GE(start_offset, 0);
if (IsNull(active_time))
return NullValue();
DCHECK(active_time >= 0 &&
LessThanOrEqualToWithinEpsilon(active_time, active_duration));
if (!std::isfinite(active_time))
return std::numeric_limits<double>::infinity();
return active_time + start_offset;
}
static inline bool EndsOnIterationBoundary(double iteration_count,
double iteration_start) {
DCHECK(std::isfinite(iteration_count));
return !fmod(iteration_count + iteration_start, 1);
}
// TODO(crbug.com/630915): Align this function with current Web Animations spec
// text.
static inline double CalculateIterationTime(double iteration_duration,
double repeated_duration,
double offset_active_time,
double start_offset,
AnimationEffect::Phase phase,
const Timing& specified) {
DCHECK_GT(iteration_duration, 0);
DCHECK_EQ(repeated_duration,
MultiplyZeroAlwaysGivesZero(iteration_duration,
specified.iteration_count));
if (IsNull(offset_active_time))
return NullValue();
DCHECK_GE(offset_active_time, 0);
DCHECK(LessThanOrEqualToWithinEpsilon(offset_active_time,
repeated_duration + start_offset));
if (!std::isfinite(offset_active_time) ||
(offset_active_time - start_offset == repeated_duration &&
specified.iteration_count &&
EndsOnIterationBoundary(specified.iteration_count,
specified.iteration_start)))
return iteration_duration;
DCHECK(std::isfinite(offset_active_time));
double iteration_time = fmod(offset_active_time, iteration_duration);
// This implements step 3 of
// https://drafts.csswg.org/web-animations/#calculating-the-simple-iteration-progress
if (iteration_time == 0 && phase == AnimationEffect::kPhaseAfter &&
repeated_duration != 0 && offset_active_time != 0)
return iteration_duration;
return iteration_time;
}
// Calculates the overall progress, which describes the number of iterations // Calculates the overall progress, which describes the number of iterations
// that have completed (including partial iterations). // that have completed (including partial iterations).
// https://drafts.csswg.org/web-animations/#calculating-the-overall-progress // https://drafts.csswg.org/web-animations/#calculating-the-overall-progress
...@@ -358,6 +302,71 @@ static inline double CalculateTransformedProgress( ...@@ -358,6 +302,71 @@ static inline double CalculateTransformedProgress(
AccuracyForDuration(iteration_duration)); AccuracyForDuration(iteration_duration));
} }
// Offsets the active time by how far into the animation we start (i.e. the
// product of the iteration start and iteration duration). This is not part of
// the Web Animations spec; it is used for calculating the time until the next
// iteration to optimize scheduling.
static inline double CalculateOffsetActiveTime(double active_duration,
double active_time,
double start_offset) {
DCHECK_GE(active_duration, 0);
DCHECK_GE(start_offset, 0);
if (IsNull(active_time))
return NullValue();
DCHECK(active_time >= 0 &&
LessThanOrEqualToWithinEpsilon(active_time, active_duration));
if (!std::isfinite(active_time))
return std::numeric_limits<double>::infinity();
return active_time + start_offset;
}
// Maps the offset active time into 'iteration time space'[0], aka the offset
// into the current iteration. This is not part of the Web Animations spec (note
// that the section linked below is non-normative); it is used for calculating
// the time until the next iteration to optimize scheduling.
//
// [0] https://drafts.csswg.org/web-animations-1/#iteration-time-space
static inline double CalculateIterationTime(double iteration_duration,
double active_duration,
double offset_active_time,
double start_offset,
AnimationEffect::Phase phase,
const Timing& specified) {
DCHECK_GT(iteration_duration, 0);
DCHECK_EQ(active_duration,
MultiplyZeroAlwaysGivesZero(iteration_duration,
specified.iteration_count));
if (IsNull(offset_active_time))
return NullValue();
DCHECK_GE(offset_active_time, 0);
DCHECK(LessThanOrEqualToWithinEpsilon(offset_active_time,
active_duration + start_offset));
if (!std::isfinite(offset_active_time) ||
(offset_active_time - start_offset == active_duration &&
specified.iteration_count &&
EndsOnIterationBoundary(specified.iteration_count,
specified.iteration_start)))
return iteration_duration;
DCHECK(std::isfinite(offset_active_time));
double iteration_time = fmod(offset_active_time, iteration_duration);
// This implements step 3 of
// https://drafts.csswg.org/web-animations/#calculating-the-simple-iteration-progress
if (iteration_time == 0 && phase == AnimationEffect::kPhaseAfter &&
active_duration != 0 && offset_active_time != 0)
return iteration_duration;
return iteration_time;
}
} // namespace blink } // namespace blink
#endif #endif
...@@ -104,7 +104,7 @@ TEST(AnimationTimingCalculationsTest, IterationTime) { ...@@ -104,7 +104,7 @@ TEST(AnimationTimingCalculationsTest, IterationTime) {
Timing timing; Timing timing;
// calculateIterationTime( // calculateIterationTime(
// iterationDuration, repeatedDuration, scaledActiveTime, startOffset, // iterationDuration, activeDuration, scaledActiveTime, startOffset,
// phase, timing) // phase, timing)
// if the scaled active time is null // if the scaled active time is null
...@@ -125,14 +125,14 @@ TEST(AnimationTimingCalculationsTest, IterationTime) { ...@@ -125,14 +125,14 @@ TEST(AnimationTimingCalculationsTest, IterationTime) {
EXPECT_EQ(8, CalculateIterationTime(12, 120, 20, 7, EXPECT_EQ(8, CalculateIterationTime(12, 120, 20, 7,
AnimationEffect::kPhaseActive, timing)); AnimationEffect::kPhaseActive, timing));
// Edge case for offset_active_time being within epsilon of (repeated_duration // Edge case for offset_active_time being within epsilon of (active_duration
// + start_offset). https://crbug.com/962138 // + start_offset). https://crbug.com/962138
timing.iteration_count = 1; timing.iteration_count = 1;
const double offset_active_time = 1.3435713716800004; const double offset_active_time = 1.3435713716800004;
const double iteration_duration = 1.3435713716800002; const double iteration_duration = 1.3435713716800002;
const double repeated_duration = 1.3435713716800002; const double active_duration = 1.3435713716800002;
EXPECT_NEAR(2.22045e-16, EXPECT_NEAR(2.22045e-16,
CalculateIterationTime(iteration_duration, repeated_duration, CalculateIterationTime(iteration_duration, active_duration,
offset_active_time, 0, offset_active_time, 0,
AnimationEffect::kPhaseActive, timing), AnimationEffect::kPhaseActive, timing),
std::numeric_limits<float>::epsilon()); std::numeric_limits<float>::epsilon());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment