diff --git a/components/style/properties/longhands/ui.mako.rs b/components/style/properties/longhands/ui.mako.rs index af9d21e982b..b347be13284 100644 --- a/components/style/properties/longhands/ui.mako.rs +++ b/components/style/properties/longhands/ui.mako.rs @@ -287,7 +287,6 @@ ${helpers.single_keyword( gecko_inexhaustive=True, gecko_pref="layout.css.animation-composition.enabled", spec="https://drafts.csswg.org/css-animations-2/#animation-composition", - rule_types_allowed=DEFAULT_RULES_EXCEPT_KEYFRAME, )} ${helpers.predefined_type( diff --git a/components/style/stylesheets/keyframes_rule.rs b/components/style/stylesheets/keyframes_rule.rs index 9f3ec6295d7..dd04dbf01a3 100644 --- a/components/style/stylesheets/keyframes_rule.rs +++ b/components/style/stylesheets/keyframes_rule.rs @@ -6,6 +6,7 @@ use crate::error_reporting::ContextualParseError; 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::LonghandIdSet; use crate::properties::{Importance, PropertyDeclaration}; @@ -279,40 +280,81 @@ pub struct KeyframesStep { /// Declarations that will determine the final style during the step, or /// `ComputedValues` if this is an autogenerated step. 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. /// /// This is used to know when to override the keyframe animation style. 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 { #[inline] fn new( - percentage: KeyframePercentage, + start_percentage: KeyframePercentage, value: KeyframesStepValue, guard: &SharedRwLockReadGuard, ) -> Self { - let declared_timing_function = match value { - KeyframesStepValue::Declarations { ref block } => block - .read_with(guard) - .declarations() - .iter() - .any(|prop_decl| match *prop_decl { - PropertyDeclaration::AnimationTimingFunction(..) => true, - _ => false, - }), - _ => false, - }; + let mut declared_timing_function = false; + let mut declared_composition = false; + if let KeyframesStepValue::Declarations { ref block } = value { + for prop_decl in block.read_with(guard).declarations().iter() { + match *prop_decl { + PropertyDeclaration::AnimationTimingFunction(..) => { + declared_timing_function = true; + }, + PropertyDeclaration::AnimationComposition(..) => { + declared_composition = true; + }, + _ => continue, + } + // Don't need to continue the loop if both are found. + if declared_timing_function && declared_composition { + break; + } + } + } KeyframesStep { - start_percentage: percentage, - value: value, - declared_timing_function: declared_timing_function, + start_percentage, + value, + 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( &self, guard: &SharedRwLockReadGuard, @@ -320,28 +362,38 @@ impl KeyframesStep { if !self.declared_timing_function { return None; } - match self.value { - KeyframesStepValue::Declarations { ref block } => { - let guard = block.read_with(guard); - let (declaration, _) = guard - .get(PropertyDeclarationId::Longhand( - LonghandId::AnimationTimingFunction, - )) - .unwrap(); - match *declaration { + + self.get_declared_property(guard, LonghandId::AnimationTimingFunction) + .map(|decl| { + match *decl { PropertyDeclaration::AnimationTimingFunction(ref value) => { - // Use the first value. - Some(value.0[0].clone()) + // Use the first value + value.0[0].clone() }, - PropertyDeclaration::CSSWideKeyword(..) => None, - PropertyDeclaration::WithVariables(..) => None, - _ => panic!(), + _ => unreachable!("Unexpected PropertyDeclaration"), } - }, - 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 { + 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"), + } + }) } }