Parse interpolation hints (fixes #15166)

This commit is contained in:
Anthony Ramine 2017-04-27 12:52:04 +02:00
parent 8824a68063
commit ae82cdab34
6 changed files with 152 additions and 57 deletions

View file

@ -92,8 +92,8 @@ impl Image {
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Gradient {
/// The color stops.
pub stops: Vec<ColorStop>,
/// The color stops and interpolation hints.
pub items: Vec<GradientItem>,
/// True if this is a repeating gradient.
pub repeating: bool,
/// Gradients can be linear or radial.
@ -132,13 +132,13 @@ impl ToCss for Gradient {
}
},
}
for stop in &self.stops {
for item in &self.items {
if !skipcomma {
try!(dest.write_str(", "));
} else {
skipcomma = false;
}
try!(stop.to_css(dest));
try!(item.to_css(dest));
}
dest.write_str(")")
}
@ -148,18 +148,18 @@ impl Gradient {
/// Parses a gradient from the given arguments.
pub fn parse_function(context: &ParserContext, input: &mut Parser) -> Result<Gradient, ()> {
fn parse<F>(context: &ParserContext, input: &mut Parser, parse_kind: F)
-> Result<(GradientKind, Vec<ColorStop>), ()>
-> Result<(GradientKind, Vec<GradientItem>), ()>
where F: FnOnce(&ParserContext, &mut Parser) -> Result<GradientKind, ()>
{
input.parse_nested_block(|input| {
let kind = try!(parse_kind(context, input));
let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i)));
Ok((kind, stops))
let items = try!(Gradient::parse_items(context, input));
Ok((kind, items))
})
};
let mut repeating = false;
let mut compat_mode = CompatMode::Modern;
let (gradient_kind, stops) = match_ignore_ascii_case! { &try!(input.expect_function()),
let (gradient_kind, items) = match_ignore_ascii_case! { &try!(input.expect_function()),
"linear-gradient" => {
try!(parse(context, input, GradientKind::parse_modern_linear))
},
@ -195,18 +195,31 @@ impl Gradient {
_ => { return Err(()); }
};
// https://drafts.csswg.org/css-images/#typedef-color-stop-list
if stops.len() < 2 {
return Err(())
}
Ok(Gradient {
stops: stops,
items: items,
repeating: repeating,
gradient_kind: gradient_kind,
compat_mode: compat_mode,
})
}
fn parse_items(context: &ParserContext, input: &mut Parser) -> Result<Vec<GradientItem>, ()> {
let mut seen_stop = false;
let items = try!(input.parse_comma_separated(|input| {
if seen_stop {
if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) {
seen_stop = false;
return Ok(GradientItem::InterpolationHint(hint));
}
}
seen_stop = true;
ColorStop::parse(context, input).map(GradientItem::ColorStop)
}));
if !seen_stop || items.len() < 2 {
return Err(());
}
Ok(items)
}
}
/// Specified values for CSS linear or radial gradients.
@ -489,7 +502,27 @@ impl AngleOrCorner {
}
}
/// Specified values for one color stop in a linear gradient.
/// Specified values for color stops and interpolation hints.
/// https://drafts.csswg.org/css-images-4/#color-stop-syntax
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GradientItem {
/// A color stop.
ColorStop(ColorStop),
/// An interpolation hint.
InterpolationHint(LengthOrPercentage),
}
impl ToCss for GradientItem {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
GradientItem::ColorStop(ref stop) => stop.to_css(dest),
GradientItem::InterpolationHint(ref hint) => hint.to_css(dest),
}
}
}
/// Specified values for one color stop in a gradient.
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]