diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 68f8d2327d5..4ce44136279 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -16,18 +16,16 @@ use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue, Matrix4x4Comp use crate::gecko_bindings::structs::{nsStyleImage, nsresult}; use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; use crate::stylesheets::RulesMutateError; -use crate::values::computed::image::LineDirection; use crate::values::computed::transform::Matrix3D; use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::{Angle, Gradient, Image}; use crate::values::computed::{Integer, LengthPercentage}; use crate::values::computed::{Length, Percentage, TextAlign}; use crate::values::generics::grid::{TrackListValue, TrackSize}; -use crate::values::generics::image::{CompatMode, Image as GenericImage}; +use crate::values::generics::image::GenericImage; use crate::values::generics::rect::Rect; use crate::Zero; use app_units::Au; -use std::f32::consts::PI; use style_traits::values::specified::AllowedNumericType; impl From for nsStyleCoord_CalcValue { @@ -64,56 +62,11 @@ impl From for CoordDataValue { } } -fn line_direction(horizontal: LengthPercentage, vertical: LengthPercentage) -> LineDirection { - use crate::values::specified::position::{X, Y}; - - let horizontal_percentage = horizontal.as_percentage(); - let vertical_percentage = vertical.as_percentage(); - - let horizontal_as_corner = horizontal_percentage.and_then(|percentage| { - if percentage.0 == 0.0 { - Some(X::Left) - } else if percentage.0 == 1.0 { - Some(X::Right) - } else { - None - } - }); - - let vertical_as_corner = vertical_percentage.and_then(|percentage| { - if percentage.0 == 0.0 { - Some(Y::Top) - } else if percentage.0 == 1.0 { - Some(Y::Bottom) - } else { - None - } - }); - - if let (Some(hc), Some(vc)) = (horizontal_as_corner, vertical_as_corner) { - return LineDirection::Corner(hc, vc); - } - - if let Some(hc) = horizontal_as_corner { - if vertical_percentage == Some(Percentage(0.5)) { - return LineDirection::Horizontal(hc); - } - } - - if let Some(vc) = vertical_as_corner { - if horizontal_percentage == Some(Percentage(0.5)) { - return LineDirection::Vertical(vc); - } - } - - unreachable!("Unexpected line direction"); -} - impl nsStyleImage { /// Set a given Servo `Image` value into this `nsStyleImage`. pub fn set(&mut self, image: Image) { match image { - GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient), + GenericImage::Gradient(boxed_gradient) => self.set_gradient(boxed_gradient), GenericImage::Url(ref url) => unsafe { bindings::Gecko_SetLayerImageImageValue(self, url); }, @@ -144,172 +97,9 @@ impl nsStyleImage { } } - // FIXME(emilio): This is really complex, we should use cbindgen for this. - fn set_gradient(&mut self, gradient: Gradient) { - use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER; - use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; - use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; - use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE; - use crate::values::generics::image::{ - Circle, Ellipse, EndingShape, GradientKind, ShapeExtent, - }; - use crate::values::specified::position::{X, Y}; - - let stop_count = gradient.items.len(); - if stop_count >= ::std::u32::MAX as usize { - warn!("stylo: Prevented overflow due to too many gradient stops"); - return; - } - - let gecko_gradient = match gradient.kind { - GradientKind::Linear(direction) => { - let gecko_gradient = unsafe { - bindings::Gecko_CreateGradient( - structs::NS_STYLE_GRADIENT_SHAPE_LINEAR as u8, - structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8, - gradient.repeating, - gradient.compat_mode != CompatMode::Modern, - gradient.compat_mode == CompatMode::Moz, - stop_count as u32, - ) - }; - - match direction { - LineDirection::Angle(angle) => { - // PI radians (180deg) is ignored because it is the default value. - if angle.radians() != PI { - unsafe { - (*gecko_gradient).mAngle.set(angle); - } - } - }, - LineDirection::Horizontal(x) => { - let x = match x { - X::Left => 0.0, - X::Right => 1.0, - }; - - unsafe { - (*gecko_gradient) - .mBgPosX - .set_value(CoordDataValue::Percent(x)); - (*gecko_gradient) - .mBgPosY - .set_value(CoordDataValue::Percent(0.5)); - } - }, - LineDirection::Vertical(y) => { - // Although bottom is the default value, we can not ignore - // it here, because the rendering code of Gecko relies on - // this to behave correctly for legacy mode. - let y = match y { - Y::Top => 0.0, - Y::Bottom => 1.0, - }; - unsafe { - (*gecko_gradient) - .mBgPosX - .set_value(CoordDataValue::Percent(0.5)); - (*gecko_gradient) - .mBgPosY - .set_value(CoordDataValue::Percent(y)); - } - }, - LineDirection::Corner(horiz, vert) => { - let percent_x = match horiz { - X::Left => 0.0, - X::Right => 1.0, - }; - let percent_y = match vert { - Y::Top => 0.0, - Y::Bottom => 1.0, - }; - - unsafe { - (*gecko_gradient) - .mBgPosX - .set_value(CoordDataValue::Percent(percent_x)); - (*gecko_gradient) - .mBgPosY - .set_value(CoordDataValue::Percent(percent_y)); - } - }, - } - gecko_gradient - }, - GradientKind::Radial(shape, position) => { - let keyword_to_gecko_size = |keyword| match keyword { - ShapeExtent::ClosestSide => CLOSEST_SIDE, - ShapeExtent::FarthestSide => FARTHEST_SIDE, - ShapeExtent::ClosestCorner => CLOSEST_CORNER, - ShapeExtent::FarthestCorner => FARTHEST_CORNER, - ShapeExtent::Contain => CLOSEST_SIDE, - ShapeExtent::Cover => FARTHEST_CORNER, - }; - let (gecko_shape, gecko_size) = match shape { - EndingShape::Circle(ref circle) => { - let size = match *circle { - Circle::Extent(extent) => keyword_to_gecko_size(extent), - _ => structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE, - }; - (structs::NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8) - }, - EndingShape::Ellipse(ref ellipse) => { - let size = match *ellipse { - Ellipse::Extent(extent) => keyword_to_gecko_size(extent), - _ => structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE, - }; - ( - structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL as u8, - size as u8, - ) - }, - }; - - let gecko_gradient = unsafe { - bindings::Gecko_CreateGradient( - gecko_shape, - gecko_size, - gradient.repeating, - gradient.compat_mode == CompatMode::Moz, - gradient.compat_mode == CompatMode::Moz, - stop_count as u32, - ) - }; - - // Setting radius values depending shape - match shape { - EndingShape::Circle(Circle::Radius(length)) => unsafe { - let au = length.to_i32_au(); - (*gecko_gradient) - .mRadiusX - .set_value(CoordDataValue::Coord(au)); - (*gecko_gradient) - .mRadiusY - .set_value(CoordDataValue::Coord(au)); - }, - EndingShape::Ellipse(Ellipse::Radii(x, y)) => unsafe { - (*gecko_gradient).mRadiusX.set(x); - (*gecko_gradient).mRadiusY.set(y); - }, - _ => {}, - } - unsafe { - (*gecko_gradient).mBgPosX.set(position.horizontal); - (*gecko_gradient).mBgPosY.set(position.vertical); - } - - gecko_gradient - }, - }; - - for (index, item) in gradient.items.into_iter().enumerate() { - let gecko_stop = unsafe { &mut (*gecko_gradient).mStops[index] }; - *gecko_stop = item; - } - + fn set_gradient(&mut self, gradient: Box) { unsafe { - bindings::Gecko_SetGradientImageValue(self, gecko_gradient); + bindings::Gecko_SetGradientImageValue(self, Box::into_raw(gradient)); } } @@ -352,7 +142,9 @@ impl nsStyleImage { } }, nsStyleImageType::eStyleImageType_Gradient => { - Some(GenericImage::Gradient(self.get_gradient())) + let gradient: &Gradient = + &**self.__bindgen_anon_1.mGradient.as_ref(); + Some(GenericImage::Gradient(Box::new(gradient.clone()))) }, nsStyleImageType::eStyleImageType_Element => { use crate::gecko_string_cache::Atom; @@ -368,131 +160,6 @@ impl nsStyleImage { .expect("Null image request?"); ComputedImageUrl::from_image_request(image_request) } - - unsafe fn get_gradient(self: &nsStyleImage) -> Box { - use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER; - use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; - use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; - use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE; - use crate::values::computed::position::Position; - use crate::values::generics::image::{Circle, Ellipse}; - use crate::values::generics::image::{EndingShape, GradientKind, ShapeExtent}; - - let gecko_gradient = bindings::Gecko_GetGradientImageValue(self) - .as_ref() - .unwrap(); - let horizontal_style = LengthPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosX); - let vertical_style = LengthPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosY); - - let kind = match gecko_gradient.mShape as u32 { - structs::NS_STYLE_GRADIENT_SHAPE_LINEAR => { - let angle = Angle::from_gecko_style_coord(&gecko_gradient.mAngle); - let line_direction = match (angle, horizontal_style, vertical_style) { - (Some(a), None, None) => LineDirection::Angle(a), - (None, None, None) => LineDirection::Angle(Angle::from_radians(PI)), - (None, Some(horizontal), Some(vertical)) => { - line_direction(horizontal, vertical) - }, - _ => { - unreachable!("unexpected line direction for linear gradient direction"); - }, - }; - GradientKind::Linear(line_direction) - }, - _ => { - let gecko_size_to_keyword = |gecko_size| { - match gecko_size { - CLOSEST_SIDE => ShapeExtent::ClosestSide, - FARTHEST_SIDE => ShapeExtent::FarthestSide, - CLOSEST_CORNER => ShapeExtent::ClosestCorner, - FARTHEST_CORNER => ShapeExtent::FarthestCorner, - // FIXME: We should support ShapeExtent::Contain and ShapeExtent::Cover. - // But we can't choose those yet since Gecko does not support both values. - // https://bugzilla.mozilla.org/show_bug.cgi?id=1217664 - _ => panic!("Found unexpected gecko_size"), - } - }; - - let shape = match gecko_gradient.mShape as u32 { - structs::NS_STYLE_GRADIENT_SHAPE_CIRCULAR => { - let circle = match gecko_gradient.mSize as u32 { - structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => { - let radius = - Length::from_gecko_style_coord(&gecko_gradient.mRadiusX) - .expect("mRadiusX could not convert to Length"); - debug_assert_eq!( - radius, - Length::from_gecko_style_coord(&gecko_gradient.mRadiusY) - .unwrap() - ); - Circle::Radius(radius) - }, - size => Circle::Extent(gecko_size_to_keyword(size)), - }; - EndingShape::Circle(circle) - }, - structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL => { - let length_percentage_keyword = match gecko_gradient.mSize as u32 { - structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => match ( - LengthPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusX), - LengthPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusY), - ) { - (Some(x), Some(y)) => Ellipse::Radii(x, y), - _ => { - debug_assert!( - false, - "mRadiusX, mRadiusY could not convert to LengthPercentage" - ); - Ellipse::Radii( - LengthPercentage::zero(), - LengthPercentage::zero(), - ) - }, - }, - size => Ellipse::Extent(gecko_size_to_keyword(size)), - }; - EndingShape::Ellipse(length_percentage_keyword) - }, - _ => panic!("Found unexpected mShape"), - }; - - let position = match (horizontal_style, vertical_style) { - (Some(horizontal), Some(vertical)) => Position { - horizontal, - vertical, - }, - _ => { - debug_assert!( - false, - "mRadiusX, mRadiusY could not convert to LengthPercentage" - ); - Position { - horizontal: LengthPercentage::zero(), - vertical: LengthPercentage::zero(), - } - }, - }; - - GradientKind::Radial(shape, position) - }, - }; - - let items = gecko_gradient.mStops.iter().cloned().collect(); - let compat_mode = if gecko_gradient.mMozLegacySyntax { - CompatMode::Moz - } else if gecko_gradient.mLegacySyntax { - CompatMode::WebKit - } else { - CompatMode::Modern - }; - - Box::new(Gradient { - items, - repeating: gecko_gradient.mRepeating, - kind, - compat_mode, - }) - } } pub mod basic_shape { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 9f56c42cc2b..3ff3be2a2ec 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -55,6 +55,7 @@ use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::BorderStyle; use crate::values::computed::font::FontSize; use crate::values::generics::column::ColumnCount; +use crate::values::generics::image::ImageLayer; use crate::values::generics::transform::TransformStyle; use crate::values::generics::url::UrlOrNone; @@ -982,7 +983,7 @@ fn static_assert() { Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource); } - if let Either::Second(image) = image { + if let ImageLayer::Image(image) = image { self.gecko.mBorderImageSource.set(image); } } @@ -999,11 +1000,9 @@ fn static_assert() { } pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T { - use crate::values::None_; - match unsafe { self.gecko.mBorderImageSource.into_image() } { - Some(image) => Either::Second(image), - None => Either::First(None_), + Some(image) => ImageLayer::Image(image), + None => ImageLayer::None, } } @@ -2714,22 +2713,20 @@ fn static_assert() { for (image, geckoimage) in images.zip(self.gecko.${image_layers_field} .mLayers.iter_mut()) { - if let Either::Second(image) = image { + if let ImageLayer::Image(image) = image { geckoimage.mImage.set(image) } } } pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T { - use crate::values::None_; - longhands::${shorthand}_image::computed_value::List( self.gecko.${image_layers_field}.mLayers.iter() .take(self.gecko.${image_layers_field}.mImageCount as usize) .map(|ref layer| { match unsafe { layer.mImage.into_image() } { - Some(image) => Either::Second(image), - None => Either::First(None_), + Some(image) => ImageLayer::Image(image), + None => ImageLayer::None, } }).collect() ) diff --git a/components/style/properties/longhands/background.mako.rs b/components/style/properties/longhands/background.mako.rs index 9c66e4676f9..e9e866983c0 100644 --- a/components/style/properties/longhands/background.mako.rs +++ b/components/style/properties/longhands/background.mako.rs @@ -22,8 +22,8 @@ ${helpers.predefined_type( ${helpers.predefined_type( "background-image", "ImageLayer", - initial_value="Either::First(None_)", - initial_specified_value="Either::First(None_)", + initial_value="computed::ImageLayer::none()", + initial_specified_value="specified::ImageLayer::none()", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector="True", animation_value_type="discrete", diff --git a/components/style/properties/longhands/border.mako.rs b/components/style/properties/longhands/border.mako.rs index 7909372be17..66544a44858 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -107,8 +107,8 @@ ${helpers.single_keyword( ${helpers.predefined_type( "border-image-source", "ImageLayer", - initial_value="Either::First(None_)", - initial_specified_value="Either::First(None_)", + initial_value="computed::ImageLayer::none()", + initial_specified_value="specified::ImageLayer::none()", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector=False, animation_value_type="discrete", diff --git a/components/style/properties/longhands/svg.mako.rs b/components/style/properties/longhands/svg.mako.rs index 8e93d03dbb1..9f0e0db9fbc 100644 --- a/components/style/properties/longhands/svg.mako.rs +++ b/components/style/properties/longhands/svg.mako.rs @@ -181,8 +181,8 @@ ${helpers.single_keyword( ${helpers.predefined_type( "mask-image", "ImageLayer", - "Either::First(None_)", - initial_specified_value="Either::First(None_)", + initial_value="computed::ImageLayer::none()", + initial_specified_value="specified::ImageLayer::none()", parse_method="parse_with_cors_anonymous", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image", vector=True, diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index ea2f4e9530b..3012eece0e7 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -11,41 +11,41 @@ use crate::values::computed::position::Position; use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::{Angle, Color, Context}; use crate::values::computed::{Length, LengthPercentage, NumberOrPercentage, ToComputedValue}; -use crate::values::generics::image::{self as generic, CompatMode}; +use crate::values::generics::image::{self as generic, GradientCompatMode}; use crate::values::specified::image::LineDirection as SpecifiedLineDirection; -use crate::values::specified::position::{X, Y}; -use crate::values::{Either, None_}; +use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword}; use std::f32::consts::PI; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; /// A computed image layer. -pub type ImageLayer = Either; +pub type ImageLayer = generic::GenericImageLayer; /// Computed values for an image according to CSS-IMAGES. /// -pub type Image = generic::Image; +pub type Image = generic::GenericImage; /// Computed values for a CSS gradient. /// pub type Gradient = - generic::Gradient; + generic::GenericGradient; /// A computed gradient kind. pub type GradientKind = - generic::GradientKind; + generic::GenericGradientKind; /// A computed gradient line direction. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue)] +#[repr(C, u8)] pub enum LineDirection { /// An angle. Angle(Angle), /// A horizontal direction. - Horizontal(X), + Horizontal(HorizontalPositionKeyword), /// A vertical direction. - Vertical(Y), + Vertical(VerticalPositionKeyword), /// A corner. - Corner(X, Y), + Corner(HorizontalPositionKeyword, VerticalPositionKeyword), } /// A computed radial gradient ending shape. @@ -61,35 +61,39 @@ pub type ColorStop = generic::ColorStop; pub type MozImageRect = generic::MozImageRect; impl generic::LineDirection for LineDirection { - fn points_downwards(&self, compat_mode: CompatMode) -> bool { + fn points_downwards(&self, compat_mode: GradientCompatMode) -> bool { match *self { LineDirection::Angle(angle) => angle.radians() == PI, - LineDirection::Vertical(Y::Bottom) if compat_mode == CompatMode::Modern => true, - LineDirection::Vertical(Y::Top) if compat_mode != CompatMode::Modern => true, + LineDirection::Vertical(VerticalPositionKeyword::Bottom) => { + compat_mode == GradientCompatMode::Modern + } + LineDirection::Vertical(VerticalPositionKeyword::Top) => { + compat_mode != GradientCompatMode::Modern + } _ => false, } } - fn to_css(&self, dest: &mut CssWriter, compat_mode: CompatMode) -> fmt::Result + fn to_css(&self, dest: &mut CssWriter, compat_mode: GradientCompatMode) -> fmt::Result where W: Write, { match *self { LineDirection::Angle(ref angle) => angle.to_css(dest), LineDirection::Horizontal(x) => { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { dest.write_str("to ")?; } x.to_css(dest) }, LineDirection::Vertical(y) => { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { dest.write_str("to ")?; } y.to_css(dest) }, LineDirection::Corner(x, y) => { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { dest.write_str("to ")?; } x.to_css(dest)?; diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index c672efc2e7d..3f126a6e20d 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -13,13 +13,35 @@ use servo_arc::Arc; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; +/// An | (for background-image, for example). +#[derive( + Clone, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem, +)] +pub enum GenericImageLayer { + /// The `none` value. + None, + /// The `` value. + Image(Image), +} + +pub use self::GenericImageLayer as ImageLayer; + +impl ImageLayer { + /// Returns `none`. + #[inline] + pub fn none() -> Self { + ImageLayer::None + } +} + /// An [image]. /// /// [image]: https://drafts.csswg.org/css-images/#image-values #[derive( Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem, )] -pub enum Image { +#[repr(C, u8)] +pub enum GenericImage { /// A `` image. Url(ImageUrl), /// A `` image. Gradients are rather large, and not nearly as @@ -36,23 +58,29 @@ pub enum Image { PaintWorklet(PaintWorklet), } +pub use self::GenericImage as Image; + /// A CSS gradient. /// #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] -pub struct Gradient { +#[repr(C)] +pub struct GenericGradient { /// Gradients can be linear or radial. - pub kind: GradientKind, + pub kind: GenericGradientKind, /// The color stops and interpolation hints. - pub items: Vec>, + pub items: crate::OwnedSlice>, /// True if this is a repeating gradient. pub repeating: bool, /// Compatibility mode. - pub compat_mode: CompatMode, + pub compat_mode: GradientCompatMode, } +pub use self::GenericGradient as Gradient; + #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] +#[repr(u8)] /// Whether we used the modern notation or the compatibility `-webkit`, `-moz` prefixes. -pub enum CompatMode { +pub enum GradientCompatMode { /// Modern syntax. Modern, /// `-webkit` prefix. @@ -63,44 +91,56 @@ pub enum CompatMode { /// A gradient kind. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] -pub enum GradientKind { +#[repr(C, u8)] +pub enum GenericGradientKind { /// A linear gradient. Linear(LineDirection), /// A radial gradient. - Radial(EndingShape, Position), + 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, )] -pub enum EndingShape { +#[repr(C, u8)] +pub enum GenericEndingShape { /// A circular gradient. - Circle(Circle), + Circle(GenericCircle), /// An elliptic gradient. - Ellipse(Ellipse), + Ellipse(GenericEllipse), } +pub use self::GenericEndingShape as EndingShape; + /// A circle shape. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] -pub enum Circle { +#[repr(C, u8)] +pub enum GenericCircle { /// A circle radius. Radius(Length), /// A circle extent. Extent(ShapeExtent), } +pub use self::GenericCircle as Circle; + /// An ellipse shape. #[derive( Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] -pub enum Ellipse { +#[repr(C, u8)] +pub enum GenericEllipse { /// An ellipse pair of radii. Radii(LengthPercentage, LengthPercentage), /// An ellipse extent. Extent(ShapeExtent), } +pub use self::GenericEllipse as Ellipse; + /// #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] @@ -117,6 +157,7 @@ pub enum Ellipse { ToResolvedValue, ToShmem, )] +#[repr(u8)] pub enum ShapeExtent { ClosestSide, FarthestSide, @@ -277,8 +318,8 @@ where W: Write, { match self.compat_mode { - CompatMode::WebKit => dest.write_str("-webkit-")?, - CompatMode::Moz => dest.write_str("-moz-")?, + GradientCompatMode::WebKit => dest.write_str("-webkit-")?, + GradientCompatMode::Moz => dest.write_str("-moz-")?, _ => {}, } @@ -301,7 +342,7 @@ where EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => true, _ => false, }; - if self.compat_mode == CompatMode::Modern { + if self.compat_mode == GradientCompatMode::Modern { if !omit_shape { shape.to_css(dest)?; dest.write_str(" ")?; @@ -318,7 +359,7 @@ where false }, }; - for item in &self.items { + for item in &*self.items { if !skip_comma { dest.write_str(", ")?; } @@ -341,10 +382,10 @@ impl GradientKind { /// The direction of a linear gradient. pub trait LineDirection { /// Whether this direction points towards, and thus can be omitted. - fn points_downwards(&self, compat_mode: CompatMode) -> bool; + fn points_downwards(&self, compat_mode: GradientCompatMode) -> bool; /// Serialises this direction according to the compatibility mode. - fn to_css(&self, dest: &mut CssWriter, compat_mode: CompatMode) -> fmt::Result + fn to_css(&self, dest: &mut CssWriter, compat_mode: GradientCompatMode) -> fmt::Result where W: Write; } diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index 9779c6fa2f6..f4f4cf9afce 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -11,13 +11,13 @@ use crate::custom_properties::SpecifiedValue; use crate::parser::{Parse, ParserContext}; use crate::stylesheets::CorsMode; use crate::values::generics::image::PaintWorklet; -use crate::values::generics::image::{self as generic, Circle, CompatMode, Ellipse, ShapeExtent}; +use crate::values::generics::image::{self as generic, Circle, GradientCompatMode, Ellipse, ShapeExtent}; use crate::values::generics::position::Position as GenericPosition; -use crate::values::specified::position::{Position, PositionComponent, Side, X, Y}; +use crate::values::specified::position::{Position, PositionComponent, Side}; +use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword}; use crate::values::specified::url::SpecifiedImageUrl; use crate::values::specified::{Angle, Color, Length, LengthPercentage}; use crate::values::specified::{Number, NumberOrPercentage, Percentage}; -use crate::values::{Either, None_}; use crate::Atom; use cssparser::{Delimiter, Parser, Token}; use selectors::parser::SelectorParseErrorKind; @@ -29,7 +29,7 @@ use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError}; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; /// A specified image layer. -pub type ImageLayer = Either; +pub type ImageLayer = generic::GenericImageLayer; impl ImageLayer { /// This is a specialization of Either with an alternative parse @@ -38,10 +38,11 @@ impl ImageLayer { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - if let Ok(v) = input.try(|i| None_::parse(context, i)) { - return Ok(Either::First(v)); + if let Ok(v) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) { + return Ok(generic::GenericImageLayer::Image(v)); } - Image::parse_with_cors_anonymous(context, input).map(Either::Second) + input.expect_ident_matching("none")?; + Ok(generic::GenericImageLayer::None) } } @@ -87,11 +88,11 @@ pub enum LineDirection { /// An angular direction. Angle(Angle), /// A horizontal direction. - Horizontal(X), + Horizontal(HorizontalPositionKeyword), /// A vertical direction. - Vertical(Y), + Vertical(VerticalPositionKeyword), /// A direction towards a corner of a box. - Corner(X, Y), + Corner(HorizontalPositionKeyword, VerticalPositionKeyword), } /// A specified ending shape. @@ -182,44 +183,44 @@ impl Parse for Gradient { let func = input.expect_function()?.clone(); let result = match_ignore_ascii_case! { &func, "linear-gradient" => { - Some((Shape::Linear, false, CompatMode::Modern)) + Some((Shape::Linear, false, GradientCompatMode::Modern)) }, "-webkit-linear-gradient" => { - Some((Shape::Linear, false, CompatMode::WebKit)) + Some((Shape::Linear, false, GradientCompatMode::WebKit)) }, #[cfg(feature = "gecko")] "-moz-linear-gradient" => { - Some((Shape::Linear, false, CompatMode::Moz)) + Some((Shape::Linear, false, GradientCompatMode::Moz)) }, "repeating-linear-gradient" => { - Some((Shape::Linear, true, CompatMode::Modern)) + Some((Shape::Linear, true, GradientCompatMode::Modern)) }, "-webkit-repeating-linear-gradient" => { - Some((Shape::Linear, true, CompatMode::WebKit)) + Some((Shape::Linear, true, GradientCompatMode::WebKit)) }, #[cfg(feature = "gecko")] "-moz-repeating-linear-gradient" => { - Some((Shape::Linear, true, CompatMode::Moz)) + Some((Shape::Linear, true, GradientCompatMode::Moz)) }, "radial-gradient" => { - Some((Shape::Radial, false, CompatMode::Modern)) + Some((Shape::Radial, false, GradientCompatMode::Modern)) }, "-webkit-radial-gradient" => { - Some((Shape::Radial, false, CompatMode::WebKit)) + Some((Shape::Radial, false, GradientCompatMode::WebKit)) } #[cfg(feature = "gecko")] "-moz-radial-gradient" => { - Some((Shape::Radial, false, CompatMode::Moz)) + Some((Shape::Radial, false, GradientCompatMode::Moz)) }, "repeating-radial-gradient" => { - Some((Shape::Radial, true, CompatMode::Modern)) + Some((Shape::Radial, true, GradientCompatMode::Modern)) }, "-webkit-repeating-radial-gradient" => { - Some((Shape::Radial, true, CompatMode::WebKit)) + Some((Shape::Radial, true, GradientCompatMode::WebKit)) }, #[cfg(feature = "gecko")] "-moz-repeating-radial-gradient" => { - Some((Shape::Radial, true, CompatMode::Moz)) + Some((Shape::Radial, true, GradientCompatMode::Moz)) }, "-webkit-gradient" => { return input.parse_nested_block(|i| { @@ -249,12 +250,7 @@ impl Parse for Gradient { return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } - Ok(Gradient { - items: items, - repeating: repeating, - kind: kind, - compat_mode: compat_mode, - }) + Ok(Gradient { items, repeating, kind, compat_mode }) } } @@ -263,6 +259,7 @@ impl Gradient { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { + use crate::values::specified::position::{HorizontalPositionKeyword as X, VerticalPositionKeyword as Y}; type Point = GenericPosition, Component>; #[derive(Clone, Copy, Parse)] @@ -493,21 +490,21 @@ impl Gradient { } Ok(generic::Gradient { - kind: kind, - items: items, + kind, + items: items.into(), repeating: false, - compat_mode: CompatMode::Modern, + compat_mode: GradientCompatMode::Modern, }) } } impl GradientKind { /// Parses a linear gradient. - /// CompatMode can change during `-moz-` prefixed gradient parsing if it come across a `to` keyword. + /// 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>, - compat_mode: &mut CompatMode, + compat_mode: &mut GradientCompatMode, ) -> Result> { let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode)) { @@ -515,8 +512,8 @@ impl GradientKind { d } else { match *compat_mode { - CompatMode::Modern => LineDirection::Vertical(Y::Bottom), - _ => LineDirection::Vertical(Y::Top), + GradientCompatMode::Modern => LineDirection::Vertical(VerticalPositionKeyword::Bottom), + _ => LineDirection::Vertical(VerticalPositionKeyword::Top), } }; Ok(generic::GradientKind::Linear(direction)) @@ -524,10 +521,10 @@ impl GradientKind { fn parse_radial<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, - compat_mode: &mut CompatMode, + compat_mode: &mut GradientCompatMode, ) -> Result> { let (shape, position) = match *compat_mode { - CompatMode::Modern => { + GradientCompatMode::Modern => { let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode)); let position = input.try(|i| { i.expect_ident_matching("at")?; @@ -561,35 +558,39 @@ impl GradientKind { } impl generic::LineDirection for LineDirection { - fn points_downwards(&self, compat_mode: CompatMode) -> bool { + fn points_downwards(&self, compat_mode: GradientCompatMode) -> bool { match *self { LineDirection::Angle(ref angle) => angle.degrees() == 180.0, - LineDirection::Vertical(Y::Bottom) if compat_mode == CompatMode::Modern => true, - LineDirection::Vertical(Y::Top) if compat_mode != CompatMode::Modern => true, + LineDirection::Vertical(VerticalPositionKeyword::Bottom) => { + compat_mode == GradientCompatMode::Modern + } + LineDirection::Vertical(VerticalPositionKeyword::Top) => { + compat_mode != GradientCompatMode::Modern + } _ => false, } } - fn to_css(&self, dest: &mut CssWriter, compat_mode: CompatMode) -> fmt::Result + fn to_css(&self, dest: &mut CssWriter, compat_mode: GradientCompatMode) -> fmt::Result where W: Write, { match *self { LineDirection::Angle(angle) => angle.to_css(dest), LineDirection::Horizontal(x) => { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { dest.write_str("to ")?; } x.to_css(dest) }, LineDirection::Vertical(y) => { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { dest.write_str("to ")?; } y.to_css(dest) }, LineDirection::Corner(x, y) => { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { dest.write_str("to ")?; } x.to_css(dest)?; @@ -604,7 +605,7 @@ impl LineDirection { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, - compat_mode: &mut CompatMode, + compat_mode: &mut GradientCompatMode, ) -> Result> { // Gradients allow unitless zero angles as an exception, see: // https://github.com/w3c/csswg-drafts/issues/1162 @@ -616,14 +617,14 @@ impl LineDirection { let to_ident = i.try(|i| i.expect_ident_matching("to")); match *compat_mode { // `to` keyword is mandatory in modern syntax. - CompatMode::Modern => to_ident?, + GradientCompatMode::Modern => to_ident?, // Fall back to Modern compatibility mode in case there is a `to` keyword. // According to Gecko, `-moz-linear-gradient(to ...)` should serialize like // `linear-gradient(to ...)`. - CompatMode::Moz if to_ident.is_ok() => *compat_mode = CompatMode::Modern, + GradientCompatMode::Moz if to_ident.is_ok() => *compat_mode = GradientCompatMode::Modern, // There is no `to` keyword in webkit prefixed syntax. If it's consumed, // parsing should throw an error. - CompatMode::WebKit if to_ident.is_ok() => { + GradientCompatMode::WebKit if to_ident.is_ok() => { return Err( i.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("to".into())) ); @@ -631,14 +632,14 @@ impl LineDirection { _ => {}, } - if let Ok(x) = i.try(X::parse) { - if let Ok(y) = i.try(Y::parse) { + if let Ok(x) = i.try(HorizontalPositionKeyword::parse) { + if let Ok(y) = i.try(VerticalPositionKeyword::parse) { return Ok(LineDirection::Corner(x, y)); } return Ok(LineDirection::Horizontal(x)); } - let y = Y::parse(i)?; - if let Ok(x) = i.try(X::parse) { + let y = VerticalPositionKeyword::parse(i)?; + if let Ok(x) = i.try(HorizontalPositionKeyword::parse) { return Ok(LineDirection::Corner(x, y)); } Ok(LineDirection::Vertical(y)) @@ -650,7 +651,7 @@ impl EndingShape { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, - compat_mode: CompatMode, + compat_mode: GradientCompatMode, ) -> Result> { if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) { if input.try(|i| i.expect_ident_matching("circle")).is_ok() { @@ -663,7 +664,7 @@ impl EndingShape { if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) { return Ok(generic::EndingShape::Circle(Circle::Extent(extent))); } - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { if let Ok(length) = input.try(|i| Length::parse(context, i)) { return Ok(generic::EndingShape::Circle(Circle::Radius(length))); } @@ -676,7 +677,7 @@ impl EndingShape { if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) { return Ok(generic::EndingShape::Ellipse(Ellipse::Extent(extent))); } - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { let pair: Result<_, ParseError> = input.try(|i| { let x = LengthPercentage::parse(context, i)?; let y = LengthPercentage::parse(context, i)?; @@ -692,7 +693,7 @@ impl EndingShape { } if let Ok(length) = input.try(|i| Length::parse(context, i)) { if let Ok(y) = input.try(|i| LengthPercentage::parse(context, i)) { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { let _ = input.try(|i| i.expect_ident_matching("ellipse")); } return Ok(generic::EndingShape::Ellipse(Ellipse::Radii( @@ -700,7 +701,7 @@ impl EndingShape { y, ))); } - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { let y = input.try(|i| { i.expect_ident_matching("ellipse")?; LengthPercentage::parse(context, i) @@ -719,12 +720,12 @@ impl EndingShape { input.try(|i| { let x = Percentage::parse(context, i)?; let y = if let Ok(y) = i.try(|i| LengthPercentage::parse(context, i)) { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { let _ = i.try(|i| i.expect_ident_matching("ellipse")); } y } else { - if compat_mode == CompatMode::Modern { + if compat_mode == GradientCompatMode::Modern { i.expect_ident_matching("ellipse")?; } LengthPercentage::parse(context, i)? @@ -737,10 +738,10 @@ impl EndingShape { impl ShapeExtent { fn parse_with_compat_mode<'i, 't>( input: &mut Parser<'i, 't>, - compat_mode: CompatMode, + compat_mode: GradientCompatMode, ) -> Result> { match Self::parse(input)? { - ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == CompatMode::Modern => { + ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == GradientCompatMode::Modern => { Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) }, ShapeExtent::Contain => Ok(ShapeExtent::ClosestSide), @@ -754,7 +755,7 @@ impl GradientItem { fn parse_comma_separated<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, - ) -> Result, ParseError<'i>> { + ) -> Result, ParseError<'i>> { let mut items = Vec::new(); let mut seen_stop = false; @@ -798,7 +799,7 @@ impl GradientItem { if !seen_stop || items.len() < 2 { return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } - Ok(items) + Ok(items.into()) } } diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index d9d75343331..fed0c5d3098 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -28,10 +28,10 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; pub type Position = GenericPosition; /// The specified value of a horizontal position. -pub type HorizontalPosition = PositionComponent; +pub type HorizontalPosition = PositionComponent; /// The specified value of a vertical position. -pub type VerticalPosition = PositionComponent; +pub type VerticalPosition = PositionComponent; /// The specified value of a component of a CSS ``. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] @@ -61,7 +61,8 @@ pub enum PositionComponent { ToShmem, )] #[allow(missing_docs)] -pub enum X { +#[repr(u8)] +pub enum HorizontalPositionKeyword { Left, Right, } @@ -83,7 +84,8 @@ pub enum X { ToShmem, )] #[allow(missing_docs)] -pub enum Y { +#[repr(u8)] +pub enum VerticalPositionKeyword { Top, Bottom, } @@ -123,7 +125,7 @@ impl Position { let y_pos = PositionComponent::Center; return Ok(Self::new(x_pos, y_pos)); } - if let Ok(y_keyword) = input.try(Y::parse) { + if let Ok(y_keyword) = input.try(VerticalPositionKeyword::parse) { let y_lp = input .try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks)) .ok(); @@ -136,7 +138,7 @@ impl Position { return Ok(Self::new(x_pos, y_pos)); }, Ok(x_pos @ PositionComponent::Length(_)) => { - if let Ok(y_keyword) = input.try(Y::parse) { + if let Ok(y_keyword) = input.try(VerticalPositionKeyword::parse) { let y_pos = PositionComponent::Side(y_keyword, None); return Ok(Self::new(x_pos, y_pos)); } @@ -152,12 +154,12 @@ impl Position { }, Err(_) => {}, } - let y_keyword = Y::parse(input)?; + let y_keyword = VerticalPositionKeyword::parse(input)?; let lp_and_x_pos: Result<_, ParseError> = input.try(|i| { let y_lp = i .try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks)) .ok(); - if let Ok(x_keyword) = i.try(X::parse) { + if let Ok(x_keyword) = i.try(HorizontalPositionKeyword::parse) { let x_lp = i .try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks)) .ok(); @@ -301,27 +303,27 @@ pub trait Side { fn is_start(&self) -> bool; } -impl Side for X { +impl Side for HorizontalPositionKeyword { #[inline] fn start() -> Self { - X::Left + HorizontalPositionKeyword::Left } #[inline] fn is_start(&self) -> bool { - *self == X::Left + *self == Self::start() } } -impl Side for Y { +impl Side for VerticalPositionKeyword { #[inline] fn start() -> Self { - Y::Top + VerticalPositionKeyword::Top } #[inline] fn is_start(&self) -> bool { - *self == Y::Top + *self == Self::start() } } diff --git a/components/style/values/specified/transform.rs b/components/style/values/specified/transform.rs index e942cf13085..d52aa69cd24 100644 --- a/components/style/values/specified/transform.rs +++ b/components/style/values/specified/transform.rs @@ -9,7 +9,7 @@ use crate::values::computed::{Context, LengthPercentage as ComputedLengthPercent use crate::values::computed::{Percentage as ComputedPercentage, ToComputedValue}; use crate::values::generics::transform as generic; use crate::values::generics::transform::{Matrix, Matrix3D}; -use crate::values::specified::position::{Side, X, Y}; +use crate::values::specified::position::{Side, HorizontalPositionKeyword, VerticalPositionKeyword}; use crate::values::specified::{self, Angle, Integer, Length, LengthPercentage, Number}; use crate::Zero; use cssparser::Parser; @@ -25,7 +25,11 @@ pub type TransformOperation = pub type Transform = generic::Transform; /// The specified value of a CSS `` -pub type TransformOrigin = generic::TransformOrigin, OriginComponent, Length>; +pub type TransformOrigin = generic::TransformOrigin< + OriginComponent, + OriginComponent, + Length, +>; impl Transform { /// Internal parse function for deciding if we wish to accept prefixed values or not @@ -263,7 +267,7 @@ impl Parse for TransformOrigin { return Ok(Self::new(x_origin, y_origin, depth)); } let y_origin = OriginComponent::Center; - if let Ok(x_keyword) = input.try(X::parse) { + if let Ok(x_keyword) = input.try(HorizontalPositionKeyword::parse) { let x_origin = OriginComponent::Side(x_keyword); let depth = parse_depth(input); return Ok(Self::new(x_origin, y_origin, depth)); @@ -282,9 +286,9 @@ impl Parse for TransformOrigin { }, Err(_) => {}, } - let y_keyword = Y::parse(input)?; + let y_keyword = VerticalPositionKeyword::parse(input)?; let y_origin = OriginComponent::Side(y_keyword); - if let Ok(x_keyword) = input.try(X::parse) { + if let Ok(x_keyword) = input.try(HorizontalPositionKeyword::parse) { let x_origin = OriginComponent::Side(x_keyword); let depth = parse_depth(input); return Ok(Self::new(x_origin, y_origin, depth));