style/servo/
animation.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! CSS transitions and animations.
6
7// NOTE(emilio): This code isn't really executed in Gecko, but we don't want to
8// compile it out so that people remember it exists.
9
10use crate::context::{CascadeInputs, SharedStyleContext};
11use crate::derives::*;
12use crate::dom::{OpaqueNode, TDocument, TElement, TNode};
13use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
14use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
15use crate::properties::longhands::animation_fill_mode::computed_value::single_value::T as AnimationFillMode;
16use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
17use crate::properties::AnimationDeclarations;
18use crate::properties::{
19    ComputedValues, Importance, LonghandId, PropertyDeclarationBlock, PropertyDeclarationId,
20    PropertyDeclarationIdSet,
21};
22use crate::rule_tree::{CascadeLevel, CascadeOrigin, RuleCascadeFlags};
23use crate::selector_parser::PseudoElement;
24use crate::shared_lock::{Locked, SharedRwLock};
25use crate::style_resolver::StyleResolverForElement;
26use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
27use crate::stylesheets::layer_rule::LayerOrder;
28use crate::values::animated::{Animate, Procedure};
29use crate::values::computed::TimingFunction;
30use crate::values::generics::easing::BeforeFlag;
31use crate::values::specified::TransitionBehavior;
32use crate::Atom;
33use parking_lot::RwLock;
34use rustc_hash::FxHashMap;
35use servo_arc::Arc;
36use std::fmt;
37
38/// Represents an animation for a given property.
39#[derive(Clone, Debug, MallocSizeOf)]
40pub struct PropertyAnimation {
41    /// The value we are animating from.
42    from: AnimationValue,
43
44    /// The value we are animating to.
45    to: AnimationValue,
46
47    /// The timing function of this `PropertyAnimation`.
48    timing_function: TimingFunction,
49
50    /// The duration of this `PropertyAnimation` in seconds.
51    pub duration: f64,
52}
53
54impl PropertyAnimation {
55    /// Returns the given property longhand id.
56    pub fn property_id(&self) -> PropertyDeclarationId<'_> {
57        debug_assert_eq!(self.from.id(), self.to.id());
58        self.from.id()
59    }
60
61    /// The output of the timing function given the progress ration of this animation.
62    fn timing_function_output(&self, progress: f64) -> f64 {
63        let epsilon = 1. / (200. * self.duration);
64        // FIXME: Need to set the before flag correctly.
65        // In order to get the before flag, we have to know the current animation phase
66        // and whether the iteration is reversed. For now, we skip this calculation
67        // by treating as if the flag is unset at all times.
68        // https://drafts.csswg.org/css-easing/#step-timing-function-algo
69        self.timing_function
70            .calculate_output(progress, BeforeFlag::Unset, epsilon)
71    }
72
73    /// Update the given animation at a given point of progress.
74    fn calculate_value(&self, progress: f64) -> AnimationValue {
75        let progress = self.timing_function_output(progress);
76        let procedure = Procedure::Interpolate { progress };
77        self.from.animate(&self.to, procedure).unwrap_or_else(|()| {
78            // Fall back to discrete interpolation
79            if progress < 0.5 {
80                self.from.clone()
81            } else {
82                self.to.clone()
83            }
84        })
85    }
86}
87
88/// This structure represents the state of an animation.
89#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
90pub enum AnimationState {
91    /// The animation has been created, but is not running yet. This state
92    /// is also used when an animation is still in the first delay phase.
93    Pending,
94    /// This animation is currently running.
95    Running,
96    /// This animation is paused. The inner field is the percentage of progress
97    /// when it was paused, from 0 to 1.
98    Paused(f64),
99    /// This animation has finished.
100    Finished,
101    /// This animation has been canceled.
102    Canceled,
103}
104
105impl AnimationState {
106    /// Whether or not this state requires its owning animation to be ticked.
107    fn needs_to_be_ticked(&self) -> bool {
108        *self == AnimationState::Running || *self == AnimationState::Pending
109    }
110}
111
112enum IgnoreTransitions {
113    Canceled,
114    CanceledAndFinished,
115}
116
117/// This structure represents a keyframes animation current iteration state.
118///
119/// If the iteration count is infinite, there's no other state, otherwise we
120/// have to keep track the current iteration and the max iteration count.
121#[derive(Clone, Debug, MallocSizeOf)]
122pub enum KeyframesIterationState {
123    /// Infinite iterations with the current iteration count.
124    Infinite(f64),
125    /// Current and max iterations.
126    Finite(f64, f64),
127}
128
129/// A temporary data structure used when calculating ComputedKeyframes for an
130/// animation. This data structure is used to collapse information for steps
131/// which may be spread across multiple keyframe declarations into a single
132/// instance per `start_percentage`.
133#[derive(Debug)]
134struct IntermediateComputedKeyframe {
135    declarations: PropertyDeclarationBlock,
136    timing_function: Option<TimingFunction>,
137    start_percentage: f32,
138}
139
140impl IntermediateComputedKeyframe {
141    fn new(start_percentage: f32) -> Self {
142        IntermediateComputedKeyframe {
143            declarations: PropertyDeclarationBlock::new(),
144            timing_function: None,
145            start_percentage,
146        }
147    }
148
149    /// Walk through all keyframe declarations and combine all declarations with the
150    /// same `start_percentage` into individual `IntermediateComputedKeyframe`s.
151    fn generate_for_keyframes(
152        animation: &KeyframesAnimation,
153        context: &SharedStyleContext,
154        base_style: &ComputedValues,
155    ) -> Vec<Self> {
156        if animation.steps.is_empty() {
157            return vec![];
158        }
159
160        let mut intermediate_steps: Vec<Self> = Vec::with_capacity(animation.steps.len());
161        let mut current_step = IntermediateComputedKeyframe::new(0.);
162        for step in animation.steps.iter() {
163            let start_percentage = step.start_percentage.0;
164            if start_percentage != current_step.start_percentage {
165                let new_step = IntermediateComputedKeyframe::new(start_percentage);
166                intermediate_steps.push(std::mem::replace(&mut current_step, new_step));
167            }
168
169            current_step.update_from_step(step, context, base_style);
170        }
171        intermediate_steps.push(current_step);
172
173        // We should always have a first and a last step, even if these are just
174        // generated by KeyframesStepValue::ComputedValues.
175        debug_assert!(intermediate_steps.first().unwrap().start_percentage == 0.);
176        debug_assert!(intermediate_steps.last().unwrap().start_percentage == 1.);
177
178        intermediate_steps
179    }
180
181    fn update_from_step(
182        &mut self,
183        step: &KeyframesStep,
184        context: &SharedStyleContext,
185        base_style: &ComputedValues,
186    ) {
187        // Each keyframe declaration may optionally specify a timing function, falling
188        // back to the one defined global for the animation.
189        let guard = &context.guards.author;
190        if let Some(timing_function) = step.get_animation_timing_function(&guard) {
191            self.timing_function = Some(timing_function.to_computed_value_without_context());
192        }
193
194        let block = match step.value {
195            KeyframesStepValue::ComputedValues => return,
196            KeyframesStepValue::Declarations { ref block } => block,
197        };
198
199        // Filter out !important, non-animatable properties, and the
200        // 'display' property (which is only animatable from SMIL).
201        let guard = block.read_with(&guard);
202        for declaration in guard.normal_declaration_iter() {
203            if let PropertyDeclarationId::Longhand(id) = declaration.id() {
204                if id == LonghandId::Display {
205                    continue;
206                }
207
208                if !id.is_animatable() {
209                    continue;
210                }
211            }
212
213            self.declarations.push(
214                declaration.to_physical(base_style.writing_mode),
215                Importance::Normal,
216            );
217        }
218    }
219
220    fn resolve_style<E>(
221        self,
222        element: E,
223        context: &SharedStyleContext,
224        base_style: &Arc<ComputedValues>,
225        resolver: &mut StyleResolverForElement<E>,
226    ) -> Arc<ComputedValues>
227    where
228        E: TElement,
229    {
230        if !self.declarations.any_normal() {
231            return base_style.clone();
232        }
233
234        let document = element.as_node().owner_doc();
235        let locked_block = Arc::new(document.shared_lock().wrap(self.declarations));
236        let mut important_rules_changed = false;
237        let rule_node = base_style.rules().clone();
238        let new_node = context.stylist.rule_tree().update_rule_at_level(
239            CascadeLevel::new(CascadeOrigin::Animations),
240            LayerOrder::root(),
241            Some(locked_block.borrow_arc()),
242            &rule_node,
243            &context.guards,
244            &mut important_rules_changed,
245        );
246
247        if new_node.is_none() {
248            return base_style.clone();
249        }
250
251        let inputs = CascadeInputs {
252            rules: new_node,
253            visited_rules: base_style.visited_rules().cloned(),
254            flags: base_style.flags.for_cascade_inputs(),
255            included_cascade_flags: RuleCascadeFlags::empty(),
256        };
257        resolver
258            .cascade_style_and_visited_with_default_parents(inputs)
259            .0
260    }
261}
262
263#[derive(Clone, Debug, MallocSizeOf)]
264struct PropertyDeclarationOffsets {
265    /// The absolute index of the most recent preceding keyframe that declared
266    /// the given property.
267    preceding_declaration: usize,
268    /// The absolute index of the next keyframe that will declare the given
269    /// property.
270    following_declaration: usize,
271}
272
273#[derive(Clone, Debug, MallocSizeOf)]
274enum AnimationValueOrReference {
275    /// This keyframe declares the property with the given value.
276    AnimationValue(AnimationValue),
277    /// This keyframe does not declare the property.
278    NotDefinedHere(PropertyDeclarationOffsets),
279}
280
281/// A single computed keyframe for a CSS Animation.
282#[derive(Clone, Debug, MallocSizeOf)]
283struct ComputedKeyframe {
284    /// The timing function to use for transitions between this step
285    /// and the next one.
286    timing_function: TimingFunction,
287
288    /// The starting percentage (a number between 0 and 1) which represents
289    /// at what point in an animation iteration this step is.
290    start_percentage: f32,
291
292    /// The animation values to transition to and from when processing this
293    /// keyframe animation step.
294    values: Box<[AnimationValueOrReference]>,
295}
296
297/// Caches the indices of keyframes that declare a specific property.
298///
299/// While traversing the list of keyframes, this is used to avoid repeatedly
300/// searching for the next or last keyframe that declares the property. That
301/// would result in quadratic runtime with respect to the number of keyframes.
302#[derive(Clone, Copy, Debug, Default)]
303struct KeyframeOffsetCacheForProperty {
304    /// The index of a previous keyframe that declares the property.
305    ///
306    /// Note that if the first keyframe does not declare a property, then it implicitly
307    /// uses the computed value of that property. That's why there's always a preceding keyframe
308    /// with the property.
309    last_keyframe_that_defined_property: usize,
310
311    /// The index of a future keyframe or `None` if we have not yet walked the list of keyframes
312    /// to find the next index.
313    ///
314    /// There will always be a next keyframe because the last keyframe (like the first keyframe)
315    /// declares *all* animating properties.
316    next_keyframe_that_defines_property: Option<usize>,
317}
318
319struct KeyframeDataForProperty<'a> {
320    /// The timing function to use for transitions between this step
321    /// and the next one.
322    timing_function: &'a TimingFunction,
323
324    /// The starting percentage (a number between 0 and 1) which represents
325    /// at what point in an animation iteration this step is.
326    start_percentage: f32,
327
328    value: &'a AnimationValue,
329}
330
331#[derive(Clone, Copy, Debug)]
332enum Direction {
333    Forward,
334    Backward,
335}
336
337impl Direction {
338    fn relative_to_animation_direction(&self, reverse: bool) -> Self {
339        match self {
340            Self::Forward if reverse => Self::Backward,
341            Self::Backward if reverse => Self::Forward,
342            _ => *self,
343        }
344    }
345}
346
347impl Animation {
348    /// Starting from the keyframe at `keyframe_index`, returns the contents of the next keyframe in `direction`
349    /// that sets the property at `property_index`.
350    ///
351    /// Returns `None` if there is no keyframe in the specified direction that sets the property.
352    fn next_relevant_keyframe_for_property_in_direction(
353        &self,
354        property_index: usize,
355        keyframe_index: usize,
356        direction: Direction,
357    ) -> Option<KeyframeDataForProperty<'_>> {
358        let relevant_keyframe = &self.computed_steps[keyframe_index];
359        let parameters = match &relevant_keyframe.values[property_index] {
360            AnimationValueOrReference::AnimationValue(animation_value) => KeyframeDataForProperty {
361                timing_function: &relevant_keyframe.timing_function,
362                start_percentage: relevant_keyframe.start_percentage,
363                value: animation_value,
364            },
365            AnimationValueOrReference::NotDefinedHere(offsets) => {
366                let next_relevant_keyframe_index = match direction {
367                    Direction::Forward => offsets.following_declaration,
368                    Direction::Backward => offsets.preceding_declaration,
369                };
370                let next_relevant_keyframe = &self.computed_steps[next_relevant_keyframe_index];
371                let AnimationValueOrReference::AnimationValue(animation_value) =
372                    &next_relevant_keyframe.values[property_index]
373                else {
374                    panic!("Referenced keyframe does not set property");
375                };
376
377                KeyframeDataForProperty {
378                    timing_function: &next_relevant_keyframe.timing_function,
379                    start_percentage: next_relevant_keyframe.start_percentage,
380                    value: &animation_value,
381                }
382            },
383        };
384
385        Some(parameters)
386    }
387}
388impl ComputedKeyframe {
389    fn generate_for_keyframes<E>(
390        element: E,
391        animation: &KeyframesAnimation,
392        context: &SharedStyleContext,
393        base_style: &Arc<ComputedValues>,
394        default_timing_function: TimingFunction,
395        resolver: &mut StyleResolverForElement<E>,
396        animating_properties: PropertyDeclarationIdSet,
397        number_of_animating_properties: usize,
398    ) -> Box<[Self]>
399    where
400        E: TElement,
401    {
402        let animation_values_from_style: Vec<AnimationValue> = animating_properties
403            .iter()
404            .map(|property| {
405                AnimationValue::from_computed_values(property, &**base_style)
406                    .expect("Unexpected non-animatable property.")
407            })
408            .collect();
409
410        let intermediate_steps =
411            IntermediateComputedKeyframe::generate_for_keyframes(animation, context, base_style);
412
413        // Used while iterating over the keyframes to, for each property, remember the most recent and
414        // next keyframe that declares the property. That avoids a quadratic number of traversals per
415        // property.
416        let mut keyframe_offset_caches: Vec<KeyframeOffsetCacheForProperty> =
417            vec![Default::default(); number_of_animating_properties];
418
419        let mut computed_steps: Vec<Self> = Vec::with_capacity(intermediate_steps.len());
420        let mut remaining_steps = intermediate_steps.into_iter();
421        let mut step_index = 0;
422        while let Some(step) = remaining_steps.next() {
423            let start_percentage = step.start_percentage;
424            let properties_changed_in_step = step.declarations.property_ids().clone();
425            let timing_function = step
426                .timing_function
427                .clone()
428                .unwrap_or_else(|| default_timing_function.clone());
429            let step_style = step.resolve_style(element, context, base_style, resolver);
430
431            let values: Box<[_]> = {
432                // For each property that is animating, pull the value from the resolved
433                // style for this step if it's in one of the declarations.
434                animating_properties
435                    .iter()
436                    .enumerate()
437                    .map(|(property_index, property_declaration)| {
438                        let keyframe_offset_cache = &mut keyframe_offset_caches[property_index];
439                        if properties_changed_in_step.contains(property_declaration) {
440                            keyframe_offset_cache.last_keyframe_that_defined_property = step_index;
441                            let animation_value = AnimationValue::from_computed_values(
442                                property_declaration,
443                                &step_style,
444                            )
445                            .unwrap();
446                            return AnimationValueOrReference::AnimationValue(animation_value);
447                        }
448
449                        // https://drafts.csswg.org/css-animations/#keyframes
450                        // > If a 0% or from keyframe is not specified, then the user agent constructs a 0% keyframe
451                        // > using the computed values of the properties being animated. If a 100% or to keyframe is
452                        // > not specified, then the user agent constructs a 100% keyframe using the computed values
453                        // > of the properties being animated.
454                        if step_index == 0 || remaining_steps.as_slice().is_empty() {
455                            return AnimationValueOrReference::AnimationValue(
456                                animation_values_from_style[property_index].clone(),
457                            );
458                        }
459
460                        // This animating property is not defined on this keyframe - we should act as if this keyframe
461                        // didn't exist for this property, so we calculate an interpolated value.
462                        // (https://drafts.csswg.org/css-animations/#keyframes)
463                        //
464                        // If the property was not defined on any previous keyframe then we use the value from style.
465                        // and if it's not defined on any following keyframe then we've already finished animating it.
466                        let preceding_declaration =
467                            keyframe_offset_cache.last_keyframe_that_defined_property;
468                        let following_declaration = keyframe_offset_cache
469                            .next_keyframe_that_defines_property
470                            .filter(|offset| *offset > step_index)
471                            .unwrap_or_else(|| {
472                                let relative_offset = remaining_steps
473                                    .as_slice()
474                                    .iter()
475                                    .position(|step| {
476                                        step.declarations.contains(property_declaration)
477                                    })
478                                    .unwrap_or(remaining_steps.as_slice().len() - 1);
479                                let absolute_offset = step_index + 1 + relative_offset;
480
481                                keyframe_offset_cache.next_keyframe_that_defines_property =
482                                    Some(absolute_offset);
483                                absolute_offset
484                            });
485
486                        AnimationValueOrReference::NotDefinedHere(PropertyDeclarationOffsets {
487                            preceding_declaration,
488                            following_declaration,
489                        })
490                    })
491                    .collect()
492            };
493            debug_assert_eq!(values.len(), number_of_animating_properties);
494
495            computed_steps.push(ComputedKeyframe {
496                timing_function,
497                start_percentage,
498                values,
499            });
500
501            step_index += 1;
502        }
503
504        // The first and last steps (at 0% and 100% respectively) should declare all animating properties.
505        // If they don't then we should have filled the missing properties with the computed values.
506        debug_assert!(computed_steps.first().is_none_or(|first_step| {
507            first_step
508                .values
509                .iter()
510                .all(|value| matches!(value, AnimationValueOrReference::AnimationValue(_)))
511        }));
512        debug_assert!(computed_steps.last().is_none_or(|first_step| {
513            first_step
514                .values
515                .iter()
516                .all(|value| matches!(value, AnimationValueOrReference::AnimationValue(_)))
517        }));
518
519        computed_steps.into_boxed_slice()
520    }
521}
522
523/// A CSS Animation
524#[derive(Clone, MallocSizeOf)]
525pub struct Animation {
526    /// The name of this animation as defined by the style.
527    pub name: Atom,
528
529    /// The properties that change in this animation.
530    properties_changed: PropertyDeclarationIdSet,
531
532    /// The computed style for each keyframe of this animation.
533    computed_steps: Box<[ComputedKeyframe]>,
534
535    /// The time this animation started at, which is the current value of the animation
536    /// timeline when this animation was created plus any animation delay.
537    pub started_at: f64,
538
539    /// The duration of this animation.
540    pub duration: f64,
541
542    /// The delay of the animation.
543    pub delay: f64,
544
545    /// The `animation-fill-mode` property of this animation.
546    pub fill_mode: AnimationFillMode,
547
548    /// The current iteration state for the animation.
549    pub iteration_state: KeyframesIterationState,
550
551    /// Whether this animation is paused.
552    pub state: AnimationState,
553
554    /// The declared animation direction of this animation.
555    pub direction: AnimationDirection,
556
557    /// The current animation direction. This can only be `normal` or `reverse`.
558    pub current_direction: AnimationDirection,
559
560    /// The number of properties that are affected by this animation.
561    pub number_of_animating_properties: usize,
562
563    /// Whether or not this animation is new and or has already been tracked
564    /// by the script thread.
565    pub is_new: bool,
566}
567
568impl Animation {
569    /// Whether or not this animation is cancelled by changes from a new style.
570    fn is_cancelled_in_new_style(&self, new_style: &Arc<ComputedValues>) -> bool {
571        let new_ui = new_style.get_ui();
572        let index = new_ui
573            .animation_name_iter()
574            .position(|animation_name| Some(&self.name) == animation_name.as_atom());
575        let index = match index {
576            Some(index) => index,
577            None => return true,
578        };
579
580        new_ui.animation_duration_mod(index).seconds() == 0.
581    }
582
583    /// Given the current time, advances this animation to the next iteration,
584    /// updates times, and then toggles the direction if appropriate. Otherwise
585    /// does nothing. Returns true if this animation has iterated.
586    pub fn iterate_if_necessary(&mut self, time: f64) -> bool {
587        if !self.iteration_over(time) {
588            return false;
589        }
590
591        // Only iterate animations that are currently running.
592        if self.state != AnimationState::Running {
593            return false;
594        }
595
596        if self.on_last_iteration() {
597            return false;
598        }
599
600        self.iterate();
601        true
602    }
603
604    fn iterate(&mut self) {
605        debug_assert!(!self.on_last_iteration());
606
607        if let KeyframesIterationState::Finite(ref mut current, max) = self.iteration_state {
608            *current = (*current + 1.).min(max);
609        }
610
611        if let AnimationState::Paused(ref mut progress) = self.state {
612            debug_assert!(*progress > 1.);
613            *progress -= 1.;
614        }
615
616        // Update the next iteration direction if applicable.
617        self.started_at += self.duration;
618        match self.direction {
619            AnimationDirection::Alternate | AnimationDirection::AlternateReverse => {
620                self.current_direction = match self.current_direction {
621                    AnimationDirection::Normal => AnimationDirection::Reverse,
622                    AnimationDirection::Reverse => AnimationDirection::Normal,
623                    _ => unreachable!(),
624                };
625            },
626            _ => {},
627        }
628    }
629
630    /// A number (> 0 and <= 1) which represents the fraction of a full iteration
631    /// that the current iteration of the animation lasts. This will be less than 1
632    /// if the current iteration is the fractional remainder of a non-integral
633    /// iteration count.
634    pub fn current_iteration_end_progress(&self) -> f64 {
635        match self.iteration_state {
636            KeyframesIterationState::Finite(current, max) => (max - current).min(1.),
637            KeyframesIterationState::Infinite(_) => 1.,
638        }
639    }
640
641    /// The duration of the current iteration of this animation which may be less
642    /// than the animation duration if it has a non-integral iteration count.
643    pub fn current_iteration_duration(&self) -> f64 {
644        self.current_iteration_end_progress() * self.duration
645    }
646
647    /// Whether or not the current iteration is over. Note that this method assumes that
648    /// the animation is still running.
649    fn iteration_over(&self, time: f64) -> bool {
650        time > (self.started_at + self.current_iteration_duration())
651    }
652
653    /// Assuming this animation is running, whether or not it is on the last iteration.
654    fn on_last_iteration(&self) -> bool {
655        match self.iteration_state {
656            KeyframesIterationState::Finite(current, max) => current >= (max - 1.),
657            KeyframesIterationState::Infinite(_) => false,
658        }
659    }
660
661    /// Whether or not this animation has finished at the provided time. This does
662    /// not take into account canceling i.e. when an animation or transition is
663    /// canceled due to changes in the style.
664    pub fn has_ended(&self, time: f64) -> bool {
665        if !self.on_last_iteration() {
666            return false;
667        }
668
669        let progress = match self.state {
670            AnimationState::Finished => return true,
671            AnimationState::Paused(progress) => progress,
672            AnimationState::Running => (time - self.started_at) / self.duration,
673            AnimationState::Pending | AnimationState::Canceled => return false,
674        };
675
676        progress >= self.current_iteration_end_progress()
677    }
678
679    /// Updates the appropiate state from other animation.
680    ///
681    /// This happens when an animation is re-submitted to layout, presumably
682    /// because of an state change.
683    ///
684    /// There are some bits of state we can't just replace, over all taking in
685    /// account times, so here's that logic.
686    pub fn update_from_other(&mut self, other: &Self, now: f64) {
687        use self::AnimationState::*;
688
689        debug!(
690            "KeyframesAnimationState::update_from_other({:?}, {:?})",
691            self, other
692        );
693
694        // NB: We shall not touch the started_at field, since we don't want to
695        // restart the animation.
696        let old_started_at = self.started_at;
697        let old_duration = self.duration;
698        let old_direction = self.current_direction;
699        let old_state = self.state.clone();
700        let old_iteration_state = self.iteration_state.clone();
701
702        *self = other.clone();
703
704        self.started_at = old_started_at;
705        self.current_direction = old_direction;
706
707        // Don't update the iteration count, just the iteration limit.
708        // TODO: see how changing the limit affects rendering in other browsers.
709        // We might need to keep the iteration count even when it's infinite.
710        match (&mut self.iteration_state, old_iteration_state) {
711            (
712                &mut KeyframesIterationState::Finite(ref mut iters, _),
713                KeyframesIterationState::Finite(old_iters, _),
714            ) => *iters = old_iters,
715            _ => {},
716        }
717
718        // Don't pause or restart animations that should remain finished.
719        // We call mem::replace because `has_ended(...)` looks at `Animation::state`.
720        let new_state = std::mem::replace(&mut self.state, Running);
721        if old_state == Finished && self.has_ended(now) {
722            self.state = Finished;
723        } else {
724            self.state = new_state;
725        }
726
727        // If we're unpausing the animation, fake the start time so we seem to
728        // restore it.
729        //
730        // If the animation keeps paused, keep the old value.
731        //
732        // If we're pausing the animation, compute the progress value.
733        match (&mut self.state, &old_state) {
734            (&mut Pending, &Paused(progress)) => {
735                self.started_at = now - (self.duration * progress);
736            },
737            (&mut Paused(ref mut new), &Paused(old)) => *new = old,
738            (&mut Paused(ref mut progress), &Running) => {
739                *progress = (now - old_started_at) / old_duration
740            },
741            _ => {},
742        }
743
744        // Try to detect when we should skip straight to the running phase to
745        // avoid sending multiple animationstart events.
746        if self.state == Pending && self.started_at <= now && old_state != Pending {
747            self.state = Running;
748        }
749    }
750
751    /// Fill in an `AnimationValueMap` with values calculated from this animation at
752    /// the given time value.
753    fn get_property_declaration_at_time(&self, now: f64, map: &mut AnimationValueMap) {
754        if self.computed_steps.is_empty() {
755            // Nothing to do.
756            return;
757        }
758
759        let total_progress = match self.state {
760            AnimationState::Running | AnimationState::Pending | AnimationState::Finished => {
761                (now - self.started_at) / self.duration
762            },
763            AnimationState::Paused(progress) => progress,
764            AnimationState::Canceled => return,
765        };
766
767        if total_progress < 0.
768            && self.fill_mode != AnimationFillMode::Backwards
769            && self.fill_mode != AnimationFillMode::Both
770        {
771            return;
772        }
773        if self.has_ended(now)
774            && self.fill_mode != AnimationFillMode::Forwards
775            && self.fill_mode != AnimationFillMode::Both
776        {
777            return;
778        }
779        let total_progress = total_progress
780            .min(self.current_iteration_end_progress())
781            .max(0.0);
782
783        // Get the indices of the previous (from) keyframe and the next (to) keyframe.
784        let next_keyframe_index;
785        let prev_keyframe_index;
786        let num_steps = self.computed_steps.len();
787        match self.current_direction {
788            AnimationDirection::Normal => {
789                next_keyframe_index = self
790                    .computed_steps
791                    .iter()
792                    .position(|step| total_progress as f32 <= step.start_percentage);
793                prev_keyframe_index = next_keyframe_index
794                    .and_then(|pos| if pos != 0 { Some(pos - 1) } else { None })
795                    .unwrap_or(0);
796            },
797            AnimationDirection::Reverse => {
798                next_keyframe_index = self
799                    .computed_steps
800                    .iter()
801                    .rev()
802                    .position(|step| total_progress as f32 <= 1. - step.start_percentage)
803                    .map(|pos| num_steps - pos - 1);
804                prev_keyframe_index = next_keyframe_index
805                    .and_then(|pos| {
806                        if pos != num_steps - 1 {
807                            Some(pos + 1)
808                        } else {
809                            None
810                        }
811                    })
812                    .unwrap_or(num_steps - 1)
813            },
814            _ => unreachable!(),
815        }
816
817        debug!(
818            "Animation::get_property_declaration_at_time: keyframe from {:?} to {:?}",
819            prev_keyframe_index, next_keyframe_index
820        );
821
822        let Some(next_keyframe_index) = next_keyframe_index else {
823            return;
824        };
825
826        // If we only need to take into account one keyframe, then exit early
827        // in order to avoid doing more work.
828        let mut add_declarations_to_map = |keyframe_index: usize| {
829            for value_or_reference in &self.computed_steps[keyframe_index].values {
830                let AnimationValueOrReference::AnimationValue(value) = value_or_reference else {
831                    unreachable!("First or last keyframes define all properties");
832                };
833
834                map.insert(value.id().to_owned(), value.clone());
835            }
836        };
837
838        let reversed = self.current_direction != AnimationDirection::Normal;
839        if total_progress <= 0.0 {
840            if reversed {
841                add_declarations_to_map(self.computed_steps.len() - 1);
842            } else {
843                add_declarations_to_map(0);
844            }
845            return;
846        }
847        if total_progress >= 1.0 {
848            if reversed {
849                add_declarations_to_map(0);
850            } else {
851                add_declarations_to_map(self.computed_steps.len() - 1);
852            }
853            return;
854        }
855
856        // Interpolate a new value for each animating property
857        for property_index in 0..self.number_of_animating_properties {
858            let Some(previous_keyframe) = self.next_relevant_keyframe_for_property_in_direction(
859                property_index,
860                prev_keyframe_index,
861                Direction::Backward.relative_to_animation_direction(reversed),
862            ) else {
863                // Animation of this property has not started yet
864                continue;
865            };
866
867            let Some(next_keyframe) = self.next_relevant_keyframe_for_property_in_direction(
868                property_index,
869                next_keyframe_index,
870                Direction::Forward.relative_to_animation_direction(reversed),
871            ) else {
872                // This property has finished animating, just use the previous data
873                map.insert(
874                    previous_keyframe.value.id().to_owned(),
875                    previous_keyframe.value.clone(),
876                );
877                continue;
878            };
879
880            let percentage_between_keyframes =
881                (next_keyframe.start_percentage - previous_keyframe.start_percentage).abs() as f64;
882            let duration_between_keyframes = percentage_between_keyframes * self.duration;
883            let direction_aware_prev_keyframe_start_percentage = match self.current_direction {
884                AnimationDirection::Normal => previous_keyframe.start_percentage as f64,
885                AnimationDirection::Reverse => 1. - previous_keyframe.start_percentage as f64,
886                _ => unreachable!(),
887            };
888            let progress_between_keyframes = (total_progress
889                - direction_aware_prev_keyframe_start_percentage)
890                / percentage_between_keyframes;
891            let animation = PropertyAnimation {
892                from: previous_keyframe.value.clone(),
893                to: next_keyframe.value.clone(),
894                timing_function: previous_keyframe.timing_function.clone(),
895                duration: duration_between_keyframes as f64,
896            };
897
898            let value = animation.calculate_value(progress_between_keyframes);
899            map.insert(value.id().to_owned(), value);
900        }
901    }
902}
903
904impl fmt::Debug for Animation {
905    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
906        f.debug_struct("Animation")
907            .field("name", &self.name)
908            .field("started_at", &self.started_at)
909            .field("duration", &self.duration)
910            .field("delay", &self.delay)
911            .field("iteration_state", &self.iteration_state)
912            .field("state", &self.state)
913            .field("direction", &self.direction)
914            .field("current_direction", &self.current_direction)
915            .field("cascade_style", &())
916            .finish()
917    }
918}
919
920/// A CSS Transition
921#[derive(Clone, Debug, MallocSizeOf)]
922pub struct Transition {
923    /// The start time of this transition, which is the current value of the animation
924    /// timeline when this transition was created plus any animation delay.
925    pub start_time: f64,
926
927    /// The delay used for this transition.
928    pub delay: f64,
929
930    /// The internal style `PropertyAnimation` for this transition.
931    pub property_animation: PropertyAnimation,
932
933    /// The state of this transition.
934    pub state: AnimationState,
935
936    /// Whether or not this transition is new and or has already been tracked
937    /// by the script thread.
938    pub is_new: bool,
939
940    /// If this `Transition` has been replaced by a new one this field is
941    /// used to help produce better reversed transitions.
942    pub reversing_adjusted_start_value: AnimationValue,
943
944    /// If this `Transition` has been replaced by a new one this field is
945    /// used to help produce better reversed transitions.
946    pub reversing_shortening_factor: f64,
947}
948
949impl Transition {
950    fn new(
951        start_time: f64,
952        delay: f64,
953        duration: f64,
954        from: AnimationValue,
955        to: AnimationValue,
956        timing_function: &TimingFunction,
957    ) -> Self {
958        let property_animation = PropertyAnimation {
959            from: from.clone(),
960            to,
961            timing_function: timing_function.clone(),
962            duration,
963        };
964        Self {
965            start_time,
966            delay,
967            property_animation,
968            state: AnimationState::Pending,
969            is_new: true,
970            reversing_adjusted_start_value: from,
971            reversing_shortening_factor: 1.0,
972        }
973    }
974
975    fn update_for_possibly_reversed_transition(
976        &mut self,
977        replaced_transition: &Transition,
978        delay: f64,
979        now: f64,
980    ) {
981        // If we reach here, we need to calculate a reversed transition according to
982        // https://drafts.csswg.org/css-transitions/#starting
983        //
984        //  "...if the reversing-adjusted start value of the running transition
985        //  is the same as the value of the property in the after-change style (see
986        //  the section on reversing of transitions for why these case exists),
987        //  implementations must cancel the running transition and start
988        //  a new transition..."
989        if replaced_transition.reversing_adjusted_start_value != self.property_animation.to {
990            return;
991        }
992
993        // "* reversing-adjusted start value is the end value of the running transition"
994        let replaced_animation = &replaced_transition.property_animation;
995        self.reversing_adjusted_start_value = replaced_animation.to.clone();
996
997        // "* reversing shortening factor is the absolute value, clamped to the
998        //    range [0, 1], of the sum of:
999        //    1. the output of the timing function of the old transition at the
1000        //      time of the style change event, times the reversing shortening
1001        //      factor of the old transition
1002        //    2.  1 minus the reversing shortening factor of the old transition."
1003        let transition_progress = ((now - replaced_transition.start_time)
1004            / (replaced_transition.property_animation.duration))
1005            .min(1.0)
1006            .max(0.0);
1007        let timing_function_output = replaced_animation.timing_function_output(transition_progress);
1008        let old_reversing_shortening_factor = replaced_transition.reversing_shortening_factor;
1009        self.reversing_shortening_factor = ((timing_function_output
1010            * old_reversing_shortening_factor)
1011            + (1.0 - old_reversing_shortening_factor))
1012            .abs()
1013            .min(1.0)
1014            .max(0.0);
1015
1016        // "* start time is the time of the style change event plus:
1017        //    1. if the matching transition delay is nonnegative, the matching
1018        //       transition delay, or.
1019        //    2. if the matching transition delay is negative, the product of the new
1020        //       transition’s reversing shortening factor and the matching transition delay,"
1021        self.start_time = if delay >= 0. {
1022            now + delay
1023        } else {
1024            now + (self.reversing_shortening_factor * delay)
1025        };
1026
1027        // "* end time is the start time plus the product of the matching transition
1028        //    duration and the new transition’s reversing shortening factor,"
1029        self.property_animation.duration *= self.reversing_shortening_factor;
1030
1031        // "* start value is the current value of the property in the running transition,
1032        //  * end value is the value of the property in the after-change style,"
1033        let procedure = Procedure::Interpolate {
1034            progress: timing_function_output,
1035        };
1036        match replaced_animation
1037            .from
1038            .animate(&replaced_animation.to, procedure)
1039        {
1040            Ok(new_start) => self.property_animation.from = new_start,
1041            Err(..) => {},
1042        }
1043    }
1044
1045    /// Whether or not this animation has ended at the provided time. This does
1046    /// not take into account canceling i.e. when an animation or transition is
1047    /// canceled due to changes in the style.
1048    pub fn has_ended(&self, time: f64) -> bool {
1049        time >= self.start_time + (self.property_animation.duration)
1050    }
1051
1052    /// Update the given animation at a given point of progress.
1053    pub fn calculate_value(&self, time: f64) -> AnimationValue {
1054        let progress = (time - self.start_time) / (self.property_animation.duration);
1055        self.property_animation
1056            .calculate_value(progress.clamp(0.0, 1.0))
1057    }
1058}
1059
1060/// Holds the animation state for a particular element.
1061#[derive(Debug, Default, MallocSizeOf)]
1062pub struct ElementAnimationSet {
1063    /// The animations for this element.
1064    pub animations: Vec<Animation>,
1065
1066    /// The transitions for this element.
1067    pub transitions: Vec<Transition>,
1068
1069    /// Whether or not this ElementAnimationSet has had animations or transitions
1070    /// which have been added, removed, or had their state changed.
1071    pub dirty: bool,
1072}
1073
1074impl ElementAnimationSet {
1075    /// Cancel all animations in this `ElementAnimationSet`. This is typically called
1076    /// when the element has been removed from the DOM.
1077    pub fn cancel_all_animations(&mut self) {
1078        self.dirty = !self.animations.is_empty();
1079        for animation in self.animations.iter_mut() {
1080            animation.state = AnimationState::Canceled;
1081        }
1082        self.cancel_active_transitions();
1083    }
1084
1085    fn cancel_active_transitions(&mut self) {
1086        for transition in self.transitions.iter_mut() {
1087            if transition.state != AnimationState::Finished {
1088                self.dirty = true;
1089                transition.state = AnimationState::Canceled;
1090            }
1091        }
1092    }
1093
1094    /// Apply all active animations.
1095    pub fn apply_active_animations(
1096        &self,
1097        context: &SharedStyleContext,
1098        style: &mut Arc<ComputedValues>,
1099    ) {
1100        let now = context.current_time_for_animations;
1101        let mutable_style = Arc::make_mut(style);
1102        if let Some(map) = self.get_value_map_for_active_animations(now) {
1103            for value in map.values() {
1104                value.set_in_style_for_servo(mutable_style, context);
1105            }
1106        }
1107
1108        if let Some(map) = self.get_value_map_for_transitions(now, IgnoreTransitions::Canceled) {
1109            for value in map.values() {
1110                value.set_in_style_for_servo(mutable_style, context);
1111            }
1112        }
1113    }
1114
1115    /// Clear all canceled animations and transitions from this `ElementAnimationSet`.
1116    pub fn clear_canceled_animations(&mut self) {
1117        self.animations
1118            .retain(|animation| animation.state != AnimationState::Canceled);
1119        self.transitions
1120            .retain(|animation| animation.state != AnimationState::Canceled);
1121    }
1122
1123    /// Whether this `ElementAnimationSet` is empty, which means it doesn't
1124    /// hold any animations in any state.
1125    pub fn is_empty(&self) -> bool {
1126        self.animations.is_empty() && self.transitions.is_empty()
1127    }
1128
1129    /// Whether or not this state needs animation ticks for its transitions
1130    /// or animations.
1131    pub fn needs_animation_ticks(&self) -> bool {
1132        self.animations
1133            .iter()
1134            .any(|animation| animation.state.needs_to_be_ticked())
1135            || self
1136                .transitions
1137                .iter()
1138                .any(|transition| transition.state.needs_to_be_ticked())
1139    }
1140
1141    /// The number of running animations and transitions for this `ElementAnimationSet`.
1142    pub fn running_animation_and_transition_count(&self) -> usize {
1143        self.animations
1144            .iter()
1145            .filter(|animation| animation.state.needs_to_be_ticked())
1146            .count()
1147            + self
1148                .transitions
1149                .iter()
1150                .filter(|transition| transition.state.needs_to_be_ticked())
1151                .count()
1152    }
1153
1154    /// If this `ElementAnimationSet` has any any active animations.
1155    pub fn has_active_animation(&self) -> bool {
1156        self.animations
1157            .iter()
1158            .any(|animation| animation.state != AnimationState::Canceled)
1159    }
1160
1161    /// If this `ElementAnimationSet` has any any active transitions.
1162    pub fn has_active_transition(&self) -> bool {
1163        self.transitions
1164            .iter()
1165            .any(|transition| transition.state != AnimationState::Canceled)
1166    }
1167
1168    /// Update our animations given a new style, canceling or starting new animations
1169    /// when appropriate.
1170    pub fn update_animations_for_new_style<E>(
1171        &mut self,
1172        element: E,
1173        context: &SharedStyleContext,
1174        new_style: &Arc<ComputedValues>,
1175        resolver: &mut StyleResolverForElement<E>,
1176    ) where
1177        E: TElement,
1178    {
1179        for animation in self.animations.iter_mut() {
1180            if animation.is_cancelled_in_new_style(new_style) {
1181                animation.state = AnimationState::Canceled;
1182            }
1183        }
1184
1185        maybe_start_animations(element, &context, &new_style, self, resolver);
1186    }
1187
1188    /// Update our transitions given a new style, canceling or starting new animations
1189    /// when appropriate.
1190    pub fn update_transitions_for_new_style(
1191        &mut self,
1192        might_need_transitions_update: bool,
1193        context: &SharedStyleContext,
1194        old_style: Option<&Arc<ComputedValues>>,
1195        after_change_style: &Arc<ComputedValues>,
1196    ) {
1197        // If this is the first style, we don't trigger any transitions and we assume
1198        // there were no previously triggered transitions.
1199        let mut before_change_style = match old_style {
1200            Some(old_style) => Arc::clone(old_style),
1201            None => return,
1202        };
1203
1204        // If the style of this element is display:none, then cancel all active transitions.
1205        if after_change_style.get_box().clone_display().is_none() {
1206            self.cancel_active_transitions();
1207            return;
1208        }
1209
1210        if !might_need_transitions_update {
1211            return;
1212        }
1213
1214        // We convert old values into `before-change-style` here.
1215        if self.has_active_transition() || self.has_active_animation() {
1216            self.apply_active_animations(context, &mut before_change_style);
1217        }
1218
1219        let transitioning_properties = start_transitions_if_applicable(
1220            context,
1221            &before_change_style,
1222            after_change_style,
1223            self,
1224        );
1225
1226        // Cancel any non-finished transitions that have properties which no
1227        // longer transition.
1228        //
1229        // Step 3 in https://drafts.csswg.org/css-transitions/#starting:
1230        // > If the element has a running transition or completed transition for
1231        // > the property, and there is not a matching transition-property value,
1232        // > then implementations must cancel the running transition or remove the
1233        // > completed transition from the set of completed transitions.
1234        //
1235        // TODO: This is happening here as opposed to in
1236        // `start_transition_if_applicable` as an optimization, but maybe this
1237        // code should be reworked to be more like the specification.
1238        for transition in self.transitions.iter_mut() {
1239            if transition.state == AnimationState::Finished
1240                || transition.state == AnimationState::Canceled
1241            {
1242                continue;
1243            }
1244            if transitioning_properties.contains(transition.property_animation.property_id()) {
1245                continue;
1246            }
1247            transition.state = AnimationState::Canceled;
1248            self.dirty = true;
1249        }
1250    }
1251
1252    fn start_transition_if_applicable(
1253        &mut self,
1254        context: &SharedStyleContext,
1255        property_declaration_id: &PropertyDeclarationId,
1256        index: usize,
1257        old_style: &ComputedValues,
1258        new_style: &Arc<ComputedValues>,
1259    ) {
1260        let style = new_style.get_ui();
1261        let allow_discrete =
1262            style.transition_behavior_mod(index) == TransitionBehavior::AllowDiscrete;
1263
1264        // FIXME(emilio): Handle the case where old_style and new_style's writing mode differ.
1265        let Some(from) = AnimationValue::from_computed_values(*property_declaration_id, old_style)
1266        else {
1267            return;
1268        };
1269        let Some(to) = AnimationValue::from_computed_values(*property_declaration_id, new_style)
1270        else {
1271            return;
1272        };
1273
1274        let timing_function = style.transition_timing_function_mod(index);
1275        let duration = style.transition_duration_mod(index).seconds() as f64;
1276        let delay = style.transition_delay_mod(index).seconds() as f64;
1277        let now = context.current_time_for_animations;
1278        let transitionable = property_declaration_id.is_animatable()
1279            && (allow_discrete || !property_declaration_id.is_discrete_animatable())
1280            && (allow_discrete || from.interpolable_with(&to));
1281
1282        let mut existing_transition = self.transitions.iter_mut().find(|transition| {
1283            transition.property_animation.property_id() == *property_declaration_id
1284        });
1285
1286        // Step 1:
1287        // > If all of the following are true:
1288        // >  - the element does not have a running transition for the property,
1289        // >  - the before-change style is different from the after-change style
1290        // >    for that property, and the values for the property are
1291        // >    transitionable,
1292        // >  - the element does not have a completed transition for the property
1293        // >    or the end value of the completed transition is different from the
1294        // >    after-change style for the property,
1295        // >  - there is a matching transition-property value, and
1296        // >  - the combined duration is greater than 0s,
1297        //
1298        // This function is only run if there is a matching transition-property
1299        // value, so that check is skipped here.
1300        let has_running_transition = existing_transition.as_ref().is_some_and(|transition| {
1301            transition.state != AnimationState::Finished
1302                && transition.state != AnimationState::Canceled
1303        });
1304        let no_completed_transition_or_end_values_differ =
1305            existing_transition.as_ref().is_none_or(|transition| {
1306                transition.state != AnimationState::Finished
1307                    || transition.property_animation.to != to
1308            });
1309        if !has_running_transition
1310            && from != to
1311            && transitionable
1312            && no_completed_transition_or_end_values_differ
1313            && (duration + delay > 0.0)
1314        {
1315            // > then implementations must remove the completed transition (if
1316            // > present) from the set of completed transitions and start a
1317            // > transition whose:
1318            // >
1319            // > - start time is the time of the style change event plus the matching transition delay,
1320            // > - end time is the start time plus the matching transition duration,
1321            // > - start value is the value of the transitioning property in the before-change style,
1322            // > - end value is the value of the transitioning property in the after-change style,
1323            // > - reversing-adjusted start value is the same as the start value, and
1324            // > - reversing shortening factor is 1.
1325            self.transitions.push(Transition::new(
1326                now + delay, /* start_time */
1327                delay,
1328                duration,
1329                from,
1330                to,
1331                &timing_function,
1332            ));
1333            self.dirty = true;
1334            return;
1335        }
1336
1337        // > Step 2: Otherwise, if the element has a completed transition for the
1338        // > property and the end value of the completed transition is different
1339        // > from the after-change style for the property, then implementations
1340        // > must remove the completed transition from the set of completed
1341        // > transitions.
1342        //
1343        // All completed transitions will be cleared from the `AnimationSet` in
1344        // `process_animations_for_style in `matching.rs`.
1345
1346        // > Step 3: If the element has a running transition or completed
1347        // > transition for the property, and there is not a matching
1348        // > transition-property value, then implementations must cancel the
1349        // > running transition or remove the completed transition from the set
1350        // > of completed transitions.
1351        //
1352        // - All completed transitions will be cleared cleared from the `AnimationSet` in
1353        //   `process_animations_for_style in `matching.rs`.
1354        // - Transitions for properties that don't have a matching transition-property
1355        //   value will be canceled in `Self::update_transitions_for_new_style`. In addition,
1356        //   this method is only called for properties that do ahave a matching
1357        //   transition-property value.
1358
1359        let Some(existing_transition) = existing_transition.as_mut() else {
1360            return;
1361        };
1362
1363        // > Step 4: If the element has a running transition for the property,
1364        // > there is a matching transition-property value, and the end value of
1365        // > the running transition is not equal to the value of the property in
1366        // > the after-change style, then:
1367        if has_running_transition && existing_transition.property_animation.to != to {
1368            // > Step 4.1: If the current value of the property in the running transition is
1369            // > equal to the value of the property in the after-change style, or
1370            // > if these two values are not transitionable, then implementations
1371            // > must cancel the running transition.
1372            let current_value = existing_transition.calculate_value(now);
1373            let transitionable_from_current_value =
1374                transitionable && (allow_discrete || current_value.interpolable_with(&to));
1375            if current_value == to || !transitionable_from_current_value {
1376                existing_transition.state = AnimationState::Canceled;
1377                self.dirty = true;
1378                return;
1379            }
1380
1381            // > Step 4.2: Otherwise, if the combined duration is less than or
1382            // > equal to 0s, or if the current value of the property in the
1383            // > running transition is not transitionable with the value of the
1384            // > property in the after-change style, then implementations must
1385            // > cancel the running transition.
1386            if duration + delay <= 0.0 {
1387                existing_transition.state = AnimationState::Canceled;
1388                self.dirty = true;
1389                return;
1390            }
1391
1392            // > Step 4.3: Otherwise, if the reversing-adjusted start value of the
1393            // > running transition is the same as the value of the property in
1394            // > the after-change style (see the section on reversing of
1395            // > transitions for why these case exists), implementations must
1396            // > cancel the running transition and start a new transition whose:
1397            if existing_transition.reversing_adjusted_start_value == to {
1398                existing_transition.state = AnimationState::Canceled;
1399
1400                let mut transition = Transition::new(
1401                    now + delay, /* start_time */
1402                    delay,
1403                    duration,
1404                    from,
1405                    to,
1406                    &timing_function,
1407                );
1408
1409                // This function takes care of applying all of the modifications to the transition
1410                // after "whose:" above.
1411                transition.update_for_possibly_reversed_transition(
1412                    &existing_transition,
1413                    delay,
1414                    now,
1415                );
1416
1417                self.transitions.push(transition);
1418                self.dirty = true;
1419                return;
1420            }
1421
1422            // > Step 4.4: Otherwise, implementations must cancel the running
1423            // > transition and start a new transition whose:
1424            // >  - start time is the time of the style change event plus the matching transition delay,
1425            // >  - end time is the start time plus the matching transition duration,
1426            // >  - start value is the current value of the property in the running transition,
1427            // >  - end value is the value of the property in the after-change style,
1428            // >  - reversing-adjusted start value is the same as the start value, and
1429            // >  - reversing shortening factor is 1.
1430            existing_transition.state = AnimationState::Canceled;
1431            self.transitions.push(Transition::new(
1432                now + delay, /* start_time */
1433                delay,
1434                duration,
1435                current_value,
1436                to,
1437                &timing_function,
1438            ));
1439            self.dirty = true;
1440        }
1441    }
1442
1443    /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
1444    /// transitions, ignoring those specified by the `ignore_transitions`
1445    /// argument.
1446    fn get_value_map_for_transitions(
1447        &self,
1448        now: f64,
1449        ignore_transitions: IgnoreTransitions,
1450    ) -> Option<AnimationValueMap> {
1451        if !self.has_active_transition() {
1452            return None;
1453        }
1454
1455        let mut map =
1456            AnimationValueMap::with_capacity_and_hasher(self.transitions.len(), Default::default());
1457        for transition in &self.transitions {
1458            match ignore_transitions {
1459                IgnoreTransitions::Canceled => {
1460                    if transition.state == AnimationState::Canceled {
1461                        continue;
1462                    }
1463                },
1464                IgnoreTransitions::CanceledAndFinished => {
1465                    if transition.state == AnimationState::Canceled
1466                        || transition.state == AnimationState::Finished
1467                    {
1468                        continue;
1469                    }
1470                },
1471            }
1472
1473            let value = transition.calculate_value(now);
1474            map.insert(value.id().to_owned(), value);
1475        }
1476
1477        Some(map)
1478    }
1479
1480    /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
1481    /// active animations at the given time value.
1482    pub fn get_value_map_for_active_animations(&self, now: f64) -> Option<AnimationValueMap> {
1483        if !self.has_active_animation() {
1484            return None;
1485        }
1486
1487        let mut map = Default::default();
1488        for animation in &self.animations {
1489            animation.get_property_declaration_at_time(now, &mut map);
1490        }
1491
1492        Some(map)
1493    }
1494}
1495
1496#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
1497/// A key that is used to identify nodes in the `DocumentAnimationSet`.
1498pub struct AnimationSetKey {
1499    /// The node for this `AnimationSetKey`.
1500    pub node: OpaqueNode,
1501    /// The pseudo element for this `AnimationSetKey`. If `None` this key will
1502    /// refer to the main content for its node.
1503    pub pseudo_element: Option<PseudoElement>,
1504}
1505
1506impl AnimationSetKey {
1507    /// Create a new key given a node and optional pseudo element.
1508    pub fn new(node: OpaqueNode, pseudo_element: Option<PseudoElement>) -> Self {
1509        AnimationSetKey {
1510            node,
1511            pseudo_element,
1512        }
1513    }
1514
1515    /// Create a new key for the main content of this node.
1516    pub fn new_for_non_pseudo(node: OpaqueNode) -> Self {
1517        AnimationSetKey {
1518            node,
1519            pseudo_element: None,
1520        }
1521    }
1522
1523    /// Create a new key for given node and pseudo element.
1524    pub fn new_for_pseudo(node: OpaqueNode, pseudo_element: PseudoElement) -> Self {
1525        AnimationSetKey {
1526            node,
1527            pseudo_element: Some(pseudo_element),
1528        }
1529    }
1530}
1531
1532#[derive(Clone, Debug, Default, MallocSizeOf)]
1533/// A set of animations for a document.
1534pub struct DocumentAnimationSet {
1535    /// The `ElementAnimationSet`s that this set contains.
1536    #[ignore_malloc_size_of = "Arc is hard"]
1537    pub sets: Arc<RwLock<FxHashMap<AnimationSetKey, ElementAnimationSet>>>,
1538}
1539
1540impl DocumentAnimationSet {
1541    /// Return whether or not the provided node has active CSS animations.
1542    pub fn has_active_animations(&self, key: &AnimationSetKey) -> bool {
1543        self.sets
1544            .read()
1545            .get(key)
1546            .map_or(false, |set| set.has_active_animation())
1547    }
1548
1549    /// Return whether or not the provided node has active CSS transitions.
1550    pub fn has_active_transitions(&self, key: &AnimationSetKey) -> bool {
1551        self.sets
1552            .read()
1553            .get(key)
1554            .map_or(false, |set| set.has_active_transition())
1555    }
1556
1557    /// Return a locked PropertyDeclarationBlock with animation values for the given
1558    /// key and time.
1559    pub fn get_animation_declarations(
1560        &self,
1561        key: &AnimationSetKey,
1562        time: f64,
1563        shared_lock: &SharedRwLock,
1564    ) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
1565        self.sets
1566            .read()
1567            .get(key)
1568            .and_then(|set| set.get_value_map_for_active_animations(time))
1569            .map(|map| {
1570                let block = PropertyDeclarationBlock::from_animation_value_map(&map);
1571                Arc::new(shared_lock.wrap(block))
1572            })
1573    }
1574
1575    /// Return a locked PropertyDeclarationBlock with transition values for the given
1576    /// key and time.
1577    pub fn get_transition_declarations(
1578        &self,
1579        key: &AnimationSetKey,
1580        time: f64,
1581        shared_lock: &SharedRwLock,
1582    ) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
1583        self.sets
1584            .read()
1585            .get(key)
1586            .and_then(|set| {
1587                set.get_value_map_for_transitions(time, IgnoreTransitions::CanceledAndFinished)
1588            })
1589            .map(|map| {
1590                let block = PropertyDeclarationBlock::from_animation_value_map(&map);
1591                Arc::new(shared_lock.wrap(block))
1592            })
1593    }
1594
1595    /// Get all the animation declarations for the given key, returning an empty
1596    /// `AnimationDeclarations` if there are no animations.
1597    pub fn get_all_declarations(
1598        &self,
1599        key: &AnimationSetKey,
1600        time: f64,
1601        shared_lock: &SharedRwLock,
1602    ) -> AnimationDeclarations {
1603        let sets = self.sets.read();
1604        let set = match sets.get(key) {
1605            Some(set) => set,
1606            None => return Default::default(),
1607        };
1608
1609        let animations = set.get_value_map_for_active_animations(time).map(|map| {
1610            let block = PropertyDeclarationBlock::from_animation_value_map(&map);
1611            Arc::new(shared_lock.wrap(block))
1612        });
1613        let transitions = set
1614            .get_value_map_for_transitions(time, IgnoreTransitions::CanceledAndFinished)
1615            .map(|map| {
1616                let block = PropertyDeclarationBlock::from_animation_value_map(&map);
1617                Arc::new(shared_lock.wrap(block))
1618            });
1619        AnimationDeclarations {
1620            animations,
1621            transitions,
1622        }
1623    }
1624
1625    /// Cancel all animations for set at the given key.
1626    pub fn cancel_all_animations_for_key(&self, key: &AnimationSetKey) {
1627        if let Some(set) = self.sets.write().get_mut(key) {
1628            set.cancel_all_animations();
1629        }
1630    }
1631}
1632
1633/// Kick off any new transitions for this node and return all of the properties that are
1634/// transitioning. This is at the end of calculating style for a single node.
1635pub fn start_transitions_if_applicable(
1636    context: &SharedStyleContext,
1637    old_style: &ComputedValues,
1638    new_style: &Arc<ComputedValues>,
1639    animation_state: &mut ElementAnimationSet,
1640) -> PropertyDeclarationIdSet {
1641    // See <https://www.w3.org/TR/css-transitions-1/#transitions>
1642    // "If a property is specified multiple times in the value of transition-property
1643    // (either on its own, via a shorthand that contains it, or via the all value),
1644    // then the transition that starts uses the duration, delay, and timing function
1645    // at the index corresponding to the last item in the value of transition-property
1646    // that calls for animating that property."
1647    // See Example 3 of <https://www.w3.org/TR/css-transitions-1/#transitions>
1648    //
1649    // Reversing the transition order here means that transitions defined later in the list
1650    // have preference, in accordance with the specification.
1651    //
1652    // TODO: It would be better to be able to do this without having to allocate an array.
1653    // We should restructure the code or make `transition_properties()` return a reversible
1654    // iterator in order to avoid the allocation.
1655    let mut transition_properties = new_style.transition_properties().collect::<Vec<_>>();
1656    transition_properties.reverse();
1657
1658    let mut properties_that_transition = PropertyDeclarationIdSet::default();
1659    for transition in transition_properties {
1660        let physical_property = transition
1661            .property
1662            .as_borrowed()
1663            .to_physical(new_style.writing_mode);
1664        if properties_that_transition.contains(physical_property) {
1665            continue;
1666        }
1667
1668        properties_that_transition.insert(physical_property);
1669        animation_state.start_transition_if_applicable(
1670            context,
1671            &physical_property,
1672            transition.index,
1673            old_style,
1674            new_style,
1675        );
1676    }
1677
1678    properties_that_transition
1679}
1680
1681/// Triggers animations for a given node looking at the animation property
1682/// values.
1683pub fn maybe_start_animations<E>(
1684    element: E,
1685    context: &SharedStyleContext,
1686    new_style: &Arc<ComputedValues>,
1687    animation_state: &mut ElementAnimationSet,
1688    resolver: &mut StyleResolverForElement<E>,
1689) where
1690    E: TElement,
1691{
1692    let style = new_style.get_ui();
1693    for (i, name) in style.animation_name_iter().enumerate() {
1694        let name = match name.as_atom() {
1695            Some(atom) => atom,
1696            None => continue,
1697        };
1698
1699        debug!("maybe_start_animations: name={}", name);
1700        let duration = style.animation_duration_mod(i).seconds() as f64;
1701        if duration == 0. {
1702            continue;
1703        }
1704
1705        let Some(keyframe_animation) = context.stylist.lookup_keyframes(name, element) else {
1706            continue;
1707        };
1708
1709        debug!("maybe_start_animations: animation {} found", name);
1710
1711        // NB: This delay may be negative, meaning that the animation may be created
1712        // in a state where we have advanced one or more iterations or even that the
1713        // animation begins in a finished state.
1714        let delay = style.animation_delay_mod(i).seconds();
1715
1716        let iteration_count = style.animation_iteration_count_mod(i);
1717        let iteration_state = if iteration_count.0.is_infinite() {
1718            KeyframesIterationState::Infinite(0.0)
1719        } else {
1720            KeyframesIterationState::Finite(0.0, iteration_count.0 as f64)
1721        };
1722
1723        let animation_direction = style.animation_direction_mod(i);
1724
1725        let initial_direction = match animation_direction {
1726            AnimationDirection::Normal | AnimationDirection::Alternate => {
1727                AnimationDirection::Normal
1728            },
1729            AnimationDirection::Reverse | AnimationDirection::AlternateReverse => {
1730                AnimationDirection::Reverse
1731            },
1732        };
1733
1734        let now = context.current_time_for_animations;
1735        let started_at = now + delay as f64;
1736        let mut starting_progress = (now - started_at) / duration;
1737        let state = match style.animation_play_state_mod(i) {
1738            AnimationPlayState::Paused => AnimationState::Paused(starting_progress),
1739            AnimationPlayState::Running => AnimationState::Pending,
1740        };
1741
1742        // Determine the set of animating properties. This is not equivalent to the set of changed properties
1743        // when one changed property overrides another. (For example, "block-size" with writing-mode: initial
1744        // is the same as "height")
1745        let mut animating_properties = PropertyDeclarationIdSet::default();
1746        let mut number_of_animating_properties = 0;
1747        for property in keyframe_animation.properties_changed.iter() {
1748            debug_assert!(property.is_animatable());
1749
1750            if animating_properties.insert(property.to_physical(new_style.writing_mode)) {
1751                number_of_animating_properties += 1;
1752            }
1753        }
1754
1755        let computed_steps = ComputedKeyframe::generate_for_keyframes(
1756            element,
1757            &keyframe_animation,
1758            context,
1759            new_style,
1760            style.animation_timing_function_mod(i),
1761            resolver,
1762            animating_properties,
1763            number_of_animating_properties,
1764        );
1765
1766        let mut new_animation = Animation {
1767            name: name.clone(),
1768            properties_changed: keyframe_animation.properties_changed.clone(),
1769            computed_steps,
1770            started_at,
1771            duration,
1772            fill_mode: style.animation_fill_mode_mod(i),
1773            delay: delay as f64,
1774            iteration_state,
1775            state,
1776            direction: animation_direction,
1777            current_direction: initial_direction,
1778            number_of_animating_properties,
1779            is_new: true,
1780        };
1781
1782        // If we started with a negative delay, make sure we iterate the animation if
1783        // the delay moves us past the first iteration.
1784        while starting_progress > 1. && !new_animation.on_last_iteration() {
1785            new_animation.iterate();
1786            starting_progress -= 1.;
1787        }
1788
1789        animation_state.dirty = true;
1790
1791        // If the animation was already present in the list for the node, just update its state.
1792        for existing_animation in animation_state.animations.iter_mut() {
1793            if existing_animation.state == AnimationState::Canceled {
1794                continue;
1795            }
1796
1797            if new_animation.name == existing_animation.name {
1798                existing_animation
1799                    .update_from_other(&new_animation, context.current_time_for_animations);
1800                return;
1801            }
1802        }
1803
1804        animation_state.animations.push(new_animation);
1805    }
1806}