mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
style: Fix parsing and add generated keyframes
This commit is contained in:
parent
46eec45886
commit
2d566ef0ef
10 changed files with 189 additions and 94 deletions
|
@ -4,12 +4,11 @@
|
|||
|
||||
//! CSS transitions and animations.
|
||||
|
||||
use app_units::Au;
|
||||
use bezier::Bezier;
|
||||
use context::SharedStyleContext;
|
||||
use dom::{OpaqueNode, TRestyleDamage};
|
||||
use euclid::point::Point2D;
|
||||
use keyframes::KeyframesStep;
|
||||
use keyframes::{KeyframesStep, KeyframesStepValue};
|
||||
use properties::animated_properties::{AnimatedProperty, TransitionProperty};
|
||||
use properties::longhands::animation_direction::computed_value::AnimationDirection;
|
||||
use properties::longhands::animation_iteration_count::computed_value::AnimationIterationCount;
|
||||
|
@ -54,7 +53,7 @@ pub enum KeyframesRunningState {
|
|||
/// playing or paused).
|
||||
// TODO: unify the use of f32/f64 in this file.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KeyframesAnimationState {
|
||||
pub struct KeyframesAnimationState<Impl: SelectorImplExt> {
|
||||
/// The time this animation started at.
|
||||
pub started_at: f64,
|
||||
/// The duration of this animation.
|
||||
|
@ -71,9 +70,12 @@ pub struct KeyframesAnimationState {
|
|||
pub current_direction: AnimationDirection,
|
||||
/// Werther this keyframe animation is outdated due to a restyle.
|
||||
pub expired: bool,
|
||||
/// The original cascade style, needed to compute the generated keyframes of
|
||||
/// the animation.
|
||||
pub cascade_style: Arc<Impl::ComputedValues>,
|
||||
}
|
||||
|
||||
impl KeyframesAnimationState {
|
||||
impl<Impl: SelectorImplExt> KeyframesAnimationState<Impl> {
|
||||
/// 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.
|
||||
|
@ -121,7 +123,8 @@ impl KeyframesAnimationState {
|
|||
///
|
||||
/// There are some bits of state we can't just replace, over all taking in
|
||||
/// account times, so here's that logic.
|
||||
pub fn update_from_other(&mut self, other: &Self) {
|
||||
pub fn update_from_other(&mut self, other: &Self)
|
||||
where Self: Clone {
|
||||
use self::KeyframesRunningState::*;
|
||||
|
||||
debug!("KeyframesAnimationState::update_from_other({:?}, {:?})", self, other);
|
||||
|
@ -167,7 +170,7 @@ impl KeyframesAnimationState {
|
|||
|
||||
/// State relating to an animation.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Animation {
|
||||
pub enum Animation<Impl: SelectorImplExt> {
|
||||
/// A transition is just a single frame triggered at a time, with a reflow.
|
||||
///
|
||||
/// the f64 field is the start time as returned by `time::precise_time_s()`.
|
||||
|
@ -176,10 +179,10 @@ pub enum Animation {
|
|||
Transition(OpaqueNode, f64, AnimationFrame, bool),
|
||||
/// A keyframes animation is identified by a name, and can have a
|
||||
/// node-dependent state (i.e. iteration count, etc.).
|
||||
Keyframes(OpaqueNode, Atom, KeyframesAnimationState),
|
||||
Keyframes(OpaqueNode, Atom, KeyframesAnimationState<Impl>),
|
||||
}
|
||||
|
||||
impl Animation {
|
||||
impl<Impl: SelectorImplExt> Animation<Impl> {
|
||||
#[inline]
|
||||
pub fn mark_as_expired(&mut self) {
|
||||
debug_assert!(!self.is_expired());
|
||||
|
@ -344,18 +347,20 @@ impl<T> GetMod for Vec<T> {
|
|||
//
|
||||
// TODO(emilio): Take rid of this mutex splitting SharedLayoutContex into a
|
||||
// cloneable part and a non-cloneable part..
|
||||
pub fn start_transitions_if_applicable<C: ComputedValues>(new_animations_sender: &Mutex<Sender<Animation>>,
|
||||
node: OpaqueNode,
|
||||
old_style: &C,
|
||||
new_style: &mut C)
|
||||
-> bool {
|
||||
pub fn start_transitions_if_applicable<Impl: SelectorImplExt>(new_animations_sender: &Mutex<Sender<Animation<Impl>>>,
|
||||
node: OpaqueNode,
|
||||
old_style: &Impl::ComputedValues,
|
||||
new_style: &mut Arc<Impl::ComputedValues>)
|
||||
-> bool {
|
||||
let mut had_animations = false;
|
||||
for i in 0..new_style.get_box().transition_count() {
|
||||
// Create any property animations, if applicable.
|
||||
let property_animations = PropertyAnimation::from_transition(i, old_style, new_style);
|
||||
let property_animations = PropertyAnimation::from_transition(i, old_style, Arc::make_mut(new_style));
|
||||
for property_animation in property_animations {
|
||||
// Set the property to the initial value.
|
||||
property_animation.update(new_style, 0.0);
|
||||
// NB: get_mut is guaranteed to succeed since we called make_mut()
|
||||
// above.
|
||||
property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0);
|
||||
|
||||
// Kick off the animation.
|
||||
let now = time::precise_time_s();
|
||||
|
@ -378,24 +383,33 @@ pub fn start_transitions_if_applicable<C: ComputedValues>(new_animations_sender:
|
|||
|
||||
fn compute_style_for_animation_step<Impl: SelectorImplExt>(context: &SharedStyleContext<Impl>,
|
||||
step: &KeyframesStep,
|
||||
old_style: &Impl::ComputedValues) -> Impl::ComputedValues {
|
||||
let declaration_block = DeclarationBlock {
|
||||
declarations: step.declarations.clone(),
|
||||
source_order: 0,
|
||||
specificity: ::std::u32::MAX,
|
||||
};
|
||||
let (computed, _) = properties::cascade(context.viewport_size,
|
||||
&[declaration_block],
|
||||
false,
|
||||
Some(old_style),
|
||||
None,
|
||||
context.error_reporter.clone());
|
||||
computed
|
||||
previous_style: &Impl::ComputedValues,
|
||||
style_from_cascade: &Impl::ComputedValues)
|
||||
-> Impl::ComputedValues {
|
||||
match step.value {
|
||||
// TODO: avoiding this spurious clone might involve having to create
|
||||
// an Arc in the below (more common case).
|
||||
KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
|
||||
KeyframesStepValue::Declarations(ref declarations) => {
|
||||
let declaration_block = DeclarationBlock {
|
||||
declarations: declarations.clone(),
|
||||
source_order: 0,
|
||||
specificity: ::std::u32::MAX,
|
||||
};
|
||||
let (computed, _) = properties::cascade(context.viewport_size,
|
||||
&[declaration_block],
|
||||
false,
|
||||
Some(previous_style),
|
||||
None,
|
||||
context.error_reporter.clone());
|
||||
computed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContext<Impl>,
|
||||
node: OpaqueNode,
|
||||
new_style: &Impl::ComputedValues) -> bool
|
||||
new_style: &Arc<Impl::ComputedValues>) -> bool
|
||||
{
|
||||
let mut had_animations = false;
|
||||
|
||||
|
@ -407,8 +421,17 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
|
|||
continue
|
||||
}
|
||||
|
||||
if context.stylist.animations().get(&name).is_some() {
|
||||
if let Some(ref anim) = context.stylist.animations().get(&name) {
|
||||
debug!("maybe_start_animations: animation {} found", name);
|
||||
|
||||
// If this animation doesn't have any keyframe, we can just continue
|
||||
// without submitting it to the compositor, since both the first and
|
||||
// the second keyframes would be synthetised from the computed
|
||||
// values.
|
||||
if anim.steps.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let delay = box_style.animation_delay.0.get_mod(i).seconds();
|
||||
let now = time::precise_time_s();
|
||||
let animation_start = now + delay as f64;
|
||||
|
@ -444,6 +467,7 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
|
|||
direction: animation_direction,
|
||||
current_direction: initial_direction,
|
||||
expired: false,
|
||||
cascade_style: new_style.clone(),
|
||||
})).unwrap();
|
||||
had_animations = true;
|
||||
}
|
||||
|
@ -474,7 +498,7 @@ pub fn update_style_for_animation_frame<C: ComputedValues>(mut new_style: &mut A
|
|||
/// 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<Damage, Impl>(context: &SharedStyleContext<Impl>,
|
||||
animation: &Animation,
|
||||
animation: &Animation<Impl>,
|
||||
style: &mut Arc<Damage::ConcreteComputedValues>,
|
||||
damage: Option<&mut Damage>)
|
||||
where Impl: SelectorImplExt,
|
||||
|
@ -516,6 +540,8 @@ where Impl: SelectorImplExt,
|
|||
Some(animation) => animation,
|
||||
};
|
||||
|
||||
debug_assert!(!animation.steps.is_empty());
|
||||
|
||||
let maybe_index = style.as_servo()
|
||||
.get_box().animation_name.0.iter()
|
||||
.position(|animation_name| name == animation_name);
|
||||
|
@ -579,8 +605,6 @@ where Impl: SelectorImplExt,
|
|||
let target_keyframe = match target_keyframe_position {
|
||||
Some(target) => &animation.steps[target],
|
||||
None => {
|
||||
// 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;
|
||||
|
@ -605,7 +629,8 @@ where Impl: SelectorImplExt,
|
|||
// TODO: How could we optimise it? Is it such a big deal?
|
||||
let from_style = compute_style_for_animation_step(context,
|
||||
last_keyframe,
|
||||
&**style);
|
||||
&**style,
|
||||
&state.cascade_style);
|
||||
|
||||
// NB: The spec says that the timing function can be overwritten
|
||||
// from the keyframe style.
|
||||
|
@ -616,7 +641,8 @@ where Impl: SelectorImplExt,
|
|||
|
||||
let target_style = compute_style_for_animation_step(context,
|
||||
target_keyframe,
|
||||
&from_style);
|
||||
&from_style,
|
||||
&state.cascade_style);
|
||||
|
||||
let mut new_style = (*style).clone();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue