aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <servo-ops@mozilla.com>2020-06-16 03:25:29 -0400
committerGitHub <noreply@github.com>2020-06-16 03:25:29 -0400
commitba5568a0a60cbd4bbedd3b766b7182824d75b131 (patch)
treeebf1b7c38ff7d98f195b331c81fbcb88287393f0
parent19c1f72eb2fe5178311161b6c85a67956a5a69b3 (diff)
parent4a3995bb375d43d53666a348ec0c08065784f6ea (diff)
downloadservo-ba5568a0a60cbd4bbedd3b766b7182824d75b131.tar.gz
servo-ba5568a0a60cbd4bbedd3b766b7182824d75b131.zip
Auto merge of #26921 - mrobinson:animation-set-key, r=jdm
Add DocumentAnimationSet and AnimationSetKey This will be used in order to hold animations for pseudo elements in the DocumentAnimationSet. Also no longer store the OpaqueNode in the animation and transition data structures. This is already part of the DocumentAnimationSet key. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes do not require tests because they should not change behavior. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
-rw-r--r--components/layout_2020/flow/root.rs5
-rw-r--r--components/layout_thread/dom_wrapper.rs55
-rw-r--r--components/layout_thread/lib.rs24
-rw-r--r--components/layout_thread_2020/dom_wrapper.rs55
-rw-r--r--components/layout_thread_2020/lib.rs20
-rw-r--r--components/script/animations.rs67
-rw-r--r--components/script/dom/bindings/trace.rs4
-rw-r--r--components/script_layout_interface/message.rs6
-rw-r--r--components/style/animation.rs86
-rw-r--r--components/style/context.rs9
-rw-r--r--components/style/matching.rs15
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