Bug 1328787 - Part 8: Animation timing function can be overridden by animation-timing-function specified in keyframe. r?heycam draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Fri, 27 Jan 2017 09:55:41 +0900
changeset 467023 a7a2cecafca3ffec7dfa8ea595d867c0862d49cd
parent 467022 9585b49ee1d9515c88340d2a3387369eac013114
child 467024 250c2b40e250e9321f4e792425c3bfcb9d8fe398
push id43089
push userhikezoe@mozilla.com
push dateFri, 27 Jan 2017 01:33:18 +0000
reviewersheycam
bugs1328787
milestone54.0a1
Bug 1328787 - Part 8: Animation timing function can be overridden by animation-timing-function specified in keyframe. r?heycam MozReview-Commit-ID: HcoNx1XJ0EH
servo/components/style/keyframes.rs
servo/components/style/properties/longhand/box.mako.rs
servo/ports/geckolib/glue.rs
--- a/servo/components/style/keyframes.rs
+++ b/servo/components/style/keyframes.rs
@@ -6,18 +6,20 @@
 
 #![deny(missing_docs)]
 
 use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
 use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
 use parking_lot::RwLock;
 use parser::{ParserContext, ParserContextExtraData, log_css_error};
 use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
+use properties::{PropertyDeclarationId, LonghandId, DeclaredValue};
 use properties::PropertyDeclarationParseResult;
 use properties::animated_properties::TransitionProperty;
+use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
 use std::fmt;
 use std::sync::Arc;
 use style_traits::ToCss;
 use stylesheets::{MemoryHoleReporter, Stylesheet};
 
 /// A number from 0 to 1, indicating the percentage of the animation when this
 /// keyframe should run.
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
@@ -193,16 +195,45 @@ impl KeyframesStep {
         };
 
         KeyframesStep {
             start_percentage: percentage,
             value: value,
             declared_timing_function: declared_timing_function,
         }
     }
+
+    /// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
+    pub fn get_animation_timing_function(&self) -> Option<SpecifiedTimingFunction> {
+        if !self.declared_timing_function {
+            return None;
+        }
+        match self.value {
+            KeyframesStepValue::Declarations { ref block } => {
+                let guard = block.read();
+                let &(ref declaration, _) =
+                    guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap();
+                match *declaration {
+                    PropertyDeclaration::AnimationTimingFunction(ref value) => {
+                        match *value {
+                            DeclaredValue::Value(ref value) => {
+                                // Use the first value.
+                                Some(value.0[0])
+                            },
+                            _ => None,
+                        }
+                    },
+                    _ => panic!(),
+                }
+            },
+            KeyframesStepValue::ComputedValues => {
+                panic!("Shouldn't happen to set animation-timing-function in missing keyframes")
+            },
+        }
+    }
 }
 
 /// 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)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -825,17 +825,17 @@
     pub use properties::longhands::transition_duration::single_value::SpecifiedValue;
 </%helpers:vector_longhand>
 
 <%helpers:vector_longhand name="animation-timing-function"
                           need_index="True"
                           animatable="False",
                           extra_prefixes="moz webkit"
                           spec="https://drafts.csswg.org/css-animations/#propdef-animation-timing-function",
-                          allowed_in_keyframe_block="False">
+                          allowed_in_keyframe_block="True">
     pub use properties::longhands::transition_timing_function::single_value::computed_value;
     pub use properties::longhands::transition_timing_function::single_value::get_initial_value;
     pub use properties::longhands::transition_timing_function::single_value::get_initial_specified_value;
     pub use properties::longhands::transition_timing_function::single_value::parse;
     pub use properties::longhands::transition_timing_function::single_value::SpecifiedValue;
 </%helpers:vector_longhand>
 
 <%helpers:vector_longhand name="animation-iteration-count"
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1149,17 +1149,22 @@ pub extern "C" fn Servo_StyleSet_FillKey
                                                       _style: ServoComputedValuesBorrowed,
                                                       keyframes: RawGeckoKeyframeListBorrowedMut) -> bool {
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) };
     let style_timing_function = unsafe { timing_function.as_ref().unwrap() };
 
     if let Some(ref animation) = data.stylist.animations().get(&name) {
        for step in &animation.steps {
-          let timing_function = *style_timing_function;
+          // Override timing_function if the keyframe has animation-timing-function.
+          let timing_function = if let Some(val) = step.get_animation_timing_function() {
+              val.into()
+          } else {
+              *style_timing_function
+          };
 
           let _keyframe = unsafe {
                 Gecko_AnimationAppendKeyframe(keyframes,
                                               step.start_percentage.0 as f32,
                                               &timing_function)
           };
           // Set each PropertyValuePair.
        }