author | Martin Robinson <mrobinson@igalia.com> |
Thu, 18 Jun 2020 18:14:02 +0000 | |
changeset 536354 | 04f8394b23bb2fcc2f19d6baf1a31a66be6bc297 |
parent 536353 | cb3a0bb7571a752bb87866cdc721e75f9314416a |
child 536355 | 0da5430c2b2eb7ad0592dc831be1945750813132 |
push id | 37520 |
push user | dluca@mozilla.com |
push date | Fri, 19 Jun 2020 04:04:08 +0000 |
treeherder | mozilla-central@d1a4f9157858 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1646811 |
milestone | 79.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/servo/components/style/animation.rs +++ b/servo/components/style/animation.rs @@ -14,23 +14,26 @@ use crate::properties::animated_properti use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection; use crate::properties::longhands::animation_fill_mode::computed_value::single_value::T as AnimationFillMode; use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState; use crate::properties::{ ComputedValues, Importance, LonghandId, LonghandIdSet, PropertyDeclarationBlock, 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}; 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; /// Represents an animation for a given property. #[derive(Clone, Debug, MallocSizeOf)] pub struct PropertyAnimation { /// The value we are animating from. from: AnimationValue, @@ -388,19 +391,16 @@ impl ComputedKeyframe { } computed_steps } } /// 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, /// The properties that change in this animation. properties_changed: LonghandIdSet, /// The computed style for each keyframe of this animation. computed_steps: Vec<ComputedKeyframe>, @@ -731,19 +731,16 @@ impl fmt::Debug for Animation { .field("cascade_style", &()) .finish() } } /// 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, /// The delay used for this transition. pub delay: f64, /// The internal style `PropertyAnimation` for this transition. @@ -886,17 +883,17 @@ impl ElementAnimationSet { if transition.state != AnimationState::Finished { self.dirty = true; transition.state = AnimationState::Canceled; } } } pub(crate) fn apply_active_animations( - &mut self, + &self, context: &SharedStyleContext, style: &mut Arc<ComputedValues>, ) { let now = context.current_time_for_animations; let mutable_style = Arc::make_mut(style); if let Some(map) = self.get_value_map_for_active_animations(now) { for value in map.values() { value.set_in_style_for_servo(mutable_style); @@ -982,17 +979,16 @@ impl ElementAnimationSet { } /// Update our transitions given a new style, canceling or starting new animations /// when appropriate. pub fn update_transitions_for_new_style( &mut self, might_need_transitions_update: bool, context: &SharedStyleContext, - opaque_node: OpaqueNode, old_style: Option<&Arc<ComputedValues>>, after_change_style: &Arc<ComputedValues>, ) { // If this is the first style, we don't trigger any transitions and we assume // there were no previously triggered transitions. let mut before_change_style = match old_style { Some(old_style) => Arc::clone(old_style), None => return, @@ -1010,17 +1006,16 @@ impl ElementAnimationSet { // We convert old values into `before-change-style` here. if self.has_active_transition() || self.has_active_animation() { self.apply_active_animations(context, &mut before_change_style); } let transitioning_properties = start_transitions_if_applicable( context, - opaque_node, &before_change_style, after_change_style, self, ); // Cancel any non-finished transitions that have properties which no longer transition. for transition in self.transitions.iter_mut() { if transition.state == AnimationState::Finished { @@ -1032,17 +1027,16 @@ impl ElementAnimationSet { transition.state = AnimationState::Canceled; self.dirty = true; } } fn start_transition_if_applicable( &mut self, context: &SharedStyleContext, - opaque_node: OpaqueNode, longhand_id: LonghandId, index: usize, old_style: &ComputedValues, new_style: &Arc<ComputedValues>, ) { let box_style = new_style.get_box(); let timing_function = box_style.transition_timing_function_mod(index); let duration = box_style.transition_duration_mod(index); @@ -1074,17 +1068,16 @@ impl ElementAnimationSet { { return; } // We are going to start a new transition, but we might have to update // 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, state: AnimationState::Pending, is_new: true, reversing_adjusted_start_value, reversing_shortening_factor: 1.0, }; @@ -1138,36 +1131,102 @@ impl ElementAnimationSet { for animation in &self.animations { animation.get_property_declaration_at_time(now, &mut map); } Some(map) } } +#[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<RwLock<FxHashMap<AnimationSetKey, ElementAnimationSet>>>, +} + +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<Arc<Locked<PropertyDeclarationBlock>>> { + 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<Arc<Locked<PropertyDeclarationBlock>>> { + 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<ComputedValues>, animation_state: &mut ElementAnimationSet, ) -> LonghandIdSet { let mut properties_that_transition = LonghandIdSet::new(); for transition in new_style.transition_properties() { let physical_property = transition.longhand_id.to_physical(new_style.writing_mode); if properties_that_transition.contains(physical_property) { continue; } properties_that_transition.insert(physical_property); animation_state.start_transition_if_applicable( context, - opaque_node, physical_property, transition.index, old_style, new_style, ); } properties_that_transition @@ -1240,17 +1299,16 @@ pub fn maybe_start_animations<E>( &keyframe_animation, context, new_style, new_style.get_box().animation_timing_function_mod(i), resolver, ); let new_animation = Animation { - node: element.as_node().opaque(), name: name.clone(), properties_changed: keyframe_animation.properties_changed, computed_steps, started_at: animation_start, duration: duration as f64, fill_mode: box_style.animation_fill_mode_mod(i), delay: delay as f64, iteration_state,
--- a/servo/components/style/context.rs +++ b/servo/components/style/context.rs @@ -1,20 +1,18 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! 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")] use crate::gecko_bindings::structs; use crate::parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB}; use crate::properties::ComputedValues; #[cfg(feature = "servo")] use crate::properties::PropertyId; @@ -26,20 +24,19 @@ use crate::sharing::StyleSharingCache; use crate::stylist::Stylist; use crate::thread_state::{self, ThreadState}; use crate::traversal::DomTraversal; use crate::traversal_flags::TraversalFlags; 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; use std::fmt; use std::ops; use style_traits::CSSPixel; use style_traits::DevicePixel; #[cfg(feature = "servo")] @@ -162,17 +159,17 @@ pub struct SharedStyleContext<'a> { /// Flags controlling how we traverse the tree. pub traversal_flags: TraversalFlags, /// A map with our snapshots in order to handle restyle hints. pub snapshot_map: &'a SnapshotMap, /// The state of all animations for our styled elements. #[cfg(feature = "servo")] - pub animation_states: Arc<RwLock<FxHashMap<OpaqueNode, ElementAnimationSet>>>, + pub animations: DocumentAnimationSet, /// Paint worklets #[cfg(feature = "servo")] pub registered_speculative_painters: &'a dyn RegisteredSpeculativePainters, } impl<'a> SharedStyleContext<'a> { /// Return a suitable viewport size in order to be used for viewport units.
--- a/servo/components/style/matching.rs +++ b/servo/components/style/matching.rs @@ -522,39 +522,40 @@ trait PrivateMatchMethods: TElement { #[cfg(feature = "servo")] fn process_animations_for_style( &self, context: &mut StyleContext<Self>, old_values: &mut Option<Arc<ComputedValues>>, new_values: &mut Arc<ComputedValues>, ) -> 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(). let needs_animations_update = self.needs_animations_update(context, old_values.as_ref().map(|s| &**s), new_values); let might_need_transitions_update = self.might_need_transitions_update( context, old_values.as_ref().map(|s| &**s), new_values, ); let mut after_change_style = None; if might_need_transitions_update { 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 // for all the keyframes. We only want to do this if we think that there's a // chance that the animations really changed. if needs_animations_update { let mut resolver = StyleResolverForElement::new( *self, @@ -569,17 +570,16 @@ trait PrivateMatchMethods: TElement { &new_values, &mut resolver, ); } 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), ); // We clear away any finished transitions, but retain animations, because they // might still be used for proper calculation of `animation-fill-mode`. This // should change the computed values in the style, so we don't need to mark // this set as dirty. @@ -588,19 +588,20 @@ trait PrivateMatchMethods: TElement { .retain(|transition| transition.state != AnimationState::Finished); // If the ElementAnimationSet is empty, and don't store it in order to // save memory and to avoid extra processing later. let changed_animations = animation_set.dirty; 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 } /// Computes and applies non-redundant damage. fn accumulate_damage_for( &self,