mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
Write animated values into the ComputedValues
structures when
animations complete or are interrupted. This adds a new pair of reader-writer locks. I measured the performance of style recalculation on Wikipedia and the overhead of the locks was not measurable. Closes #7816.
This commit is contained in:
parent
6f35b867c9
commit
e881f0feeb
5 changed files with 134 additions and 56 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue