mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
Allow empty keyframe and keyframes with non-animatable properties.
We need to create CSS animations that have empty keyframe or keyframes which have only invalid properties or non-animatable properties to fire animation events for such animations.
This commit is contained in:
parent
8421ae6077
commit
a80725c91b
4 changed files with 67 additions and 31 deletions
|
@ -266,50 +266,51 @@ fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
|
||||||
impl KeyframesAnimation {
|
impl KeyframesAnimation {
|
||||||
/// Create a keyframes animation from a given list of keyframes.
|
/// Create a keyframes animation from a given list of keyframes.
|
||||||
///
|
///
|
||||||
/// This will return `None` if the list of keyframes is empty, or there are
|
/// This will return a keyframe animation with empty steps and
|
||||||
/// no animated properties obtained from the keyframes.
|
/// properties_changed if the list of keyframes is empty, or there are no
|
||||||
|
// animated properties obtained from the keyframes.
|
||||||
///
|
///
|
||||||
/// Otherwise, this will compute and sort the steps used for the animation,
|
/// Otherwise, this will compute and sort the steps used for the animation,
|
||||||
/// and return the animation object.
|
/// and return the animation object.
|
||||||
pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Option<Self> {
|
pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Self {
|
||||||
|
let mut result = KeyframesAnimation {
|
||||||
|
steps: vec![],
|
||||||
|
properties_changed: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
if keyframes.is_empty() {
|
if keyframes.is_empty() {
|
||||||
return None;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
let animated_properties = get_animated_properties(&keyframes[0].read());
|
result.properties_changed = get_animated_properties(&keyframes[0].read());
|
||||||
if animated_properties.is_empty() {
|
if result.properties_changed.is_empty() {
|
||||||
return None;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut steps = vec![];
|
|
||||||
|
|
||||||
for keyframe in keyframes {
|
for keyframe in keyframes {
|
||||||
let keyframe = keyframe.read();
|
let keyframe = keyframe.read();
|
||||||
for percentage in keyframe.selector.0.iter() {
|
for percentage in keyframe.selector.0.iter() {
|
||||||
steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
|
result.steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
|
||||||
block: keyframe.block.clone(),
|
block: keyframe.block.clone(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by the start percentage, so we can easily find a frame.
|
// Sort by the start percentage, so we can easily find a frame.
|
||||||
steps.sort_by_key(|step| step.start_percentage);
|
result.steps.sort_by_key(|step| step.start_percentage);
|
||||||
|
|
||||||
// Prepend autogenerated keyframes if appropriate.
|
// Prepend autogenerated keyframes if appropriate.
|
||||||
if steps[0].start_percentage.0 != 0. {
|
if result.steps[0].start_percentage.0 != 0. {
|
||||||
steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
|
result.steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
|
||||||
KeyframesStepValue::ComputedValues));
|
KeyframesStepValue::ComputedValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
if steps.last().unwrap().start_percentage.0 != 1. {
|
if result.steps.last().unwrap().start_percentage.0 != 1. {
|
||||||
steps.push(KeyframesStep::new(KeyframePercentage::new(1.),
|
result.steps.push(KeyframesStep::new(KeyframePercentage::new(1.),
|
||||||
KeyframesStepValue::ComputedValues));
|
KeyframesStepValue::ComputedValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(KeyframesAnimation {
|
result
|
||||||
steps: steps,
|
|
||||||
properties_changed: animated_properties,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,7 @@ impl Stylist {
|
||||||
self.precomputed_pseudo_element_decls = Default::default();
|
self.precomputed_pseudo_element_decls = Default::default();
|
||||||
self.rules_source_order = 0;
|
self.rules_source_order = 0;
|
||||||
self.state_deps.clear();
|
self.state_deps.clear();
|
||||||
|
self.animations.clear();
|
||||||
|
|
||||||
self.sibling_affecting_selectors.clear();
|
self.sibling_affecting_selectors.clear();
|
||||||
self.non_common_style_affecting_attributes_selectors.clear();
|
self.non_common_style_affecting_attributes_selectors.clear();
|
||||||
|
@ -274,16 +275,9 @@ impl Stylist {
|
||||||
CssRule::Keyframes(ref keyframes_rule) => {
|
CssRule::Keyframes(ref keyframes_rule) => {
|
||||||
let keyframes_rule = keyframes_rule.read();
|
let keyframes_rule = keyframes_rule.read();
|
||||||
debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
|
debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
|
||||||
if let Some(animation) = KeyframesAnimation::from_keyframes(&keyframes_rule.keyframes) {
|
let animation = KeyframesAnimation::from_keyframes(&keyframes_rule.keyframes);
|
||||||
debug!("Found valid keyframe animation: {:?}", animation);
|
debug!("Found valid keyframe animation: {:?}", animation);
|
||||||
self.animations.insert(keyframes_rule.name.clone(),
|
self.animations.insert(keyframes_rule.name.clone(), animation);
|
||||||
animation);
|
|
||||||
} else {
|
|
||||||
// If there's a valid keyframes rule, even if it doesn't
|
|
||||||
// produce an animation, should shadow other animations
|
|
||||||
// with the same name.
|
|
||||||
self.animations.remove(&keyframes_rule.name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// We don't care about any other rule.
|
// We don't care about any other rule.
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
40
tests/unit/style/keyframes.rs
Normal file
40
tests/unit/style/keyframes.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use style::keyframes::{Keyframe, KeyframesAnimation, KeyframePercentage, KeyframeSelector};
|
||||||
|
use style::properties::PropertyDeclarationBlock;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_keyframe() {
|
||||||
|
let keyframes = vec![];
|
||||||
|
let animation = KeyframesAnimation::from_keyframes(&keyframes);
|
||||||
|
let expected = KeyframesAnimation {
|
||||||
|
steps: vec![],
|
||||||
|
properties_changed: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_property_in_keyframe() {
|
||||||
|
let keyframes = vec![
|
||||||
|
Arc::new(RwLock::new(Keyframe {
|
||||||
|
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
|
||||||
|
block: Arc::new(RwLock::new(PropertyDeclarationBlock {
|
||||||
|
declarations: vec![],
|
||||||
|
important_count: 0,
|
||||||
|
}))
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
let animation = KeyframesAnimation::from_keyframes(&keyframes);
|
||||||
|
let expected = KeyframesAnimation {
|
||||||
|
steps: vec![],
|
||||||
|
properties_changed: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ extern crate test;
|
||||||
mod animated_properties;
|
mod animated_properties;
|
||||||
mod attr;
|
mod attr;
|
||||||
mod cache;
|
mod cache;
|
||||||
|
mod keyframes;
|
||||||
mod logical_geometry;
|
mod logical_geometry;
|
||||||
mod media_queries;
|
mod media_queries;
|
||||||
mod owning_handle;
|
mod owning_handle;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue