mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
style: Support animation-composition in keyframe at rules
So we can specify the keyframe-specific composite operation. However, these is a spec issue about the default composite for CSS Animations: https://github.com/w3c/csswg-drafts/issues/7476. I choose to use auto as the default composite for missing keyframes to match the definition in web-animations-1 because I think this makes more sense: > If the keyframe-specific composite operation for a keyframe is not set, the > composite operation specified for the keyframe effect as a whole is used for > values specified in that keyframe. Differential Revision: https://phabricator.services.mozilla.com/D150808
This commit is contained in:
parent
06f81aea07
commit
e53f4ee4c7
2 changed files with 87 additions and 36 deletions
|
@ -287,7 +287,6 @@ ${helpers.single_keyword(
|
||||||
gecko_inexhaustive=True,
|
gecko_inexhaustive=True,
|
||||||
gecko_pref="layout.css.animation-composition.enabled",
|
gecko_pref="layout.css.animation-composition.enabled",
|
||||||
spec="https://drafts.csswg.org/css-animations-2/#animation-composition",
|
spec="https://drafts.csswg.org/css-animations-2/#animation-composition",
|
||||||
rule_types_allowed=DEFAULT_RULES_EXCEPT_KEYFRAME,
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use crate::error_reporting::ContextualParseError;
|
use crate::error_reporting::ContextualParseError;
|
||||||
use crate::parser::ParserContext;
|
use crate::parser::ParserContext;
|
||||||
|
use crate::properties::longhands::animation_composition::single_value::SpecifiedValue as SpecifiedComposition;
|
||||||
use crate::properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
|
use crate::properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
|
||||||
use crate::properties::LonghandIdSet;
|
use crate::properties::LonghandIdSet;
|
||||||
use crate::properties::{Importance, PropertyDeclaration};
|
use crate::properties::{Importance, PropertyDeclaration};
|
||||||
|
@ -279,40 +280,81 @@ pub struct KeyframesStep {
|
||||||
/// Declarations that will determine the final style during the step, or
|
/// Declarations that will determine the final style during the step, or
|
||||||
/// `ComputedValues` if this is an autogenerated step.
|
/// `ComputedValues` if this is an autogenerated step.
|
||||||
pub value: KeyframesStepValue,
|
pub value: KeyframesStepValue,
|
||||||
/// Wether a animation-timing-function declaration exists in the list of
|
/// Whether an animation-timing-function declaration exists in the list of
|
||||||
/// declarations.
|
/// declarations.
|
||||||
///
|
///
|
||||||
/// This is used to know when to override the keyframe animation style.
|
/// This is used to know when to override the keyframe animation style.
|
||||||
pub declared_timing_function: bool,
|
pub declared_timing_function: bool,
|
||||||
|
/// Whether an animation-composition declaration exists in the list of
|
||||||
|
/// declarations.
|
||||||
|
///
|
||||||
|
/// This is used to know when to override the keyframe animation style.
|
||||||
|
pub declared_composition: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyframesStep {
|
impl KeyframesStep {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(
|
fn new(
|
||||||
percentage: KeyframePercentage,
|
start_percentage: KeyframePercentage,
|
||||||
value: KeyframesStepValue,
|
value: KeyframesStepValue,
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let declared_timing_function = match value {
|
let mut declared_timing_function = false;
|
||||||
KeyframesStepValue::Declarations { ref block } => block
|
let mut declared_composition = false;
|
||||||
.read_with(guard)
|
if let KeyframesStepValue::Declarations { ref block } = value {
|
||||||
.declarations()
|
for prop_decl in block.read_with(guard).declarations().iter() {
|
||||||
.iter()
|
match *prop_decl {
|
||||||
.any(|prop_decl| match *prop_decl {
|
PropertyDeclaration::AnimationTimingFunction(..) => {
|
||||||
PropertyDeclaration::AnimationTimingFunction(..) => true,
|
declared_timing_function = true;
|
||||||
_ => false,
|
},
|
||||||
}),
|
PropertyDeclaration::AnimationComposition(..) => {
|
||||||
_ => false,
|
declared_composition = true;
|
||||||
};
|
},
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
// Don't need to continue the loop if both are found.
|
||||||
|
if declared_timing_function && declared_composition {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KeyframesStep {
|
KeyframesStep {
|
||||||
start_percentage: percentage,
|
start_percentage,
|
||||||
value: value,
|
value,
|
||||||
declared_timing_function: declared_timing_function,
|
declared_timing_function,
|
||||||
|
declared_composition,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
|
/// Return specified PropertyDeclaration.
|
||||||
|
#[inline]
|
||||||
|
fn get_declared_property<'a>(
|
||||||
|
&'a self,
|
||||||
|
guard: &'a SharedRwLockReadGuard,
|
||||||
|
property: LonghandId,
|
||||||
|
) -> Option<&'a PropertyDeclaration> {
|
||||||
|
match self.value {
|
||||||
|
KeyframesStepValue::Declarations { ref block } => {
|
||||||
|
let guard = block.read_with(guard);
|
||||||
|
let (declaration, _) = guard
|
||||||
|
.get(PropertyDeclarationId::Longhand(property))
|
||||||
|
.unwrap();
|
||||||
|
match *declaration {
|
||||||
|
PropertyDeclaration::CSSWideKeyword(..) => None,
|
||||||
|
// FIXME: Bug 1710735: Support css variable in @keyframes rule.
|
||||||
|
PropertyDeclaration::WithVariables(..) => None,
|
||||||
|
_ => Some(declaration),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
KeyframesStepValue::ComputedValues => {
|
||||||
|
panic!("Shouldn't happen to set this property in missing keyframes")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return specified TransitionTimingFunction if this KeyframesSteps has
|
||||||
|
/// 'animation-timing-function'.
|
||||||
pub fn get_animation_timing_function(
|
pub fn get_animation_timing_function(
|
||||||
&self,
|
&self,
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
|
@ -320,28 +362,38 @@ impl KeyframesStep {
|
||||||
if !self.declared_timing_function {
|
if !self.declared_timing_function {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match self.value {
|
|
||||||
KeyframesStepValue::Declarations { ref block } => {
|
self.get_declared_property(guard, LonghandId::AnimationTimingFunction)
|
||||||
let guard = block.read_with(guard);
|
.map(|decl| {
|
||||||
let (declaration, _) = guard
|
match *decl {
|
||||||
.get(PropertyDeclarationId::Longhand(
|
|
||||||
LonghandId::AnimationTimingFunction,
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
match *declaration {
|
|
||||||
PropertyDeclaration::AnimationTimingFunction(ref value) => {
|
PropertyDeclaration::AnimationTimingFunction(ref value) => {
|
||||||
// Use the first value.
|
// Use the first value
|
||||||
Some(value.0[0].clone())
|
value.0[0].clone()
|
||||||
},
|
},
|
||||||
PropertyDeclaration::CSSWideKeyword(..) => None,
|
_ => unreachable!("Unexpected PropertyDeclaration"),
|
||||||
PropertyDeclaration::WithVariables(..) => None,
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
KeyframesStepValue::ComputedValues => {
|
|
||||||
panic!("Shouldn't happen to set animation-timing-function in missing keyframes")
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return CompositeOperation if this KeyframesSteps has 'animation-composition'.
|
||||||
|
pub fn get_animation_composition(
|
||||||
|
&self,
|
||||||
|
guard: &SharedRwLockReadGuard,
|
||||||
|
) -> Option<SpecifiedComposition> {
|
||||||
|
if !self.declared_composition {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.get_declared_property(guard, LonghandId::AnimationComposition)
|
||||||
|
.map(|decl| {
|
||||||
|
match *decl {
|
||||||
|
PropertyDeclaration::AnimationComposition(ref value) => {
|
||||||
|
// Use the first value
|
||||||
|
value.0[0].clone()
|
||||||
|
},
|
||||||
|
_ => unreachable!("Unexpected PropertyDeclaration"),
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue