1313#include < LibWeb/Bindings/AnimationPrototype.h>
1414#include < LibWeb/Bindings/Intrinsics.h>
1515#include < LibWeb/CSS/CSSAnimation.h>
16+ #include < LibWeb/CSS/CSSNumericValue.h>
1617#include < LibWeb/DOM/Document.h>
1718#include < LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
1819#include < LibWeb/HTML/Window.h>
@@ -132,33 +133,84 @@ void Animation::set_timeline(GC::Ptr<AnimationTimeline> new_timeline)
132133 update_finished_state (DidSeek::No, SynchronouslyNotify::No);
133134}
134135
136+ // https://drafts.csswg.org/web-animations-2/#validating-a-css-numberish-time
137+ WebIDL::ExceptionOr<Optional<TimeValue>> Animation::validate_a_css_numberish_time (Optional<CSS::CSSNumberish> const & time) const
138+ {
139+ // The procedure to validate a CSSNumberish time for an input value of time is based on the first condition that matches:
140+
141+ // FIXME: If all of the following conditions are true:
142+ // The animation is associated with a progress-based timeline, and
143+ // time is not a CSSNumeric value with percent units:
144+ // throw a TypeError.
145+ // return false;
146+
147+ // If all of the following conditions are true:
148+ if (
149+ // FIXME: The animation is not associated with a progress-based timeline, and
150+
151+ // time is a CSSNumericValue, and
152+ time.has_value () && time->has <GC::Root<CSS::CSSNumericValue>>() &&
153+
154+ // the units of time are not duration units:
155+ !time->get <GC::Root<CSS::CSSNumericValue>>()->type ().matches_time ({}) &&
156+
157+ // AD-HOC: While it's not mentioned in the spec WPT also expects us to support number CSSNumericValues here
158+ !time->get <GC::Root<CSS::CSSNumericValue>>()->type ().matches_number ({})) {
159+ // throw a TypeError.
160+ // return false.
161+ return WebIDL::SimpleException {
162+ WebIDL::SimpleExceptionType::TypeError,
163+ " CSSNumericValue must be a time for non-progress based animations" sv
164+ };
165+ }
166+
167+ // Otherwise
168+ // return true.
169+
170+ // AD-HOC: The spec doesn't say when we should absolutize the validated value so we do it here and return the
171+ // absolutized value instead of a boolean
172+ if (!time.has_value ())
173+ return OptionalNone {};
174+
175+ // FIXME: Figure out which element we should use for this, for now we just use the document element of the current
176+ // window
177+ return TimeValue::from_css_numberish (time.value (), DOM::AbstractElement { *as<HTML::Window>(realm ().global_object ()).associated_document ().document_element () });
178+
179+ VERIFY_NOT_REACHED ();
180+ }
181+
135182// https://www.w3.org/TR/web-animations-1/#dom-animation-starttime
136183// https://www.w3.org/TR/web-animations-1/#set-the-start-time
137- void Animation::set_start_time_for_bindings (Optional<double > const & new_start_time)
184+ WebIDL::ExceptionOr< void > Animation::set_start_time_for_bindings (Optional<CSS::CSSNumberish > const & new_start_time)
138185{
139186 // Setting this attribute updates the start time using the procedure to set the start time of this object to the new
140187 // value.
141- auto valid_start_time = new_start_time.map ([](auto const & value) { return TimeValue { TimeValue::Type::Milliseconds, value }; });
142188
143- // 1. Let timeline time be the current time value of the timeline that animation is associated with. If there is no
189+ // 1. Let valid start time be the result of running the validate a CSSNumberish time procedure with new start time as the input.
190+ // 2. If valid start time is false, abort this procedure.
191+ auto valid_start_time = TRY (validate_a_css_numberish_time (new_start_time));
192+
193+ // FIXME: 3. Set auto align start time to false.
194+
195+ // 4. Let timeline time be the current time value of the timeline that animation is associated with. If there is no
144196 // timeline associated with animation or the associated timeline is inactive, let the timeline time be
145197 // unresolved.
146198 auto timeline_time = m_timeline && !m_timeline->is_inactive () ? m_timeline->current_time () : Optional<TimeValue> {};
147199
148- // 2 . If timeline time is unresolved and new start time is resolved, make animation’s hold time unresolved.
200+ // 5 . If timeline time is unresolved and new start time is resolved, make animation’s hold time unresolved.
149201 if (!timeline_time.has_value () && new_start_time.has_value ())
150202 m_hold_time = {};
151203
152- // 3 . Let previous current time be animation’s current time.
204+ // 6 . Let previous current time be animation’s current time.
153205 auto previous_current_time = current_time ();
154206
155- // 4 . Apply any pending playback rate on animation.
207+ // 7 . Apply any pending playback rate on animation.
156208 apply_any_pending_playback_rate ();
157209
158- // 5 . Set animation’s start time to new start time.
210+ // 8 . Set animation’s start time to new start time.
159211 m_start_time = valid_start_time;
160212
161- // 6 . Update animation’s hold time based on the first matching condition from the following,
213+ // 9 . Update animation’s hold time based on the first matching condition from the following,
162214
163215 // -> If new start time is resolved,
164216 if (valid_start_time.has_value ()) {
@@ -172,17 +224,19 @@ void Animation::set_start_time_for_bindings(Optional<double> const& new_start_ti
172224 m_hold_time = previous_current_time;
173225 }
174226
175- // 7 . If animation has a pending play task or a pending pause task, cancel that task and resolve animation’s current
227+ // 10 . If animation has a pending play task or a pending pause task, cancel that task and resolve animation’s current
176228 // ready promise with animation.
177229 if (pending ()) {
178230 m_pending_play_task = TaskState::None;
179231 m_pending_pause_task = TaskState::None;
180232 WebIDL::resolve_promise (realm (), current_ready_promise (), this );
181233 }
182234
183- // 8 . Run the procedure to update an animation’s finished state for animation with the did seek flag set to true,
235+ // 11 . Run the procedure to update an animation’s finished state for animation with the did seek flag set to true,
184236 // and the synchronously notify flag set to false.
185237 update_finished_state (DidSeek::Yes, SynchronouslyNotify::No);
238+
239+ return {};
186240}
187241
188242// https://www.w3.org/TR/web-animations-1/#animation-current-time
@@ -213,9 +267,11 @@ Optional<TimeValue> Animation::current_time() const
213267}
214268
215269// https://www.w3.org/TR/web-animations-1/#animation-set-the-current-time
216- WebIDL::ExceptionOr<void > Animation::set_current_time_for_bindings (Optional<double > const & seek_time)
270+ WebIDL::ExceptionOr<void > Animation::set_current_time_for_bindings (Optional<CSS::CSSNumberish > const & seek_time)
217271{
218- auto valid_seek_time = seek_time.map ([](auto const & value) { return TimeValue { TimeValue::Type::Milliseconds, value }; });
272+ // AD-HOC: We validate here instead of within silently_set_current_time so we have access to the `TimeValue`
273+ // value within this function.
274+ auto valid_seek_time = TRY (validate_a_css_numberish_time (seek_time));
219275
220276 // 1. Run the steps to silently set the current time of animation to seek time.
221277 TRY (silently_set_current_time (valid_seek_time));
@@ -269,7 +325,7 @@ WebIDL::ExceptionOr<void> Animation::set_playback_rate(double new_playback_rate)
269325 // -> If animation is associated with a monotonically increasing timeline and the previous time is resolved,
270326 if (m_timeline && m_timeline->is_monotonically_increasing () && previous_time.has_value ()) {
271327 // set the current time of animation to previous time.
272- TRY (set_current_time_for_bindings (previous_time->as_milliseconds ()));
328+ TRY (set_current_time_for_bindings (previous_time->as_css_numberish ()));
273329 }
274330 // -> If animation is associated with a non-null timeline that is not monotonically increasing, the start time of
275331 // animation is resolved, associated effect end is not infinity, and either:
@@ -1002,10 +1058,10 @@ void Animation::apply_any_pending_playback_rate()
10021058}
10031059
10041060// https://www.w3.org/TR/web-animations-1/#animation-silently-set-the-current-time
1005- WebIDL::ExceptionOr<void > Animation::silently_set_current_time (Optional<TimeValue> seek_time )
1061+ WebIDL::ExceptionOr<void > Animation::silently_set_current_time (Optional<TimeValue> valid_seek_time )
10061062{
10071063 // 1. If seek time is an unresolved time value, then perform the following steps.
1008- if (!seek_time .has_value ()) {
1064+ if (!valid_seek_time .has_value ()) {
10091065 // 1. If the current time is resolved, then throw a TypeError.
10101066 if (current_time ().has_value ()) {
10111067 return WebIDL::SimpleException {
@@ -1018,7 +1074,13 @@ WebIDL::ExceptionOr<void> Animation::silently_set_current_time(Optional<TimeValu
10181074 return {};
10191075 }
10201076
1021- // 2. Update either animation’s hold time or start time as follows:
1077+ // 2. Let valid seek time be the result of running the validate a CSSNumberish time procedure with seek time as the input.
1078+ // 3. If valid seek time is false, abort this procedure.
1079+ // AD-HOC: We have already validated in the caller.
1080+
1081+ // FIXME: 4. Set auto align start time to false.
1082+
1083+ // 5. Update either animation’s hold time or start time as follows:
10221084
10231085 // -> If any of the following conditions are true:
10241086 // - animation’s hold time is resolved, or
@@ -1027,21 +1089,21 @@ WebIDL::ExceptionOr<void> Animation::silently_set_current_time(Optional<TimeValu
10271089 // - animation’s playback rate is 0,
10281090 if (m_hold_time.has_value () || !m_start_time.has_value () || !m_timeline || m_timeline->is_inactive () || m_playback_rate == 0.0 ) {
10291091 // Set animation’s hold time to seek time.
1030- m_hold_time = seek_time ;
1092+ m_hold_time = valid_seek_time ;
10311093 }
10321094 // -> Otherwise,
10331095 else {
10341096 // Set animation’s start time to the result of evaluating timeline time - (seek time / playback rate) where
10351097 // timeline time is the current time value of timeline associated with animation.
1036- m_start_time = m_timeline->current_time ().value () - (seek_time .value () / m_playback_rate);
1098+ m_start_time = m_timeline->current_time ().value () - (valid_seek_time .value () / m_playback_rate);
10371099 }
10381100
1039- // 3 . If animation has no associated timeline or the associated timeline is inactive, make animation’s start time
1101+ // 6 . If animation has no associated timeline or the associated timeline is inactive, make animation’s start time
10401102 // unresolved.
10411103 if (!m_timeline || m_timeline->is_inactive ())
10421104 m_start_time = {};
10431105
1044- // 4 . Make animation’s previous current time unresolved.
1106+ // 7 . Make animation’s previous current time unresolved.
10451107 m_previous_current_time = {};
10461108
10471109 return {};
0 commit comments