diff --git a/servo/components/style/animation.rs b/servo/components/style/animation.rs index 75efde37b67f..ecb921a5e4a8 100644 --- a/servo/components/style/animation.rs +++ b/servo/components/style/animation.rs @@ -19,6 +19,7 @@ use crate::properties::{ PropertyDeclarationId, }; use crate::rule_tree::CascadeLevel; +use crate::shared_lock::{Locked, SharedRwLock}; use crate::style_resolver::StyleResolverForElement; use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue}; use crate::values::animated::{Animate, Procedure}; @@ -26,6 +27,8 @@ use crate::values::computed::{Time, TimingFunction}; use crate::values::generics::box_::AnimationIterationCount; use crate::values::generics::easing::{StepPosition, TimingFunction as GenericTimingFunction}; use crate::Atom; +use fxhash::FxHashMap; +use parking_lot::RwLock; use servo_arc::Arc; use std::fmt; @@ -393,9 +396,6 @@ impl ComputedKeyframe { /// A CSS Animation #[derive(Clone, MallocSizeOf)] pub struct Animation { - /// The node associated with this animation. - pub node: OpaqueNode, - /// The name of this animation as defined by the style. pub name: Atom, @@ -736,9 +736,6 @@ impl fmt::Debug for Animation { /// A CSS Transition #[derive(Clone, Debug, MallocSizeOf)] pub struct Transition { - /// The node associated with this animation. - pub node: OpaqueNode, - /// The start time of this transition, which is the current value of the animation /// timeline when this transition was created plus any animation delay. pub start_time: f64, @@ -891,7 +888,7 @@ impl ElementAnimationSet { } pub(crate) fn apply_active_animations( - &mut self, + &self, context: &SharedStyleContext, style: &mut Arc, ) { @@ -987,7 +984,6 @@ impl ElementAnimationSet { &mut self, might_need_transitions_update: bool, context: &SharedStyleContext, - opaque_node: OpaqueNode, old_style: Option<&Arc>, after_change_style: &Arc, ) { @@ -1015,7 +1011,6 @@ impl ElementAnimationSet { let transitioning_properties = start_transitions_if_applicable( context, - opaque_node, &before_change_style, after_change_style, self, @@ -1037,7 +1032,6 @@ impl ElementAnimationSet { fn start_transition_if_applicable( &mut self, context: &SharedStyleContext, - opaque_node: OpaqueNode, longhand_id: LonghandId, index: usize, old_style: &ComputedValues, @@ -1079,7 +1073,6 @@ impl ElementAnimationSet { // it if we are replacing a reversed transition. let reversing_adjusted_start_value = property_animation.from.clone(); let mut new_transition = Transition { - node: opaque_node, start_time: now + delay, delay, property_animation, @@ -1143,11 +1136,78 @@ impl ElementAnimationSet { } } +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +/// A key that is used to identify nodes in the `DocumentAnimationSet`. +pub struct AnimationSetKey(pub OpaqueNode); + +#[derive(Clone, Debug, Default, MallocSizeOf)] +/// A set of animations for a document. +pub struct DocumentAnimationSet { + /// The `ElementAnimationSet`s that this set contains. + #[ignore_malloc_size_of = "Arc is hard"] + pub sets: Arc>>, +} + +impl DocumentAnimationSet { + /// Return whether or not the provided node has active CSS animations. + pub fn has_active_animations(&self, key: &AnimationSetKey) -> bool { + self.sets + .read() + .get(key) + .map(|set| set.has_active_animation()) + .unwrap_or(false) + } + + /// Return whether or not the provided node has active CSS transitions. + pub fn has_active_transitions(&self, key: &AnimationSetKey) -> bool { + self.sets + .read() + .get(key) + .map(|set| set.has_active_transition()) + .unwrap_or(false) + } + + /// Return a locked PropertyDeclarationBlock with animation values for the given + /// key and time. + pub fn get_animation_declarations( + &self, + key: &AnimationSetKey, + time: f64, + shared_lock: &SharedRwLock, + ) -> Option>> { + self.sets + .read() + .get(key) + .and_then(|set| set.get_value_map_for_active_animations(time)) + .map(|map| { + let block = PropertyDeclarationBlock::from_animation_value_map(&map); + Arc::new(shared_lock.wrap(block)) + }) + } + + /// Return a locked PropertyDeclarationBlock with transition values for the given + /// key and time. + pub fn get_transition_declarations( + &self, + key: &AnimationSetKey, + time: f64, + shared_lock: &SharedRwLock, + ) -> Option>> { + self.sets + .read() + .get(key) + .and_then(|set| set.get_value_map_for_active_transitions(time)) + .map(|map| { + let block = PropertyDeclarationBlock::from_animation_value_map(&map); + Arc::new(shared_lock.wrap(block)) + }) + } +} + /// Kick off any new transitions for this node and return all of the properties that are /// transitioning. This is at the end of calculating style for a single node. pub fn start_transitions_if_applicable( context: &SharedStyleContext, - opaque_node: OpaqueNode, old_style: &ComputedValues, new_style: &Arc, animation_state: &mut ElementAnimationSet, @@ -1162,7 +1222,6 @@ pub fn start_transitions_if_applicable( properties_that_transition.insert(physical_property); animation_state.start_transition_if_applicable( context, - opaque_node, physical_property, transition.index, old_style, @@ -1245,7 +1304,6 @@ pub fn maybe_start_animations( ); let new_animation = Animation { - node: element.as_node().opaque(), name: name.clone(), properties_changed: keyframe_animation.properties_changed, computed_steps, diff --git a/servo/components/style/context.rs b/servo/components/style/context.rs index 832fcd109867..608e58ea0320 100644 --- a/servo/components/style/context.rs +++ b/servo/components/style/context.rs @@ -5,11 +5,9 @@ //! The context within which style is calculated. #[cfg(feature = "servo")] -use crate::animation::ElementAnimationSet; +use crate::animation::DocumentAnimationSet; use crate::bloom::StyleBloom; use crate::data::{EagerPseudoStyles, ElementData}; -#[cfg(feature = "servo")] -use crate::dom::OpaqueNode; use crate::dom::{SendElement, TElement}; use crate::font_metrics::FontMetricsProvider; #[cfg(feature = "gecko")] @@ -31,10 +29,9 @@ use app_units::Au; use euclid::default::Size2D; use euclid::Scale; use fxhash::FxHashMap; -#[cfg(feature = "servo")] -use parking_lot::RwLock; use selectors::matching::ElementSelectorFlags; use selectors::NthIndexCache; +#[cfg(feature = "gecko")] use servo_arc::Arc; #[cfg(feature = "servo")] use servo_atoms::Atom; @@ -167,7 +164,7 @@ pub struct SharedStyleContext<'a> { /// The state of all animations for our styled elements. #[cfg(feature = "servo")] - pub animation_states: Arc>>, + pub animations: DocumentAnimationSet, /// Paint worklets #[cfg(feature = "servo")] diff --git a/servo/components/style/matching.rs b/servo/components/style/matching.rs index 359476dc545b..cee6ec7afd23 100644 --- a/servo/components/style/matching.rs +++ b/servo/components/style/matching.rs @@ -527,7 +527,7 @@ trait PrivateMatchMethods: TElement { old_values: &mut Option>, new_values: &mut Arc, ) -> bool { - use crate::animation::AnimationState; + use crate::animation::{AnimationSetKey, AnimationState}; // We need to call this before accessing the `ElementAnimationSet` from the // map because this call will do a RwLock::read(). @@ -544,12 +544,13 @@ trait PrivateMatchMethods: TElement { after_change_style = self.after_change_style(context, new_values); } - let this_opaque = self.as_node().opaque(); + let key = AnimationSetKey(self.as_node().opaque()); let shared_context = context.shared; let mut animation_set = shared_context - .animation_states + .animations + .sets .write() - .remove(&this_opaque) + .remove(&key) .unwrap_or_default(); // Starting animations is expensive, because we have to recalculate the style @@ -574,7 +575,6 @@ trait PrivateMatchMethods: TElement { animation_set.update_transitions_for_new_style( might_need_transitions_update, &shared_context, - this_opaque, old_values.as_ref(), after_change_style.as_ref().unwrap_or(new_values), ); @@ -593,9 +593,10 @@ trait PrivateMatchMethods: TElement { if !animation_set.is_empty() { animation_set.dirty = false; shared_context - .animation_states + .animations + .sets .write() - .insert(this_opaque, animation_set); + .insert(key, animation_set); } changed_animations