Skip to content

Commit

Permalink
Remove AnimatedProperty
Browse files Browse the repository at this point in the history
This removes an extra layer of abstraction and allows Servo to share
more code with Gecko. In addition, we will need to handle raw
`AnimationValue` structs soon in order to fully implement "faster
reversing of interrupted transitions."
  • Loading branch information
mrobinson committed May 13, 2020
1 parent bdfa6b0 commit 0f1831e
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 361 deletions.
6 changes: 3 additions & 3 deletions components/script/animations.rs
Expand Up @@ -113,7 +113,7 @@ impl Animations {
transition.state = AnimationState::Finished;
update.add_event(
transition.node,
transition.property_animation.property_name().into(),
transition.property_animation.property_id().name().into(),
TransitionOrAnimationEventType::TransitionEnd,
transition.property_animation.duration,
);
Expand All @@ -135,7 +135,7 @@ impl Animations {
// according to https://drafts.csswg.org/css-transitions/#event-transitionevent
update.add_event(
transition.node,
transition.property_animation.property_name().into(),
transition.property_animation.property_id().name().into(),
TransitionOrAnimationEventType::TransitionCancel,
(now - transition.start_time).max(0.),
);
Expand All @@ -157,7 +157,7 @@ impl Animations {
// according to https://drafts.csswg.org/css-transitions/#event-transitionevent
update.add_event(
transition.node,
transition.property_animation.property_name().into(),
transition.property_animation.property_id().name().into(),
TransitionOrAnimationEventType::TransitionRun,
0.,
);
Expand Down
154 changes: 64 additions & 90 deletions components/style/animation.rs
Expand Up @@ -11,13 +11,14 @@ use crate::bezier::Bezier;
use crate::context::SharedStyleContext;
use crate::dom::{OpaqueNode, TElement, TNode};
use crate::font_metrics::FontMetricsProvider;
use crate::properties::animated_properties::AnimatedProperty;
use crate::properties::animated_properties::AnimationValue;
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
use crate::properties::LonghandIdSet;
use crate::properties::{self, CascadeMode, ComputedValues, LonghandId};
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
use crate::stylesheets::Origin;
use crate::values::animated::{Animate, Procedure};
use crate::values::computed::Time;
use crate::values::computed::TimingFunction;
use crate::values::generics::box_::AnimationIterationCount;
Expand All @@ -29,8 +30,11 @@ use std::fmt;
/// Represents an animation for a given property.
#[derive(Clone, Debug, MallocSizeOf)]
pub struct PropertyAnimation {
/// An `AnimatedProperty` that this `PropertyAnimation` corresponds to.
property: AnimatedProperty,
/// The value we are animating from.
from: AnimationValue,

/// The value we are animating to.
to: AnimationValue,

/// The timing function of this `PropertyAnimation`.
timing_function: TimingFunction,
Expand All @@ -42,12 +46,8 @@ pub struct PropertyAnimation {
impl PropertyAnimation {
/// Returns the given property longhand id.
pub fn property_id(&self) -> LonghandId {
self.property.id()
}

/// Returns the given property name.
pub fn property_name(&self) -> &'static str {
self.property.name()
debug_assert_eq!(self.from.id(), self.to.id());
self.from.id()
}

fn from_longhand(
Expand All @@ -57,30 +57,33 @@ impl PropertyAnimation {
old_style: &ComputedValues,
new_style: &ComputedValues,
) -> Option<PropertyAnimation> {
let animated_property = AnimatedProperty::from_longhand(longhand, old_style, new_style)?;
// FIXME(emilio): Handle the case where old_style and new_style's writing mode differ.
let longhand = longhand.to_physical(new_style.writing_mode);
let from = AnimationValue::from_computed_values(longhand, old_style)?;
let to = AnimationValue::from_computed_values(longhand, new_style)?;
let duration = duration.seconds() as f64;

if from == to || duration == 0.0 {
return None;
}

let property_animation = PropertyAnimation {
property: animated_property,
Some(PropertyAnimation {
from,
to,
timing_function,
duration: duration.seconds() as f64,
};

if property_animation.does_animate() {
Some(property_animation)
} else {
None
}
duration,
})
}

/// Update the given animation at a given point of progress.
pub fn update(&self, style: &mut ComputedValues, time: f64) {
/// The output of the timing function given the progress ration of this animation.
fn timing_function_output(&self, progress: f64) -> f64 {
let epsilon = 1. / (200. * self.duration);
let progress = match self.timing_function {
match self.timing_function {
GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => {
Bezier::new(x1, y1, x2, y2).solve(time, epsilon)
Bezier::new(x1, y1, x2, y2).solve(progress, epsilon)
},
GenericTimingFunction::Steps(steps, pos) => {
let mut current_step = (time * (steps as f64)).floor() as i32;
let mut current_step = (progress * (steps as f64)).floor() as i32;

if pos == StepPosition::Start ||
pos == StepPosition::JumpStart ||
Expand All @@ -95,7 +98,7 @@ impl PropertyAnimation {
// (i.e. Treat before_flag is unset,)
// https://drafts.csswg.org/css-easing/#step-timing-function-algo

if time >= 0.0 && current_step < 0 {
if progress >= 0.0 && current_step < 0 {
current_step = 0;
}

Expand All @@ -108,30 +111,27 @@ impl PropertyAnimation {
StepPosition::End => steps,
};

if time <= 1.0 && current_step > jumps {
if progress <= 1.0 && current_step > jumps {
current_step = jumps;
}

(current_step as f64) / (jumps as f64)
},
GenericTimingFunction::Keyword(keyword) => {
let (x1, x2, y1, y2) = keyword.to_bezier();
Bezier::new(x1, x2, y1, y2).solve(time, epsilon)
Bezier::new(x1, x2, y1, y2).solve(progress, epsilon)
},
};

self.property.update(style, progress);
}

#[inline]
fn does_animate(&self) -> bool {
self.property.does_animate() && self.duration != 0.0
}
}

/// Whether this animation has the same end value as another one.
#[inline]
pub fn has_the_same_end_value_as(&self, other: &Self) -> bool {
self.property.has_the_same_end_value_as(&other.property)
/// Update the given animation at a given point of progress.
fn update(&self, style: &mut ComputedValues, progress: f64) {
let procedure = Procedure::Interpolate {
progress: self.timing_function_output(progress),
};
if let Ok(new_value) = self.from.animate(&self.to, procedure) {
new_value.set_in_style_for_servo(style);
}
}
}

Expand Down Expand Up @@ -486,42 +486,23 @@ impl Animation {
);

let mut new_style = (*style).clone();

for property in self.keyframes_animation.properties_changed.iter() {
debug!(
"Animation::update_style: scanning prop {:?} for animation \"{}\"",
property, self.name
);
let animation = PropertyAnimation::from_longhand(
property,
let mut update_style_for_longhand = |longhand| {
let from = AnimationValue::from_computed_values(longhand, &from_style)?;
let to = AnimationValue::from_computed_values(longhand, &target_style)?;
PropertyAnimation {
from,
to,
timing_function,
Time::from_seconds(relative_duration as f32),
&from_style,
&target_style,
);

match animation {
Some(property_animation) => {
debug!(
"Animation::update_style: got property animation for prop {:?}",
property
);
debug!("Animation::update_style: {:?}", property_animation);
property_animation.update(&mut new_style, relative_progress);
},
None => {
debug!(
"Animation::update_style: property animation {:?} not animating",
property
);
},
duration: relative_duration as f64,
}
.update(&mut new_style, relative_progress);
None::<()>
};

for property in self.keyframes_animation.properties_changed.iter() {
update_style_for_longhand(property);
}

debug!(
"Animation::update_style: got style change in animation \"{}\"",
self.name
);
*style = new_style;
}
}
Expand Down Expand Up @@ -573,12 +554,9 @@ impl Transition {

/// Whether this animation has the same end value as another one.
#[inline]
fn has_same_end_value(&self, other_animation: &PropertyAnimation) -> bool {
if self.state == AnimationState::Canceled {
return false;
}
self.property_animation
.has_the_same_end_value_as(other_animation)
fn progress(&self, now: f64) -> f64 {
let progress = (now - self.start_time) / (self.property_animation.duration);
progress.min(1.0)
}

/// Update a style to the value specified by this `Transition` given a `SharedStyleContext`.
Expand All @@ -588,9 +566,7 @@ impl Transition {
return;
}

let now = context.current_time_for_animations;
let progress = (now - self.start_time) / (self.property_animation.duration);
let progress = progress.min(1.0);
let progress = self.progress(context.current_time_for_animations);
if progress >= 0.0 {
self.property_animation.update(style, progress);
}
Expand Down Expand Up @@ -782,7 +758,8 @@ pub fn start_transitions_if_applicable(
) -> LonghandIdSet {
// If the style of this element is display:none, then we don't start any transitions
// and we cancel any currently running transitions by returning an empty LonghandIdSet.
if new_style.get_box().clone_display().is_none() {
let box_style = new_style.get_box();
if box_style.clone_display().is_none() {
return LonghandIdSet::new();
}

Expand All @@ -797,12 +774,8 @@ pub fn start_transitions_if_applicable(

let property_animation = match PropertyAnimation::from_longhand(
transition.longhand_id,
new_style
.get_box()
.transition_timing_function_mod(transition.index),
new_style
.get_box()
.transition_duration_mod(transition.index),
box_style.transition_timing_function_mod(transition.index),
box_style.transition_duration_mod(transition.index),
old_style,
new_style,
) {
Expand All @@ -812,12 +785,13 @@ pub fn start_transitions_if_applicable(

// Per [1], don't trigger a new transition if the end state for that
// transition is the same as that of a transition that's running or
// completed.
// completed. We don't take into account any canceled animations.
// [1]: https://drafts.csswg.org/css-transitions/#starting
if animation_state
.transitions
.iter()
.any(|transition| transition.has_same_end_value(&property_animation))
.filter(|transition| transition.state != AnimationState::Canceled)
.any(|transition| transition.property_animation.to == property_animation.to)
{
continue;
}
Expand Down

0 comments on commit 0f1831e

Please sign in to comment.