diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index ae08f79b2930..532095bc00d2 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -316,6 +316,10 @@ computed_value::T::${to_rust_ident(values.split()[0])} } #[inline] + pub fn get_initial_specified_value() -> SpecifiedValue { + get_initial_value() + } + #[inline] pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { computed_value::T::parse(input) diff --git a/components/style/properties/shorthand/background.mako.rs b/components/style/properties/shorthand/background.mako.rs index 853e55549373..a7dff5047b35 100644 --- a/components/style/properties/shorthand/background.mako.rs +++ b/components/style/properties/shorthand/background.mako.rs @@ -12,172 +12,208 @@ use properties::longhands::{background_image, background_size, background_origin, background_clip}; pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { - 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 + % for name in "image position repeat size attachment origin clip".split(): + let mut any_${name} = false; + % endfor + + let mut background_color = None; + let vec = try!(input.parse_comma_separated(|input| { + % for name in "image position repeat size attachment origin clip".split(): + let mut ${name} = None; + % endfor + + loop { + if background_color.is_none() { + if let Ok(value) = input.try(|input| background_color::parse(context, input)) { + background_color = Some(value); + continue + } + } else { + // color can only be the last element + return Err(()) } - } - if clip.is_none() { - if let Ok(value) = input.try(|input| background_clip::parse(context, input)) { - clip = Some(value); - any = true; - continue + if position.is_none() { + if let Ok(value) = input.try(|input| background_position::single_value::parse(context, input)) { + position = Some(value); + any_position = true; + + // Parse background size, if applicable. + size = input.try(|input| { + try!(input.expect_delim('/')); + background_size::single_value::parse(context, input) + }).ok(); + if let Some(_) = size { + any_size = true; + } + + continue + } } + % for name in "image repeat attachment origin clip".split(): + if ${name}.is_none() { + if let Ok(value) = input.try(|input| background_${name}::single_value::parse(context, input)) { + ${name} = Some(value); + any_${name} = true; + continue + } + } + % endfor + break } - break + Ok((image, position, repeat, size, attachment, origin, clip)) + })); + + if !(any_image || any_position || any_repeat || any_size || + any_attachment || any_origin || any_clip || + background_color.is_some()) { + return Err(()) } - 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(()) + % for name in "image position repeat size attachment origin clip".split(): + let mut background_${name} = if any_${name} { + Some(background_${name}::SpecifiedValue(Vec::new())) + } else { + None + }; + % endfor + + for i in vec { + % for i,name in enumerate("image position repeat size attachment origin clip".split()): + if let Some(ref mut buf) = background_${name} { + if let Some(bg_${name}) = i.${i} { + buf.0.push(bg_${name}) + } else { + buf.0.push(background_${name}::single_value::get_initial_specified_value()) + } + } + % endfor } + + Ok(Longhands { + background_color: background_color, + background_image: background_image, + background_position: background_position, + background_repeat: background_repeat, + background_attachment: background_attachment, + background_size: background_size, + background_origin: background_origin, + background_clip: background_clip, + }) } impl<'a> ToCss for LonghandsToSerialize<'a> { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self.background_color { - DeclaredValue::Value(ref color) => { - try!(color.to_css(dest)); - }, - _ => { - try!(write!(dest, "transparent")); + // mako doesn't like ampersands following `<` + fn extract_value(x: &DeclaredValue) -> Option< &T> { + match *x { + DeclaredValue::Value(ref val) => Some(val), + _ => None, } - }; + } + use std::cmp; + use std::iter::{once, repeat}; + let mut len = 0; + % for name in "image position repeat size attachment origin clip".split(): + len = cmp::max(len, extract_value(self.background_${name}).map(|i| i.0.len()) + .unwrap_or(0)); + % endfor + + let iter = repeat(None).take(len - 1).chain(once(Some(self.background_color))) + % for name in "image position repeat size attachment origin clip".split(): + .zip(extract_value(self.background_${name}).into_iter() + .flat_map(|x| x.0.iter()) + .map(Some).chain(repeat(None))) + % endfor + ; + let mut first = true; + for (((((((color, image), position), repeat), size), attachment), origin), clip) in iter { + if first { + first = false; + } else { + try!(write!(dest, ", ")); + } + match color { + Some(&DeclaredValue::Value(ref color)) => { + try!(color.to_css(dest)); + try!(write!(dest, " ")); + }, + Some(_) => { + try!(write!(dest, "transparent ")); + try!(write!(dest, " ")); + } + // Not yet the last one + None => () + }; - try!(write!(dest, " ")); - match *self.background_image { - DeclaredValue::Value(ref image) => { + if let Some(image) = image { try!(image.to_css(dest)); - }, - _ => { + } else { try!(write!(dest, "none")); } - }; - try!(write!(dest, " ")); + try!(write!(dest, " ")); - try!(self.background_repeat.to_css(dest)); + if let Some(repeat) = repeat { + try!(repeat.to_css(dest)); + } else { + try!(write!(dest, "repeat")); + } - try!(write!(dest, " ")); + try!(write!(dest, " ")); - match *self.background_attachment { - DeclaredValue::Value(ref attachment) => { + if let Some(attachment) = attachment { try!(attachment.to_css(dest)); - }, - _ => { + } else { try!(write!(dest, "scroll")); } - }; - try!(write!(dest, " ")); + try!(write!(dest, " ")); - try!(self.background_position.to_css(dest)); + try!(position.unwrap_or(&background_position::single_value + ::get_initial_specified_value()) + .to_css(dest)); - if let DeclaredValue::Value(ref size) = *self.background_size { - try!(write!(dest, " / ")); - try!(size.to_css(dest)); - } + if let Some(size) = size { + try!(write!(dest, " / ")); + try!(size.to_css(dest)); + } - match (self.background_origin, self.background_clip) { - (&DeclaredValue::Value(ref origin), &DeclaredValue::Value(ref clip)) => { - use properties::longhands::background_origin::computed_value::T as Origin; - use properties::longhands::background_clip::computed_value::T as Clip; - - try!(write!(dest, " ")); - - match (origin, clip) { - (&Origin::padding_box, &Clip::padding_box) => { - try!(origin.to_css(dest)); - }, - (&Origin::border_box, &Clip::border_box) => { - try!(origin.to_css(dest)); - }, - (&Origin::content_box, &Clip::content_box) => { - try!(origin.to_css(dest)); - }, - _ => { - try!(origin.to_css(dest)); - try!(write!(dest, " ")); - try!(clip.to_css(dest)); + match (origin, clip) { + (Some(origin), Some(clip)) => { + use properties::longhands::background_origin::single_value::computed_value::T as Origin; + use properties::longhands::background_clip::single_value::computed_value::T as Clip; + + try!(write!(dest, " ")); + + match (origin, clip) { + (&Origin::padding_box, &Clip::padding_box) => { + try!(origin.to_css(dest)); + }, + (&Origin::border_box, &Clip::border_box) => { + try!(origin.to_css(dest)); + }, + (&Origin::content_box, &Clip::content_box) => { + try!(origin.to_css(dest)); + }, + _ => { + try!(origin.to_css(dest)); + try!(write!(dest, " ")); + try!(clip.to_css(dest)); + } } - } - }, - (&DeclaredValue::Value(ref origin), _) => { - try!(write!(dest, " ")); - try!(origin.to_css(dest)); - }, - (_, &DeclaredValue::Value(ref clip)) => { - try!(write!(dest, " ")); - try!(clip.to_css(dest)); - }, - _ => {} - }; + }, + (Some(origin), _) => { + try!(write!(dest, " ")); + try!(origin.to_css(dest)); + }, + (_, Some(clip)) => { + try!(write!(dest, " ")); + try!(clip.to_css(dest)); + }, + _ => {} + }; + } Ok(()) diff --git a/components/style/properties/shorthand/outline.mako.rs b/components/style/properties/shorthand/outline.mako.rs index c00294f45df8..d09fe2152b2d 100644 --- a/components/style/properties/shorthand/outline.mako.rs +++ b/components/style/properties/shorthand/outline.mako.rs @@ -89,8 +89,8 @@ } // TODO: Border radius for the radius shorthand is not implemented correctly yet - impl<'a> ToCss for LonghandsToSerialize<'a> { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + impl<'a> LonghandsToSerialize<'a> { + fn to_css_declared(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { try!(self._moz_outline_radius_topleft.to_css(dest)); try!(write!(dest, " "));