Extracted shorthands to separate files.

I've deliberately tried to keep things similarly structured as in the longhand files. I.e. if a given property is in e.g. longhand/box.mako.rs, the shorthand stuff that relates to the same property is in shorthand/box.mako.rs and so forth.
This commit is contained in:
Per Lundberg 2016-04-26 23:12:35 +03:00
parent 1fee7185a7
commit 38f90a3e2e
12 changed files with 727 additions and 664 deletions

View file

@ -189,3 +189,82 @@
}
</%call>
</%def>
<%def name="shorthand(name, sub_properties, experimental=False)">
<%
shorthand = data.declare_shorthand(name, sub_properties.split(), experimental=experimental)
%>
pub mod ${shorthand.ident} {
use cssparser::Parser;
use parser::ParserContext;
use properties::{longhands, PropertyDeclaration, DeclaredValue, Shorthand};
pub struct Longhands {
% for sub_property in shorthand.sub_properties:
pub ${sub_property.ident}:
Option<longhands::${sub_property.ident}::SpecifiedValue>,
% endfor
}
pub fn parse(context: &ParserContext, input: &mut Parser,
declarations: &mut Vec<PropertyDeclaration>)
-> Result<(), ()> {
input.look_for_var_functions();
let start = input.position();
let value = input.parse_entirely(|input| parse_value(context, input));
if value.is_err() {
while let Ok(_) = input.next() {} // Look for var() after the error.
}
let var = input.seen_var_functions();
if let Ok(value) = value {
% for sub_property in shorthand.sub_properties:
declarations.push(PropertyDeclaration::${sub_property.camel_case}(
match value.${sub_property.ident} {
Some(value) => DeclaredValue::Value(value),
None => DeclaredValue::Initial,
}
));
% endfor
Ok(())
} else if var {
input.reset(start);
let (first_token_type, css) = try!(
::custom_properties::parse_non_custom_with_var(input));
% for sub_property in shorthand.sub_properties:
declarations.push(PropertyDeclaration::${sub_property.camel_case}(
DeclaredValue::WithVariables {
css: css.clone().into_owned(),
first_token_type: first_token_type,
base_url: context.base_url.clone(),
from_shorthand: Some(Shorthand::${shorthand.camel_case}),
}
));
% endfor
Ok(())
} else {
Err(())
}
}
#[allow(unused_variables)]
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
${caller.body()}
}
}
</%def>
<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function)">
<%self:shorthand name="${name}" sub_properties="${
' '.join(sub_property_pattern % side
for side in ['top', 'right', 'bottom', 'left'])}">
use super::parse_four_sides;
use values::specified;
let _unused = context;
let (top, right, bottom, left) = try!(parse_four_sides(input, ${parser_function}));
Ok(Longhands {
% for side in ["top", "right", "bottom", "left"]:
${to_rust_ident(sub_property_pattern % side)}: Some(${side}),
% endfor
})
</%self:shorthand>
</%def>

View file

@ -70,75 +70,11 @@ pub mod longhands {
<%include file="/longhand/svg.mako.rs" />
}
pub mod shorthands {
use cssparser::Parser;
use parser::ParserContext;
use values::specified;
<%def name="shorthand(name, sub_properties, experimental=False)">
<%
shorthand = data.declare_shorthand(name, sub_properties.split(), experimental=experimental)
%>
pub mod ${shorthand.ident} {
use cssparser::Parser;
use parser::ParserContext;
use properties::{longhands, PropertyDeclaration, DeclaredValue, Shorthand};
pub struct Longhands {
% for sub_property in shorthand.sub_properties:
pub ${sub_property.ident}:
Option<longhands::${sub_property.ident}::SpecifiedValue>,
% endfor
}
pub fn parse(context: &ParserContext, input: &mut Parser,
declarations: &mut Vec<PropertyDeclaration>)
-> Result<(), ()> {
input.look_for_var_functions();
let start = input.position();
let value = input.parse_entirely(|input| parse_value(context, input));
if value.is_err() {
while let Ok(_) = input.next() {} // Look for var() after the error.
}
let var = input.seen_var_functions();
if let Ok(value) = value {
% for sub_property in shorthand.sub_properties:
declarations.push(PropertyDeclaration::${sub_property.camel_case}(
match value.${sub_property.ident} {
Some(value) => DeclaredValue::Value(value),
None => DeclaredValue::Initial,
}
));
% endfor
Ok(())
} else if var {
input.reset(start);
let (first_token_type, css) = try!(
::custom_properties::parse_non_custom_with_var(input));
% for sub_property in shorthand.sub_properties:
declarations.push(PropertyDeclaration::${sub_property.camel_case}(
DeclaredValue::WithVariables {
css: css.clone().into_owned(),
first_token_type: first_token_type,
base_url: context.base_url.clone(),
from_shorthand: Some(Shorthand::${shorthand.camel_case}),
}
));
% endfor
Ok(())
} else {
Err(())
}
}
#[allow(unused_variables)]
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
${caller.body()}
}
}
</%def>
fn parse_four_sides<F, T>(input: &mut Parser, parse_one: F) -> Result<(T, T, T, T), ()>
where F: Fn(&mut Parser) -> Result<T, ()>, F: Copy, T: Clone {
// zero or more than four values is invalid.
@ -182,606 +118,16 @@ pub mod shorthands {
Ok((top, right, bottom, left))
}
<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function)">
<%self:shorthand name="${name}" sub_properties="${
' '.join(sub_property_pattern % side
for side in ['top', 'right', 'bottom', 'left'])}">
use super::parse_four_sides;
use values::specified;
let _unused = context;
let (top, right, bottom, left) = try!(parse_four_sides(input, ${parser_function}));
Ok(Longhands {
% for side in ["top", "right", "bottom", "left"]:
${to_rust_ident(sub_property_pattern % side)}: Some(${side}),
% endfor
})
</%self:shorthand>
</%def>
// TODO: other background-* properties
<%self:shorthand name="background"
sub_properties="background-color background-position background-repeat background-attachment
background-image background-size background-origin background-clip">
use properties::longhands::{background_color, background_position, background_repeat, background_attachment};
use properties::longhands::{background_image, background_size, background_origin, background_clip};
let mut color = None;
let mut image = None;
let mut position = None;
let mut repeat = None;
let mut size = None;
let mut attachment = None;
let mut any = false;
let mut origin = None;
let mut clip = None;
loop {
if position.is_none() {
if let Ok(value) = input.try(|input| background_position::parse(context, input)) {
position = Some(value);
any = true;
// Parse background size, if applicable.
size = input.try(|input| {
try!(input.expect_delim('/'));
background_size::parse(context, input)
}).ok();
continue
}
}
if color.is_none() {
if let Ok(value) = input.try(|input| background_color::parse(context, input)) {
color = Some(value);
any = true;
continue
}
}
if image.is_none() {
if let Ok(value) = input.try(|input| background_image::parse(context, input)) {
image = Some(value);
any = true;
continue
}
}
if repeat.is_none() {
if let Ok(value) = input.try(|input| background_repeat::parse(context, input)) {
repeat = Some(value);
any = true;
continue
}
}
if attachment.is_none() {
if let Ok(value) = input.try(|input| background_attachment::parse(context, input)) {
attachment = Some(value);
any = true;
continue
}
}
if origin.is_none() {
if let Ok(value) = input.try(|input| background_origin::parse(context, input)) {
origin = Some(value);
any = true;
continue
}
}
if clip.is_none() {
if let Ok(value) = input.try(|input| background_clip::parse(context, input)) {
clip = Some(value);
any = true;
continue
}
}
break
}
if any {
Ok(Longhands {
background_color: color,
background_image: image,
background_position: position,
background_repeat: repeat,
background_attachment: attachment,
background_size: size,
background_origin: origin,
background_clip: clip,
})
} else {
Err(())
}
</%self:shorthand>
${four_sides_shorthand("margin", "margin-%s", "specified::LengthOrPercentageOrAuto::parse")}
${four_sides_shorthand("padding", "padding-%s", "specified::LengthOrPercentage::parse")}
${four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse")}
${four_sides_shorthand("border-style", "border-%s-style",
"specified::BorderStyle::parse")}
<%self:shorthand name="border-width" sub_properties="${
' '.join('border-%s-width' % side
for side in ['top', 'right', 'bottom', 'left'])}">
use super::parse_four_sides;
use values::specified;
let _unused = context;
let (top, right, bottom, left) = try!(parse_four_sides(input, specified::parse_border_width));
Ok(Longhands {
% for side in ["top", "right", "bottom", "left"]:
${to_rust_ident('border-%s-width' % side)}:
Some(longhands::${to_rust_ident('border-%s-width' % side)}::SpecifiedValue(${side})),
% endfor
})
</%self:shorthand>
pub fn parse_border(context: &ParserContext, input: &mut Parser)
-> Result<(Option<specified::CSSColor>,
Option<specified::BorderStyle>,
Option<specified::Length>), ()> {
use values::specified;
let _unused = context;
let mut color = None;
let mut style = None;
let mut width = None;
let mut any = false;
loop {
if color.is_none() {
if let Ok(value) = input.try(specified::CSSColor::parse) {
color = Some(value);
any = true;
continue
}
}
if style.is_none() {
if let Ok(value) = input.try(specified::BorderStyle::parse) {
style = Some(value);
any = true;
continue
}
}
if width.is_none() {
if let Ok(value) = input.try(specified::parse_border_width) {
width = Some(value);
any = true;
continue
}
}
break
}
if any { Ok((color, style, width)) } else { Err(()) }
}
% for side in ["top", "right", "bottom", "left"]:
<%self:shorthand name="border-${side}" sub_properties="${' '.join(
'border-%s-%s' % (side, prop)
for prop in ['color', 'style', 'width']
)}">
let (color, style, width) = try!(super::parse_border(context, input));
Ok(Longhands {
border_${side}_color: color,
border_${side}_style: style,
border_${side}_width:
width.map(longhands::${to_rust_ident('border-%s-width' % side)}::SpecifiedValue),
})
</%self:shorthand>
% endfor
<%self:shorthand name="border" sub_properties="${' '.join(
'border-%s-%s' % (side, prop)
for side in ['top', 'right', 'bottom', 'left']
for prop in ['color', 'style', 'width']
)}">
let (color, style, width) = try!(super::parse_border(context, input));
Ok(Longhands {
% for side in ["top", "right", "bottom", "left"]:
border_${side}_color: color.clone(),
border_${side}_style: style,
border_${side}_width:
width.map(longhands::${to_rust_ident('border-%s-width' % side)}::SpecifiedValue),
% endfor
})
</%self:shorthand>
<%self:shorthand name="border-radius" sub_properties="${' '.join(
'border-%s-radius' % (corner)
for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
)}">
use app_units::Au;
use values::specified::{Length, LengthOrPercentage};
use values::specified::BorderRadiusSize;
let _ignored = context;
fn parse_one_set_of_border_values(mut input: &mut Parser)
-> Result<[LengthOrPercentage; 4], ()> {
let mut count = 0;
let mut values = [LengthOrPercentage::Length(Length::Absolute(Au(0))); 4];
while count < 4 {
if let Ok(value) = input.try(LengthOrPercentage::parse) {
values[count] = value;
count += 1;
} else {
break
}
}
match count {
1 => Ok([values[0], values[0], values[0], values[0]]),
2 => Ok([values[0], values[1], values[0], values[1]]),
3 => Ok([values[0], values[1], values[2], values[1]]),
4 => Ok([values[0], values[1], values[2], values[3]]),
_ => Err(()),
}
}
fn parse_one_set_of_border_radii(mut input: &mut Parser)
-> Result<[BorderRadiusSize; 4], ()> {
let widths = try!(parse_one_set_of_border_values(input));
let mut heights = widths.clone();
let mut radii_values = [BorderRadiusSize::zero(); 4];
if input.try(|input| input.expect_delim('/')).is_ok() {
heights = try!(parse_one_set_of_border_values(input));
}
for i in 0..radii_values.len() {
radii_values[i] = BorderRadiusSize::new(widths[i], heights[i]);
}
Ok(radii_values)
}
let radii = try!(parse_one_set_of_border_radii(input));
Ok(Longhands {
border_top_left_radius: Some(radii[0]),
border_top_right_radius: Some(radii[1]),
border_bottom_right_radius: Some(radii[2]),
border_bottom_left_radius: Some(radii[3]),
})
</%self:shorthand>
<%self:shorthand name="outline" sub_properties="outline-color outline-style outline-width">
use properties::longhands::outline_width;
use values::specified;
let _unused = context;
let mut color = None;
let mut style = None;
let mut width = None;
let mut any = false;
loop {
if color.is_none() {
if let Ok(value) = input.try(specified::CSSColor::parse) {
color = Some(value);
any = true;
continue
}
}
if style.is_none() {
if let Ok(value) = input.try(specified::BorderStyle::parse) {
style = Some(value);
any = true;
continue
}
}
if width.is_none() {
if let Ok(value) = input.try(|input| outline_width::parse(context, input)) {
width = Some(value);
any = true;
continue
}
}
break
}
if any {
Ok(Longhands {
outline_color: color,
outline_style: style,
outline_width: width,
})
} else {
Err(())
}
</%self:shorthand>
<%self:shorthand name="font" sub_properties="font-style font-variant font-weight
font-size line-height font-family">
use properties::longhands::{font_style, font_variant, font_weight, font_size,
line_height, font_family};
let mut nb_normals = 0;
let mut style = None;
let mut variant = None;
let mut weight = None;
let size;
loop {
// Special-case 'normal' because it is valid in each of
// font-style, font-weight and font-variant.
// Leaves the values to None, 'normal' is the initial value for each of them.
if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
nb_normals += 1;
continue;
}
if style.is_none() {
if let Ok(value) = input.try(|input| font_style::parse(context, input)) {
style = Some(value);
continue
}
}
if weight.is_none() {
if let Ok(value) = input.try(|input| font_weight::parse(context, input)) {
weight = Some(value);
continue
}
}
if variant.is_none() {
if let Ok(value) = input.try(|input| font_variant::parse(context, input)) {
variant = Some(value);
continue
}
}
size = Some(try!(font_size::parse(context, input)));
break
}
#[inline]
fn count<T>(opt: &Option<T>) -> u8 {
if opt.is_some() { 1 } else { 0 }
}
if size.is_none() || (count(&style) + count(&weight) + count(&variant) + nb_normals) > 3 {
return Err(())
}
let line_height = if input.try(|input| input.expect_delim('/')).is_ok() {
Some(try!(line_height::parse(context, input)))
} else {
None
};
let family = try!(input.parse_comma_separated(font_family::parse_one_family));
Ok(Longhands {
font_style: style,
font_variant: variant,
font_weight: weight,
font_size: size,
line_height: line_height,
font_family: Some(font_family::SpecifiedValue(family))
})
</%self:shorthand>
// Per CSS-TEXT 6.2, "for legacy reasons, UAs must treat `word-wrap` as an alternate name for
// the `overflow-wrap` property, as if it were a shorthand of `overflow-wrap`."
<%self:shorthand name="word-wrap" sub_properties="overflow-wrap">
use properties::longhands::overflow_wrap;
Ok(Longhands {
overflow_wrap: Some(try!(overflow_wrap::parse(context, input))),
})
</%self:shorthand>
<%self:shorthand name="list-style"
sub_properties="list-style-image list-style-position list-style-type">
use properties::longhands::{list_style_image, list_style_position, list_style_type};
// `none` is ambiguous until we've finished parsing the shorthands, so we count the number
// of times we see it.
let mut nones = 0u8;
let (mut image, mut position, mut list_style_type, mut any) = (None, None, None, false);
loop {
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
nones = nones + 1;
if nones > 2 {
return Err(())
}
any = true;
continue
}
if list_style_type.is_none() {
if let Ok(value) = input.try(|input| list_style_type::parse(context, input)) {
list_style_type = Some(value);
any = true;
continue
}
}
if image.is_none() {
if let Ok(value) = input.try(|input| list_style_image::parse(context, input)) {
image = Some(value);
any = true;
continue
}
}
if position.is_none() {
if let Ok(value) = input.try(|input| list_style_position::parse(context, input)) {
position = Some(value);
any = true;
continue
}
}
break
}
// If there are two `none`s, then we can't have a type or image; if there is one `none`,
// then we can't have both a type *and* an image; if there is no `none` then we're fine as
// long as we parsed something.
match (any, nones, list_style_type, image) {
(true, 2, None, None) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(list_style_image::SpecifiedValue::None),
list_style_type: Some(list_style_type::SpecifiedValue::none),
})
}
(true, 1, None, Some(image)) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(image),
list_style_type: Some(list_style_type::SpecifiedValue::none),
})
}
(true, 1, Some(list_style_type), None) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(list_style_image::SpecifiedValue::None),
list_style_type: Some(list_style_type),
})
}
(true, 1, None, None) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(list_style_image::SpecifiedValue::None),
list_style_type: Some(list_style_type::SpecifiedValue::none),
})
}
(true, 0, list_style_type, image) => {
Ok(Longhands {
list_style_position: position,
list_style_image: image,
list_style_type: list_style_type,
})
}
_ => Err(()),
}
</%self:shorthand>
<%self:shorthand name="columns" sub_properties="column-count column-width" experimental="True">
use properties::longhands::{column_count, column_width};
let mut column_count = None;
let mut column_width = None;
let mut autos = 0;
loop {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
// Leave the options to None, 'auto' is the initial value.
autos += 1;
continue
}
if column_count.is_none() {
if let Ok(value) = input.try(|input| column_count::parse(context, input)) {
column_count = Some(value);
continue
}
}
if column_width.is_none() {
if let Ok(value) = input.try(|input| column_width::parse(context, input)) {
column_width = Some(value);
continue
}
}
break
}
let values = autos + column_count.iter().len() + column_width.iter().len();
if values == 0 || values > 2 {
Err(())
} else {
Ok(Longhands {
column_count: column_count,
column_width: column_width,
})
}
</%self:shorthand>
<%self:shorthand name="overflow" sub_properties="overflow-x overflow-y">
use properties::longhands::{overflow_x, overflow_y};
let overflow = try!(overflow_x::parse(context, input));
Ok(Longhands {
overflow_x: Some(overflow),
overflow_y: Some(overflow_y::SpecifiedValue(overflow)),
})
</%self:shorthand>
<%self: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};
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 {
if property.is_none() {
if let Ok(value) = input.try(|input| transition_property::parse_one(input)) {
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;
}
}
break
}
if let Some(property) = property {
Ok(SingleTransition {
transition_property: property,
transition_duration:
duration.unwrap_or(transition_duration::get_initial_single_value()),
transition_timing_function:
timing_function.unwrap_or(
transition_timing_function::get_initial_single_value()),
transition_delay:
delay.unwrap_or(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)),
})
</%self:shorthand>
<%include file="/shorthand/background.mako.rs" />
<%include file="/shorthand/border.mako.rs" />
<%include file="/shorthand/box.mako.rs" />
<%include file="/shorthand/column.mako.rs" />
<%include file="/shorthand/font.mako.rs" />
<%include file="/shorthand/inherited_text.mako.rs" />
<%include file="/shorthand/list.mako.rs" />
<%include file="/shorthand/margin.mako.rs" />
<%include file="/shorthand/outline.mako.rs" />
<%include file="/shorthand/padding.mako.rs" />
}

View file

@ -0,0 +1,99 @@
/* 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" />
// TODO: other background-* properties
<%helpers:shorthand name="background"
sub_properties="background-color background-position background-repeat background-attachment
background-image background-size background-origin background-clip">
use properties::longhands::{background_color, background_position, background_repeat, background_attachment};
use properties::longhands::{background_image, background_size, background_origin, background_clip};
let mut color = None;
let mut image = None;
let mut position = None;
let mut repeat = None;
let mut size = None;
let mut attachment = None;
let mut any = false;
let mut origin = None;
let mut clip = None;
loop {
if position.is_none() {
if let Ok(value) = input.try(|input| background_position::parse(context, input)) {
position = Some(value);
any = true;
// Parse background size, if applicable.
size = input.try(|input| {
try!(input.expect_delim('/'));
background_size::parse(context, input)
}).ok();
continue
}
}
if color.is_none() {
if let Ok(value) = input.try(|input| background_color::parse(context, input)) {
color = Some(value);
any = true;
continue
}
}
if image.is_none() {
if let Ok(value) = input.try(|input| background_image::parse(context, input)) {
image = Some(value);
any = true;
continue
}
}
if repeat.is_none() {
if let Ok(value) = input.try(|input| background_repeat::parse(context, input)) {
repeat = Some(value);
any = true;
continue
}
}
if attachment.is_none() {
if let Ok(value) = input.try(|input| background_attachment::parse(context, input)) {
attachment = Some(value);
any = true;
continue
}
}
if origin.is_none() {
if let Ok(value) = input.try(|input| background_origin::parse(context, input)) {
origin = Some(value);
any = true;
continue
}
}
if clip.is_none() {
if let Ok(value) = input.try(|input| background_clip::parse(context, input)) {
clip = Some(value);
any = true;
continue
}
}
break
}
if any {
Ok(Longhands {
background_color: color,
background_image: image,
background_position: position,
background_repeat: repeat,
background_attachment: attachment,
background_size: size,
background_origin: origin,
background_clip: clip,
})
} else {
Err(())
}
</%helpers:shorthand>

View file

@ -0,0 +1,149 @@
/* 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" />
<% from data import to_rust_ident %>
${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse")}
${helpers.four_sides_shorthand("border-style", "border-%s-style",
"specified::BorderStyle::parse")}
<%helpers:shorthand name="border-width" sub_properties="${
' '.join('border-%s-width' % side
for side in ['top', 'right', 'bottom', 'left'])}">
use super::parse_four_sides;
use values::specified;
let _unused = context;
let (top, right, bottom, left) = try!(parse_four_sides(input, specified::parse_border_width));
Ok(Longhands {
% for side in ["top", "right", "bottom", "left"]:
${to_rust_ident('border-%s-width' % side)}:
Some(longhands::${to_rust_ident('border-%s-width' % side)}::SpecifiedValue(${side})),
% endfor
})
</%helpers:shorthand>
pub fn parse_border(context: &ParserContext, input: &mut Parser)
-> Result<(Option<specified::CSSColor>,
Option<specified::BorderStyle>,
Option<specified::Length>), ()> {
use values::specified;
let _unused = context;
let mut color = None;
let mut style = None;
let mut width = None;
let mut any = false;
loop {
if color.is_none() {
if let Ok(value) = input.try(specified::CSSColor::parse) {
color = Some(value);
any = true;
continue
}
}
if style.is_none() {
if let Ok(value) = input.try(specified::BorderStyle::parse) {
style = Some(value);
any = true;
continue
}
}
if width.is_none() {
if let Ok(value) = input.try(specified::parse_border_width) {
width = Some(value);
any = true;
continue
}
}
break
}
if any { Ok((color, style, width)) } else { Err(()) }
}
% for side in ["top", "right", "bottom", "left"]:
<%helpers:shorthand name="border-${side}" sub_properties="${' '.join(
'border-%s-%s' % (side, prop)
for prop in ['color', 'style', 'width']
)}">
let (color, style, width) = try!(super::parse_border(context, input));
Ok(Longhands {
border_${side}_color: color,
border_${side}_style: style,
border_${side}_width:
width.map(longhands::${to_rust_ident('border-%s-width' % side)}::SpecifiedValue),
})
</%helpers:shorthand>
% endfor
<%helpers:shorthand name="border" sub_properties="${' '.join(
'border-%s-%s' % (side, prop)
for side in ['top', 'right', 'bottom', 'left']
for prop in ['color', 'style', 'width']
)}">
let (color, style, width) = try!(super::parse_border(context, input));
Ok(Longhands {
% for side in ["top", "right", "bottom", "left"]:
border_${side}_color: color.clone(),
border_${side}_style: style,
border_${side}_width:
width.map(longhands::${to_rust_ident('border-%s-width' % side)}::SpecifiedValue),
% endfor
})
</%helpers:shorthand>
<%helpers:shorthand name="border-radius" sub_properties="${' '.join(
'border-%s-radius' % (corner)
for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
)}">
use app_units::Au;
use values::specified::{Length, LengthOrPercentage};
use values::specified::BorderRadiusSize;
let _ignored = context;
fn parse_one_set_of_border_values(mut input: &mut Parser)
-> Result<[LengthOrPercentage; 4], ()> {
let mut count = 0;
let mut values = [LengthOrPercentage::Length(Length::Absolute(Au(0))); 4];
while count < 4 {
if let Ok(value) = input.try(LengthOrPercentage::parse) {
values[count] = value;
count += 1;
} else {
break
}
}
match count {
1 => Ok([values[0], values[0], values[0], values[0]]),
2 => Ok([values[0], values[1], values[0], values[1]]),
3 => Ok([values[0], values[1], values[2], values[1]]),
4 => Ok([values[0], values[1], values[2], values[3]]),
_ => Err(()),
}
}
fn parse_one_set_of_border_radii(mut input: &mut Parser)
-> Result<[BorderRadiusSize; 4], ()> {
let widths = try!(parse_one_set_of_border_values(input));
let mut heights = widths.clone();
let mut radii_values = [BorderRadiusSize::zero(); 4];
if input.try(|input| input.expect_delim('/')).is_ok() {
heights = try!(parse_one_set_of_border_values(input));
}
for i in 0..radii_values.len() {
radii_values[i] = BorderRadiusSize::new(widths[i], heights[i]);
}
Ok(radii_values)
}
let radii = try!(parse_one_set_of_border_radii(input));
Ok(Longhands {
border_top_left_radius: Some(radii[0]),
border_top_right_radius: Some(radii[1]),
border_bottom_right_radius: Some(radii[2]),
border_bottom_left_radius: Some(radii[3]),
})
</%helpers:shorthand>

View file

@ -0,0 +1,109 @@
/* 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};
let overflow = try!(overflow_x::parse(context, input));
Ok(Longhands {
overflow_x: Some(overflow),
overflow_y: Some(overflow_y::SpecifiedValue(overflow)),
})
</%helpers:shorthand>
<%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};
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 {
if property.is_none() {
if let Ok(value) = input.try(|input| transition_property::parse_one(input)) {
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;
}
}
break
}
if let Some(property) = property {
Ok(SingleTransition {
transition_property: property,
transition_duration:
duration.unwrap_or(transition_duration::get_initial_single_value()),
transition_timing_function:
timing_function.unwrap_or(
transition_timing_function::get_initial_single_value()),
transition_delay:
delay.unwrap_or(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)),
})
</%helpers:shorthand>

View file

@ -0,0 +1,46 @@
/* 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="columns" sub_properties="column-count column-width" experimental="True">
use properties::longhands::{column_count, column_width};
let mut column_count = None;
let mut column_width = None;
let mut autos = 0;
loop {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
// Leave the options to None, 'auto' is the initial value.
autos += 1;
continue
}
if column_count.is_none() {
if let Ok(value) = input.try(|input| column_count::parse(context, input)) {
column_count = Some(value);
continue
}
}
if column_width.is_none() {
if let Ok(value) = input.try(|input| column_width::parse(context, input)) {
column_width = Some(value);
continue
}
}
break
}
let values = autos + column_count.iter().len() + column_width.iter().len();
if values == 0 || values > 2 {
Err(())
} else {
Ok(Longhands {
column_count: column_count,
column_width: column_width,
})
}
</%helpers:shorthand>

View file

@ -0,0 +1,66 @@
/* 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="font" sub_properties="font-style font-variant font-weight
font-size line-height font-family">
use properties::longhands::{font_style, font_variant, font_weight, font_size,
line_height, font_family};
let mut nb_normals = 0;
let mut style = None;
let mut variant = None;
let mut weight = None;
let size;
loop {
// Special-case 'normal' because it is valid in each of
// font-style, font-weight and font-variant.
// Leaves the values to None, 'normal' is the initial value for each of them.
if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
nb_normals += 1;
continue;
}
if style.is_none() {
if let Ok(value) = input.try(|input| font_style::parse(context, input)) {
style = Some(value);
continue
}
}
if weight.is_none() {
if let Ok(value) = input.try(|input| font_weight::parse(context, input)) {
weight = Some(value);
continue
}
}
if variant.is_none() {
if let Ok(value) = input.try(|input| font_variant::parse(context, input)) {
variant = Some(value);
continue
}
}
size = Some(try!(font_size::parse(context, input)));
break
}
#[inline]
fn count<T>(opt: &Option<T>) -> u8 {
if opt.is_some() { 1 } else { 0 }
}
if size.is_none() || (count(&style) + count(&weight) + count(&variant) + nb_normals) > 3 {
return Err(())
}
let line_height = if input.try(|input| input.expect_delim('/')).is_ok() {
Some(try!(line_height::parse(context, input)))
} else {
None
};
let family = try!(input.parse_comma_separated(font_family::parse_one_family));
Ok(Longhands {
font_style: style,
font_variant: variant,
font_weight: weight,
font_size: size,
line_height: line_height,
font_family: Some(font_family::SpecifiedValue(family))
})
</%helpers:shorthand>

View file

@ -0,0 +1,14 @@
/* 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" />
// Per CSS-TEXT 6.2, "for legacy reasons, UAs must treat `word-wrap` as an alternate name for
// the `overflow-wrap` property, as if it were a shorthand of `overflow-wrap`."
<%helpers:shorthand name="word-wrap" sub_properties="overflow-wrap">
use properties::longhands::overflow_wrap;
Ok(Longhands {
overflow_wrap: Some(try!(overflow_wrap::parse(context, input))),
})
</%helpers:shorthand>

View file

@ -0,0 +1,92 @@
/* 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="list-style"
sub_properties="list-style-image list-style-position list-style-type">
use properties::longhands::{list_style_image, list_style_position, list_style_type};
// `none` is ambiguous until we've finished parsing the shorthands, so we count the number
// of times we see it.
let mut nones = 0u8;
let (mut image, mut position, mut list_style_type, mut any) = (None, None, None, false);
loop {
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
nones = nones + 1;
if nones > 2 {
return Err(())
}
any = true;
continue
}
if list_style_type.is_none() {
if let Ok(value) = input.try(|input| list_style_type::parse(context, input)) {
list_style_type = Some(value);
any = true;
continue
}
}
if image.is_none() {
if let Ok(value) = input.try(|input| list_style_image::parse(context, input)) {
image = Some(value);
any = true;
continue
}
}
if position.is_none() {
if let Ok(value) = input.try(|input| list_style_position::parse(context, input)) {
position = Some(value);
any = true;
continue
}
}
break
}
// If there are two `none`s, then we can't have a type or image; if there is one `none`,
// then we can't have both a type *and* an image; if there is no `none` then we're fine as
// long as we parsed something.
match (any, nones, list_style_type, image) {
(true, 2, None, None) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(list_style_image::SpecifiedValue::None),
list_style_type: Some(list_style_type::SpecifiedValue::none),
})
}
(true, 1, None, Some(image)) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(image),
list_style_type: Some(list_style_type::SpecifiedValue::none),
})
}
(true, 1, Some(list_style_type), None) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(list_style_image::SpecifiedValue::None),
list_style_type: Some(list_style_type),
})
}
(true, 1, None, None) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(list_style_image::SpecifiedValue::None),
list_style_type: Some(list_style_type::SpecifiedValue::none),
})
}
(true, 0, list_style_type, image) => {
Ok(Longhands {
list_style_position: position,
list_style_image: image,
list_style_type: list_style_type,
})
}
_ => Err(()),
}
</%helpers:shorthand>

View file

@ -0,0 +1,7 @@
/* 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.four_sides_shorthand("margin", "margin-%s", "specified::LengthOrPercentageOrAuto::parse")}

View file

@ -0,0 +1,49 @@
/* 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="outline" sub_properties="outline-color outline-style outline-width">
use properties::longhands::outline_width;
use values::specified;
let _unused = context;
let mut color = None;
let mut style = None;
let mut width = None;
let mut any = false;
loop {
if color.is_none() {
if let Ok(value) = input.try(specified::CSSColor::parse) {
color = Some(value);
any = true;
continue
}
}
if style.is_none() {
if let Ok(value) = input.try(specified::BorderStyle::parse) {
style = Some(value);
any = true;
continue
}
}
if width.is_none() {
if let Ok(value) = input.try(|input| outline_width::parse(context, input)) {
width = Some(value);
any = true;
continue
}
}
break
}
if any {
Ok(Longhands {
outline_color: color,
outline_style: style,
outline_width: width,
})
} else {
Err(())
}
</%helpers:shorthand>

View file

@ -0,0 +1,7 @@
/* 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.four_sides_shorthand("padding", "padding-%s", "specified::LengthOrPercentage::parse")}