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