style/servo/
animation.rs

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