Skip to content

Commit

Permalink
Auto merge of #18604 - emilio:animated-value-cleanup, r=nox
Browse files Browse the repository at this point in the history
style: Cleanup the animated value setup.

We have three different enums to represent slightly different things. Reuse them
properly, and kill some code in the animated_properties module while at it.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18604)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Sep 29, 2017
2 parents 8732f6d + 3215e36 commit 9ffd2b8
Show file tree
Hide file tree
Showing 12 changed files with 579 additions and 696 deletions.
155 changes: 76 additions & 79 deletions components/style/animation.rs
Expand Up @@ -10,8 +10,8 @@ use bezier::Bezier;
use context::SharedStyleContext;
use dom::OpaqueNode;
use font_metrics::FontMetricsProvider;
use properties::{self, CascadeFlags, ComputedValues};
use properties::animated_properties::{AnimatableLonghand, AnimatedProperty, TransitionProperty};
use properties::{self, CascadeFlags, ComputedValues, LonghandId};
use properties::animated_properties::{AnimatedProperty, TransitionProperty};
use properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
use properties::longhands::animation_iteration_count::single_value::computed_value::T as AnimationIterationCount;
use properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
Expand Down Expand Up @@ -271,87 +271,80 @@ impl PropertyAnimation {
/// and new styles. Any number of animations may be returned, from zero (if
/// the property did not animate) to one (for a single transition property)
/// to arbitrarily many (for `all`).
pub fn from_transition(transition_index: usize,
old_style: &ComputedValues,
new_style: &mut ComputedValues)
-> Vec<PropertyAnimation> {
pub fn from_transition(
transition_index: usize,
old_style: &ComputedValues,
new_style: &mut ComputedValues,
) -> Vec<PropertyAnimation> {
let mut result = vec![];
let box_style = new_style.get_box();
let transition_property = box_style.transition_property_at(transition_index);
let timing_function = box_style.transition_timing_function_mod(transition_index);
let duration = box_style.transition_duration_mod(transition_index);

if let TransitionProperty::Unsupported(_) = transition_property {
return result
}

if transition_property.is_shorthand() {
return transition_property.longhands().iter().filter_map(|transition_property| {
PropertyAnimation::from_transition_property(transition_property,
timing_function,
duration,
old_style,
new_style)
}).collect();
}

if transition_property != TransitionProperty::All {
if let Some(property_animation) =
PropertyAnimation::from_transition_property(&transition_property,
timing_function,
duration,
old_style,
new_style) {
result.push(property_animation)
match transition_property {
TransitionProperty::Unsupported(_) => result,
TransitionProperty::Shorthand(ref shorthand_id) => {
shorthand_id.longhands().iter().filter_map(|longhand| {
PropertyAnimation::from_longhand(
&longhand,
timing_function,
duration,
old_style,
new_style,
)
}).collect()
}
return result
}

TransitionProperty::each(|transition_property| {
if let Some(property_animation) =
PropertyAnimation::from_transition_property(&transition_property,
timing_function,
duration,
old_style,
new_style) {
result.push(property_animation)
TransitionProperty::Longhand(ref longhand_id) => {
let animation = PropertyAnimation::from_longhand(
longhand_id,
timing_function,
duration,
old_style,
new_style,
);

if let Some(animation) = animation {
result.push(animation);
}
result
}
});

result
}

fn from_transition_property(transition_property: &TransitionProperty,
timing_function: TimingFunction,
duration: Time,
old_style: &ComputedValues,
new_style: &ComputedValues)
-> Option<PropertyAnimation> {
debug_assert!(!transition_property.is_shorthand() &&
transition_property != &TransitionProperty::All);

// We're not expecting |transition_property| to be a shorthand (including 'all') and
// all other transitionable properties should be animatable longhands (since transitionable
// is a subset of animatable).
let animatable_longhand =
AnimatableLonghand::from_transition_property(transition_property).unwrap();

PropertyAnimation::from_animatable_longhand(&animatable_longhand,
timing_function,
duration,
old_style,
new_style)
TransitionProperty::All => {
TransitionProperty::each(|longhand_id| {
let animation = PropertyAnimation::from_longhand(
longhand_id,
timing_function,
duration,
old_style,
new_style,
);

if let Some(animation) = animation {
result.push(animation);
}
});
result
}
}
}

fn from_animatable_longhand(animatable_longhand: &AnimatableLonghand,
timing_function: TimingFunction,
duration: Time,
old_style: &ComputedValues,
new_style: &ComputedValues)
-> Option<PropertyAnimation> {
let animated_property = AnimatedProperty::from_animatable_longhand(animatable_longhand,
old_style,
new_style);
fn from_longhand(
longhand: &LonghandId,
timing_function: TimingFunction,
duration: Time,
old_style: &ComputedValues,
new_style: &ComputedValues,
) -> Option<PropertyAnimation> {
let animated_property = AnimatedProperty::from_longhand(
longhand,
old_style,
new_style,
);

let animated_property = match animated_property {
Some(p) => p,
None => return None,
};

let property_animation = PropertyAnimation {
property: animated_property,
Expand Down Expand Up @@ -758,14 +751,18 @@ pub fn update_style_for_animation(context: &SharedStyleContext,

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

for property in &animation.properties_changed {
for property in animation.properties_changed.iter() {
debug!("update_style_for_animation: scanning prop {:?} for animation \"{}\"",
property, name);
match PropertyAnimation::from_animatable_longhand(property,
timing_function,
Time::from_seconds(relative_duration as f32),
&from_style,
&target_style) {
let animation = PropertyAnimation::from_longhand(
&property,
timing_function,
Time::from_seconds(relative_duration as f32),
&from_style,
&target_style
);

match animation {
Some(property_animation) => {
debug!("update_style_for_animation: got property animation for prop {:?}", property);
debug!("update_style_for_animation: {:?}", property_animation);
Expand Down
3 changes: 2 additions & 1 deletion components/style/dom.rs
Expand Up @@ -17,6 +17,7 @@ use element_state::ElementState;
use font_metrics::FontMetricsProvider;
use media_queries::Device;
use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
#[cfg(feature = "gecko")] use properties::LonghandId;
#[cfg(feature = "gecko")] use properties::animated_properties::AnimationValue;
#[cfg(feature = "gecko")] use properties::animated_properties::TransitionProperty;
use rule_tree::CascadeLevel;
Expand Down Expand Up @@ -679,7 +680,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
#[cfg(feature = "gecko")]
fn needs_transitions_update_per_property(
&self,
property: &TransitionProperty,
property: &LonghandId,
combined_duration: f32,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues,
Expand Down
118 changes: 66 additions & 52 deletions components/style/gecko/wrapper.rs
Expand Up @@ -69,9 +69,9 @@ use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
use hash::HashMap;
use logical_geometry::WritingMode;
use media_queries::Device;
use properties::{ComputedValues, parse_style_attribute};
use properties::{ComputedValues, LonghandId, parse_style_attribute};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::animated_properties::{AnimatableLonghand, AnimationValue, AnimationValueMap};
use properties::animated_properties::{AnimationValue, AnimationValueMap};
use properties::animated_properties::TransitionProperty;
use properties::style_structs::Font;
use rule_tree::CascadeLevel as ServoCascadeLevel;
Expand Down Expand Up @@ -1357,12 +1357,13 @@ impl<'le> TElement for GeckoElement<'le> {
// update.
//
// https://drafts.csswg.org/css-transitions/#starting
fn needs_transitions_update(&self,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues)
-> bool {
fn needs_transitions_update(
&self,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues
) -> bool {
use gecko_bindings::structs::nsCSSPropertyID;
use hash::HashSet;
use std::collections::HashSet;

debug_assert!(self.might_need_transitions_update(Some(before_change_style),
after_change_style),
Expand All @@ -1372,13 +1373,6 @@ impl<'le> TElement for GeckoElement<'le> {
let after_change_box_style = after_change_style.get_box();
let transitions_count = after_change_box_style.transition_property_count();
let existing_transitions = self.get_css_transitions_info();
let mut transitions_to_keep = if !existing_transitions.is_empty() &&
(after_change_box_style.transition_nscsspropertyid_at(0) !=
nsCSSPropertyID::eCSSPropertyExtra_all_properties) {
Some(HashSet::<TransitionProperty>::with_capacity(transitions_count))
} else {
None
};

// Check if this property is none, custom or unknown.
let is_none_or_custom_property = |property: nsCSSPropertyID| -> bool {
Expand All @@ -1387,6 +1381,14 @@ impl<'le> TElement for GeckoElement<'le> {
property == nsCSSPropertyID::eCSSProperty_UNKNOWN;
};

let mut transitions_to_keep = if !existing_transitions.is_empty() &&
(after_change_box_style.transition_nscsspropertyid_at(0) !=
nsCSSPropertyID::eCSSPropertyExtra_all_properties) {
Some(HashSet::<TransitionProperty>::with_capacity(transitions_count))
} else {
None
};

for i in 0..transitions_count {
let property = after_change_box_style.transition_nscsspropertyid_at(i);
let combined_duration = after_change_box_style.transition_combined_duration_at(i);
Expand All @@ -1398,21 +1400,14 @@ impl<'le> TElement for GeckoElement<'le> {

let transition_property: TransitionProperty = property.into();

let mut property_check_helper = |property: &TransitionProperty| -> bool {
if self.needs_transitions_update_per_property(property,
combined_duration,
before_change_style,
after_change_style,
&existing_transitions) {
return true;
}

if let Some(set) = transitions_to_keep.as_mut() {
// The TransitionProperty here must be animatable, so cloning it is cheap
// because it is an integer-like enum.
set.insert(property.clone());
}
false
let property_check_helper = |property: &LonghandId| -> bool {
self.needs_transitions_update_per_property(
property,
combined_duration,
before_change_style,
after_change_style,
&existing_transitions
)
};

match transition_property {
Expand All @@ -1421,58 +1416,77 @@ impl<'le> TElement for GeckoElement<'le> {
return true;
}
},
TransitionProperty::Unsupported(_) => { },
ref shorthand if shorthand.is_shorthand() => {
if shorthand.longhands().iter().any(|p| property_check_helper(p)) {
TransitionProperty::Unsupported(..) => {},
TransitionProperty::Shorthand(ref shorthand) => {
if shorthand.longhands().iter().any(property_check_helper) {
return true;
}
},
ref longhand => {
if property_check_helper(longhand) {
TransitionProperty::Longhand(ref longhand_id) => {
if property_check_helper(longhand_id) {
return true;
}
},
};

if let Some(ref mut transitions_to_keep) = transitions_to_keep {
transitions_to_keep.insert(transition_property);
}
}

// Check if we have to cancel the running transition because this is not a matching
// transition-property value.
// Check if we have to cancel the running transition because this is not
// a matching transition-property value.
transitions_to_keep.map_or(false, |set| {
existing_transitions.keys().any(|property| !set.contains(property))
})
}

fn needs_transitions_update_per_property(
&self,
property: &TransitionProperty,
longhand_id: &LonghandId,
combined_duration: f32,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues,
existing_transitions: &HashMap<TransitionProperty, Arc<AnimationValue>>,
) -> bool {
use values::animated::{Animate, Procedure};

// |property| should be an animatable longhand
let animatable_longhand = AnimatableLonghand::from_transition_property(property).unwrap();

if existing_transitions.contains_key(property) {
// If there is an existing transition, update only if the end value differs.
// If the end value has not changed, we should leave the currently running
// transition as-is since we don't want to interrupt its timing function.
// If there is an existing transition, update only if the end value
// differs.
//
// If the end value has not changed, we should leave the currently
// running transition as-is since we don't want to interrupt its timing
// function.
//
// FIXME(emilio): The shorthand / longhand mapping with transitions
// looks pretty fishy!
if let Some(ref existing) = existing_transitions.get(&TransitionProperty::Longhand(*longhand_id)) {
let after_value =
Arc::new(AnimationValue::from_computed_values(&animatable_longhand,
after_change_style));
return existing_transitions.get(property).unwrap() != &after_value;
AnimationValue::from_computed_values(
&longhand_id,
after_change_style
).unwrap();

return ***existing != after_value
}

let from = AnimationValue::from_computed_values(&animatable_longhand,
before_change_style);
let to = AnimationValue::from_computed_values(&animatable_longhand,
after_change_style);
let from = AnimationValue::from_computed_values(
&longhand_id,
before_change_style,
);
let to = AnimationValue::from_computed_values(
&longhand_id,
after_change_style,
);

debug_assert_eq!(to.is_some(), from.is_some());

combined_duration > 0.0f32 &&
from != to &&
from.animate(&to, Procedure::Interpolate { progress: 0.5 }).is_ok()
from.unwrap().animate(
to.as_ref().unwrap(),
Procedure::Interpolate { progress: 0.5 }
).is_ok()
}

#[inline]
Expand Down

0 comments on commit 9ffd2b8

Please sign in to comment.