/* 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 cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser}; use cssparser::{DeclarationListParser, DeclarationParser}; use parser::{ParserContext, log_css_error}; use properties::PropertyDeclarationParseResult; use properties::animated_properties::TransitionProperty; use properties::{PropertyDeclaration, PropertyDeclarationBlock, Importance}; use std::sync::Arc; /// A number from 1 to 100, indicating the percentage of the animation where /// this keyframe should run. #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct KeyframePercentage(pub f32); impl ::std::cmp::Ord for KeyframePercentage { #[inline] fn cmp(&self, other: &Self) -> ::std::cmp::Ordering { // We know we have a number from 0 to 1, so unwrap() here is safe. self.0.partial_cmp(&other.0).unwrap() } } impl ::std::cmp::Eq for KeyframePercentage { } impl KeyframePercentage { #[inline] pub fn new(value: f32) -> KeyframePercentage { debug_assert!(value >= 0. && value <= 1.); KeyframePercentage(value) } fn parse(input: &mut Parser) -> Result { let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() { KeyframePercentage::new(0.) } else if input.try(|input| input.expect_ident_matching("to")).is_ok() { KeyframePercentage::new(1.) } else { let percentage = try!(input.expect_percentage()); if percentage > 1. || percentage < 0. { return Err(()); } KeyframePercentage::new(percentage) }; Ok(percentage) } } /// A keyframes selector is a list of percentages or from/to symbols, which are /// converted at parse time to percentages. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct KeyframeSelector(Vec); impl KeyframeSelector { #[inline] pub fn percentages(&self) -> &[KeyframePercentage] { &self.0 } /// A dummy public function so we can write a unit test for this. pub fn new_for_unit_testing(percentages: Vec) -> KeyframeSelector { KeyframeSelector(percentages) } } /// A keyframe. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct Keyframe { pub selector: KeyframeSelector, /// `!important` is not allowed in keyframe declarations, /// so the second value of these tuples is always `Importance::Normal`. /// But including them enables `compute_style_for_animation_step` to create a `ApplicableDeclarationBlock` /// by cloning an `Arc<_>` (incrementing a reference count) rather than re-creating a `Vec<_>`. pub block: Arc, } /// A keyframes step value. This can be a synthetised keyframes animation, that /// is, one autogenerated from the current computed values, or a list of /// declarations to apply. // TODO: Find a better name for this? #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum KeyframesStepValue { /// See `Keyframe::declarations`’s docs about the presence of `Importance`. Declarations(Arc), ComputedValues, } /// A single step from a keyframe animation. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct KeyframesStep { /// The percentage of the animation duration when this step starts. pub start_percentage: KeyframePercentage, /// 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 /// declarations. /// /// This is used to know when to override the keyframe animation style. pub declared_timing_function: bool, } impl KeyframesStep { #[inline] fn new(percentage: KeyframePercentage, value: KeyframesStepValue) -> Self { let declared_timing_function = match value { KeyframesStepValue::Declarations(ref block) => { block.declarations.iter().any(|&(ref prop_decl, _)| { match *prop_decl { PropertyDeclaration::AnimationTimingFunction(..) => true, _ => false, } }) } _ => false, }; KeyframesStep { start_percentage: percentage, value: value, declared_timing_function: declared_timing_function, } } } /// This structure represents a list of animation steps computed from the list /// of keyframes, in order. /// /// It only takes into account animable properties. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct KeyframesAnimation { pub steps: Vec, /// The properties that change in this animation. pub properties_changed: Vec, } /// Get all the animated properties in a keyframes animation. Note that it's not /// defined what happens when a property is not on a keyframe, so we only peek /// the props of the first one. /// /// In practice, browsers seem to try to do their best job at it, so we might /// want to go through all the actual keyframes and deduplicate properties. fn get_animated_properties(keyframe: &Keyframe) -> Vec { let mut ret = vec![]; // NB: declarations are already deduplicated, so we don't have to check for // it here. for &(ref declaration, _) in keyframe.block.declarations.iter() { if let Some(property) = TransitionProperty::from_declaration(declaration) { ret.push(property); } } ret } impl KeyframesAnimation { pub fn from_keyframes(keyframes: &[Arc]) -> Option { if keyframes.is_empty() { return None; } let animated_properties = get_animated_properties(&keyframes[0]); if animated_properties.is_empty() { return None; } let mut steps = vec![]; for keyframe in keyframes { for percentage in keyframe.selector.0.iter() { steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations(keyframe.block.clone()))); } } // Sort by the start percentage, so we can easily find a frame. steps.sort_by_key(|step| step.start_percentage); // Prepend autogenerated keyframes if appropriate. if steps[0].start_percentage.0 != 0. { steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.), KeyframesStepValue::ComputedValues)); } if steps.last().unwrap().start_percentage.0 != 1. { steps.push(KeyframesStep::new(KeyframePercentage::new(0.), KeyframesStepValue::ComputedValues)); } Some(KeyframesAnimation { steps: steps, properties_changed: animated_properties, }) } } /// Parses a keyframes list, like: /// 0%, 50% { /// width: 50%; /// } /// /// 40%, 60%, 100% { /// width: 100%; /// } struct KeyframeListParser<'a> { context: &'a ParserContext<'a>, } pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec> { RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context }) .filter_map(Result::ok) .collect() } enum Void {} impl<'a> AtRuleParser for KeyframeListParser<'a> { type Prelude = Void; type AtRule = Arc; } impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { type Prelude = KeyframeSelector; type QualifiedRule = Arc; fn parse_prelude(&self, input: &mut Parser) -> Result { let start = input.position(); match input.parse_comma_separated(|input| KeyframePercentage::parse(input)) { Ok(percentages) => Ok(KeyframeSelector(percentages)), Err(()) => { let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start)); log_css_error(input, start, &message, self.context); Err(()) } } } fn parse_block(&self, prelude: Self::Prelude, input: &mut Parser) -> Result { let mut declarations = Vec::new(); let parser = KeyframeDeclarationParser { context: self.context, }; let mut iter = DeclarationListParser::new(input, parser); while let Some(declaration) = iter.next() { match declaration { Ok(d) => declarations.extend(d.into_iter().map(|d| (d, Importance::Normal))), Err(range) => { let pos = range.start; let message = format!("Unsupported keyframe property declaration: '{}'", iter.input.slice(range)); log_css_error(iter.input, pos, &*message, self.context); } } // `parse_important` is not called here, `!important` is not allowed in keyframe blocks. } Ok(Arc::new(Keyframe { selector: prelude, block: Arc::new(PropertyDeclarationBlock { declarations: declarations, important_count: 0, }), })) } } struct KeyframeDeclarationParser<'a, 'b: 'a> { context: &'a ParserContext<'b>, } /// Default methods reject all at rules. impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> { type Prelude = (); type AtRule = Vec; } impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> { type Declaration = Vec; fn parse_value(&self, name: &str, input: &mut Parser) -> Result, ()> { let mut results = Vec::new(); match PropertyDeclaration::parse(name, self.context, input, &mut results, true) { PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {} _ => return Err(()) } Ok(results) } }