mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
style: layout: Get actual keyframes working!
There are a few shortcomings, for example: * We don't do the same as other browsers when some properties are not specified in some of the keyframes, though this is easy to work out (though a bit more expensive in the sense that we should apply all the previous keyframes' style instead of just the previous and the next. * To trigger the initial animation, a restyle is necessary. Should be easy to do an initial restyle off-hand or something like that, but for now this is worked-around adding a :hover rule to the node. Also, the animation is resetted when the node is hovered. That's a bug, but is probably not so difficult to test. * A few things, mainly animation-direction, are not supported yet, but shouldn't be that hard to support. Still a lot of work to do, but I think this approach might be ok.
This commit is contained in:
parent
bc970596d6
commit
cb3da24f08
2 changed files with 68 additions and 16 deletions
|
@ -26,7 +26,44 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
|||
pipeline_id: PipelineId) {
|
||||
let mut new_running_animations = vec![];
|
||||
while let Ok(animation) = new_animations_receiver.try_recv() {
|
||||
new_running_animations.push(animation)
|
||||
let should_push = match animation {
|
||||
Animation::Transition(..) => true,
|
||||
Animation::Keyframes(ref node, ref name, ref state) => {
|
||||
// If the animation was already present in the list for the
|
||||
// node, just update its state, else push the new animation to
|
||||
// run.
|
||||
if let Some(ref mut animations) = running_animations.get_mut(node) {
|
||||
// TODO: This being linear is probably not optimal.
|
||||
match animations.iter_mut().find(|anim| match **anim {
|
||||
Animation::Keyframes(_, ref anim_name, _) => *name == *anim_name,
|
||||
Animation::Transition(..) => false,
|
||||
}) {
|
||||
Some(mut anim) => {
|
||||
debug!("update_animation_state: Found other animation {}", name);
|
||||
match *anim {
|
||||
Animation::Keyframes(_, _, ref mut anim_state) => {
|
||||
// NB: The important part is not touching
|
||||
// the started_at field.
|
||||
anim_state.duration = state.duration;
|
||||
anim_state.iteration_state = state.iteration_state.clone();
|
||||
anim_state.paused = state.paused;
|
||||
anim_state.delay = state.delay;
|
||||
false
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
None => true,
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if should_push {
|
||||
new_running_animations.push(animation);
|
||||
}
|
||||
}
|
||||
|
||||
if running_animations.is_empty() && new_running_animations.is_empty() {
|
||||
|
@ -54,8 +91,9 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
|||
*current += 1;
|
||||
*current < *max
|
||||
}
|
||||
// Just tick it again.
|
||||
KeyframesIterationState::Infinite => {
|
||||
state.started_at += state.duration;
|
||||
state.started_at += state.duration + state.delay;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,10 +41,12 @@ pub enum KeyframesIterationState {
|
|||
/// This structure represents the current keyframe animation state, i.e., the
|
||||
/// duration, the current and maximum iteration count, and the state (either
|
||||
/// playing or paused).
|
||||
// TODO: unify the use of f32/f64 in this file.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KeyframesAnimationState {
|
||||
pub started_at: f64,
|
||||
pub duration: f64,
|
||||
pub delay: f64,
|
||||
pub iteration_state: KeyframesIterationState,
|
||||
pub paused: bool,
|
||||
}
|
||||
|
@ -294,6 +296,7 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
|
|||
.send(Animation::Keyframes(node, name.clone(), KeyframesAnimationState {
|
||||
started_at: animation_start,
|
||||
duration: duration as f64,
|
||||
delay: delay as f64,
|
||||
iteration_state: iteration_state,
|
||||
paused: paused,
|
||||
})).unwrap();
|
||||
|
@ -383,36 +386,46 @@ where Impl: SelectorImplExt,
|
|||
let mut total_progress = (now - started_at) / total_duration;
|
||||
if total_progress < 0. {
|
||||
warn!("Negative progress found for animation {:?}", name);
|
||||
return;
|
||||
}
|
||||
if total_progress > 1. {
|
||||
total_progress = 1.;
|
||||
}
|
||||
|
||||
debug!("update_style_for_animation: anim \"{}\", steps: {:?}, state: {:?}, progress: {}", name, animation.steps, state, total_progress);
|
||||
|
||||
let mut last_keyframe = None;
|
||||
let mut target_keyframe = None;
|
||||
let mut last_keyframe_position = None;
|
||||
let mut target_keyframe_position = None;
|
||||
|
||||
// TODO: we could maybe binary-search this?
|
||||
for i in 1..animation.steps.len() {
|
||||
// TODO: we could maybe binary-search this? Also, find is probably a
|
||||
// bit more idiomatic here?
|
||||
for i in 0..animation.steps.len() {
|
||||
if total_progress as f32 <= animation.steps[i].start_percentage.0 {
|
||||
// We might have found our current keyframe.
|
||||
last_keyframe = target_keyframe;
|
||||
target_keyframe = Some(&animation.steps[i]);
|
||||
target_keyframe_position = Some(i);
|
||||
if i != 0 {
|
||||
last_keyframe_position = Some(i - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let target_keyframe = match target_keyframe {
|
||||
Some(current) => current,
|
||||
debug!("update_style_for_animation: keyframe from {:?} to {:?}", last_keyframe_position, target_keyframe_position);
|
||||
|
||||
let target_keyframe = match target_keyframe_position {
|
||||
Some(target) => &animation.steps[target],
|
||||
None => {
|
||||
warn!("update_style_for_animation: No current keyframe found for animation {:?} at progress {}", name, total_progress);
|
||||
// TODO: The 0. case falls here, maybe we should just resort
|
||||
// to the first keyframe instead.
|
||||
warn!("update_style_for_animation: No current keyframe found for animation \"{}\" at progress {}", name, total_progress);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let last_keyframe = match last_keyframe {
|
||||
Some(last_keyframe) => last_keyframe,
|
||||
let last_keyframe = match last_keyframe_position {
|
||||
Some(last) => &animation.steps[last],
|
||||
None => {
|
||||
warn!("update_style_for_animation: No last keyframe found for animation {:?} at progress {}", name, total_progress);
|
||||
warn!("update_style_for_animation: No last keyframe found for animation \"{}\" at progress {}", name, total_progress);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
@ -441,20 +454,21 @@ where Impl: SelectorImplExt,
|
|||
let mut style_changed = false;
|
||||
|
||||
for transition_property in &animation.properties_changed {
|
||||
debug!("update_style_for_animation: scanning prop {:?} for animation {}", transition_property, name);
|
||||
debug!("update_style_for_animation: scanning prop {:?} for animation \"{}\"", transition_property, name);
|
||||
if let Some(property_animation) = PropertyAnimation::from_transition_property(*transition_property,
|
||||
timing_function,
|
||||
Time(relative_duration as f32),
|
||||
&from_style,
|
||||
&target_style) {
|
||||
debug!("update_style_for_animation: got property animation for prop {:?}", transition_property);
|
||||
debug!("update_style_for_animation: {:?}", property_animation);
|
||||
property_animation.update(Arc::make_mut(&mut new_style), relative_progress);
|
||||
style_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if style_changed {
|
||||
debug!("update_style_for_animation: got style change in animation {:?}", name);
|
||||
debug!("update_style_for_animation: got style change in animation \"{}\"", name);
|
||||
if let Some(damage) = damage {
|
||||
*damage = *damage | Damage::compute(Some(style), &new_style);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue