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