style: Refactor GenericGradient for conic-gradient support.

Differential Revision: https://phabricator.services.mozilla.com/D62923
This commit is contained in:
Tim Nguyen 2020-02-15 22:04:35 +00:00 committed by Emilio Cobos Álvarez
parent fc88e908d5
commit 25b265a10f
4 changed files with 120 additions and 105 deletions

View file

@ -70,10 +70,6 @@ impl SpecifiedValueInfo for Gradient {
}
}
/// A specified gradient kind.
pub type GradientKind =
generic::GradientKind<LineDirection, NonNegativeLength, NonNegativeLengthPercentage, Position>;
/// A specified gradient line direction.
///
/// FIXME(emilio): This should be generic over Angle.
@ -245,25 +241,12 @@ impl Parse for Gradient {
}
};
let (kind, items) = input.parse_nested_block(|i| {
let shape = match shape {
Shape::Linear => GradientKind::parse_linear(context, i, &mut compat_mode)?,
Shape::Radial => GradientKind::parse_radial(context, i, &mut compat_mode)?,
};
let items = generic::GradientItem::parse_comma_separated(context, i)?;
Ok((shape, items))
})?;
if items.len() < 2 {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(Gradient {
items,
repeating,
kind,
compat_mode,
})
Ok(input.parse_nested_block(|i| {
Ok(match shape {
Shape::Linear => Self::parse_linear(context, i, repeating, &mut compat_mode)?,
Shape::Radial => Self::parse_radial(context, i, repeating, compat_mode)?,
})
})?)
}
}
@ -383,16 +366,21 @@ impl Gradient {
let ident = input.expect_ident_cloned()?;
input.expect_comma()?;
let (kind, reverse_stops) = match_ignore_ascii_case! { &ident,
Ok(match_ignore_ascii_case! { &ident,
"linear" => {
let first = Point::parse(context, input)?;
input.expect_comma()?;
let second = Point::parse(context, input)?;
let direction = LineDirection::from_points(first, second);
let kind = generic::GradientKind::Linear(direction);
let items = Gradient::parse_webkit_gradient_stops(context, input, false)?;
(kind, false)
generic::Gradient::Linear {
direction,
items,
repeating: false,
compat_mode: GradientCompatMode::Modern,
}
},
"radial" => {
let first_point = Point::parse(context, input)?;
@ -412,16 +400,28 @@ impl Gradient {
let rad = Circle::Radius(NonNegative(Length::from_px(radius.value)));
let shape = generic::EndingShape::Circle(rad);
let position: Position = point.into();
let items = Gradient::parse_webkit_gradient_stops(context, input, reverse_stops)?;
let kind = generic::GradientKind::Radial(shape, position);
(kind, reverse_stops)
generic::Gradient::Radial {
shape,
position,
items,
repeating: false,
compat_mode: GradientCompatMode::Modern,
}
},
_ => {
let e = SelectorParseErrorKind::UnexpectedIdent(ident.clone());
return Err(input.new_custom_error(e));
},
};
})
}
fn parse_webkit_gradient_stops<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
reverse_stops: bool,
) -> Result<crate::OwnedSlice<generic::GradientItem<Color, LengthPercentage>>, ParseError<'i>> {
let mut items = input
.try(|i| {
i.expect_comma()?;
@ -500,22 +500,29 @@ impl Gradient {
}
})
}
Ok(generic::Gradient {
kind,
items: items.into(),
repeating: false,
compat_mode: GradientCompatMode::Modern,
})
Ok(items.into())
}
/// Not used for -webkit-gradient syntax.
fn parse_stops<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<crate::OwnedSlice<generic::GradientItem<Color, LengthPercentage>>, ParseError<'i>> {
let items = generic::GradientItem::parse_comma_separated(context, input)?;
if items.len() < 2 {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(items)
}
}
impl GradientKind {
/// Parses a linear gradient.
/// GradientCompatMode can change during `-moz-` prefixed gradient parsing if it come across a `to` keyword.
fn parse_linear<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
repeating: bool,
compat_mode: &mut GradientCompatMode,
) -> Result<Self, ParseError<'i>> {
let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode))
@ -523,23 +530,33 @@ impl GradientKind {
input.expect_comma()?;
d
} else {
match *compat_mode {
match compat_mode {
GradientCompatMode::Modern => {
LineDirection::Vertical(VerticalPositionKeyword::Bottom)
},
_ => LineDirection::Vertical(VerticalPositionKeyword::Top),
}
};
Ok(generic::GradientKind::Linear(direction))
let items = Gradient::parse_stops(context, input)?;
Ok(Gradient::Linear {
direction,
items,
repeating,
compat_mode: *compat_mode,
})
}
/// Parses a radial gradient.
fn parse_radial<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
compat_mode: &mut GradientCompatMode,
repeating: bool,
compat_mode: GradientCompatMode,
) -> Result<Self, ParseError<'i>> {
let (shape, position) = match *compat_mode {
let (shape, position) = match compat_mode {
GradientCompatMode::Modern => {
let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode));
let shape = input.try(|i| EndingShape::parse(context, i, compat_mode));
let position = input.try(|i| {
i.expect_ident_matching("at")?;
Position::parse(context, i)
@ -552,7 +569,7 @@ impl GradientKind {
if position.is_ok() {
i.expect_comma()?;
}
EndingShape::parse(context, i, *compat_mode)
EndingShape::parse(context, i, compat_mode)
});
(shape, position.ok())
},
@ -567,7 +584,16 @@ impl GradientKind {
});
let position = position.unwrap_or(Position::center());
Ok(generic::GradientKind::Radial(shape, position))
let items = Gradient::parse_stops(context, input)?;
Ok(Gradient::Radial {
shape,
position,
items,
repeating,
compat_mode,
})
}
}

View file

@ -29,7 +29,7 @@ use style_traits::values::specified::AllowedNumericType;
use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind};
pub use super::image::{EndingShape as GradientEndingShape, Gradient};
pub use super::image::{GradientKind, Image};
pub use super::image::Image;
pub use crate::values::specified::calc::CalcLengthPercentage;
/// Number of app units per pixel

View file

@ -56,7 +56,7 @@ pub use self::font::{FontVariantAlternates, FontWeight};
pub use self::font::{FontVariantEastAsian, FontVariationSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
pub use self::image::{EndingShape as GradientEndingShape, Gradient};
pub use self::image::{GradientKind, Image, MozImageRect};
pub use self::image::{Image, MozImageRect};
pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth};
pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLengthOrNumber};
pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};