diff options
Diffstat (limited to 'components/layout/animation.rs')
-rw-r--r-- | components/layout/animation.rs | 90 |
1 files changed, 58 insertions, 32 deletions
diff --git a/components/layout/animation.rs b/components/layout/animation.rs index f3e01c20b8c..b214910c4f6 100644 --- a/components/layout/animation.rs +++ b/components/layout/animation.rs @@ -19,11 +19,14 @@ use style::animation::{GetMod, PropertyAnimation}; use style::properties::ComputedValues; /// Inserts transitions into the queue of running animations as applicable for the given style -/// difference. This is called from the layout worker threads. +/// difference. This is called from the layout worker threads. Returns true if any animations were +/// kicked off and false otherwise. pub fn start_transitions_if_applicable(new_animations_sender: &Mutex<Sender<Animation>>, node: OpaqueNode, old_style: &ComputedValues, - new_style: &mut ComputedValues) { + new_style: &mut ComputedValues) + -> bool { + let mut had_animations = false; for i in 0..new_style.get_animation().transition_property.0.len() { // Create any property animations, if applicable. let property_animations = PropertyAnimation::from_transition(i, old_style, new_style); @@ -42,15 +45,20 @@ pub fn start_transitions_if_applicable(new_animations_sender: &Mutex<Sender<Anim start_time: start_time, end_time: start_time + (animation_style.transition_duration.0.get_mod(i).seconds() as f64), - }).unwrap() + }).unwrap(); + + had_animations = true } } + + had_animations } /// Processes any new animations that were discovered after style recalculation. -/// Also expire any old animations that have completed. +/// Also expire any old animations that have completed, inserting them into `expired_animations`. pub fn update_animation_state(constellation_chan: &ConstellationChan<ConstellationMsg>, - running_animations: &mut Arc<HashMap<OpaqueNode, Vec<Animation>>>, + running_animations: &mut HashMap<OpaqueNode, Vec<Animation>>, + expired_animations: &mut HashMap<OpaqueNode, Vec<Animation>>, new_animations_receiver: &Receiver<Animation>, pipeline_id: PipelineId) { let mut new_running_animations = Vec::new(); @@ -58,9 +66,7 @@ pub fn update_animation_state(constellation_chan: &ConstellationChan<Constellati new_running_animations.push(animation) } - let mut running_animations_hash = (**running_animations).clone(); - - if running_animations_hash.is_empty() && new_running_animations.is_empty() { + if running_animations.is_empty() && new_running_animations.is_empty() { // Nothing to do. Return early so we don't flood the compositor with // `ChangeRunningAnimationsState` messages. return @@ -69,21 +75,33 @@ pub fn update_animation_state(constellation_chan: &ConstellationChan<Constellati // Expire old running animations. let now = clock_ticks::precise_time_s(); let mut keys_to_remove = Vec::new(); - for (key, running_animations) in &mut running_animations_hash { - running_animations.retain(|running_animation| { - now < running_animation.end_time - }); - if running_animations.len() == 0 { + for (key, running_animations) in running_animations.iter_mut() { + let mut animations_still_running = vec![]; + for running_animation in running_animations.drain(..) { + if now < running_animation.end_time { + animations_still_running.push(running_animation); + continue + } + match expired_animations.entry(*key) { + Entry::Vacant(entry) => { + entry.insert(vec![running_animation]); + } + Entry::Occupied(mut entry) => entry.get_mut().push(running_animation), + } + } + if animations_still_running.len() == 0 { keys_to_remove.push(*key); + } else { + *running_animations = animations_still_running } } for key in keys_to_remove { - running_animations_hash.remove(&key).unwrap(); + running_animations.remove(&key).unwrap(); } // Add new running animations. for new_running_animation in new_running_animations { - match running_animations_hash.entry(OpaqueNode(new_running_animation.node)) { + match running_animations.entry(OpaqueNode(new_running_animation.node)) { Entry::Vacant(entry) => { entry.insert(vec![new_running_animation]); } @@ -91,8 +109,6 @@ pub fn update_animation_state(constellation_chan: &ConstellationChan<Constellati } } - *running_animations = Arc::new(running_animations_hash); - let animation_state; if running_animations.is_empty() { animation_state = AnimationState::NoAnimationsPresent; @@ -112,21 +128,7 @@ pub fn recalc_style_for_animations(flow: &mut Flow, flow.mutate_fragments(&mut |fragment| { if let Some(ref animations) = animations.get(&OpaqueNode(fragment.node.id())) { for animation in *animations { - let now = clock_ticks::precise_time_s(); - let mut progress = (now - animation.start_time) / animation.duration(); - if progress > 1.0 { - progress = 1.0 - } - if progress <= 0.0 { - continue - } - - let mut new_style = fragment.style.clone(); - animation.property_animation.update(&mut *Arc::make_mut(&mut new_style), - progress); - damage.insert(incremental::compute_damage(&Some(fragment.style.clone()), - &new_style)); - fragment.style = new_style + update_style_for_animation(animation, &mut fragment.style, Some(&mut damage)); } } }); @@ -137,3 +139,27 @@ pub fn recalc_style_for_animations(flow: &mut Flow, recalc_style_for_animations(kid, animations) } } + +/// Updates a single animation and associated style based on the current time. If `damage` is +/// provided, inserts the appropriate restyle damage. +pub fn update_style_for_animation(animation: &Animation, + style: &mut Arc<ComputedValues>, + damage: Option<&mut RestyleDamage>) { + let now = clock_ticks::precise_time_s(); + let mut progress = (now - animation.start_time) / animation.duration(); + if progress > 1.0 { + progress = 1.0 + } + if progress <= 0.0 { + return + } + + let mut new_style = (*style).clone(); + animation.property_animation.update(&mut *Arc::make_mut(&mut new_style), progress); + if let Some(damage) = damage { + damage.insert(incremental::compute_damage(&Some((*style).clone()), &new_style)); + } + + *style = new_style +} + |