mirror of
https://github.com/servo/servo.git
synced 2025-06-09 09:03:23 +00:00
style: Support animation-direction.
This commit is contained in:
parent
9cf2e52d36
commit
33f581883b
2 changed files with 97 additions and 32 deletions
|
@ -13,7 +13,7 @@ use script_layout_interface::restyle_damage::RestyleDamage;
|
||||||
use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
|
use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
use style::animation::{Animation, KeyframesIterationState, update_style_for_animation};
|
use style::animation::{Animation, 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.
|
||||||
|
@ -42,11 +42,11 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
||||||
match *anim {
|
match *anim {
|
||||||
Animation::Keyframes(_, _, ref mut anim_state) => {
|
Animation::Keyframes(_, _, ref mut anim_state) => {
|
||||||
// NB: The important part is not touching
|
// NB: The important part is not touching
|
||||||
// the started_at field.
|
// the started_at field, since we don't want
|
||||||
anim_state.duration = state.duration;
|
// to restart the animation.
|
||||||
anim_state.iteration_state = state.iteration_state.clone();
|
let old_started_at = anim_state.started_at;
|
||||||
anim_state.paused = state.paused;
|
*anim_state = state.clone();
|
||||||
anim_state.delay = state.delay;
|
anim_state.started_at = old_started_at;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -84,18 +84,7 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
||||||
Animation::Keyframes(_, _, ref mut state) => {
|
Animation::Keyframes(_, _, ref mut state) => {
|
||||||
// This animation is still running, or we need to keep
|
// This animation is still running, or we need to keep
|
||||||
// iterating.
|
// iterating.
|
||||||
now < state.started_at + state.duration ||
|
now < state.started_at + state.duration || state.tick()
|
||||||
match state.iteration_state {
|
|
||||||
KeyframesIterationState::Finite(ref mut current, ref max) => {
|
|
||||||
*current += 1;
|
|
||||||
*current < *max
|
|
||||||
}
|
|
||||||
// Just tick it again.
|
|
||||||
KeyframesIterationState::Infinite => {
|
|
||||||
state.started_at += state.duration + state.delay;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ use dom::{OpaqueNode, TRestyleDamage};
|
||||||
use euclid::point::Point2D;
|
use euclid::point::Point2D;
|
||||||
use keyframes::KeyframesStep;
|
use keyframes::KeyframesStep;
|
||||||
use properties::animated_properties::{AnimatedProperty, TransitionProperty};
|
use properties::animated_properties::{AnimatedProperty, TransitionProperty};
|
||||||
|
use properties::longhands::animation_direction::computed_value::AnimationDirection;
|
||||||
use properties::longhands::animation_iteration_count::computed_value::AnimationIterationCount;
|
use properties::longhands::animation_iteration_count::computed_value::AnimationIterationCount;
|
||||||
use properties::longhands::animation_play_state::computed_value::AnimationPlayState;
|
use properties::longhands::animation_play_state::computed_value::AnimationPlayState;
|
||||||
use properties::longhands::transition_timing_function::computed_value::StartEnd;
|
use properties::longhands::transition_timing_function::computed_value::StartEnd;
|
||||||
|
@ -42,11 +43,55 @@ pub enum KeyframesIterationState {
|
||||||
// TODO: unify the use of f32/f64 in this file.
|
// TODO: unify the use of f32/f64 in this file.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct KeyframesAnimationState {
|
pub struct KeyframesAnimationState {
|
||||||
|
/// The time this animation started at.
|
||||||
pub started_at: f64,
|
pub started_at: f64,
|
||||||
|
/// The duration of this animation.
|
||||||
pub duration: f64,
|
pub duration: f64,
|
||||||
|
/// The delay of the animation.
|
||||||
pub delay: f64,
|
pub delay: f64,
|
||||||
|
/// The current iteration state for the animation.
|
||||||
pub iteration_state: KeyframesIterationState,
|
pub iteration_state: KeyframesIterationState,
|
||||||
|
/// Werther this animation is paused.
|
||||||
pub paused: bool,
|
pub paused: bool,
|
||||||
|
/// The declared animation direction of this animation.
|
||||||
|
pub direction: AnimationDirection,
|
||||||
|
/// The current animation direction. This can only be `normal` or `reverse`.
|
||||||
|
pub current_direction: AnimationDirection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyframesAnimationState {
|
||||||
|
/// Performs a tick in the animation state, i.e., increments the counter of
|
||||||
|
/// the current iteration count, updates times and then toggles the
|
||||||
|
/// direction if appropriate.
|
||||||
|
///
|
||||||
|
/// Returns true if the animation should keep running.
|
||||||
|
pub fn tick(&mut self) -> bool {
|
||||||
|
let still_running = match self.iteration_state {
|
||||||
|
KeyframesIterationState::Finite(ref mut current, ref max) => {
|
||||||
|
*current += 1;
|
||||||
|
*current < *max
|
||||||
|
}
|
||||||
|
KeyframesIterationState::Infinite => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Just tick it again updating the started_at field.
|
||||||
|
self.started_at += self.duration + self.delay;
|
||||||
|
|
||||||
|
// Update the next iteration direction if applicable.
|
||||||
|
match self.direction {
|
||||||
|
AnimationDirection::alternate |
|
||||||
|
AnimationDirection::alternate_reverse => {
|
||||||
|
self.current_direction = match self.current_direction {
|
||||||
|
AnimationDirection::normal => AnimationDirection::reverse,
|
||||||
|
AnimationDirection::reverse => AnimationDirection::normal,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
still_running
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State relating to an animation.
|
/// State relating to an animation.
|
||||||
|
@ -287,6 +332,16 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
|
||||||
AnimationIterationCount::Infinite => KeyframesIterationState::Infinite,
|
AnimationIterationCount::Infinite => KeyframesIterationState::Infinite,
|
||||||
AnimationIterationCount::Number(n) => KeyframesIterationState::Finite(0, n),
|
AnimationIterationCount::Number(n) => KeyframesIterationState::Finite(0, n),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let animation_direction = *box_style.animation_direction.0.get_mod(i);
|
||||||
|
|
||||||
|
let initial_direction = match animation_direction {
|
||||||
|
AnimationDirection::normal |
|
||||||
|
AnimationDirection::alternate => AnimationDirection::normal,
|
||||||
|
AnimationDirection::reverse |
|
||||||
|
AnimationDirection::alternate_reverse => AnimationDirection::reverse,
|
||||||
|
};
|
||||||
|
|
||||||
let paused = *box_style.animation_play_state.0.get_mod(i) == AnimationPlayState::paused;
|
let paused = *box_style.animation_play_state.0.get_mod(i) == AnimationPlayState::paused;
|
||||||
|
|
||||||
context.new_animations_sender
|
context.new_animations_sender
|
||||||
|
@ -297,6 +352,8 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
|
||||||
delay: delay as f64,
|
delay: delay as f64,
|
||||||
iteration_state: iteration_state,
|
iteration_state: iteration_state,
|
||||||
paused: paused,
|
paused: paused,
|
||||||
|
direction: animation_direction,
|
||||||
|
current_direction: initial_direction,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
had_animations = true;
|
had_animations = true;
|
||||||
}
|
}
|
||||||
|
@ -393,20 +450,31 @@ where Impl: SelectorImplExt,
|
||||||
debug!("update_style_for_animation: anim \"{}\", steps: {:?}, state: {:?}, progress: {}",
|
debug!("update_style_for_animation: anim \"{}\", steps: {:?}, state: {:?}, progress: {}",
|
||||||
name, animation.steps, state, total_progress);
|
name, animation.steps, state, total_progress);
|
||||||
|
|
||||||
let mut last_keyframe_position = None;
|
// Get the target and the last keyframe position.
|
||||||
let mut target_keyframe_position = None;
|
let last_keyframe_position;
|
||||||
|
let target_keyframe_position;
|
||||||
|
match state.current_direction {
|
||||||
|
AnimationDirection::normal => {
|
||||||
|
target_keyframe_position =
|
||||||
|
animation.steps.iter().position(|step| {
|
||||||
|
total_progress as f32 <= step.start_percentage.0
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: we could maybe binary-search this? Also, find is probably a
|
last_keyframe_position = target_keyframe_position.and_then(|pos| {
|
||||||
// bit more idiomatic here?
|
if pos != 0 { Some(pos - 1) } else { None }
|
||||||
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.
|
|
||||||
target_keyframe_position = Some(i);
|
|
||||||
if i != 0 {
|
|
||||||
last_keyframe_position = Some(i - 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
AnimationDirection::reverse => {
|
||||||
|
target_keyframe_position =
|
||||||
|
animation.steps.iter().rev().position(|step| {
|
||||||
|
total_progress as f32 <= 1. - step.start_percentage.0
|
||||||
|
}).map(|pos| animation.steps.len() - pos - 1);
|
||||||
|
|
||||||
|
last_keyframe_position = target_keyframe_position.and_then(|pos| {
|
||||||
|
if pos != animation.steps.len() - 1 { Some(pos + 1) } else { None }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("update_style_for_animation: keyframe from {:?} to {:?}",
|
debug!("update_style_for_animation: keyframe from {:?} to {:?}",
|
||||||
|
@ -432,9 +500,17 @@ where Impl: SelectorImplExt,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let relative_timespan = target_keyframe.start_percentage.0 - last_keyframe.start_percentage.0;
|
let relative_timespan = (target_keyframe.start_percentage.0 - last_keyframe.start_percentage.0).abs();
|
||||||
let relative_duration = relative_timespan as f64 * duration;
|
let relative_duration = relative_timespan as f64 * duration;
|
||||||
let last_keyframe_ended_at = state.started_at + (total_duration * last_keyframe.start_percentage.0 as f64);
|
let last_keyframe_ended_at = match state.current_direction {
|
||||||
|
AnimationDirection::normal => {
|
||||||
|
state.started_at + (total_duration * last_keyframe.start_percentage.0 as f64)
|
||||||
|
}
|
||||||
|
AnimationDirection::reverse => {
|
||||||
|
state.started_at + (total_duration * (1. - last_keyframe.start_percentage.0 as f64))
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
let relative_progress = (now - last_keyframe_ended_at) / relative_duration;
|
let relative_progress = (now - last_keyframe_ended_at) / relative_duration;
|
||||||
|
|
||||||
// TODO: How could we optimise it? Is it such a big deal?
|
// TODO: How could we optimise it? Is it such a big deal?
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue