diff options
Diffstat (limited to '')
-rw-r--r-- | servo/components/style/properties/shorthands/ui.mako.rs | 104 |
1 files changed, 83 insertions, 21 deletions
diff --git a/servo/components/style/properties/shorthands/ui.mako.rs b/servo/components/style/properties/shorthands/ui.mako.rs index 4a27d5e003..1915c65a63 100644 --- a/servo/components/style/properties/shorthands/ui.mako.rs +++ b/servo/components/style/properties/shorthands/ui.mako.rs @@ -18,7 +18,7 @@ macro_rules! try_parse_one { } <%helpers:shorthand name="transition" - engines="gecko servo-2013 servo-2020" + engines="gecko servo" extra_prefixes="moz:layout.css.prefixes.transitions webkit" sub_properties="transition-property transition-duration transition-timing-function @@ -204,7 +204,7 @@ macro_rules! try_parse_one { </%helpers:shorthand> <%helpers:shorthand name="animation" - engines="gecko servo-2013 servo-2020" + engines="gecko servo" extra_prefixes="moz:layout.css.prefixes.animations webkit" sub_properties="animation-name animation-duration animation-timing-function animation-delay @@ -295,6 +295,13 @@ macro_rules! try_parse_one { impl<'a> ToCss for LonghandsToSerialize<'a> { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write { + use crate::values::specified::easing::TimingFunction; + use crate::values::specified::{ + AnimationDirection, AnimationFillMode, AnimationPlayState, + }; + use crate::Zero; + use style_traits::values::SequenceWriter; + let len = self.animation_name.0.len(); // There should be at least one declared value if len == 0 { @@ -320,28 +327,83 @@ macro_rules! try_parse_one { dest.write_str(", ")?; } - % for name in props[2:]: - self.animation_${name}.0[i].to_css(dest)?; - dest.write_char(' ')?; + // We follow the order of this syntax: + // <single-animation> = + // <animation-duration> || + // <easing-function> || + // <animation-delay> || + // <single-animation-iteration-count> || + // <single-animation-direction> || + // <single-animation-fill-mode> || + // <single-animation-play-state> || + // [ none | <keyframes-name> ] || + // <single-animation-timeline> + // + // https://drafts.csswg.org/css-animations-2/#animation-shorthand + // + // FIXME: Bug 1804574. The initial value of duration should be auto, per + // css-animations-2. + let has_duration = !self.animation_duration.0[i].is_zero(); + let has_timing_function = !self.animation_timing_function.0[i].is_ease(); + let has_delay = !self.animation_delay.0[i].is_zero(); + let has_iteration_count = !self.animation_iteration_count.0[i].is_one(); + let has_direction = + !matches!(self.animation_direction.0[i], AnimationDirection::Normal); + let has_fill_mode = + !matches!(self.animation_fill_mode.0[i], AnimationFillMode::None); + let has_play_state = + !matches!(self.animation_play_state.0[i], AnimationPlayState::Running); + let animation_name = &self.animation_name.0[i]; + let has_name = !animation_name.is_none(); + let has_timeline = match self.animation_timeline { + Some(timeline) => !timeline.0[i].is_auto(), + _ => false, + }; + + let mut writer = SequenceWriter::new(dest, " "); + + // To avoid ambiguity, we have to serialize duration if both duration is initial + // but delay is not. (In other words, it's ambiguous if we serialize delay only.) + if has_duration || has_delay { + writer.item(&self.animation_duration.0[i])?; + } + + if has_timing_function || TimingFunction::match_keywords(animation_name) { + writer.item(&self.animation_timing_function.0[i])?; + } + + // For animation-delay and animation-iteration-count. + % for name in props[4:6]: + if has_${name} { + writer.item(&self.animation_${name}.0[i])?; + } % endfor - self.animation_name.0[i].to_css(dest)?; + if has_direction || AnimationDirection::match_keywords(animation_name) { + writer.item(&self.animation_direction.0[i])?; + } + + if has_fill_mode || AnimationFillMode::match_keywords(animation_name) { + writer.item(&self.animation_fill_mode.0[i])?; + } - // Based on the spec, the default values of other properties must be output in at - // least the cases necessary to distinguish an animation-name. The serialization - // order of animation-timeline is always later than animation-name, so it's fine - // to not serialize it if it is the default value. It's still possible to - // distinguish them (because we always serialize animation-name). - // https://drafts.csswg.org/css-animations-1/#animation - // https://drafts.csswg.org/css-animations-2/#typedef-single-animation - // - // Note: it's also fine to always serialize this. However, it seems Blink - // doesn't serialize default animation-timeline now, so we follow the same rule. - if let Some(ref timeline) = self.animation_timeline { - if !timeline.0[i].is_auto() { - dest.write_char(' ')?; - timeline.0[i].to_css(dest)?; - } + if has_play_state || AnimationPlayState::match_keywords(animation_name) { + writer.item(&self.animation_play_state.0[i])?; + } + + // If all values are initial, we must serialize animation-name. + let has_any = { + has_timeline + % for name in props[2:]: + || has_${name} + % endfor + }; + if has_name || !has_any { + writer.item(animation_name)?; + } + + if has_timeline { + writer.item(&self.animation_timeline.unwrap().0[i])?; } } Ok(()) |