From def92d1b8e9d373e2f6f27c366d578d97d8960c6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:34:50 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- .../style/values/generics/basic_shape.rs | 532 ++++++++++++++++++++- servo/components/style/values/generics/counters.rs | 14 +- servo/components/style/values/generics/image.rs | 4 +- .../components/style/values/generics/transform.rs | 1 - 4 files changed, 528 insertions(+), 23 deletions(-) (limited to 'servo/components/style/values/generics') diff --git a/servo/components/style/values/generics/basic_shape.rs b/servo/components/style/values/generics/basic_shape.rs index 13d27995c1..ca7646fb13 100644 --- a/servo/components/style/values/generics/basic_shape.rs +++ b/servo/components/style/values/generics/basic_shape.rs @@ -10,7 +10,7 @@ use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; use crate::values::generics::border::GenericBorderRadius; use crate::values::generics::position::GenericPositionOrAuto; use crate::values::generics::rect::Rect; -use crate::values::specified::SVGPathData; +use crate::values::specified::svg_path::{PathCommand, SVGPathData}; use crate::Zero; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; @@ -181,8 +181,13 @@ pub use self::GenericShapeOutside as ShapeOutside; ToShmem, )] #[repr(C, u8)] -pub enum GenericBasicShape -{ +pub enum GenericBasicShape< + Angle, + Position, + LengthPercentage, + NonNegativeLengthPercentage, + BasicShapeRect, +> { /// The . Rect(BasicShapeRect), /// Defines a circle with a center and a radius. @@ -199,10 +204,11 @@ pub enum GenericBasicShape), - /// Defines a path with SVG path syntax. - Path(Path), - // TODO: Bug 1823463. Add shape(). - // https://drafts.csswg.org/css-shapes-2/#shape-function + /// Defines a path() or shape(). + PathOrShape( + #[animation(field_bound)] + #[css(field_bound)] + GenericPathOrShapeFunction), } pub use self::GenericBasicShape as BasicShape; @@ -366,6 +372,30 @@ pub use self::GenericPolygon as Polygon; #[repr(C)] pub struct PolygonCoord(pub LengthPercentage, pub LengthPercentage); +/// path() function or shape() function. +#[derive( + Clone, + ComputeSquaredDistance, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(C, u8)] +pub enum GenericPathOrShapeFunction { + /// Defines a path with SVG path syntax. + Path(Path), + /// Defines a shape function, which is identical to path() but it uses the CSS syntax. + Shape(#[css(field_bound)] Shape), +} + // https://drafts.csswg.org/css-shapes/#typedef-fill-rule // NOTE: Basic shapes spec says that these are the only two values, however // https://www.w3.org/TR/SVG/painting.html#FillRuleProperty @@ -397,9 +427,9 @@ pub enum FillRule { Evenodd, } -/// The path function defined in css-shape-2. +/// The path function. /// -/// https://drafts.csswg.org/css-shapes-2/#funcdef-path +/// https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-path #[derive( Animate, Clone, @@ -426,6 +456,14 @@ pub struct Path { pub path: SVGPathData, } +impl Path { + /// Returns the slice of PathCommand. + #[inline] + pub fn commands(&self) -> &[PathCommand] { + self.path.commands() + } +} + impl ToAnimatedZero for ClipPath { fn to_animated_zero(&self) -> Result { Err(()) @@ -565,3 +603,479 @@ impl Default for FillRule { fn is_default(fill: &T) -> bool { *fill == Default::default() } + +/// The shape function defined in css-shape-2. +/// shape() = shape(? from , #) +/// +/// https://drafts.csswg.org/css-shapes-2/#shape-function +#[derive( + Clone, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] +#[repr(C)] +pub struct Shape { + /// The filling rule for this shape. + pub fill: FillRule, + /// The shape command data. Note that the starting point will be the first command in this + /// slice. + // Note: The first command is always GenericShapeCommand::Move. + pub commands: crate::OwnedSlice>, +} + +impl Shape { + /// Returns the slice of GenericShapeCommand<..>. + #[inline] + pub fn commands(&self) -> &[GenericShapeCommand] { + &self.commands + } +} + +impl Animate for Shape +where + Angle: Animate, + LengthPercentage: Animate, +{ + fn animate(&self, other: &Self, procedure: Procedure) -> Result { + if self.fill != other.fill { + return Err(()); + } + let commands = + lists::by_computed_value::animate(&self.commands, &other.commands, procedure)?; + Ok(Self { + fill: self.fill, + commands, + }) + } +} + +impl ComputeSquaredDistance for Shape +where + Angle: ComputeSquaredDistance, + LengthPercentage: ComputeSquaredDistance, +{ + fn compute_squared_distance(&self, other: &Self) -> Result { + if self.fill != other.fill { + return Err(()); + } + lists::by_computed_value::squared_distance(&self.commands, &other.commands) + } +} + +impl ToCss for Shape +where + Angle: ToCss + Zero, + LengthPercentage: PartialEq + ToCss, +{ + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + use style_traits::values::SequenceWriter; + + // Per spec, we must have the first move command and at least one following command. + debug_assert!(self.commands.len() > 1); + + dest.write_str("shape(")?; + if !is_default(&self.fill) { + self.fill.to_css(dest)?; + dest.write_char(' ')?; + } + dest.write_str("from ")?; + match self.commands[0] { + ShapeCommand::Move { + by_to: _, + ref point, + } => point.to_css(dest)?, + _ => unreachable!("The first command must be move"), + } + dest.write_str(", ")?; + { + let mut writer = SequenceWriter::new(dest, ", "); + for command in self.commands.iter().skip(1) { + writer.item(command)?; + } + } + dest.write_char(')') + } +} + +/// This is a more general shape(path) command type, for both shape() and path(). +/// +/// https://www.w3.org/TR/SVG11/paths.html#PathData +/// https://drafts.csswg.org/css-shapes-2/#shape-function +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + SpecifiedValueInfo, + ToAnimatedValue, + ToAnimatedZero, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] +#[allow(missing_docs)] +#[repr(C, u8)] +pub enum GenericShapeCommand { + /// The move command. + Move { + by_to: ByTo, + point: CoordinatePair, + }, + /// The line command. + Line { + by_to: ByTo, + point: CoordinatePair, + }, + /// The hline command. + HLine { by_to: ByTo, x: LengthPercentage }, + /// The vline command. + VLine { by_to: ByTo, y: LengthPercentage }, + /// The cubic Bézier curve command. + CubicCurve { + by_to: ByTo, + point: CoordinatePair, + control1: CoordinatePair, + control2: CoordinatePair, + }, + /// The quadratic Bézier curve command. + QuadCurve { + by_to: ByTo, + point: CoordinatePair, + control1: CoordinatePair, + }, + /// The smooth command. + SmoothCubic { + by_to: ByTo, + point: CoordinatePair, + control2: CoordinatePair, + }, + /// The smooth quadratic Bézier curve command. + SmoothQuad { + by_to: ByTo, + point: CoordinatePair, + }, + /// The arc command. + Arc { + by_to: ByTo, + point: CoordinatePair, + radii: CoordinatePair, + arc_sweep: ArcSweep, + arc_size: ArcSize, + rotate: Angle, + }, + /// The closepath command. + Close, +} + +pub use self::GenericShapeCommand as ShapeCommand; + +impl ToCss for ShapeCommand +where + Angle: ToCss + Zero, + LengthPercentage: PartialEq + ToCss, +{ + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: fmt::Write, + { + use self::ShapeCommand::*; + match *self { + Move { by_to, ref point } => { + dest.write_str("move ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest) + }, + Line { by_to, ref point } => { + dest.write_str("line ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest) + }, + HLine { by_to, ref x } => { + dest.write_str("hline ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + x.to_css(dest) + }, + VLine { by_to, ref y } => { + dest.write_str("vline ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + y.to_css(dest) + }, + CubicCurve { + by_to, + ref point, + ref control1, + ref control2, + } => { + dest.write_str("curve ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest)?; + dest.write_str(" via ")?; + control1.to_css(dest)?; + dest.write_char(' ')?; + control2.to_css(dest) + }, + QuadCurve { + by_to, + ref point, + ref control1, + } => { + dest.write_str("curve ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest)?; + dest.write_str(" via ")?; + control1.to_css(dest) + }, + SmoothCubic { + by_to, + ref point, + ref control2, + } => { + dest.write_str("smooth ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest)?; + dest.write_str(" via ")?; + control2.to_css(dest) + }, + SmoothQuad { by_to, ref point } => { + dest.write_str("smooth ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest) + }, + Arc { + by_to, + ref point, + ref radii, + arc_sweep, + arc_size, + ref rotate, + } => { + dest.write_str("arc ")?; + by_to.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest)?; + dest.write_str(" of ")?; + radii.x.to_css(dest)?; + if radii.x != radii.y { + dest.write_char(' ')?; + radii.y.to_css(dest)?; + } + + if matches!(arc_sweep, ArcSweep::Cw) { + dest.write_str(" cw")?; + } + + if matches!(arc_size, ArcSize::Large) { + dest.write_str(" large")?; + } + + if !rotate.is_zero() { + dest.write_str(" rotate ")?; + rotate.to_css(dest)?; + } + Ok(()) + }, + Close => dest.write_str("close"), + } + } +} + +/// This indicates the command is absolute or relative. +/// https://drafts.csswg.org/css-shapes-2/#typedef-shape-by-to +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + Deserialize, + MallocSizeOf, + Parse, + PartialEq, + Serialize, + SpecifiedValueInfo, + ToAnimatedValue, + ToAnimatedZero, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum ByTo { + /// This indicates that the s are relative to the command’s starting point. + By, + /// This relative to the top-left corner of the reference box. + To, +} + +impl ByTo { + /// Return true if it is absolute, i.e. it is To. + #[inline] + pub fn is_abs(&self) -> bool { + matches!(self, ByTo::To) + } + + /// Create ByTo based on the flag if it is absolute. + #[inline] + pub fn new(is_abs: bool) -> Self { + if is_abs { + Self::To + } else { + Self::By + } + } +} + +/// Defines a pair of coordinates, representing a rightward and downward offset, respectively, from +/// a specified reference point. Percentages are resolved against the width or height, +/// respectively, of the reference box. +/// https://drafts.csswg.org/css-shapes-2/#typedef-shape-coordinate-pair +#[allow(missing_docs)] +#[derive( + AddAssign, + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + SpecifiedValueInfo, + ToAnimatedValue, + ToAnimatedZero, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(C)] +pub struct CoordinatePair { + pub x: LengthPercentage, + pub y: LengthPercentage, +} + +impl CoordinatePair { + /// Create a CoordinatePair. + #[inline] + pub fn new(x: LengthPercentage, y: LengthPercentage) -> Self { + Self { x, y } + } +} + +/// This indicates that the arc that is traced around the ellipse clockwise or counter-clockwise +/// from the center. +/// https://drafts.csswg.org/css-shapes-2/#typedef-shape-arc-sweep +#[derive( + Clone, + Copy, + Debug, + Deserialize, + FromPrimitive, + MallocSizeOf, + Parse, + PartialEq, + Serialize, + SpecifiedValueInfo, + ToAnimatedValue, + ToAnimatedZero, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum ArcSweep { + /// Counter-clockwise. The default value. (This also represents 0 in the svg path.) + Ccw = 0, + /// Clockwise. (This also represents 1 in the svg path.) + Cw = 1, +} + +impl Animate for ArcSweep { + fn animate(&self, other: &Self, procedure: Procedure) -> Result { + use num_traits::FromPrimitive; + // If an arc command has different between its starting and ending list, then + // the interpolated result uses cw for any progress value between 0 and 1. + (*self as i32) + .animate(&(*other as i32), procedure) + .map(|v| ArcSweep::from_u8((v > 0) as u8).unwrap_or(ArcSweep::Ccw)) + } +} + +impl ComputeSquaredDistance for ArcSweep { + fn compute_squared_distance(&self, other: &Self) -> Result { + (*self as i32).compute_squared_distance(&(*other as i32)) + } +} + +/// This indicates that the larger or smaller, respectively, of the two possible arcs must be +/// chosen. +/// https://drafts.csswg.org/css-shapes-2/#typedef-shape-arc-size +#[derive( + Clone, + Copy, + Debug, + Deserialize, + FromPrimitive, + MallocSizeOf, + Parse, + PartialEq, + Serialize, + SpecifiedValueInfo, + ToAnimatedValue, + ToAnimatedZero, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum ArcSize { + /// Choose the small one. The default value. (This also represents 0 in the svg path.) + Small = 0, + /// Choose the large one. (This also represents 1 in the svg path.) + Large = 1, +} + +impl Animate for ArcSize { + fn animate(&self, other: &Self, procedure: Procedure) -> Result { + use num_traits::FromPrimitive; + // If it has different keywords, then the interpolated result uses large for any + // progress value between 0 and 1. + (*self as i32) + .animate(&(*other as i32), procedure) + .map(|v| ArcSize::from_u8((v > 0) as u8).unwrap_or(ArcSize::Small)) + } +} + +impl ComputeSquaredDistance for ArcSize { + fn compute_squared_distance(&self, other: &Self) -> Result { + (*self as i32).compute_squared_distance(&(*other as i32)) + } +} diff --git a/servo/components/style/values/generics/counters.rs b/servo/components/style/values/generics/counters.rs index 1d4518c57b..3f23c74b33 100644 --- a/servo/components/style/values/generics/counters.rs +++ b/servo/components/style/values/generics/counters.rs @@ -4,11 +4,10 @@ //! Generic types for counters-related CSS values. -#[cfg(feature = "servo-layout-2013")] +#[cfg(feature = "servo")] use crate::computed_values::list_style_type::T as ListStyleType; #[cfg(feature = "gecko")] use crate::values::generics::CounterStyle; -#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))] use crate::values::specified::Attr; use crate::values::CustomIdent; use std::fmt::{self, Write}; @@ -186,13 +185,13 @@ pub struct GenericCounters( ); pub use self::GenericCounters as Counters; -#[cfg(feature = "servo-layout-2013")] +#[cfg(feature = "servo")] type CounterStyleType = ListStyleType; #[cfg(feature = "gecko")] type CounterStyleType = CounterStyle; -#[cfg(feature = "servo-layout-2013")] +#[cfg(feature = "servo")] #[inline] fn is_decimal(counter_type: &CounterStyleType) -> bool { *counter_type == ListStyleType::Decimal @@ -254,11 +253,9 @@ pub enum GenericContentItem { /// Literal string content. String(crate::OwnedStr), /// `counter(name, style)`. - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] #[css(comma, function)] Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType), /// `counters(name, separator, style)`. - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] #[css(comma, function)] Counters( CustomIdent, @@ -266,16 +263,12 @@ pub enum GenericContentItem { #[css(skip_if = "is_decimal")] CounterStyleType, ), /// `open-quote`. - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] OpenQuote, /// `close-quote`. - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] CloseQuote, /// `no-open-quote`. - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] NoOpenQuote, /// `no-close-quote`. - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] NoCloseQuote, /// `-moz-alt-content`. #[cfg(feature = "gecko")] @@ -286,7 +279,6 @@ pub enum GenericContentItem { #[cfg(feature = "gecko")] MozLabelContent, /// `attr([namespace? `|`]? ident)` - #[cfg(any(feature = "gecko", feature = "servo-layout-2020"))] Attr(Attr), /// image-set(url) | url(url) Image(I), diff --git a/servo/components/style/values/generics/image.rs b/servo/components/style/values/generics/image.rs index 6fc0870e15..ca1c716052 100644 --- a/servo/components/style/values/generics/image.rs +++ b/servo/components/style/values/generics/image.rs @@ -41,7 +41,7 @@ pub enum GenericImage { /// A paint worklet image. /// - #[cfg(feature = "servo-layout-2013")] + #[cfg(feature = "servo")] PaintWorklet(PaintWorklet), /// A `` image. Storing this directly inside of @@ -416,7 +416,7 @@ where Image::None => dest.write_str("none"), Image::Url(ref url) => url.to_css(dest), Image::Gradient(ref gradient) => gradient.to_css(dest), - #[cfg(feature = "servo-layout-2013")] + #[cfg(feature = "servo")] Image::PaintWorklet(ref paint_worklet) => paint_worklet.to_css(dest), #[cfg(feature = "gecko")] Image::Element(ref selector) => { diff --git a/servo/components/style/values/generics/transform.rs b/servo/components/style/values/generics/transform.rs index 3a65c460a7..4d70e4465c 100644 --- a/servo/components/style/values/generics/transform.rs +++ b/servo/components/style/values/generics/transform.rs @@ -11,7 +11,6 @@ use crate::values::specified::length::Length as SpecifiedLength; use crate::values::specified::length::LengthPercentage as SpecifiedLengthPercentage; use crate::values::{computed, CSSFloat}; use crate::{Zero, ZeroNoPercent}; -use euclid; use euclid::default::{Rect, Transform3D}; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; -- cgit v1.2.3