diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/layout_2020/flow/root.rs | 5 | ||||
-rw-r--r-- | components/layout_thread/dom_wrapper.rs | 55 | ||||
-rw-r--r-- | components/layout_thread/lib.rs | 24 | ||||
-rw-r--r-- | components/layout_thread_2020/dom_wrapper.rs | 55 | ||||
-rw-r--r-- | components/layout_thread_2020/lib.rs | 20 | ||||
-rw-r--r-- | components/script/animations.rs | 67 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 4 | ||||
-rw-r--r-- | components/script_layout_interface/message.rs | 6 | ||||
-rw-r--r-- | components/style/animation.rs | 86 | ||||
-rw-r--r-- | components/style/context.rs | 9 | ||||
-rw-r--r-- | components/style/matching.rs | 15 |
11 files changed, 184 insertions, 162 deletions
diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 46b7cf8438c..55c325a3cd0 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -35,6 +35,7 @@ use gfx_traits::print_tree::PrintTree; use script_layout_interface::wrapper_traits::LayoutNode; use script_layout_interface::{LayoutElementType, LayoutNodeType}; use servo_arc::Arc; +use style::animation::AnimationSetKey; use style::dom::OpaqueNode; use style::properties::ComputedValues; use style::values::computed::Length; @@ -446,10 +447,10 @@ impl FragmentTree { }) } - pub fn remove_nodes_in_fragment_tree_from_set(&self, set: &mut FxHashSet<OpaqueNode>) { + pub fn remove_nodes_in_fragment_tree_from_set(&self, set: &mut FxHashSet<AnimationSetKey>) { self.find(|fragment, _| { if let Some(tag) = fragment.tag().as_ref() { - set.remove(&tag.node()); + set.remove(&AnimationSetKey(tag.node())); } None::<()> }); diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index b477a653188..3d3f50317a9 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -72,6 +72,7 @@ use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::sync::atomic::Ordering; use std::sync::Arc as StdArc; +use style::animation::AnimationSetKey; use style::applicable_declarations::ApplicableDeclarationBlock; use style::attr::AttrValue; use style::context::SharedStyleContext; @@ -474,20 +475,11 @@ impl<'le> TElement for ServoLayoutElement<'le> { ) -> Option<Arc<StyleLocked<PropertyDeclarationBlock>>> { let node = self.as_node(); let document = node.owner_doc(); - context - .animation_states - .read() - .get(&node.opaque()) - .and_then(|set| { - set.get_value_map_for_active_animations(context.current_time_for_animations) - }) - .map(|map| { - Arc::new( - document - .style_shared_lock() - .wrap(PropertyDeclarationBlock::from_animation_value_map(&map)), - ) - }) + context.animations.get_animation_declarations( + &AnimationSetKey(node.opaque()), + context.current_time_for_animations, + document.style_shared_lock(), + ) } fn transition_rule( @@ -496,20 +488,11 @@ impl<'le> TElement for ServoLayoutElement<'le> { ) -> Option<Arc<StyleLocked<PropertyDeclarationBlock>>> { let node = self.as_node(); let document = node.owner_doc(); - context - .animation_states - .read() - .get(&node.opaque()) - .and_then(|set| { - set.get_value_map_for_active_transitions(context.current_time_for_animations) - }) - .map(|map| { - Arc::new( - document - .style_shared_lock() - .wrap(PropertyDeclarationBlock::from_animation_value_map(&map)), - ) - }) + context.animations.get_transition_declarations( + &AnimationSetKey(node.opaque()), + context.current_time_for_animations, + document.style_shared_lock(), + ) } fn state(&self) -> ElementState { @@ -634,21 +617,13 @@ impl<'le> TElement for ServoLayoutElement<'le> { } fn has_css_animations(&self, context: &SharedStyleContext) -> bool { - context - .animation_states - .read() - .get(&self.as_node().opaque()) - .map(|set| set.has_active_animation()) - .unwrap_or(false) + let key = AnimationSetKey(self.as_node().opaque()); + context.animations.has_active_animations(&key) } fn has_css_transitions(&self, context: &SharedStyleContext) -> bool { - context - .animation_states - .read() - .get(&self.as_node().opaque()) - .map(|set| set.has_active_transition()) - .unwrap_or(false) + let key = AnimationSetKey(self.as_node().opaque()); + context.animations.has_active_transitions(&key) } #[inline] diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 14dbfc0c80e..5930e85b08c 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -42,7 +42,7 @@ use layout::context::malloc_size_of_persistent_local_context; use layout::context::LayoutContext; use layout::context::RegisteredPainter; use layout::context::RegisteredPainters; -use layout::display_list::items::{OpaqueNode, WebRenderImageInfo}; +use layout::display_list::items::WebRenderImageInfo; use layout::display_list::{IndexableText, ToLayout}; use layout::flow::{Flow, GetBaseFlow, ImmutableFlowUtils, MutableOwnedFlowUtils}; use layout::flow_ref::FlowRef; @@ -98,7 +98,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex, MutexGuard}; use std::thread; use std::time::Duration; -use style::animation::ElementAnimationSet; +use style::animation::{AnimationSetKey, DocumentAnimationSet, ElementAnimationSet}; use style::context::SharedStyleContext; use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters}; use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TDocument, TElement, TNode}; @@ -604,7 +604,7 @@ impl LayoutThread { snapshot_map: &'a SnapshotMap, origin: ImmutableOrigin, animation_timeline_value: f64, - animation_states: ServoArc<RwLock<FxHashMap<OpaqueNode, ElementAnimationSet>>>, + animations: &DocumentAnimationSet, stylesheets_changed: bool, ) -> LayoutContext<'a> { let traversal_flags = match stylesheets_changed { @@ -620,7 +620,7 @@ impl LayoutThread { options: GLOBAL_STYLE_DATA.options.clone(), guards, visited_styles_enabled: false, - animation_states, + animations: animations.clone(), registered_speculative_painters: &self.registered_painters, current_time_for_animations: animation_timeline_value, traversal_flags, @@ -1402,7 +1402,7 @@ impl LayoutThread { &map, origin, data.animation_timeline_value, - data.animations.clone(), + &data.animations, data.stylesheets_changed, ); @@ -1643,24 +1643,26 @@ impl LayoutThread { /// TODO(mrobinson): We should look into a way of doing this during flow tree construction. /// This also doesn't yet handles nodes that have been reparented. fn cancel_animations_for_nodes_not_in_flow_tree( - animation_states: &mut FxHashMap<OpaqueNode, ElementAnimationSet>, + animations: &mut FxHashMap<AnimationSetKey, ElementAnimationSet>, root_flow: &mut dyn Flow, ) { // Assume all nodes have been removed until proven otherwise. - let mut invalid_nodes: FxHashSet<OpaqueNode> = animation_states.keys().cloned().collect(); - fn traverse_flow(flow: &mut dyn Flow, invalid_nodes: &mut FxHashSet<OpaqueNode>) { + let mut invalid_nodes = animations.keys().cloned().collect(); + + fn traverse_flow(flow: &mut dyn Flow, invalid_nodes: &mut FxHashSet<AnimationSetKey>) { flow.mutate_fragments(&mut |fragment| { - invalid_nodes.remove(&fragment.node); + invalid_nodes.remove(&AnimationSetKey(fragment.node)); }); for kid in flow.mut_base().children.iter_mut() { traverse_flow(kid, invalid_nodes) } } + traverse_flow(root_flow, &mut invalid_nodes); // Cancel animations for any nodes that are no longer in the flow tree. for node in &invalid_nodes { - if let Some(state) = animation_states.get_mut(node) { + if let Some(state) = animations.get_mut(node) { state.cancel_all_animations(); } } @@ -1676,7 +1678,7 @@ impl LayoutThread { context: &mut LayoutContext, ) { Self::cancel_animations_for_nodes_not_in_flow_tree( - &mut *(context.style_context.animation_states.write()), + &mut *(context.style_context.animations.sets.write()), FlowRef::deref_mut(root_flow), ); diff --git a/components/layout_thread_2020/dom_wrapper.rs b/components/layout_thread_2020/dom_wrapper.rs index 037b927539e..c8a7aa4dd05 100644 --- a/components/layout_thread_2020/dom_wrapper.rs +++ b/components/layout_thread_2020/dom_wrapper.rs @@ -72,6 +72,7 @@ use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::sync::atomic::Ordering; use std::sync::Arc as StdArc; +use style::animation::AnimationSetKey; use style::applicable_declarations::ApplicableDeclarationBlock; use style::attr::AttrValue; use style::context::SharedStyleContext; @@ -482,20 +483,11 @@ impl<'le> TElement for ServoLayoutElement<'le> { ) -> Option<Arc<StyleLocked<PropertyDeclarationBlock>>> { let node = self.as_node(); let document = node.owner_doc(); - context - .animation_states - .read() - .get(&node.opaque()) - .and_then(|set| { - set.get_value_map_for_active_animations(context.current_time_for_animations) - }) - .map(|map| { - Arc::new( - document - .style_shared_lock() - .wrap(PropertyDeclarationBlock::from_animation_value_map(&map)), - ) - }) + context.animations.get_animation_declarations( + &AnimationSetKey(node.opaque()), + context.current_time_for_animations, + document.style_shared_lock(), + ) } fn transition_rule( @@ -504,20 +496,11 @@ impl<'le> TElement for ServoLayoutElement<'le> { ) -> Option<Arc<StyleLocked<PropertyDeclarationBlock>>> { let node = self.as_node(); let document = node.owner_doc(); - context - .animation_states - .read() - .get(&node.opaque()) - .and_then(|set| { - set.get_value_map_for_active_transitions(context.current_time_for_animations) - }) - .map(|map| { - Arc::new( - document - .style_shared_lock() - .wrap(PropertyDeclarationBlock::from_animation_value_map(&map)), - ) - }) + context.animations.get_transition_declarations( + &AnimationSetKey(node.opaque()), + context.current_time_for_animations, + document.style_shared_lock(), + ) } fn state(&self) -> ElementState { @@ -642,21 +625,13 @@ impl<'le> TElement for ServoLayoutElement<'le> { } fn has_css_animations(&self, context: &SharedStyleContext) -> bool { - context - .animation_states - .read() - .get(&self.as_node().opaque()) - .map(|set| set.has_active_animation()) - .unwrap_or(false) + let key = AnimationSetKey(self.as_node().opaque()); + context.animations.has_active_animations(&key) } fn has_css_transitions(&self, context: &SharedStyleContext) -> bool { - context - .animation_states - .read() - .get(&self.as_node().opaque()) - .map(|set| set.has_active_transition()) - .unwrap_or(false) + let key = AnimationSetKey(self.as_node().opaque()); + context.animations.has_active_transitions(&key) } #[inline] diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 4ae69e6255a..4e04f6f0c4b 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -27,7 +27,7 @@ use crossbeam_channel::{Receiver, Sender}; use embedder_traits::resources::{self, Resource}; use euclid::{default::Size2D as UntypedSize2D, Point2D, Rect, Scale, Size2D}; use fnv::FnvHashMap; -use fxhash::{FxHashMap, FxHashSet}; +use fxhash::FxHashMap; use gfx::font_cache_thread::FontCacheThread; use gfx::font_context; use gfx_traits::{node_id_from_scroll_id, Epoch}; @@ -81,11 +81,10 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex, MutexGuard}; use std::thread; use std::time::Duration; -use style::animation::ElementAnimationSet; +use style::animation::DocumentAnimationSet; use style::context::{ QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext, }; -use style::dom::OpaqueNode; use style::dom::{TDocument, TElement, TNode}; use style::driver; use style::error_reporting::RustLogReporter; @@ -568,7 +567,7 @@ impl LayoutThread { snapshot_map: &'a SnapshotMap, origin: ImmutableOrigin, animation_timeline_value: f64, - animation_states: ServoArc<RwLock<FxHashMap<OpaqueNode, ElementAnimationSet>>>, + animations: &DocumentAnimationSet, stylesheets_changed: bool, ) -> LayoutContext<'a> { let traversal_flags = match stylesheets_changed { @@ -584,7 +583,7 @@ impl LayoutThread { options: GLOBAL_STYLE_DATA.options.clone(), guards, visited_styles_enabled: false, - animation_states, + animations: animations.clone(), registered_speculative_painters: &self.registered_painters, current_time_for_animations: animation_timeline_value, traversal_flags, @@ -1065,7 +1064,7 @@ impl LayoutThread { &map, origin, data.animation_timeline_value, - data.animations.clone(), + &data.animations, data.stylesheets_changed, ); @@ -1292,7 +1291,7 @@ impl LayoutThread { context: &mut LayoutContext, ) { Self::cancel_animations_for_nodes_not_in_fragment_tree( - &mut *(context.style_context.animation_states.write()), + &context.style_context.animations, &fragment_tree, ); @@ -1380,16 +1379,17 @@ impl LayoutThread { /// TODO(mrobinson): We should look into a way of doing this during flow tree construction. /// This also doesn't yet handles nodes that have been reparented. fn cancel_animations_for_nodes_not_in_fragment_tree( - animation_states: &mut FxHashMap<OpaqueNode, ElementAnimationSet>, + animations: &DocumentAnimationSet, root: &FragmentTree, ) { // Assume all nodes have been removed until proven otherwise. - let mut invalid_nodes: FxHashSet<OpaqueNode> = animation_states.keys().cloned().collect(); + let mut animations = animations.sets.write(); + let mut invalid_nodes = animations.keys().cloned().collect(); root.remove_nodes_in_fragment_tree_from_set(&mut invalid_nodes); // Cancel animations for any nodes that are no longer in the fragment tree. for node in &invalid_nodes { - if let Some(state) = animation_states.get_mut(node) { + if let Some(state) = animations.get_mut(node) { state.cancel_all_animations(); } } diff --git a/components/script/animations.rs b/components/script/animations.rs index d0bfcef6f79..0b35ba4ae1d 100644 --- a/components/script/animations.rs +++ b/components/script/animations.rs @@ -19,15 +19,14 @@ use crate::dom::event::Event; use crate::dom::node::{from_untrusted_node_address, window_from_node, Node, NodeDamage}; use crate::dom::transitionevent::TransitionEvent; use crate::dom::window::Window; -use fxhash::FxHashMap; +use fxhash::{FxHashMap, FxHashSet}; use libc::c_void; use msg::constellation_msg::PipelineId; -use parking_lot::RwLock; use script_traits::{AnimationState as AnimationsPresentState, ScriptMsg, UntrustedNodeAddress}; -use servo_arc::Arc; use std::cell::Cell; use style::animation::{ - Animation, AnimationState, ElementAnimationSet, KeyframesIterationState, Transition, + Animation, AnimationSetKey, AnimationState, DocumentAnimationSet, ElementAnimationSet, + KeyframesIterationState, Transition, }; use style::dom::OpaqueNode; @@ -36,8 +35,7 @@ use style::dom::OpaqueNode; #[unrooted_must_root_lint::must_root] pub(crate) struct Animations { /// The map of nodes to their animation states. - #[ignore_malloc_size_of = "Arc is hard"] - pub sets: Arc<RwLock<FxHashMap<OpaqueNode, ElementAnimationSet>>>, + pub sets: DocumentAnimationSet, /// Whether or not we have animations that are running. have_running_animations: Cell<bool>, @@ -60,30 +58,31 @@ impl Animations { } pub(crate) fn clear(&self) { - self.sets.write().clear(); + self.sets.sets.write().clear(); self.rooted_nodes.borrow_mut().clear(); self.pending_events.borrow_mut().clear(); } pub(crate) fn mark_animating_nodes_as_dirty(&self) { - let sets = self.sets.read(); + let sets = self.sets.sets.read(); let rooted_nodes = self.rooted_nodes.borrow(); - for node in sets.keys().filter_map(|node| rooted_nodes.get(&node)) { + for node in sets.keys().filter_map(|key| rooted_nodes.get(&key.0)) { node.dirty(NodeDamage::NodeStyleDamaged); } } pub(crate) fn update_for_new_timeline_value(&self, window: &Window, now: f64) { let pipeline_id = window.pipeline_id(); - let mut sets = self.sets.write(); + let mut sets = self.sets.sets.write(); - for set in sets.values_mut() { - self.start_pending_animations(set, now, pipeline_id); + for (key, set) in sets.iter_mut() { + self.start_pending_animations(key, set, now, pipeline_id); // When necessary, iterate our running animations to the next iteration. for animation in set.animations.iter_mut() { if animation.iterate_if_necessary(now) { self.add_animation_event( + key, animation, TransitionOrAnimationEventType::AnimationIteration, now, @@ -92,7 +91,7 @@ impl Animations { } } - self.finish_running_animations(set, now, pipeline_id); + self.finish_running_animations(key, set, now, pipeline_id); } self.unroot_unused_nodes(&sets); @@ -102,12 +101,12 @@ impl Animations { /// that trigger events for any animations that changed state. pub(crate) fn do_post_reflow_update(&self, window: &Window, now: f64) { let pipeline_id = window.pipeline_id(); - let mut sets = self.sets.write(); + let mut sets = self.sets.sets.write(); self.root_newly_animating_dom_nodes(&sets, window); - for set in sets.values_mut() { - self.handle_canceled_animations(set, now, pipeline_id); - self.handle_new_animations(set, now, pipeline_id); + for (key, set) in sets.iter_mut() { + self.handle_canceled_animations(key, set, now, pipeline_id); + self.handle_new_animations(key, set, now, pipeline_id); } // Remove empty states from our collection of states in order to free @@ -136,6 +135,7 @@ impl Animations { pub(crate) fn running_animation_count(&self) -> usize { self.sets + .sets .read() .values() .map(|state| state.running_animation_and_transition_count()) @@ -146,6 +146,7 @@ impl Animations { /// have left the delay phase. fn start_pending_animations( &self, + key: &AnimationSetKey, set: &mut ElementAnimationSet, now: f64, pipeline_id: PipelineId, @@ -154,6 +155,7 @@ impl Animations { if animation.state == AnimationState::Pending && animation.started_at <= now { animation.state = AnimationState::Running; self.add_animation_event( + key, animation, TransitionOrAnimationEventType::AnimationStart, now, @@ -166,6 +168,7 @@ impl Animations { if transition.state == AnimationState::Pending && transition.start_time <= now { transition.state = AnimationState::Running; self.add_transition_event( + key, transition, TransitionOrAnimationEventType::TransitionStart, now, @@ -179,6 +182,7 @@ impl Animations { /// have ended. fn finish_running_animations( &self, + key: &AnimationSetKey, set: &mut ElementAnimationSet, now: f64, pipeline_id: PipelineId, @@ -187,6 +191,7 @@ impl Animations { if animation.state == AnimationState::Running && animation.has_ended(now) { animation.state = AnimationState::Finished; self.add_animation_event( + key, animation, TransitionOrAnimationEventType::AnimationEnd, now, @@ -199,6 +204,7 @@ impl Animations { if transition.state == AnimationState::Running && transition.has_ended(now) { transition.state = AnimationState::Finished; self.add_transition_event( + key, transition, TransitionOrAnimationEventType::TransitionEnd, now, @@ -213,6 +219,7 @@ impl Animations { /// well. fn handle_canceled_animations( &self, + key: &AnimationSetKey, set: &mut ElementAnimationSet, now: f64, pipeline_id: PipelineId, @@ -220,6 +227,7 @@ impl Animations { for transition in &set.transitions { if transition.state == AnimationState::Canceled { self.add_transition_event( + key, transition, TransitionOrAnimationEventType::TransitionCancel, now, @@ -231,6 +239,7 @@ impl Animations { for animation in &set.animations { if animation.state == AnimationState::Canceled { self.add_animation_event( + key, animation, TransitionOrAnimationEventType::AnimationCancel, now, @@ -244,6 +253,7 @@ impl Animations { fn handle_new_animations( &self, + key: &AnimationSetKey, set: &mut ElementAnimationSet, now: f64, pipeline_id: PipelineId, @@ -255,6 +265,7 @@ impl Animations { for transition in set.transitions.iter_mut() { if transition.is_new { self.add_transition_event( + key, transition, TransitionOrAnimationEventType::TransitionRun, now, @@ -270,13 +281,14 @@ impl Animations { #[allow(unsafe_code)] fn root_newly_animating_dom_nodes( &self, - sets: &FxHashMap<OpaqueNode, ElementAnimationSet>, + sets: &FxHashMap<AnimationSetKey, ElementAnimationSet>, window: &Window, ) { let js_runtime = window.get_js_runtime().as_ref().unwrap().rt(); let mut rooted_nodes = self.rooted_nodes.borrow_mut(); - for (opaque_node, set) in sets.iter() { - if rooted_nodes.contains_key(opaque_node) { + for (key, set) in sets.iter() { + let opaque_node = key.0; + if rooted_nodes.contains_key(&opaque_node) { continue; } @@ -286,7 +298,7 @@ impl Animations { let address = UntrustedNodeAddress(opaque_node.0 as *const c_void); unsafe { rooted_nodes.insert( - opaque_node.clone(), + opaque_node, Dom::from_ref(&*from_untrusted_node_address(js_runtime, address)), ) }; @@ -295,15 +307,17 @@ impl Animations { } // Unroot any nodes that we have rooted but are no longer tracking animations for. - fn unroot_unused_nodes(&self, sets: &FxHashMap<OpaqueNode, ElementAnimationSet>) { + fn unroot_unused_nodes(&self, sets: &FxHashMap<AnimationSetKey, ElementAnimationSet>) { let pending_events = self.pending_events.borrow(); - self.rooted_nodes.borrow_mut().retain(|key, _| { - sets.contains_key(key) || pending_events.iter().any(|event| event.node == *key) + let nodes: FxHashSet<OpaqueNode> = sets.keys().map(|key| key.0).collect(); + self.rooted_nodes.borrow_mut().retain(|node, _| { + nodes.contains(&node) || pending_events.iter().any(|event| event.node == *node) }); } fn add_transition_event( &self, + key: &AnimationSetKey, transition: &Transition, event_type: TransitionOrAnimationEventType, now: f64, @@ -330,7 +344,7 @@ impl Animations { .push(TransitionOrAnimationEvent { pipeline_id, event_type, - node: transition.node.clone(), + node: key.0, property_or_animation_name: transition .property_animation .property_id() @@ -342,6 +356,7 @@ impl Animations { fn add_animation_event( &self, + key: &AnimationSetKey, animation: &Animation, event_type: TransitionOrAnimationEventType, now: f64, @@ -377,7 +392,7 @@ impl Animations { .push(TransitionOrAnimationEvent { pipeline_id, event_type, - node: animation.node.clone(), + node: key.0, property_or_animation_name: animation.name.to_string(), elapsed_time, }); diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 01cbde4bcfa..3c1a78802b4 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -141,7 +141,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::{Arc, Mutex}; use std::thread::JoinHandle; use std::time::{Instant, SystemTime}; -use style::animation::ElementAnimationSet; +use style::animation::DocumentAnimationSet; use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto}; use style::author_styles::AuthorStyles; use style::context::QuirksMode; @@ -621,7 +621,7 @@ unsafe_no_jsmanaged_fields!(MediaSessionActionType); unsafe_no_jsmanaged_fields!(MediaMetadata); unsafe_no_jsmanaged_fields!(WebrenderIpcSender); unsafe_no_jsmanaged_fields!(StreamConsumer); -unsafe_no_jsmanaged_fields!(ElementAnimationSet); +unsafe_no_jsmanaged_fields!(DocumentAnimationSet); unsafe impl<'a> JSTraceable for &'a str { #[inline] diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 724cd2b79e7..2d1ca34eef3 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -7,13 +7,11 @@ use crate::{PendingImage, TrustedNodeAddress}; use app_units::Au; use crossbeam_channel::{Receiver, Sender}; use euclid::default::{Point2D, Rect}; -use fxhash::FxHashMap; use gfx_traits::Epoch; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use metrics::PaintTimeMetrics; use msg::constellation_msg::{BackgroundHangMonitorRegister, BrowsingContextId, PipelineId}; use net_traits::image_cache::ImageCache; -use parking_lot::RwLock; use profile_traits::mem::ReportsChan; use script_traits::Painter; use script_traits::{ @@ -25,7 +23,7 @@ use servo_atoms::Atom; use servo_url::{ImmutableOrigin, ServoUrl}; use std::sync::atomic::AtomicBool; use std::sync::Arc; -use style::animation::ElementAnimationSet; +use style::animation::DocumentAnimationSet; use style::context::QuirksMode; use style::dom::OpaqueNode; use style::invalidation::element::restyle_hints::RestyleHint; @@ -215,7 +213,7 @@ pub struct ScriptReflow { /// The current animation timeline value. pub animation_timeline_value: f64, /// The set of animations for this document. - pub animations: ServoArc<RwLock<FxHashMap<OpaqueNode, ElementAnimationSet>>>, + pub animations: DocumentAnimationSet, } pub struct LayoutThreadInit { diff --git a/components/style/animation.rs b/components/style/animation.rs index 75efde37b67..ecb921a5e4a 100644 --- a/components/style/animation.rs +++ b/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<ComputedValues>, ) { @@ -987,7 +984,6 @@ impl ElementAnimationSet { &mut self, might_need_transitions_update: bool, context: &SharedStyleContext, - opaque_node: OpaqueNode, old_style: Option<&Arc<ComputedValues>>, after_change_style: &Arc<ComputedValues>, ) { @@ -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<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, @@ -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<E>( ); let new_animation = Animation { - node: element.as_node().opaque(), name: name.clone(), properties_changed: keyframe_animation.properties_changed, computed_steps, diff --git a/components/style/context.rs b/components/style/context.rs index 832fcd10986..608e58ea032 100644 --- a/components/style/context.rs +++ b/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<RwLock<FxHashMap<OpaqueNode, ElementAnimationSet>>>, + pub animations: DocumentAnimationSet, /// Paint worklets #[cfg(feature = "servo")] diff --git a/components/style/matching.rs b/components/style/matching.rs index 36369af5ec9..a8edf36829e 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -524,7 +524,7 @@ trait PrivateMatchMethods: TElement { 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(). @@ -541,12 +541,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 @@ -571,7 +572,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), ); @@ -590,9 +590,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 |