servo: Merge #15814 - Revert #15793 for crashes and test failures on stylo (from bholley:backout_15793); r=bholley
authorBobby Holley <bobbyholley@gmail.com>
Fri, 03 Mar 2017 11:53:52 -0800
changeset 394879 218ab57e5242a008b8adc447305d1cd89a9baec8
parent 394878 e393e6c239cd79fbef63a72ff9e15f1a989c80ae
child 394880 130e62d8966352e4883af609347316e5d57d704a
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #15814 - Revert #15793 for crashes and test failures on stylo (from bholley:backout_15793); r=bholley Looks like #15793 busted autoland. Given that it's the weekend for Xidorn I'm going to back out the patch. CC @upsuper Source-Repo: https://github.com/servo/servo Source-Revision: 3ca6ee2f7fc7cb5eda2930a66f854be05c4e5567
servo/components/style/matching.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/box.mako.rs
servo/components/style/properties/shorthand/box.mako.rs
servo/tests/unit/style/lib.rs
servo/tests/unit/style/parsing/animation.rs
servo/tests/unit/style/properties/serialization.rs
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -393,19 +393,17 @@ impl<E: TElement> StyleSharingCandidateC
         }
 
         let box_style = style.get_box();
         if box_style.transition_property_count() > 0 {
             debug!("Failing to insert to the cache: transitions");
             return;
         }
 
-        let animation_count = box_style.animation_name_count();
-        debug_assert!(animation_count > 0);
-        if animation_count > 1 || box_style.animation_name_at(0).0 != atom!("") {
+        if box_style.animation_name_count() > 0 {
             debug!("Failing to insert to the cache: animations");
             return;
         }
 
         debug!("Inserting into cache: {:?} with parent {:?}",
                element, parent);
 
         self.cache.insert(StyleSharingCandidate {
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1319,17 +1319,17 @@ fn static_assert() {
     pub fn animation_${ident}_count(&self) -> usize {
         self.gecko.mAnimation${gecko_ffi_name}Count as usize
     }
 </%def>
 
 <%def name="impl_animation_time_value(ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn set_animation_${ident}(&mut self, v: longhands::animation_${ident}::computed_value::T) {
-        debug_assert!(!v.0.is_empty());
+        assert!(v.0.len() > 0);
         unsafe { self.gecko.mAnimations.ensure_len(v.0.len()) };
 
         self.gecko.mAnimation${gecko_ffi_name}Count = v.0.len() as u32;
         for (servo, gecko) in v.0.into_iter().zip(self.gecko.mAnimations.iter_mut()) {
             gecko.m${gecko_ffi_name} = servo.seconds() * 1000.;
         }
     }
     #[allow(non_snake_case)]
@@ -1343,17 +1343,17 @@ fn static_assert() {
 </%def>
 
 <%def name="impl_animation_keyword(ident, gecko_ffi_name, keyword, cast_type='u8')">
     #[allow(non_snake_case)]
     pub fn set_animation_${ident}(&mut self, v: longhands::animation_${ident}::computed_value::T) {
         use properties::longhands::animation_${ident}::single_value::computed_value::T as Keyword;
         use gecko_bindings::structs;
 
-        debug_assert!(!v.0.is_empty());
+        assert!(v.0.len() > 0);
         unsafe { self.gecko.mAnimations.ensure_len(v.0.len()) };
 
         self.gecko.mAnimation${gecko_ffi_name}Count = v.0.len() as u32;
 
         for (servo, gecko) in v.0.into_iter().zip(self.gecko.mAnimations.iter_mut()) {
             let result = match servo {
                 % for value in keyword.gecko_values():
                     Keyword::${to_rust_ident(value)} =>
@@ -1722,24 +1722,25 @@ fn static_assert() {
             result.push(servo);
             unsafe { cur = (&*cur).mNext };
         }
         computed_value::T(Some(result))
     }
 
     pub fn set_animation_name(&mut self, v: longhands::animation_name::computed_value::T) {
         use nsstring::nsCString;
-
-        debug_assert!(!v.0.is_empty());
         unsafe { self.gecko.mAnimations.ensure_len(v.0.len()) };
 
-        self.gecko.mAnimationNameCount = v.0.len() as u32;
-        for (servo, gecko) in v.0.into_iter().zip(self.gecko.mAnimations.iter_mut()) {
-            // TODO This is inefficient. We should fix this in bug 1329169.
-            gecko.mName.assign_utf8(&nsCString::from(servo.0.to_string()));
+        if v.0.len() > 0 {
+            self.gecko.mAnimationNameCount = v.0.len() as u32;
+            for (servo, gecko) in v.0.into_iter().zip(self.gecko.mAnimations.iter_mut()) {
+                gecko.mName.assign_utf8(&nsCString::from(servo.0.to_string()));
+            }
+        } else {
+            unsafe { self.gecko.mAnimations[0].mName.truncate(); }
         }
     }
     pub fn animation_name_at(&self, index: usize)
         -> longhands::animation_name::computed_value::SingleComputedValue {
         use Atom;
         use properties::longhands::animation_name::single_value::SpecifiedValue as AnimationName;
         // XXX: Is there any effective ways?
         AnimationName(Atom::from(String::from_utf16_lossy(&self.gecko.mAnimations[index].mName[..])))
@@ -1767,17 +1768,17 @@ fn static_assert() {
                              data.longhands_by_name["animation-fill-mode"].keyword)}
     ${impl_animation_keyword('play_state', 'PlayState',
                              data.longhands_by_name["animation-play-state"].keyword)}
 
     pub fn set_animation_iteration_count(&mut self, v: longhands::animation_iteration_count::computed_value::T) {
         use std::f32;
         use properties::longhands::animation_iteration_count::single_value::SpecifiedValue as AnimationIterationCount;
 
-        debug_assert!(!v.0.is_empty());
+        assert!(v.0.len() > 0);
         unsafe { self.gecko.mAnimations.ensure_len(v.0.len()) };
 
         self.gecko.mAnimationIterationCountCount = v.0.len() as u32;
         for (servo, gecko) in v.0.into_iter().zip(self.gecko.mAnimations.iter_mut()) {
             match servo {
                 AnimationIterationCount::Number(n) => gecko.mIterationCount = n,
                 AnimationIterationCount::Infinite => gecko.mIterationCount = f32::INFINITY,
             }
@@ -1793,17 +1794,17 @@ fn static_assert() {
         } else {
             AnimationIterationCount::Number(self.gecko.mAnimations[index].mIterationCount)
         }
     }
     ${impl_animation_count('iteration_count', 'IterationCount')}
     ${impl_copy_animation_value('iteration_count', 'IterationCount')}
 
     pub fn set_animation_timing_function(&mut self, v: longhands::animation_timing_function::computed_value::T) {
-        debug_assert!(!v.0.is_empty());
+        assert!(v.0.len() > 0);
         unsafe { self.gecko.mAnimations.ensure_len(v.0.len()) };
 
         self.gecko.mAnimationTimingFunctionCount = v.0.len() as u32;
         for (servo, gecko) in v.0.into_iter().zip(self.gecko.mAnimations.iter_mut()) {
             gecko.mTimingFunction = servo.into();
         }
     }
     ${impl_animation_count('timing_function', 'TimingFunction')}
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -455,21 +455,16 @@
         pub use values::computed::Time as T;
     }
 
     #[inline]
     pub fn get_initial_value() -> Time {
         Time(0.0)
     }
 
-    #[inline]
-    pub fn get_initial_specified_value() -> SpecifiedValue {
-        SpecifiedValue(0.0)
-    }
-
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         Time::parse(context, input)
     }
 </%helpers:vector_longhand>
 
 // TODO(pcwalton): Lots more timing functions.
 <%helpers:vector_longhand name="transition-timing-function"
                           need_index="True"
@@ -727,17 +722,17 @@
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         ease()
     }
 
     #[inline]
     pub fn get_initial_specified_value() -> SpecifiedValue {
-        SpecifiedValue::Keyword(FunctionKeyword::Ease)
+        ToComputedValue::from_computed_value(&ease())
     }
 
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         SpecifiedValue::parse(context, input)
     }
 </%helpers:vector_longhand>
 
 <%helpers:vector_longhand name="transition-property"
@@ -776,16 +771,17 @@
                           extra_prefixes="moz webkit"
                           spec="https://drafts.csswg.org/css-transitions/#propdef-transition-delay">
     pub use properties::longhands::transition_duration::single_value::SpecifiedValue;
     pub use properties::longhands::transition_duration::single_value::computed_value;
     pub use properties::longhands::transition_duration::single_value::{get_initial_value, parse};
 </%helpers:vector_longhand>
 
 <%helpers:vector_longhand name="animation-name"
+                          allow_empty="True"
                           need_index="True"
                           animatable="False",
                           extra_prefixes="moz webkit"
                           allowed_in_keyframe_block="False"
                           spec="https://drafts.csswg.org/css-animations/#propdef-animation-name">
     use Atom;
     use std::fmt;
     use std::ops::Deref;
@@ -796,51 +792,33 @@
     pub mod computed_value {
         pub use super::SpecifiedValue as T;
     }
 
     #[derive(Clone, Debug, Hash, Eq, PartialEq)]
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     pub struct SpecifiedValue(pub Atom);
 
-    #[inline]
-    pub fn get_initial_value() -> computed_value::T {
-        get_initial_specified_value()
-    }
-
-    #[inline]
-    pub fn get_initial_specified_value() -> SpecifiedValue {
-        SpecifiedValue(atom!(""))
-    }
-
     impl fmt::Display for SpecifiedValue {
         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             self.0.fmt(f)
         }
     }
 
     impl ToCss for SpecifiedValue {
         fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-            if self.0 == atom!("") {
-                dest.write_str("none")
-            } else {
-                dest.write_str(&*self.0.to_string())
-            }
+            dest.write_str(&*self.0.to_string())
         }
     }
 
     impl Parse for SpecifiedValue {
         fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<Self, ()> {
             use cssparser::Token;
             Ok(match input.next() {
-                Ok(Token::Ident(ref value)) => SpecifiedValue(if value == "none" {
-                    atom!("")
-                } else {
-                    Atom::from(&**value)
-                }),
+                Ok(Token::Ident(ref value)) if value != "none" => SpecifiedValue(Atom::from(&**value)),
                 Ok(Token::QuotedString(value)) => SpecifiedValue(Atom::from(&*value)),
                 _ => return Err(()),
             })
         }
     }
     no_viewport_percentage!(SpecifiedValue);
 
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
@@ -852,17 +830,16 @@
 
 <%helpers:vector_longhand name="animation-duration"
                           need_index="True"
                           animatable="False",
                           extra_prefixes="moz webkit"
                           spec="https://drafts.csswg.org/css-animations/#propdef-animation-duration",
                           allowed_in_keyframe_block="False">
     pub use properties::longhands::transition_duration::single_value::computed_value;
-    pub use properties::longhands::transition_duration::single_value::get_initial_specified_value;
     pub use properties::longhands::transition_duration::single_value::{get_initial_value, parse};
     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"
@@ -921,22 +898,17 @@
             }
         }
     }
 
     no_viewport_percentage!(SpecifiedValue);
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
-        get_initial_specified_value()
-    }
-
-    #[inline]
-    pub fn get_initial_specified_value() -> SpecifiedValue {
-        SpecifiedValue::Number(1.0)
+        computed_value::T::Number(1.0)
     }
 
     #[inline]
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         SpecifiedValue::parse(context, input)
     }
 
     impl ComputedValueAsSpecified for SpecifiedValue {}
@@ -978,17 +950,16 @@
 
 <%helpers:vector_longhand name="animation-delay"
                           need_index="True"
                           animatable="False",
                           extra_prefixes="moz webkit",
                           spec="https://drafts.csswg.org/css-animations/#propdef-animation-delay",
                           allowed_in_keyframe_block="False">
     pub use properties::longhands::transition_duration::single_value::computed_value;
-    pub use properties::longhands::transition_duration::single_value::get_initial_specified_value;
     pub use properties::longhands::transition_duration::single_value::{get_initial_value, parse};
     pub use properties::longhands::transition_duration::single_value::SpecifiedValue;
 </%helpers:vector_longhand>
 
 <%helpers:longhand products="gecko" name="scroll-snap-points-y" animatable="False"
                    spec="Nonstandard (https://www.w3.org/TR/2015/WD-css-snappoints-1-20150326/#scroll-snap-points)">
     use std::fmt;
     use style_traits::ToCss;
--- a/servo/components/style/properties/shorthand/box.mako.rs
+++ b/servo/components/style/properties/shorthand/box.mako.rs
@@ -148,36 +148,42 @@ macro_rules! try_parse_one {
 
 <%helpers:shorthand name="animation" extra_prefixes="moz webkit"
                     sub_properties="animation-name animation-duration
                                     animation-timing-function animation-delay
                                     animation-iteration-count animation-direction
                                     animation-fill-mode animation-play-state"
                     allowed_in_keyframe_block="False"
                     spec="https://drafts.csswg.org/css-animations/#propdef-animation">
-    <%
-        props = "name duration timing_function delay iteration_count \
-                 direction fill_mode play_state".split()
-    %>
     use parser::Parse;
-    % for prop in props:
-    use properties::longhands::animation_${prop};
-    % endfor
+    use properties::longhands::{animation_name, animation_duration, animation_timing_function};
+    use properties::longhands::{animation_delay, animation_iteration_count, animation_direction};
+    use properties::longhands::{animation_fill_mode, animation_play_state};
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         struct SingleAnimation {
-            % for prop in props:
-            animation_${prop}: animation_${prop}::SingleSpecifiedValue,
-            % endfor
+            animation_name: animation_name::SingleSpecifiedValue,
+            animation_duration: animation_duration::SingleSpecifiedValue,
+            animation_timing_function: animation_timing_function::SingleSpecifiedValue,
+            animation_delay: animation_delay::SingleSpecifiedValue,
+            animation_iteration_count: animation_iteration_count::SingleSpecifiedValue,
+            animation_direction: animation_direction::SingleSpecifiedValue,
+            animation_fill_mode: animation_fill_mode::SingleSpecifiedValue,
+            animation_play_state: animation_play_state::SingleSpecifiedValue,
         }
 
         fn parse_one_animation(context: &ParserContext, input: &mut Parser) -> Result<SingleAnimation,()> {
-            % for prop in props:
-            let mut ${prop} = None;
-            % endfor
+            let mut duration = None;
+            let mut timing_function = None;
+            let mut delay = None;
+            let mut iteration_count = None;
+            let mut direction = None;
+            let mut fill_mode = None;
+            let mut play_state = None;
+            let mut name = None;
 
             // NB: Name must be the last one here so that keywords valid for other
             // longhands are not interpreted as names.
             //
             // Also, duration must be before delay, see
             // https://drafts.csswg.org/css-animations/#typedef-single-animation
             loop {
                 try_parse_one!(context, input, duration, animation_duration);
@@ -187,64 +193,102 @@ macro_rules! try_parse_one {
                 try_parse_one!(input, direction, animation_direction);
                 try_parse_one!(input, fill_mode, animation_fill_mode);
                 try_parse_one!(input, play_state, animation_play_state);
                 try_parse_one!(context, input, name, animation_name);
 
                 break
             }
 
-            Ok(SingleAnimation {
-                % for prop in props:
-                animation_${prop}: ${prop}.unwrap_or_else(animation_${prop}::single_value
-                                                          ::get_initial_specified_value),
-                % endfor
-            })
+            if let Some(name) = name {
+                Ok(SingleAnimation {
+                    animation_name: name,
+                    animation_duration:
+                        duration.unwrap_or_else(animation_duration::single_value::get_initial_value),
+                    animation_timing_function:
+                        timing_function.unwrap_or_else(animation_timing_function::single_value
+                                                                                ::get_initial_specified_value),
+                    animation_delay:
+                        delay.unwrap_or_else(animation_delay::single_value::get_initial_value),
+                    animation_iteration_count:
+                        iteration_count.unwrap_or_else(animation_iteration_count::single_value::get_initial_value),
+                    animation_direction:
+                        direction.unwrap_or_else(animation_direction::single_value::get_initial_value),
+                    animation_fill_mode:
+                        fill_mode.unwrap_or_else(animation_fill_mode::single_value::get_initial_value),
+                    animation_play_state:
+                        play_state.unwrap_or_else(animation_play_state::single_value::get_initial_value),
+                })
+            } else {
+                Err(())
+            }
         }
 
-        % for prop in props:
-        let mut ${prop}s = vec![];
-        % endfor
+        let mut names = vec![];
+        let mut durations = vec![];
+        let mut timing_functions = vec![];
+        let mut delays = vec![];
+        let mut iteration_counts = vec![];
+        let mut directions = vec![];
+        let mut fill_modes = vec![];
+        let mut play_states = vec![];
 
-        let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));
-        for result in results.into_iter() {
-            % for prop in props:
-            ${prop}s.push(result.animation_${prop});
-            % endfor
+        if input.try(|input| input.expect_ident_matching("none")).is_err() {
+            let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));
+            for result in results.into_iter() {
+                names.push(result.animation_name);
+                durations.push(result.animation_duration);
+                timing_functions.push(result.animation_timing_function);
+                delays.push(result.animation_delay);
+                iteration_counts.push(result.animation_iteration_count);
+                directions.push(result.animation_direction);
+                fill_modes.push(result.animation_fill_mode);
+                play_states.push(result.animation_play_state);
+            }
         }
 
         Ok(Longhands {
-            % for prop in props:
-            animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s),
-            % endfor
+            animation_name: animation_name::SpecifiedValue(names),
+            animation_duration: animation_duration::SpecifiedValue(durations),
+            animation_timing_function: animation_timing_function::SpecifiedValue(timing_functions),
+            animation_delay: animation_delay::SpecifiedValue(delays),
+            animation_iteration_count: animation_iteration_count::SpecifiedValue(iteration_counts),
+            animation_direction: animation_direction::SpecifiedValue(directions),
+            animation_fill_mode: animation_fill_mode::SpecifiedValue(fill_modes),
+            animation_play_state: animation_play_state::SpecifiedValue(play_states),
         })
     }
 
     impl<'a> ToCss for LonghandsToSerialize<'a>  {
         fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             let len = self.animation_name.0.len();
             // There should be at least one declared value
             if len == 0 {
                 return Ok(());
             }
 
+            <%
+                subproperties = "duration timing_function delay direction \
+                                 fill_mode iteration_count play_state".split()
+            %>
+
             // If any value list length is differs then we don't do a shorthand serialization
             // either.
-            % for name in props[1:]:
+            % for name in subproperties:
                 if len != self.animation_${name}.0.len() {
                     return Ok(())
                 }
             % endfor
 
             for i in 0..len {
                 if i != 0 {
                     try!(write!(dest, ", "));
                 }
 
-                % for name in props[1:]:
+                % for name in subproperties:
                     self.animation_${name}.0[i].to_css(dest)?;
                     dest.write_str(" ")?;
                 % endfor
                 self.animation_name.0[i].to_css(dest)?;
             }
             Ok(())
         }
     }
--- a/servo/tests/unit/style/lib.rs
+++ b/servo/tests/unit/style/lib.rs
@@ -9,17 +9,17 @@ extern crate app_units;
 extern crate cssparser;
 extern crate euclid;
 #[macro_use] extern crate html5ever_atoms;
 extern crate owning_ref;
 extern crate parking_lot;
 extern crate rayon;
 extern crate rustc_serialize;
 extern crate selectors;
-#[macro_use] extern crate servo_atoms;
+extern crate servo_atoms;
 extern crate servo_config;
 extern crate servo_url;
 extern crate style;
 extern crate style_traits;
 extern crate test;
 
 mod animated_properties;
 mod attr;
--- a/servo/tests/unit/style/parsing/animation.rs
+++ b/servo/tests/unit/style/parsing/animation.rs
@@ -1,37 +1,21 @@
 /* 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::Parser;
 use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use servo_atoms::Atom;
 use style::parser::{Parse, ParserContext};
 use style::properties::longhands::animation_iteration_count::single_value::computed_value::T as AnimationIterationCount;
-use style::properties::longhands::animation_name;
 use style::stylesheets::Origin;
 use style_traits::ToCss;
 
 #[test]
-fn test_animation_name() {
-    use self::animation_name::single_value::SpecifiedValue as SingleValue;
-    let other_name = Atom::from("other-name");
-    assert_eq!(parse_longhand!(animation_name, "none"),
-               animation_name::SpecifiedValue(vec![SingleValue(atom!(""))]));
-    assert_eq!(parse_longhand!(animation_name, "other-name, none, 'other-name', \"other-name\""),
-               animation_name::SpecifiedValue(
-                   vec![SingleValue(other_name.clone()),
-                        SingleValue(atom!("")),
-                        SingleValue(other_name.clone()),
-                        SingleValue(other_name.clone())]));
-}
-
-#[test]
 fn test_animation_iteration() {
     assert_roundtrip_with_context!(AnimationIterationCount::parse, "0", "0");
     assert_roundtrip_with_context!(AnimationIterationCount::parse, "0.1", "0.1");
     assert_roundtrip_with_context!(AnimationIterationCount::parse, "infinite", "infinite");
 
     // Negative numbers are invalid
     assert!(parse(AnimationIterationCount::parse, "-1").is_err());
 }
--- a/servo/tests/unit/style/properties/serialization.rs
+++ b/servo/tests/unit/style/properties/serialization.rs
@@ -978,17 +978,17 @@ mod shorthand_serialization {
                 animation-delay: 0s;\
                 animation-direction: normal;\
                 animation-fill-mode: forwards;\
                 animation-iteration-count: infinite;\
                 animation-play-state: paused;");
 
             let serialization = block.to_css_string();
 
-            assert_eq!(serialization, "animation: 1s ease-in 0s infinite normal forwards paused bounce;")
+            assert_eq!(serialization, "animation: 1s ease-in 0s normal forwards infinite paused bounce;")
         }
 
         #[test]
         fn serialize_multiple_animations() {
             let block = parse_declaration_block("\
                 animation-name: bounce, roll;\
                 animation-duration: 1s, 0.2s;\
                 animation-timing-function: ease-in, linear;\
@@ -996,18 +996,18 @@ mod shorthand_serialization {
                 animation-direction: normal, reverse;\
                 animation-fill-mode: forwards, backwards;\
                 animation-iteration-count: infinite, 2;\
                 animation-play-state: paused, running;");
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization,
-                       "animation: 1s ease-in 0s infinite normal forwards paused bounce, \
-                                   0.2s linear 1s 2 reverse backwards running roll;");
+                       "animation: 1s ease-in 0s normal forwards infinite paused bounce, \
+                                   0.2s linear 1s reverse backwards 2 running roll;");
         }
 
         #[test]
         fn serialize_multiple_animations_unequal_property_lists() {
             // When the lengths of property values are different, the shorthand serialization
             // should not be used. Previously the implementation cycled values if the lists were
             // uneven. This is incorrect, in that we should serialize to a shorthand only when the
             // lists have the same length (this affects background, transition and animation).