diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 8946290918e..98d5ad296c9 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -679,10 +679,10 @@ ${helpers.predefined_type( ${helpers.predefined_type( "shape-outside", - "basic_shape::FloatAreaShape", - "generics::basic_shape::ShapeSource::None", + "basic_shape::ShapeOutside", + "generics::basic_shape::ShapeOutside::None", engines="gecko", - animation_value_type="basic_shape::FloatAreaShape", + animation_value_type="basic_shape::ShapeOutside", spec="https://drafts.csswg.org/css-shapes/#shape-outside-property", )} diff --git a/components/style/properties/longhands/svg.mako.rs b/components/style/properties/longhands/svg.mako.rs index 3b992ba3f5a..fbf240db205 100644 --- a/components/style/properties/longhands/svg.mako.rs +++ b/components/style/properties/longhands/svg.mako.rs @@ -76,10 +76,10 @@ ${helpers.single_keyword( ${helpers.predefined_type( "clip-path", - "basic_shape::ClippingShape", - "generics::basic_shape::ShapeSource::None", + "basic_shape::ClipPath", + "generics::basic_shape::ClipPath::None", engines="gecko", - animation_value_type="basic_shape::ClippingShape", + animation_value_type="basic_shape::ClipPath", flags="CREATES_STACKING_CONTEXT", spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path", )} diff --git a/components/style/values/computed/basic_shape.rs b/components/style/values/computed/basic_shape.rs index 2b36809fd7e..fa30220157b 100644 --- a/components/style/values/computed/basic_shape.rs +++ b/components/style/values/computed/basic_shape.rs @@ -14,11 +14,11 @@ use crate::values::generics::basic_shape as generic; /// A computed alias for FillRule. pub use crate::values::generics::basic_shape::FillRule; -/// A computed clipping shape. -pub type ClippingShape = generic::GenericClippingShape; +/// A computed `clip-path` value. +pub type ClipPath = generic::GenericClipPath; -/// A computed float area shape. -pub type FloatAreaShape = generic::GenericFloatAreaShape; +/// A computed `shape-outside` value. +pub type ShapeOutside = generic::GenericShapeOutside; /// A computed basic shape. pub type BasicShape = generic::GenericBasicShape< diff --git a/components/style/values/distance.rs b/components/style/values/distance.rs index 67c735676b5..efaa2314e01 100644 --- a/components/style/values/distance.rs +++ b/components/style/values/distance.rs @@ -81,6 +81,16 @@ impl ComputeSquaredDistance for Au { } } +impl ComputeSquaredDistance for Box +where + T: ComputeSquaredDistance, +{ + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + (**self).compute_squared_distance(&**other) + } +} + impl ComputeSquaredDistance for Option where T: ComputeSquaredDistance, diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index 92a0a6d7839..111af31bfeb 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -15,14 +15,12 @@ use crate::Zero; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; -/// A clipping shape, for `clip-path`. -pub type GenericClippingShape = GenericShapeSource; - /// #[allow(missing_docs)] #[derive( Animate, Clone, + ComputeSquaredDistance, Copy, Debug, MallocSizeOf, @@ -57,9 +55,6 @@ impl Default for ShapeGeometryBox { } } -/// A float area shape, for `shape-outside`. -pub type GenericFloatAreaShape = GenericShapeSource; - /// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] @@ -67,6 +62,7 @@ pub type GenericFloatAreaShape = GenericShapeSource -where - ReferenceBox: Default + PartialEq, -{ - #[animation(error)] - ImageOrUrl(I), - Shape(Box, #[css(skip_if = "is_default")] ReferenceBox), - #[animation(error)] - Box(ReferenceBox), - #[css(function)] - Path(Path), +pub enum GenericClipPath { #[animation(error)] None, + #[animation(error)] + Url(U), + #[css(function)] + Path(Path), + Shape(Box, #[css(skip_if = "is_default")] ShapeGeometryBox), + #[animation(error)] + Box(ShapeGeometryBox), } -pub use self::GenericShapeSource as ShapeSource; +pub use self::GenericClipPath as ClipPath; + +/// A value for the `shape-outside` property. +#[allow(missing_docs)] +#[animation(no_bound(I))] +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum GenericShapeOutside { + #[animation(error)] + None, + #[animation(error)] + Image(I), + Shape(Box, #[css(skip_if = "is_default")] ShapeBox), + #[animation(error)] + Box(ShapeBox), +} + +pub use self::GenericShapeOutside as ShapeOutside; #[allow(missing_docs)] #[derive( @@ -340,6 +364,7 @@ pub enum FillRule { #[derive( Animate, Clone, + ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, @@ -360,33 +385,13 @@ pub struct Path { pub path: SVGPathData, } -// FIXME(nox): Implement ComputeSquaredDistance for T types and stop -// using PartialEq here, this will let us derive this impl. -impl ComputeSquaredDistance for ShapeSource -where - B: ComputeSquaredDistance, - T: Default + PartialEq, -{ - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - ( - &ShapeSource::Shape(ref this, ref this_box), - &ShapeSource::Shape(ref other, ref other_box), - ) if this_box == other_box => this.compute_squared_distance(other), - (&ShapeSource::Path(ref this), &ShapeSource::Path(ref other)) - if this.fill == other.fill => - { - this.path.compute_squared_distance(&other.path) - }, - _ => Err(()), - } +impl ToAnimatedZero for ClipPath { + fn to_animated_zero(&self) -> Result { + Err(()) } } -impl ToAnimatedZero for ShapeSource -where - T: Default + PartialEq, -{ +impl ToAnimatedZero for ShapeOutside { fn to_animated_zero(&self) -> Result { Err(()) } diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index 188ec19279f..0811fb627a7 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -9,7 +9,7 @@ use crate::parser::{Parse, ParserContext}; use crate::values::generics::basic_shape as generic; -use crate::values::generics::basic_shape::{Path, PolygonCoord, ShapeSource}; +use crate::values::generics::basic_shape::{Path, PolygonCoord}; use crate::values::generics::rect::Rect; use crate::values::specified::border::BorderRadius; use crate::values::specified::image::Image; @@ -24,11 +24,11 @@ use style_traits::{ParseError, StyleParseErrorKind}; /// A specified alias for FillRule. pub use crate::values::generics::basic_shape::FillRule; -/// A specified clipping shape. -pub type ClippingShape = generic::GenericClippingShape; +/// A specified `clip-path` value. +pub type ClipPath = generic::GenericClipPath; -/// A specified float area shape. -pub type FloatAreaShape = generic::GenericFloatAreaShape; +/// A specified `shape-outside` value. +pub type ShapeOutside = generic::GenericShapeOutside; /// A specified basic shape. pub type BasicShape = generic::GenericBasicShape< @@ -64,31 +64,78 @@ fn is_clip_path_path_enabled(_: &ParserContext) -> bool { false } -impl Parse for ClippingShape { +/// A helper for both clip-path and shape-outside parsing of shapes. +fn parse_shape_or_box<'i, 't, R, ReferenceBox>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + to_shape: impl FnOnce(Box, ReferenceBox) -> R, + to_reference_box: impl FnOnce(ReferenceBox) -> R, +) -> Result> +where + ReferenceBox: Default + Parse, +{ + fn parse_component( + context: &ParserContext, + input: &mut Parser, + component: &mut Option, + ) -> bool { + if component.is_some() { + return false; // already parsed this component + } + + *component = input.try(|i| U::parse(context, i)).ok(); + component.is_some() + } + + let mut shape = None; + let mut ref_box = None; + + while parse_component(context, input, &mut shape) || + parse_component(context, input, &mut ref_box) + { + // + } + + if let Some(shp) = shape { + return Ok(to_shape(Box::new(shp), ref_box.unwrap_or_default())); + } + + match ref_box { + Some(r) => Ok(to_reference_box(r)), + None => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), + } +} + +impl Parse for ClipPath { #[inline] fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { if input.try(|i| i.expect_ident_matching("none")).is_ok() { - return Ok(ShapeSource::None); + return Ok(ClipPath::None); } if is_clip_path_path_enabled(context) { if let Ok(p) = input.try(|i| Path::parse(context, i)) { - return Ok(ShapeSource::Path(p)); + return Ok(ClipPath::Path(p)); } } if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) { - return Ok(ShapeSource::ImageOrUrl(url)); + return Ok(ClipPath::Url(url)); } - Self::parse_common(context, input) + parse_shape_or_box( + context, + input, + ClipPath::Shape, + ClipPath::Box, + ) } } -impl Parse for FloatAreaShape { +impl Parse for ShapeOutside { #[inline] fn parse<'i, 't>( context: &ParserContext, @@ -97,56 +144,20 @@ impl Parse for FloatAreaShape { // Need to parse this here so that `Image::parse_with_cors_anonymous` // doesn't parse it. if input.try(|i| i.expect_ident_matching("none")).is_ok() { - return Ok(ShapeSource::None); + return Ok(ShapeOutside::None); } if let Ok(image) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) { debug_assert_ne!(image, Image::None); - return Ok(ShapeSource::ImageOrUrl(image)); + return Ok(ShapeOutside::Image(image)); } - Self::parse_common(context, input) - } -} - -impl ShapeSource -where - ReferenceBox: Parse + Default + PartialEq, -{ - /// The internal parser for ShapeSource. - fn parse_common<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - fn parse_component( - context: &ParserContext, - input: &mut Parser, - component: &mut Option, - ) -> bool { - if component.is_some() { - return false; // already parsed this component - } - - *component = input.try(|i| U::parse(context, i)).ok(); - component.is_some() - } - - let mut shape = None; - let mut ref_box = None; - - while parse_component(context, input, &mut shape) || - parse_component(context, input, &mut ref_box) - { - // - } - - if let Some(shp) = shape { - return Ok(ShapeSource::Shape(Box::new(shp), ref_box.unwrap_or_default())); - } - - ref_box - .map(ShapeSource::Box) - .ok_or(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + parse_shape_or_box( + context, + input, + ShapeOutside::Shape, + ShapeOutside::Box, + ) } }