diff --git a/Userland/Libraries/LibWeb/Animations/Animation.cpp b/Userland/Libraries/LibWeb/Animations/Animation.cpp index 243ed56569..b2b54a0446 100644 --- a/Userland/Libraries/LibWeb/Animations/Animation.cpp +++ b/Userland/Libraries/LibWeb/Animations/Animation.cpp @@ -257,8 +257,39 @@ WebIDL::ExceptionOr Animation::set_playback_rate(double new_playback_rate) // https://www.w3.org/TR/web-animations-1/#animation-play-state Bindings::AnimationPlayState Animation::play_state() const { - // FIXME: Implement - return Bindings::AnimationPlayState::Idle; + // The play state of animation, animation, at a given moment is the state corresponding to the first matching + // condition from the following: + + // -> All of the following conditions are true: + // - The current time of animation is unresolved, and + // - the start time of animation is unresolved, and + // - animation does not have either a pending play task or a pending pause task, + auto current_time = this->current_time(); + if (!current_time.has_value() && !m_start_time.has_value() && !pending()) { + // → idle + return Bindings::AnimationPlayState::Idle; + } + + // -> Either of the following conditions are true: + // - animation has a pending pause task, or + // - both the start time of animation is unresolved and it does not have a pending play task, + if (m_pending_pause_task == TaskState::Pending || (!m_start_time.has_value() && m_pending_play_task == TaskState::None)) { + // → paused + return Bindings::AnimationPlayState::Paused; + } + + // -> For animation, current time is resolved and either of the following conditions are true: + // - animation’s effective playback rate > 0 and current time ≥ associated effect end; or + // - animation’s effective playback rate < 0 and current time ≤ 0, + auto effective_playback_rate = this->effective_playback_rate(); + if (current_time.has_value() && ((effective_playback_rate > 0.0 && current_time.value() >= associated_effect_end()) || (effective_playback_rate < 0.0 && current_time.value() <= 0.0))) { + // → finished + return Bindings::AnimationPlayState::Finished; + } + + // -> Otherwise, + // → running + return Bindings::AnimationPlayState::Running; } // https://www.w3.org/TR/web-animations-1/#associated-effect-end @@ -269,6 +300,14 @@ double Animation::associated_effect_end() const return m_effect ? m_effect->end_time() : 0.0; } +// https://www.w3.org/TR/web-animations-1/#effective-playback-rate +double Animation::effective_playback_rate() const +{ + // The effective playback rate of an animation is its pending playback rate, if set, otherwise it is the animation’s + // playback rate. + return m_pending_playback_rate.has_value() ? m_pending_playback_rate.value() : m_playback_rate; +} + // https://www.w3.org/TR/web-animations-1/#apply-any-pending-playback-rate void Animation::apply_any_pending_playback_rate() { diff --git a/Userland/Libraries/LibWeb/Animations/Animation.h b/Userland/Libraries/LibWeb/Animations/Animation.h index 1afce8ec7a..1847f9ce2f 100644 --- a/Userland/Libraries/LibWeb/Animations/Animation.h +++ b/Userland/Libraries/LibWeb/Animations/Animation.h @@ -42,6 +42,9 @@ public: Bindings::AnimationReplaceState replace_state() const { return m_replace_state; } + // https://www.w3.org/TR/web-animations-1/#dom-animation-pending + bool pending() const { return m_pending_pause_task != TaskState::None || m_pending_play_task != TaskState::None; } + // https://www.w3.org/TR/web-animations-1/#dom-animation-ready JS::NonnullGCPtr ready() const { return *current_ready_promise()->promise(); } @@ -62,6 +65,7 @@ private: }; double associated_effect_end() const; + double effective_playback_rate() const; void apply_any_pending_playback_rate(); WebIDL::ExceptionOr silently_set_current_time(Optional); diff --git a/Userland/Libraries/LibWeb/Animations/Animation.idl b/Userland/Libraries/LibWeb/Animations/Animation.idl index 55e680b84b..30f1430783 100644 --- a/Userland/Libraries/LibWeb/Animations/Animation.idl +++ b/Userland/Libraries/LibWeb/Animations/Animation.idl @@ -15,8 +15,7 @@ interface Animation : EventTarget { attribute double playbackRate; readonly attribute AnimationPlayState playState; readonly attribute AnimationReplaceState replaceState; - // FIXME: - // readonly attribute boolean pending; + readonly attribute boolean pending; readonly attribute Promise ready; readonly attribute Promise finished;