servo/components/style/properties/shorthand/box.mako.rs
2016-08-16 22:28:51 -04:00

298 lines
13 KiB
Rust

/* 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/. */
<%namespace name="helpers" file="/helpers.mako.rs" />
<%helpers:shorthand name="overflow" sub_properties="overflow-x overflow-y">
use properties::longhands::{overflow_x, overflow_y};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
let overflow = try!(overflow_x::parse(context, input));
Ok(Longhands {
overflow_x: Some(overflow),
overflow_y: Some(overflow_y::SpecifiedValue(overflow)),
})
}
// Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
// values, they no longer use the shared property name "overflow".
// Other shorthands do not include their name in the to_css method
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let x_and_y_equal = match (self.overflow_x, self.overflow_y) {
(&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => {
*x_value == y_container.0
},
(&DeclaredValue::WithVariables { .. }, &DeclaredValue::WithVariables { .. }) => true,
(&DeclaredValue::Initial, &DeclaredValue::Initial) => true,
(&DeclaredValue::Inherit, &DeclaredValue::Inherit) => true,
_ => false
};
if x_and_y_equal {
try!(write!(dest, "overflow"));
try!(write!(dest, ": "));
try!(self.overflow_x.to_css(dest));
} else {
try!(write!(dest, "overflow-x"));
try!(write!(dest, ": "));
try!(self.overflow_x.to_css(dest));
try!(write!(dest, "; "));
try!(write!(dest, "overflow-y: "));
try!(self.overflow_y.to_css(dest));
}
write!(dest, ";")
}
}
</%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
transition-delay">
use properties::longhands::{transition_delay, transition_duration, transition_property};
use properties::longhands::{transition_timing_function};
pub fn parse_value(_: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
struct SingleTransition {
transition_property: transition_property::SingleSpecifiedValue,
transition_duration: transition_duration::SingleSpecifiedValue,
transition_timing_function: transition_timing_function::SingleSpecifiedValue,
transition_delay: transition_delay::SingleSpecifiedValue,
}
fn parse_one_transition(input: &mut Parser) -> Result<SingleTransition,()> {
let (mut property, mut duration) = (None, None);
let (mut timing_function, mut delay) = (None, None);
loop {
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
}
if let Some(property) = property {
Ok(SingleTransition {
transition_property: property,
transition_duration:
duration.unwrap_or_else(transition_duration::get_initial_single_value),
transition_timing_function:
timing_function.unwrap_or_else(
transition_timing_function::get_initial_single_value),
transition_delay:
delay.unwrap_or_else(transition_delay::get_initial_single_value),
})
} else {
Err(())
}
}
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(Longhands {
transition_property: None,
transition_duration: None,
transition_timing_function: None,
transition_delay: None,
})
}
let results = try!(input.parse_comma_separated(parse_one_transition));
let (mut properties, mut durations) = (Vec::new(), Vec::new());
let (mut timing_functions, mut delays) = (Vec::new(), Vec::new());
for result in results {
properties.push(result.transition_property);
durations.push(result.transition_duration);
timing_functions.push(result.transition_timing_function);
delays.push(result.transition_delay);
}
Ok(Longhands {
transition_property: Some(transition_property::SpecifiedValue(properties)),
transition_duration: Some(transition_duration::SpecifiedValue(durations)),
transition_timing_function:
Some(transition_timing_function::SpecifiedValue(timing_functions)),
transition_delay: Some(transition_delay::SpecifiedValue(delays)),
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.transition_property.to_css(dest));
try!(write!(dest, " "));
try!(self.transition_duration.to_css(dest));
try!(write!(dest, " "));
try!(self.transition_timing_function.to_css(dest));
try!(write!(dest, " "));
self.transition_delay.to_css(dest)
}
}
</%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};
pub fn parse_value(_: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
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)),
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.animation_duration.to_css(dest));
try!(write!(dest, " "));
// FIXME: timing function is displaying the actual mathematical name "cubic-bezier(0.25, 0.1, 0.25, 1)"
// instead of the common name "ease"
try!(self.animation_timing_function.to_css(dest));
try!(write!(dest, " "));
try!(self.animation_delay.to_css(dest));
try!(write!(dest, " "));
try!(self.animation_direction.to_css(dest));
try!(write!(dest, " "));
try!(self.animation_fill_mode.to_css(dest));
try!(write!(dest, " "));
try!(self.animation_iteration_count.to_css(dest));
try!(write!(dest, " "));
try!(self.animation_play_state.to_css(dest));
try!(write!(dest, " "));
self.animation_name.to_css(dest)
}
}
</%helpers:shorthand>