aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/animation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/style/animation.rs')
-rw-r--r--components/style/animation.rs161
1 files changed, 105 insertions, 56 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs
index d7601a8ed73..75efde37b67 100644
--- a/components/style/animation.rs
+++ b/components/style/animation.rs
@@ -10,7 +10,7 @@
use crate::bezier::Bezier;
use crate::context::{CascadeInputs, SharedStyleContext};
use crate::dom::{OpaqueNode, TDocument, TElement, TNode};
-use crate::properties::animated_properties::AnimationValue;
+use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
use crate::properties::longhands::animation_fill_mode::computed_value::single_value::T as AnimationFillMode;
use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
@@ -127,13 +127,11 @@ impl PropertyAnimation {
}
/// Update the given animation at a given point of progress.
- fn update(&self, style: &mut ComputedValues, progress: f64) {
+ fn calculate_value(&self, progress: f64) -> Result<AnimationValue, ()> {
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);
- }
+ self.from.animate(&self.to, procedure)
}
}
@@ -598,16 +596,14 @@ impl Animation {
}
}
- /// Update the given style to reflect the values specified by this `Animation`
- /// at the time provided by the given `SharedStyleContext`.
- fn update_style(&self, context: &SharedStyleContext, style: &mut Arc<ComputedValues>) {
+ /// Fill in an `AnimationValueMap` with values calculated from this animation at
+ /// the given time value.
+ fn get_property_declaration_at_time(&self, now: f64, map: &mut AnimationValueMap) {
let duration = self.duration;
let started_at = self.started_at;
let now = match self.state {
- AnimationState::Running | AnimationState::Pending | AnimationState::Finished => {
- context.current_time_for_animations
- },
+ AnimationState::Running | AnimationState::Pending | AnimationState::Finished => now,
AnimationState::Paused(progress) => started_at + duration * progress,
AnimationState::Canceled => return,
};
@@ -666,7 +662,7 @@ impl Animation {
}
debug!(
- "Animation::update_style: keyframe from {:?} to {:?}",
+ "Animation::get_property_declaration_at_time: keyframe from {:?} to {:?}",
prev_keyframe_index, next_keyframe_index
);
@@ -676,20 +672,19 @@ impl Animation {
None => return,
};
- let update_with_single_keyframe_style = |style, keyframe: &ComputedKeyframe| {
- let mutable_style = Arc::make_mut(style);
+ let mut add_declarations_to_map = |keyframe: &ComputedKeyframe| {
for value in keyframe.values.iter() {
- value.set_in_style_for_servo(mutable_style);
+ map.insert(value.id(), value.clone());
}
};
if total_progress <= 0.0 {
- update_with_single_keyframe_style(style, &prev_keyframe);
+ add_declarations_to_map(&prev_keyframe);
return;
}
if total_progress >= 1.0 {
- update_with_single_keyframe_style(style, &next_keyframe);
+ add_declarations_to_map(&next_keyframe);
return;
}
@@ -707,18 +702,18 @@ impl Animation {
};
let relative_progress = (now - last_keyframe_ended_at) / relative_duration;
- let mut new_style = (**style).clone();
for (from, to) in prev_keyframe.values.iter().zip(next_keyframe.values.iter()) {
- PropertyAnimation {
+ let animation = PropertyAnimation {
from: from.clone(),
to: to.clone(),
timing_function: prev_keyframe.timing_function,
duration: relative_duration as f64,
+ };
+
+ if let Ok(value) = animation.calculate_value(relative_progress) {
+ map.insert(value.id(), value);
}
- .update(&mut new_style, relative_progress);
}
-
- *Arc::make_mut(style) = new_style;
}
}
@@ -799,7 +794,10 @@ impl Transition {
// time of the style change event, times the reversing shortening
// factor of the old transition
// 2. 1 minus the reversing shortening factor of the old transition."
- let transition_progress = replaced_transition.progress(now);
+ let transition_progress = ((now - replaced_transition.start_time) /
+ (replaced_transition.property_animation.duration))
+ .min(1.0)
+ .max(0.0);
let timing_function_output = replaced_animation.timing_function_output(transition_progress);
let old_reversing_shortening_factor = replaced_transition.reversing_shortening_factor;
self.reversing_shortening_factor = ((timing_function_output *
@@ -845,25 +843,16 @@ impl Transition {
time >= self.start_time + (self.property_animation.duration)
}
- /// Whether this animation has the same end value as another one.
- #[inline]
- 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`.
- fn update_style(&self, context: &SharedStyleContext, style: &mut Arc<ComputedValues>) {
- // Never apply canceled transitions to a style.
- if self.state == AnimationState::Canceled {
- return;
+ /// Update the given animation at a given point of progress.
+ pub fn calculate_value(&self, time: f64) -> Option<AnimationValue> {
+ let progress = (time - self.start_time) / (self.property_animation.duration);
+ if progress < 0.0 {
+ return None;
}
- let progress = self.progress(context.current_time_for_animations);
- if progress >= 0.0 {
- self.property_animation
- .update(Arc::make_mut(style), progress);
- }
+ self.property_animation
+ .calculate_value(progress.min(1.0))
+ .ok()
}
}
@@ -875,17 +864,29 @@ pub struct ElementAnimationSet {
/// The transitions for this element.
pub transitions: Vec<Transition>,
+
+ /// Whether or not this ElementAnimationSet has had animations or transitions
+ /// which have been added, removed, or had their state changed.
+ pub dirty: bool,
}
impl ElementAnimationSet {
/// Cancel all animations in this `ElementAnimationSet`. This is typically called
/// when the element has been removed from the DOM.
pub fn cancel_all_animations(&mut self) {
+ self.dirty = !self.animations.is_empty();
for animation in self.animations.iter_mut() {
animation.state = AnimationState::Canceled;
}
+ self.cancel_active_transitions();
+ }
+
+ fn cancel_active_transitions(&mut self) {
for transition in self.transitions.iter_mut() {
- transition.state = AnimationState::Canceled;
+ if transition.state != AnimationState::Finished {
+ self.dirty = true;
+ transition.state = AnimationState::Canceled;
+ }
}
}
@@ -894,12 +895,18 @@ impl ElementAnimationSet {
context: &SharedStyleContext,
style: &mut Arc<ComputedValues>,
) {
- for animation in &self.animations {
- animation.update_style(context, style);
+ let now = context.current_time_for_animations;
+ let mutable_style = Arc::make_mut(style);
+ if let Some(map) = self.get_value_map_for_active_animations(now) {
+ for value in map.values() {
+ value.set_in_style_for_servo(mutable_style);
+ }
}
- for transition in &self.transitions {
- transition.update_style(context, style);
+ if let Some(map) = self.get_value_map_for_active_transitions(now) {
+ for value in map.values() {
+ value.set_in_style_for_servo(mutable_style);
+ }
}
}
@@ -978,6 +985,7 @@ impl ElementAnimationSet {
/// when appropriate.
pub fn update_transitions_for_new_style(
&mut self,
+ might_need_transitions_update: bool,
context: &SharedStyleContext,
opaque_node: OpaqueNode,
old_style: Option<&Arc<ComputedValues>>,
@@ -990,12 +998,18 @@ impl ElementAnimationSet {
None => return,
};
+ // If the style of this element is display:none, then cancel all active transitions.
+ if after_change_style.get_box().clone_display().is_none() {
+ self.cancel_active_transitions();
+ return;
+ }
+
+ if !might_need_transitions_update {
+ return;
+ }
+
// We convert old values into `before-change-style` here.
- // See https://drafts.csswg.org/css-transitions/#starting. We need to clone the
- // style because this might still be a reference to the original `old_style` and
- // we want to preserve that so that we can later properly calculate restyle damage.
if self.has_active_transition() || self.has_active_animation() {
- before_change_style = before_change_style.clone();
self.apply_active_animations(context, &mut before_change_style);
}
@@ -1016,6 +1030,7 @@ impl ElementAnimationSet {
continue;
}
transition.state = AnimationState::Canceled;
+ self.dirty = true;
}
}
@@ -1086,6 +1101,45 @@ impl ElementAnimationSet {
}
self.transitions.push(new_transition);
+ self.dirty = true;
+ }
+
+ /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
+ /// active transitions at the given time value.
+ pub fn get_value_map_for_active_transitions(&self, now: f64) -> Option<AnimationValueMap> {
+ if !self.has_active_transition() {
+ return None;
+ }
+
+ let mut map =
+ AnimationValueMap::with_capacity_and_hasher(self.transitions.len(), Default::default());
+ for transition in &self.transitions {
+ if transition.state == AnimationState::Canceled {
+ continue;
+ }
+ let value = match transition.calculate_value(now) {
+ Some(value) => value,
+ None => continue,
+ };
+ map.insert(value.id(), value);
+ }
+
+ Some(map)
+ }
+
+ /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
+ /// active animations at the given time value.
+ pub fn get_value_map_for_active_animations(&self, now: f64) -> Option<AnimationValueMap> {
+ if !self.has_active_animation() {
+ return None;
+ }
+
+ let mut map = Default::default();
+ for animation in &self.animations {
+ animation.get_property_declaration_at_time(now, &mut map);
+ }
+
+ Some(map)
}
}
@@ -1098,13 +1152,6 @@ pub fn start_transitions_if_applicable(
new_style: &Arc<ComputedValues>,
animation_state: &mut ElementAnimationSet,
) -> 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.
- let box_style = new_style.get_box();
- if box_style.clone_display().is_none() {
- return LonghandIdSet::new();
- }
-
let mut properties_that_transition = LonghandIdSet::new();
for transition in new_style.transition_properties() {
let physical_property = transition.longhand_id.to_physical(new_style.writing_mode);
@@ -1214,6 +1261,8 @@ pub fn maybe_start_animations<E>(
is_new: true,
};
+ animation_state.dirty = true;
+
// If the animation was already present in the list for the node, just update its state.
for existing_animation in animation_state.animations.iter_mut() {
if existing_animation.state == AnimationState::Canceled {