diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 30317792b313..6ffe3b6d5adb 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -315,7 +315,6 @@ var validGradientAndElementValues = [ // radial w/ no color stops (valid) and a several different radius values: "-webkit-gradient(radial, 1 2, 8, 3 4, 9)", "-webkit-gradient(radial, 0 0, 10, 0 0, 5)", - "-webkit-gradient(radial, 1 2, -1.5, center center, +99999.9999)", // radial w/ color stops // (mostly leaning on more-robust 'linear' tests above; just testing a few @@ -584,6 +583,7 @@ var invalidGradientAndElementValues = [ "-webkit-gradient(radial, 1 2, 8, 3)", // Incomplete 2nd "-webkit-gradient(radial, 1 2, 8, 3 4)", // Missing 2nd radius "-webkit-gradient(radial, 1 2, 3 4, 9)", // Missing 1st radius + "-webkit-gradient(radial, 1 2, -1.5, center center, +99999.9999)", // Negative radius // radial w/ incorrect units on radius (invalid; expecting ) "-webkit-gradient(radial, 1 2, 8%, 3 4, 9)", @@ -969,7 +969,6 @@ if (/* mozGradientsEnabled */ true) { "-moz-radial-gradient(left calc(100px + -25%), red, blue)", "-moz-radial-gradient(calc(100px + -25px) top, red, blue)", "-moz-radial-gradient(left calc(100px + -25px), red, blue)", - "-moz-radial-gradient(40%, -100px -10%, red, blue)" ); invalidGradientAndElementValues.push( @@ -1032,6 +1031,9 @@ if (/* mozGradientsEnabled */ true) { "-moz-repeating-linear-gradient(10deg 20px, red, blue)", "-moz-repeating-linear-gradient(.414rad bottom, red, blue)", + /* Negative radii */ + "-moz-radial-gradient(40%, -100px -10%, red, blue)", + /* no quirks mode colors */ "-moz-radial-gradient(10% bottom, ffffff, black) scroll no-repeat", /* no quirks mode lengths */ diff --git a/servo/components/style/values/computed/image.rs b/servo/components/style/values/computed/image.rs index 67b432d5ffd8..82fda5e4f02a 100644 --- a/servo/components/style/values/computed/image.rs +++ b/servo/components/style/values/computed/image.rs @@ -10,7 +10,7 @@ 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::computed::{LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, NumberOrPercentage, ToComputedValue}; use crate::values::generics::image::{self as generic, GradientCompatMode}; use crate::values::specified::image::LineDirection as SpecifiedLineDirection; use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword}; @@ -27,12 +27,14 @@ pub type Image = generic::GenericImage /// Computed values for a CSS gradient. /// -pub type Gradient = - generic::GenericGradient; - -/// A computed gradient kind. -pub type GradientKind = - generic::GenericGradientKind; +pub type Gradient = generic::GenericGradient< + LineDirection, + LengthPercentage, + NonNegativeLength, + NonNegativeLengthPercentage, + Position, + Color, +>; /// A computed gradient line direction. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue)] @@ -48,9 +50,6 @@ pub enum LineDirection { Corner(HorizontalPositionKeyword, VerticalPositionKeyword), } -/// A computed radial gradient ending shape. -pub type EndingShape = generic::EndingShape; - /// A computed gradient item. pub type GradientItem = generic::GenericGradientItem; diff --git a/servo/components/style/values/generics/image.rs b/servo/components/style/values/generics/image.rs index c739820ae038..99cf3379b60d 100644 --- a/servo/components/style/values/generics/image.rs +++ b/servo/components/style/values/generics/image.rs @@ -73,9 +73,16 @@ pub use self::GenericImage as Image; /// #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(C)] -pub struct GenericGradient { +pub struct GenericGradient< + LineDirection, + LengthPercentage, + NonNegativeLength, + NonNegativeLengthPercentage, + Position, + Color, +> { /// Gradients can be linear or radial. - pub kind: GenericGradientKind, + pub kind: GenericGradientKind, /// The color stops and interpolation hints. pub items: crate::OwnedSlice>, /// True if this is a repeating gradient. @@ -101,11 +108,11 @@ pub enum GradientCompatMode { /// A gradient kind. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(C, u8)] -pub enum GenericGradientKind { +pub enum GenericGradientKind { /// A linear gradient. Linear(LineDirection), /// A radial gradient. - Radial(GenericEndingShape, Position), + Radial(GenericEndingShape, Position), } pub use self::GenericGradientKind as GradientKind; @@ -115,11 +122,11 @@ pub use self::GenericGradientKind as GradientKind; Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] #[repr(C, u8)] -pub enum GenericEndingShape { +pub enum GenericEndingShape { /// A circular gradient. - Circle(GenericCircle), + Circle(GenericCircle), /// An elliptic gradient. - Ellipse(GenericEllipse), + Ellipse(GenericEllipse), } pub use self::GenericEndingShape as EndingShape; @@ -127,9 +134,9 @@ pub use self::GenericEndingShape as EndingShape; /// A circle shape. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(C, u8)] -pub enum GenericCircle { +pub enum GenericCircle { /// A circle radius. - Radius(Length), + Radius(NonNegativeLength), /// A circle extent. Extent(ShapeExtent), } @@ -141,9 +148,9 @@ pub use self::GenericCircle as Circle; Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] #[repr(C, u8)] -pub enum GenericEllipse { +pub enum GenericEllipse { /// An ellipse pair of radii. - Radii(LengthPercentage, LengthPercentage), + Radii(NonNegativeLengthPercentage, NonNegativeLengthPercentage), /// An ellipse extent. Extent(ShapeExtent), } @@ -314,11 +321,12 @@ where } } -impl ToCss for Gradient +impl ToCss for Gradient where D: LineDirection, - L: ToCss, - LoP: ToCss, + LP: ToCss, + NL: ToCss, + NLP: ToCss, P: ToCss, C: ToCss, { diff --git a/servo/components/style/values/specified/image.rs b/servo/components/style/values/specified/image.rs index b0133f7a4016..a1f75dbbbf9d 100644 --- a/servo/components/style/values/specified/image.rs +++ b/servo/components/style/values/specified/image.rs @@ -10,6 +10,7 @@ use crate::custom_properties::SpecifiedValue; use crate::parser::{Parse, ParserContext}; use crate::stylesheets::CorsMode; +use crate::values::generics::NonNegative; use crate::values::generics::image::PaintWorklet; use crate::values::generics::image::{ self as generic, Circle, Ellipse, GradientCompatMode, ShapeExtent, @@ -18,7 +19,7 @@ use crate::values::generics::position::Position as GenericPosition; use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword}; use crate::values::specified::position::{Position, PositionComponent, Side}; use crate::values::specified::url::SpecifiedImageUrl; -use crate::values::specified::{Angle, Color, Length, LengthPercentage}; +use crate::values::specified::{Angle, Color, Length, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage}; use crate::values::specified::{Number, NumberOrPercentage, Percentage}; use crate::Atom; use cssparser::{Delimiter, Parser, Token}; @@ -54,7 +55,14 @@ pub type Image = generic::Image; /// Specified values for a CSS gradient. /// -pub type Gradient = generic::Gradient; +pub type Gradient = generic::Gradient< + LineDirection, + LengthPercentage, + NonNegativeLength, + NonNegativeLengthPercentage, + Position, + Color, +>; impl SpecifiedValueInfo for Gradient { const SUPPORTED_TYPES: u8 = CssType::GRADIENT; @@ -80,7 +88,7 @@ impl SpecifiedValueInfo for Gradient { } /// A specified gradient kind. -pub type GradientKind = generic::GradientKind; +pub type GradientKind = generic::GradientKind; /// A specified gradient line direction. /// @@ -98,7 +106,7 @@ pub enum LineDirection { } /// A specified ending shape. -pub type EndingShape = generic::EndingShape; +pub type EndingShape = generic::EndingShape; /// A specified gradient item. pub type GradientItem = generic::GradientItem; @@ -391,11 +399,11 @@ impl Gradient { "radial" => { let first_point = Point::parse(context, input)?; input.expect_comma()?; - let first_radius = Number::parse(context, input)?; + let first_radius = Number::parse_non_negative(context, input)?; input.expect_comma()?; let second_point = Point::parse(context, input)?; input.expect_comma()?; - let second_radius = Number::parse(context, input)?; + let second_radius = Number::parse_non_negative(context, input)?; let (reverse_stops, point, radius) = if second_radius.value >= first_radius.value { (false, second_point, second_radius) @@ -403,7 +411,7 @@ impl Gradient { (true, first_point, first_radius) }; - let rad = Circle::Radius(Length::from_px(radius.value)); + let rad = Circle::Radius(NonNegative(Length::from_px(radius.value))); let shape = generic::EndingShape::Circle(rad); let position: Position = point.into(); @@ -678,7 +686,7 @@ impl EndingShape { return Ok(generic::EndingShape::Circle(Circle::Extent(extent))); } if compat_mode == GradientCompatMode::Modern { - if let Ok(length) = input.try(|i| Length::parse(context, i)) { + if let Ok(length) = input.try(|i| NonNegativeLength::parse(context, i)) { return Ok(generic::EndingShape::Circle(Circle::Radius(length))); } } @@ -692,8 +700,8 @@ impl EndingShape { } if compat_mode == GradientCompatMode::Modern { let pair: Result<_, ParseError> = input.try(|i| { - let x = LengthPercentage::parse(context, i)?; - let y = LengthPercentage::parse(context, i)?; + let x = NonNegativeLengthPercentage::parse(context, i)?; + let y = NonNegativeLengthPercentage::parse(context, i)?; Ok((x, y)) }); if let Ok((x, y)) = pair { @@ -704,24 +712,24 @@ impl EndingShape { ShapeExtent::FarthestCorner, ))); } - if let Ok(length) = input.try(|i| Length::parse(context, i)) { - if let Ok(y) = input.try(|i| LengthPercentage::parse(context, i)) { + if let Ok(length) = input.try(|i| NonNegativeLength::parse(context, i)) { + if let Ok(y) = input.try(|i| NonNegativeLengthPercentage::parse(context, i)) { if compat_mode == GradientCompatMode::Modern { let _ = input.try(|i| i.expect_ident_matching("ellipse")); } return Ok(generic::EndingShape::Ellipse(Ellipse::Radii( - length.into(), + NonNegative(LengthPercentage::from(length.0)), y, ))); } if compat_mode == GradientCompatMode::Modern { let y = input.try(|i| { i.expect_ident_matching("ellipse")?; - LengthPercentage::parse(context, i) + NonNegativeLengthPercentage::parse(context, i) }); if let Ok(y) = y { return Ok(generic::EndingShape::Ellipse(Ellipse::Radii( - length.into(), + NonNegative(LengthPercentage::from(length.0)), y, ))); } @@ -731,8 +739,8 @@ impl EndingShape { return Ok(generic::EndingShape::Circle(Circle::Radius(length))); } input.try(|i| { - let x = Percentage::parse(context, i)?; - let y = if let Ok(y) = i.try(|i| LengthPercentage::parse(context, i)) { + let x = Percentage::parse_non_negative(context, i)?; + let y = if let Ok(y) = i.try(|i| NonNegativeLengthPercentage::parse(context, i)) { if compat_mode == GradientCompatMode::Modern { let _ = i.try(|i| i.expect_ident_matching("ellipse")); } @@ -741,9 +749,9 @@ impl EndingShape { if compat_mode == GradientCompatMode::Modern { i.expect_ident_matching("ellipse")?; } - LengthPercentage::parse(context, i)? + NonNegativeLengthPercentage::parse(context, i)? }; - Ok(generic::EndingShape::Ellipse(Ellipse::Radii(x.into(), y))) + Ok(generic::EndingShape::Ellipse(Ellipse::Radii(NonNegative(LengthPercentage::from(x)), y))) }) } } diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs index 6ae374685b85..1934edf9669d 100644 --- a/servo/components/style/values/specified/length.rs +++ b/servo/components/style/values/specified/length.rs @@ -704,14 +704,14 @@ impl Parse for NonNegativeLength { impl From for NonNegativeLength { #[inline] fn from(len: NoCalcLength) -> Self { - NonNegative::(Length::NoCalc(len)) + NonNegative(Length::NoCalc(len)) } } impl From for NonNegativeLength { #[inline] fn from(len: Length) -> Self { - NonNegative::(len) + NonNegative(len) } } diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs index 5daecf353bfe..89036556f23d 100644 --- a/servo/components/style/values/specified/mod.rs +++ b/servo/components/style/values/specified/mod.rs @@ -62,7 +62,7 @@ pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLe pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; pub use self::length::{MaxSize, Size}; pub use self::length::{NoCalcLength, ViewportPercentageLength}; -pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto}; +pub use self::length::{NonNegativeLength, NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto}; #[cfg(feature = "gecko")] pub use self::list::ListStyleType; pub use self::list::MozListReversed; diff --git a/testing/web-platform/meta/css/css-backgrounds/parsing/background-image-computed.sub.html.ini b/testing/web-platform/meta/css/css-backgrounds/parsing/background-image-computed.sub.html.ini deleted file mode 100644 index 673f52af1059..000000000000 --- a/testing/web-platform/meta/css/css-backgrounds/parsing/background-image-computed.sub.html.ini +++ /dev/null @@ -1,10 +0,0 @@ -[background-image-computed.sub.html] - [Property background-image value 'radial-gradient(ellipse calc(-0.5em + 10px) calc(0.5em + 10px) at 20px 30px, red, blue)' computes to 'radial-gradient(0px 30px at 20px 30px, rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - - [Property background-image value 'radial-gradient(circle calc(-0.5em + 10px) at calc(-1em + 10px) calc(-2em + 10px), red, blue)' computes to 'radial-gradient(0px at -30px -70px, rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - - [Property background-image value 'radial-gradient(ellipse calc(0.5em + 10px) calc(-0.5em + 10px) at 20px 30px, red, blue)' computes to 'radial-gradient(30px 0px at 20px 30px, rgb(255, 0, 0), rgb(0, 0, 255))'] - expected: FAIL - diff --git a/testing/web-platform/meta/css/css-backgrounds/parsing/background-image-invalid.html.ini b/testing/web-platform/meta/css/css-backgrounds/parsing/background-image-invalid.html.ini deleted file mode 100644 index 183b1db9b2e1..000000000000 --- a/testing/web-platform/meta/css/css-backgrounds/parsing/background-image-invalid.html.ini +++ /dev/null @@ -1,19 +0,0 @@ -[background-image-invalid.html] - [e.style['background-image'\] = "radial-gradient(ellipse -20px 30px at center, red, blue)" should not set the property value] - expected: FAIL - - [e.style['background-image'\] = "repeating-radial-gradient(-20% 30% at center, red, blue)" should not set the property value] - expected: FAIL - - [e.style['background-image'\] = "radial-gradient(circle -10px at center, red, blue)" should not set the property value] - expected: FAIL - - [e.style['background-image'\] = "repeating-radial-gradient(20px -30px ellipse at center, red, blue)" should not set the property value] - expected: FAIL - - [e.style['background-image'\] = "radial-gradient(20px -30px at center, red, blue)" should not set the property value] - expected: FAIL - - [e.style['background-image'\] = "repeating-radial-gradient(-10px at center, red, blue)" should not set the property value] - expected: FAIL -