aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/animation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/animation.rs')
-rw-r--r--components/layout/animation.rs191
1 files changed, 74 insertions, 117 deletions
diff --git a/components/layout/animation.rs b/components/layout/animation.rs
index 64c1dfd2e0a..c85d962008c 100644
--- a/components/layout/animation.rs
+++ b/components/layout/animation.rs
@@ -4,7 +4,6 @@
//! CSS transitions and animations.
-use crate::context::LayoutContext;
use crate::display_list::items::OpaqueNode;
use crate::flow::{Flow, GetBaseFlow};
use crate::opaque_node::OpaqueNodeMethods;
@@ -14,56 +13,29 @@ use msg::constellation_msg::PipelineId;
use script_traits::UntrustedNodeAddress;
use script_traits::{
AnimationState, ConstellationControlMsg, LayoutMsg as ConstellationMsg,
- TransitionOrAnimationEventType,
+ TransitionOrAnimationEvent, TransitionOrAnimationEventType,
};
-use servo_arc::Arc;
-use style::animation::{update_style_for_animation, Animation, ElementAnimationState};
-use style::dom::TElement;
-use style::font_metrics::ServoMetricsProvider;
-use style::selector_parser::RestyleDamage;
-use style::timer::Timer;
+use style::animation::{Animation, ElementAnimationState};
-/// Collect newly animating nodes, which is used by the script process during
-/// forced, synchronous reflows to root DOM nodes for the duration of their
-/// animations or transitions.
-pub fn collect_newly_animating_nodes(
- animation_states: &FxHashMap<OpaqueNode, ElementAnimationState>,
- mut out: Option<&mut Vec<UntrustedNodeAddress>>,
-) {
- // This extends the output vector with an iterator that contains a copy of the node
- // address for every new animation. This is a bit goofy, but the script thread
- // currently stores a rooted node for every property that is transitioning.
- if let Some(ref mut out) = out {
- out.extend(animation_states.iter().flat_map(|(node, state)| {
- std::iter::repeat(node.to_untrusted_node_address()).take(state.new_animations.len())
- }));
- }
-}
-
-/// Processes any new animations that were discovered after style recalculation. Also
-/// finish any animations that have completed, inserting them into `finished_animations`.
-pub fn update_animation_states(
+/// Processes any new animations that were discovered after style recalculation and
+/// remove animations for any disconnected nodes. Send messages that trigger events
+/// for any events that changed state.
+pub fn do_post_style_animations_update(
constellation_chan: &IpcSender<ConstellationMsg>,
script_chan: &IpcSender<ConstellationControlMsg>,
animation_states: &mut FxHashMap<OpaqueNode, ElementAnimationState>,
- invalid_nodes: FxHashSet<OpaqueNode>,
pipeline_id: PipelineId,
- timer: &Timer,
+ now: f64,
+ out: &mut Vec<UntrustedNodeAddress>,
+ root_flow: &mut dyn Flow,
) {
let had_running_animations = animation_states
.values()
.any(|state| !state.running_animations.is_empty());
- // Cancel all animations on any invalid nodes. These entries will later
- // be removed from the list of states, because their states will become
- // empty.
- for node in &invalid_nodes {
- if let Some(mut state) = animation_states.remove(node) {
- state.cancel_all_animations();
- }
- }
+ cancel_animations_for_disconnected_nodes(animation_states, root_flow);
+ collect_newly_animating_nodes(animation_states, out);
- let now = timer.seconds();
let mut have_running_animations = false;
for (node, animation_state) in animation_states.iter_mut() {
update_animation_state(script_chan, animation_state, pipeline_id, now, *node);
@@ -89,7 +61,50 @@ pub fn update_animation_states(
.unwrap();
}
-pub fn update_animation_state(
+/// Collect newly animating nodes, which is used by the script process during
+/// forced, synchronous reflows to root DOM nodes for the duration of their
+/// animations or transitions.
+pub fn collect_newly_animating_nodes(
+ animation_states: &FxHashMap<OpaqueNode, ElementAnimationState>,
+ out: &mut Vec<UntrustedNodeAddress>,
+) {
+ // This extends the output vector with an iterator that contains a copy of the node
+ // address for every new animation. This is a bit goofy, but the script thread
+ // currently stores a rooted node for every property that is transitioning.
+ out.extend(animation_states.iter().flat_map(|(node, state)| {
+ std::iter::repeat(node.to_untrusted_node_address()).take(state.new_animations.len())
+ }));
+}
+
+/// Cancel animations for any nodes which have been removed from the DOM or are display:none.
+/// We detect this by looking for nodes that are used in the flow tree.
+/// 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.
+pub fn cancel_animations_for_disconnected_nodes(
+ animation_states: &mut FxHashMap<OpaqueNode, ElementAnimationState>,
+ 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>) {
+ flow.mutate_fragments(&mut |fragment| {
+ invalid_nodes.remove(&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) {
+ state.cancel_all_animations();
+ }
+ }
+}
+
+fn update_animation_state(
script_channel: &IpcSender<ConstellationControlMsg>,
animation_state: &mut ElementAnimationState,
pipeline_id: PipelineId,
@@ -105,13 +120,15 @@ pub fn update_animation_state(
};
script_channel
- .send(ConstellationControlMsg::TransitionOrAnimationEvent {
- pipeline_id,
- event_type,
- node: node.to_untrusted_node_address(),
- property_or_animation_name,
- elapsed_time,
- })
+ .send(ConstellationControlMsg::TransitionOrAnimationEvent(
+ TransitionOrAnimationEvent {
+ pipeline_id,
+ event_type,
+ node: node.to_untrusted_node_address(),
+ property_or_animation_name,
+ elapsed_time,
+ },
+ ))
.unwrap()
};
@@ -122,36 +139,28 @@ pub fn update_animation_state(
/// Walk through the list of running animations and remove all of the ones that
/// have ended.
-pub fn handle_running_animations(
+fn handle_running_animations(
animation_state: &mut ElementAnimationState,
now: f64,
mut send_event: impl FnMut(&Animation, TransitionOrAnimationEventType, f64),
) {
+ if animation_state.running_animations.is_empty() {
+ return;
+ }
+
let mut running_animations =
std::mem::replace(&mut animation_state.running_animations, Vec::new());
- for mut running_animation in running_animations.drain(..) {
- let still_running = match running_animation {
- Animation::Transition(_, started_at, ref property_animation) => {
- now < started_at + (property_animation.duration)
- },
- Animation::Keyframes(_, _, _, ref mut state) => {
- // This animation is still running, or we need to keep
- // iterating.
- now < state.started_at + state.duration || state.tick()
- },
- };
-
+ for running_animation in running_animations.drain(..) {
// If the animation is still running, add it back to the list of running animations.
- if still_running {
+ if !running_animation.has_ended(now) {
animation_state.running_animations.push(running_animation);
} else {
- debug!("Finishing transition: {:?}", running_animation);
let (event_type, elapsed_time) = match running_animation {
Animation::Transition(_, _, ref property_animation) => (
TransitionOrAnimationEventType::TransitionEnd,
property_animation.duration,
),
- Animation::Keyframes(_, _, _, ref mut state) => (
+ Animation::Keyframes(_, _, _, ref state) => (
TransitionOrAnimationEventType::AnimationEnd,
state.active_duration(),
),
@@ -166,7 +175,7 @@ pub fn handle_running_animations(
/// Send events for cancelled animations. Currently this only handles cancelled
/// transitions, but eventually this should handle cancelled CSS animations as
/// well.
-pub fn handle_cancelled_animations(
+fn handle_cancelled_animations(
animation_state: &mut ElementAnimationState,
now: f64,
mut send_event: impl FnMut(&Animation, TransitionOrAnimationEventType, f64),
@@ -188,7 +197,7 @@ pub fn handle_cancelled_animations(
}
}
-pub fn handle_new_animations(
+fn handle_new_animations(
animation_state: &mut ElementAnimationState,
mut send_event: impl FnMut(&Animation, TransitionOrAnimationEventType, f64),
) {
@@ -208,55 +217,3 @@ pub fn handle_new_animations(
animation_state.running_animations.push(animation);
}
}
-
-/// Recalculates style for a set of animations. This does *not* run with the DOM
-/// lock held. Returns a set of nodes associated with animations that are no longer
-/// valid.
-pub fn recalc_style_for_animations<E>(
- context: &LayoutContext,
- flow: &mut dyn Flow,
- animation_states: &FxHashMap<OpaqueNode, ElementAnimationState>,
-) -> FxHashSet<OpaqueNode>
-where
- E: TElement,
-{
- let mut invalid_nodes = animation_states.keys().cloned().collect();
- do_recalc_style_for_animations::<E>(context, flow, animation_states, &mut invalid_nodes);
- invalid_nodes
-}
-
-fn do_recalc_style_for_animations<E>(
- context: &LayoutContext,
- flow: &mut dyn Flow,
- animation_states: &FxHashMap<OpaqueNode, ElementAnimationState>,
- invalid_nodes: &mut FxHashSet<OpaqueNode>,
-) where
- E: TElement,
-{
- let mut damage = RestyleDamage::empty();
- flow.mutate_fragments(&mut |fragment| {
- let animations = match animation_states.get(&fragment.node) {
- Some(state) => &state.running_animations,
- None => return,
- };
-
- invalid_nodes.remove(&fragment.node);
- for animation in animations.iter() {
- let old_style = fragment.style.clone();
- update_style_for_animation::<E>(
- &context.style_context,
- animation,
- Arc::make_mut(&mut fragment.style),
- &ServoMetricsProvider,
- );
- let difference = RestyleDamage::compute_style_difference(&old_style, &fragment.style);
- damage |= difference.damage;
- }
- });
-
- let base = flow.mut_base();
- base.restyle_damage.insert(damage);
- for kid in base.children.iter_mut() {
- do_recalc_style_for_animations::<E>(context, kid, animation_states, invalid_nodes)
- }
-}