IsCurrent: Only return before-phase animations when they have positive playback rate

See https://drafts.csswg.org/web-animations-1/#current

Bug: 1005848
Change-Id: I95981797ced813d6a7a0e57a1b719f3bb0bd736b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1814200
Reviewed-by: Kevin Ellis <kevers@chromium.org>
Reviewed-by: Majid Valipour <majidvp@chromium.org>
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#699744}
diff --git a/third_party/blink/renderer/core/animation/animatable.cc b/third_party/blink/renderer/core/animation/animatable.cc
index 6c772ba..88fc2ef 100644
--- a/third_party/blink/renderer/core/animation/animatable.cc
+++ b/third_party/blink/renderer/core/animation/animatable.cc
@@ -100,10 +100,12 @@
        element->GetDocument().Timeline().getAnimations()) {
     DCHECK(animation->effect());
     Element* target = ToKeyframeEffect(animation->effect())->target();
-
     if (element == target || (use_subtree && element->contains(target))) {
-      if (animation->effect()->IsCurrent() || animation->effect()->IsInEffect())
-        animations.push_back(animation);
+      // DocumentTimeline::getAnimations should only give us animations that are
+      // either current or in effect.
+      DCHECK(animation->effect()->IsCurrent() ||
+             animation->effect()->IsInEffect());
+      animations.push_back(animation);
     }
   }
   return animations;
diff --git a/third_party/blink/renderer/core/animation/animation_effect.cc b/third_party/blink/renderer/core/animation/animation_effect.cc
index 8d185980..1f75362 100644
--- a/third_party/blink/renderer/core/animation/animation_effect.cc
+++ b/third_party/blink/renderer/core/animation/animation_effect.cc
@@ -76,8 +76,11 @@
 
 void AnimationEffect::UpdateInheritedTime(double inherited_time,
                                           TimingUpdateReason reason) const {
+  base::Optional<double> playback_rate = base::nullopt;
+  if (GetAnimation())
+    playback_rate = GetAnimation()->playbackRate();
   const Timing::AnimationDirection direction =
-      (GetAnimation() && GetAnimation()->playbackRate() < 0)
+      (playback_rate && playback_rate.value() < 0)
           ? Timing::AnimationDirection::kBackwards
           : Timing::AnimationDirection::kForwards;
   bool needs_update =
@@ -91,7 +94,7 @@
   const double local_time = inherited_time;
   if (needs_update) {
     Timing::CalculatedTiming calculated = SpecifiedTiming().CalculateTimings(
-        local_time, direction, IsKeyframeEffect());
+        local_time, direction, IsKeyframeEffect(), playback_rate);
 
     const bool was_canceled = calculated.phase != calculated_.phase &&
                               calculated.phase == Timing::kPhaseNone;
diff --git a/third_party/blink/renderer/core/animation/timing.cc b/third_party/blink/renderer/core/animation/timing.cc
index c93c25f..63c25d4a 100644
--- a/third_party/blink/renderer/core/animation/timing.cc
+++ b/third_party/blink/renderer/core/animation/timing.cc
@@ -155,7 +155,8 @@
 Timing::CalculatedTiming Timing::CalculateTimings(
     double local_time,
     AnimationDirection animation_direction,
-    bool is_keyframe_effect) const {
+    bool is_keyframe_effect,
+    base::Optional<double> playback_rate) const {
   const double active_duration = ActiveDuration();
 
   const Timing::Phase current_phase =
@@ -219,8 +220,10 @@
   DCHECK(!calculated.is_in_effect ||
          (current_iteration.has_value() && progress.has_value()));
   calculated.is_in_play = calculated.phase == Timing::kPhaseActive;
-  calculated.is_current =
-      calculated.phase == Timing::kPhaseBefore || calculated.is_in_play;
+  // https://drafts.csswg.org/web-animations-1/#current
+  calculated.is_current = calculated.is_in_play ||
+                          (playback_rate.has_value() && playback_rate > 0 &&
+                           calculated.phase == Timing::kPhaseBefore);
   calculated.local_time = local_time;
   calculated.time_to_next_iteration = time_to_next_iteration;
 
diff --git a/third_party/blink/renderer/core/animation/timing.h b/third_party/blink/renderer/core/animation/timing.h
index 6b693eb..0dafc87 100644
--- a/third_party/blink/renderer/core/animation/timing.h
+++ b/third_party/blink/renderer/core/animation/timing.h
@@ -150,7 +150,8 @@
 
   CalculatedTiming CalculateTimings(double local_time,
                                     AnimationDirection animation_direction,
-                                    bool is_keyframe_effect) const;
+                                    bool is_keyframe_effect,
+                                    base::Optional<double> playback_rate) const;
   ComputedEffectTiming* getComputedTiming(const CalculatedTiming& calculated,
                                           bool is_keyframe_effect) const;
 };
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation_effect.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation_effect.cc
index fb79cdf..1eeba64 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation_effect.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation_effect.cc
@@ -31,8 +31,14 @@
   last_update_time_ = local_time;
 
   if (needs_update) {
+    // The playback rate is needed to calculate whether the effect is current or
+    // not (https://drafts.csswg.org/web-animations-1/#current). Since we only
+    // use this information to create a ComputedEffectTiming, which does not
+    // include that information, we do not need to supply one.
+    base::Optional<double> playback_rate = base::nullopt;
     calculated_ = specified_timing_.CalculateTimings(
-        local_time, Timing::AnimationDirection::kForwards, false);
+        local_time, Timing::AnimationDirection::kForwards, false,
+        playback_rate);
   }
 
   return specified_timing_.getComputedTiming(calculated_,
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/getAnimations-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/getAnimations-expected.txt
index 8450824..35c5a82 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/getAnimations-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/getAnimations-expected.txt
@@ -10,10 +10,10 @@
 PASS Does not return finished animations that do not fill forwards
 PASS Returns finished animations that fill forwards
 PASS Returns animations yet to reach their active phase
-FAIL Does not return reversed finished animations that do not fill backwards assert_array_equals: lengths differ, expected 0 got 1
+PASS Does not return reversed finished animations that do not fill backwards
 PASS Returns reversed finished animations that fill backwards
 FAIL Returns reversed animations yet to reach their active phase assert_array_equals: lengths differ, expected 1 got 0
-FAIL Does not return animations with zero playback rate in before phase assert_array_equals: lengths differ, expected 0 got 1
+PASS Does not return animations with zero playback rate in before phase
 PASS Does not return animations with zero playback rate in after phase
 PASS Returns animations based on dynamic changes to individual animations' duration
 PASS Returns animations based on dynamic changes to individual animations' end delay