Skip to content

Commit

Permalink
style: Add support to the animation shorthand and fix parsing of anim…
Browse files Browse the repository at this point in the history
…ation-name.
  • Loading branch information
emilio committed Jul 7, 2016
1 parent 4fafcb1 commit 411ae84
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 46 deletions.
1 change: 1 addition & 0 deletions components/script/dom/webidls/CSSStyleDeclaration.webidl
Expand Up @@ -331,6 +331,7 @@ partial interface CSSStyleDeclaration {
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString alignSelf;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString align-self;

[SetterThrows, TreatNullAs=EmptyString] attribute DOMString animation;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString animation-name;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString animationName;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString animation-duration;
Expand Down
16 changes: 13 additions & 3 deletions components/style/properties/helpers.mako.rs
Expand Up @@ -235,11 +235,21 @@
}
}

pub use self::computed_value::${to_camel_case(name)} as SingleSpecifiedValue;

#[inline]
pub fn parse_one(input: &mut Parser) -> Result<SingleSpecifiedValue, ()> {
SingleSpecifiedValue::parse(input)
}

#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T(vec![
computed_value::${to_camel_case(name)}::${to_rust_ident(values.split()[0])}
])
computed_value::T(vec![get_initial_single_value()])
}

#[inline]
pub fn get_initial_single_value() -> SingleSpecifiedValue {
SingleSpecifiedValue::${to_rust_ident(values.split()[0])}
}

#[inline]
Expand Down
46 changes: 37 additions & 9 deletions components/style/properties/longhand/box.mako.rs
Expand Up @@ -490,8 +490,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",

pub fn parse_one(input: &mut Parser) -> Result<SingleSpecifiedValue,()> {
if let Ok(function_name) = input.try(|input| input.expect_function()) {
return match_ignore_ascii_case! {
function_name,
return match_ignore_ascii_case! { function_name,
"cubic-bezier" => {
let (mut p1x, mut p1y, mut p2x, mut p2y) = (0.0, 0.0, 0.0, 0.0);
try!(input.parse_nested_block(|input| {
Expand Down Expand Up @@ -582,6 +581,12 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
computed_value::T(Vec::new())
}


#[inline]
pub fn parse_one(input: &mut Parser) -> Result<SingleSpecifiedValue, ()> {
SingleSpecifiedValue::parse(input)
}

pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
Ok(SpecifiedValue(try!(input.parse_comma_separated(SingleSpecifiedValue::parse))))
}
Expand Down Expand Up @@ -640,6 +645,18 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
}

pub use self::computed_value::T as SpecifiedValue;
pub use string_cache::Atom as SingleSpecifiedValue;

#[inline]
pub fn parse_one(input: &mut Parser) -> Result<SingleSpecifiedValue, ()> {
use cssparser::Token;

Ok(match input.next() {
Ok(Token::Ident(ref value)) if value != "none" => Atom::from(&**value),
Ok(Token::QuotedString(value)) => Atom::from(&*value),
_ => return Err(()),
})
}

#[inline]
pub fn get_initial_value() -> computed_value::T {
Expand All @@ -648,9 +665,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",

pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
use std::borrow::Cow;
Ok(SpecifiedValue(try!(input.parse_comma_separated(|input| {
input.expect_ident().map(Atom::from)
}))))
Ok(SpecifiedValue(try!(input.parse_comma_separated(parse_one))))
}

impl ComputedValueAsSpecified for SpecifiedValue {}
Expand All @@ -660,16 +675,20 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
need_index="True"
animatable="False">
pub use super::transition_duration::computed_value;
pub use super::transition_duration::{parse, get_initial_value};
pub use super::transition_duration::{get_initial_value, get_initial_single_value};
pub use super::transition_duration::{parse, parse_one};
pub use super::transition_duration::SpecifiedValue;
pub use super::transition_duration::SingleSpecifiedValue;
</%helpers:longhand>

<%helpers:longhand name="animation-timing-function"
need_index="True"
animatable="False">
pub use super::transition_timing_function::computed_value;
pub use super::transition_timing_function::{parse, get_initial_value};
pub use super::transition_timing_function::{get_initial_value, get_initial_single_value};
pub use super::transition_timing_function::{parse, parse_one};
pub use super::transition_timing_function::SpecifiedValue;
pub use super::transition_timing_function::SingleSpecifiedValue;
</%helpers:longhand>

<%helpers:longhand name="animation-iteration-count"
Expand Down Expand Up @@ -720,8 +739,14 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
}

pub use self::computed_value::AnimationIterationCount;
pub use self::computed_value::AnimationIterationCount as SingleSpecifiedValue;
pub use self::computed_value::T as SpecifiedValue;

#[inline]
pub fn get_initial_single_value() -> AnimationIterationCount {
AnimationIterationCount::Number(1)
}

pub fn parse_one(input: &mut Parser) -> Result<AnimationIterationCount, ()> {
if input.try(|input| input.expect_ident_matching("infinite")).is_ok() {
Ok(AnimationIterationCount::Infinite)
Expand All @@ -740,8 +765,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
Ok(SpecifiedValue(try!(input.parse_comma_separated(parse_one))))
}

#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T(vec![AnimationIterationCount::Number(1)])
computed_value::T(vec![get_initial_single_value()])
}

impl ComputedValueAsSpecified for SpecifiedValue {}
Expand All @@ -767,8 +793,10 @@ ${helpers.keyword_list("animation-fill-mode",
need_index="True"
animatable="False">
pub use super::transition_duration::computed_value;
pub use super::transition_duration::{parse, get_initial_value};
pub use super::transition_duration::{get_initial_value, get_initial_single_value};
pub use super::transition_duration::{parse, parse_one};
pub use super::transition_duration::SpecifiedValue;
pub use super::transition_duration::SingleSpecifiedValue;
</%helpers:longhand>

// CSSOM View Module
Expand Down
173 changes: 139 additions & 34 deletions components/style/properties/shorthand/box.mako.rs
Expand Up @@ -14,8 +14,20 @@
})
</%helpers:shorthand>

macro_rules! try_parse_one {
($input: expr, $var: ident, $prop_module: ident) => {
if $var.is_none() {
if let Ok(value) = $input.try($prop_module::parse_one) {
$var = Some(value);
continue;
}
}
}
}

<%helpers:shorthand name="transition"
sub_properties="transition-property transition-duration transition-timing-function
sub_properties="transition-property transition-duration
transition-timing-function
transition-delay">
use properties::longhands::{transition_delay, transition_duration, transition_property};
use properties::longhands::{transition_timing_function};
Expand All @@ -31,35 +43,10 @@
let (mut property, mut duration) = (None, None);
let (mut timing_function, mut delay) = (None, None);
loop {
if property.is_none() {
if let Ok(value) = input.try(transition_property::SingleSpecifiedValue::parse) {
property = Some(value);
continue
}
}

if duration.is_none() {
if let Ok(value) = input.try(|input| transition_duration::parse_one(input)) {
duration = Some(value);
continue
}
}

if timing_function.is_none() {
if let Ok(value) = input.try(|input| {
transition_timing_function::parse_one(input)
}) {
timing_function = Some(value);
continue
}
}

if delay.is_none() {
if let Ok(value) = input.try(|input| transition_delay::parse_one(input)) {
delay = Some(value);
continue;
}
}
try_parse_one!(input, property, transition_property);
try_parse_one!(input, duration, transition_duration);
try_parse_one!(input, timing_function, transition_timing_function);
try_parse_one!(input, delay, transition_delay);

break
}
Expand All @@ -68,12 +55,12 @@
Ok(SingleTransition {
transition_property: property,
transition_duration:
duration.unwrap_or(transition_duration::get_initial_single_value()),
duration.unwrap_or_else(transition_duration::get_initial_single_value),
transition_timing_function:
timing_function.unwrap_or(
transition_timing_function::get_initial_single_value()),
timing_function.unwrap_or_else(
transition_timing_function::get_initial_single_value),
transition_delay:
delay.unwrap_or(transition_delay::get_initial_single_value()),
delay.unwrap_or_else(transition_delay::get_initial_single_value),
})
} else {
Err(())
Expand Down Expand Up @@ -107,3 +94,121 @@
transition_delay: Some(transition_delay::SpecifiedValue(delays)),
})
</%helpers:shorthand>

<%helpers:shorthand name="animation"
sub_properties="animation-name animation-duration
animation-timing-function animation-delay
animation-iteration-count animation-direction
animation-fill-mode animation-play-state">
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};

struct SingleAnimation {
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(input: &mut Parser) -> Result<SingleAnimation,()> {
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!(input, duration, animation_duration);
try_parse_one!(input, timing_function, animation_timing_function);
try_parse_one!(input, delay, animation_delay);
try_parse_one!(input, iteration_count, animation_iteration_count);
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!(input, name, animation_name);

break
}

if let Some(name) = name {
Ok(SingleAnimation {
animation_name: name,
animation_duration:
duration.unwrap_or_else(animation_duration::get_initial_single_value),
animation_timing_function:
timing_function.unwrap_or_else(animation_timing_function::get_initial_single_value),
animation_delay:
delay.unwrap_or_else(animation_delay::get_initial_single_value),
animation_iteration_count:
iteration_count.unwrap_or_else(animation_iteration_count::get_initial_single_value),
animation_direction:
direction.unwrap_or_else(animation_direction::get_initial_single_value),
animation_fill_mode:
fill_mode.unwrap_or_else(animation_fill_mode::get_initial_single_value),
animation_play_state:
play_state.unwrap_or_else(animation_play_state::get_initial_single_value),
})
} else {
Err(())
}
}

if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(Longhands {
animation_name: None,
animation_duration: None,
animation_timing_function: None,
animation_delay: None,
animation_iteration_count: None,
animation_direction: None,
animation_fill_mode: None,
animation_play_state: None,
})
}

let results = try!(input.parse_comma_separated(parse_one_animation));

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![];

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 {
animation_name: Some(animation_name::SpecifiedValue(names)),
animation_duration: Some(animation_duration::SpecifiedValue(durations)),
animation_timing_function: Some(animation_timing_function::SpecifiedValue(timing_functions)),
animation_delay: Some(animation_delay::SpecifiedValue(delays)),
animation_iteration_count: Some(animation_iteration_count::SpecifiedValue(iteration_counts)),
animation_direction: Some(animation_direction::SpecifiedValue(directions)),
animation_fill_mode: Some(animation_fill_mode::SpecifiedValue(fill_modes)),
animation_play_state: Some(animation_play_state::SpecifiedValue(play_states)),
})
</%helpers:shorthand>
@@ -0,0 +1,4 @@
[css-flexbox-height-animation-stretch.htm]
type: reftest
expected: TIMEOUT
bug: https://github.com/servo/servo/issues/12328

0 comments on commit 411ae84

Please sign in to comment.