style: Implement multi-position gradient color-stops syntax.

This commit adds the multi-position gradient color-stops syntax.

GradientItem::parse_comma_separated is extended to attempt to parse
a LengthOrPercent after each color stop. If it succeeds, it appends
an additional color stop with a duplicate color and the specified
position.

This change is only to the parsing, serialization is left unchanged
as per [1].

[1] https://github.com/w3c/csswg-drafts/issues/2714

Differential Revision: https://phabricator.services.mozilla.com/D7380
This commit is contained in:
Ryan Hunt 2018-10-01 14:26:23 -05:00 committed by Emilio Cobos Álvarez
parent 2cf4e9998a
commit 7f8a3530a3
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C

View file

@ -8,7 +8,7 @@
//! [image]: https://drafts.csswg.org/css-images/#image-values
use Atom;
use cssparser::{Parser, Token};
use cssparser::{Parser, Token, Delimiter};
use custom_properties::SpecifiedValue;
use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseErrorKind;
@ -956,17 +956,43 @@ impl GradientItem {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Vec<Self>, ParseError<'i>> {
let mut items = Vec::new();
let mut seen_stop = false;
let items = input.parse_comma_separated(|input| {
if seen_stop {
if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) {
seen_stop = false;
return Ok(generic::GradientItem::InterpolationHint(hint));
loop {
input.parse_until_before(Delimiter::Comma, |input| {
if seen_stop {
if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) {
seen_stop = false;
items.push(generic::GradientItem::InterpolationHint(hint));
return Ok(());
}
}
let stop = ColorStop::parse(context, input)?;
if let Ok(multi_position) = input.try(|i| LengthOrPercentage::parse(context, i)) {
let stop_color = stop.color.clone();
items.push(generic::GradientItem::ColorStop(stop));
items.push(generic::GradientItem::ColorStop(ColorStop {
color: stop_color,
position: Some(multi_position),
}));
} else {
items.push(generic::GradientItem::ColorStop(stop));
}
seen_stop = true;
Ok(())
})?;
match input.next() {
Err(_) => break,
Ok(&Token::Comma) => continue,
Ok(_) => unreachable!(),
}
seen_stop = true;
ColorStop::parse(context, input).map(generic::GradientItem::ColorStop)
})?;
}
if !seen_stop || items.len() < 2 {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}