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