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.rs90
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
+}
+