LibWeb: Store animation time values in abstract type
In level 2 of the web animations spec, times are no longer always measures in milliseconds, they can also be percents when dealing with progress-based (i.e. scroll-based) timelines. We don't actually support percent times yet but this change will make it easier to implement when we do.
This commit is contained in:
parent
f9df1c4eea
commit
69f05bd45d
14 changed files with 206 additions and 107 deletions
|
|
@ -134,15 +134,16 @@ void Animation::set_timeline(GC::Ptr<AnimationTimeline> new_timeline)
|
|||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animation-starttime
|
||||
// https://www.w3.org/TR/web-animations-1/#set-the-start-time
|
||||
void Animation::set_start_time(Optional<double> const& new_start_time)
|
||||
void Animation::set_start_time_for_bindings(Optional<double> const& raw_new_start_time)
|
||||
{
|
||||
// Setting this attribute updates the start time using the procedure to set the start time of this object to the new
|
||||
// value.
|
||||
auto new_start_time = raw_new_start_time.map([](auto const& value) { return TimeValue { TimeValue::Type::Milliseconds, 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.
|
||||
auto timeline_time = m_timeline && !m_timeline->is_inactive() ? m_timeline->current_time() : Optional<double> {};
|
||||
auto timeline_time = m_timeline && !m_timeline->is_inactive() ? m_timeline->current_time() : Optional<TimeValue> {};
|
||||
|
||||
// 2. If timeline time is unresolved and new start time is resolved, make animation’s hold time unresolved.
|
||||
if (!timeline_time.has_value() && new_start_time.has_value())
|
||||
|
|
@ -185,7 +186,7 @@ void Animation::set_start_time(Optional<double> const& new_start_time)
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-current-time
|
||||
Optional<double> Animation::current_time() const
|
||||
Optional<TimeValue> Animation::current_time() const
|
||||
{
|
||||
// The current time is calculated from the first matching condition from below:
|
||||
|
||||
|
|
@ -212,8 +213,10 @@ Optional<double> Animation::current_time() const
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-set-the-current-time
|
||||
WebIDL::ExceptionOr<void> Animation::set_current_time(Optional<double> const& seek_time)
|
||||
WebIDL::ExceptionOr<void> Animation::set_current_time_for_bindings(Optional<double> const& raw_seek_time)
|
||||
{
|
||||
auto seek_time = raw_seek_time.map([](auto const& value) { return TimeValue { TimeValue::Type::Milliseconds, value }; });
|
||||
|
||||
// 1. Run the steps to silently set the current time of animation to seek time.
|
||||
TRY(silently_set_current_time(seek_time));
|
||||
|
||||
|
|
@ -266,13 +269,13 @@ WebIDL::ExceptionOr<void> Animation::set_playback_rate(double new_playback_rate)
|
|||
// -> If animation is associated with a monotonically increasing timeline and the previous time is resolved,
|
||||
if (m_timeline && m_timeline->is_monotonically_increasing() && previous_time.has_value()) {
|
||||
// set the current time of animation to previous time.
|
||||
TRY(set_current_time(previous_time));
|
||||
TRY(set_current_time_for_bindings(previous_time->as_milliseconds()));
|
||||
}
|
||||
// -> If animation is associated with a non-null timeline that is not monotonically increasing, the start time of
|
||||
// animation is resolved, associated effect end is not infinity, and either:
|
||||
// - the previous playback rate < 0 and the new playback rate ≥ 0, or
|
||||
// - the previous playback rate ≥ 0 and the new playback rate < 0,
|
||||
else if (m_timeline && !m_timeline->is_monotonically_increasing() && m_start_time.has_value() && !isinf(associated_effect_end()) && ((previous_playback_rate < 0.0 && new_playback_rate >= 0.0) || (previous_playback_rate >= 0 && new_playback_rate < 0))) {
|
||||
else if (m_timeline && !m_timeline->is_monotonically_increasing() && m_start_time.has_value() && !isinf(associated_effect_end().value) && ((previous_playback_rate < 0.0 && new_playback_rate >= 0.0) || (previous_playback_rate >= 0 && new_playback_rate < 0))) {
|
||||
// Set animation’s start time to the result of evaluating associated effect end - start time for animation.
|
||||
m_start_time = associated_effect_end() - m_start_time.value();
|
||||
}
|
||||
|
|
@ -316,7 +319,7 @@ Bindings::AnimationPlayState Animation::play_state() const
|
|||
// - 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))) {
|
||||
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))) {
|
||||
// → finished
|
||||
return Bindings::AnimationPlayState::Finished;
|
||||
}
|
||||
|
|
@ -463,7 +466,7 @@ void Animation::cancel(ShouldInvalidate should_invalidate)
|
|||
// not associated with an active timeline, let timeline time be an unresolved time value.
|
||||
// 9. Set cancelEvent’s timelineTime to timeline time. If timeline time is unresolved, set it to null.
|
||||
AnimationPlaybackEventInit init;
|
||||
init.timeline_time = m_timeline && !m_timeline->is_inactive() ? m_timeline->current_time() : Optional<double> {};
|
||||
init.timeline_time = m_timeline && !m_timeline->is_inactive() ? m_timeline->current_time().map([](auto const& value) { return value.as_milliseconds(); }) : Optional<double> {};
|
||||
auto cancel_event = AnimationPlaybackEvent::create(realm, HTML::EventNames::cancel, init);
|
||||
|
||||
// 10. If animation has a document for timing, then append cancelEvent to its document for timing's pending
|
||||
|
|
@ -507,7 +510,7 @@ WebIDL::ExceptionOr<void> Animation::finish()
|
|||
auto effective_playback_rate = this->effective_playback_rate();
|
||||
if (effective_playback_rate == 0.0)
|
||||
return WebIDL::InvalidStateError::create(realm(), "Animation with a playback rate of 0 cannot be finished"_utf16);
|
||||
if (effective_playback_rate > 0.0 && isinf(associated_effect_end()))
|
||||
if (effective_playback_rate > 0.0 && isinf(associated_effect_end().value))
|
||||
return WebIDL::InvalidStateError::create(realm(), "Animation with no end cannot be finished"_utf16);
|
||||
|
||||
// 2. Apply any pending playback rate to animation.
|
||||
|
|
@ -519,7 +522,7 @@ WebIDL::ExceptionOr<void> Animation::finish()
|
|||
// -> Otherwise,
|
||||
// Let limit be zero.
|
||||
auto playback_rate = this->playback_rate();
|
||||
auto limit = playback_rate > 0.0 ? associated_effect_end() : 0.0;
|
||||
auto limit = playback_rate > 0.0 ? associated_effect_end() : TimeValue::create_zero(m_timeline);
|
||||
|
||||
// 4. Silently set the current time to limit.
|
||||
TRY(silently_set_current_time(limit));
|
||||
|
|
@ -582,7 +585,7 @@ WebIDL::ExceptionOr<void> Animation::play_an_animation(AutoRewind auto_rewind)
|
|||
auto has_pending_ready_promise = false;
|
||||
|
||||
// 3. Let seek time be a time value that is initially unresolved.
|
||||
Optional<double> seek_time;
|
||||
Optional<TimeValue> seek_time;
|
||||
|
||||
// 4. If the auto-rewind flag is true, perform the steps corresponding to the first matching condition from the
|
||||
// following, if any:
|
||||
|
|
@ -595,17 +598,17 @@ WebIDL::ExceptionOr<void> Animation::play_an_animation(AutoRewind auto_rewind)
|
|||
// - unresolved, or
|
||||
// - less than zero, or
|
||||
// - greater than or equal to associated effect end,
|
||||
if (playback_rate >= 0.0 && (!current_time.has_value() || current_time.value() < 0.0 || current_time.value() >= associated_effect_end)) {
|
||||
if (playback_rate >= 0.0 && (!current_time.has_value() || current_time->value < 0 || current_time.value() >= associated_effect_end)) {
|
||||
// Set seek time to zero.
|
||||
seek_time = 0.0;
|
||||
seek_time = TimeValue::create_zero(m_timeline);
|
||||
}
|
||||
// -> If animation’s effective playback rate < 0, and animation’s current time is either:
|
||||
// - unresolved, or
|
||||
// - less than or equal to zero, or
|
||||
// - greater than associated effect end,
|
||||
else if (playback_rate < 0.0 && (!current_time.has_value() || current_time.value() <= 0.0 || current_time.value() > associated_effect_end)) {
|
||||
else if (playback_rate < 0.0 && (!current_time.has_value() || current_time->value <= 0 || current_time.value() > associated_effect_end)) {
|
||||
// -> If associated effect end is positive infinity,
|
||||
if (isinf(associated_effect_end) && associated_effect_end > 0.0) {
|
||||
if (isinf(associated_effect_end.value) && associated_effect_end.value > 0) {
|
||||
// throw an "InvalidStateError" DOMException and abort these steps.
|
||||
return WebIDL::InvalidStateError::create(realm(), "Cannot rewind an animation with an infinite effect end"_utf16);
|
||||
}
|
||||
|
|
@ -621,7 +624,7 @@ WebIDL::ExceptionOr<void> Animation::play_an_animation(AutoRewind auto_rewind)
|
|||
// - animation’s current time is unresolved,
|
||||
if (!seek_time.has_value() && !m_start_time.has_value() && !current_time().has_value()) {
|
||||
// set seek time to zero.
|
||||
seek_time = 0.0;
|
||||
seek_time = TimeValue::create_zero(m_timeline);
|
||||
}
|
||||
|
||||
// 6. Let has finite timeline be true if animation has an associated timeline that is not monotonically increasing.
|
||||
|
|
@ -709,7 +712,7 @@ WebIDL::ExceptionOr<void> Animation::pause()
|
|||
return {};
|
||||
|
||||
// 3. Let seek time be a time value that is initially unresolved.
|
||||
Optional<double> seek_time;
|
||||
Optional<TimeValue> seek_time;
|
||||
|
||||
// 4. Let has finite timeline be true if animation has an associated timeline that is not monotonically increasing.
|
||||
auto has_finite_timeline = m_timeline && !m_timeline->is_monotonically_increasing();
|
||||
|
|
@ -720,13 +723,13 @@ WebIDL::ExceptionOr<void> Animation::pause()
|
|||
// -> If animation’s playback rate is ≥ 0,
|
||||
if (playback_rate() >= 0.0) {
|
||||
// Set seek time to zero.
|
||||
seek_time = 0.0;
|
||||
seek_time = TimeValue::create_zero(m_timeline);
|
||||
}
|
||||
// -> Otherwise
|
||||
else {
|
||||
// If associated effect end for animation is positive infinity,
|
||||
auto associated_effect_end = this->associated_effect_end();
|
||||
if (isinf(associated_effect_end) && associated_effect_end > 0.0) {
|
||||
if (isinf(associated_effect_end.value) && associated_effect_end.value > 0) {
|
||||
// throw an "InvalidStateError" DOMException and abort these steps.
|
||||
return WebIDL::InvalidStateError::create(realm(), "Cannot pause an animation with an infinite effect end"_utf16);
|
||||
}
|
||||
|
|
@ -814,7 +817,7 @@ WebIDL::ExceptionOr<void> Animation::update_playback_rate(double new_playback_ra
|
|||
else if (previous_play_state == Bindings::AnimationPlayState::Finished) {
|
||||
// 1. Let the unconstrained current time be the result of calculating the current time of animation
|
||||
// substituting an unresolved time value for the hold time.
|
||||
Optional<double> unconstrained_current_time;
|
||||
Optional<TimeValue> unconstrained_current_time;
|
||||
{
|
||||
TemporaryChange change(m_hold_time, {});
|
||||
unconstrained_current_time = current_time();
|
||||
|
|
@ -883,14 +886,14 @@ void Animation::persist()
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-time-to-timeline-time
|
||||
Optional<double> Animation::convert_an_animation_time_to_timeline_time(Optional<double> time) const
|
||||
Optional<TimeValue> Animation::convert_an_animation_time_to_timeline_time(Optional<TimeValue> time) const
|
||||
{
|
||||
// 1. If time is unresolved, return time.
|
||||
if (!time.has_value())
|
||||
return time;
|
||||
|
||||
// 2. If time is infinity, return an unresolved time value.
|
||||
if (isinf(time.value()))
|
||||
if (isinf(time->value))
|
||||
return {};
|
||||
|
||||
// 3. If animation’s playback rate is zero, return an unresolved time value.
|
||||
|
|
@ -907,14 +910,14 @@ Optional<double> Animation::convert_an_animation_time_to_timeline_time(Optional<
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-time-to-origin-relative-time
|
||||
Optional<double> Animation::convert_a_timeline_time_to_an_origin_relative_time(Optional<double> time) const
|
||||
Optional<double> Animation::convert_a_timeline_time_to_an_origin_relative_time(Optional<TimeValue> time) const
|
||||
{
|
||||
// 1. Let timeline time be the result of converting time from an animation time to a timeline time.
|
||||
auto timeline_time = convert_an_animation_time_to_timeline_time(time);
|
||||
|
||||
// 2. If timeline time is unresolved, return time.
|
||||
if (!timeline_time.has_value())
|
||||
return time;
|
||||
return {};
|
||||
|
||||
// 3. If animation is not associated with a timeline, return an unresolved time value.
|
||||
if (!m_timeline)
|
||||
|
|
@ -969,11 +972,11 @@ void Animation::effect_timing_changed(Badge<AnimationEffect>)
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#associated-effect-end
|
||||
double Animation::associated_effect_end() const
|
||||
TimeValue Animation::associated_effect_end() const
|
||||
{
|
||||
// The associated effect end of an animation is equal to the end time of the animation’s associated effect. If the
|
||||
// animation has no associated effect, the associated effect end is zero.
|
||||
return m_effect ? m_effect->end_time() : 0.0;
|
||||
return m_effect ? m_effect->end_time() : TimeValue::create_zero(m_timeline);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#effective-playback-rate
|
||||
|
|
@ -999,7 +1002,7 @@ void Animation::apply_any_pending_playback_rate()
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-silently-set-the-current-time
|
||||
WebIDL::ExceptionOr<void> Animation::silently_set_current_time(Optional<double> seek_time)
|
||||
WebIDL::ExceptionOr<void> Animation::silently_set_current_time(Optional<TimeValue> seek_time)
|
||||
{
|
||||
// 1. If seek time is an unresolved time value, then perform the following steps.
|
||||
if (!seek_time.has_value()) {
|
||||
|
|
@ -1055,7 +1058,7 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
|
|||
//
|
||||
// Note: This is required to accommodate timelines that may change direction. Without this definition, a once-
|
||||
// finished animation would remain finished even when its timeline progresses in the opposite direction.
|
||||
Optional<double> unconstrained_current_time;
|
||||
Optional<TimeValue> unconstrained_current_time;
|
||||
if (did_seek == DidSeek::No) {
|
||||
TemporaryChange change(m_hold_time, {});
|
||||
unconstrained_current_time = current_time();
|
||||
|
|
@ -1086,7 +1089,7 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
|
|||
}
|
||||
}
|
||||
// -> If playback rate < 0 and unconstrained current time is less than or equal to 0,
|
||||
else if (m_playback_rate < 0.0 && unconstrained_current_time.value() <= 0.0) {
|
||||
else if (m_playback_rate < 0.0 && unconstrained_current_time->value <= 0) {
|
||||
// If did seek is true, let the hold time be the value of unconstrained current time.
|
||||
if (did_seek == DidSeek::Yes) {
|
||||
m_hold_time = unconstrained_current_time;
|
||||
|
|
@ -1094,9 +1097,9 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
|
|||
// If did seek is false, let the hold time be the minimum value of previous current time and zero. If the
|
||||
// previous current time is unresolved, let the hold time be zero.
|
||||
else if (m_previous_current_time.has_value()) {
|
||||
m_hold_time = min(m_previous_current_time.value(), 0.0);
|
||||
m_hold_time = min(m_previous_current_time.value(), TimeValue::create_zero(m_timeline));
|
||||
} else {
|
||||
m_hold_time = 0.0;
|
||||
m_hold_time = TimeValue::create_zero(m_timeline);
|
||||
}
|
||||
}
|
||||
// -> If playback rate ≠ 0, and animation is associated with an active timeline,
|
||||
|
|
@ -1138,14 +1141,14 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
|
|||
// 4. Set finishEvent’s type attribute to finish.
|
||||
// 5. Set finishEvent’s currentTime attribute to the current time of animation.
|
||||
AnimationPlaybackEventInit init;
|
||||
init.current_time = current_time();
|
||||
init.current_time = current_time()->as_milliseconds();
|
||||
auto finish_event = AnimationPlaybackEvent::create(realm, HTML::EventNames::finish, init);
|
||||
|
||||
// 6. Set finishEvent’s timelineTime attribute to the current time of the timeline with which animation is
|
||||
// associated. If animation is not associated with a timeline, or the timeline is inactive, let
|
||||
// timelineTime be null.
|
||||
if (m_timeline && !m_timeline->is_inactive())
|
||||
finish_event->set_timeline_time(m_timeline->current_time());
|
||||
finish_event->set_timeline_time(m_timeline->current_time()->as_milliseconds());
|
||||
else
|
||||
finish_event->set_timeline_time({});
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/PromiseCapability.h>
|
||||
#include <LibWeb/Animations/TimeValue.h>
|
||||
#include <LibWeb/Bindings/AnimationPrototype.h>
|
||||
#include <LibWeb/DOM/AbstractElement.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
|
|
@ -40,11 +41,21 @@ public:
|
|||
GC::Ptr<AnimationTimeline> timeline() const { return m_timeline; }
|
||||
void set_timeline(GC::Ptr<AnimationTimeline>);
|
||||
|
||||
Optional<double> const& start_time() const { return m_start_time; }
|
||||
void set_start_time(Optional<double> const&);
|
||||
// https://drafts.csswg.org/web-animations-2/#dom-animation-starttime
|
||||
Optional<double> start_time_for_bindings() const
|
||||
{
|
||||
return start_time().map([](auto const& start_time) { return start_time.as_milliseconds(); });
|
||||
}
|
||||
Optional<TimeValue> start_time() const { return m_start_time; }
|
||||
void set_start_time_for_bindings(Optional<double> const&);
|
||||
|
||||
Optional<double> current_time() const;
|
||||
WebIDL::ExceptionOr<void> set_current_time(Optional<double> const&);
|
||||
// https://drafts.csswg.org/web-animations-2/#dom-animation-currenttime
|
||||
Optional<double> current_time_for_bindings() const
|
||||
{
|
||||
return current_time().map([](auto const& current_time) { return current_time.as_milliseconds(); });
|
||||
}
|
||||
Optional<TimeValue> current_time() const;
|
||||
WebIDL::ExceptionOr<void> set_current_time_for_bindings(Optional<double> const&);
|
||||
|
||||
double playback_rate() const { return m_playback_rate; }
|
||||
WebIDL::ExceptionOr<void> set_playback_rate(double value);
|
||||
|
|
@ -94,8 +105,8 @@ public:
|
|||
WebIDL::ExceptionOr<void> reverse();
|
||||
void persist();
|
||||
|
||||
Optional<double> convert_an_animation_time_to_timeline_time(Optional<double>) const;
|
||||
Optional<double> convert_a_timeline_time_to_an_origin_relative_time(Optional<double>) const;
|
||||
Optional<TimeValue> convert_an_animation_time_to_timeline_time(Optional<TimeValue>) const;
|
||||
Optional<double> convert_a_timeline_time_to_an_origin_relative_time(Optional<TimeValue>) const;
|
||||
|
||||
GC::Ptr<DOM::Document> document_for_timing() const;
|
||||
void notify_timeline_time_did_change();
|
||||
|
|
@ -115,7 +126,8 @@ public:
|
|||
|
||||
auto release_saved_cancel_time() { return move(m_saved_cancel_time); }
|
||||
|
||||
double associated_effect_end() const;
|
||||
TimeValue associated_effect_end() const;
|
||||
|
||||
Optional<CSS::AnimationPlayState> last_css_animation_play_state() const { return m_last_css_animation_play_state; }
|
||||
void set_last_css_animation_play_state(CSS::AnimationPlayState state) { m_last_css_animation_play_state = state; }
|
||||
|
||||
|
|
@ -144,7 +156,7 @@ private:
|
|||
double effective_playback_rate() const;
|
||||
|
||||
void apply_any_pending_playback_rate();
|
||||
WebIDL::ExceptionOr<void> silently_set_current_time(Optional<double>);
|
||||
WebIDL::ExceptionOr<void> silently_set_current_time(Optional<TimeValue>);
|
||||
void update_finished_state(DidSeek, SynchronouslyNotify);
|
||||
void reset_an_animations_pending_tasks();
|
||||
|
||||
|
|
@ -169,13 +181,13 @@ private:
|
|||
GC::Ptr<AnimationTimeline> m_timeline;
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-start-time
|
||||
Optional<double> m_start_time {};
|
||||
Optional<TimeValue> m_start_time {};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-hold-time
|
||||
Optional<double> m_hold_time {};
|
||||
Optional<TimeValue> m_hold_time {};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#previous-current-time
|
||||
Optional<double> m_previous_current_time {};
|
||||
Optional<TimeValue> m_previous_current_time {};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#playback-rate
|
||||
double m_playback_rate { 1.0 };
|
||||
|
|
@ -205,9 +217,10 @@ private:
|
|||
|
||||
Optional<HTML::TaskID> m_pending_finish_microtask_id;
|
||||
|
||||
Optional<double> m_saved_play_time;
|
||||
Optional<double> m_saved_pause_time;
|
||||
Optional<double> m_saved_cancel_time;
|
||||
Optional<TimeValue> m_saved_play_time;
|
||||
Optional<TimeValue> m_saved_pause_time;
|
||||
Optional<TimeValue> m_saved_cancel_time;
|
||||
|
||||
Optional<CSS::AnimationPlayState> m_last_css_animation_play_state;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ interface Animation : EventTarget {
|
|||
attribute DOMString id;
|
||||
attribute AnimationEffect? effect;
|
||||
attribute AnimationTimeline? timeline;
|
||||
attribute double? startTime;
|
||||
attribute double? currentTime;
|
||||
[ImplementedAs=start_time_for_bindings] attribute double? startTime;
|
||||
[ImplementedAs=current_time_for_bindings] attribute double? currentTime;
|
||||
attribute double playbackRate;
|
||||
[ImplementedAs=play_state_for_bindings] readonly attribute AnimationPlayState playState;
|
||||
readonly attribute AnimationReplaceState replaceState;
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ ComputedEffectTiming AnimationEffect::get_computed_timing() const
|
|||
.easing = m_timing_function.to_string(),
|
||||
},
|
||||
|
||||
end_time(),
|
||||
active_duration(),
|
||||
local_time(),
|
||||
end_time().as_milliseconds(),
|
||||
active_duration().as_milliseconds(),
|
||||
local_time().map([](auto const& time) { return time.as_milliseconds(); }),
|
||||
transformed_progress(),
|
||||
current_iteration(),
|
||||
};
|
||||
|
|
@ -314,15 +314,15 @@ AnimationDirection AnimationEffect::animation_direction() const
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#end-time
|
||||
double AnimationEffect::end_time() const
|
||||
TimeValue AnimationEffect::end_time() const
|
||||
{
|
||||
// 1. The end time of an animation effect is the result of evaluating
|
||||
// max(start delay + active duration + end delay, 0).
|
||||
return max(m_start_delay.as_milliseconds() + active_duration() + m_end_delay.as_milliseconds(), 0.0);
|
||||
return max(m_start_delay + active_duration() + m_end_delay, TimeValue::create_zero(associated_timeline()));
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#local-time
|
||||
Optional<double> AnimationEffect::local_time() const
|
||||
Optional<TimeValue> AnimationEffect::local_time() const
|
||||
{
|
||||
// The local time of an animation effect at a given moment is based on the first matching condition from the
|
||||
// following:
|
||||
|
|
@ -339,25 +339,25 @@ Optional<double> AnimationEffect::local_time() const
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#active-duration
|
||||
double AnimationEffect::active_duration() const
|
||||
TimeValue AnimationEffect::active_duration() const
|
||||
{
|
||||
// The active duration is calculated as follows:
|
||||
// active duration = iteration duration × iteration count
|
||||
// If either the iteration duration or iteration count are zero, the active duration is zero. This clarification is
|
||||
// needed since the result of infinity multiplied by zero is undefined according to IEEE 754-2008.
|
||||
if (m_iteration_duration.value == 0 || m_iteration_count == 0.0)
|
||||
return 0.0;
|
||||
return TimeValue::create_zero(associated_timeline());
|
||||
|
||||
return m_iteration_duration.as_milliseconds() * m_iteration_count;
|
||||
return m_iteration_duration * m_iteration_count;
|
||||
}
|
||||
|
||||
Optional<double> AnimationEffect::active_time() const
|
||||
Optional<TimeValue> AnimationEffect::active_time() const
|
||||
{
|
||||
return active_time_using_fill(m_fill_mode);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#calculating-the-active-time
|
||||
Optional<double> AnimationEffect::active_time_using_fill(Bindings::FillMode fill_mode) const
|
||||
Optional<TimeValue> AnimationEffect::active_time_using_fill(Bindings::FillMode fill_mode) const
|
||||
{
|
||||
// The active time is based on the local time and start delay. However, it is only defined when the animation effect
|
||||
// should produce an output and hence depends on its fill mode and phase as follows,
|
||||
|
|
@ -369,7 +369,7 @@ Optional<double> AnimationEffect::active_time_using_fill(Bindings::FillMode fill
|
|||
// -> If the fill mode is backwards or both,
|
||||
if (fill_mode == Bindings::FillMode::Backwards || fill_mode == Bindings::FillMode::Both) {
|
||||
// Return the result of evaluating max(local time - start delay, 0).
|
||||
return max(local_time().value() - m_start_delay.as_milliseconds(), 0.0);
|
||||
return max(local_time().value() - m_start_delay, TimeValue::create_zero(associated_timeline()));
|
||||
}
|
||||
|
||||
// -> Otherwise,
|
||||
|
|
@ -380,7 +380,7 @@ Optional<double> AnimationEffect::active_time_using_fill(Bindings::FillMode fill
|
|||
// -> If the animation effect is in the active phase,
|
||||
if (is_in_the_active_phase()) {
|
||||
// Return the result of evaluating local time - start delay.
|
||||
return local_time().value() - m_start_delay.as_milliseconds();
|
||||
return local_time().value() - m_start_delay;
|
||||
}
|
||||
|
||||
// -> If the animation effect is in the after phase,
|
||||
|
|
@ -390,7 +390,7 @@ Optional<double> AnimationEffect::active_time_using_fill(Bindings::FillMode fill
|
|||
// -> If the fill mode is forwards or both,
|
||||
if (fill_mode == Bindings::FillMode::Forwards || fill_mode == Bindings::FillMode::Both) {
|
||||
// Return the result of evaluating max(min(local time - start delay, active duration), 0).
|
||||
return max(min(local_time().value() - m_start_delay.as_milliseconds(), active_duration()), 0.0);
|
||||
return max(min(local_time().value() - m_start_delay, active_duration()), TimeValue::create_zero(associated_timeline()));
|
||||
}
|
||||
|
||||
// -> Otherwise,
|
||||
|
|
@ -452,17 +452,17 @@ bool AnimationEffect::is_in_effect() const
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#before-active-boundary-time
|
||||
double AnimationEffect::before_active_boundary_time() const
|
||||
TimeValue AnimationEffect::before_active_boundary_time() const
|
||||
{
|
||||
// max(min(start delay, end time), 0)
|
||||
return max(min(m_start_delay.as_milliseconds(), end_time()), 0.0);
|
||||
return max(min(m_start_delay, end_time()), TimeValue::create_zero(associated_timeline()));
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#active-after-boundary-time
|
||||
double AnimationEffect::after_active_boundary_time() const
|
||||
TimeValue AnimationEffect::after_active_boundary_time() const
|
||||
{
|
||||
// max(min(start delay + active duration, end time), 0)
|
||||
return max(min(m_start_delay.as_milliseconds() + active_duration(), end_time()), 0.0);
|
||||
return max(min(m_start_delay + active_duration(), end_time()), TimeValue::create_zero(associated_timeline()));
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-effect-before-phase
|
||||
|
|
@ -565,7 +565,7 @@ Optional<double> AnimationEffect::overall_progress() const
|
|||
// Otherwise,
|
||||
else {
|
||||
// Let overall progress be the result of calculating active time / iteration duration.
|
||||
overall_progress = active_time.value() / m_iteration_duration.as_milliseconds();
|
||||
overall_progress = active_time.value() / m_iteration_duration;
|
||||
}
|
||||
|
||||
// 3. Return the result of calculating overall progress + iteration start.
|
||||
|
|
|
|||
|
|
@ -116,18 +116,18 @@ public:
|
|||
|
||||
AnimationDirection animation_direction() const;
|
||||
|
||||
double end_time() const;
|
||||
Optional<double> local_time() const;
|
||||
double active_duration() const;
|
||||
Optional<double> active_time() const;
|
||||
Optional<double> active_time_using_fill(Bindings::FillMode) const;
|
||||
TimeValue end_time() const;
|
||||
Optional<TimeValue> local_time() const;
|
||||
TimeValue active_duration() const;
|
||||
Optional<TimeValue> active_time() const;
|
||||
Optional<TimeValue> active_time_using_fill(Bindings::FillMode) const;
|
||||
|
||||
bool is_in_play() const;
|
||||
bool is_current() const;
|
||||
bool is_in_effect() const;
|
||||
|
||||
double before_active_boundary_time() const;
|
||||
double after_active_boundary_time() const;
|
||||
TimeValue before_active_boundary_time() const;
|
||||
TimeValue after_active_boundary_time() const;
|
||||
|
||||
bool is_in_the_before_phase() const;
|
||||
bool is_in_the_after_phase() const;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Web::Animations {
|
|||
GC_DEFINE_ALLOCATOR(AnimationTimeline);
|
||||
|
||||
// https://drafts.csswg.org/web-animations-1/#dom-animationtimeline-currenttime
|
||||
Optional<double> AnimationTimeline::current_time() const
|
||||
Optional<TimeValue> AnimationTimeline::current_time() const
|
||||
{
|
||||
// Returns the current time for this timeline or null if this timeline is inactive.
|
||||
if (is_inactive())
|
||||
|
|
@ -22,7 +22,7 @@ Optional<double> AnimationTimeline::current_time() const
|
|||
return m_current_time;
|
||||
}
|
||||
|
||||
void AnimationTimeline::set_current_time(Optional<double> value)
|
||||
void AnimationTimeline::set_current_time(Optional<TimeValue> value)
|
||||
{
|
||||
if (value == m_current_time)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@ class AnimationTimeline : public Bindings::PlatformObject {
|
|||
GC_DECLARE_ALLOCATOR(AnimationTimeline);
|
||||
|
||||
public:
|
||||
Optional<double> current_time() const;
|
||||
Optional<double> current_time_for_bindings() const
|
||||
{
|
||||
return current_time().map([](auto const& current_time) { return current_time.as_milliseconds(); });
|
||||
}
|
||||
Optional<TimeValue> current_time() const;
|
||||
|
||||
virtual void update_current_time(double timestamp) = 0;
|
||||
|
||||
|
|
@ -31,7 +35,7 @@ public:
|
|||
bool is_monotonically_increasing() const { return m_is_monotonically_increasing; }
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#timeline-time-to-origin-relative-time
|
||||
virtual Optional<double> convert_a_timeline_time_to_an_origin_relative_time(Optional<double>) { VERIFY_NOT_REACHED(); }
|
||||
virtual Optional<double> convert_a_timeline_time_to_an_origin_relative_time(Optional<TimeValue>) { VERIFY_NOT_REACHED(); }
|
||||
virtual bool can_convert_a_timeline_time_to_an_origin_relative_time() const { return false; }
|
||||
|
||||
void associate_with_animation(GC::Ref<Animation> value) { m_associated_animations.set(value); }
|
||||
|
|
@ -45,10 +49,10 @@ protected:
|
|||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
virtual void finalize() override;
|
||||
|
||||
void set_current_time(Optional<double> value);
|
||||
void set_current_time(Optional<TimeValue> value);
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animationtimeline-currenttime
|
||||
Optional<double> m_current_time {};
|
||||
Optional<TimeValue> m_current_time {};
|
||||
|
||||
// https://drafts.csswg.org/web-animations-1/#monotonically-increasing-timeline
|
||||
bool m_is_monotonically_increasing { false };
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// https://drafts.csswg.org/web-animations-2/#the-animationtimeline-interface
|
||||
[Exposed=Window]
|
||||
interface AnimationTimeline {
|
||||
readonly attribute double? currentTime;
|
||||
[ImplementedAs=current_time_for_bindings] readonly attribute double? currentTime;
|
||||
[ImplementedAs=duration_for_bindings] readonly attribute CSSNumberish? duration;
|
||||
[FIXME] Animation play (optional AnimationEffect? effect = null);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,14 +41,18 @@ WebIDL::ExceptionOr<GC::Ref<DocumentTimeline>> DocumentTimeline::construct_impl(
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#ref-for-timeline-time-to-origin-relative-time
|
||||
Optional<double> DocumentTimeline::convert_a_timeline_time_to_an_origin_relative_time(Optional<double> timeline_time)
|
||||
Optional<double> DocumentTimeline::convert_a_timeline_time_to_an_origin_relative_time(Optional<TimeValue> timeline_time)
|
||||
{
|
||||
// To convert a timeline time, timeline time, to an origin-relative time for a document timeline, timeline, return
|
||||
// the sum of the timeline time and timeline’s origin time. If timeline is inactive, return an unresolved time
|
||||
// value.
|
||||
if (is_inactive() || !timeline_time.has_value())
|
||||
return {};
|
||||
return timeline_time.value() + m_origin_time;
|
||||
|
||||
// NB: We know the timeline time of a DocumentTimeline is always in milliseconds because it's only ever set from
|
||||
// update_current_time()
|
||||
VERIFY(timeline_time->type == TimeValue::Type::Milliseconds);
|
||||
return timeline_time->value + m_origin_time;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/web-animations-1/#document-timeline
|
||||
|
|
@ -58,7 +62,7 @@ void DocumentTimeline::update_current_time(double timestamp)
|
|||
// as a fixed offset from the now timestamp provided each time the update animations and send events procedure is
|
||||
// run. This fixed offset is equal to the current time of the default document timeline when this timeline’s current
|
||||
// time was zero, and is thus referred to as the document timeline’s origin time.
|
||||
set_current_time(timestamp - m_origin_time);
|
||||
set_current_time(TimeValue { TimeValue::Type::Milliseconds, timestamp - m_origin_time });
|
||||
|
||||
// https://drafts.csswg.org/web-animations-1/#ref-for-active-timeline
|
||||
// After a document timeline becomes active, it is monotonically increasing.
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public:
|
|||
virtual void update_current_time(double timestamp) override;
|
||||
virtual bool is_inactive() const override;
|
||||
|
||||
virtual Optional<double> convert_a_timeline_time_to_an_origin_relative_time(Optional<double>) override;
|
||||
virtual Optional<double> convert_a_timeline_time_to_an_origin_relative_time(Optional<TimeValue>) override;
|
||||
virtual bool can_convert_a_timeline_time_to_an_origin_relative_time() const override { return true; }
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,55 @@ struct TimeValue {
|
|||
Type type;
|
||||
double value;
|
||||
|
||||
TimeValue operator-() const
|
||||
{
|
||||
return { type, -value };
|
||||
}
|
||||
|
||||
TimeValue operator*(double other) const
|
||||
{
|
||||
return { type, value * other };
|
||||
}
|
||||
|
||||
TimeValue operator-(TimeValue const& other) const
|
||||
{
|
||||
VERIFY(type == other.type);
|
||||
return { type, value - other.value };
|
||||
}
|
||||
|
||||
TimeValue operator+(TimeValue const& other) const
|
||||
{
|
||||
VERIFY(type == other.type);
|
||||
return { type, value + other.value };
|
||||
}
|
||||
|
||||
TimeValue operator/(double divisor) const
|
||||
{
|
||||
return { type, value / divisor };
|
||||
}
|
||||
|
||||
double operator/(TimeValue const& other) const
|
||||
{
|
||||
VERIFY(type == other.type);
|
||||
return value / other.value;
|
||||
}
|
||||
|
||||
int operator<=>(TimeValue const& other) const
|
||||
{
|
||||
VERIFY(type == other.type);
|
||||
|
||||
if (value < other.value)
|
||||
return -1;
|
||||
if (value > other.value)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operator==(TimeValue const& other) const
|
||||
{
|
||||
return type == other.type && value == other.value;
|
||||
}
|
||||
|
||||
// FIXME: This method is temporary as we migrate all CSS timing to use TimeValue.
|
||||
double as_milliseconds() const
|
||||
{
|
||||
|
|
@ -61,3 +110,15 @@ struct NullableCSSNumberish : FlattenVariant<Variant<Empty>, CSS::CSSNumberish>
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct AK::Formatter<Web::Animations::TimeValue> : Formatter<FormatString> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, Web::Animations::TimeValue const& time)
|
||||
{
|
||||
switch (time.type) {
|
||||
case Web::Animations::TimeValue::Type::Milliseconds:
|
||||
return Formatter<FormatString>::format(builder, "{}ms"sv, time.value);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1074,7 +1074,9 @@ void StyleComputer::start_needed_transitions(ComputedProperties const& previous_
|
|||
};
|
||||
|
||||
// For each element and property, the implementation must act as follows:
|
||||
auto style_change_event_time = m_document->timeline()->current_time().value();
|
||||
// NB: We know that a DocumentTimeline's current time is always in milliseconds
|
||||
VERIFY(m_document->timeline()->current_time()->type == Animations::TimeValue::Type::Milliseconds);
|
||||
auto style_change_event_time = m_document->timeline()->current_time()->value;
|
||||
|
||||
// FIXME: Add some transition helpers to AbstractElement.
|
||||
auto& element = abstract_element.element();
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <LibWeb/Animations/AnimationPlaybackEvent.h>
|
||||
#include <LibWeb/Animations/AnimationTimeline.h>
|
||||
#include <LibWeb/Animations/DocumentTimeline.h>
|
||||
#include <LibWeb/Animations/TimeValue.h>
|
||||
#include <LibWeb/Bindings/DocumentPrototype.h>
|
||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||
#include <LibWeb/Bindings/PrincipalHostDefined.h>
|
||||
|
|
@ -2646,7 +2647,7 @@ void Document::dispatch_events_for_transition(GC::Ref<CSS::CSSTransition> transi
|
|||
if (!transition->current_time().has_value()) {
|
||||
// If the transition has an unresolved current time,
|
||||
// The transition phase is ‘idle’.
|
||||
} else if (transition->current_time().value() < 0.0) {
|
||||
} else if (transition->current_time()->value < 0) {
|
||||
// If the transition has a current time < 0,
|
||||
// The transition phase is ‘before’.
|
||||
transition_phase = Phase::Before;
|
||||
|
|
@ -2680,19 +2681,27 @@ void Document::dispatch_events_for_transition(GC::Ref<CSS::CSSTransition> transi
|
|||
|
||||
auto effect = transition->effect();
|
||||
|
||||
double elapsed_time = [&]() {
|
||||
Animations::TimeValue elapsed_time = [&]() {
|
||||
if (interval == Interval::Start)
|
||||
return max(min(-effect->start_delay().as_milliseconds(), effect->active_duration()), 0) / 1000;
|
||||
return max(min(-effect->start_delay(), effect->active_duration()), Animations::TimeValue::create_zero(transition->timeline()));
|
||||
if (interval == Interval::End)
|
||||
return max(min(transition->associated_effect_end() - effect->start_delay().as_milliseconds(), effect->active_duration()), 0) / 1000;
|
||||
return max(min(transition->associated_effect_end() - effect->start_delay(), effect->active_duration()), Animations::TimeValue::create_zero(transition->timeline()));
|
||||
if (interval == Interval::ActiveTime) {
|
||||
// The active time of the animation at the moment it was canceled calculated using a fill mode of both.
|
||||
// FIXME: Compute this properly.
|
||||
return 0.0;
|
||||
return Animations::TimeValue::create_zero(transition->timeline());
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}();
|
||||
|
||||
double elapsed_time_output;
|
||||
|
||||
switch (elapsed_time.type) {
|
||||
case Animations::TimeValue::Type::Milliseconds:
|
||||
elapsed_time_output = elapsed_time.value / 1000;
|
||||
break;
|
||||
}
|
||||
|
||||
append_pending_animation_event({
|
||||
.event = CSS::TransitionEvent::create(
|
||||
transition->owning_element()->element().realm(),
|
||||
|
|
@ -2700,7 +2709,7 @@ void Document::dispatch_events_for_transition(GC::Ref<CSS::CSSTransition> transi
|
|||
CSS::TransitionEventInit {
|
||||
{ .bubbles = true },
|
||||
MUST(String::from_utf8(transition->transition_property())),
|
||||
elapsed_time,
|
||||
elapsed_time_output,
|
||||
transition->owning_element()->pseudo_element().map([](auto it) {
|
||||
return MUST(String::formatted("::{}", CSS::pseudo_element_name(it)));
|
||||
})
|
||||
|
|
@ -2785,8 +2794,13 @@ void Document::dispatch_events_for_animation_if_necessary(GC::Ref<Animations::An
|
|||
|
||||
auto owning_element = css_animation.owning_element();
|
||||
|
||||
auto dispatch_event = [&](FlyString const& name, double elapsed_time_ms) {
|
||||
auto elapsed_time_seconds = elapsed_time_ms / 1000;
|
||||
auto dispatch_event = [&](FlyString const& name, Animations::TimeValue elapsed_time) {
|
||||
double elapsed_time_output;
|
||||
switch (elapsed_time.type) {
|
||||
case Animations::TimeValue::Type::Milliseconds:
|
||||
elapsed_time_output = elapsed_time.value / 1000;
|
||||
break;
|
||||
}
|
||||
|
||||
append_pending_animation_event({
|
||||
.event = CSS::AnimationEvent::create(
|
||||
|
|
@ -2795,7 +2809,7 @@ void Document::dispatch_events_for_animation_if_necessary(GC::Ref<Animations::An
|
|||
{
|
||||
{ .bubbles = true },
|
||||
css_animation.animation_name(),
|
||||
elapsed_time_seconds,
|
||||
elapsed_time_output,
|
||||
owning_element->pseudo_element().map([](auto it) {
|
||||
return MUST(String::formatted("::{}", CSS::pseudo_element_name(it)));
|
||||
})
|
||||
|
|
@ -2810,10 +2824,10 @@ void Document::dispatch_events_for_animation_if_necessary(GC::Ref<Animations::An
|
|||
// For calculating the elapsedTime of each event, the following definitions are used:
|
||||
|
||||
// - interval start = max(min(-start delay, active duration), 0)
|
||||
auto interval_start = max(min(-effect->start_delay().as_milliseconds(), effect->active_duration()), 0.0);
|
||||
auto interval_start = max(min(-effect->start_delay(), effect->active_duration()), Animations::TimeValue::create_zero(animation->timeline()));
|
||||
|
||||
// - interval end = max(min(associated effect end - start delay, active duration), 0)
|
||||
auto interval_end = max(min(effect->end_time() - effect->start_delay().as_milliseconds(), effect->active_duration()), 0.0);
|
||||
auto interval_end = max(min(effect->end_time() - effect->start_delay(), effect->active_duration()), Animations::TimeValue::create_zero(animation->timeline()));
|
||||
|
||||
switch (previous_phase) {
|
||||
case Animations::AnimationEffect::Phase::Before:
|
||||
|
|
@ -2841,9 +2855,7 @@ void Document::dispatch_events_for_animation_if_necessary(GC::Ref<Animations::An
|
|||
auto iteration_boundary = previous_current_iteration > current_iteration ? current_iteration + 1 : current_iteration;
|
||||
|
||||
// 3. The elapsed time is the result of evaluating (iteration boundary - iteration start) × iteration duration).
|
||||
auto iteration_duration_variant = effect->iteration_duration();
|
||||
auto iteration_duration = iteration_duration_variant.as_milliseconds();
|
||||
auto elapsed_time = (iteration_boundary - effect->iteration_start()) * iteration_duration;
|
||||
auto elapsed_time = effect->iteration_duration() * (iteration_boundary - effect->iteration_start());
|
||||
|
||||
dispatch_event(HTML::EventNames::animationiteration, elapsed_time);
|
||||
}
|
||||
|
|
@ -2863,7 +2875,7 @@ void Document::dispatch_events_for_animation_if_necessary(GC::Ref<Animations::An
|
|||
|
||||
if (current_phase == Animations::AnimationEffect::Phase::Idle && previous_phase != Animations::AnimationEffect::Phase::Idle && previous_phase != Animations::AnimationEffect::Phase::After) {
|
||||
// FIXME: Calculate a non-zero time when the animation is cancelled by means other than calling cancel()
|
||||
auto cancel_time = animation->release_saved_cancel_time().value_or(0.0);
|
||||
auto cancel_time = animation->release_saved_cancel_time().value_or(Animations::TimeValue::create_zero(animation->timeline()));
|
||||
dispatch_event(HTML::EventNames::animationcancel, cancel_time);
|
||||
}
|
||||
|
||||
|
|
@ -5448,8 +5460,8 @@ void Document::remove_replaced_animations()
|
|||
// - Set removeEvent’s timelineTime attribute to the current time of the timeline with which animation is
|
||||
// associated.
|
||||
Animations::AnimationPlaybackEventInit init;
|
||||
init.current_time = animation->current_time();
|
||||
init.timeline_time = animation->timeline()->current_time();
|
||||
init.current_time = animation->current_time()->as_milliseconds();
|
||||
init.timeline_time = animation->timeline()->current_time()->as_milliseconds();
|
||||
auto remove_event = Animations::AnimationPlaybackEvent::create(realm(), HTML::EventNames::remove, init);
|
||||
|
||||
// - If animation has a document for timing, then append removeEvent to its document for timing's pending
|
||||
|
|
@ -5461,7 +5473,7 @@ void Document::remove_replaced_animations()
|
|||
.event = remove_event,
|
||||
.animation = animation,
|
||||
.target = animation,
|
||||
.scheduled_event_time = animation->timeline()->convert_a_timeline_time_to_an_origin_relative_time(init.timeline_time),
|
||||
.scheduled_event_time = animation->timeline()->convert_a_timeline_time_to_an_origin_relative_time(animation->timeline()->current_time()),
|
||||
};
|
||||
document->append_pending_animation_event(pending_animation_event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ void InternalAnimationTimeline::update_current_time(double)
|
|||
|
||||
void InternalAnimationTimeline::set_time(Optional<double> time)
|
||||
{
|
||||
set_current_time(time);
|
||||
set_current_time(time.map([](double value) -> Animations::TimeValue { return { Animations::TimeValue::Type::Milliseconds, value }; }));
|
||||
}
|
||||
|
||||
InternalAnimationTimeline::InternalAnimationTimeline(JS::Realm& realm)
|
||||
: AnimationTimeline(realm)
|
||||
{
|
||||
m_current_time = 0.0;
|
||||
m_current_time = { Animations::TimeValue::Type::Milliseconds, 0.0 };
|
||||
m_is_monotonically_increasing = true;
|
||||
|
||||
auto& document = as<HTML::Window>(HTML::relevant_global_object(*this)).associated_document();
|
||||
|
|
|
|||
Loading…
Reference in a new issue