Skip to main content

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