Support serializing vector backgrounds in shorthand form

This commit is contained in:
Manish Goregaokar 2016-08-19 21:27:36 +05:30
parent 979a2798d5
commit 66cdf9ae4f
3 changed files with 176 additions and 136 deletions

View file

@ -316,6 +316,10 @@
computed_value::T::${to_rust_ident(values.split()[0])} computed_value::T::${to_rust_ident(values.split()[0])}
} }
#[inline] #[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
get_initial_value()
}
#[inline]
pub fn parse(_context: &ParserContext, input: &mut Parser) pub fn parse(_context: &ParserContext, input: &mut Parser)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ()> {
computed_value::T::parse(input) computed_value::T::parse(input)

View file

@ -12,142 +12,177 @@
use properties::longhands::{background_image, background_size, background_origin, background_clip}; use properties::longhands::{background_image, background_size, background_origin, background_clip};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
let mut color = None; % for name in "image position repeat size attachment origin clip".split():
let mut image = None; let mut any_${name} = false;
let mut position = None; % endfor
let mut repeat = None;
let mut size = None; let mut background_color = None;
let mut attachment = None; let vec = try!(input.parse_comma_separated(|input| {
let mut any = false; % for name in "image position repeat size attachment origin clip".split():
let mut origin = None; let mut ${name} = None;
let mut clip = None; % endfor
loop { 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 position.is_none() { if position.is_none() {
if let Ok(value) = input.try(|input| background_position::parse(context, input)) { if let Ok(value) = input.try(|input| background_position::single_value::parse(context, input)) {
position = Some(value); position = Some(value);
any = true; any_position = true;
// Parse background size, if applicable. // Parse background size, if applicable.
size = input.try(|input| { size = input.try(|input| {
try!(input.expect_delim('/')); try!(input.expect_delim('/'));
background_size::parse(context, input) background_size::single_value::parse(context, input)
}).ok(); }).ok();
if let Some(_) = size {
any_size = true;
}
continue continue
} }
} }
if color.is_none() { % for name in "image repeat attachment origin clip".split():
if let Ok(value) = input.try(|input| background_color::parse(context, input)) { if ${name}.is_none() {
color = Some(value); if let Ok(value) = input.try(|input| background_${name}::single_value::parse(context, input)) {
any = true; ${name} = Some(value);
continue any_${name} = true;
}
}
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 continue
} }
} }
% endfor
break break
} }
Ok((image, position, repeat, size, attachment, origin, clip))
}));
if any { if !(any_image || any_position || any_repeat || any_size ||
Ok(Longhands { any_attachment || any_origin || any_clip ||
background_color: color, background_color.is_some()) {
background_image: image, return Err(())
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> { impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self.background_color { // mako doesn't like ampersands following `<`
DeclaredValue::Value(ref color) => { fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
try!(color.to_css(dest)); match *x {
}, DeclaredValue::Value(ref val) => Some(val),
_ => { _ => None,
try!(write!(dest, "transparent"));
} }
}
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 { if let Some(image) = image {
DeclaredValue::Value(ref image) => {
try!(image.to_css(dest)); try!(image.to_css(dest));
}, } else {
_ => {
try!(write!(dest, "none")); 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 { if let Some(attachment) = attachment {
DeclaredValue::Value(ref attachment) => {
try!(attachment.to_css(dest)); try!(attachment.to_css(dest));
}, } else {
_ => {
try!(write!(dest, "scroll")); 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 { if let Some(size) = size {
try!(write!(dest, " / ")); try!(write!(dest, " / "));
try!(size.to_css(dest)); try!(size.to_css(dest));
} }
match (self.background_origin, self.background_clip) { match (origin, clip) {
(&DeclaredValue::Value(ref origin), &DeclaredValue::Value(ref clip)) => { (Some(origin), Some(clip)) => {
use properties::longhands::background_origin::computed_value::T as Origin; use properties::longhands::background_origin::single_value::computed_value::T as Origin;
use properties::longhands::background_clip::computed_value::T as Clip; use properties::longhands::background_clip::single_value::computed_value::T as Clip;
try!(write!(dest, " ")); try!(write!(dest, " "));
@ -168,16 +203,17 @@
} }
} }
}, },
(&DeclaredValue::Value(ref origin), _) => { (Some(origin), _) => {
try!(write!(dest, " ")); try!(write!(dest, " "));
try!(origin.to_css(dest)); try!(origin.to_css(dest));
}, },
(_, &DeclaredValue::Value(ref clip)) => { (_, Some(clip)) => {
try!(write!(dest, " ")); try!(write!(dest, " "));
try!(clip.to_css(dest)); try!(clip.to_css(dest));
}, },
_ => {} _ => {}
}; };
}
Ok(()) Ok(())

View file

@ -89,8 +89,8 @@
} }
// TODO: Border radius for the radius shorthand is not implemented correctly yet // TODO: Border radius for the radius shorthand is not implemented correctly yet
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self._moz_outline_radius_topleft.to_css(dest)); try!(self._moz_outline_radius_topleft.to_css(dest));
try!(write!(dest, " ")); try!(write!(dest, " "));