summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/animation
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/animation')
-rw-r--r--chromium/third_party/blink/renderer/core/animation/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/animation/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animatable.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation.cc391
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation.h89
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_effect.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_effect.h12
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_test.cc723
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_time_delta.h6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_timeline.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_timeline.h3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/build.gni2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations.h1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animation.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animation.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animations.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc136
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.cc164
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h53
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map_test.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_animations.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_animations.h21
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_animations_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_timeline.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_timeline.h16
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/animation/element_animations.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/animation/element_animations.h1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/inert_effect.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/inert_effect.h4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.cc65
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h62
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolable_length.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolable_value.h1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/animation/length_property_functions.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/pending_animations.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/animation/pending_animations.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline.h10
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc79
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/animation/string_keyframe.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/timing.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/timing_calculations.h6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/timing_input_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/transition_keyframe.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h6
88 files changed, 2016 insertions, 734 deletions
diff --git a/chromium/third_party/blink/renderer/core/animation/BUILD.gn b/chromium/third_party/blink/renderer/core/animation/BUILD.gn
index a690dc32877..efc1cfc7c81 100644
--- a/chromium/third_party/blink/renderer/core/animation/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/animation/BUILD.gn
@@ -72,6 +72,8 @@ blink_core_sources("animation") {
"css/css_transition_data.h",
"css_angle_interpolation_type.cc",
"css_angle_interpolation_type.h",
+ "css_aspect_ratio_interpolation_type.cc",
+ "css_aspect_ratio_interpolation_type.h",
"css_basic_shape_interpolation_type.cc",
"css_basic_shape_interpolation_type.h",
"css_border_image_length_box_interpolation_type.cc",
@@ -168,6 +170,8 @@ blink_core_sources("animation") {
"image_slice_property_functions.h",
"inert_effect.cc",
"inert_effect.h",
+ "interpolable_aspect_ratio.cc",
+ "interpolable_aspect_ratio.h",
"interpolable_filter.cc",
"interpolable_filter.h",
"interpolable_length.cc",
diff --git a/chromium/third_party/blink/renderer/core/animation/DIR_METADATA b/chromium/third_party/blink/renderer/core/animation/DIR_METADATA
new file mode 100644
index 00000000000..072e8c98258
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Animation"
+}
+
+team_email: "animations-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/animation/OWNERS b/chromium/third_party/blink/renderer/core/animation/OWNERS
index ef3593179c5..e7571208635 100644
--- a/chromium/third_party/blink/renderer/core/animation/OWNERS
+++ b/chromium/third_party/blink/renderer/core/animation/OWNERS
@@ -8,6 +8,3 @@ alancutter@chromium.org
ericwilligers@chromium.org
per-file compositor_*=loyso@chromium.org
-
-# TEAM: animations-dev@chromium.org
-# COMPONENT: Blink>Animation
diff --git a/chromium/third_party/blink/renderer/core/animation/animatable.cc b/chromium/third_party/blink/renderer/core/animation/animatable.cc
index 01fee49eac1..bb64f4e2334 100644
--- a/chromium/third_party/blink/renderer/core/animation/animatable.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animatable.cc
@@ -73,6 +73,11 @@ Animation* Animatable::animate(
if (exception_state.HadException())
return nullptr;
+ // Creation of the keyframe effect parses JavaScript, which could result
+ // in destruction of the execution context. Recheck that it is still valid.
+ if (!element->GetExecutionContext())
+ return nullptr;
+
ReportFeaturePolicyViolationsIfNecessary(*element->GetExecutionContext(),
*effect->Model());
if (!options.IsKeyframeAnimationOptions())
@@ -90,6 +95,9 @@ Animation* Animatable::animate(
nullptr, exception_state);
}
+ if (!animation)
+ return nullptr;
+
animation->setId(options_dict->id());
return animation;
}
@@ -107,6 +115,11 @@ Animation* Animatable::animate(ScriptState* script_state,
if (exception_state.HadException())
return nullptr;
+ // Creation of the keyframe effect parses JavaScript, which could result
+ // in destruction of the execution context. Recheck that it is still valid.
+ if (!element->GetExecutionContext())
+ return nullptr;
+
ReportFeaturePolicyViolationsIfNecessary(*element->GetExecutionContext(),
*effect->Model());
return element->GetDocument().Timeline().Play(effect);
diff --git a/chromium/third_party/blink/renderer/core/animation/animation.cc b/chromium/third_party/blink/renderer/core/animation/animation.cc
index 3cd250acb32..5bededa4316 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation.cc
@@ -53,6 +53,8 @@
#include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_document_state.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/events/animation_playback_event.h"
@@ -83,26 +85,6 @@ unsigned NextSequenceNumber() {
return ++next;
}
-double SecondsToMilliseconds(double seconds) {
- return seconds * 1000;
-}
-
-double MillisecondsToSeconds(double milliseconds) {
- return milliseconds / 1000;
-}
-
-double Max(base::Optional<double> a, double b) {
- if (a.has_value())
- return std::max(a.value(), b);
- return b;
-}
-
-double Min(base::Optional<double> a, double b) {
- if (a.has_value())
- return std::min(a.value(), b);
- return b;
-}
-
PseudoPriority ConvertPseudoIdtoPriority(const PseudoId& pseudo) {
if (pseudo == kPseudoIdNone)
return PseudoPriority::kNone;
@@ -180,6 +162,16 @@ AtomicString GetCSSTransitionCSSPropertyName(const Animation* animation) {
->TransitionCSSPropertyName()
.ToAtomicString();
}
+
+bool GreaterThanOrEqualWithinTimeTolerance(const AnimationTimeDelta& a,
+ const AnimationTimeDelta& b) {
+ double a_ms = a.InMillisecondsF();
+ double b_ms = b.InMillisecondsF();
+ if (std::abs(a_ms - b_ms) < Animation::kTimeToleranceMs)
+ return true;
+
+ return a_ms > b_ms;
+}
} // namespace
Animation* Animation::Create(AnimationEffect* effect,
@@ -294,13 +286,21 @@ void Animation::Dispose() {
DCHECK(!compositor_animation_);
}
-double Animation::EffectEnd() const {
- return content_ ? content_->SpecifiedTiming().EndTimeInternal() : 0;
+AnimationTimeDelta Animation::EffectEnd() const {
+ return content_ ? AnimationTimeDelta::FromSecondsD(
+ content_->SpecifiedTiming().EndTimeInternal())
+ : AnimationTimeDelta();
}
-bool Animation::Limited(base::Optional<double> current_time) const {
- return (EffectivePlaybackRate() < 0 && current_time <= 0) ||
- (EffectivePlaybackRate() > 0 && current_time >= EffectEnd());
+bool Animation::Limited(base::Optional<AnimationTimeDelta> current_time) const {
+ if (!current_time)
+ return false;
+
+ return (EffectivePlaybackRate() < 0 &&
+ current_time <= AnimationTimeDelta()) ||
+ (EffectivePlaybackRate() > 0 &&
+ GreaterThanOrEqualWithinTimeTolerance(current_time.value(),
+ EffectEnd()));
}
Document* Animation::GetDocument() const {
@@ -312,9 +312,9 @@ base::Optional<double> Animation::TimelineTime() const {
}
// https://drafts.csswg.org/web-animations/#setting-the-current-time-of-an-animation.
-void Animation::setCurrentTime(base::Optional<double> new_current_time,
+void Animation::setCurrentTime(CSSNumberish current_time,
ExceptionState& exception_state) {
- if (!new_current_time) {
+ if (current_time.IsNull()) {
// If the current time is resolved, then throw a TypeError.
if (CurrentTimeInternal()) {
exception_state.ThrowTypeError(
@@ -323,12 +323,25 @@ void Animation::setCurrentTime(base::Optional<double> new_current_time,
return;
}
- SetCurrentTimeInternal(MillisecondsToSeconds(new_current_time.value()));
+ if (current_time.IsCSSNumericValue()) {
+ // Throw exception for CSSNumberish that is a CSSNumericValue
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "Invalid startTime. CSSNumericValue not yet supported.");
+ return;
+ }
+
+ DCHECK(current_time.IsDouble());
+ // Convert from double to AnimationTimeDelta for internal use.
+ base::Optional<AnimationTimeDelta> new_current_time =
+ AnimationTimeDelta::FromMillisecondsD(current_time.GetAsDouble());
+
+ DCHECK(new_current_time);
+ SetCurrentTimeInternal(new_current_time.value());
// Synchronously resolve pending pause task.
if (pending_pause_) {
- SetHoldTimeAndPhase(MillisecondsToSeconds(new_current_time.value()),
- TimelinePhase::kActive);
+ SetHoldTimeAndPhase(new_current_time, TimelinePhase::kActive);
ApplyPendingPlaybackRate();
start_time_ = base::nullopt;
pending_pause_ = false;
@@ -345,19 +358,17 @@ void Animation::setCurrentTime(base::Optional<double> new_current_time,
NotifyProbe();
}
-void Animation::setCurrentTime(base::Optional<double> new_current_time) {
+void Animation::setCurrentTime(CSSNumberish current_time) {
NonThrowableExceptionState exception_state;
- setCurrentTime(new_current_time, exception_state);
+ setCurrentTime(current_time, exception_state);
}
// https://drafts.csswg.org/web-animations/#setting-the-current-time-of-an-animation
// See steps for silently setting the current time. The preliminary step of
// handling an unresolved time are to be handled by the caller.
-void Animation::SetCurrentTimeInternal(double new_current_time) {
- DCHECK(std::isfinite(new_current_time));
-
- base::Optional<double> previous_start_time = start_time_;
- base::Optional<double> previous_hold_time = hold_time_;
+void Animation::SetCurrentTimeInternal(AnimationTimeDelta new_current_time) {
+ base::Optional<AnimationTimeDelta> previous_start_time = start_time_;
+ base::Optional<AnimationTimeDelta> previous_hold_time = hold_time_;
base::Optional<TimelinePhase> previous_hold_phase = hold_phase_;
// Update either the hold time or the start time.
@@ -383,11 +394,8 @@ void Animation::SetCurrentTimeInternal(double new_current_time) {
}
void Animation::SetHoldTimeAndPhase(
- base::Optional<double> new_hold_time /* in seconds */,
+ base::Optional<AnimationTimeDelta> new_hold_time,
TimelinePhase new_hold_phase) {
- // new_hold_time must be valid, unless new_hold_phase is inactive.
- DCHECK(new_hold_time ||
- (!new_hold_time && new_hold_phase == TimelinePhase::kInactive));
hold_time_ = new_hold_time;
hold_phase_ = new_hold_phase;
}
@@ -397,18 +405,22 @@ void Animation::ResetHoldTimeAndPhase() {
hold_phase_ = base::nullopt;
}
-base::Optional<double> Animation::startTime() const {
- return start_time_
- ? base::make_optional(SecondsToMilliseconds(start_time_.value()))
- : base::nullopt;
+void Animation::startTime(CSSNumberish& startTime) const {
+ startTime =
+ start_time_
+ ? CSSNumberish::FromDouble(start_time_.value().InMillisecondsF())
+ : CSSNumberish();
}
// https://drafts.csswg.org/web-animations/#the-current-time-of-an-animation
-base::Optional<double> Animation::currentTime() const {
+void Animation::currentTime(CSSNumberish& currentTime) const {
// 1. If the animation’s hold time is resolved,
// The current time is the animation’s hold time.
- if (hold_time_.has_value())
- return SecondsToMilliseconds(hold_time_.value());
+ if (hold_time_.has_value()) {
+ currentTime =
+ CSSNumberish::FromDouble(hold_time_.value().InMillisecondsF());
+ return;
+ }
// 2. If any of the following are true:
// * the animation has no associated timeline, or
@@ -416,28 +428,30 @@ base::Optional<double> Animation::currentTime() const {
// * the animation’s start time is unresolved.
// The current time is an unresolved time value.
if (!timeline_ || !timeline_->IsActive() || !start_time_)
- return base::nullopt;
+ return;
// 3. Otherwise,
// current time = (timeline time - start time) × playback rate
- base::Optional<double> timeline_time = timeline_->CurrentTimeSeconds();
+ base::Optional<AnimationTimeDelta> timeline_time = timeline_->CurrentTime();
// An active timeline should always have a value, and since inactive timeline
// is handled in step 2 above, make sure that timeline_time has a value.
DCHECK(timeline_time.has_value());
- double current_time =
+ AnimationTimeDelta calculated_current_time =
(timeline_time.value() - start_time_.value()) * playback_rate_;
- return SecondsToMilliseconds(current_time);
+
+ currentTime =
+ CSSNumberish::FromDouble(calculated_current_time.InMillisecondsF());
}
bool Animation::ValidateHoldTimeAndPhase() const {
- return (hold_phase_ && hold_time_) ||
+ return hold_phase_ ||
((!hold_phase_ || hold_phase_ == TimelinePhase::kInactive) &&
!hold_time_);
}
-base::Optional<double> Animation::CurrentTimeInternal() const {
+base::Optional<AnimationTimeDelta> Animation::CurrentTimeInternal() const {
DCHECK(ValidateHoldTimeAndPhase());
return hold_time_ ? hold_time_ : CalculateCurrentTime();
}
@@ -447,7 +461,7 @@ TimelinePhase Animation::CurrentPhaseInternal() const {
return hold_phase_ ? hold_phase_.value() : CalculateCurrentPhase();
}
-base::Optional<double> Animation::UnlimitedCurrentTime() const {
+base::Optional<AnimationTimeDelta> Animation::UnlimitedCurrentTime() const {
return CalculateAnimationPlayState() == kPaused || !start_time_
? CurrentTimeInternal()
: CalculateCurrentTime();
@@ -466,9 +480,11 @@ bool Animation::PreCommit(
compositor_state_ &&
(Paused() || compositor_state_->playback_rate != EffectivePlaybackRate());
bool hard_change =
- compositor_state_ && (compositor_state_->effect_changed ||
- compositor_state_->start_time != start_time_ ||
- !compositor_state_->start_time || !start_time_);
+ compositor_state_ &&
+ (compositor_state_->effect_changed || !compositor_state_->start_time ||
+ !start_time_ ||
+ !IsWithinAnimationTimeEpsilon(compositor_state_->start_time.value(),
+ start_time_.value().InSecondsF()));
// FIXME: softChange && !hardChange should generate a Pause/ThenStart,
// not a Cancel, but we can't communicate these to the compositor yet.
@@ -526,7 +542,8 @@ void Animation::PostCommit() {
DCHECK_EQ(kStart, compositor_state_->pending_action);
if (compositor_state_->start_time) {
- DCHECK_EQ(start_time_.value(), compositor_state_->start_time.value());
+ DCHECK(IsWithinAnimationTimeEpsilon(start_time_.value().InSecondsF(),
+ compositor_state_->start_time.value()));
compositor_state_->pending_action = kNone;
}
}
@@ -621,7 +638,7 @@ bool Animation::HasLowerCompositeOrdering(
return animation1->SequenceNumber() < animation2->SequenceNumber();
}
-void Animation::NotifyReady(double ready_time) {
+void Animation::NotifyReady(AnimationTimeDelta ready_time) {
// Complete the pending updates prior to updating the compositor state in
// order to ensure a correct start time for the compositor state without the
// need to duplicate the calculations.
@@ -633,7 +650,9 @@ void Animation::NotifyReady(double ready_time) {
if (compositor_state_ && compositor_state_->pending_action == kStart) {
DCHECK(!compositor_state_->start_time);
compositor_state_->pending_action = kNone;
- compositor_state_->start_time = start_time_;
+ compositor_state_->start_time =
+ start_time_ ? base::make_optional(start_time_.value().InSecondsF())
+ : base::nullopt;
}
// Notify of change to play state.
@@ -643,8 +662,7 @@ void Animation::NotifyReady(double ready_time) {
// Microtask for playing an animation.
// Refer to Step 8.3 'pending play task' in
// https://drafts.csswg.org/web-animations/#playing-an-animation-section.
-void Animation::CommitPendingPlay(double ready_time) {
- DCHECK(std::isfinite(ready_time));
+void Animation::CommitPendingPlay(AnimationTimeDelta ready_time) {
DCHECK(start_time_ || hold_time_);
DCHECK(pending_play_);
pending_play_ = false;
@@ -680,7 +698,7 @@ void Animation::CommitPendingPlay(double ready_time) {
// If the playback rate is zero, let new start time be simply ready
// time.
// B.5 Set the start time of animation to new start time.
- double current_time_to_match =
+ AnimationTimeDelta current_time_to_match =
(ready_time - start_time_.value()) * playback_rate_;
ApplyPendingPlaybackRate();
if (playback_rate_ == 0) {
@@ -705,7 +723,7 @@ void Animation::CommitPendingPlay(double ready_time) {
// Microtask for pausing an animation.
// Refer to step 7 'pending pause task' in
// https://drafts.csswg.org/web-animations-1/#pausing-an-animation-section
-void Animation::CommitPendingPause(double ready_time) {
+void Animation::CommitPendingPause(AnimationTimeDelta ready_time) {
DCHECK(pending_pause_);
pending_pause_ = false;
@@ -769,7 +787,7 @@ void Animation::setTimeline(AnimationTimeline* timeline) {
UpdateIfNecessary();
AnimationPlayState old_play_state = CalculateAnimationPlayState();
- base::Optional<double> old_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> old_current_time = CurrentTimeInternal();
CancelAnimationOnCompositor();
@@ -795,7 +813,8 @@ void Animation::setTimeline(AnimationTimeline* timeline) {
if (timeline) {
if (!timeline->IsMonotonicallyIncreasing()) {
ApplyPendingPlaybackRate();
- double boundary_time = (playback_rate_ > 0) ? 0 : EffectEnd();
+ AnimationTimeDelta boundary_time =
+ (playback_rate_ > 0) ? AnimationTimeDelta() : EffectEnd();
switch (old_play_state) {
case kIdle:
break;
@@ -851,11 +870,11 @@ void Animation::setTimeline(AnimationTimeline* timeline) {
NotifyProbe();
}
-base::Optional<double> Animation::CalculateStartTime(
- double current_time) const {
- base::Optional<double> start_time;
+base::Optional<AnimationTimeDelta> Animation::CalculateStartTime(
+ AnimationTimeDelta current_time) const {
+ base::Optional<AnimationTimeDelta> start_time;
if (timeline_) {
- base::Optional<double> timeline_time = timeline_->CurrentTimeSeconds();
+ base::Optional<AnimationTimeDelta> timeline_time = timeline_->CurrentTime();
if (timeline_time)
start_time = timeline_time.value() - current_time / playback_rate_;
// TODO(crbug.com/916117): Handle NaN time for scroll-linked animations.
@@ -864,16 +883,13 @@ base::Optional<double> Animation::CalculateStartTime(
return start_time;
}
-base::Optional<double> Animation::CalculateCurrentTime() const {
+base::Optional<AnimationTimeDelta> Animation::CalculateCurrentTime() const {
if (!start_time_ || !timeline_ || !timeline_->IsActive())
return base::nullopt;
- base::Optional<double> timeline_time = timeline_->CurrentTimeSeconds();
- if (!timeline_time) {
- // timeline_time can be null only when the timeline is inactive
- DCHECK(!timeline_->IsActive());
- return base::nullopt;
- }
+ base::Optional<AnimationTimeDelta> timeline_time = timeline_->CurrentTime();
+ // timeline_ must be active here, make sure it is returning a current_time.
+ DCHECK(timeline_time);
return (timeline_time.value() - start_time_.value()) * playback_rate_;
}
@@ -885,42 +901,56 @@ TimelinePhase Animation::CalculateCurrentPhase() const {
}
// https://drafts.csswg.org/web-animations/#setting-the-start-time-of-an-animation
-void Animation::setStartTime(base::Optional<double> start_time_ms,
+void Animation::setStartTime(CSSNumberish start_time,
ExceptionState& exception_state) {
+ if (!start_time.IsNull() && start_time.IsCSSNumericValue()) {
+ // Throw exception for CSSNumberish that is a CSSNumericValue
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "Invalid startTime. CSSNumericValue not yet supported.");
+ return;
+ }
+
+ base::Optional<AnimationTimeDelta> new_start_time =
+ !start_time.IsNull()
+ ? base::make_optional(
+ AnimationTimeDelta::FromMillisecondsD(start_time.GetAsDouble()))
+ : base::nullopt;
+
bool had_start_time = start_time_.has_value();
// 1. Let timeline time be the current time value of the timeline that
// animation is associated with. If there is no timeline associated with
// animation or the associated timeline is inactive, let the timeline time
// be unresolved.
- base::Optional<double> timeline_time = timeline_ && timeline_->IsActive()
- ? timeline_->CurrentTimeSeconds()
- : base::nullopt;
+ base::Optional<AnimationTimeDelta> timeline_time =
+ timeline_ && timeline_->IsActive() ? timeline_->CurrentTime()
+ : base::nullopt;
// 2. If timeline time is unresolved and new start time is resolved, make
// animation’s hold time unresolved.
// This preserves the invariant that when we don’t have an active timeline it
// is only possible to set either the start time or the animation’s current
// time.
- if (!timeline_time && start_time_ms) {
+ if (!timeline_time && new_start_time) {
ResetHoldTimeAndPhase();
}
// 3. Let previous current time be animation’s current time.
- base::Optional<double> previous_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> previous_current_time =
+ CurrentTimeInternal();
TimelinePhase previous_current_phase = CurrentPhaseInternal();
// 4. Apply any pending playback rate on animation.
ApplyPendingPlaybackRate();
// 5. Set animation’s start time to new start time.
- base::Optional<double> new_start_time;
- if (start_time_ms) {
- new_start_time = MillisecondsToSeconds(start_time_ms.value());
+ if (new_start_time) {
// Snap to timeline time if within floating point tolerance to ensure
// deterministic behavior in phase transitions.
- if (timeline_time && IsWithinAnimationTimeEpsilon(timeline_time.value(),
- new_start_time.value())) {
+ if (timeline_time &&
+ IsWithinAnimationTimeEpsilon(timeline_time.value().InSecondsF(),
+ new_start_time.value().InSecondsF())) {
new_start_time = timeline_time.value();
}
}
@@ -959,7 +989,7 @@ void Animation::setStartTime(base::Optional<double> start_time_ms,
UpdateFinishedState(UpdateType::kDiscontinuous, NotificationType::kAsync);
// Update user agent.
- base::Optional<double> new_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> new_current_time = CurrentTimeInternal();
// Even when the animation is not outdated,call SetOutdated to ensure
// the animation is tracked by its timeline for future timing
// updates.
@@ -972,9 +1002,9 @@ void Animation::setStartTime(base::Optional<double> start_time_ms,
NotifyProbe();
}
-void Animation::setStartTime(base::Optional<double> start_time_ms) {
+void Animation::setStartTime(CSSNumberish start_time) {
NonThrowableExceptionState exception_state;
- setStartTime(start_time_ms, exception_state);
+ setStartTime(start_time, exception_state);
}
// https://drafts.csswg.org/web-animations-1/#setting-the-associated-effect
@@ -1049,11 +1079,11 @@ void Animation::setEffect(AnimationEffect* new_effect) {
// The timing phase is ‘before’.
// Otherwise,
// The timing phase is ‘after’.
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
Timing::Phase phase;
if (!current_time)
phase = Timing::kPhaseNone;
- else if (current_time < 0)
+ else if (current_time < AnimationTimeDelta())
phase = Timing::kPhaseBefore;
else
phase = Timing::kPhaseAfter;
@@ -1177,7 +1207,7 @@ void Animation::pause(ExceptionState& exception_state) {
return;
// 3. Let seek time be a time value that is initially unresolved.
- base::Optional<double> seek_time;
+ base::Optional<AnimationTimeDelta> seek_time;
// 4. Let has finite timeline be true if animation has an associated timeline
// that is not monotonically increasing.
@@ -1194,12 +1224,11 @@ void Animation::pause(ExceptionState& exception_state) {
// steps.
// Otherwise,
// Set seek time to animation's associated effect end.
- base::Optional<double> current_time = CurrentTimeInternal();
- if (!current_time) {
+ if (!CurrentTimeInternal()) {
if (playback_rate_ >= 0) {
- seek_time = 0;
+ seek_time = AnimationTimeDelta();
} else {
- if (EffectEnd() == std::numeric_limits<double>::infinity()) {
+ if (EffectEnd().is_inf()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Cannot play reversed Animation with infinite target effect end.");
@@ -1283,7 +1312,7 @@ void Animation::PlayInternal(AutoRewind auto_rewind,
bool enable_seek =
auto_rewind == AutoRewind::kEnabled || reset_current_time_on_resume_;
bool has_pending_ready_promise = false;
- base::Optional<double> seek_time;
+ base::Optional<AnimationTimeDelta> seek_time;
bool has_finite_timeline =
timeline_ && !timeline_->IsMonotonicallyIncreasing();
@@ -1311,21 +1340,23 @@ void Animation::PlayInternal(AutoRewind auto_rewind,
// is unresolved,
// 5c1. Set seek time to zero.
double effective_playback_rate = EffectivePlaybackRate();
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
if (reset_current_time_on_resume_) {
current_time = base::nullopt;
reset_current_time_on_resume_ = false;
}
+ base::Optional<AnimationTimeDelta> effect_end = EffectEnd();
if (effective_playback_rate > 0 && enable_seek &&
- (!current_time || current_time < 0 || current_time >= EffectEnd())) {
- seek_time = 0;
+ (!current_time || current_time < AnimationTimeDelta() ||
+ current_time >= effect_end)) {
+ seek_time = AnimationTimeDelta();
} else if (effective_playback_rate < 0 && enable_seek &&
- (!current_time || current_time <= 0 ||
+ (!current_time || current_time <= AnimationTimeDelta() ||
current_time > EffectEnd())) {
- if (EffectEnd() == std::numeric_limits<double>::infinity()) {
+ if (EffectEnd().is_inf()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Cannot play reversed Animation with infinite target effect end.");
@@ -1333,7 +1364,7 @@ void Animation::PlayInternal(AutoRewind auto_rewind,
}
seek_time = EffectEnd();
} else if (effective_playback_rate == 0 && !current_time) {
- seek_time = 0;
+ seek_time = AnimationTimeDelta();
}
// 6. If seek time is resolved,
@@ -1441,8 +1472,7 @@ void Animation::finish(ExceptionState& exception_state) {
"Cannot finish Animation with a playbackRate of 0.");
return;
}
- if (EffectivePlaybackRate() > 0 &&
- EffectEnd() == std::numeric_limits<double>::infinity()) {
+ if (EffectivePlaybackRate() > 0 && EffectEnd().is_inf()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Cannot finish Animation with an infinite target effect end.");
@@ -1451,7 +1481,8 @@ void Animation::finish(ExceptionState& exception_state) {
ApplyPendingPlaybackRate();
- double new_current_time = playback_rate_ < 0 ? 0 : EffectEnd();
+ AnimationTimeDelta new_current_time =
+ playback_rate_ < 0 ? AnimationTimeDelta() : EffectEnd();
SetCurrentTimeInternal(new_current_time);
if (!start_time_ && timeline_ && timeline_->IsActive())
@@ -1483,7 +1514,7 @@ void Animation::UpdateFinishedState(UpdateType update_type,
// required to accommodate timelines that may change direction. Without this
// distinction, a once-finished animation would remain finished even when its
// timeline progresses in the opposite direction.
- base::Optional<double> unconstrained_current_time =
+ base::Optional<AnimationTimeDelta> unconstrained_current_time =
did_seek ? CurrentTimeInternal() : CalculateCurrentTime();
// 2. Conditionally update the hold time.
@@ -1497,22 +1528,42 @@ void Animation::UpdateFinishedState(UpdateType update_type,
// boundary. The value of previous current time is used to retain this
// value.
double playback_rate = EffectivePlaybackRate();
- base::Optional<double> hold_time;
+ base::Optional<AnimationTimeDelta> hold_time;
TimelinePhase hold_phase;
- if (playback_rate > 0 && unconstrained_current_time >= EffectEnd()) {
- hold_time = did_seek ? unconstrained_current_time
- : Max(previous_current_time_, EffectEnd());
+
+ if (playback_rate > 0 &&
+ GreaterThanOrEqualWithinTimeTolerance(
+ unconstrained_current_time.value(), EffectEnd())) {
+ if (did_seek) {
+ hold_time = unconstrained_current_time;
+ } else {
+ if (previous_current_time_ > EffectEnd()) {
+ hold_time = previous_current_time_;
+ } else {
+ hold_time = EffectEnd();
+ }
+ }
hold_phase = did_seek ? TimelinePhase::kActive : CalculateCurrentPhase();
SetHoldTimeAndPhase(hold_time, hold_phase);
- } else if (playback_rate < 0 && unconstrained_current_time <= 0) {
- hold_time = did_seek ? unconstrained_current_time
- : Min(previous_current_time_, 0);
+ } else if (playback_rate < 0 &&
+ unconstrained_current_time.value() <= AnimationTimeDelta()) {
+ if (did_seek) {
+ hold_time = unconstrained_current_time;
+ } else {
+ if (previous_current_time_ <= AnimationTimeDelta()) {
+ hold_time = previous_current_time_;
+ } else {
+ hold_time = AnimationTimeDelta();
+ }
+ }
hold_phase = did_seek ? TimelinePhase::kActive : CalculateCurrentPhase();
// Hack for resolving precision issue at zero.
- if (hold_time.value() == -0)
- hold_time = 0;
+ if (hold_time.has_value() &&
+ IsWithinAnimationTimeEpsilon(hold_time.value().InSecondsF(), -0)) {
+ hold_time = AnimationTimeDelta();
+ }
SetHoldTimeAndPhase(hold_time, hold_phase);
} else if (playback_rate != 0) {
@@ -1573,7 +1624,7 @@ void Animation::AsyncFinishMicrotask() {
if (pending_finish_notification_) {
// A pending play or pause must resolve before the finish promise.
if (PendingInternal() && timeline_)
- NotifyReady(timeline_->CurrentTimeSeconds().value_or(0));
+ NotifyReady(timeline_->CurrentTime().value_or(AnimationTimeDelta()));
CommitFinishNotification();
}
@@ -1645,14 +1696,14 @@ void Animation::updatePlaybackRate(double playback_rate,
// animation with the did seek flag set to false, and the
// synchronously notify flag set to false.
case kFinished: {
- base::Optional<double> unconstrained_current_time =
+ base::Optional<AnimationTimeDelta> unconstrained_current_time =
CalculateCurrentTime();
- base::Optional<double> timeline_time =
- timeline_ ? timeline_->CurrentTimeSeconds() : base::nullopt;
+ base::Optional<AnimationTimeDelta> timeline_time =
+ timeline_ ? timeline_->CurrentTime() : base::nullopt;
if (playback_rate) {
if (timeline_time) {
start_time_ = (timeline_time && unconstrained_current_time)
- ? base::make_optional<double>(
+ ? base::make_optional<AnimationTimeDelta>(
(timeline_time.value() -
unconstrained_current_time.value()) /
playback_rate)
@@ -1768,7 +1819,7 @@ void Animation::ApplyPendingPlaybackRate() {
void Animation::setPlaybackRate(double playback_rate,
ExceptionState& exception_state) {
- base::Optional<double> start_time_before = start_time_;
+ base::Optional<AnimationTimeDelta> start_time_before = start_time_;
// 1. Clear any pending playback rate on animation.
// 2. Let previous time be the value of the current time of animation before
@@ -1777,9 +1828,10 @@ void Animation::setPlaybackRate(double playback_rate,
// 4. If previous time is resolved, set the current time of animation to
// previous time
pending_playback_rate_ = base::nullopt;
- base::Optional<double> previous_current_time = currentTime();
+ CSSNumberish previous_current_time;
+ currentTime(previous_current_time);
playback_rate_ = playback_rate;
- if (previous_current_time.has_value()) {
+ if (!previous_current_time.IsNull()) {
setCurrentTime(previous_current_time, exception_state);
}
@@ -1855,7 +1907,7 @@ Animation::CheckCanStartAnimationOnCompositorInternal() const {
// enable compositing provided the iteration duration is finite. Having an
// infinite number of iterations in the animation should not impede the
// ability to composite the animation.
- if (std::isinf(EffectEnd()) && EffectivePlaybackRate() < 0)
+ if (EffectEnd().is_inf() && EffectivePlaybackRate() < 0)
reasons |= CompositorAnimations::kInvalidAnimationOrEffect;
// An Animation without a timeline effectively isn't playing, so there is no
@@ -1893,10 +1945,13 @@ void Animation::StartAnimationOnCompositor(
CheckCanStartAnimationOnCompositor(paint_artifact_compositor, nullptr),
CompositorAnimations::kNoFailure);
+ // If PlaybackRate is 0, then we will run into divide by 0 issues.
+ DCHECK(!IsWithinAnimationTimeEpsilon(0, EffectivePlaybackRate()));
+
bool reversed = EffectivePlaybackRate() < 0;
- base::Optional<double> start_time = base::nullopt;
- double time_offset = 0;
+ base::Optional<AnimationTimeDelta> start_time;
+ AnimationTimeDelta time_offset = AnimationTimeDelta();
// Start the animation on the compositor with either a start time or time
// offset. The start time is used for synchronous updates where the
// compositor start time must be in precise alignment with the specified time
@@ -1905,27 +1960,30 @@ void Animation::StartAnimationOnCompositor(
// Asynchronous updates have an associated pending play or pending pause
// task associated with them.
if (start_time_ && !PendingInternal()) {
- start_time = timeline_->ZeroTimeInSeconds() + start_time_.value();
+ start_time = timeline_->ZeroTime() + start_time_.value();
if (reversed) {
start_time =
start_time.value() - (EffectEnd() / fabs(EffectivePlaybackRate()));
}
- DCHECK(std::isfinite(start_time.value()));
} else {
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
DCHECK(current_time);
time_offset =
reversed ? EffectEnd() - current_time.value() : current_time.value();
time_offset = time_offset / fabs(EffectivePlaybackRate());
- DCHECK(std::isfinite(time_offset));
}
DCHECK_NE(compositor_group_, 0);
DCHECK(To<KeyframeEffect>(content_.Get()));
+ base::Optional<double> start_time_s;
+ if (start_time) {
+ start_time_s = start_time.value().InSecondsF();
+ }
To<KeyframeEffect>(content_.Get())
- ->StartAnimationOnCompositor(compositor_group_, start_time,
- base::TimeDelta::FromSecondsD(time_offset),
- EffectivePlaybackRate());
+ ->StartAnimationOnCompositor(
+ compositor_group_, start_time_s,
+ base::TimeDelta::FromSecondsD(time_offset.InSecondsF()),
+ EffectivePlaybackRate());
}
// TODO(crbug.com/960944): Rename to SetPendingCommit. This method handles both
@@ -1952,7 +2010,10 @@ void Animation::SetCompositorPending(bool effect_changed) {
if (PendingInternal() || !compositor_state_ ||
compositor_state_->effect_changed ||
compositor_state_->playback_rate != EffectivePlaybackRate() ||
- compositor_state_->start_time != start_time_ ||
+ compositor_state_->start_time.has_value() != start_time_.has_value() ||
+ (compositor_state_->start_time && start_time_ &&
+ !IsWithinAnimationTimeEpsilon(compositor_state_->start_time.value(),
+ start_time_.value().InSecondsF())) ||
!compositor_state_->start_time || !start_time_) {
compositor_pending_ = true;
document_->GetPendingAnimations().Add(this);
@@ -2002,14 +2063,14 @@ bool Animation::Update(TimingUpdateReason reason) {
UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync);
if (content_) {
- base::Optional<double> inherited_time;
+ base::Optional<AnimationTimeDelta> inherited_time;
TimelinePhase inherited_phase = TimelinePhase::kInactive;
if (!idle) {
inherited_time = CurrentTimeInternal();
// Special case for end-exclusivity when playing backwards.
- if (inherited_time == 0 && EffectivePlaybackRate() < 0)
- inherited_time = -1;
+ if (inherited_time == AnimationTimeDelta() && EffectivePlaybackRate() < 0)
+ inherited_time = AnimationTimeDelta::FromSecondsD(-1);
inherited_phase = CurrentPhaseInternal();
}
@@ -2049,12 +2110,14 @@ bool Animation::Update(TimingUpdateReason reason) {
void Animation::QueueFinishedEvent() {
const AtomicString& event_type = event_type_names::kFinish;
if (GetExecutionContext() && HasEventListeners(event_type)) {
- base::Optional<double> event_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> event_current_time =
+ CurrentTimeInternal();
+ base::Optional<double> event_current_time_ms;
if (event_current_time)
- event_current_time = SecondsToMilliseconds(event_current_time.value());
+ event_current_time_ms = event_current_time.value().InMillisecondsF();
// TODO(crbug.com/916117): Handle NaN values for scroll-linked animations.
pending_finished_event_ = MakeGarbageCollected<AnimationPlaybackEvent>(
- event_type, event_current_time, TimelineTime());
+ event_type, event_current_time_ms, TimelineTime());
pending_finished_event_->SetTarget(this);
pending_finished_event_->SetCurrentTarget(this);
document_->EnqueueAnimationFrameEvent(pending_finished_event_);
@@ -2084,10 +2147,9 @@ base::Optional<AnimationTimeDelta> Animation::TimeToEffectChange() {
return base::nullopt;
if (!content_) {
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
DCHECK(current_time);
- return AnimationTimeDelta::FromSecondsD(-current_time.value() /
- playback_rate_);
+ return -current_time.value() / playback_rate_;
}
if (!HasActiveAnimationsOnCompositor() &&
@@ -2100,7 +2162,8 @@ base::Optional<AnimationTimeDelta> Animation::TimeToEffectChange() {
}
void Animation::cancel() {
- double current_time_before_cancel = CurrentTimeInternal().value_or(0);
+ AnimationTimeDelta current_time_before_cancel =
+ CurrentTimeInternal().value_or(AnimationTimeDelta());
AnimationPlayState initial_play_state = CalculateAnimationPlayState();
if (initial_play_state != kIdle) {
ResetPendingTasks();
@@ -2223,7 +2286,7 @@ void Animation::AddedEventListener(
UseCounter::Count(GetExecutionContext(), WebFeature::kAnimationFinishEvent);
}
-void Animation::PauseForTesting(double pause_time) {
+void Animation::PauseForTesting(AnimationTimeDelta pause_time) {
// Do not restart a canceled animation.
if (CalculateAnimationPlayState() == kIdle)
return;
@@ -2232,11 +2295,11 @@ void Animation::PauseForTesting(double pause_time) {
// animation.
SetCurrentTimeInternal(pause_time);
if (HasActiveAnimationsOnCompositor()) {
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
DCHECK(current_time);
To<KeyframeEffect>(content_.Get())
->PauseAnimationForTestingOnCompositor(
- base::TimeDelta::FromSecondsD(current_time.value()));
+ base::TimeDelta::FromSecondsD(current_time.value().InSecondsF()));
}
// Do not wait for animation ready to lock in the hold time. Otherwise,
@@ -2420,11 +2483,13 @@ void Animation::RemoveReplacedAnimation() {
replace_state_ = kRemoved;
const AtomicString& event_type = event_type_names::kRemove;
if (GetExecutionContext() && HasEventListeners(event_type)) {
- base::Optional<double> event_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> event_current_time =
+ CurrentTimeInternal();
+ base::Optional<double> event_current_time_ms;
if (event_current_time)
- event_current_time = SecondsToMilliseconds(event_current_time.value());
+ event_current_time_ms = event_current_time.value().InMillisecondsF();
pending_remove_event_ = MakeGarbageCollected<AnimationPlaybackEvent>(
- event_type, event_current_time, TimelineTime());
+ event_type, event_current_time_ms, TimelineTime());
pending_remove_event_->SetTarget(this);
pending_remove_event_->SetCurrentTarget(this);
document_->EnqueueAnimationFrameEvent(pending_remove_event_);
@@ -2533,6 +2598,24 @@ void Animation::commitStyles(ExceptionState& exception_state) {
WrapWeakPersistent(inline_style), WrapWeakPersistent(target)));
}
+bool Animation::IsInDisplayLockedSubtree() {
+ Element* owning_element = OwningElement();
+ if (!owning_element || !GetDocument())
+ return false;
+
+ base::TimeTicks display_lock_update_timestamp =
+ GetDocument()->GetDisplayLockDocumentState().GetLockUpdateTimestamp();
+
+ if (last_display_lock_update_time_ < display_lock_update_timestamp) {
+ const Element* element =
+ DisplayLockUtilities::NearestLockedExclusiveAncestor(*owning_element);
+ is_in_display_locked_subtree_ = !!element;
+ last_display_lock_update_time_ = display_lock_update_timestamp;
+ }
+
+ return is_in_display_locked_subtree_;
+}
+
void Animation::Trace(Visitor* visitor) const {
visitor->Trace(content_);
visitor->Trace(document_);
diff --git a/chromium/third_party/blink/renderer/core/animation/animation.h b/chromium/third_party/blink/renderer/core/animation/animation.h
index caeacc7cf95..1a512b861d3 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation.h
@@ -36,6 +36,7 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
+#include "base/time/time.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_property.h"
@@ -44,6 +45,7 @@
#include "third_party/blink/renderer/core/animation/compositor_animations.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
+#include "third_party/blink/renderer/core/css/cssom/css_numeric_value.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
@@ -99,6 +101,10 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// relative position.
enum CompareAnimationsOrdering { kTreeOrder, kPointerOrder };
+ // Only expect timing accuracy to within 1 microsecond.
+ // drafts.csswg.org/web-animations/#precision-of-time-values.
+ static constexpr double kTimeToleranceMs = 0.001;
+
static Animation* Create(AnimationEffect*,
AnimationTimeline*,
ExceptionState& = ASSERT_NO_EXCEPTION);
@@ -141,12 +147,13 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
void cancel();
- base::Optional<double> currentTime() const;
- void setCurrentTime(base::Optional<double> new_current_time,
- ExceptionState& exception_state);
- void setCurrentTime(base::Optional<double> new_current_time);
+ void currentTime(CSSNumberish&) const;
+ base::Optional<AnimationTimeDelta> CurrentTimeInternal() const;
+ void setCurrentTime(CSSNumberish, ExceptionState& exception_state);
+ void setCurrentTime(CSSNumberish);
+ void SetCurrentTimeInternal(AnimationTimeDelta);
- base::Optional<double> UnlimitedCurrentTime() const;
+ base::Optional<AnimationTimeDelta> UnlimitedCurrentTime() const;
// https://drafts.csswg.org/web-animations/#play-states
String PlayStateString() const;
@@ -202,10 +209,12 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
virtual void setTimeline(AnimationTimeline* timeline);
Document* GetDocument() const;
- base::Optional<double> startTime() const;
- base::Optional<double> StartTimeInternal() const { return start_time_; }
- virtual void setStartTime(base::Optional<double>, ExceptionState&);
- void setStartTime(base::Optional<double>);
+ void startTime(CSSNumberish&) const;
+ base::Optional<AnimationTimeDelta> StartTimeInternal() const {
+ return start_time_;
+ }
+ virtual void setStartTime(CSSNumberish, ExceptionState&);
+ void setStartTime(CSSNumberish);
const AnimationEffect* effect() const { return content_.Get(); }
AnimationEffect* effect() { return content_.Get(); }
@@ -216,7 +225,7 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// Pausing via this method is not reflected in the value returned by
// paused() and must never overlap with pausing via pause().
- void PauseForTesting(double pause_time);
+ void PauseForTesting(AnimationTimeDelta pause_time);
void DisableCompositedAnimationForTesting();
// This should only be used for CSS
@@ -238,9 +247,9 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
void CancelIncompatibleAnimationsOnCompositor();
bool HasActiveAnimationsOnCompositor();
void SetCompositorPending(bool effect_changed = false);
- void NotifyReady(double ready_time);
- void CommitPendingPlay(double ready_time);
- void CommitPendingPause(double ready_time);
+ void NotifyReady(AnimationTimeDelta ready_time);
+ void CommitPendingPlay(AnimationTimeDelta ready_time);
+ void CommitPendingPause(AnimationTimeDelta ready_time);
// CompositorAnimationClient implementation.
CompositorAnimation* GetCompositorAnimation() const override {
return compositor_animation_ ? compositor_animation_->GetAnimation()
@@ -291,11 +300,16 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// depends on computed values.
virtual void FlushPendingUpdates() const {}
+ bool IsInDisplayLockedSubtree();
+
+ void SetCanCompositeBGColorAnim() { can_composite_bgcolor_anim_ = true; }
+ void ResetCanCompositeBGColorAnim() { can_composite_bgcolor_anim_ = false; }
+ bool CanCompositeBGColorAnim() const { return can_composite_bgcolor_anim_; }
+
protected:
DispatchEventResult DispatchEventInternal(Event&) override;
void AddedEventListener(const AtomicString& event_type,
RegisteredEventListener&) override;
- base::Optional<double> CurrentTimeInternal() const;
TimelinePhase CurrentPhaseInternal() const;
virtual AnimationEffect::EventDelegate* CreateEventDelegate(
Element* target,
@@ -304,18 +318,16 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
}
private:
- void SetCurrentTimeInternal(double new_current_time);
- void SetHoldTimeAndPhase(
- base::Optional<double> new_hold_time /* in seconds */,
- TimelinePhase new_hold_phase);
+ void SetHoldTimeAndPhase(base::Optional<AnimationTimeDelta> new_hold_time,
+ TimelinePhase new_hold_phase);
void ResetHoldTimeAndPhase();
bool ValidateHoldTimeAndPhase() const;
void ClearOutdated();
void ForceServiceOnNextFrame();
- double EffectEnd() const;
- bool Limited(base::Optional<double> current_time) const;
+ AnimationTimeDelta EffectEnd() const;
+ bool Limited(base::Optional<AnimationTimeDelta> current_time) const;
// Playback rate that will take effect once any pending tasks are resolved.
// If there are no pending tasks, then the effective playback rate equals the
@@ -323,8 +335,9 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
double EffectivePlaybackRate() const;
void ApplyPendingPlaybackRate();
- base::Optional<double> CalculateStartTime(double current_time) const;
- base::Optional<double> CalculateCurrentTime() const;
+ base::Optional<AnimationTimeDelta> CalculateStartTime(
+ AnimationTimeDelta current_time) const;
+ base::Optional<AnimationTimeDelta> CalculateCurrentTime() const;
TimelinePhase CalculateCurrentPhase() const;
void BeginUpdatingState();
@@ -387,10 +400,10 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// effect when running a scheduled task in response to the animation being
// ready.
base::Optional<double> pending_playback_rate_;
- base::Optional<double> start_time_;
- base::Optional<double> hold_time_;
+ base::Optional<AnimationTimeDelta> start_time_;
+ base::Optional<AnimationTimeDelta> hold_time_;
base::Optional<TimelinePhase> hold_phase_;
- base::Optional<double> previous_current_time_;
+ base::Optional<AnimationTimeDelta> previous_current_time_;
bool reset_current_time_on_resume_ = false;
unsigned sequence_number_;
@@ -445,9 +458,17 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
USING_FAST_MALLOC(CompositorState);
public:
+ // TODO(https://crbug.com/1166397): Convert composited animations to use
+ // AnimationTimeDelta for start_time_ and hold_time_.
explicit CompositorState(Animation& animation)
- : start_time(animation.start_time_),
- hold_time(animation.hold_time_),
+ : start_time(animation.start_time_
+ ? base::make_optional(
+ animation.start_time_.value().InSecondsF())
+ : base::nullopt),
+ hold_time(animation.hold_time_
+ ? base::make_optional(
+ animation.hold_time_.value().InSecondsF())
+ : base::nullopt),
playback_rate(animation.EffectivePlaybackRate()),
effect_changed(false),
pending_action(animation.start_time_ ? kNone : kStart) {}
@@ -503,6 +524,20 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
bool effect_suppressed_;
+ // True if the background color animation can be composited. Set by the
+ // BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams. We keep it here
+ // instead of ElementAnimations such that when we create a compositor
+ // animation, we know which animation should fall back. Note that when we
+ // extend the native paint worklet to composite other types of animations in
+ // the future, we might need to extend this to be a fall back reasons.
+ bool can_composite_bgcolor_anim_ = false;
+
+ // Animations with an owning element stop ticking if there is an active
+ // display lock on an ancestor element. Cache the status to minimize the
+ // number of tree walks.
+ base::TimeTicks last_display_lock_update_time_ = base::TimeTicks();
+ bool is_in_display_locked_subtree_ = false;
+
FRIEND_TEST_ALL_PREFIXES(AnimationAnimationTestCompositeAfterPaint,
NoCompositeWithoutCompositedElementId);
FRIEND_TEST_ALL_PREFIXES(AnimationAnimationTestNoCompositing,
diff --git a/chromium/third_party/blink/renderer/core/animation/animation.idl b/chromium/third_party/blink/renderer/core/animation/animation.idl
index ee01f455ec1..0bdb34f11c0 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation.idl
+++ b/chromium/third_party/blink/renderer/core/animation/animation.idl
@@ -41,8 +41,8 @@ enum ReplaceState { "active", "removed", "persisted" };
[CallWith=ExecutionContext, RaisesException] constructor(optional AnimationEffect? effect = null, optional AnimationTimeline? timeline);
[Measure] attribute AnimationEffect? effect;
[RuntimeEnabled=WebAnimationsAPI] attribute AnimationTimeline? timeline;
- [Measure, RaisesException=Setter] attribute double? startTime;
- [Measure, RaisesException=Setter] attribute double? currentTime;
+ [Measure, RaisesException=Setter] attribute CSSNumberish? startTime;
+ [Measure, RaisesException=Setter] attribute CSSNumberish? currentTime;
[Measure, RaisesException=Setter] attribute double playbackRate;
[Measure] readonly attribute AnimationPlayState playState;
[RuntimeEnabled=WebAnimationsAPI, Measure] readonly attribute ReplaceState replaceState;
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_effect.cc b/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
index 286f2d33216..6cdacfffe51 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
@@ -47,7 +47,7 @@ AnimationEffect::AnimationEffect(const Timing& timing,
timing_(timing),
event_delegate_(event_delegate),
needs_update_(true),
- cancel_time_(0) {
+ cancel_time_(AnimationTimeDelta()) {
timing_.AssertValid();
}
@@ -131,7 +131,7 @@ base::Optional<Timing::Phase> TimelinePhaseToTimingPhase(
}
void AnimationEffect::UpdateInheritedTime(
- base::Optional<double> inherited_time,
+ base::Optional<AnimationTimeDelta> inherited_time,
base::Optional<TimelinePhase> inherited_timeline_phase,
TimingUpdateReason reason) const {
base::Optional<double> playback_rate = base::nullopt;
@@ -152,7 +152,9 @@ void AnimationEffect::UpdateInheritedTime(
last_update_time_ = inherited_time;
last_update_phase_ = timeline_phase;
- const base::Optional<double> local_time = inherited_time;
+ const base::Optional<double> local_time =
+ inherited_time ? base::make_optional(inherited_time.value().InSecondsF())
+ : base::nullopt;
if (needs_update) {
Timing::CalculatedTiming calculated = SpecifiedTiming().CalculateTimings(
local_time, timeline_phase, direction, IsA<KeyframeEffect>(this),
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_effect.h b/chromium/third_party/blink/renderer/core/animation/animation_effect.h
index a2373d4f7de..c876426d7e9 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_effect.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation_effect.h
@@ -114,8 +114,10 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
ComputedEffectTiming* getComputedTiming() const;
void updateTiming(OptionalEffectTiming*,
ExceptionState& = ASSERT_NO_EXCEPTION);
- double GetCancelTime() const { return cancel_time_; }
- void SetCancelTime(double cancel_time) { cancel_time_ = cancel_time; }
+ AnimationTimeDelta GetCancelTime() const { return cancel_time_; }
+ void SetCancelTime(AnimationTimeDelta cancel_time) {
+ cancel_time_ = cancel_time;
+ }
// Attach/Detach the AnimationEffect from its owning animation.
virtual void Attach(AnimationEffectOwner* owner) { owner_ = owner; }
@@ -134,7 +136,7 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
// When AnimationEffect receives a new inherited time via updateInheritedTime
// it will (if necessary) recalculate timings and (if necessary) call
// updateChildrenAndEffects.
- void UpdateInheritedTime(base::Optional<double> inherited_time,
+ void UpdateInheritedTime(base::Optional<AnimationTimeDelta> inherited_time,
base::Optional<TimelinePhase> inherited_phase,
TimingUpdateReason) const;
void Invalidate() const { needs_update_ = true; }
@@ -168,9 +170,9 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
mutable Timing::CalculatedTiming calculated_;
mutable bool needs_update_;
- mutable base::Optional<double> last_update_time_;
+ mutable base::Optional<AnimationTimeDelta> last_update_time_;
mutable base::Optional<Timing::Phase> last_update_phase_;
- double cancel_time_;
+ AnimationTimeDelta cancel_time_;
const Timing::CalculatedTiming& EnsureCalculated() const;
};
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc b/chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc
index bacd7956bf9..9a810175445 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc
@@ -84,8 +84,9 @@ class TestAnimationEffect : public AnimationEffect {
void UpdateInheritedTime(double time, TimingUpdateReason reason) {
event_delegate_->Reset();
- AnimationEffect::UpdateInheritedTime(
- time, /*inherited_phase*/ base::nullopt, reason);
+ AnimationEffect::UpdateInheritedTime(AnimationTimeDelta::FromSecondsD(time),
+ /*inherited_phase*/ base::nullopt,
+ reason);
}
void UpdateChildrenAndEffects() const override {}
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc b/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
index fd95d13cd49..86a7a8b13d0 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
@@ -79,7 +79,7 @@ CSSPropertyID AnimationInputHelpers::KeyframeAttributeToCSSProperty(
builder.Append('-');
builder.Append(property[i]);
}
- return cssPropertyID(document.GetExecutionContext(), builder.ToString());
+ return CssPropertyID(document.GetExecutionContext(), builder.ToString());
}
CSSPropertyID AnimationInputHelpers::KeyframeAttributeToPresentationAttribute(
@@ -92,7 +92,7 @@ CSSPropertyID AnimationInputHelpers::KeyframeAttributeToPresentationAttribute(
String unprefixed_property = RemoveSVGPrefix(property);
if (SVGElement::IsAnimatableCSSProperty(QualifiedName(
g_null_atom, AtomicString(unprefixed_property), g_null_atom))) {
- return cssPropertyID(element->GetExecutionContext(), unprefixed_property);
+ return CssPropertyID(element->GetExecutionContext(), unprefixed_property);
}
return CSSPropertyID::kInvalid;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_test.cc b/chromium/third_party/blink/renderer/core/animation/animation_test.cc
index 151f3417187..5916636297d 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_test.cc
@@ -68,14 +68,6 @@
namespace blink {
-namespace {
-
-double MillisecondsToSeconds(double milliseconds) {
- return milliseconds / 1000;
-}
-
-} // namespace
-
void ExpectRelativeErrorWithinEpsilon(double expected, double observed) {
EXPECT_NEAR(1.0, observed / expected, std::numeric_limits<double>::epsilon());
}
@@ -97,7 +89,7 @@ class AnimationAnimationTestNoCompositing : public RenderingTest {
timeline = GetDocument().Timeline();
timeline->ResetForTesting();
animation = timeline->Play(nullptr);
- animation->setStartTime(0);
+ animation->setStartTime(CSSNumberish::FromDouble(0));
animation->setEffect(MakeAnimation());
}
@@ -193,8 +185,10 @@ class AnimationAnimationTestNoCompositing : public RenderingTest {
}
bool SimulateFrame(double time_ms) {
- if (animation->pending())
- animation->NotifyReady(MillisecondsToSeconds(last_frame_time));
+ if (animation->pending()) {
+ animation->NotifyReady(
+ AnimationTimeDelta::FromMillisecondsD(last_frame_time));
+ }
SimulateMicrotask();
last_frame_time = time_ms;
@@ -222,6 +216,33 @@ class AnimationAnimationTestNoCompositing : public RenderingTest {
GetPage().Animator().ServiceScriptedAnimations(new_time);
}
+ bool StartTimeIsSet(Persistent<blink::Animation> animation) {
+ CSSNumberish start_time;
+ animation->startTime(start_time);
+ return !start_time.IsNull();
+ }
+
+ bool CurrentTimeIsSet(Persistent<blink::Animation> animation) {
+ CSSNumberish current_time;
+ animation->currentTime(current_time);
+ return !current_time.IsNull();
+ }
+
+ double GetStartTimeMs(Persistent<blink::Animation> animation) {
+ CSSNumberish start_time;
+ animation->startTime(start_time);
+ return start_time.GetAsDouble();
+ }
+
+ double GetCurrentTimeMs(Persistent<blink::Animation> animation) {
+ CSSNumberish current_time;
+ animation->currentTime(current_time);
+ return current_time.GetAsDouble();
+ }
+
+#define EXPECT_TIME(expected, observed) \
+ EXPECT_NEAR(expected, observed, Animation::kTimeToleranceMs)
+
Persistent<DocumentTimeline> timeline;
Persistent<Animation> animation;
@@ -231,6 +252,38 @@ class AnimationAnimationTestNoCompositing : public RenderingTest {
class AnimationAnimationTestCompositing
: public AnimationAnimationTestNoCompositing {
+ public:
+ Animation* CreateAnimation(CSSPropertyID property_id,
+ String from,
+ String to) {
+ Timing timing;
+ timing.iteration_duration = AnimationTimeDelta::FromSecondsD(30);
+
+ Persistent<StringKeyframe> start_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ start_keyframe->SetCSSPropertyValue(
+ property_id, from, SecureContextMode::kInsecureContext, nullptr);
+ Persistent<StringKeyframe> end_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ end_keyframe->SetCSSPropertyValue(
+ property_id, to, SecureContextMode::kInsecureContext, nullptr);
+
+ StringKeyframeVector keyframes;
+ keyframes.push_back(start_keyframe);
+ keyframes.push_back(end_keyframe);
+
+ Element* element = GetElementById("target");
+ auto* model = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
+
+ NonThrowableExceptionState exception_state;
+ DocumentTimeline* timeline =
+ MakeGarbageCollected<DocumentTimeline>(&GetDocument());
+ return Animation::Create(
+ MakeGarbageCollected<KeyframeEffect>(element, model, timing), timeline,
+ exception_state);
+ }
+
+ private:
void SetUp() override {
EnableCompositing();
AnimationAnimationTestNoCompositing::SetUp();
@@ -250,155 +303,158 @@ class AnimationAnimationTestCompositeAfterPaint
TEST_F(AnimationAnimationTestNoCompositing, InitialState) {
SetUpWithoutStartingTimeline();
animation = timeline->Play(nullptr);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->pending());
EXPECT_FALSE(animation->Paused());
EXPECT_EQ(1, animation->playbackRate());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(StartTimeIsSet(animation));
StartTimeline();
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(0, timeline->CurrentTimeMilliseconds());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, timeline->CurrentTimeMilliseconds().value());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Paused());
EXPECT_FALSE(animation->pending());
EXPECT_EQ(1, animation->playbackRate());
- EXPECT_EQ(0, animation->startTime());
+ EXPECT_TIME(0, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, CurrentTimeDoesNotSetOutdated) {
EXPECT_FALSE(animation->Outdated());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Outdated());
// FIXME: We should split simulateFrame into a version that doesn't update
// the animation and one that does, as most of the tests don't require
// update() to be called.
GetDocument().GetAnimationClock().UpdateTime(
base::TimeTicks() + base::TimeDelta::FromMilliseconds(10000));
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Outdated());
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTime) {
EXPECT_EQ("running", animation->playState());
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTimeNegative) {
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(-10000, animation->currentTime());
+ EXPECT_TIME(-10000, GetCurrentTimeMs(animation));
SimulateFrame(20000);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
animation->setPlaybackRate(-2);
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("finished", animation->playState());
// A seek can set current time outside the range [0, EffectEnd()].
- EXPECT_EQ(-10000, animation->currentTime());
+ EXPECT_TIME(-10000, GetCurrentTimeMs(animation));
SimulateFrame(40000);
// Hold current time even though outside normal range for the animation.
EXPECT_FALSE(animation->pending());
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(-10000, animation->currentTime());
+ EXPECT_TIME(-10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing,
SetCurrentTimeNegativeWithoutSimultaneousPlaybackRateChange) {
SimulateFrame(20000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
// Reversing the direction preserves current time.
animation->setPlaybackRate(-1);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(30000);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("finished", animation->playState());
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTimePastContentEnd) {
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
SimulateFrame(20000);
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
// Reversing the play direction changes the play state from finished to
// running.
animation->setPlaybackRate(-2);
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(40000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTimeMax) {
double limit = std::numeric_limits<double>::max();
- animation->setCurrentTime(limit);
- ExpectRelativeErrorWithinEpsilon(limit, animation->currentTime().value());
+ animation->setCurrentTime(CSSNumberish::FromDouble(limit));
+ CSSNumberish current_time;
+ animation->currentTime(current_time);
+ ExpectRelativeErrorWithinEpsilon(limit, current_time.GetAsDouble());
SimulateFrame(100000);
- ExpectRelativeErrorWithinEpsilon(limit, animation->currentTime().value());
+ animation->currentTime(current_time);
+ ExpectRelativeErrorWithinEpsilon(limit, current_time.GetAsDouble());
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTimeSetsStartTime) {
- EXPECT_EQ(0, animation->startTime());
- animation->setCurrentTime(1000);
- EXPECT_EQ(-1000, animation->startTime());
+ EXPECT_TIME(0, GetStartTimeMs(animation));
+ animation->setCurrentTime(CSSNumberish::FromDouble(1000));
+ EXPECT_TIME(-1000, GetStartTimeMs(animation));
SimulateFrame(1000);
- EXPECT_EQ(-1000, animation->startTime());
- EXPECT_EQ(2000, animation->currentTime());
+ EXPECT_TIME(-1000, GetStartTimeMs(animation));
+ EXPECT_TIME(2000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetStartTime) {
SimulateFrame(20000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(0, animation->startTime());
- EXPECT_EQ(20000, animation->currentTime());
- animation->setStartTime(10000);
+ EXPECT_TIME(0, GetStartTimeMs(animation));
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
+ animation->setStartTime(CSSNumberish::FromDouble(10000));
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(10000, animation->startTime());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetStartTimeMs(animation));
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateFrame(30000);
- EXPECT_EQ(10000, animation->startTime());
- EXPECT_EQ(20000, animation->currentTime());
- animation->setStartTime(-20000);
+ EXPECT_TIME(10000, GetStartTimeMs(animation));
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
+ animation->setStartTime(CSSNumberish::FromDouble(-20000));
EXPECT_EQ("finished", animation->playState());
}
TEST_F(AnimationAnimationTestNoCompositing, SetStartTimeLimitsAnimation) {
// Setting the start time is a seek operation, which is not constrained by the
// normal limits on the animation.
- animation->setStartTime(-50000);
+ animation->setStartTime(CSSNumberish::FromDouble(-50000));
EXPECT_EQ("finished", animation->playState());
EXPECT_TRUE(animation->Limited());
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
animation->setPlaybackRate(-1);
EXPECT_EQ("running", animation->playState());
- animation->setStartTime(-100000);
+ animation->setStartTime(CSSNumberish::FromDouble(-100000));
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(-100000, animation->currentTime());
+ EXPECT_TIME(-100000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
}
@@ -406,15 +462,15 @@ TEST_F(AnimationAnimationTestNoCompositing, SetStartTimeOnLimitedAnimation) {
// The setStartTime method is a seek and thus not constrained by the normal
// limits on the animation.
SimulateFrame(30000);
- animation->setStartTime(-10000);
+ animation->setStartTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(40000, animation->currentTime());
+ EXPECT_TIME(40000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
- animation->setCurrentTime(50000);
- EXPECT_EQ(50000, animation->currentTime());
- animation->setStartTime(-40000);
- EXPECT_EQ(70000, animation->currentTime());
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
+ animation->setStartTime(CSSNumberish::FromDouble(-40000));
+ EXPECT_TIME(70000, GetCurrentTimeMs(animation));
EXPECT_EQ("finished", animation->playState());
EXPECT_TRUE(animation->Limited());
}
@@ -426,11 +482,11 @@ TEST_F(AnimationAnimationTestNoCompositing, StartTimePauseFinish) {
EXPECT_TRUE(animation->pending());
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(StartTimeIsSet(animation));
animation->finish(exception_state);
EXPECT_EQ("finished", animation->playState());
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(-30000, animation->startTime());
+ EXPECT_TIME(-30000, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, FinishWhenPaused) {
@@ -449,24 +505,24 @@ TEST_F(AnimationAnimationTestNoCompositing, FinishWhenPaused) {
TEST_F(AnimationAnimationTestNoCompositing, StartTimeFinishPause) {
NonThrowableExceptionState exception_state;
animation->finish(exception_state);
- EXPECT_EQ(-30000, animation->startTime());
+ EXPECT_TIME(-30000, GetStartTimeMs(animation));
animation->pause();
EXPECT_EQ("paused", animation->playState());
EXPECT_TRUE(animation->pending());
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(StartTimeIsSet(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, StartTimeWithZeroPlaybackRate) {
animation->setPlaybackRate(0);
EXPECT_EQ("running", animation->playState());
SimulateAwaitReady();
- EXPECT_TRUE(animation->startTime().has_value());
+ EXPECT_TRUE(StartTimeIsSet(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, PausePlay) {
@@ -475,13 +531,13 @@ TEST_F(AnimationAnimationTestNoCompositing, PausePlay) {
animation->pause();
EXPECT_EQ("paused", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
// Resume playing the animation at the 20s mark.
SimulateFrame(20000);
EXPECT_EQ("paused", animation->playState());
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
animation->play();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
@@ -490,19 +546,19 @@ TEST_F(AnimationAnimationTestNoCompositing, PausePlay) {
// Advance another 10s.
SimulateFrame(30000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, PlayRewindsToStart) {
// Auto-replay when starting from limit.
- animation->setCurrentTime(30000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(30000));
animation->play();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
// Auto-replay when starting past the upper bound.
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->play();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
@@ -510,11 +566,11 @@ TEST_F(AnimationAnimationTestNoCompositing, PlayRewindsToStart) {
// from a negative value of current time.
SimulateFrame(10000);
EXPECT_FALSE(animation->pending());
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("running", animation->playState());
EXPECT_FALSE(animation->pending());
animation->play();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
SimulateAwaitReady();
@@ -526,14 +582,14 @@ TEST_F(AnimationAnimationTestNoCompositing, PlayRewindsToEnd) {
// Snap to end when playing a reversed animation from the start.
animation->setPlaybackRate(-1);
animation->play();
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
// Snap to end if playing a reversed animation starting past the upper limit.
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
animation->play();
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->pending());
SimulateFrame(10000);
@@ -542,9 +598,9 @@ TEST_F(AnimationAnimationTestNoCompositing, PlayRewindsToEnd) {
// Snap to the end if playing a reversed animation starting with a negative
// value for current time.
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->play();
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
@@ -559,15 +615,15 @@ TEST_F(AnimationAnimationTestNoCompositing,
// becomes the hold time.
animation->setPlaybackRate(0);
animation->play();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->play();
- EXPECT_EQ(40000, animation->currentTime());
+ EXPECT_TIME(40000, GetCurrentTimeMs(animation));
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->play();
- EXPECT_EQ(-10000, animation->currentTime());
+ EXPECT_TIME(-10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing,
@@ -583,76 +639,76 @@ TEST_F(AnimationAnimationTestNoCompositing,
}
TEST_F(AnimationAnimationTestNoCompositing, Reverse) {
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
animation->pause();
animation->reverse();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
// Effective playback rate does not kick in until the animation is ready.
EXPECT_EQ(1, animation->playbackRate());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
EXPECT_EQ(-1, animation->playbackRate());
// Updating the playback rate does not change current time.
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing,
ReverseHoldsCurrentTimeWithPlaybackRateZero) {
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
animation->setPlaybackRate(0);
animation->pause();
animation->reverse();
SimulateAwaitReady();
EXPECT_EQ("running", animation->playState());
EXPECT_EQ(0, animation->playbackRate());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateFrame(20000);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, ReverseSeeksToStart) {
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->setPlaybackRate(-1);
animation->reverse();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, ReverseSeeksToEnd) {
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->reverse();
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, ReverseBeyondLimit) {
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->setPlaybackRate(-1);
animation->reverse();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->reverse();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, Finish) {
NonThrowableExceptionState exception_state;
animation->finish(exception_state);
// Finished snaps to the end of the animation.
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_EQ("finished", animation->playState());
// Finished is a synchronous operation.
EXPECT_FALSE(animation->pending());
animation->setPlaybackRate(-1);
animation->finish(exception_state);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_EQ("finished", animation->playState());
EXPECT_FALSE(animation->pending());
}
@@ -660,28 +716,28 @@ TEST_F(AnimationAnimationTestNoCompositing, Finish) {
TEST_F(AnimationAnimationTestNoCompositing, FinishAfterEffectEnd) {
NonThrowableExceptionState exception_state;
// OK to set current time out of bounds.
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->finish(exception_state);
// The finish method triggers a snap to the upper boundary.
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, FinishBeforeStart) {
NonThrowableExceptionState exception_state;
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->setPlaybackRate(-1);
animation->finish(exception_state);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing,
FinishDoesNothingWithPlaybackRateZero) {
// Cannot finish an animation that has a playback rate of zero.
DummyExceptionStateForTesting exception_state;
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
animation->setPlaybackRate(0);
animation->finish(exception_state);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
EXPECT_TRUE(exception_state.HadException());
}
@@ -693,11 +749,11 @@ TEST_F(AnimationAnimationTestNoCompositing, FinishRaisesException) {
timing.iteration_count = std::numeric_limits<double>::infinity();
animation->setEffect(MakeGarbageCollected<KeyframeEffect>(
nullptr, MakeEmptyEffectModel(), timing));
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
DummyExceptionStateForTesting exception_state;
animation->finish(exception_state);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
EXPECT_TRUE(exception_state.HadException());
EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
exception_state.CodeAs<DOMExceptionCode>());
@@ -705,12 +761,12 @@ TEST_F(AnimationAnimationTestNoCompositing, FinishRaisesException) {
TEST_F(AnimationAnimationTestNoCompositing, LimitingAtEffectEnd) {
SimulateFrame(30000);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
// Cannot run past the end of the animation without a seek.
SimulateFrame(40000);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Paused());
}
@@ -720,11 +776,11 @@ TEST_F(AnimationAnimationTestNoCompositing, LimitingAtStart) {
SimulateAwaitReady();
SimulateFrame(45000);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
SimulateFrame(60000);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Paused());
}
@@ -732,75 +788,75 @@ TEST_F(AnimationAnimationTestNoCompositing, LimitingWithNoEffect) {
animation->setEffect(nullptr);
EXPECT_TRUE(animation->Limited());
SimulateFrame(30000);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRate) {
animation->setPlaybackRate(2);
SimulateAwaitReady();
EXPECT_EQ(2, animation->playbackRate());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
SimulateFrame(10000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateWhilePaused) {
SimulateFrame(10000);
animation->pause();
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
animation->setPlaybackRate(2);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(20000);
animation->play();
// Change to playback rate does not alter current time.
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(25000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateWhileLimited) {
// Animation plays until it hits the upper bound.
SimulateFrame(40000);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
animation->setPlaybackRate(2);
SimulateAwaitReady();
// Already at the end of the animation.
SimulateFrame(50000);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
animation->setPlaybackRate(-2);
SimulateAwaitReady();
SimulateFrame(60000);
EXPECT_FALSE(animation->Limited());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateZero) {
SimulateFrame(10000);
animation->setPlaybackRate(0);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateFrame(20000);
- EXPECT_EQ(10000, animation->currentTime());
- animation->setCurrentTime(20000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
+ animation->setCurrentTime(CSSNumberish::FromDouble(20000));
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateMax) {
animation->setPlaybackRate(std::numeric_limits<double>::max());
EXPECT_EQ(std::numeric_limits<double>::max(), animation->playbackRate());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(1);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRate) {
@@ -808,10 +864,10 @@ TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRate) {
EXPECT_EQ(1, animation->playbackRate());
SimulateAwaitReady();
EXPECT_EQ(2, animation->playbackRate());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
SimulateFrame(10000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateWhilePaused) {
@@ -836,11 +892,11 @@ TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateWhilePaused) {
TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateWhileLimited) {
NonThrowableExceptionState exception_state;
animation->finish(exception_state);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
// Updating playback rate does not affect current time.
animation->updatePlaybackRate(2);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
// Updating payback rate is resolved immediately for an animation in the
// finished state.
@@ -863,36 +919,36 @@ TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateWhileRunning) {
TEST_F(AnimationAnimationTestNoCompositing, SetEffect) {
animation = timeline->Play(nullptr);
- animation->setStartTime(0);
+ animation->setStartTime(CSSNumberish::FromDouble(0));
AnimationEffect* effect1 = MakeAnimation();
AnimationEffect* effect2 = MakeAnimation();
animation->setEffect(effect1);
EXPECT_EQ(effect1, animation->effect());
- EXPECT_EQ(0, animation->currentTime());
- animation->setCurrentTime(15000);
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ animation->setCurrentTime(CSSNumberish::FromDouble(15000));
animation->setEffect(effect2);
- EXPECT_EQ(15000, animation->currentTime());
+ EXPECT_TIME(15000, GetCurrentTimeMs(animation));
EXPECT_EQ(nullptr, effect1->GetAnimationForTesting());
EXPECT_EQ(animation, effect2->GetAnimationForTesting());
EXPECT_EQ(effect2, animation->effect());
}
TEST_F(AnimationAnimationTestNoCompositing, SetEffectLimitsAnimation) {
- animation->setCurrentTime(20000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(20000));
animation->setEffect(MakeAnimation(10));
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
SimulateFrame(10000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetEffectUnlimitsAnimation) {
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->setEffect(MakeAnimation(60));
EXPECT_FALSE(animation->Limited());
- EXPECT_EQ(40000, animation->currentTime());
+ EXPECT_TIME(40000, GetCurrentTimeMs(animation));
SimulateFrame(10000);
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, EmptyAnimationsDontUpdateEffects) {
@@ -912,6 +968,10 @@ TEST_F(AnimationAnimationTestNoCompositing, AnimationsDisassociateFromEffect) {
EXPECT_EQ(nullptr, animation2->effect());
}
+#define EXPECT_TIMEDELTA(expected, observed) \
+ EXPECT_NEAR(expected.InMillisecondsF(), observed.InMillisecondsF(), \
+ Animation::kTimeToleranceMs)
+
TEST_F(AnimationAnimationTestNoCompositing, AnimationsReturnTimeToNextEffect) {
Timing timing;
timing.start_delay = 1;
@@ -920,46 +980,48 @@ TEST_F(AnimationAnimationTestNoCompositing, AnimationsReturnTimeToNextEffect) {
auto* keyframe_effect = MakeGarbageCollected<KeyframeEffect>(
nullptr, MakeEmptyEffectModel(), timing);
animation = timeline->Play(keyframe_effect);
- animation->setStartTime(0);
+ animation->setStartTime(CSSNumberish::FromDouble(0));
// Next effect change at end of start delay.
SimulateFrame(0);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ animation->TimeToEffectChange().value());
// Next effect change at end of start delay.
SimulateFrame(500);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(0.5),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(0.5),
+ animation->TimeToEffectChange().value());
// Start of active phase.
SimulateFrame(1000);
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
// Still in active phase.
SimulateFrame(1500);
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
// Start of the after phase. Next effect change at end of after phase.
SimulateFrame(2000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ animation->TimeToEffectChange().value());
// Still in effect if fillmode = forward|both.
SimulateFrame(3000);
EXPECT_EQ(base::nullopt, animation->TimeToEffectChange());
// Reset to start of animation. Next effect at the end of the start delay.
- animation->setCurrentTime(0);
+ animation->setCurrentTime(CSSNumberish::FromDouble(0));
SimulateFrame(3000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ animation->TimeToEffectChange().value());
// Start delay is scaled by playback rate.
animation->setPlaybackRate(2);
SimulateFrame(3000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(0.5),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(0.5),
+ animation->TimeToEffectChange().value());
// Effectively a paused animation.
animation->setPlaybackRate(0);
@@ -967,23 +1029,24 @@ TEST_F(AnimationAnimationTestNoCompositing, AnimationsReturnTimeToNextEffect) {
EXPECT_EQ(base::nullopt, animation->TimeToEffectChange());
// Reversed animation from end time. Next effect after end delay.
- animation->setCurrentTime(3000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(3000));
animation->setPlaybackRate(-1);
animation->Update(kTimingUpdateOnDemand);
SimulateFrame(3000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ animation->TimeToEffectChange().value());
// End delay is scaled by playback rate.
animation->setPlaybackRate(-2);
animation->Update(kTimingUpdateOnDemand);
SimulateFrame(3000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(0.5),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(0.5),
+ animation->TimeToEffectChange().value());
}
TEST_F(AnimationAnimationTestNoCompositing, TimeToNextEffectWhenPaused) {
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
animation->pause();
EXPECT_TRUE(animation->pending());
EXPECT_EQ("paused", animation->playState());
@@ -995,8 +1058,9 @@ TEST_F(AnimationAnimationTestNoCompositing, TimeToNextEffectWhenPaused) {
TEST_F(AnimationAnimationTestNoCompositing,
TimeToNextEffectWhenCancelledBeforeStart) {
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
- animation->setCurrentTime(-8000);
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
+ animation->setCurrentTime(CSSNumberish::FromDouble(-8000));
animation->setPlaybackRate(2);
EXPECT_EQ("running", animation->playState());
animation->cancel();
@@ -1010,8 +1074,9 @@ TEST_F(AnimationAnimationTestNoCompositing,
TEST_F(AnimationAnimationTestNoCompositing,
TimeToNextEffectWhenCancelledBeforeStartReverse) {
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
- animation->setCurrentTime(9000);
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
+ animation->setCurrentTime(CSSNumberish::FromDouble(9000));
animation->setPlaybackRate(-3);
EXPECT_EQ("running", animation->playState());
animation->cancel();
@@ -1023,7 +1088,8 @@ TEST_F(AnimationAnimationTestNoCompositing,
TEST_F(AnimationAnimationTestNoCompositing,
TimeToNextEffectSimpleCancelledBeforeStart) {
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
EXPECT_EQ("running", animation->playState());
animation->cancel();
EXPECT_EQ("idle", animation->playState());
@@ -1059,99 +1125,99 @@ TEST_F(AnimationAnimationTestNoCompositing, HasLowerCompositeOrdering) {
TEST_F(AnimationAnimationTestNoCompositing, PlayAfterCancel) {
animation->cancel();
EXPECT_EQ("idle", animation->playState());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
animation->play();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
- EXPECT_EQ(0, animation->startTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ EXPECT_TIME(0, GetStartTimeMs(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(10000, animation->currentTime());
- EXPECT_EQ(0, animation->startTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
+ EXPECT_TIME(0, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, PlayBackwardsAfterCancel) {
animation->setPlaybackRate(-1);
- animation->setCurrentTime(15000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(15000));
animation->cancel();
EXPECT_EQ("idle", animation->playState());
EXPECT_FALSE(animation->pending());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
// Snap to the end of the animation.
animation->play();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(30000, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(30000, animation->startTime());
+ EXPECT_TIME(30000, GetStartTimeMs(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(20000, animation->currentTime());
- EXPECT_EQ(30000, animation->startTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
+ EXPECT_TIME(30000, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, ReverseAfterCancel) {
animation->cancel();
EXPECT_EQ("idle", animation->playState());
EXPECT_FALSE(animation->pending());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
// Reverse snaps to the end of the animation.
animation->reverse();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(30000, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(30000, animation->startTime());
+ EXPECT_TIME(30000, GetStartTimeMs(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(20000, animation->currentTime());
- EXPECT_EQ(30000, animation->startTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
+ EXPECT_TIME(30000, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, FinishAfterCancel) {
NonThrowableExceptionState exception_state;
animation->cancel();
EXPECT_EQ("idle", animation->playState());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
animation->finish(exception_state);
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(30000, animation->currentTime());
- EXPECT_EQ(-30000, animation->startTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
+ EXPECT_TIME(-30000, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, PauseAfterCancel) {
animation->cancel();
EXPECT_EQ("idle", animation->playState());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
animation->pause();
EXPECT_EQ("paused", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
}
// crbug.com/1052217
@@ -1169,7 +1235,8 @@ TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateAfterFinish) {
EXPECT_EQ(animation->playbackRate(), -1);
EXPECT_TRUE(animation->Outdated());
animation->Update(kTimingUpdateOnDemand);
- EXPECT_EQ(0, animation->TimeToEffectChange()->InSecondsF());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
EXPECT_FALSE(animation->Outdated());
}
@@ -1189,7 +1256,8 @@ TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateAfterFinish) {
EXPECT_EQ(animation->playbackRate(), -1);
EXPECT_TRUE(animation->Outdated());
animation->Update(kTimingUpdateOnDemand);
- EXPECT_EQ(0, animation->TimeToEffectChange()->InSecondsF());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
EXPECT_FALSE(animation->Outdated());
}
@@ -1302,7 +1370,7 @@ TEST_F(AnimationAnimationTestCompositing, PreCommitRecordsHistograms) {
// Now make the playback rate 0. This trips both the invalid animation and
// unsupported timing parameter reasons.
animation->setPlaybackRate(0);
- animation->NotifyReady(100);
+ animation->NotifyReady(AnimationTimeDelta::FromSecondsD(100));
{
HistogramTester histogram;
ASSERT_TRUE(animation->PreCommit(0, nullptr, true));
@@ -1403,6 +1471,163 @@ TEST_F(AnimationAnimationTestCompositing, InfiniteDurationAnimation) {
animation->CheckCanStartAnimationOnCompositor(nullptr));
}
+// This test ensures that a background-color animation can start on compositor.
+TEST_F(AnimationAnimationTestCompositing, BackgroundColorComposited) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target" style="width: 100px; height: 100px">
+ </div>
+ )HTML");
+
+ Animation* animation =
+ CreateAnimation(CSSPropertyID::kBackgroundColor, "red", "green");
+
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ // A basic condition for an animation to be compositable is that it is set so
+ // by BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams.
+ animation->SetCanCompositeBGColorAnim();
+ EXPECT_EQ(animation->CheckCanStartAnimationOnCompositor(nullptr),
+ CompositorAnimations::kNoFailure);
+}
+
+// crbug.com/1149012
+// Regression test to ensure proper restart logic for composited animations on
+// relative transforms after a size change. In this test, the transform depends
+// on the width and height of the box and a change to either triggers a restart
+// of the animation if running.
+TEST_F(AnimationAnimationTestCompositing,
+ RestartCompositedAnimationOnSizeChange) {
+ // TODO(crbug.com/389359): Remove forced feature enabling once on by
+ // default.
+ ScopedCompositeRelativeKeyframesForTest composite_relative_keyframes(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target"
+ style="width: 100px; height: 200px; will-change: transform">
+ </div>
+ )HTML");
+
+ Animation* animation = CreateAnimation(
+ CSSPropertyID::kTransform, "translate(100%, 100%)", "translate(0%, 0%)");
+
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ KeyframeEffect* keyframe_effect =
+ DynamicTo<KeyframeEffect>(animation->effect());
+ ASSERT_TRUE(keyframe_effect);
+
+ EXPECT_EQ(animation->CheckCanStartAnimationOnCompositor(nullptr),
+ CompositorAnimations::kNoFailure);
+
+ GetDocument().GetPendingAnimations().Update(nullptr, true);
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Kick the animation out of the play-pending state.
+ animation->setStartTime(CSSNumberish::FromDouble(0));
+
+ // No size change and animation does not require a restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(100, 200));
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Restart animation on a width change.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(200, 200));
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+
+ GetDocument().GetPendingAnimations().Update(nullptr, true);
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Restart animation on a height change.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(200, 300));
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+}
+
+// crbug.com/1149012
+// Regression test to ensure proper restart logic for composited animations on
+// relative transforms after a size change. In this test, the transform only
+// depends on width and a change to the height does not trigger a restart.
+TEST_F(AnimationAnimationTestCompositing,
+ RestartCompositedAnimationOnWidthChange) {
+ // TODO(crbug.com/389359): Remove forced feature enabling once on by
+ // default.
+ ScopedCompositeRelativeKeyframesForTest composite_relative_keyframes(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target"
+ style="width: 100px; height: 200px; will-change: transform">
+ </div>
+ )HTML");
+
+ animation = CreateAnimation(CSSPropertyID::kTransform, "translateX(100%)",
+ "translateX(0%)");
+
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ KeyframeEffect* keyframe_effect =
+ DynamicTo<KeyframeEffect>(animation->effect());
+ ASSERT_TRUE(keyframe_effect);
+
+ GetDocument().GetPendingAnimations().Update(nullptr, true);
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(100, 200));
+ animation->setStartTime(CSSNumberish::FromDouble(0));
+
+ // Transform is not height dependent and a change to the height does not force
+ // an animation restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(100, 300));
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Width change forces a restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(200, 300));
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+}
+
+// crbug.com/1149012
+// Regression test to ensure proper restart logic for composited animations on
+// relative transforms after a size change. In this test, the transition only
+// affects height and a change to the width does not trigger a restart.
+TEST_F(AnimationAnimationTestCompositing,
+ RestartCompositedAnimationOnHeightChange) {
+ // TODO(crbug.com/389359): Remove forced feature enabling once on by
+ // default.
+ ScopedCompositeRelativeKeyframesForTest composite_relative_keyframes(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target"
+ style="width: 100px; height: 200px; will-change: transform">
+ </div>
+ )HTML");
+
+ animation = CreateAnimation(CSSPropertyID::kTransform, "translateY(100%)",
+ "translateY(0%)");
+
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ KeyframeEffect* keyframe_effect =
+ DynamicTo<KeyframeEffect>(animation->effect());
+ ASSERT_TRUE(keyframe_effect);
+
+ GetDocument().GetPendingAnimations().Update(nullptr, true);
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(100, 200));
+ animation->setStartTime(CSSNumberish::FromDouble(0));
+
+ // Transform is not width dependent and a change to the width does not force
+ // an animation restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(300, 200));
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Height change forces a restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(300, 400));
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+}
+
TEST_F(AnimationAnimationTestCompositing,
ScrollLinkedAnimationCanBeComposited) {
ResetWithCompositedAnimation();
@@ -1533,7 +1758,7 @@ TEST_F(AnimationAnimationTestCompositing,
UpdateAllLifecyclePhasesForTest();
const double TEST_START_TIME = 10;
- scroll_animation->setStartTime(TEST_START_TIME);
+ scroll_animation->setStartTime(CSSNumberish::FromDouble(TEST_START_TIME));
scroll_animation->play();
EXPECT_EQ(scroll_animation->CheckCanStartAnimationOnCompositor(nullptr),
CompositorAnimations::kNoFailure);
@@ -1581,25 +1806,25 @@ TEST_F(AnimationAnimationTestNoCompositing, ScrollLinkedAnimationCreation) {
Animation::Create(MakeAnimation(), scroll_timeline, exception_state);
// Verify start and current times in Idle state.
- EXPECT_FALSE(scroll_animation->startTime().has_value());
- EXPECT_FALSE(scroll_animation->currentTime().has_value());
+ EXPECT_FALSE(StartTimeIsSet(scroll_animation));
+ EXPECT_FALSE(CurrentTimeIsSet(scroll_animation));
scroll_animation->play();
// Verify start and current times in Pending state.
- EXPECT_EQ(0, scroll_animation->startTime());
- EXPECT_EQ(20, scroll_animation->currentTime());
+ EXPECT_TIME(0, GetStartTimeMs(scroll_animation));
+ EXPECT_TIME(20, GetCurrentTimeMs(scroll_animation));
UpdateAllLifecyclePhasesForTest();
// Verify start and current times in Playing state.
- EXPECT_EQ(0, scroll_animation->startTime());
- EXPECT_EQ(20, scroll_animation->currentTime());
+ EXPECT_TIME(0, GetStartTimeMs(scroll_animation));
+ EXPECT_TIME(20, GetCurrentTimeMs(scroll_animation));
// Verify current time after scroll.
scrollable_area->SetScrollOffset(ScrollOffset(0, 40),
mojom::blink::ScrollType::kProgrammatic);
SimulateFrameForScrollAnimations();
- EXPECT_EQ(40, scroll_animation->currentTime());
+ EXPECT_TIME(40, GetCurrentTimeMs(scroll_animation));
}
// Verifies that finished composited scroll-linked animations restart on
@@ -1671,14 +1896,14 @@ TEST_F(AnimationAnimationTestCompositing,
// Advances the animation to "finished" state. The composited animation will
// be destroyed accordingly.
- scroll_animation->setCurrentTime(50000);
+ scroll_animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ(scroll_animation->playState(), "finished");
scroll_animation->Update(kTimingUpdateForAnimationFrame);
GetDocument().GetPendingAnimations().Update(nullptr, true);
EXPECT_FALSE(scroll_animation->HasActiveAnimationsOnCompositor());
// Restarting the animation should create a new compositor animation.
- scroll_animation->setCurrentTime(100);
+ scroll_animation->setCurrentTime(CSSNumberish::FromDouble(100));
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(scroll_animation->playState(), "running");
scroll_animation->Update(kTimingUpdateForAnimationFrame);
@@ -1715,7 +1940,7 @@ TEST_F(AnimationAnimationTestNoCompositing,
EXPECT_TRUE(animation->Update(kTimingUpdateForAnimationFrame));
// Asynchronous completion.
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("finished", animation->playState());
EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
}
@@ -1735,7 +1960,7 @@ TEST_F(AnimationAnimationTestNoCompositing,
EXPECT_TRUE(animation->HasPendingActivity());
// Resolving the finished promise clears the pending activity.
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("finished", animation->playState());
SimulateMicrotask();
EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
@@ -1786,7 +2011,7 @@ TEST_F(AnimationAnimationTestNoCompositing,
EXPECT_TRUE(animation->HasPendingActivity());
// Finishing the animation asynchronously clears the pending activity.
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("finished", animation->playState());
SimulateMicrotask();
EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
@@ -2012,4 +2237,62 @@ TEST_F(AnimationAnimationTestCompositing,
CompositorAnimations::kTimelineSourceHasInvalidCompositingState);
}
+TEST_F(AnimationAnimationTestCompositing, ContentVisibleDisplayLockTest) {
+ animation->cancel();
+ RunDocumentLifecycle();
+
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .container {
+ content-visibility: auto;
+ }
+ @keyframes anim {
+ from { opacity: 0; }
+ to { opacity: 1; }
+ }
+ #target {
+ background-color: blue;
+ width: 50px;
+ height: 50px;
+ animation: anim 1s linear alternate infinite;
+ }
+ </style>
+ <div id="outer" class="container">
+ <div id="inner" class="container">
+ <div id ="target">
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ RunDocumentLifecycle();
+
+ Element* outer = GetElementById("outer");
+ Element* inner = GetElementById("inner");
+ Element* target = GetElementById("target");
+
+ ElementAnimations* element_animations = target->GetElementAnimations();
+ EXPECT_EQ(1u, element_animations->Animations().size());
+
+ Animation* animation = element_animations->Animations().begin()->key;
+ ASSERT_TRUE(!!animation);
+ EXPECT_FALSE(animation->IsInDisplayLockedSubtree());
+
+ inner->setAttribute(html_names::kStyleAttr, "content-visibility: hidden");
+ RunDocumentLifecycle();
+ EXPECT_TRUE(animation->IsInDisplayLockedSubtree());
+
+ inner->setAttribute(html_names::kStyleAttr, "content-visibility: visible");
+ RunDocumentLifecycle();
+ EXPECT_FALSE(animation->IsInDisplayLockedSubtree());
+
+ outer->setAttribute(html_names::kStyleAttr, "content-visibility: hidden");
+ RunDocumentLifecycle();
+ EXPECT_TRUE(animation->IsInDisplayLockedSubtree());
+
+ // Ensure that the animation has not been canceled even though display locked.
+ EXPECT_EQ(1u, target->GetElementAnimations()->Animations().size());
+ EXPECT_EQ(animation->playState(), "running");
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_time_delta.h b/chromium/third_party/blink/renderer/core/animation/animation_time_delta.h
index 9c330f3443b..b7ab9757fcd 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_time_delta.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation_time_delta.h
@@ -41,6 +41,8 @@ class CORE_EXPORT AnimationTimeDelta {
public:
constexpr AnimationTimeDelta() : delta_(0) {}
+ constexpr explicit AnimationTimeDelta(base::TimeDelta time_delta)
+ : delta_(time_delta.InSecondsF()) {}
static AnimationTimeDelta FromSecondsD(double time_s) {
DCHECK(!std::isnan(time_s));
@@ -61,6 +63,9 @@ class CORE_EXPORT AnimationTimeDelta {
bool is_max() const {
return delta_ == std::numeric_limits<double>::infinity();
}
+
+ bool is_inf() const { return std::isinf(delta_); }
+
bool is_zero() const { return delta_ == 0; }
AnimationTimeDelta operator+(AnimationTimeDelta other) const {
@@ -72,6 +77,7 @@ class CORE_EXPORT AnimationTimeDelta {
AnimationTimeDelta operator-(AnimationTimeDelta other) const {
return AnimationTimeDelta(delta_ - other.delta_);
}
+ AnimationTimeDelta operator-() { return AnimationTimeDelta(-delta_); }
template <typename T>
AnimationTimeDelta operator*(T a) const {
return AnimationTimeDelta(delta_ * a);
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_timeline.cc b/chromium/third_party/blink/renderer/core/animation/animation_timeline.cc
index 3a3859f3f1c..e6a822b50c8 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_timeline.cc
@@ -46,6 +46,12 @@ void AnimationTimeline::currentTime(CSSNumberish& currentTime) {
: CSSNumberish();
}
+base::Optional<AnimationTimeDelta> AnimationTimeline::CurrentTime() {
+ base::Optional<base::TimeDelta> result = CurrentPhaseAndTime().time;
+ return result ? base::make_optional(AnimationTimeDelta(result.value()))
+ : base::nullopt;
+}
+
base::Optional<double> AnimationTimeline::CurrentTimeMilliseconds() {
base::Optional<base::TimeDelta> result = CurrentPhaseAndTime().time;
return result ? base::make_optional(result->InMillisecondsF())
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_timeline.h b/chromium/third_party/blink/renderer/core/animation/animation_timeline.h
index 6c16a91fd4e..8cc0a6252e8 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation_timeline.h
@@ -36,6 +36,7 @@ class CORE_EXPORT AnimationTimeline : public ScriptWrappable {
~AnimationTimeline() override = default;
virtual void currentTime(CSSNumberish&);
+ base::Optional<AnimationTimeDelta> CurrentTime();
base::Optional<double> CurrentTimeMilliseconds();
base::Optional<double> CurrentTimeSeconds();
@@ -48,7 +49,7 @@ class CORE_EXPORT AnimationTimeline : public ScriptWrappable {
virtual bool IsScrollTimeline() const { return false; }
virtual bool IsCSSScrollTimeline() const { return false; }
virtual bool IsActive() const = 0;
- virtual double ZeroTimeInSeconds() = 0;
+ virtual AnimationTimeDelta ZeroTime() = 0;
// https://drafts.csswg.org/web-animations/#monotonically-increasing-timeline
// A timeline is monotonically increasing if its reported current time is
// always greater than or equal than its previously reported current time.
diff --git a/chromium/third_party/blink/renderer/core/animation/build.gni b/chromium/third_party/blink/renderer/core/animation/build.gni
index 65558126ec5..acf6f02e997 100644
--- a/chromium/third_party/blink/renderer/core/animation/build.gni
+++ b/chromium/third_party/blink/renderer/core/animation/build.gni
@@ -15,6 +15,8 @@ blink_core_tests_animation = [
"css/css_animations_test.cc",
"css/css_scroll_timeline_test.cc",
"css/css_transition_data_test.cc",
+ "css_color_interpolation_type_test.cc",
+ "css_interpolation_types_map_test.cc",
"document_animations_test.cc",
"document_timeline_test.cc",
"effect_input_test.cc",
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc b/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
index 51fb92a1f8c..204c414357d 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -153,6 +153,16 @@ bool HasIncompatibleAnimations(const Element& target_element,
return false;
}
+void DefaultToUnsupportedProperty(
+ PropertyHandleSet* unsupported_properties,
+ const PropertyHandle& property,
+ CompositorAnimations::FailureReasons* reasons) {
+ (*reasons) |= CompositorAnimations::kUnsupportedCSSProperty;
+ if (unsupported_properties) {
+ unsupported_properties->insert(property);
+ }
+}
+
} // namespace
CompositorElementIdNamespace
@@ -169,10 +179,11 @@ CompositorAnimations::CompositorElementNamespaceForProperty(
return CompositorElementIdNamespace::kPrimaryTransform;
case CSSPropertyID::kFilter:
return CompositorElementIdNamespace::kEffectFilter;
+ case CSSPropertyID::kBackgroundColor:
case CSSPropertyID::kVariable:
- // TODO(crbug.com/883721): Variables should not require the target
- // element to have any composited property tree nodes - i.e. should
- // not need to check for existence of a property tree node.
+ // TODO(crbug.com/883721): Variables and background color should not
+ // require the target element to have any composited property tree nodes -
+ // i.e. should not need to check for existence of a property tree node.
// For now, variable animations target the primary animation target
// node - the effect namespace.
return CompositorElementIdNamespace::kPrimaryEffect;
@@ -272,6 +283,13 @@ CompositorAnimations::CheckCanStartEffectOnCompositor(
// Backdrop-filter pixel moving filters do not change the layer bounds
// like regular filters do, so they can still be composited.
break;
+ case CSSPropertyID::kBackgroundColor:
+ if (!RuntimeEnabledFeatures::CompositeBGColorAnimationEnabled() ||
+ !animation_to_add->CanCompositeBGColorAnim()) {
+ DefaultToUnsupportedProperty(unsupported_properties, property,
+ &reasons);
+ }
+ break;
case CSSPropertyID::kVariable: {
// Custom properties are supported only in the case of
// OffMainThreadCSSPaintEnabled, and even then only for some specific
@@ -287,10 +305,8 @@ CompositorAnimations::CheckCanStartEffectOnCompositor(
!layout_object->Style()->HasCSSPaintImagesUsingCustomProperty(
property.CustomPropertyName(),
layout_object->GetDocument())) {
- if (unsupported_properties) {
- unsupported_properties->insert(property);
- }
- reasons |= kUnsupportedCSSProperty;
+ DefaultToUnsupportedProperty(unsupported_properties, property,
+ &reasons);
}
// TODO: Add support for keyframes containing different types
if (!keyframes.front() ||
@@ -302,10 +318,8 @@ CompositorAnimations::CheckCanStartEffectOnCompositor(
} else {
// We skip the rest of the loop in this case for the same reason as
// unsupported CSS properties - see below.
- if (unsupported_properties) {
- unsupported_properties->insert(property);
- }
- reasons |= kUnsupportedCSSProperty;
+ DefaultToUnsupportedProperty(unsupported_properties, property,
+ &reasons);
continue;
}
break;
@@ -316,10 +330,8 @@ CompositorAnimations::CheckCanStartEffectOnCompositor(
// an unsupported property.
// ii. GetCompositorKeyframeValue() will be false so we will
// accidentally count this as kInvalidAnimationOrEffect as well.
- if (unsupported_properties) {
- unsupported_properties->insert(property);
- }
- reasons |= kUnsupportedCSSProperty;
+ DefaultToUnsupportedProperty(unsupported_properties, property,
+ &reasons);
continue;
}
@@ -406,7 +418,7 @@ CompositorAnimations::CheckCanStartElementOnCompositor(
(effect && effect->HasDirectCompositingReasons());
}
if (!has_direct_compositing_reasons &&
- To<KeyframeEffectModelBase>(model).HasNonVariableProperty()) {
+ To<KeyframeEffectModelBase>(model).RequiresPropertyNode()) {
reasons |= kTargetHasInvalidCompositingState;
}
} else {
@@ -696,6 +708,8 @@ void CompositorAnimations::GetAnimationOnCompositor(
DCHECK(!properties.IsEmpty());
for (const auto& property : properties) {
AtomicString custom_property_name = "";
+ CompositorPaintWorkletInput::NativePropertyType native_property_type =
+ CompositorPaintWorkletInput::NativePropertyType::kInvalid;
// If the animation duration is infinite, it doesn't make sense to scale
// the keyframe offset, so use a scale of 1.0. This is connected to
// the known issue of how the Web Animations spec handles infinite
@@ -749,6 +763,17 @@ void CompositorAnimations::GetAnimationOnCompositor(
curve = std::move(transform_curve);
break;
}
+ case CSSPropertyID::kBackgroundColor: {
+ native_property_type =
+ CompositorPaintWorkletInput::NativePropertyType::kBackgroundColor;
+ auto float_curve = std::make_unique<CompositorFloatAnimationCurve>();
+ target_property = compositor_target_property::NATIVE_PROPERTY;
+ AddKeyframesToCurve(*float_curve, values);
+ float_curve->SetTimingFunction(*timing.timing_function);
+ float_curve->SetScaledDuration(scale);
+ curve = std::move(float_curve);
+ break;
+ }
case CSSPropertyID::kVariable: {
DCHECK(RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled());
custom_property_name = property.CustomPropertyName();
@@ -776,8 +801,18 @@ void CompositorAnimations::GetAnimationOnCompositor(
}
DCHECK(curve.get());
- auto keyframe_model = std::make_unique<CompositorKeyframeModel>(
- *curve, target_property, 0, group, std::move(custom_property_name));
+ std::unique_ptr<CompositorKeyframeModel> keyframe_model;
+ if (!custom_property_name.IsEmpty()) {
+ keyframe_model = std::make_unique<CompositorKeyframeModel>(
+ *curve, target_property, 0, group, std::move(custom_property_name));
+ } else if (native_property_type !=
+ CompositorPaintWorkletInput::NativePropertyType::kInvalid) {
+ keyframe_model = std::make_unique<CompositorKeyframeModel>(
+ *curve, target_property, 0, group, native_property_type);
+ } else {
+ keyframe_model = std::make_unique<CompositorKeyframeModel>(
+ *curve, target_property, 0, group);
+ }
if (start_time)
keyframe_model->SetStartTime(start_time.value());
@@ -834,8 +869,9 @@ CompositorAnimations::CheckCanStartTransformAnimationOnCompositorForSVG(
if (layout_object->IsSVGViewportContainer()) {
// Nested SVG doesn't support transforms for now.
reasons |= kTransformRelatedPropertyCannotBeAcceleratedOnTarget;
- } else if (layout_object->IsSVGForeignObject() &&
- layout_object->StyleRef().EffectiveZoom() != 1) {
+ } else if (layout_object->StyleRef().EffectiveZoom() != 1) {
+ // TODO(crbug.com/1186312): Composited transform animation with non-1
+ // effective zoom is incorrectly scaled for now.
// TODO(crbug.com/1134775): If a foreignObject's effect zoom is not 1,
// its transform node contains an additional scale which would be removed
// by composited animation.
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations.h b/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
index ad0abb2462b..c107d8b8fed 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
@@ -47,6 +47,7 @@ class Animation;
class CompositorAnimation;
class Element;
class KeyframeEffectModelBase;
+class Node;
class PaintArtifactCompositor;
class SVGElement;
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 69121bf03e4..63147572614 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -56,7 +56,6 @@
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
@@ -183,7 +182,8 @@ class AnimationCompositorAnimationsTest : public PaintTestConfigurations,
const Timing& timing,
const KeyframeEffectModelBase& effect) {
// TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
- auto style = GetDocument().GetStyleResolver().StyleForElement(element_);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element_, StyleRecalcContext());
effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
nullptr);
return CheckCanStartEffectOnCompositor(timing, *element_.Get(), nullptr,
@@ -455,7 +455,8 @@ class AnimationCompositorAnimationsTest : public PaintTestConfigurations,
// As the compositor code only understands CompositorKeyframeValues, we must
// snapshot the effect to make those available.
// TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
- auto style = GetDocument().GetStyleResolver().StyleForElement(element_);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element_, StyleRecalcContext());
effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
nullptr);
@@ -635,7 +636,8 @@ TEST_P(AnimationCompositorAnimationsTest,
SetCustomProperty("--x", "5");
UpdateAllLifecyclePhasesForTest();
- auto style = GetDocument().GetStyleResolver().StyleForElement(element_);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element_, StyleRecalcContext());
EXPECT_TRUE(style->NonInheritedVariables());
EXPECT_TRUE(style->NonInheritedVariables()
->GetData(AtomicString("--foo"))
@@ -1334,7 +1336,7 @@ TEST_P(AnimationCompositorAnimationsTest, CanStartEffectOnCompositorBasic) {
MakeGarbageCollected<StringKeyframeEffectModel>(non_css_frames_vector);
EXPECT_TRUE(CanStartEffectOnCompositor(timing_, *non_css_frames) &
CompositorAnimations::kAnimationAffectsNonCSSProperties);
- EXPECT_TRUE(non_css_frames->HasNonVariableProperty());
+ EXPECT_TRUE(non_css_frames->RequiresPropertyNode());
// NB: Important that non_css_frames_vector goes away and cleans up
// before fake_name.
}
@@ -1737,7 +1739,7 @@ TEST_P(AnimationCompositorAnimationsTest,
keyframe_model->TargetProperty());
EXPECT_EQ(keyframe_model->GetCustomPropertyNameForTesting(),
property_name.Utf8().data());
- EXPECT_FALSE(effect->HasNonVariableProperty());
+ EXPECT_FALSE(effect->RequiresPropertyNode());
}
TEST_P(AnimationCompositorAnimationsTest,
@@ -2065,8 +2067,7 @@ TEST_P(AnimationCompositorAnimationsTest, CompositedTransformAnimation) {
ASSERT_NE(nullptr, cc_transform);
EXPECT_TRUE(cc_transform->has_potential_animation);
EXPECT_TRUE(cc_transform->is_currently_animating);
- EXPECT_EQ(cc::kNotScaled, cc_transform->starting_animation_scale);
- EXPECT_EQ(cc::kNotScaled, cc_transform->maximum_animation_scale);
+ EXPECT_EQ(1.f, cc_transform->maximum_animation_scale);
// Make sure the animation is started on the compositor.
EXPECT_EQ(
@@ -2100,7 +2101,6 @@ TEST_P(AnimationCompositorAnimationsTest, CompositedScaleAnimation) {
ASSERT_NE(nullptr, cc_transform);
EXPECT_TRUE(cc_transform->has_potential_animation);
EXPECT_TRUE(cc_transform->is_currently_animating);
- EXPECT_EQ(2.f, cc_transform->starting_animation_scale);
EXPECT_EQ(5.f, cc_transform->maximum_animation_scale);
// Make sure the animation is started on the compositor.
@@ -2242,6 +2242,9 @@ TEST_P(AnimationCompositorAnimationsTest,
<use id="use" href="#rect-useref" class="animate"/>
<use id="use-offset" href="#rect-useref" x="10" class="animate"/>
</svg>
+ <svg id="svg-zoomed" class="animate" style="zoom: 1.5">
+ <rect id="rect-zoomed" class="animate"/>
+ </svg>
)HTML");
auto CanStartAnimation = [&](const char* id) -> bool {
@@ -2261,6 +2264,9 @@ TEST_P(AnimationCompositorAnimationsTest,
EXPECT_TRUE(CanStartAnimation("use"));
EXPECT_FALSE(CanStartAnimation("use-offset"));
+ EXPECT_FALSE(CanStartAnimation("svg-zoomed"));
+ EXPECT_FALSE(CanStartAnimation("rect-zoomed"));
+
To<SVGElement>(GetDocument().getElementById("rect"))
->SetWebAnimatedAttribute(
svg_names::kXAttr,
diff --git a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h
index 83be42ab243..7bd0c3fd1b7 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h
+++ b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/animation/css/compositor_keyframe_value.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc
index d84627765c8..cede2395cd2 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc
@@ -34,7 +34,8 @@ static CompositorKeyframeValue* CreateFromTransformProperties(
CompositorKeyframeValue* CompositorKeyframeValueFactory::Create(
const PropertyHandle& property,
- const ComputedStyle& style) {
+ const ComputedStyle& style,
+ double offset) {
const CSSProperty& css_property = property.GetCSSProperty();
#if DCHECK_IS_ON()
// Variables are conditionally interpolable and compositable.
@@ -67,6 +68,9 @@ CompositorKeyframeValue* CompositorKeyframeValueFactory::Create(
return CreateFromTransformProperties(style.Scale(), style.EffectiveZoom(),
nullptr);
}
+ case CSSPropertyID::kBackgroundColor: {
+ return MakeGarbageCollected<CompositorKeyframeDouble>(offset);
+ }
case CSSPropertyID::kVariable: {
if (!RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled()) {
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h
index d4e55a9a6b1..17115618768 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h
+++ b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h
@@ -18,7 +18,8 @@ class CompositorKeyframeValueFactory {
public:
static CompositorKeyframeValue* Create(const PropertyHandle&,
- const ComputedStyle&);
+ const ComputedStyle&,
+ double offset);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animation.cc b/chromium/third_party/blink/renderer/core/animation/css/css_animation.cc
index e2e7beb7993..9e637788e15 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animation.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animation.cc
@@ -60,7 +60,7 @@ void CSSAnimation::setTimeline(AnimationTimeline* timeline) {
ignore_css_timeline_ = true;
}
-void CSSAnimation::setStartTime(base::Optional<double> start_time_ms,
+void CSSAnimation::setStartTime(CSSNumberish start_time_ms,
ExceptionState& exception_state) {
PlayStateTransitionScope scope(*this);
Animation::setStartTime(start_time_ms, exception_state);
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animation.h b/chromium/third_party/blink/renderer/core/animation/css/css_animation.h
index 745f14f4876..32bfc8a162c 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animation.h
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animation.h
@@ -51,7 +51,7 @@ class CORE_EXPORT CSSAnimation : public Animation {
void play(ExceptionState& = ASSERT_NO_EXCEPTION) override;
void reverse(ExceptionState& = ASSERT_NO_EXCEPTION) override;
void setTimeline(AnimationTimeline*) override;
- void setStartTime(base::Optional<double>, ExceptionState&) override;
+ void setStartTime(CSSNumberish, ExceptionState&) override;
// When set, subsequent changes to animation-play-state no longer affect the
// play state.
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animations.cc b/chromium/third_party/blink/renderer/core/animation/css/css_animations.cc
index 601832605c7..18dcabd7910 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -434,11 +434,11 @@ AnimationTimeDelta IterationElapsedTime(const AnimationEffect& effect,
CSSScrollTimeline* CreateCSSScrollTimeline(
Element* element,
- const CSSScrollTimeline::Options& options) {
+ CSSScrollTimeline::Options&& options) {
if (!options.IsValid())
return nullptr;
- auto* scroll_timeline =
- MakeGarbageCollected<CSSScrollTimeline>(&element->GetDocument(), options);
+ auto* scroll_timeline = MakeGarbageCollected<CSSScrollTimeline>(
+ &element->GetDocument(), std::move(options));
// It's is not allowed for a style resolve to create timelines that
// needs timing updates (i.e. AnimationTimeline::NeedsAnimationTimingUpdate()
// must return false). Servicing animations after creation preserves this
@@ -486,7 +486,7 @@ AnimationTimeline* ComputeTimeline(Element* element,
if (timeline->Matches(options))
return existing_timeline;
}
- if (auto* timeline = CreateCSSScrollTimeline(element, options))
+ if (auto* timeline = CreateCSSScrollTimeline(element, std::move(options)))
return timeline;
}
return nullptr;
@@ -760,7 +760,7 @@ void CSSAnimations::CalculateAnimationUpdate(CSSAnimationUpdate& update,
DCHECK(!is_animation_style_change);
base::Optional<TimelinePhase> inherited_phase;
- base::Optional<double> inherited_time;
+ base::Optional<AnimationTimeDelta> inherited_time;
if (timeline) {
inherited_phase = base::make_optional(timeline->Phase());
@@ -770,7 +770,7 @@ void CSSAnimations::CalculateAnimationUpdate(CSSAnimationUpdate& update,
((timeline != existing_animation->Timeline()) ||
animation->ResetsCurrentTimeOnResume())) {
if (!timeline->IsMonotonicallyIncreasing())
- inherited_time = timeline->CurrentTimeSeconds();
+ inherited_time = timeline->CurrentTime();
}
}
@@ -792,13 +792,13 @@ void CSSAnimations::CalculateAnimationUpdate(CSSAnimationUpdate& update,
ComputeTimeline(&element, timeline_name, scroll_timeline_rule,
nullptr /* existing_timeline */);
base::Optional<TimelinePhase> inherited_phase;
- base::Optional<double> inherited_time;
+ base::Optional<AnimationTimeDelta> inherited_time;
if (timeline) {
if (timeline->IsMonotonicallyIncreasing()) {
- inherited_time = 0;
+ inherited_time = AnimationTimeDelta();
} else {
inherited_phase = base::make_optional(timeline->Phase());
- inherited_time = timeline->CurrentTimeSeconds();
+ inherited_time = timeline->CurrentTime();
}
}
update.StartAnimation(
@@ -1039,8 +1039,9 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) {
// Set the current time as the start time for retargeted transitions
if (retargeted_compositor_transitions.Contains(property)) {
- animation->setStartTime(
- element->GetDocument().Timeline().CurrentTimeMilliseconds());
+ CSSNumberish current_time;
+ element->GetDocument().Timeline().currentTime(current_time);
+ animation->setStartTime(current_time);
}
animation->Update(kTimingUpdateOnDemand);
running_transition->animation = animation;
@@ -1239,9 +1240,9 @@ void CSSAnimations::CalculateTransitionUpdateForProperty(
if (property.GetCSSProperty().IsCompositableProperty()) {
CompositorKeyframeValue* from = CompositorKeyframeValueFactory::Create(
- property, *state.before_change_style);
- CompositorKeyframeValue* to =
- CompositorKeyframeValueFactory::Create(property, state.style);
+ property, *state.before_change_style, start_keyframe->Offset().value());
+ CompositorKeyframeValue* to = CompositorKeyframeValueFactory::Create(
+ property, state.style, end_keyframe->Offset().value());
start_keyframe->SetCompositorValue(from);
end_keyframe->SetCompositorValue(to);
}
@@ -1253,8 +1254,8 @@ void CSSAnimations::CalculateTransitionUpdateForProperty(
state.update.StartTransition(
property, state.before_change_style, state.cloned_style,
reversing_adjusted_start_value, reversing_shortening_factor,
- *MakeGarbageCollected<InertEffect>(model, timing, false, 0,
- base::nullopt));
+ *MakeGarbageCollected<InertEffect>(model, timing, false,
+ AnimationTimeDelta(), base::nullopt));
DCHECK(!state.animating_element->GetElementAnimations() ||
!state.animating_element->GetElementAnimations()
->IsAnimationStyleChange());
@@ -1288,7 +1289,7 @@ void CSSAnimations::CalculateTransitionUpdateForStandardProperty(
}
CSSPropertyID resolved_id =
- resolveCSSPropertyID(transition_property.unresolved_property);
+ ResolveCSSPropertyID(transition_property.unresolved_property);
bool animate_all = resolved_id == CSSPropertyID::kAll;
const StylePropertyShorthand& property_list =
animate_all ? PropertiesForTransitionAll()
@@ -1299,7 +1300,7 @@ void CSSAnimations::CalculateTransitionUpdateForStandardProperty(
CSSPropertyID longhand_id =
property_list.length() ? property_list.properties()[i]->PropertyID()
: resolved_id;
- DCHECK_GE(longhand_id, firstCSSProperty);
+ DCHECK_GE(longhand_id, kFirstCSSProperty);
const CSSProperty& property =
CSSProperty::Get(longhand_id)
.ResolveDirectionAwareProperty(style.Direction(),
@@ -1425,19 +1426,27 @@ scoped_refptr<const ComputedStyle> CSSAnimations::CalculateBeforeChangeStyle(
a, b, Animation::CompareAnimationsOrdering::kPointerOrder);
});
- // Sample animations and add to the interpolations map.
+ // Sample animations and add to the interpolatzions map.
for (Animation* animation : animations) {
- base::Optional<double> current_time = animation->currentTime();
- if (!current_time)
+ CSSNumberish current_time_numberish;
+ animation->currentTime(current_time_numberish);
+ if (current_time_numberish.IsNull())
continue;
+ // CSSNumericValue is not yet supported, verify that it is not used
+ DCHECK(!current_time_numberish.IsCSSNumericValue());
+
+ base::Optional<AnimationTimeDelta> current_time =
+ AnimationTimeDelta::FromMillisecondsD(
+ current_time_numberish.GetAsDouble());
+
auto* effect = DynamicTo<KeyframeEffect>(animation->effect());
if (!effect)
continue;
auto* inert_animation_for_sampling = MakeGarbageCollected<InertEffect>(
- effect->Model(), effect->SpecifiedTiming(), false,
- current_time.value() / 1000, base::nullopt);
+ effect->Model(), effect->SpecifiedTiming(), false, current_time,
+ base::nullopt);
HeapVector<Member<Interpolation>> sample;
inert_animation_for_sampling->Sample(sample);
@@ -1692,10 +1701,9 @@ void CSSAnimations::AnimationEventDelegate::OnEventCondition(
previous_phase_ != Timing::kPhaseAfter) {
// TODO(crbug.com/1059968): Determine if animation direction or playback
// rate factor into the calculation of the elapsed time.
- double cancel_time = animation_node.GetCancelTime();
+ AnimationTimeDelta cancel_time = animation_node.GetCancelTime();
MaybeDispatch(Document::kAnimationCancelListener,
- event_type_names::kAnimationcancel,
- AnimationTimeDelta::FromSecondsD(cancel_time));
+ event_type_names::kAnimationcancel, cancel_time);
}
if (!phase_change && current_phase == Timing::kPhaseActive &&
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc b/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
index 0857a0e4daa..9982f48ab31 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/animation/animation.h"
#include "third_party/blink/renderer/core/animation/document_timeline.h"
#include "third_party/blink/renderer/core/animation/element_animations.h"
+#include "third_party/blink/renderer/core/css/cssom/css_numeric_value.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
@@ -38,7 +39,7 @@ class CSSAnimationsTest : public RenderingTest {
SetUpAnimationClockForTesting();
// Advance timer to document time.
platform()->AdvanceClockSeconds(
- GetDocument().Timeline().ZeroTime().since_origin().InSecondsF());
+ GetDocument().Timeline().ZeroTime().InSecondsF());
}
void TearDown() override {
@@ -263,8 +264,9 @@ class CSSAnimationsCompositorSyncTest : public CSSAnimationsTest {
void VerifyCompositorOpacity(double expected_value) {
cc::KeyframeModel* keyframe_model = GetCompositorKeyframeForOpacity();
base::TimeDelta iteration_time = CompositorIterationTime();
- const cc::FloatAnimationCurve* opacity_curve =
- keyframe_model->curve()->ToFloatAnimationCurve();
+ const gfx::FloatAnimationCurve* opacity_curve =
+ gfx::FloatAnimationCurve::ToFloatAnimationCurve(
+ keyframe_model->curve());
EXPECT_NEAR(expected_value, opacity_curve->GetValue(iteration_time),
kTolerance);
}
@@ -347,15 +349,21 @@ TEST_F(CSSAnimationsCompositorSyncTest, SetStartTime) {
Animation* animation = GetAnimation();
int compositor_group = animation->CompositorGroup();
+ CSSNumberish start_time, current_time;
+ animation->startTime(start_time);
+ animation->currentTime(current_time);
+
// Partially rewind the animation via setStartTime.
- double new_start_time =
- animation->startTime().value() + animation->currentTime().value() / 2;
+ CSSNumberish new_start_time = CSSNumberish::FromDouble(
+ start_time.GetAsDouble() + (current_time.GetAsDouble() / 2));
+
animation->setStartTime(new_start_time, ASSERT_NO_EXCEPTION);
UpdateAllLifecyclePhasesForTest();
// Verify blink updates.
- EXPECT_NEAR(250, animation->currentTime().value(),
- kTimeToleranceMilliseconds);
+ animation->currentTime(current_time);
+ EXPECT_TRUE(current_time.IsDouble());
+ EXPECT_NEAR(250, current_time.GetAsDouble(), kTimeToleranceMilliseconds);
EXPECT_NEAR(0.75, element_->GetComputedStyle()->Opacity(), kTolerance);
// Compositor animation needs to restart and will have a new compositor group.
@@ -386,12 +394,14 @@ TEST_F(CSSAnimationsCompositorSyncTest, SetCurrentTime) {
int compositor_group = animation->CompositorGroup();
// Advance current time.
- animation->setCurrentTime(750, ASSERT_NO_EXCEPTION);
+ animation->setCurrentTime(CSSNumberish::FromDouble(750), ASSERT_NO_EXCEPTION);
UpdateAllLifecyclePhasesForTest();
// Verify blink updates.
- EXPECT_NEAR(750, animation->currentTime().value(),
- kTimeToleranceMilliseconds);
+ CSSNumberish current_time;
+ animation->currentTime(current_time);
+ EXPECT_TRUE(current_time.IsDouble());
+ EXPECT_NEAR(750, current_time.GetAsDouble(), kTimeToleranceMilliseconds);
EXPECT_NEAR(0.25, element_->GetComputedStyle()->Opacity(), kTolerance);
// Compositor animation needs to restart and will have a new compositor group.
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
index 179646a550c..d63409c1c28 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
@@ -82,8 +82,10 @@ double ComputeElementOffsetThreshold(const CSSValue* value) {
ScrollTimelineElementBasedOffset* ComputeElementBasedOffset(
Document& document,
const cssvalue::CSSElementOffsetValue* value) {
- auto* offset = MakeGarbageCollected<ScrollTimelineElementBasedOffset>();
- offset->setTarget(ComputeElementOffsetTarget(document, value->Target()));
+ auto* offset = ScrollTimelineElementBasedOffset::Create();
+ Element* target = ComputeElementOffsetTarget(document, value->Target());
+ if (target)
+ offset->setTarget(target);
offset->setEdge(ComputeElementOffsetEdge(value->Edge()));
offset->setThreshold(ComputeElementOffsetThreshold(value->Threshold()));
return offset;
@@ -121,23 +123,22 @@ ScrollTimelineOffset* ComputeScrollOffset(Document& document,
return MakeGarbageCollected<ScrollTimelineOffset>();
}
-HeapVector<Member<ScrollTimelineOffset>>* ComputeScrollOffsets(
+HeapVector<Member<ScrollTimelineOffset>> ComputeScrollOffsets(
Document& document,
const CSSValue* start,
const CSSValue* end) {
- auto* offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
+ HeapVector<Member<ScrollTimelineOffset>> offsets;
- bool start_is_auto = IsAuto(start) || !start;
- bool end_is_auto = IsAuto(end) || !end;
+ const bool start_is_auto = !start || IsAuto(start);
+ const bool end_is_auto = !end || IsAuto(end);
// TODO(crbug.com/1094014): scroll_offsets will replace start and end
// offsets once spec decision on multiple scroll offsets is finalized.
// https://github.com/w3c/csswg-drafts/issues/4912
if (!start_is_auto)
- offsets->push_back(ComputeScrollOffset(document, start));
+ offsets.push_back(ComputeScrollOffset(document, start));
if (!end_is_auto || !start_is_auto)
- offsets->push_back(ComputeScrollOffset(document, end));
+ offsets.push_back(ComputeScrollOffset(document, end));
return offsets;
}
@@ -212,11 +213,11 @@ CSSScrollTimeline::Options::Options(Element* element,
time_range_(ComputeTimeRange(rule.GetTimeRange())),
rule_(&rule) {}
-CSSScrollTimeline::CSSScrollTimeline(Document* document, const Options& options)
+CSSScrollTimeline::CSSScrollTimeline(Document* document, Options&& options)
: ScrollTimeline(document,
options.source_,
options.direction_,
- options.offsets_,
+ std::move(options.offsets_),
*options.time_range_),
rule_(options.rule_) {
DCHECK(options.IsValid());
@@ -229,10 +230,9 @@ const AtomicString& CSSScrollTimeline::Name() const {
}
bool CSSScrollTimeline::Matches(const Options& options) const {
- DCHECK(options.offsets_);
return (scrollSource() == options.source_) &&
(GetOrientation() == options.direction_) &&
- (ScrollOffsetsEqual(*options.offsets_)) &&
+ (ScrollOffsetsEqual(options.offsets_)) &&
(GetTimeRange() == options.time_range_) && (rule_ == options.rule_);
}
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h
index c06419f378e..ef6811a5c33 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h
@@ -33,12 +33,12 @@ class CORE_EXPORT CSSScrollTimeline : public ScrollTimeline {
Element* source_;
ScrollTimeline::ScrollDirection direction_;
- HeapVector<Member<ScrollTimelineOffset>>* offsets_;
+ HeapVector<Member<ScrollTimelineOffset>> offsets_;
base::Optional<double> time_range_;
StyleRuleScrollTimeline* rule_;
};
- CSSScrollTimeline(Document*, const Options&);
+ CSSScrollTimeline(Document*, Options&&);
const AtomicString& Name() const;
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
index a693940dd30..3e6b652a202 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
@@ -4,10 +4,16 @@
#include "third_party/blink/renderer/core/animation/css/css_scroll_timeline.h"
+#include "third_party/blink/renderer/core/animation/document_animations.h"
#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/dom/id_target_observer_registry.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/html/html_div_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_style_element.h"
+#include "third_party/blink/renderer/core/resize_observer/resize_observer.h"
+#include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -22,6 +28,10 @@ class CSSScrollTimelineTest : public PageTestBase,
bool HasObservers(const AtomicString& id) {
return GetDocument().GetIdTargetObserverRegistry().HasObservers(id);
}
+
+ DocumentAnimations& GetDocumentAnimations() const {
+ return GetDocument().GetDocumentAnimations();
+ }
};
TEST_F(CSSScrollTimelineTest, IdObserverElementRemoval) {
@@ -217,4 +227,130 @@ TEST_F(CSSScrollTimelineTest, SharedTimelines) {
EXPECT_NE(animations2[2]->timeline(), animations1[1]->timeline());
}
+TEST_F(CSSScrollTimelineTest, MultipleLifecyclePasses) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ @keyframes anim {
+ from { color: green; }
+ to { color: green; }
+ }
+ @scroll-timeline timeline {
+ source: selector(#scroller);
+ time-range: 10s;
+ start: auto;
+ end: auto;
+ }
+ #scroller {
+ height: 100px;
+ overflow: scroll;
+ }
+ #scroller > div {
+ height: 200px;
+ }
+ #element {
+ color: red;
+ animation: anim 10s timeline;
+ }
+ </style>
+ <div id=element></div>
+ <div id=scroller>
+ <div id=contents></div>
+ </div>
+ )HTML");
+
+ Element* element = GetDocument().getElementById("element");
+ ASSERT_TRUE(element);
+
+ // According to the rules of the spec [1], the timeline is now inactive,
+ // because #scroller did not have a layout box at the time style recalc
+ // for #element happened.
+ //
+ // However, we do an additional style/layout pass if we detect new
+ // CSSScrollTimelines in this situation, hence we ultimately do expect
+ // the animation to apply [2].
+ //
+ // See also DocumentAnimations::ValidateTimelines.
+ //
+ // [1] https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
+ // [2] https://github.com/w3c/csswg-drafts/issues/5261
+ EXPECT_EQ(MakeRGB(0, 128, 0),
+ element->GetComputedStyle()->VisitedDependentColor(
+ GetCSSPropertyColor()));
+}
+
+namespace {
+
+class AnimationTriggeringDelegate : public ResizeObserver::Delegate {
+ public:
+ explicit AnimationTriggeringDelegate(Element* element) : element_(element) {}
+
+ void OnResize(
+ const HeapVector<Member<ResizeObserverEntry>>& entries) override {
+ element_->setAttribute(blink::html_names::kClassAttr, "animate");
+ }
+
+ void Trace(Visitor* visitor) const override {
+ ResizeObserver::Delegate::Trace(visitor);
+ visitor->Trace(element_);
+ }
+
+ private:
+ Member<Element> element_;
+};
+
+} // namespace
+
+TEST_F(CSSScrollTimelineTest, ResizeObserverTriggeredTimelines) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ @keyframes anim {
+ from { width: 100px; }
+ to { width: 100px; }
+ }
+ @scroll-timeline timeline {
+ source: selector(#scroller);
+ time-range: 10s;
+ }
+ #scroller {
+ height: 100px;
+ overflow: scroll;
+ }
+ #scroller > div {
+ height: 200px;
+ }
+ #element {
+ width: 1px;
+ }
+ #element.animate {
+ animation: anim 10s timeline;
+ }
+ </style>
+ <div id=main></div>
+ )HTML");
+
+ ASSERT_TRUE(
+ GetDocumentAnimations().GetUnvalidatedTimelinesForTesting().IsEmpty());
+
+ Element* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+ element->setAttribute(blink::html_names::kIdAttr, "element");
+
+ Element* scroller = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+ scroller->setAttribute(blink::html_names::kIdAttr, "scroller");
+ scroller->AppendChild(MakeGarbageCollected<HTMLDivElement>(GetDocument()));
+
+ Element* main = GetDocument().getElementById("main");
+ ASSERT_TRUE(main);
+ main->AppendChild(element);
+ main->AppendChild(scroller);
+
+ auto* delegate = MakeGarbageCollected<AnimationTriggeringDelegate>(element);
+ ResizeObserver* observer =
+ ResizeObserver::Create(GetDocument().domWindow(), delegate);
+ observer->observe(element);
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(1u,
+ GetDocumentAnimations().GetUnvalidatedTimelinesForTesting().size());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.cc
new file mode 100644
index 00000000000..d0552b1a8d7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.cc
@@ -0,0 +1,164 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h"
+#include "third_party/blink/renderer/core/css/resolver/style_builder_converter.h"
+#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/style/style_aspect_ratio.h"
+
+namespace blink {
+
+class CSSAspectRatioNonInterpolableValue final : public NonInterpolableValue {
+ public:
+ ~CSSAspectRatioNonInterpolableValue() final = default;
+
+ static scoped_refptr<CSSAspectRatioNonInterpolableValue> Create(
+ StyleAspectRatio aspect_ratio) {
+ return base::AdoptRef(
+ new CSSAspectRatioNonInterpolableValue(aspect_ratio.GetType()));
+ }
+
+ EAspectRatioType GetAspectRatioType() const { return type_; }
+
+ bool IsCompatibleWith(const CSSAspectRatioNonInterpolableValue& other) const {
+ if (GetAspectRatioType() == EAspectRatioType::kAuto ||
+ GetAspectRatioType() != other.GetAspectRatioType())
+ return false;
+ return true;
+ }
+
+ DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
+
+ private:
+ explicit CSSAspectRatioNonInterpolableValue(EAspectRatioType type)
+ : type_(type) {}
+
+ EAspectRatioType type_;
+};
+
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSAspectRatioNonInterpolableValue);
+template <>
+struct DowncastTraits<CSSAspectRatioNonInterpolableValue> {
+ static bool AllowFrom(const NonInterpolableValue* value) {
+ return value && AllowFrom(*value);
+ }
+ static bool AllowFrom(const NonInterpolableValue& value) {
+ return value.GetType() == CSSAspectRatioNonInterpolableValue::static_type_;
+ }
+};
+
+class InheritedAspectRatioChecker
+ : public CSSInterpolationType::CSSConversionChecker {
+ public:
+ explicit InheritedAspectRatioChecker(StyleAspectRatio aspect_ratio)
+ : aspect_ratio_(aspect_ratio) {}
+
+ private:
+ bool IsValid(const StyleResolverState& state,
+ const InterpolationValue& underlying) const final {
+ return state.ParentStyle()->AspectRatio() == aspect_ratio_;
+ }
+
+ const StyleAspectRatio aspect_ratio_;
+};
+
+std::unique_ptr<InterpolableValue>
+CSSAspectRatioInterpolationType::CreateInterpolableAspectRatio(
+ const StyleAspectRatio& aspect_ratio) {
+ std::unique_ptr<InterpolableAspectRatio> result =
+ InterpolableAspectRatio::MaybeCreate(aspect_ratio);
+ return std::move(result);
+}
+
+PairwiseInterpolationValue CSSAspectRatioInterpolationType::MaybeMergeSingles(
+ InterpolationValue&& start,
+ InterpolationValue&& end) const {
+ if (!To<CSSAspectRatioNonInterpolableValue>(*start.non_interpolable_value)
+ .IsCompatibleWith(To<CSSAspectRatioNonInterpolableValue>(
+ *end.non_interpolable_value))) {
+ return nullptr;
+ }
+ return PairwiseInterpolationValue(std::move(start.interpolable_value),
+ std::move(end.interpolable_value),
+ std::move(start.non_interpolable_value));
+}
+
+InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertNeutral(
+ const InterpolationValue& underlying,
+ ConversionCheckers& conversion_checkers) const {
+ return InterpolationValue(underlying.interpolable_value->CloneAndZero(),
+ underlying.non_interpolable_value);
+}
+
+InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertInitial(
+ const StyleResolverState&,
+ ConversionCheckers& conversion_checkers) const {
+ StyleAspectRatio initial_ratio = ComputedStyle::InitialStyle().AspectRatio();
+ return InterpolationValue(
+ CreateInterpolableAspectRatio(initial_ratio),
+ CSSAspectRatioNonInterpolableValue::Create(initial_ratio));
+}
+
+InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertInherit(
+ const StyleResolverState& state,
+ ConversionCheckers& conversion_checkers) const {
+ if (!state.ParentStyle())
+ return nullptr;
+
+ StyleAspectRatio inherited_aspect_ratio = state.ParentStyle()->AspectRatio();
+ conversion_checkers.push_back(
+ std::make_unique<InheritedAspectRatioChecker>(inherited_aspect_ratio));
+ if (inherited_aspect_ratio.IsAuto())
+ return nullptr;
+
+ return InterpolationValue(
+ CreateInterpolableAspectRatio(inherited_aspect_ratio),
+ CSSAspectRatioNonInterpolableValue::Create(inherited_aspect_ratio));
+}
+
+InterpolationValue
+CSSAspectRatioInterpolationType::MaybeConvertStandardPropertyUnderlyingValue(
+ const ComputedStyle& style) const {
+ return InterpolationValue(
+ CreateInterpolableAspectRatio(style.AspectRatio()),
+ CSSAspectRatioNonInterpolableValue::Create(style.AspectRatio()));
+}
+
+InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertValue(
+ const CSSValue& value,
+ const StyleResolverState* state,
+ ConversionCheckers&) const {
+ StyleAspectRatio ratio =
+ StyleBuilderConverter::ConvertAspectRatio(*state, value);
+ return InterpolationValue(CreateInterpolableAspectRatio(ratio),
+ CSSAspectRatioNonInterpolableValue::Create(ratio));
+}
+
+void CSSAspectRatioInterpolationType::ApplyStandardPropertyValue(
+ const InterpolableValue& interpolable_value,
+ const NonInterpolableValue* non_interpolable_value,
+ StyleResolverState& state) const {
+ const auto& aspect_ratio = To<InterpolableAspectRatio>(interpolable_value);
+ state.Style()->SetAspectRatio(StyleAspectRatio(
+ To<CSSAspectRatioNonInterpolableValue>(non_interpolable_value)
+ ->GetAspectRatioType(),
+ aspect_ratio.GetRatio()));
+}
+void CSSAspectRatioInterpolationType::Composite(
+ UnderlyingValueOwner& underlying_value_owner,
+ double underlying_fraction,
+ const InterpolationValue& value,
+ double interpolation_fraction) const {
+ underlying_value_owner.MutableValue().interpolable_value->ScaleAndAdd(
+ underlying_fraction, *value.interpolable_value);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h b/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h
new file mode 100644
index 00000000000..93d854058f7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h
@@ -0,0 +1,53 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_ASPECT_RATIO_INTERPOLATION_TYPE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_ASPECT_RATIO_INTERPOLATION_TYPE_H_
+
+#include "third_party/blink/renderer/core/animation/css_interpolation_type.h"
+#include "third_party/blink/renderer/core/css_value_keywords.h"
+
+namespace blink {
+
+class StyleAspectRatio;
+
+class CSSAspectRatioInterpolationType : public CSSInterpolationType {
+ public:
+ explicit CSSAspectRatioInterpolationType(PropertyHandle property)
+ : CSSInterpolationType(property) {
+ DCHECK_EQ(CSSPropertyID::kAspectRatio,
+ property.GetCSSProperty().PropertyID());
+ }
+
+ InterpolationValue MaybeConvertStandardPropertyUnderlyingValue(
+ const ComputedStyle&) const final;
+ PairwiseInterpolationValue MaybeMergeSingles(
+ InterpolationValue&& start,
+ InterpolationValue&& end) const final;
+ void ApplyStandardPropertyValue(const InterpolableValue&,
+ const NonInterpolableValue*,
+ StyleResolverState&) const final;
+ void Composite(UnderlyingValueOwner&,
+ double underlying_fraction,
+ const InterpolationValue&,
+ double interpolation_fraction) const final;
+
+ static std::unique_ptr<InterpolableValue> CreateInterpolableAspectRatio(
+ const StyleAspectRatio&);
+
+ private:
+ InterpolationValue MaybeConvertNeutral(const InterpolationValue& underlying,
+ ConversionCheckers&) const final;
+ InterpolationValue MaybeConvertInitial(const StyleResolverState&,
+ ConversionCheckers&) const final;
+ InterpolationValue MaybeConvertInherit(const StyleResolverState&,
+ ConversionCheckers&) const final;
+ InterpolationValue MaybeConvertValue(const CSSValue&,
+ const StyleResolverState*,
+ ConversionCheckers&) const final;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_ASPECT_RATIO_INTERPOLATION_TYPE_H_
diff --git a/chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
index 1bb38aa0905..57b3fe7781d 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
@@ -34,8 +34,6 @@ const BasicShape* GetBasicShape(const CSSProperty& property,
return nullptr;
return style.ShapeOutside()->Shape();
case CSSPropertyID::kClipPath: {
- if (!style.ClipPath())
- return nullptr;
auto* clip_path_operation =
DynamicTo<ShapeClipPathOperation>(style.ClipPath());
if (!clip_path_operation)
diff --git a/chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc
index 1a816361073..09adb2a97fb 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc
@@ -88,7 +88,7 @@ class InheritedClipChecker : public CSSInterpolationType::CSSConversionChecker {
const Vector<Length> inherited_length_list_;
};
-class CSSClipNonInterpolableValue : public NonInterpolableValue {
+class CSSClipNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSClipNonInterpolableValue() final = default;
@@ -121,7 +121,7 @@ struct DowncastTraits<CSSClipNonInterpolableValue> {
}
};
-class UnderlyingAutosChecker
+class UnderlyingAutosChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit UnderlyingAutosChecker(const ClipAutos& underlying_autos)
diff --git a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
index 7276cf1c59f..5f2a4f6b362 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
@@ -68,7 +68,9 @@ CSSColorInterpolationType::CreateInterpolableColor(CSSValueID keyword) {
case CSSValueID::kInternalQuirkInherit:
return CreateInterpolableColorForIndex(kQuirkInherit);
case CSSValueID::kWebkitFocusRingColor:
- return CreateInterpolableColor(LayoutTheme::GetTheme().FocusRingColor());
+ // TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
+ return CreateInterpolableColor(LayoutTheme::GetTheme().FocusRingColor(
+ ComputedStyle::InitialStyle().UsedColorScheme()));
default:
DCHECK(StyleColor::IsColorKeyword(keyword));
// TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
@@ -96,6 +98,20 @@ CSSColorInterpolationType::MaybeCreateInterpolableColor(const CSSValue& value) {
return CreateInterpolableColor(identifier_value->GetValueID());
}
+Color CSSColorInterpolationType::GetRGBA(const InterpolableValue& value) {
+ const InterpolableList& list = To<InterpolableList>(value);
+ DCHECK_GE(list.length(), kAlpha);
+ double color[kAlpha + 1];
+ for (unsigned i = kRed; i <= kAlpha; i++) {
+ const InterpolableValue& current_value = *(list.Get(i));
+ color[i] = To<InterpolableNumber>(current_value).Value();
+ }
+ return Color(MakeRGBA(std::round(color[kRed] / color[kAlpha]),
+ std::round(color[kGreen] / color[kAlpha]),
+ std::round(color[kBlue] / color[kAlpha]),
+ color[kAlpha]));
+}
+
static void AddPremultipliedColor(double& red,
double& green,
double& blue,
@@ -141,8 +157,9 @@ Color CSSColorInterpolationType::ResolveInterpolableColor(
*state.Style())
.Access();
}
- AddPremultipliedColor(red, green, blue, alpha, currentcolor_fraction,
- current_style_color.GetColor());
+ AddPremultipliedColor(
+ red, green, blue, alpha, currentcolor_fraction,
+ current_style_color.Resolve(Color(), state.Style()->UsedColorScheme()));
}
const TextLinkColors& colors = state.GetDocument().GetTextLinkColors();
if (double webkit_activelink_fraction =
diff --git a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h
index 7708b1d428b..538e1d9171e 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h
+++ b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h
@@ -15,7 +15,7 @@ namespace blink {
class StyleColor;
struct OptionalStyleColor;
-class CSSColorInterpolationType : public CSSInterpolationType {
+class CORE_EXPORT CSSColorInterpolationType : public CSSInterpolationType {
public:
CSSColorInterpolationType(PropertyHandle property,
const PropertyRegistration* registration = nullptr)
@@ -44,6 +44,10 @@ class CSSColorInterpolationType : public CSSInterpolationType {
bool is_visited = false,
bool is_text_decoration = false);
+ // Extract color info from a InterpolableValue-result, the input value must be
+ // a InterpolableList.
+ static Color GetRGBA(const InterpolableValue&);
+
private:
InterpolationValue MaybeConvertNeutral(const InterpolationValue& underlying,
ConversionCheckers&) const final;
diff --git a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type_test.cc b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type_test.cc
new file mode 100644
index 00000000000..3cc0c4ee5f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type_test.cc
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/css_color_interpolation_type.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+
+namespace blink {
+
+TEST(CSSColorInterpolationTypeTest, GetRGBA1) {
+ Color color(230, 120, 0, 255);
+ EXPECT_EQ(color,
+ CSSColorInterpolationType::GetRGBA(
+ *CSSColorInterpolationType::CreateInterpolableColor(color)));
+}
+
+TEST(CSSColorInterpolationTypeTest, GetRGBA2) {
+ Color color(100, 190, 0, 1);
+ EXPECT_EQ(color,
+ CSSColorInterpolationType::GetRGBA(
+ *CSSColorInterpolationType::CreateInterpolableColor(color)));
+}
+
+TEST(CSSColorInterpolationTypeTest, GetRGBA3) {
+ Color color(35, 140, 10, 10);
+ EXPECT_EQ(color,
+ CSSColorInterpolationType::GetRGBA(
+ *CSSColorInterpolationType::CreateInterpolableColor(color)));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h b/chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h
index 501fc9c4f09..ccd7a7045d0 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h
+++ b/chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h
@@ -11,7 +11,8 @@
namespace blink {
-class CORE_EXPORT CSSDefaultNonInterpolableValue : public NonInterpolableValue {
+class CORE_EXPORT CSSDefaultNonInterpolableValue final
+ : public NonInterpolableValue {
public:
~CSSDefaultNonInterpolableValue() final = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
index bee89cee486..c5d8b93ccfd 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
@@ -16,7 +16,7 @@
namespace blink {
-class CSSFontVariationSettingsNonInterpolableValue
+class CSSFontVariationSettingsNonInterpolableValue final
: public NonInterpolableValue {
public:
~CSSFontVariationSettingsNonInterpolableValue() final = default;
@@ -65,7 +65,8 @@ static bool TagsMatch(const NonInterpolableValue& a,
return GetTags(a) == GetTags(b);
}
-class UnderlyingTagsChecker : public InterpolationType::ConversionChecker {
+class UnderlyingTagsChecker final
+ : public InterpolationType::ConversionChecker {
public:
explicit UnderlyingTagsChecker(const Vector<uint32_t>& tags) : tags_(tags) {}
~UnderlyingTagsChecker() final = default;
@@ -79,7 +80,7 @@ class UnderlyingTagsChecker : public InterpolationType::ConversionChecker {
const Vector<uint32_t> tags_;
};
-class InheritedFontVariationSettingsChecker
+class InheritedFontVariationSettingsChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit InheritedFontVariationSettingsChecker(
diff --git a/chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc
index b7d1d7c02f0..d52bbbf5a33 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc
@@ -34,7 +34,7 @@ const StyleImage* GetStyleImage(const CSSProperty& property,
}
} // namespace
-class CSSImageNonInterpolableValue : public NonInterpolableValue {
+class CSSImageNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSImageNonInterpolableValue() final = default;
@@ -165,7 +165,7 @@ bool CSSImageInterpolationType::EqualNonInterpolableValues(
To<CSSImageNonInterpolableValue>(*b));
}
-class UnderlyingImageChecker
+class UnderlyingImageChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
UnderlyingImageChecker(const InterpolationValue& underlying)
@@ -203,7 +203,7 @@ InterpolationValue CSSImageInterpolationType::MaybeConvertInitial(
return nullptr;
}
-class InheritedImageChecker
+class InheritedImageChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
InheritedImageChecker(const CSSProperty& property,
diff --git a/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
index 52fc77278e9..e3090ccf7fd 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
@@ -18,7 +18,7 @@
namespace blink {
-class UnderlyingImageListChecker
+class UnderlyingImageListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit UnderlyingImageListChecker(const InterpolationValue& underlying)
@@ -65,7 +65,7 @@ InterpolationValue CSSImageListInterpolationType::MaybeConvertStyleImageList(
});
}
-class InheritedImageListChecker
+class InheritedImageListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
InheritedImageListChecker(const CSSProperty& property,
diff --git a/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
index 71ea57ec1e4..27982868f56 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
#include "third_party/blink/renderer/core/animation/css_angle_interpolation_type.h"
+#include "third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_border_image_length_box_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_clip_interpolation_type.h"
@@ -83,28 +84,22 @@ const InterpolationTypes& CSSInterpolationTypesMap::Get(
DEFINE_STATIC_LOCAL(ApplicableTypesMap, all_applicable_types_map, ());
DEFINE_STATIC_LOCAL(ApplicableTypesMap, composited_applicable_types_map, ());
- ApplicableTypesMap& applicable_types_map =
- allow_all_animations_ ? all_applicable_types_map
- : composited_applicable_types_map;
-
- auto entry = applicable_types_map.find(property);
- bool found_entry = entry != applicable_types_map.end();
-
// Custom property interpolation types may change over time so don't trust the
- // applicableTypesMap without checking the registry.
+ // applicable_types_map without checking the registry. Also since the static
+ // map is shared between documents, the registered type may be different in
+ // the different documents.
if (registry_ && property.IsCSSCustomProperty()) {
- const auto* registration = GetRegistration(registry_, property);
- if (registration) {
- if (found_entry) {
- applicable_types_map.erase(entry);
- }
+ if (const auto* registration = GetRegistration(registry_, property))
return registration->GetInterpolationTypes();
- }
}
- if (found_entry) {
+ ApplicableTypesMap& applicable_types_map =
+ allow_all_animations_ ? all_applicable_types_map
+ : composited_applicable_types_map;
+
+ auto entry = applicable_types_map.find(property);
+ if (entry != applicable_types_map.end())
return *entry->value;
- }
std::unique_ptr<InterpolationTypes> applicable_types =
std::make_unique<InterpolationTypes>();
@@ -179,6 +174,10 @@ const InterpolationTypes& CSSInterpolationTypesMap::Get(
applicable_types->push_back(
std::make_unique<CSSLengthInterpolationType>(used_property));
break;
+ case CSSPropertyID::kAspectRatio:
+ applicable_types->push_back(
+ std::make_unique<CSSAspectRatioInterpolationType>(used_property));
+ break;
case CSSPropertyID::kFlexGrow:
case CSSPropertyID::kFlexShrink:
case CSSPropertyID::kFillOpacity:
diff --git a/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map_test.cc b/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map_test.cc
new file mode 100644
index 00000000000..8811ad19b65
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map_test.cc
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/css_interpolation_types_map.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/feature_policy/document_policy.h"
+#include "third_party/blink/renderer/core/css/css_test_helpers.h"
+#include "third_party/blink/renderer/core/css/property_registry.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/document_init.h"
+#include "third_party/blink/renderer/core/testing/null_execution_context.h"
+
+namespace blink {
+
+TEST(CSSInterpolationTypesMapTest, RegisteredCustomProperty) {
+ auto* execution_context = MakeGarbageCollected<NullExecutionContext>();
+ execution_context->SetUpSecurityContextForTesting();
+ execution_context->GetSecurityContext().SetDocumentPolicy(
+ DocumentPolicy::CreateWithHeaderPolicy({}));
+
+ DocumentInit init =
+ DocumentInit::Create().WithExecutionContext(execution_context);
+ auto* document1 = MakeGarbageCollected<Document>(init);
+ auto* document2 = MakeGarbageCollected<Document>(init);
+
+ AtomicString property_name("--x");
+ PropertyRegistration* registration =
+ css_test_helpers::CreateLengthRegistration(property_name, 0);
+ PropertyRegistry* registry = MakeGarbageCollected<PropertyRegistry>();
+ registry->RegisterProperty(property_name, *registration);
+
+ CSSInterpolationTypesMap map1(nullptr, *document1);
+ CSSInterpolationTypesMap map2(registry, *document2);
+
+ PropertyHandle handle(property_name);
+ auto& types1 = map1.Get(handle);
+ auto& types2 = map2.Get(handle);
+ EXPECT_NE(&types1, &types2);
+ EXPECT_EQ(types1.size(), 1u);
+
+ auto& types1_1 = map1.Get(handle);
+ EXPECT_EQ(&types1, &types1_1);
+
+ execution_context->NotifyContextDestroyed();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
index 12c18f32300..936b3fbf773 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
@@ -155,12 +155,14 @@ void CSSLengthInterpolationType::ApplyStandardPropertyValue(
const float kSlack = 1e-6;
const float before_length = FloatValueForLength(before, 100);
const float after_length = FloatValueForLength(after, 100);
- // Test relative difference for large values to avoid floating point
- // inaccuracies tripping the check.
- const float delta = std::abs(before_length) < kSlack
- ? after_length - before_length
- : (after_length - before_length) / before_length;
- DCHECK_LT(std::abs(delta), kSlack);
+ if (std::isfinite(before_length) && std::isfinite(after_length)) {
+ // Test relative difference for large values to avoid floating point
+ // inaccuracies tripping the check.
+ const float delta = std::abs(before_length) < kSlack
+ ? after_length - before_length
+ : (after_length - before_length) / before_length;
+ DCHECK_LT(std::abs(delta), kSlack);
+ }
#endif
return;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
index d05ce01f00f..93c37aa00ea 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
@@ -65,7 +65,7 @@ InterpolationValue CSSLengthListInterpolationType::MaybeConvertInitial(
return MaybeConvertLengthList(initial_length_list, 1);
}
-class InheritedLengthListChecker
+class InheritedLengthListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
InheritedLengthListChecker(const CSSProperty& property,
diff --git a/chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
index 61fdbd23305..8e14fe549c4 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
@@ -30,9 +30,9 @@ bool GetColor(const CSSProperty& property,
StyleColor& result) {
switch (property.PropertyID()) {
case CSSPropertyID::kFill:
- return GetColorFromPaint(style.SvgStyle().FillPaint(), result);
+ return GetColorFromPaint(style.FillPaint(), result);
case CSSPropertyID::kStroke:
- return GetColorFromPaint(style.SvgStyle().StrokePaint(), result);
+ return GetColorFromPaint(style.StrokePaint(), result);
default:
NOTREACHED();
return false;
@@ -126,15 +126,14 @@ void CSSPaintInterpolationType::ApplyStandardPropertyValue(
StyleResolverState& state) const {
Color color = CSSColorInterpolationType::ResolveInterpolableColor(
interpolable_color, state);
- SVGComputedStyle& mutable_svg_style = state.Style()->AccessSVGStyle();
switch (CssProperty().PropertyID()) {
case CSSPropertyID::kFill:
- mutable_svg_style.SetFillPaint(SVGPaint(color));
- mutable_svg_style.SetInternalVisitedFillPaint(SVGPaint(color));
+ state.Style()->SetFillPaint(SVGPaint(color));
+ state.Style()->SetInternalVisitedFillPaint(SVGPaint(color));
break;
case CSSPropertyID::kStroke:
- mutable_svg_style.SetStrokePaint(SVGPaint(color));
- mutable_svg_style.SetInternalVisitedStrokePaint(SVGPaint(color));
+ state.Style()->SetStrokePaint(SVGPaint(color));
+ state.Style()->SetInternalVisitedStrokePaint(SVGPaint(color));
break;
default:
NOTREACHED();
diff --git a/chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
index d60b39522ee..aa9fbc19052 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
@@ -24,7 +24,7 @@ const StylePath* GetPath(const CSSProperty& property,
const ComputedStyle& style) {
switch (property.PropertyID()) {
case CSSPropertyID::kD:
- return style.SvgStyle().D();
+ return style.D();
case CSSPropertyID::kOffsetPath:
return DynamicTo<StylePath>(style.OffsetPath());
case CSSPropertyID::kClipPath: {
diff --git a/chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc
index 9da7670ecb9..a61bdf0b566 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc
@@ -81,7 +81,7 @@ class InheritedScaleChecker
} // namespace
-class CSSScaleNonInterpolableValue : public NonInterpolableValue {
+class CSSScaleNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSScaleNonInterpolableValue() final = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
index 829c2921e6e..cb79a29792b 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
@@ -18,7 +18,7 @@
namespace blink {
-class UnderlyingSizeListChecker
+class UnderlyingSizeListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit UnderlyingSizeListChecker(const NonInterpolableList& underlying_list)
@@ -47,7 +47,7 @@ class UnderlyingSizeListChecker
scoped_refptr<const NonInterpolableList> underlying_list_;
};
-class InheritedSizeListChecker
+class InheritedSizeListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
InheritedSizeListChecker(const CSSProperty& property,
diff --git a/chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc
index f3156672400..711c61fa9d2 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc
@@ -13,7 +13,7 @@
namespace blink {
-class CSSVisibilityNonInterpolableValue : public NonInterpolableValue {
+class CSSVisibilityNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSVisibilityNonInterpolableValue() final = default;
@@ -59,7 +59,7 @@ struct DowncastTraits<CSSVisibilityNonInterpolableValue> {
}
};
-class UnderlyingVisibilityChecker
+class UnderlyingVisibilityChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit UnderlyingVisibilityChecker(EVisibility visibility)
diff --git a/chromium/third_party/blink/renderer/core/animation/document_animations.cc b/chromium/third_party/blink/renderer/core/animation/document_animations.cc
index 74629dfc276..c7ed01c694e 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_animations.cc
@@ -71,6 +71,7 @@ DocumentAnimations::DocumentAnimations(Document* document)
void DocumentAnimations::AddTimeline(AnimationTimeline& timeline) {
timelines_.insert(&timeline);
+ unvalidated_timelines_.insert(&timeline);
}
void DocumentAnimations::UpdateAnimationTimingForAnimationFrame() {
@@ -159,6 +160,15 @@ HeapVector<Member<Animation>> DocumentAnimations::getAnimations(
return animations;
}
+void DocumentAnimations::ValidateTimelines() {
+ for (auto& timeline : unvalidated_timelines_) {
+ if (auto* scroll_timeline = DynamicTo<CSSScrollTimeline>(timeline.Get()))
+ scroll_timeline->ValidateState();
+ }
+
+ unvalidated_timelines_.clear();
+}
+
void DocumentAnimations::CacheCSSScrollTimeline(CSSScrollTimeline& timeline) {
// We cache the least seen CSSScrollTimeline for a given name.
cached_css_timelines_.Set(timeline.Name(), &timeline);
@@ -172,6 +182,7 @@ CSSScrollTimeline* DocumentAnimations::FindCachedCSSScrollTimeline(
void DocumentAnimations::Trace(Visitor* visitor) const {
visitor->Trace(document_);
visitor->Trace(timelines_);
+ visitor->Trace(unvalidated_timelines_);
visitor->Trace(cached_css_timelines_);
}
diff --git a/chromium/third_party/blink/renderer/core/animation/document_animations.h b/chromium/third_party/blink/renderer/core/animation/document_animations.h
index f5e30f0a731..759d9f34600 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/document_animations.h
@@ -72,6 +72,22 @@ class CORE_EXPORT DocumentAnimations final
HeapVector<Member<Animation>> getAnimations(const TreeScope&);
+ // All newly created AnimationTimelines are considered "unvalidated". This
+ // means that the internal state of the timeline is considered tentative,
+ // and that computing the actual state may require an additional style/layout
+ // pass.
+ //
+ // The lifecycle update will call this function after style and layout has
+ // completed. The function will then go though all unvalidated timelines,
+ // and compare the current state snapshot to a fresh state snapshot. If they
+ // are equal, then the tentative state turned out to be correct, and no
+ // further action is needed. Otherwise, all effects targets associated with
+ // the timeline are marked for recalc, which causes the style/layout phase
+ // to run again.
+ //
+ // https://github.com/w3c/csswg-drafts/issues/5261
+ void ValidateTimelines();
+
void CacheCSSScrollTimeline(CSSScrollTimeline&);
CSSScrollTimeline* FindCachedCSSScrollTimeline(const AtomicString&);
@@ -79,6 +95,10 @@ class CORE_EXPORT DocumentAnimations final
const {
return timelines_;
}
+ const HeapHashSet<WeakMember<AnimationTimeline>>&
+ GetUnvalidatedTimelinesForTesting() const {
+ return unvalidated_timelines_;
+ }
uint64_t current_transition_generation_;
void Trace(Visitor*) const;
@@ -90,6 +110,7 @@ class CORE_EXPORT DocumentAnimations final
private:
Member<Document> document_;
HeapHashSet<WeakMember<AnimationTimeline>> timelines_;
+ HeapHashSet<WeakMember<AnimationTimeline>> unvalidated_timelines_;
// We cache CSSScrollTimelines by name, such that multiple animations using
// the same timeline can use the same CSSScrollTimeline instance.
diff --git a/chromium/third_party/blink/renderer/core/animation/document_animations_test.cc b/chromium/third_party/blink/renderer/core/animation/document_animations_test.cc
index 9e8ec4d63ba..75ab69b5cea 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_animations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_animations_test.cc
@@ -24,7 +24,7 @@ class MockAnimationTimeline : public AnimationTimeline {
MOCK_METHOD0(Phase, TimelinePhase());
MOCK_CONST_METHOD0(IsActive, bool());
- MOCK_METHOD0(ZeroTimeInSeconds, double());
+ MOCK_METHOD0(ZeroTime, AnimationTimeDelta());
MOCK_METHOD0(InitialStartTimeForAnimations,
base::Optional<base::TimeDelta>());
MOCK_METHOD0(NeedsAnimationTimingUpdate, bool());
diff --git a/chromium/third_party/blink/renderer/core/animation/document_timeline.cc b/chromium/third_party/blink/renderer/core/animation/document_timeline.cc
index c05b1f14b81..6abfb137535 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_timeline.cc
@@ -44,10 +44,11 @@ namespace {
// Returns the current animation time for a given |document|. This is
// the animation clock time capped to be at least this document's
-// ZeroTime() such that the animation time is never negative when converted.
+// CalculateZeroTime() such that the animation time is never negative when
+// converted.
base::TimeTicks CurrentAnimationTime(Document* document) {
base::TimeTicks animation_time = document->GetAnimationClock().CurrentTime();
- base::TimeTicks document_zero_time = document->Timeline().ZeroTime();
+ base::TimeTicks document_zero_time = document->Timeline().CalculateZeroTime();
// The AnimationClock time may be null or less than the local document's
// zero time if we have not generated any frames for this document yet. If
@@ -142,10 +143,11 @@ void DocumentTimeline::DocumentTimelineTiming::WakeAfter(
void DocumentTimeline::DocumentTimelineTiming::Trace(Visitor* visitor) const {
visitor->Trace(timeline_);
+ visitor->Trace(timer_);
DocumentTimeline::PlatformTiming::Trace(visitor);
}
-base::TimeTicks DocumentTimeline::ZeroTime() {
+base::TimeTicks DocumentTimeline::CalculateZeroTime() {
if (!zero_time_initialized_ && document_->Loader()) {
zero_time_ = document_->Loader()->GetTiming().ReferenceMonotonicTime() +
origin_time_;
@@ -172,12 +174,14 @@ AnimationTimeline::PhaseAndTime DocumentTimeline::CurrentPhaseAndTime() {
base::Optional<base::TimeDelta> result =
playback_rate_ == 0
- ? ZeroTime().since_origin()
- : (CurrentAnimationTime(GetDocument()) - ZeroTime()) * playback_rate_;
+ ? CalculateZeroTime().since_origin()
+ : (CurrentAnimationTime(GetDocument()) - CalculateZeroTime()) *
+ playback_rate_;
return {TimelinePhase::kActive, result};
}
-void DocumentTimeline::PauseAnimationsForTesting(double pause_time) {
+void DocumentTimeline::PauseAnimationsForTesting(
+ AnimationTimeDelta pause_time) {
for (const auto& animation : animations_needing_update_)
animation->PauseForTesting(pause_time);
ServiceAnimations(kTimingUpdateOnDemand);
diff --git a/chromium/third_party/blink/renderer/core/animation/document_timeline.h b/chromium/third_party/blink/renderer/core/animation/document_timeline.h
index a1392ecdb62..87ae16853da 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/document_timeline.h
@@ -78,12 +78,14 @@ class CORE_EXPORT DocumentTimeline : public AnimationTimeline {
// The zero time of DocumentTimeline is computed by adding a separate
// |origin_time_| from DocumentTimelineOptions.
// https://drafts.csswg.org/web-animations/#origin-time
- base::TimeTicks ZeroTime();
- double ZeroTimeInSeconds() override {
- return ZeroTime().since_origin().InSecondsF();
+ // TODO(crbug.com/1162960) Convert DocumentTimeline::zero_time_ from
+ // base::TimeTicks to AnimationTimeDelta
+ base::TimeTicks CalculateZeroTime();
+ AnimationTimeDelta ZeroTime() override {
+ return AnimationTimeDelta(CalculateZeroTime().since_origin());
}
- void PauseAnimationsForTesting(double);
+ void PauseAnimationsForTesting(AnimationTimeDelta);
void InvalidateKeyframeEffects(const TreeScope&);
@@ -107,6 +109,8 @@ class CORE_EXPORT DocumentTimeline : public AnimationTimeline {
base::TimeDelta origin_time_;
// The origin time. This is computed by adding |origin_time_| to the time
// origin of the document.
+ // TODO(crbug.com/1162960) Convert DocumentTimeline::zero_time_ from
+ // base::TimeTicks to AnimationTimeDelta
base::TimeTicks zero_time_;
bool zero_time_initialized_;
@@ -119,7 +123,7 @@ class CORE_EXPORT DocumentTimeline : public AnimationTimeline {
class DocumentTimelineTiming final : public PlatformTiming {
public:
- DocumentTimelineTiming(DocumentTimeline* timeline)
+ explicit DocumentTimelineTiming(DocumentTimeline* timeline)
: timeline_(timeline),
timer_(timeline->GetDocument()->GetTaskRunner(
TaskType::kInternalDefault),
@@ -136,7 +140,7 @@ class CORE_EXPORT DocumentTimeline : public AnimationTimeline {
private:
Member<DocumentTimeline> timeline_;
- TaskRunnerTimer<DocumentTimelineTiming> timer_;
+ HeapTaskRunnerTimer<DocumentTimelineTiming> timer_;
};
friend class AnimationDocumentTimelineTest;
diff --git a/chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc b/chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc
index f165b142f00..6df9206afa0 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/animation/keyframe_effect.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
#include "third_party/blink/renderer/core/animation/pending_animations.h"
+#include "third_party/blink/renderer/core/animation/timing_calculations.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/qualified_name.h"
@@ -53,6 +54,10 @@ namespace {
base::TimeTicks TimeTicksFromMillisecondsD(double seconds) {
return base::TimeTicks() + base::TimeDelta::FromMillisecondsD(seconds);
}
+
+#define EXPECT_TIME_NEAR(expected, value) \
+ EXPECT_NEAR((expected).InMillisecondsF(), (value).InMillisecondsF(), \
+ Animation::kTimeToleranceMs)
} // namespace
namespace blink {
@@ -209,16 +214,16 @@ TEST_F(AnimationDocumentTimelineTest, CurrentTimeSeconds) {
}
TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormal) {
- base::TimeTicks zero_time = timeline->ZeroTime();
+ base::TimeTicks zero_time = timeline->CalculateZeroTime();
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
- EXPECT_EQ(zero_time, timeline->ZeroTime());
+ EXPECT_EQ(zero_time, timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(2000));
- EXPECT_EQ(zero_time, timeline->ZeroTime());
+ EXPECT_EQ(zero_time, timeline->CalculateZeroTime());
EXPECT_EQ(2000, timeline->CurrentTimeMilliseconds());
}
@@ -229,33 +234,33 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormalWithOriginTime) {
timeline->ResetForTesting();
EXPECT_EQ(1.0, timeline->PlaybackRate());
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100));
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(200));
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1200, timeline->CurrentTimeMilliseconds());
}
TEST_F(AnimationDocumentTimelineTest, PlaybackRatePause) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
- EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks(), timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(0.0);
EXPECT_EQ(0.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(2000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->CalculateZeroTime());
EXPECT_EQ(3000, timeline->CurrentTimeMilliseconds());
}
@@ -265,61 +270,61 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRatePauseWithOriginTime) {
document.Get(), origin_time, platform_timing);
timeline->ResetForTesting();
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100));
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(0.0);
EXPECT_EQ(0.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(200));
- EXPECT_EQ(TimeTicksFromMillisecondsD(1100), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(1100), timeline->CalculateZeroTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
- EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->CalculateZeroTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(400));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->CalculateZeroTime());
EXPECT_EQ(1300, timeline->CurrentTimeMilliseconds());
}
TEST_F(AnimationDocumentTimelineTest, PlaybackRateSlow) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
- EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks(), timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(0.5);
EXPECT_EQ(0.5, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(3000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-1000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-1000), timeline->CalculateZeroTime());
EXPECT_EQ(2000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->CalculateZeroTime());
EXPECT_EQ(3000, timeline->CurrentTimeMilliseconds());
}
TEST_F(AnimationDocumentTimelineTest, PlaybackRateFast) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
- EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks(), timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(2.0);
EXPECT_EQ(2.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(3000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(500), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(500), timeline->CalculateZeroTime());
EXPECT_EQ(5000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-2000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-2000), timeline->CalculateZeroTime());
EXPECT_EQ(6000, timeline->CurrentTimeMilliseconds());
}
@@ -329,30 +334,33 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRateFastWithOriginTime) {
timeline->ResetForTesting();
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-1000000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-1000000),
+ timeline->CalculateZeroTime());
EXPECT_EQ(1100000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(2.0);
EXPECT_EQ(2.0, timeline->PlaybackRate());
- EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->CalculateZeroTime());
EXPECT_EQ(1100000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(300000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->CalculateZeroTime());
EXPECT_EQ(1500000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
- EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000),
+ timeline->CalculateZeroTime());
EXPECT_EQ(1500000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(400000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000),
+ timeline->CalculateZeroTime());
EXPECT_EQ(1600000, timeline->CurrentTimeMilliseconds());
}
TEST_F(AnimationDocumentTimelineTest, PauseForTesting) {
- float seek_time = 1;
+ AnimationTimeDelta seek_time = AnimationTimeDelta::FromSecondsD(1);
timing.fill_mode = Timing::FillMode::FORWARDS;
auto* anim1 = MakeGarbageCollected<KeyframeEffect>(
element.Get(), CreateEmptyEffectModel(), timing);
@@ -362,8 +370,13 @@ TEST_F(AnimationDocumentTimelineTest, PauseForTesting) {
Animation* animation2 = timeline->Play(anim2);
timeline->PauseAnimationsForTesting(seek_time);
- EXPECT_FLOAT_EQ(seek_time * 1000, animation1->currentTime().value());
- EXPECT_FLOAT_EQ(seek_time * 1000, animation2->currentTime().value());
+ CSSNumberish current_time;
+ animation1->currentTime(current_time);
+ EXPECT_NEAR(seek_time.InMillisecondsF(), current_time.GetAsDouble(),
+ Animation::kTimeToleranceMs);
+ animation2->currentTime(current_time);
+ EXPECT_NEAR(seek_time.InMillisecondsF(), current_time.GetAsDouble(),
+ Animation::kTimeToleranceMs);
}
TEST_F(AnimationDocumentTimelineTest, DelayBeforeAnimationStart) {
@@ -397,7 +410,7 @@ TEST_F(AnimationDocumentTimelineTest, UseAnimationAfterTimelineDeref) {
Animation* animation = timeline->Play(nullptr);
timeline.Clear();
// Test passes if this does not crash.
- animation->setStartTime(0);
+ animation->setStartTime(CSSNumberish::FromDouble(0));
}
TEST_F(AnimationDocumentTimelineTest, PlayAfterDocumentDeref) {
@@ -459,8 +472,9 @@ TEST_F(AnimationDocumentTimelineRealTimeTest,
DocumentTimeline* timeline =
MakeGarbageCollected<DocumentTimeline>(document.Get(), origin_time);
timeline->SetPlaybackRate(0.5);
- EXPECT_EQ(origin_time * 2,
- timeline->ZeroTime() - document->Timeline().ZeroTime());
+
+ EXPECT_TIME_NEAR(AnimationTimeDelta(origin_time) * 2,
+ timeline->ZeroTime() - document->Timeline().ZeroTime());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc b/chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc
index 8f4ea26b32f..bf4f93ecf76 100644
--- a/chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc
@@ -34,14 +34,14 @@ class AnimationEffectStackTest : public PageTestBase {
Animation* Play(KeyframeEffect* effect, double start_time) {
Animation* animation = timeline->Play(effect);
- animation->setStartTime(start_time * 1000);
+ animation->setStartTime(CSSNumberish::FromDouble(start_time * 1000));
animation->Update(kTimingUpdateOnDemand);
return animation;
}
void UpdateTimeline(base::TimeDelta time) {
GetDocument().GetAnimationClock().UpdateTime(
- GetDocument().Timeline().ZeroTime() + time);
+ GetDocument().Timeline().CalculateZeroTime() + time);
timeline->ServiceAnimations(kTimingUpdateForAnimationFrame);
}
@@ -68,8 +68,8 @@ class AnimationEffectStackTest : public PageTestBase {
InertEffect* MakeInertEffect(KeyframeEffectModelBase* effect) {
Timing timing;
timing.fill_mode = Timing::FillMode::BOTH;
- return MakeGarbageCollected<InertEffect>(effect, timing, false, 0,
- base::nullopt);
+ return MakeGarbageCollected<InertEffect>(
+ effect, timing, false, AnimationTimeDelta(), base::nullopt);
}
KeyframeEffect* MakeKeyframeEffect(KeyframeEffectModelBase* effect,
diff --git a/chromium/third_party/blink/renderer/core/animation/element_animations.cc b/chromium/third_party/blink/renderer/core/animation/element_animations.cc
index 705df935c98..afad6b763cf 100644
--- a/chromium/third_party/blink/renderer/core/animation/element_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/element_animations.cc
@@ -51,6 +51,8 @@ void UpdateAnimationFlagsForEffect(const KeyframeEffect& effect,
style.SetHasCurrentFilterAnimation(true);
if (effect.Affects(PropertyHandle(GetCSSPropertyBackdropFilter())))
style.SetHasCurrentBackdropFilterAnimation(true);
+ if (effect.Affects(PropertyHandle(GetCSSPropertyBackgroundColor())))
+ style.SetHasCurrentBackgroundColorAnimation(true);
}
} // namespace
@@ -151,4 +153,16 @@ bool ElementAnimations::UpdateBoxSizeAndCheckTransformAxisAlignment(
return preserves_axis_alignment;
}
+bool ElementAnimations::IsIdentityOrTranslation() const {
+ for (auto& entry : animations_) {
+ if (auto* effect = DynamicTo<KeyframeEffect>(entry.key->effect())) {
+ if (!effect->IsCurrent() && !effect->IsInEffect())
+ continue;
+ if (!effect->IsIdentityOrTranslation())
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/element_animations.h b/chromium/third_party/blink/renderer/core/animation/element_animations.h
index a0277a0724a..babb8cbff4c 100644
--- a/chromium/third_party/blink/renderer/core/animation/element_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/element_animations.h
@@ -89,6 +89,7 @@ class CORE_EXPORT ElementAnimations final
void ClearBaseComputedStyle();
bool UpdateBoxSizeAndCheckTransformAxisAlignment(const FloatSize& box_size);
+ bool IsIdentityOrTranslation() const;
void Trace(Visitor*) const;
diff --git a/chromium/third_party/blink/renderer/core/animation/inert_effect.cc b/chromium/third_party/blink/renderer/core/animation/inert_effect.cc
index 7599fe76593..210a2dfced5 100644
--- a/chromium/third_party/blink/renderer/core/animation/inert_effect.cc
+++ b/chromium/third_party/blink/renderer/core/animation/inert_effect.cc
@@ -37,7 +37,7 @@ namespace blink {
InertEffect::InertEffect(KeyframeEffectModelBase* model,
const Timing& timing,
bool paused,
- base::Optional<double> inherited_time,
+ base::Optional<AnimationTimeDelta> inherited_time,
base::Optional<TimelinePhase> inherited_phase)
: AnimationEffect(timing),
model_(model),
diff --git a/chromium/third_party/blink/renderer/core/animation/inert_effect.h b/chromium/third_party/blink/renderer/core/animation/inert_effect.h
index 157b1207093..76e785839a5 100644
--- a/chromium/third_party/blink/renderer/core/animation/inert_effect.h
+++ b/chromium/third_party/blink/renderer/core/animation/inert_effect.h
@@ -45,7 +45,7 @@ class CORE_EXPORT InertEffect final : public AnimationEffect {
InertEffect(KeyframeEffectModelBase*,
const Timing&,
bool paused,
- base::Optional<double> inherited_time,
+ base::Optional<AnimationTimeDelta> inherited_time,
base::Optional<TimelinePhase> inherited_phase);
void Sample(HeapVector<Member<Interpolation>>&) const;
@@ -66,7 +66,7 @@ class CORE_EXPORT InertEffect final : public AnimationEffect {
private:
Member<KeyframeEffectModelBase> model_;
bool paused_;
- base::Optional<double> inherited_time_;
+ base::Optional<AnimationTimeDelta> inherited_time_;
base::Optional<TimelinePhase> inherited_phase_;
};
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.cc b/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.cc
new file mode 100644
index 00000000000..cfcbc5408f0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.cc
@@ -0,0 +1,65 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h"
+#include "third_party/blink/renderer/core/animation/interpolable_value.h"
+#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
+#include "third_party/blink/renderer/core/style/style_aspect_ratio.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+// static
+std::unique_ptr<InterpolableAspectRatio> InterpolableAspectRatio::MaybeCreate(
+ const StyleAspectRatio& aspect_ratio) {
+ if (!RuntimeEnabledFeatures::CSSAspectRatioInterpolationEnabled())
+ return nullptr;
+
+ // Auto aspect ratio cannot be interpolated to / from.
+ if (aspect_ratio.IsAuto())
+ return nullptr;
+ return std::make_unique<InterpolableAspectRatio>(aspect_ratio.GetRatio());
+}
+
+InterpolableAspectRatio::InterpolableAspectRatio(
+ const FloatSize& aspect_ratio) {
+ // The StyleAspectRatio::IsAuto check in MaybeCreate should return true if we
+ // have a degenerate aspect ratio.
+ DCHECK(aspect_ratio.Height() > 0 && aspect_ratio.Width() > 0);
+
+ value_ = std::make_unique<InterpolableNumber>(
+ log(aspect_ratio.Width() / aspect_ratio.Height()));
+}
+
+FloatSize InterpolableAspectRatio::GetRatio() const {
+ return FloatSize(exp(To<InterpolableNumber>(*value_).Value()), 1);
+}
+
+void InterpolableAspectRatio::Scale(double scale) {
+ value_->Scale(scale);
+}
+
+void InterpolableAspectRatio::Add(const InterpolableValue& other) {
+ value_->Add(*To<InterpolableAspectRatio>(other).value_);
+}
+
+void InterpolableAspectRatio::AssertCanInterpolateWith(
+ const InterpolableValue& other) const {
+ const InterpolableAspectRatio& other_aspect_ratio =
+ To<InterpolableAspectRatio>(other);
+ value_->AssertCanInterpolateWith(*other_aspect_ratio.value_);
+}
+
+void InterpolableAspectRatio::Interpolate(const InterpolableValue& to,
+ const double progress,
+ InterpolableValue& result) const {
+ const InterpolableAspectRatio& aspect_ratio_to =
+ To<InterpolableAspectRatio>(to);
+ InterpolableAspectRatio& aspect_ratio_result =
+ To<InterpolableAspectRatio>(result);
+ value_->Interpolate(*aspect_ratio_to.value_, progress,
+ *aspect_ratio_result.value_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h b/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h
new file mode 100644
index 00000000000..36d29a1d8df
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h
@@ -0,0 +1,62 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_ASPECT_RATIO_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_ASPECT_RATIO_H_
+
+#include <memory>
+#include "third_party/blink/renderer/core/animation/interpolable_value.h"
+#include "third_party/blink/renderer/core/style/style_aspect_ratio.h"
+
+namespace blink {
+
+// Represents a blink::StyleAspectRatio, converted into its logarithm for
+// interpolation.
+class CORE_EXPORT InterpolableAspectRatio final : public InterpolableValue {
+ public:
+ explicit InterpolableAspectRatio(const FloatSize& ratio);
+ explicit InterpolableAspectRatio(std::unique_ptr<InterpolableValue> value)
+ : value_(std::move(value)) {}
+
+ static std::unique_ptr<InterpolableAspectRatio> MaybeCreate(
+ const StyleAspectRatio&);
+
+ FloatSize GetRatio() const;
+
+ // InterpolableValue implementation:
+ void Interpolate(const InterpolableValue& to,
+ const double progress,
+ InterpolableValue& result) const final;
+ bool IsAspectRatio() const final { return true; }
+ bool Equals(const InterpolableValue& other) const final {
+ NOTREACHED();
+ return false;
+ }
+ void Scale(double scale) final;
+ void Add(const InterpolableValue& other) final;
+ void AssertCanInterpolateWith(const InterpolableValue& other) const final;
+
+ private:
+ InterpolableAspectRatio* RawClone() const final {
+ return new InterpolableAspectRatio(value_->Clone());
+ }
+ InterpolableAspectRatio* RawCloneAndZero() const final {
+ return new InterpolableAspectRatio(value_->CloneAndZero());
+ }
+
+ // Interpolable aspect ratio value is stored and interpolated as the log of
+ // the real aspect ratio.
+ std::unique_ptr<InterpolableValue> value_;
+};
+
+template <>
+struct DowncastTraits<InterpolableAspectRatio> {
+ static bool AllowFrom(const InterpolableValue& interpolable_value) {
+ return interpolable_value.IsAspectRatio();
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_ASPECT_RATIO_H_
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolable_length.cc b/chromium/third_party/blink/renderer/core/animation/interpolable_length.cc
index 08e6cc60d5a..4e958c4de06 100644
--- a/chromium/third_party/blink/renderer/core/animation/interpolable_length.cc
+++ b/chromium/third_party/blink/renderer/core/animation/interpolable_length.cc
@@ -204,8 +204,11 @@ static UnitType IndexToUnitType(wtf_size_t index) {
Length InterpolableLength::CreateLength(
const CSSToLengthConversionData& conversion_data,
ValueRange range) const {
+ // Passing true for ToCalcValue is a dirty hack to ensure that we don't create
+ // a degenerate value when animating 'background-position', while we know it
+ // may cause some minor animation glitches for the other properties.
if (IsExpression())
- return Length(expression_->ToCalcValue(conversion_data, range));
+ return Length(expression_->ToCalcValue(conversion_data, range, true));
bool has_percentage = HasPercentage();
double pixels = 0;
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolable_value.h b/chromium/third_party/blink/renderer/core/animation/interpolable_value.h
index 0a846d2f464..21428f41228 100644
--- a/chromium/third_party/blink/renderer/core/animation/interpolable_value.h
+++ b/chromium/third_party/blink/renderer/core/animation/interpolable_value.h
@@ -39,6 +39,7 @@ class CORE_EXPORT InterpolableValue {
virtual bool IsBool() const { return false; }
virtual bool IsList() const { return false; }
virtual bool IsLength() const { return false; }
+ virtual bool IsAspectRatio() const { return false; }
virtual bool IsShadow() const { return false; }
virtual bool IsFilter() const { return false; }
virtual bool IsTransformList() const { return false; }
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc
index 082b5a3ee9f..3cc8831033b 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -432,7 +432,7 @@ void KeyframeEffect::AttachCompositedLayers() {
// very special element id for this animation so that the compositor animation
// system recognize it. We do not use 0 as the element id because 0 is
// kInvalidElementId.
- if (compositor_animation && !Model()->HasNonVariableProperty()) {
+ if (compositor_animation && !Model()->RequiresPropertyNode()) {
compositor_animation->AttachNoElement();
return;
}
@@ -503,12 +503,10 @@ bool KeyframeEffect::UpdateBoxSizeAndCheckTransformAxisAlignment(
if (effect_target_size_) {
if ((size_dependencies & TransformOperation::kDependsWidth) &&
(effect_target_size_->Width() != box_size.Width()))
- GetAnimation()->RestartAnimationOnCompositor();
+ RestartRunningAnimationOnCompositor();
else if ((size_dependencies & TransformOperation::kDependsHeight) &&
- (effect_target_size_->Width() != box_size.Height()))
- GetAnimation()->RestartAnimationOnCompositor();
- } else if (size_dependencies) {
- GetAnimation()->RestartAnimationOnCompositor();
+ (effect_target_size_->Height() != box_size.Height()))
+ RestartRunningAnimationOnCompositor();
}
}
@@ -517,6 +515,40 @@ bool KeyframeEffect::UpdateBoxSizeAndCheckTransformAxisAlignment(
return preserves_axis_alignment;
}
+void KeyframeEffect::RestartRunningAnimationOnCompositor() {
+ Animation* animation = GetAnimation();
+ if (!animation)
+ return;
+
+ // No need to to restart an animation that is in the process of starting up,
+ // paused or idle.
+ if (!animation->StartTimeInternal())
+ return;
+
+ animation->RestartAnimationOnCompositor();
+}
+
+bool KeyframeEffect::IsIdentityOrTranslation() const {
+ static const auto** properties = TransformProperties();
+ for (size_t i = 0; i < num_transform_properties; i++) {
+ const auto* keyframes =
+ Model()->GetPropertySpecificKeyframes(PropertyHandle(*properties[i]));
+ if (!keyframes)
+ continue;
+
+ for (const auto& keyframe : *keyframes) {
+ if (const auto* value = keyframe->GetCompositorKeyframeValue()) {
+ if (!To<CompositorKeyframeTransform>(value)
+ ->GetTransformOperations()
+ .IsIdentityOrTranslation()) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
EffectModel::CompositeOperation KeyframeEffect::CompositeInternal() const {
return model_->Composite();
}
@@ -744,7 +776,7 @@ void KeyframeEffect::CountAnimatedProperties() const {
Document& document = target_element_->GetDocument();
for (const auto& property : model_->Properties()) {
if (property.IsCSSProperty()) {
- DCHECK(isValidCSSPropertyID(property.GetCSSProperty().PropertyID()));
+ DCHECK(IsValidCSSPropertyID(property.GetCSSProperty().PropertyID()));
document.CountAnimatedProperty(property.GetCSSProperty().PropertyID());
}
}
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect.h b/chromium/third_party/blink/renderer/core/animation/keyframe_effect.h
index e0e72423223..7e880f50f65 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect.h
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect.h
@@ -136,6 +136,7 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
void Trace(Visitor*) const override;
bool UpdateBoxSizeAndCheckTransformAxisAlignment(const FloatSize& box_size);
+ bool IsIdentityOrTranslation() const;
ActiveInterpolationsMap InterpolationsForCommitStyles();
@@ -165,6 +166,7 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
AnimationTimeDelta time_to_next_iteration) const override;
bool HasIncompatibleStyle() const;
bool HasMultipleTransformProperties() const;
+ void RestartRunningAnimationOnCompositor();
Member<Element> effect_target_;
Member<Element> target_element_;
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
index db13009db28..5eea620d145 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
@@ -96,15 +96,15 @@ bool KeyframeEffectModelBase::Sample(
namespace {
-static const size_t num_compositable_properties = 7;
+static const size_t num_compositable_properties = 8;
const CSSProperty** CompositableProperties() {
static const CSSProperty*
kCompositableProperties[num_compositable_properties] = {
- &GetCSSPropertyOpacity(), &GetCSSPropertyRotate(),
- &GetCSSPropertyScale(), &GetCSSPropertyTransform(),
- &GetCSSPropertyTranslate(), &GetCSSPropertyFilter(),
- &GetCSSPropertyBackdropFilter()};
+ &GetCSSPropertyOpacity(), &GetCSSPropertyRotate(),
+ &GetCSSPropertyScale(), &GetCSSPropertyTransform(),
+ &GetCSSPropertyTranslate(), &GetCSSPropertyFilter(),
+ &GetCSSPropertyBackdropFilter(), &GetCSSPropertyBackgroundColor()};
return kCompositableProperties;
}
@@ -351,11 +351,13 @@ void KeyframeEffectModelBase::EnsureKeyframeGroups() const {
}
}
-bool KeyframeEffectModelBase::HasNonVariableProperty() const {
+bool KeyframeEffectModelBase::RequiresPropertyNode() const {
for (const auto& keyframe : keyframes_) {
for (const auto& property : keyframe->Properties()) {
if (!property.IsCSSProperty() ||
- property.GetCSSProperty().PropertyID() != CSSPropertyID::kVariable)
+ (property.GetCSSProperty().PropertyID() != CSSPropertyID::kVariable &&
+ property.GetCSSProperty().PropertyID() !=
+ CSSPropertyID::kBackgroundColor))
return true;
}
}
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
index 4331383890e..61ae955cf4d 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
@@ -157,7 +157,7 @@ class CORE_EXPORT KeyframeEffectModelBase : public EffectModel {
return has_revert_;
}
- bool HasNonVariableProperty() const;
+ bool RequiresPropertyNode() const;
bool IsTransformRelatedEffect() const override;
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
index 681cc986ef0..4a75261a456 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
@@ -160,7 +160,8 @@ const PropertySpecificKeyframeVector& ConstructEffectAndGetKeyframes(
auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
- auto style = document->GetStyleResolver().StyleForElement(element);
+ auto style = document->GetStyleResolver().StyleForElement(
+ element, StyleRecalcContext());
// Snapshot should update first time after construction
EXPECT_TRUE(effect->SnapshotAllCompositorKeyframesIfNecessary(
@@ -634,7 +635,8 @@ TEST_F(AnimationKeyframeEffectModel, CompositorSnapshotUpdateBasic) {
KeyframesAtZeroAndOne(CSSPropertyID::kOpacity, "0", "1");
auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
- auto style = GetDocument().GetStyleResolver().StyleForElement(element);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element, StyleRecalcContext());
const CompositorKeyframeValue* value;
@@ -670,7 +672,8 @@ TEST_F(AnimationKeyframeEffectModel,
auto* effect =
MakeGarbageCollected<StringKeyframeEffectModel>(opacity_keyframes);
- auto style = GetDocument().GetStyleResolver().StyleForElement(element);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element, StyleRecalcContext());
EXPECT_TRUE(effect->SnapshotAllCompositorKeyframesIfNecessary(
*element, *style, nullptr));
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
index 8a17f8569f7..c7d170c625a 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_effect_timing.h"
@@ -29,6 +30,10 @@
namespace blink {
+#define EXPECT_TIMEDELTA(expected, observed) \
+ EXPECT_NEAR(expected.InMillisecondsF(), observed.InMillisecondsF(), \
+ Animation::kTimeToleranceMs)
+
using animation_test_helpers::SetV8ObjectPropertyAsNumber;
using animation_test_helpers::SetV8ObjectPropertyAsString;
@@ -227,8 +232,8 @@ TEST_F(AnimationKeyframeEffectV8Test, CanSetDuration) {
KeyframeEffect* animation = CreateAnimationFromTiming(
script_state, element.Get(), js_keyframes, duration);
- EXPECT_EQ(duration / 1000,
- animation->SpecifiedTiming().iteration_duration->InSecondsF());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromMillisecondsD(duration),
+ animation->SpecifiedTiming().iteration_duration.value());
}
TEST_F(AnimationKeyframeEffectV8Test, CanOmitSpecifiedDuration) {
@@ -367,35 +372,38 @@ TEST_F(KeyframeEffectTest, TimeToEffectChange) {
Animation* animation = GetDocument().Timeline().Play(keyframe_effect);
// Beginning of the animation.
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(100),
- keyframe_effect->TimeToForwardsEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(100),
+ keyframe_effect->TimeToForwardsEffectChange());
EXPECT_EQ(AnimationTimeDelta::Max(),
keyframe_effect->TimeToReverseEffectChange());
// End of the before phase.
- animation->setCurrentTime(100000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(100),
- keyframe_effect->TimeToForwardsEffectChange());
- EXPECT_EQ(AnimationTimeDelta(), keyframe_effect->TimeToReverseEffectChange());
+ animation->setCurrentTime(CSSNumberish::FromDouble(100000));
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(100),
+ keyframe_effect->TimeToForwardsEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ keyframe_effect->TimeToReverseEffectChange());
// Nearing the end of the active phase.
- animation->setCurrentTime(199000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- keyframe_effect->TimeToForwardsEffectChange());
- EXPECT_EQ(AnimationTimeDelta(), keyframe_effect->TimeToReverseEffectChange());
+ animation->setCurrentTime(CSSNumberish::FromDouble(199000));
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ keyframe_effect->TimeToForwardsEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ keyframe_effect->TimeToReverseEffectChange());
// End of the active phase.
- animation->setCurrentTime(200000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(100),
- keyframe_effect->TimeToForwardsEffectChange());
- EXPECT_EQ(AnimationTimeDelta(), keyframe_effect->TimeToReverseEffectChange());
+ animation->setCurrentTime(CSSNumberish::FromDouble(200000));
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(100),
+ keyframe_effect->TimeToForwardsEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ keyframe_effect->TimeToReverseEffectChange());
// End of the animation.
- animation->setCurrentTime(300000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(300000));
EXPECT_EQ(AnimationTimeDelta::Max(),
keyframe_effect->TimeToForwardsEffectChange());
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(100),
- keyframe_effect->TimeToReverseEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(100),
+ keyframe_effect->TimeToReverseEffectChange());
}
TEST_F(KeyframeEffectTest, CheckCanStartAnimationOnCompositorNoKeyframes) {
diff --git a/chromium/third_party/blink/renderer/core/animation/length_property_functions.cc b/chromium/third_party/blink/renderer/core/animation/length_property_functions.cc
index de2cc0c91df..2b78a53fb3f 100644
--- a/chromium/third_party/blink/renderer/core/animation/length_property_functions.cc
+++ b/chromium/third_party/blink/renderer/core/animation/length_property_functions.cc
@@ -130,10 +130,10 @@ bool LengthPropertyFunctions::GetLength(const CSSProperty& property,
result = style.Bottom();
return true;
case CSSPropertyID::kCx:
- result = style.SvgStyle().Cx();
+ result = style.Cx();
return true;
case CSSPropertyID::kCy:
- result = style.SvgStyle().Cy();
+ result = style.Cy();
return true;
case CSSPropertyID::kFlexBasis:
result = style.FlexBasis();
@@ -184,16 +184,16 @@ bool LengthPropertyFunctions::GetLength(const CSSProperty& property,
result = style.PaddingTop();
return true;
case CSSPropertyID::kR:
- result = style.SvgStyle().R();
+ result = style.R();
return true;
case CSSPropertyID::kRight:
result = style.Right();
return true;
case CSSPropertyID::kRx:
- result = style.SvgStyle().Rx();
+ result = style.Rx();
return true;
case CSSPropertyID::kRy:
- result = style.SvgStyle().Ry();
+ result = style.Ry();
return true;
case CSSPropertyID::kShapeMargin:
result = style.ShapeMargin();
@@ -223,10 +223,10 @@ bool LengthPropertyFunctions::GetLength(const CSSProperty& property,
result = style.Width();
return true;
case CSSPropertyID::kX:
- result = style.SvgStyle().X();
+ result = style.X();
return true;
case CSSPropertyID::kY:
- result = style.SvgStyle().Y();
+ result = style.Y();
return true;
case CSSPropertyID::kBorderBottomWidth:
@@ -277,9 +277,9 @@ bool LengthPropertyFunctions::GetLength(const CSSProperty& property,
return true;
case CSSPropertyID::kBaselineShift:
- if (style.BaselineShift() != BS_LENGTH)
+ if (style.BaselineShiftType() != EBaselineShiftType::kLength)
return false;
- result = style.BaselineShiftValue();
+ result = style.BaselineShift();
return true;
case CSSPropertyID::kLineHeight:
// Percent Lengths are used to represent numbers on line-height.
@@ -322,7 +322,8 @@ bool LengthPropertyFunctions::SetLength(const CSSProperty& property,
switch (property.PropertyID()) {
// Setters that take a Length value.
case CSSPropertyID::kBaselineShift:
- style.SetBaselineShiftValue(value);
+ style.SetBaselineShiftType(EBaselineShiftType::kLength);
+ style.SetBaselineShift(value);
return true;
case CSSPropertyID::kBottom:
style.SetBottom(value);
diff --git a/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h b/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h
index 82d035e4a71..80ead64fe8e 100644
--- a/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h
+++ b/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h
@@ -81,7 +81,7 @@ class CORE_EXPORT ListInterpolationFunctions {
const NonInterpolableValue* b);
};
-class CORE_EXPORT NonInterpolableList : public NonInterpolableValue {
+class CORE_EXPORT NonInterpolableList final : public NonInterpolableValue {
public:
~NonInterpolableList() final = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc b/chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
index f3d696942e3..a4596e6a2f9 100644
--- a/chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
+++ b/chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
@@ -100,7 +100,7 @@ InterpolationValue PathInterpolationFunctions::ConvertValue(
path_seg_types, style_path->GetWindRule()));
}
-class UnderlyingPathSegTypesChecker
+class UnderlyingPathSegTypesChecker final
: public InterpolationType::ConversionChecker {
public:
~UnderlyingPathSegTypesChecker() final = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/pending_animations.cc b/chromium/third_party/blink/renderer/core/animation/pending_animations.cc
index 8b96385792b..0377a3a87be 100644
--- a/chromium/third_party/blink/renderer/core/animation/pending_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/pending_animations.cc
@@ -72,27 +72,27 @@ bool PendingAnimations::Update(
animation->HasActiveAnimationsOnCompositor();
// Animations with a start time do not participate in compositor start-time
// grouping.
- if (animation->PreCommit(animation->startTime() ? 1 : compositor_group,
- paint_artifact_compositor, start_on_compositor)) {
+ if (animation->PreCommit(
+ animation->StartTimeInternal() ? 1 : compositor_group,
+ paint_artifact_compositor, start_on_compositor)) {
if (animation->HasActiveAnimationsOnCompositor() &&
- !had_compositor_animation && !animation->startTime()) {
+ !had_compositor_animation && !animation->StartTimeInternal()) {
started_synchronized_on_compositor = true;
}
if (!animation->timeline() || !animation->timeline()->IsActive())
continue;
- if (animation->Playing() && !animation->startTime()) {
+ if (animation->Playing() && !animation->StartTimeInternal()) {
waiting_for_start_time.push_back(animation.Get());
} else if (animation->PendingInternal()) {
DCHECK(animation->timeline()->IsActive() &&
- animation->timeline()->CurrentTimeSeconds());
+ animation->timeline()->CurrentTime());
// A pending animation that is not waiting on a start time does not need
// to be synchronized with animations that are starting up. Nonetheless,
// it needs to notify the animation to resolve the ready promise and
// commit the pending state.
- animation->NotifyReady(
- animation->timeline()->CurrentTimeSeconds().value_or(0));
+ animation->NotifyReady(animation->timeline()->CurrentTime().value());
}
} else {
deferred.push_back(animation);
@@ -108,11 +108,10 @@ bool PendingAnimations::Update(
waiting_for_start_time);
} else {
for (auto& animation : waiting_for_start_time) {
- DCHECK(!animation->startTime());
+ DCHECK(!animation->StartTimeInternal());
DCHECK(animation->timeline()->IsActive() &&
- animation->timeline()->CurrentTimeSeconds());
- animation->NotifyReady(
- animation->timeline()->CurrentTimeSeconds().value_or(0));
+ animation->timeline()->CurrentTime());
+ animation->NotifyReady(animation->timeline()->CurrentTime().value());
}
}
@@ -155,7 +154,7 @@ void PendingAnimations::NotifyCompositorAnimationStarted(
animations.swap(waiting_for_compositor_animation_start_);
for (auto animation : animations) {
- if (animation->startTime() || !animation->PendingInternal() ||
+ if (animation->StartTimeInternal() || !animation->PendingInternal() ||
!animation->timeline() || !animation->timeline()->IsActive()) {
// Already started or no longer relevant.
continue;
@@ -168,10 +167,11 @@ void PendingAnimations::NotifyCompositorAnimationStarted(
if (animation->timeline() &&
!animation->timeline()->IsMonotonicallyIncreasing()) {
animation->NotifyReady(
- animation->timeline()->CurrentTimeSeconds().value_or(0));
+ animation->timeline()->CurrentTime().value_or(AnimationTimeDelta()));
} else {
- animation->NotifyReady(monotonic_animation_start_time -
- animation->timeline()->ZeroTimeInSeconds());
+ animation->NotifyReady(
+ AnimationTimeDelta::FromSecondsD(monotonic_animation_start_time) -
+ animation->timeline()->ZeroTime());
}
}
}
@@ -192,7 +192,7 @@ void PendingAnimations::FlushWaitingNonCompositedAnimations() {
return;
// Start any main thread animations that were scheduled to wait on
- // compositor synchronization from a previous frame. Otherwise, an
+ // compositor synchronization from a previous frame. Otherwise, a
// continuous influx of new composited animations could delay the start
// of non-composited animations indefinitely (crbug.com/666710).
HeapVector<Member<Animation>> animations;
@@ -202,9 +202,8 @@ void PendingAnimations::FlushWaitingNonCompositedAnimations() {
waiting_for_compositor_animation_start_.push_back(animation);
} else {
DCHECK(animation->timeline()->IsActive() &&
- animation->timeline()->CurrentTimeSeconds());
- animation->NotifyReady(
- animation->timeline()->CurrentTimeSeconds().value_or(0));
+ animation->timeline()->CurrentTime());
+ animation->NotifyReady(animation->timeline()->CurrentTime().value());
}
}
}
@@ -212,6 +211,7 @@ void PendingAnimations::FlushWaitingNonCompositedAnimations() {
void PendingAnimations::Trace(Visitor* visitor) const {
visitor->Trace(pending_);
visitor->Trace(waiting_for_compositor_animation_start_);
+ visitor->Trace(timer_);
}
void PendingAnimations::TimerFired(TimerBase*) {
diff --git a/chromium/third_party/blink/renderer/core/animation/pending_animations.h b/chromium/third_party/blink/renderer/core/animation/pending_animations.h
index bc700e8b808..5a7c0f7deda 100644
--- a/chromium/third_party/blink/renderer/core/animation/pending_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/pending_animations.h
@@ -103,7 +103,7 @@ class CORE_EXPORT PendingAnimations final
HeapVector<Member<Animation>> pending_;
HeapVector<Member<Animation>> waiting_for_compositor_animation_start_;
- TaskRunnerTimer<PendingAnimations> timer_;
+ HeapTaskRunnerTimer<PendingAnimations> timer_;
int compositor_group_;
bool inside_timer_fired_;
};
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
index b260ad37970..259917a785b 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
@@ -138,17 +138,16 @@ ScrollTimeline* ScrollTimeline::Create(Document& document,
return nullptr;
}
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets;
if (options->scrollOffsets().IsEmpty()) {
// TODO(crbug.com/1094014): scroll_offsets will replace start and end
// offsets once spec decision on multiple scroll offsets is finalized.
// https://github.com/w3c/csswg-drafts/issues/4912
if (!start_scroll_offset->IsDefaultValue())
- scroll_offsets->push_back(start_scroll_offset);
+ scroll_offsets.push_back(start_scroll_offset);
if (!end_scroll_offset->IsDefaultValue() ||
!start_scroll_offset->IsDefaultValue())
- scroll_offsets->push_back(end_scroll_offset);
+ scroll_offsets.push_back(end_scroll_offset);
} else {
for (auto& offset : options->scrollOffsets()) {
ScrollTimelineOffset* scroll_offset =
@@ -159,13 +158,13 @@ ScrollTimeline* ScrollTimeline::Create(Document& document,
}
if (scroll_offset->IsDefaultValue() &&
(options->scrollOffsets().size() == 1 ||
- (scroll_offsets->size() + 1) < options->scrollOffsets().size())) {
+ (scroll_offsets.size() + 1) < options->scrollOffsets().size())) {
exception_state.ThrowTypeError(
"Invalid scrollOffsets: 'auto' can only be set as an end "
"offset when start offset presents.");
return nullptr;
}
- scroll_offsets->push_back(scroll_offset);
+ scroll_offsets.push_back(scroll_offset);
}
}
@@ -182,15 +181,14 @@ ScrollTimeline::ScrollTimeline(
Document* document,
Element* scroll_source,
ScrollDirection orientation,
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets,
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets,
base::Optional<double> time_range)
: AnimationTimeline(document),
scroll_source_(scroll_source),
resolved_scroll_source_(ResolveScrollSource(scroll_source_)),
orientation_(orientation),
- scroll_offsets_(scroll_offsets),
+ scroll_offsets_(std::move(scroll_offsets)),
time_range_(time_range) {
- DCHECK(scroll_offsets_);
if (resolved_scroll_source_) {
ScrollTimelineSet& set = GetScrollTimelineSet();
if (!set.Contains(resolved_scroll_source_)) {
@@ -222,14 +220,12 @@ bool ScrollTimeline::ComputeIsActive() const {
ScrollTimelineOffset* ScrollTimeline::StartScrollOffset() const {
// Single entry offset in scrollOffsets is considered as 'end'. Thus,
// resolving start offset only if there is at least 2 offsets.
- return scroll_offsets_ && scroll_offsets_->size() >= 2
- ? scroll_offsets_->at(0)
- : nullptr;
+ return scroll_offsets_.size() >= 2 ? scroll_offsets_.at(0) : nullptr;
}
ScrollTimelineOffset* ScrollTimeline::EndScrollOffset() const {
// End offset is always the last offset in scrollOffsets if exists.
- return scroll_offsets_ && scroll_offsets_->size() >= 1
- ? scroll_offsets_->at(scroll_offsets_->size() - 1)
+ return scroll_offsets_.size() >= 1
+ ? scroll_offsets_.at(scroll_offsets_.size() - 1)
: nullptr;
}
@@ -255,16 +251,16 @@ bool ScrollTimeline::ResolveScrollOffsets(
auto orientation = ToPhysicalScrollOrientation(orientation_, *layout_box);
- if (scroll_offsets_->size() == 0) {
+ if (scroll_offsets_.size() == 0) {
// Start and end offsets resolve to 'auto'.
resolved_offsets.push_back(0);
resolved_offsets.push_back(max_offset);
return true;
}
// Single entry offset in scrollOffsets is considered as 'end'.
- if (scroll_offsets_->size() == 1)
+ if (scroll_offsets_.size() == 1)
resolved_offsets.push_back(0);
- for (auto& offset : *scroll_offsets_) {
+ for (auto& offset : scroll_offsets_) {
auto resolved_offset = offset->ResolveOffset(
resolved_scroll_source_, orientation, max_offset, max_offset);
if (!resolved_offset) {
@@ -274,7 +270,6 @@ bool ScrollTimeline::ResolveScrollOffsets(
}
resolved_offsets.push_back(resolved_offset.value());
}
- // TODO(crbug.com/1094014): Implement clamping for overlapping offsets.
DCHECK_GE(resolved_offsets.size(), 2u);
return true;
}
@@ -286,12 +281,11 @@ AnimationTimeline::PhaseAndTime ScrollTimeline::CurrentPhaseAndTime() {
bool ScrollTimeline::ScrollOffsetsEqual(
const HeapVector<Member<ScrollTimelineOffset>>& other) const {
- DCHECK(scroll_offsets_);
- if (scroll_offsets_->size() != other.size())
+ if (scroll_offsets_.size() != other.size())
return false;
- size_t size = scroll_offsets_->size();
+ size_t size = scroll_offsets_.size();
for (size_t i = 0; i < size; ++i) {
- if (!DataEquivalent(scroll_offsets_->at(i), other.at(i)))
+ if (!DataEquivalent(scroll_offsets_.at(i), other.at(i)))
return false;
}
return true;
@@ -477,11 +471,7 @@ void ScrollTimeline::endScrollOffset(ScrollTimelineOffsetValue& out) const {
const HeapVector<ScrollTimelineOffsetValue> ScrollTimeline::scrollOffsets()
const {
HeapVector<ScrollTimelineOffsetValue> scroll_offsets;
-
- if (!scroll_offsets_)
- return scroll_offsets;
-
- for (auto& offset : *scroll_offsets_) {
+ for (auto& offset : scroll_offsets_) {
scroll_offsets.push_back(offset->ToScrollTimelineOffsetValue());
// 'auto' can only be the end offset.
DCHECK(!offset->IsDefaultValue() || scroll_offsets.size() == 2);
@@ -614,6 +604,14 @@ void ScrollTimeline::InvalidateEffectTargetStyle() {
animation->InvalidateEffectTargetStyle();
}
+void ScrollTimeline::ValidateState() {
+ auto state = ComputeTimelineState();
+ if (timeline_state_snapshotted_ == state)
+ return;
+ timeline_state_snapshotted_ = state;
+ InvalidateEffectTargetStyle();
+}
+
CompositorAnimationTimeline* ScrollTimeline::EnsureCompositorTimeline() {
if (compositor_timeline_)
return compositor_timeline_.get();
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
index 019885d471d..445af19f636 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
@@ -44,7 +44,7 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
ScrollTimeline(Document*,
Element*,
ScrollDirection,
- HeapVector<Member<ScrollTimelineOffset>>*,
+ HeapVector<Member<ScrollTimelineOffset>>,
base::Optional<double>);
bool IsScrollTimeline() const override { return true; }
@@ -53,7 +53,7 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
// https://github.com/WICG/scroll-animations/issues/31
bool IsActive() const override;
base::Optional<base::TimeDelta> InitialStartTimeForAnimations() override;
- double ZeroTimeInSeconds() override { return 0; }
+ AnimationTimeDelta ZeroTime() override { return AnimationTimeDelta(); }
void ServiceAnimations(TimingUpdateReason) override;
void ScheduleNextService() override;
@@ -95,6 +95,9 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
// for style recalc.
void InvalidateEffectTargetStyle();
+ // See DocumentAnimations::ValidateTimelines
+ void ValidateState();
+
CompositorAnimationTimeline* EnsureCompositorTimeline() override;
void UpdateCompositorTimeline() override;
@@ -126,6 +129,7 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
size_t AttachedAnimationsCount() const { return scroll_animations_.size(); }
private:
+ FRIEND_TEST_ALL_PREFIXES(ScrollTimelineTest, MultipleScrollOffsetsClamping);
// https://wicg.github.io/scroll-animations/#avoiding-cycles
// Snapshots scroll timeline current time and phase.
// Called once per animation frame.
@@ -166,7 +170,7 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
Member<Element> scroll_source_;
Member<Node> resolved_scroll_source_;
ScrollDirection orientation_;
- Member<HeapVector<Member<ScrollTimelineOffset>>> scroll_offsets_;
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets_;
base::Optional<double> time_range_;
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc
index 7555b92eca1..6631be00e8e 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc
@@ -58,8 +58,11 @@ bool ElementBasedOffsetsEqual(ScrollTimelineElementBasedOffset* o1,
return true;
if (!o1 || !o2)
return false;
- return (o1->edge() == o2->edge()) && (o1->target() == o2->target()) &&
- (o1->threshold() == o2->threshold());
+ // TODO(crbug.com/1070871): Use targetOr(nullptr) after migration is done.
+ Element* target_or_null1 = o1->hasTarget() ? o1->target() : nullptr;
+ Element* target_or_null2 = o2->hasTarget() ? o2->target() : nullptr;
+ return target_or_null1 == target_or_null2 && o1->edge() == o2->edge() &&
+ o1->threshold() == o2->threshold();
}
CSSKeywordValue* GetCSSKeywordValue(const ScrollTimelineOffsetValue& offset) {
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
index 5321591f55a..ac3d1cd6811 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
@@ -30,7 +30,7 @@ static constexpr double time_error_ms = 0.001 + 1e-13;
#define EXPECT_TIME_NEAR(expected, value) \
EXPECT_NEAR(expected, value, time_error_ms)
-HeapVector<Member<ScrollTimelineOffset>>* CreateScrollOffsets(
+HeapVector<Member<ScrollTimelineOffset>> CreateScrollOffsets(
ScrollTimelineOffset* start_scroll_offset =
MakeGarbageCollected<ScrollTimelineOffset>(
CSSNumericLiteralValue::Create(
@@ -41,10 +41,9 @@ HeapVector<Member<ScrollTimelineOffset>>* CreateScrollOffsets(
CSSNumericLiteralValue::Create(
90.0,
CSSPrimitiveValue::UnitType::kPixels))) {
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
- scroll_offsets->push_back(start_scroll_offset);
- scroll_offsets->push_back(end_scroll_offset);
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets;
+ scroll_offsets.push_back(start_scroll_offset);
+ scroll_offsets.push_back(end_scroll_offset);
return scroll_offsets;
}
@@ -82,12 +81,12 @@ class TestScrollTimeline : public ScrollTimeline {
public:
TestScrollTimeline(Document* document,
Element* scroll_source,
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets =
CreateScrollOffsets())
: ScrollTimeline(document,
scroll_source,
ScrollTimeline::Vertical,
- scroll_offsets,
+ std::move(scroll_offsets),
100.0),
next_service_scheduled_(false) {}
@@ -801,7 +800,7 @@ TEST_F(ScrollTimelineTest, MultipleScrollOffsetsCurrentTimeCalculations) {
auto* scroller =
To<LayoutBoxModelObject>(GetLayoutObjectByElementId("scroller"));
ASSERT_TRUE(scroller);
- ASSERT_TRUE(scroller->HasNonVisibleOverflow());
+ ASSERT_TRUE(scroller->IsScrollContainer());
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
ASSERT_TRUE(scrollable_area);
double time_range = 100.0;
@@ -879,4 +878,68 @@ TEST_F(ScrollTimelineTest, MultipleScrollOffsetsCurrentTimeCalculations) {
EXPECT_EQ(100, scroll_timeline->CurrentTimeMilliseconds().value());
}
+TEST_F(ScrollTimelineTest, OverlappingScrollOffsets) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #scroller { overflow: scroll; width: 100px; height: 100px; }
+ #spacer { height: 1000px; }
+ </style>
+ <div id='scroller'>
+ <div id ='spacer'></div>
+ </div>
+ )HTML");
+
+ auto* scroller =
+ To<LayoutBoxModelObject>(GetLayoutObjectByElementId("scroller"));
+ ASSERT_TRUE(scroller);
+ PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
+ ASSERT_TRUE(scrollable_area);
+ double time_range = 100.0;
+ ScrollTimelineOptions* options = ScrollTimelineOptions::Create();
+ options->setTimeRange(
+ DoubleOrScrollTimelineAutoKeyword::FromDouble(time_range));
+ options->setScrollSource(GetElementById("scroller"));
+ HeapVector<ScrollTimelineOffsetValue> scroll_offsets = {
+ OffsetFromString("90px"), OffsetFromString("40px"),
+ OffsetFromString("10px")};
+ options->setScrollOffsets(scroll_offsets);
+
+ ScrollTimeline* scroll_timeline =
+ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 80),
+ mojom::blink::ScrollType::kProgrammatic);
+ SimulateFrame();
+ EXPECT_EQ(0, scroll_timeline->CurrentTimeMilliseconds().value());
+
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 95),
+ mojom::blink::ScrollType::kProgrammatic);
+ SimulateFrame();
+ EXPECT_EQ(100, scroll_timeline->CurrentTimeMilliseconds().value());
+
+ scroll_offsets = {OffsetFromString("0px"), OffsetFromString("100px"),
+ OffsetFromString("50px")};
+ options->setScrollOffsets(scroll_offsets);
+
+ scroll_timeline =
+ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 40),
+ mojom::blink::ScrollType::kProgrammatic);
+ SimulateFrame();
+ EXPECT_EQ(20, scroll_timeline->CurrentTimeMilliseconds().value());
+
+ scroll_offsets = {OffsetFromString("50px"), OffsetFromString("0px"),
+ OffsetFromString("100px")};
+ options->setScrollOffsets(scroll_offsets);
+
+ scroll_timeline =
+ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 60),
+ mojom::blink::ScrollType::kProgrammatic);
+ SimulateFrame();
+ EXPECT_EQ(80, scroll_timeline->CurrentTimeMilliseconds().value());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
index 9fe7b941f90..3e3a139d403 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
@@ -16,13 +16,12 @@ namespace blink {
namespace {
-HeapVector<Member<ScrollTimelineOffset>>* CreateScrollOffsets(
+HeapVector<Member<ScrollTimelineOffset>> CreateScrollOffsets(
ScrollTimelineOffset* start_scroll_offset,
ScrollTimelineOffset* end_scroll_offset) {
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
- scroll_offsets->push_back(start_scroll_offset);
- scroll_offsets->push_back(end_scroll_offset);
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets;
+ scroll_offsets.push_back(start_scroll_offset);
+ scroll_offsets.push_back(end_scroll_offset);
return scroll_offsets;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc b/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
index 0b2840a787d..4503d3bb652 100644
--- a/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
+++ b/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
@@ -340,7 +340,7 @@ bool StringKeyframe::CSSPropertySpecificKeyframe::
const ComputedStyle* parent_style) const {
compositor_keyframe_value_cache_ =
StyleResolver::CreateCompositorKeyframeValueSnapshot(
- element, base_style, parent_style, property, value_.Get());
+ element, base_style, parent_style, property, value_.Get(), offset_);
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
index 9c256e7127d..2162168aa4d 100644
--- a/chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
@@ -47,7 +47,7 @@ SVGPropertyBase* SVGPathInterpolationType::AppliedSVGValue(
const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value) const {
return MakeGarbageCollected<SVGPath>(
- MakeGarbageCollected<cssvalue::CSSPathValue>(
+ *MakeGarbageCollected<cssvalue::CSSPathValue>(
PathInterpolationFunctions::AppliedValue(interpolable_value,
non_interpolable_value)));
}
diff --git a/chromium/third_party/blink/renderer/core/animation/timing.cc b/chromium/third_party/blink/renderer/core/animation/timing.cc
index 5a6d39467f4..8d57548ca6c 100644
--- a/chromium/third_party/blink/renderer/core/animation/timing.cc
+++ b/chromium/third_party/blink/renderer/core/animation/timing.cc
@@ -121,7 +121,7 @@ ComputedEffectTiming* Timing::getComputedTiming(
computed_timing->setLocalTime(
CSSNumberish::FromDouble(calculated_timing.local_time.value() * 1000));
} else {
- computed_timing->setLocalTimeToNull();
+ computed_timing->setLocalTime(CSSNumberish());
}
if (calculated_timing.is_in_effect) {
diff --git a/chromium/third_party/blink/renderer/core/animation/timing_calculations.h b/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
index b1ca293f721..2173cc75e7a 100644
--- a/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
+++ b/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
@@ -56,10 +56,14 @@ static inline bool IsWithinAnimationTimeEpsilon(double a, double b) {
return std::abs(a - b) <= TimingCalculationEpsilon();
}
-inline bool LessThanOrEqualToWithinEpsilon(double a, double b) {
+static inline bool LessThanOrEqualToWithinEpsilon(double a, double b) {
return a <= b + TimingCalculationEpsilon();
}
+static inline bool GreaterThanOrEqualToWithinEpsilon(double a, double b) {
+ return a >= b - TimingCalculationEpsilon();
+}
+
static inline double MultiplyZeroAlwaysGivesZero(double x, double y) {
DCHECK(!std::isnan(x));
DCHECK(!std::isnan(y));
diff --git a/chromium/third_party/blink/renderer/core/animation/timing_input_test.cc b/chromium/third_party/blink/renderer/core/animation/timing_input_test.cc
index f5b7c8f7498..98834571a87 100644
--- a/chromium/third_party/blink/renderer/core/animation/timing_input_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/timing_input_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/animation/timing_input.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/unrestricted_double_or_keyframe_animation_options.h"
#include "third_party/blink/renderer/bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
diff --git a/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h b/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
index e8c75ae0538..a5b39a1c6a0 100644
--- a/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
+++ b/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
@@ -78,6 +78,8 @@ class CORE_EXPORT TransitionKeyframe : public Keyframe {
bool IsTransitionPropertySpecificKeyframe() const final { return true; }
+ const TypedInterpolationValue* GetValue() const { return value_.get(); }
+
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
index fd899c25b55..0ab3b9a41db 100644
--- a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
+++ b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
@@ -94,19 +94,17 @@ void WorkletAnimationController::ScrollSourceCompositingStateChanged(
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
WorkletAnimationController::EnsureMainThreadMutatorDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner) {
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> mutator_dispatcher;
- if (!mutator_task_runner_) {
+ if (!main_thread_mutator_client_) {
main_thread_mutator_client_ =
AnimationWorkletMutatorDispatcherImpl::CreateMainThreadClient(
- &mutator_dispatcher, &mutator_task_runner_);
+ mutator_dispatcher, std::move(mutator_task_runner));
main_thread_mutator_client_->SetDelegate(this);
}
DCHECK(main_thread_mutator_client_);
- DCHECK(mutator_task_runner_);
DCHECK(mutator_dispatcher);
- *mutator_task_runner = mutator_task_runner_;
return mutator_dispatcher;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
index b9f5cad9e1d..b365819b6da 100644
--- a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
+++ b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
@@ -20,6 +20,7 @@ namespace blink {
class AnimationWorkletMutatorDispatcherImpl;
class Document;
class MainThreadMutatorClient;
+class Node;
class WorkletAnimationBase;
// Handles AnimationWorklet animations on the main-thread.
@@ -36,7 +37,7 @@ class CORE_EXPORT WorkletAnimationController
: public GarbageCollected<WorkletAnimationController>,
public MutatorClient {
public:
- WorkletAnimationController(Document*);
+ explicit WorkletAnimationController(Document*);
~WorkletAnimationController() override;
void AttachAnimation(WorkletAnimationBase&);
@@ -54,7 +55,7 @@ class CORE_EXPORT WorkletAnimationController
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
EnsureMainThreadMutatorDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner);
void SetMutationUpdate(
std::unique_ptr<AnimationWorkletOutput> output) override;
@@ -79,7 +80,6 @@ class CORE_EXPORT WorkletAnimationController
// TODO(crbug.com/1090515): The following proxy is needed for platform/ to
// access this class. We should bypass it eventually.
std::unique_ptr<MainThreadMutatorClient> main_thread_mutator_client_;
- scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner_;
Member<Document> document_;
};