mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
layout: Make animations work... more or less.
There's some maths I've done wrong, but it DOES animate some things, though they're only triggered past the first restyle, and we probably have some duplications where the animations arrive to layout. Anyway, got to go.
This commit is contained in:
parent
c16c5acade
commit
bc970596d6
3 changed files with 77 additions and 27 deletions
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//! CSS transitions and animations.
|
//! CSS transitions and animations.
|
||||||
|
|
||||||
|
use context::SharedLayoutContext;
|
||||||
use flow::{self, Flow};
|
use flow::{self, Flow};
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
@ -13,7 +14,7 @@ use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
use style::animation::{Animation, update_style_for_animation};
|
use style::animation::{Animation, KeyframesAnimationState, KeyframesIterationState, update_style_for_animation};
|
||||||
use time;
|
use time;
|
||||||
|
|
||||||
/// Processes any new animations that were discovered after style recalculation.
|
/// Processes any new animations that were discovered after style recalculation.
|
||||||
|
@ -39,15 +40,33 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
||||||
let mut keys_to_remove = vec![];
|
let mut keys_to_remove = vec![];
|
||||||
for (key, running_animations) in running_animations.iter_mut() {
|
for (key, running_animations) in running_animations.iter_mut() {
|
||||||
let mut animations_still_running = vec![];
|
let mut animations_still_running = vec![];
|
||||||
for running_animation in running_animations.drain(..) {
|
for mut running_animation in running_animations.drain(..) {
|
||||||
if now < running_animation.end_time {
|
let still_running = match running_animation {
|
||||||
|
Animation::Transition(_, started_at, ref frame) => {
|
||||||
|
now < started_at + frame.duration
|
||||||
|
}
|
||||||
|
Animation::Keyframes(_, _, ref mut state) => {
|
||||||
|
// This animation is still running, or we need to keep
|
||||||
|
// iterating.
|
||||||
|
now < state.started_at + state.duration ||
|
||||||
|
match state.iteration_state {
|
||||||
|
KeyframesIterationState::Finite(ref mut current, ref max) => {
|
||||||
|
*current += 1;
|
||||||
|
*current < *max
|
||||||
|
}
|
||||||
|
KeyframesIterationState::Infinite => {
|
||||||
|
state.started_at += state.duration;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if still_running {
|
||||||
animations_still_running.push(running_animation);
|
animations_still_running.push(running_animation);
|
||||||
continue
|
continue
|
||||||
} else if running_animation.state.pending_iterations > 0 {
|
|
||||||
// if the animation should run again, just tick it...
|
|
||||||
let duration = running_animation.end_time - running_animation.start_time;
|
|
||||||
running_animation.start_time += duration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expired_animations.entry(*key)
|
expired_animations.entry(*key)
|
||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
.push(running_animation);
|
.push(running_animation);
|
||||||
|
@ -59,40 +78,41 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
||||||
*running_animations = animations_still_running
|
*running_animations = animations_still_running
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in keys_to_remove {
|
for key in keys_to_remove {
|
||||||
running_animations.remove(&key).unwrap();
|
running_animations.remove(&key).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new running animations.
|
// Add new running animations.
|
||||||
for new_running_animation in new_running_animations {
|
for new_running_animation in new_running_animations {
|
||||||
match running_animations.entry(new_running_animation.node) {
|
running_animations.entry(*new_running_animation.node())
|
||||||
Entry::Vacant(entry) => {
|
.or_insert_with(Vec::new)
|
||||||
entry.insert(vec![new_running_animation]);
|
.push(new_running_animation);
|
||||||
}
|
|
||||||
Entry::Occupied(mut entry) => entry.get_mut().push(new_running_animation),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let animation_state;
|
let animation_state = if running_animations.is_empty() {
|
||||||
if running_animations.is_empty() {
|
AnimationState::NoAnimationsPresent
|
||||||
animation_state = AnimationState::NoAnimationsPresent;
|
|
||||||
} else {
|
} else {
|
||||||
animation_state = AnimationState::AnimationsPresent;
|
AnimationState::AnimationsPresent
|
||||||
}
|
};
|
||||||
|
|
||||||
constellation_chan.send(ConstellationMsg::ChangeRunningAnimationsState(pipeline_id, animation_state))
|
constellation_chan.send(ConstellationMsg::ChangeRunningAnimationsState(pipeline_id, animation_state))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recalculates style for a set of animations. This does *not* run with the DOM lock held.
|
/// Recalculates style for a set of animations. This does *not* run with the DOM lock held.
|
||||||
pub fn recalc_style_for_animations(flow: &mut Flow,
|
pub fn recalc_style_for_animations(context: &SharedLayoutContext,
|
||||||
|
flow: &mut Flow,
|
||||||
animations: &mut HashMap<OpaqueNode, Vec<Animation>>) {
|
animations: &mut HashMap<OpaqueNode, Vec<Animation>>) {
|
||||||
let mut damage = RestyleDamage::empty();
|
let mut damage = RestyleDamage::empty();
|
||||||
flow.mutate_fragments(&mut |fragment| {
|
flow.mutate_fragments(&mut |fragment| {
|
||||||
if let Some(ref animations) = animations.get_mut(&fragment.node) {
|
if let Some(ref mut animations) = animations.get_mut(&fragment.node) {
|
||||||
for mut animation in *animations {
|
for ref mut animation in animations.iter_mut() {
|
||||||
if !animation.is_paused() {
|
if !animation.is_paused() {
|
||||||
update_style_for_animation(animation, &mut fragment.style, Some(&mut damage));
|
update_style_for_animation(&context.style_context,
|
||||||
|
animation,
|
||||||
|
&mut fragment.style,
|
||||||
|
Some(&mut damage));
|
||||||
animation.increment_keyframe_if_applicable();
|
animation.increment_keyframe_if_applicable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,6 +122,6 @@ pub fn recalc_style_for_animations(flow: &mut Flow,
|
||||||
let base = flow::mut_base(flow);
|
let base = flow::mut_base(flow);
|
||||||
base.restyle_damage.insert(damage);
|
base.restyle_damage.insert(damage);
|
||||||
for kid in base.children.iter_mut() {
|
for kid in base.children.iter_mut() {
|
||||||
recalc_style_for_animations(kid, animations)
|
recalc_style_for_animations(context, kid, animations)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1307,7 +1307,8 @@ impl LayoutThread {
|
||||||
self.profiler_metadata(),
|
self.profiler_metadata(),
|
||||||
self.time_profiler_chan.clone(),
|
self.time_profiler_chan.clone(),
|
||||||
|| {
|
|| {
|
||||||
animation::recalc_style_for_animations(flow_ref::deref_mut(&mut root_flow),
|
animation::recalc_style_for_animations(&layout_context,
|
||||||
|
flow_ref::deref_mut(&mut root_flow),
|
||||||
&mut animations)
|
&mut animations)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,30 @@ pub enum Animation {
|
||||||
Keyframes(OpaqueNode, Atom, KeyframesAnimationState),
|
Keyframes(OpaqueNode, Atom, KeyframesAnimationState),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A keyframes animation previously sent to layout.
|
impl Animation {
|
||||||
|
pub fn node(&self) -> &OpaqueNode {
|
||||||
|
match *self {
|
||||||
|
Animation::Transition(ref node, _, _) => node,
|
||||||
|
Animation::Keyframes(ref node, _, _) => node,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_paused(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Animation::Transition(..) => false,
|
||||||
|
Animation::Keyframes(_, _, ref state) => state.paused,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment_keyframe_if_applicable(&mut self) {
|
||||||
|
if let Animation::Keyframes(_, _, ref mut state) = *self {
|
||||||
|
if let KeyframesIterationState::Finite(ref mut iterations, _) = state.iteration_state {
|
||||||
|
*iterations += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A single animation frame of a single property.
|
/// A single animation frame of a single property.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -255,7 +278,8 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref animation) = context.stylist.animations().get(&name) {
|
if context.stylist.animations().get(&name).is_some() {
|
||||||
|
debug!("maybe_start_animations: animation {} found", name);
|
||||||
let delay = box_style.animation_delay.0.get_mod(i).seconds();
|
let delay = box_style.animation_delay.0.get_mod(i).seconds();
|
||||||
let animation_start = time::precise_time_s() + delay as f64;
|
let animation_start = time::precise_time_s() + delay as f64;
|
||||||
let duration = box_style.animation_duration.0.get_mod(i).seconds();
|
let duration = box_style.animation_duration.0.get_mod(i).seconds();
|
||||||
|
@ -307,9 +331,11 @@ pub fn update_style_for_animation<Damage, Impl>(context: &SharedStyleContext<Imp
|
||||||
damage: Option<&mut Damage>)
|
damage: Option<&mut Damage>)
|
||||||
where Impl: SelectorImplExt,
|
where Impl: SelectorImplExt,
|
||||||
Damage: TRestyleDamage<ConcreteComputedValues = Impl::ComputedValues> {
|
Damage: TRestyleDamage<ConcreteComputedValues = Impl::ComputedValues> {
|
||||||
|
debug!("update_style_for_animation: entering");
|
||||||
let now = time::precise_time_s();
|
let now = time::precise_time_s();
|
||||||
match *animation {
|
match *animation {
|
||||||
Animation::Transition(_, start_time, ref frame) => {
|
Animation::Transition(_, start_time, ref frame) => {
|
||||||
|
debug!("update_style_for_animation: transition found");
|
||||||
let mut new_style = (*style).clone();
|
let mut new_style = (*style).clone();
|
||||||
let updated_style = update_style_for_animation_frame(&mut new_style,
|
let updated_style = update_style_for_animation_frame(&mut new_style,
|
||||||
now, start_time,
|
now, start_time,
|
||||||
|
@ -323,6 +349,7 @@ where Impl: SelectorImplExt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Animation::Keyframes(_, ref name, ref state) => {
|
Animation::Keyframes(_, ref name, ref state) => {
|
||||||
|
debug!("update_style_for_animation: animation found {:?}", name);
|
||||||
debug_assert!(!state.paused);
|
debug_assert!(!state.paused);
|
||||||
let duration = state.duration;
|
let duration = state.duration;
|
||||||
let started_at = state.started_at;
|
let started_at = state.started_at;
|
||||||
|
@ -369,8 +396,8 @@ where Impl: SelectorImplExt,
|
||||||
for i in 1..animation.steps.len() {
|
for i in 1..animation.steps.len() {
|
||||||
if total_progress as f32 <= animation.steps[i].start_percentage.0 {
|
if total_progress as f32 <= animation.steps[i].start_percentage.0 {
|
||||||
// We might have found our current keyframe.
|
// We might have found our current keyframe.
|
||||||
target_keyframe = Some(&animation.steps[i]);
|
|
||||||
last_keyframe = target_keyframe;
|
last_keyframe = target_keyframe;
|
||||||
|
target_keyframe = Some(&animation.steps[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,6 +441,7 @@ where Impl: SelectorImplExt,
|
||||||
let mut style_changed = false;
|
let mut style_changed = false;
|
||||||
|
|
||||||
for transition_property in &animation.properties_changed {
|
for transition_property in &animation.properties_changed {
|
||||||
|
debug!("update_style_for_animation: scanning prop {:?} for animation {}", transition_property, name);
|
||||||
if let Some(property_animation) = PropertyAnimation::from_transition_property(*transition_property,
|
if let Some(property_animation) = PropertyAnimation::from_transition_property(*transition_property,
|
||||||
timing_function,
|
timing_function,
|
||||||
Time(relative_duration as f32),
|
Time(relative_duration as f32),
|
||||||
|
@ -426,6 +454,7 @@ where Impl: SelectorImplExt,
|
||||||
}
|
}
|
||||||
|
|
||||||
if style_changed {
|
if style_changed {
|
||||||
|
debug!("update_style_for_animation: got style change in animation {:?}", name);
|
||||||
if let Some(damage) = damage {
|
if let Some(damage) = damage {
|
||||||
*damage = *damage | Damage::compute(Some(style), &new_style);
|
*damage = *damage | Damage::compute(Some(style), &new_style);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue