Ensure that animations expire correctly and stop compositing occurring after they finish.

There were two problems here:
(1) The animation state update function was only called when nodes were dirty or there were new animations.
(2) When all animations for a node expired, the entry from the hash table was not removed.

The result was that once an animation began, the compositor would be running as fast as it can forever.

Fixes #7721.
This commit is contained in:
Glenn Watson 2015-09-24 10:29:58 +10:00
parent eca448363d
commit f6cb6c3b86
3 changed files with 32 additions and 23 deletions

View file

@ -49,32 +49,41 @@ pub fn start_transitions_if_applicable(new_animations_sender: &Sender<Animation>
}
/// Processes any new animations that were discovered after style recalculation.
pub fn process_new_animations(rw_data: &mut LayoutTaskData, pipeline_id: PipelineId) {
/// Also expire any old animations that have completed.
pub fn update_animation_state(rw_data: &mut LayoutTaskData, pipeline_id: PipelineId) {
let mut new_running_animations = Vec::new();
while let Ok(animation) = rw_data.new_animations_receiver.try_recv() {
new_running_animations.push(animation)
}
if !new_running_animations.is_empty() {
let mut running_animations = (*rw_data.running_animations).clone();
// Expire old running animations.
let now = clock_ticks::precise_time_s();
for (_, running_animations) in &mut running_animations {
running_animations.retain(|running_animation| now < running_animation.end_time);
let mut running_animations_hash = (*rw_data.running_animations).clone();
// 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 {
keys_to_remove.push(*key);
}
// Add new running animations.
for new_running_animation in new_running_animations {
match running_animations.entry(OpaqueNode(new_running_animation.node)) {
Entry::Vacant(entry) => {
entry.insert(vec![new_running_animation]);
}
Entry::Occupied(mut entry) => entry.get_mut().push(new_running_animation),
}
}
rw_data.running_animations = Arc::new(running_animations);
}
for key in keys_to_remove {
running_animations_hash.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)) {
Entry::Vacant(entry) => {
entry.insert(vec![new_running_animation]);
}
Entry::Occupied(mut entry) => entry.get_mut().push(new_running_animation),
}
}
rw_data.running_animations = Arc::new(running_animations_hash);
let animation_state;
if rw_data.running_animations.is_empty() {

View file

@ -1183,9 +1183,6 @@ impl LayoutTask {
// Retrieve the (possibly rebuilt) root flow.
rw_data.root_flow = self.try_get_layout_root((*node).clone());
// Kick off animations if any were triggered.
animation::process_new_animations(&mut *rw_data, self.id);
}
// Send new canvas renderers to the paint task
@ -1327,6 +1324,9 @@ impl LayoutTask {
rw_data: &mut LayoutTaskData,
layout_context: &mut SharedLayoutContext) {
if let Some(mut root_flow) = rw_data.layout_root() {
// Kick off animations if any were triggered, expire completed ones.
animation::update_animation_state(&mut *rw_data, self.id);
profile(time::ProfilerCategory::LayoutRestyleDamagePropagation,
self.profiler_metadata(),
self.time_profiler_chan.clone(),

View file

@ -275,7 +275,7 @@ pub enum Msg {
NodeStatus(Option<String>),
}
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize)]
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
pub enum AnimationState {
AnimationsPresent,
AnimationCallbacksPresent,