diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index f6206a9fb25..56e3d183d83 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -51,7 +51,7 @@ pub use self::GenericImage as Image; /// #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(C)] -pub struct GenericGradient< +pub enum GenericGradient< LineDirection, LengthPercentage, NonNegativeLength, @@ -59,19 +59,30 @@ pub struct GenericGradient< Position, Color, > { - /// Gradients can be linear or radial. - pub kind: GenericGradientKind< - LineDirection, - NonNegativeLength, - NonNegativeLengthPercentage, - Position, - >, - /// The color stops and interpolation hints. - pub items: crate::OwnedSlice>, - /// True if this is a repeating gradient. - pub repeating: bool, - /// Compatibility mode. - pub compat_mode: GradientCompatMode, + /// A linear gradient. + Linear { + /// Line direction + direction: LineDirection, + /// The color stops and interpolation hints. + items: crate::OwnedSlice>, + /// True if this is a repeating gradient. + repeating: bool, + /// Compatibility mode. + compat_mode: GradientCompatMode, + }, + /// A radial gradient. + Radial { + /// Shape of gradient + shape: GenericEndingShape, + /// Center of gradient + position: Position, + /// The color stops and interpolation hints. + items: crate::OwnedSlice>, + /// True if this is a repeating gradient. + repeating: bool, + /// Compatibility mode. + compat_mode: GradientCompatMode, + }, } pub use self::GenericGradient as Gradient; @@ -88,26 +99,6 @@ pub enum GradientCompatMode { Moz, } -/// A gradient kind. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] -#[repr(C, u8)] -pub enum GenericGradientKind< - LineDirection, - NonNegativeLength, - NonNegativeLengthPercentage, - Position, -> { - /// A linear gradient. - Linear(LineDirection), - /// A radial gradient. - Radial( - GenericEndingShape, - Position, - ), -} - -pub use self::GenericGradientKind as GradientKind; - /// A radial gradient's ending shape. #[derive( Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, @@ -330,32 +321,39 @@ where where W: Write, { - match self.compat_mode { + let (compat_mode, repeating) = match *self { + Gradient::Linear { compat_mode, repeating, .. } => (compat_mode, repeating), + Gradient::Radial { compat_mode, repeating, .. } => (compat_mode, repeating), + }; + + match compat_mode { GradientCompatMode::WebKit => dest.write_str("-webkit-")?, GradientCompatMode::Moz => dest.write_str("-moz-")?, _ => {}, } - if self.repeating { + if repeating { dest.write_str("repeating-")?; } - dest.write_str(self.kind.label())?; - dest.write_str("-gradient(")?; - let mut skip_comma = match self.kind { - GradientKind::Linear(ref direction) if direction.points_downwards(self.compat_mode) => { - true + + let (items, mut skip_comma) = match *self { + Gradient::Linear { ref direction, compat_mode, ref items, .. } => { + dest.write_str("linear-gradient(")?; + if !direction.points_downwards(compat_mode) { + direction.to_css(dest, compat_mode)?; + (items, false) + } else { + (items, true) + } }, - GradientKind::Linear(ref direction) => { - direction.to_css(dest, self.compat_mode)?; - false - }, - GradientKind::Radial(ref shape, ref position) => { + Gradient::Radial { ref shape, ref position, compat_mode, ref items, .. } => { + dest.write_str("radial-gradient(")?; let omit_shape = match *shape { EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) | EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => true, _ => false, }; - if self.compat_mode == GradientCompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { if !omit_shape { shape.to_css(dest)?; dest.write_str(" ")?; @@ -369,10 +367,10 @@ where shape.to_css(dest)?; } } - false + (items, false) }, }; - for item in &*self.items { + for item in &**items { if !skip_comma { dest.write_str(", ")?; } @@ -383,15 +381,6 @@ where } } -impl GradientKind { - fn label(&self) -> &str { - match *self { - GradientKind::Linear(..) => "linear", - GradientKind::Radial(..) => "radial", - } - } -} - /// The direction of a linear gradient. pub trait LineDirection { /// Whether this direction points towards, and thus can be omitted. diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index 13e06d44c57..fdc3a795db0 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -70,10 +70,6 @@ impl SpecifiedValueInfo for Gradient { } } -/// A specified gradient kind. -pub type GradientKind = - generic::GradientKind; - /// 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>, 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>, 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> { 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> { - 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, + }) } } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index f7d7023a51a..16b9bf003e6 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -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 diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index aa8bda5c227..84e2b747234 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -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};