tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 077dbc25530d8e63a4c089d92828de59cd9b5d73
parent d47799cfcf2ad693ec82af011bbf69d24bd90a7d
Author: Narcis Beleuzu <nbeleuzu@mozilla.com>
Date:   Sat, 15 Nov 2025 03:35:37 +0200

Revert "Bug 1993308 - Fix specified value serialization of <position> in shape() to preserve keyword syntax. r=firefox-style-system-reviewers,layout-reviewers,emilio" for mochitest failure on test_bug877690.html

This reverts commit aa33de4425adac8807d2d043aac32ac82491c3e2.

Diffstat:
Mdom/svg/SVGAnimatedPathSegList.cpp | 15++++++++-------
Mdom/svg/SVGPathData.cpp | 6+++---
Mdom/svg/SVGPathElement.cpp | 8++++----
Mdom/svg/SVGPathSegUtils.h | 23++---------------------
Mdom/svg/SVGPathSegment.cpp | 9+++++----
Mdom/svg/SVGPathSegment.h | 4++--
Mlayout/base/MotionPathUtils.cpp | 6++----
Mlayout/style/ServoStyleConstsInlines.h | 30++++++++++++------------------
Mservo/components/style/values/computed/basic_shape.rs | 35+++++++++++++++++------------------
Mservo/components/style/values/generics/basic_shape.rs | 128++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mservo/components/style/values/specified/basic_shape.rs | 55++++++++++++++++++++++++++++++++++---------------------
Mservo/components/style/values/specified/svg_path.rs | 65++++++++++++++++++++++++++++++++++-------------------------------
Mtesting/web-platform/meta/css/css-shapes/shape-functions/shape-function-valid.html.ini | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtesting/web-platform/meta/css/motion/parsing/offset-path-shape-parsing.html.ini | 43+++++++++++++++++++++++++++++++++++++++++++
14 files changed, 290 insertions(+), 199 deletions(-)

diff --git a/dom/svg/SVGAnimatedPathSegList.cpp b/dom/svg/SVGAnimatedPathSegList.cpp @@ -30,20 +30,21 @@ nsresult SVGAnimatedPathSegList::SetBaseValueString(const nsAString& aValue) { enum class PositionType { Absolute, Relative }; -static StyleEndPoint<float> MakeEndPoint(PositionType type, float x, float y) { +static StyleCommandEndPoint<float> MakeEndPoint(PositionType type, float x, + float y) { if (type == PositionType::Absolute) { - return StyleEndPoint<float>::ToPosition({x, y}); + return StyleCommandEndPoint<float>::ToPosition({x, y}); } else { - return StyleEndPoint<float>::ByCoordinate({x, y}); + return StyleCommandEndPoint<float>::ByCoordinate({x, y}); } } -static StyleCurveControlPoint<float> MakeControlPoint(PositionType type, - float x, float y) { +static StyleControlPoint<float> MakeControlPoint(PositionType type, float x, + float y) { if (type == PositionType::Absolute) { - return StyleCurveControlPoint<float>::Absolute({x, y}); + return StyleControlPoint<float>::Position({x, y}); } else { - return StyleCurveControlPoint<float>::Relative( + return StyleControlPoint<float>::Relative( StyleRelativeControlPoint<float>{{x, y}, StyleControlReference::None}); } } diff --git a/dom/svg/SVGPathData.cpp b/dom/svg/SVGPathData.cpp @@ -199,13 +199,13 @@ static inline StyleCSSFloat Resolve(const LengthPercentage& aValue, return aValue.ResolveToCSSPixels(aBasis); } -template <typename Angle, typename Position, typename LP> +template <typename Angle, typename LP> static already_AddRefed<Path> BuildPathInternal( - Span<const StyleGenericShapeCommand<Angle, Position, LP>> aPath, + Span<const StyleGenericShapeCommand<Angle, LP>> aPath, PathBuilder* aBuilder, StyleStrokeLinecap aStrokeLineCap, Float aStrokeWidth, const CSSSize& aPercentageBasis, const Point& aOffset, float aZoomFactor) { - using Command = StyleGenericShapeCommand<Angle, Position, LP>; + using Command = StyleGenericShapeCommand<Angle, LP>; if (aPath.IsEmpty() || !aPath[0].IsMove()) { return nullptr; // paths without an initial moveto are invalid diff --git a/dom/svg/SVGPathElement.cpp b/dom/svg/SVGPathElement.cpp @@ -137,10 +137,10 @@ static void CreatePathSegments(SVGPathElement* aPathElement, Point cp1, cp2; while (converter.GetNextSegment(&cp1, &cp2, &segEnd)) { auto curve = StylePathCommand::CubicCurve( - StyleEndPoint<StyleCSSFloat>::ToPosition({segEnd.x, segEnd.y}), - StyleCurveControlPoint<StyleCSSFloat>::Absolute({cp1.x, cp1.y}), - StyleCurveControlPoint<StyleCSSFloat>::Absolute( - {cp2.x, cp2.y})); + StyleCommandEndPoint<StyleCSSFloat>::ToPosition( + {segEnd.x, segEnd.y}), + StyleControlPoint<StyleCSSFloat>::Position({cp1.x, cp1.y}), + StyleControlPoint<StyleCSSFloat>::Position({cp2.x, cp2.y})); aValues.AppendElement(new SVGPathSegment(aPathElement, curve)); } break; diff --git a/dom/svg/SVGPathSegUtils.h b/dom/svg/SVGPathSegUtils.h @@ -12,28 +12,9 @@ #include "mozilla/gfx/Rect.h" namespace mozilla { - -// Position -template <typename H, typename V> -struct StyleGenericPosition; - -// Command Endpoint -template <typename Position, typename LP> -struct StyleCommandEndPoint; -template <typename T> -using StyleEndPoint = StyleCommandEndPoint<StyleGenericPosition<T, T>, T>; - -// Control Point -template <typename Position, typename LP> -struct StyleControlPoint; -template <typename T> -using StyleCurveControlPoint = StyleControlPoint<StyleGenericPosition<T, T>, T>; - -// Shape Command -template <typename Angle, typename Position, typename LP> +template <typename Angle, typename LP> struct StyleGenericShapeCommand; -using StylePathCommand = - StyleGenericShapeCommand<float, StyleGenericPosition<float, float>, float>; +using StylePathCommand = StyleGenericShapeCommand<float, float>; /** * Code that works with path segments can use an instance of this class to diff --git a/dom/svg/SVGPathSegment.cpp b/dom/svg/SVGPathSegment.cpp @@ -20,7 +20,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGPathSegment, mSVGPathElement) //---------------------------------------------------------------------- // Implementation -void SVGPathSegment::AppendEndPoint(const StyleEndPoint<StyleCSSFloat>& point) { +void SVGPathSegment::AppendEndPoint( + const StyleCommandEndPoint<StyleCSSFloat>& point) { if (point.IsToPosition()) { const auto& pos = point.AsToPosition(); mValues.AppendElement(pos.horizontal); @@ -33,9 +34,9 @@ void SVGPathSegment::AppendEndPoint(const StyleEndPoint<StyleCSSFloat>& point) { } void SVGPathSegment::AppendControlPoint( - const StyleCurveControlPoint<StyleCSSFloat>& point) { - if (point.IsAbsolute()) { - const auto& pos = point.AsAbsolute(); + const StyleControlPoint<StyleCSSFloat>& point) { + if (point.IsPosition()) { + const auto& pos = point.AsPosition(); mValues.AppendElement(pos.horizontal); mValues.AppendElement(pos.vertical); } else if (point.IsRelative()) { diff --git a/dom/svg/SVGPathSegment.h b/dom/svg/SVGPathSegment.h @@ -42,8 +42,8 @@ class SVGPathSegment final : public nsWrapperCache { RefPtr<SVGPathElement> mSVGPathElement; nsString mCommand; nsTArray<float> mValues; - void AppendEndPoint(const StyleEndPoint<StyleCSSFloat>& point); - void AppendControlPoint(const StyleCurveControlPoint<StyleCSSFloat>& point); + void AppendEndPoint(const StyleCommandEndPoint<StyleCSSFloat>& point); + void AppendControlPoint(const StyleControlPoint<StyleCSSFloat>& point); }; } // namespace mozilla::dom diff --git a/layout/base/MotionPathUtils.cpp b/layout/base/MotionPathUtils.cpp @@ -475,10 +475,8 @@ static already_AddRefed<gfx::Path> BuildDefaultPathForURL( return nullptr; } - using CommandEndPoint = - StyleCommandEndPoint<StyleShapePosition<StyleCSSFloat>, StyleCSSFloat>; - Array<const StylePathCommand, 1> array( - StylePathCommand::Move(CommandEndPoint::ByCoordinate({0.0, 0.0}))); + Array<const StylePathCommand, 1> array(StylePathCommand::Move( + StyleCommandEndPoint<StyleCSSFloat>::ByCoordinate({0.0, 0.0}))); return SVGPathData::BuildPath(array, aBuilder, StyleStrokeLinecap::Butt, 0.0); } diff --git a/layout/style/ServoStyleConstsInlines.h b/layout/style/ServoStyleConstsInlines.h @@ -1291,9 +1291,8 @@ inline gfx::Point StyleShapePosition<LengthPercentage>::ToGfxPoint( } template <> -inline gfx::Point -StyleCommandEndPoint<StyleShapePosition<StyleCSSFloat>, - StyleCSSFloat>::ToGfxPoint(const CSSSize* aBasis) const { +inline gfx::Point StyleCommandEndPoint<StyleCSSFloat>::ToGfxPoint( + const CSSSize* aBasis) const { if (IsToPosition()) { auto& pos = AsToPosition(); return pos.ToGfxPoint(); @@ -1304,9 +1303,8 @@ StyleCommandEndPoint<StyleShapePosition<StyleCSSFloat>, } template <> -inline gfx::Point StyleCommandEndPoint< - StyleShapePosition<LengthPercentage>, - LengthPercentage>::ToGfxPoint(const CSSSize* aBasis) const { +inline gfx::Point StyleCommandEndPoint<LengthPercentage>::ToGfxPoint( + const CSSSize* aBasis) const { MOZ_ASSERT(aBasis); if (IsToPosition()) { auto& pos = AsToPosition(); @@ -1318,12 +1316,11 @@ inline gfx::Point StyleCommandEndPoint< } template <> -inline gfx::Point -StyleControlPoint<StyleShapePosition<StyleCSSFloat>, StyleCSSFloat>::ToGfxPoint( +inline gfx::Point StyleControlPoint<StyleCSSFloat>::ToGfxPoint( const gfx::Point aStatePos, const gfx::Point aEndPoint, const bool isRelativeEndPoint, const CSSSize* aBasis) const { - if (IsAbsolute()) { - auto& pos = AsAbsolute(); + if (IsPosition()) { + auto& pos = AsPosition(); return pos.ToGfxPoint(); } @@ -1344,15 +1341,12 @@ StyleControlPoint<StyleShapePosition<StyleCSSFloat>, StyleCSSFloat>::ToGfxPoint( } template <> -inline gfx::Point -StyleControlPoint<StyleShapePosition<LengthPercentage>, - LengthPercentage>::ToGfxPoint(const gfx::Point aStatePos, - const gfx::Point aEndPoint, - const bool isRelativeEndPoint, - const CSSSize* aBasis) const { +inline gfx::Point StyleControlPoint<LengthPercentage>::ToGfxPoint( + const gfx::Point aStatePos, const gfx::Point aEndPoint, + const bool isRelativeEndPoint, const CSSSize* aBasis) const { MOZ_ASSERT(aBasis); - if (IsAbsolute()) { - auto& pos = AsAbsolute(); + if (IsPosition()) { + auto& pos = AsPosition(); return pos.ToGfxPoint(aBasis); } diff --git a/servo/components/style/values/computed/basic_shape.rs b/servo/components/style/values/computed/basic_shape.rs @@ -10,9 +10,9 @@ use crate::values::animated::{Animate, Procedure}; use crate::values::computed::angle::Angle; use crate::values::computed::url::ComputedUrl; -use crate::values::computed::{Image, LengthPercentage, Position}; +use crate::values::computed::{Image, LengthPercentage, NonNegativeLengthPercentage, Position}; use crate::values::generics::basic_shape as generic; -use crate::values::generics::basic_shape::ShapePosition; +use crate::values::generics::position::Position as GenericPosition; use crate::values::specified::svg_path::{CoordPair, PathCommand}; use crate::values::CSSFloat; @@ -32,35 +32,34 @@ pub type BasicShape = generic::GenericBasicShape<Angle, Position, LengthPercenta pub type InsetRect = generic::GenericInsetRect<LengthPercentage>; /// A computed circle. -pub type Circle = generic::Circle<LengthPercentage>; +pub type Circle = generic::Circle<Position, NonNegativeLengthPercentage>; /// A computed ellipse. -pub type Ellipse = generic::Ellipse<LengthPercentage>; +pub type Ellipse = generic::Ellipse<Position, NonNegativeLengthPercentage>; /// The computed value of `ShapeRadius`. -pub type ShapeRadius = generic::GenericShapeRadius<LengthPercentage>; +pub type ShapeRadius = generic::GenericShapeRadius<NonNegativeLengthPercentage>; /// The computed value of `shape()`. -pub type Shape = generic::Shape<Angle, Position, LengthPercentage>; +pub type Shape = generic::Shape<Angle, LengthPercentage>; /// The computed value of `ShapeCommand`. -pub type ShapeCommand = generic::GenericShapeCommand<Angle, Position, LengthPercentage>; +pub type ShapeCommand = generic::GenericShapeCommand<Angle, LengthPercentage>; /// The computed value of `PathOrShapeFunction`. -pub type PathOrShapeFunction = - generic::GenericPathOrShapeFunction<Angle, Position, LengthPercentage>; +pub type PathOrShapeFunction = generic::GenericPathOrShapeFunction<Angle, LengthPercentage>; /// The computed value of `CoordinatePair`. pub type CoordinatePair = generic::CoordinatePair<LengthPercentage>; /// The computed value of 'ControlPoint'. -pub type ControlPoint = generic::ControlPoint<Position, LengthPercentage>; +pub type ControlPoint = generic::ControlPoint<LengthPercentage>; /// The computed value of 'RelativeControlPoint'. pub type RelativeControlPoint = generic::RelativeControlPoint<LengthPercentage>; /// The computed value of 'CommandEndPoint'. -pub type CommandEndPoint = generic::CommandEndPoint<Position, LengthPercentage>; +pub type CommandEndPoint = generic::CommandEndPoint<LengthPercentage>; /// Animate from `Shape` to `Path`, and vice versa. macro_rules! animate_shape { @@ -215,9 +214,9 @@ impl From<&CoordPair> for CoordinatePair { } } -impl From<&ShapePosition<CSSFloat>> for Position { +impl From<&GenericPosition<CSSFloat, CSSFloat>> for Position { #[inline] - fn from(p: &ShapePosition<CSSFloat>) -> Self { + fn from(p: &GenericPosition<CSSFloat, CSSFloat>) -> Self { use crate::values::computed::CSSPixelLength; Self::new( LengthPercentage::new_length(CSSPixelLength::new(p.horizontal)), @@ -226,9 +225,9 @@ impl From<&ShapePosition<CSSFloat>> for Position { } } -impl From<&generic::CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>> for CommandEndPoint { +impl From<&generic::CommandEndPoint<CSSFloat>> for CommandEndPoint { #[inline] - fn from(p: &generic::CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>) -> Self { + fn from(p: &generic::CommandEndPoint<CSSFloat>) -> Self { match p { generic::CommandEndPoint::ToPosition(pos) => Self::ToPosition(pos.into()), generic::CommandEndPoint::ByCoordinate(coord) => Self::ByCoordinate(coord.into()), @@ -236,11 +235,11 @@ impl From<&generic::CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>> for Comm } } -impl From<&generic::ControlPoint<ShapePosition<CSSFloat>, CSSFloat>> for ControlPoint { +impl From<&generic::ControlPoint<CSSFloat>> for ControlPoint { #[inline] - fn from(p: &generic::ControlPoint<ShapePosition<CSSFloat>, CSSFloat>) -> Self { + fn from(p: &generic::ControlPoint<CSSFloat>) -> Self { match p { - generic::ControlPoint::Absolute(pos) => Self::Absolute(pos.into()), + generic::ControlPoint::Position(pos) => Self::Position(pos.into()), generic::ControlPoint::Relative(point) => Self::Relative(RelativeControlPoint { coord: CoordinatePair::from(&point.coord), reference: point.reference, diff --git a/servo/components/style/values/generics/basic_shape.rs b/servo/components/style/values/generics/basic_shape.rs @@ -18,7 +18,8 @@ use crate::Zero; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; -/// A generic value for `<position>` in circle(), ellipse(), and shape(). +/// TODO(bug 1982941): Replace with GenericPosition directly if ShapePosition is under utilized. +/// A generic value for `<position>` in basic_shape. pub type ShapePosition<LengthPercentage> = GenericPosition<LengthPercentage, LengthPercentage>; /// <https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box> @@ -206,14 +207,14 @@ pub enum GenericBasicShape<Angle, Position, LengthPercentage, BasicShapeRect> { #[animation(field_bound)] #[css(field_bound)] #[shmem(field_bound)] - Circle<LengthPercentage>, + Circle<Position, NonNegative<LengthPercentage>>, ), /// Defines an ellipse with a center and x-axis/y-axis radii. Ellipse( #[animation(field_bound)] #[css(field_bound)] #[shmem(field_bound)] - Ellipse<LengthPercentage>, + Ellipse<Position, NonNegative<LengthPercentage>>, ), /// Defines a polygon with pair arguments. Polygon(GenericPolygon<LengthPercentage>), @@ -221,7 +222,7 @@ pub enum GenericBasicShape<Angle, Position, LengthPercentage, BasicShapeRect> { PathOrShape( #[animation(field_bound)] #[css(field_bound)] - GenericPathOrShapeFunction<Angle, Position, LengthPercentage>, + GenericPathOrShapeFunction<Angle, LengthPercentage>, ), } @@ -275,10 +276,9 @@ pub use self::GenericInsetRect as InsetRect; )] #[css(function)] #[repr(C)] -pub struct Circle<LengthPercentage> { - pub position: GenericPositionOrAuto<ShapePosition<LengthPercentage>>, - #[animation(field_bound)] - pub radius: GenericShapeRadius<LengthPercentage>, +pub struct Circle<Position, NonNegativeLengthPercentage> { + pub position: GenericPositionOrAuto<Position>, + pub radius: GenericShapeRadius<NonNegativeLengthPercentage>, } /// <https://drafts.csswg.org/css-shapes/#funcdef-ellipse> @@ -301,12 +301,10 @@ pub struct Circle<LengthPercentage> { )] #[css(function)] #[repr(C)] -pub struct Ellipse<LengthPercentage> { - pub position: GenericPositionOrAuto<ShapePosition<LengthPercentage>>, - #[animation(field_bound)] - pub semiaxis_x: GenericShapeRadius<LengthPercentage>, - #[animation(field_bound)] - pub semiaxis_y: GenericShapeRadius<LengthPercentage>, +pub struct Ellipse<Position, NonNegativeLengthPercentage> { + pub position: GenericPositionOrAuto<Position>, + pub semiaxis_x: GenericShapeRadius<NonNegativeLengthPercentage>, + pub semiaxis_y: GenericShapeRadius<NonNegativeLengthPercentage>, } /// <https://drafts.csswg.org/css-shapes/#typedef-shape-radius> @@ -330,12 +328,8 @@ pub struct Ellipse<LengthPercentage> { ToShmem, )] #[repr(C, u8)] -pub enum GenericShapeRadius<LengthPercentage> { - Length( - #[animation(field_bound)] - #[parse(field_bound)] - NonNegative<LengthPercentage>, - ), +pub enum GenericShapeRadius<NonNegativeLengthPercentage> { + Length(NonNegativeLengthPercentage), #[animation(error)] ClosestSide, #[animation(error)] @@ -411,11 +405,11 @@ pub struct PolygonCoord<LengthPercentage>(pub LengthPercentage, pub LengthPercen ToShmem, )] #[repr(C, u8)] -pub enum GenericPathOrShapeFunction<Angle, Position, LengthPercentage> { +pub enum GenericPathOrShapeFunction<Angle, LengthPercentage> { /// 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<Angle, Position, LengthPercentage>), + Shape(#[css(field_bound)] Shape<Angle, LengthPercentage>), } // https://drafts.csswg.org/css-shapes/#typedef-fill-rule @@ -516,10 +510,10 @@ where } } -impl<LengthPercentage> ToCss for Circle<LengthPercentage> +impl<Position, NonNegativeLengthPercentage> ToCss for Circle<Position, NonNegativeLengthPercentage> where - LengthPercentage: ToCss + PartialEq, - ShapePosition<LengthPercentage>: ToCss, + Position: ToCss, + NonNegativeLengthPercentage: ToCss + PartialEq, { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where @@ -545,10 +539,10 @@ where } } -impl<LengthPercentage> ToCss for Ellipse<LengthPercentage> +impl<Position, NonNegativeLengthPercentage> ToCss for Ellipse<Position, NonNegativeLengthPercentage> where - LengthPercentage: ToCss + PartialEq, - ShapePosition<LengthPercentage>: ToCss, + Position: ToCss, + NonNegativeLengthPercentage: ToCss + PartialEq, { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where @@ -643,27 +637,26 @@ fn is_default<T: Default + PartialEq>(fill: &T) -> bool { ToShmem, )] #[repr(C)] -pub struct Shape<Angle, Position, LengthPercentage> { +pub struct Shape<Angle, LengthPercentage> { /// 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<GenericShapeCommand<Angle, Position, LengthPercentage>>, + pub commands: crate::OwnedSlice<GenericShapeCommand<Angle, LengthPercentage>>, } -impl<Angle, Position, LengthPercentage> Shape<Angle, Position, LengthPercentage> { +impl<Angle, LengthPercentage> Shape<Angle, LengthPercentage> { /// Returns the slice of GenericShapeCommand<..>. #[inline] - pub fn commands(&self) -> &[GenericShapeCommand<Angle, Position, LengthPercentage>] { + pub fn commands(&self) -> &[GenericShapeCommand<Angle, LengthPercentage>] { &self.commands } } -impl<Angle, Position, LengthPercentage> Animate for Shape<Angle, Position, LengthPercentage> +impl<Angle, LengthPercentage> Animate for Shape<Angle, LengthPercentage> where Angle: Animate, - Position: Animate, LengthPercentage: Animate, { fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { @@ -679,11 +672,9 @@ where } } -impl<Angle, Position, LengthPercentage> ComputeSquaredDistance - for Shape<Angle, Position, LengthPercentage> +impl<Angle, LengthPercentage> ComputeSquaredDistance for Shape<Angle, LengthPercentage> where Angle: ComputeSquaredDistance, - Position: ComputeSquaredDistance, LengthPercentage: ComputeSquaredDistance, { fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { @@ -694,11 +685,11 @@ where } } -impl<Angle, Position, LengthPercentage> ToCss for Shape<Angle, Position, LengthPercentage> +impl<Angle, LengthPercentage> ToCss for Shape<Angle, LengthPercentage> where Angle: ToCss + Zero, - Position: ToCss, LengthPercentage: PartialEq + ToCss, + ShapePosition<LengthPercentage>: ToCss, { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where @@ -718,7 +709,11 @@ where match &self.commands[0] { ShapeCommand::Move { point: CommandEndPoint::ToPosition(pos), - } => pos.to_css(dest)?, + } => { + pos.horizontal.to_css(dest)?; + dest.write_char(' ')?; + pos.vertical.to_css(dest)? + }, ShapeCommand::Move { point: CommandEndPoint::ByCoordinate(coord), } => coord.to_css(dest)?, @@ -758,14 +753,14 @@ where )] #[allow(missing_docs)] #[repr(C, u8)] -pub enum GenericShapeCommand<Angle, Position, LengthPercentage> { +pub enum GenericShapeCommand<Angle, LengthPercentage> { /// The move command. Move { - point: CommandEndPoint<Position, LengthPercentage>, + point: CommandEndPoint<LengthPercentage>, }, /// The line command. Line { - point: CommandEndPoint<Position, LengthPercentage>, + point: CommandEndPoint<LengthPercentage>, }, /// The hline command. HLine { by_to: ByTo, x: LengthPercentage }, @@ -773,27 +768,27 @@ pub enum GenericShapeCommand<Angle, Position, LengthPercentage> { VLine { by_to: ByTo, y: LengthPercentage }, /// The cubic Bézier curve command. CubicCurve { - point: CommandEndPoint<Position, LengthPercentage>, - control1: ControlPoint<Position, LengthPercentage>, - control2: ControlPoint<Position, LengthPercentage>, + point: CommandEndPoint<LengthPercentage>, + control1: ControlPoint<LengthPercentage>, + control2: ControlPoint<LengthPercentage>, }, /// The quadratic Bézier curve command. QuadCurve { - point: CommandEndPoint<Position, LengthPercentage>, - control1: ControlPoint<Position, LengthPercentage>, + point: CommandEndPoint<LengthPercentage>, + control1: ControlPoint<LengthPercentage>, }, /// The smooth command. SmoothCubic { - point: CommandEndPoint<Position, LengthPercentage>, - control2: ControlPoint<Position, LengthPercentage>, + point: CommandEndPoint<LengthPercentage>, + control2: ControlPoint<LengthPercentage>, }, /// The smooth quadratic Bézier curve command. SmoothQuad { - point: CommandEndPoint<Position, LengthPercentage>, + point: CommandEndPoint<LengthPercentage>, }, /// The arc command. Arc { - point: CommandEndPoint<Position, LengthPercentage>, + point: CommandEndPoint<LengthPercentage>, radii: CoordinatePair<LengthPercentage>, arc_sweep: ArcSweep, arc_size: ArcSize, @@ -805,11 +800,11 @@ pub enum GenericShapeCommand<Angle, Position, LengthPercentage> { pub use self::GenericShapeCommand as ShapeCommand; -impl<Angle, Position, LengthPercentage> ToCss for ShapeCommand<Angle, Position, LengthPercentage> +impl<Angle, LengthPercentage> ToCss for ShapeCommand<Angle, LengthPercentage> where Angle: ToCss + Zero, - Position: ToCss, LengthPercentage: PartialEq + ToCss, + ShapePosition<LengthPercentage>: ToCss, { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where @@ -977,12 +972,12 @@ impl ByTo { ToShmem, )] #[repr(C, u8)] -pub enum CommandEndPoint<Position, LengthPercentage> { - ToPosition(Position), +pub enum CommandEndPoint<LengthPercentage> { + ToPosition(ShapePosition<LengthPercentage>), ByCoordinate(CoordinatePair<LengthPercentage>), } -impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> { +impl<LengthPercentage> CommandEndPoint<LengthPercentage> { /// Return true if it is absolute, i.e. it is To. #[inline] pub fn is_abs(&self) -> bool { @@ -990,17 +985,18 @@ impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> { } } -impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> { +impl<LengthPercentage: ToCss> ToCss for CommandEndPoint<LengthPercentage> { + /// TODO(bug 1993308): Should print position keywords as keywords. I.e. like the to_css in specified/position.rs. fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write, - Position: ToCss, - LengthPercentage: ToCss, { match self { CommandEndPoint::ToPosition(pos) => { dest.write_str("to ")?; - pos.to_css(dest) + pos.horizontal.to_css(dest)?; + dest.write_char(' ')?; + pos.vertical.to_css(dest) }, CommandEndPoint::ByCoordinate(coord) => { dest.write_str("by ")?; @@ -1070,21 +1066,21 @@ impl<LengthPercentage> CoordinatePair<LengthPercentage> { ToShmem, )] #[repr(C, u8)] -pub enum ControlPoint<Position, LengthPercentage> { - Absolute(Position), +pub enum ControlPoint<LengthPercentage> { + Position(ShapePosition<LengthPercentage>), Relative(RelativeControlPoint<LengthPercentage>), } -impl<Position, LengthPercentage> ControlPoint<Position, LengthPercentage> { +impl<LengthPercentage> ControlPoint<LengthPercentage> { /// Serialize <control-point> pub fn to_css<W>(&self, dest: &mut CssWriter<W>, is_endpoint_abs: bool) -> fmt::Result where W: Write, - Position: ToCss, LengthPercentage: ToCss, + ShapePosition<LengthPercentage>: ToCss, { match self { - ControlPoint::Absolute(pos) => pos.to_css(dest), + ControlPoint::Position(pos) => pos.to_css(dest), ControlPoint::Relative(point) => point.to_css(dest, is_endpoint_abs), } } diff --git a/servo/components/style/values/specified/basic_shape.rs b/servo/components/style/values/specified/basic_shape.rs @@ -12,13 +12,13 @@ use crate::values::computed::basic_shape::InsetRect as ComputedInsetRect; use crate::values::computed::{Context, ToComputedValue}; use crate::values::generics::basic_shape as generic; use crate::values::generics::basic_shape::{Path, PolygonCoord}; -use crate::values::generics::position::GenericPositionOrAuto; +use crate::values::generics::position::{GenericPosition, GenericPositionOrAuto}; use crate::values::generics::rect::Rect; use crate::values::specified::angle::Angle; use crate::values::specified::border::BorderRadius; use crate::values::specified::image::Image; use crate::values::specified::length::LengthPercentageOrAuto; -use crate::values::specified::position::{Position, Side}; +use crate::values::specified::position::Side; use crate::values::specified::url::SpecifiedUrl; use crate::values::specified::PositionComponent; use crate::values::specified::{LengthPercentage, NonNegativeLengthPercentage, SVGPathData}; @@ -39,32 +39,32 @@ pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>; /// A specified value for `at <position>` in circle() and ellipse(). // Note: its computed value is the same as computed::position::Position. We just want to always use // LengthPercentage as the type of its components, for basic shapes. -pub type RadialPosition = generic::ShapePosition<LengthPercentage>; +pub type ShapePosition = GenericPosition<LengthPercentage, LengthPercentage>; /// A specified basic shape. -pub type BasicShape = generic::GenericBasicShape<Angle, Position, LengthPercentage, BasicShapeRect>; +pub type BasicShape = + generic::GenericBasicShape<Angle, ShapePosition, LengthPercentage, BasicShapeRect>; /// The specified value of `inset()`. pub type InsetRect = generic::GenericInsetRect<LengthPercentage>; /// A specified circle. -pub type Circle = generic::Circle<LengthPercentage>; +pub type Circle = generic::Circle<ShapePosition, NonNegativeLengthPercentage>; /// A specified ellipse. -pub type Ellipse = generic::Ellipse<LengthPercentage>; +pub type Ellipse = generic::Ellipse<ShapePosition, NonNegativeLengthPercentage>; /// The specified value of `ShapeRadius`. -pub type ShapeRadius = generic::ShapeRadius<LengthPercentage>; +pub type ShapeRadius = generic::ShapeRadius<NonNegativeLengthPercentage>; /// The specified value of `Polygon`. pub type Polygon = generic::GenericPolygon<LengthPercentage>; /// The specified value of `PathOrShapeFunction`. -pub type PathOrShapeFunction = - generic::GenericPathOrShapeFunction<Angle, Position, LengthPercentage>; +pub type PathOrShapeFunction = generic::GenericPathOrShapeFunction<Angle, LengthPercentage>; /// The specified value of `ShapeCommand`. -pub type ShapeCommand = generic::GenericShapeCommand<Angle, Position, LengthPercentage>; +pub type ShapeCommand = generic::GenericShapeCommand<Angle, LengthPercentage>; /// The specified value of `xywh()`. /// Defines a rectangle via offsets from the top and left edge of the reference box, and a @@ -384,7 +384,7 @@ impl InsetRect { } } -impl ToCss for RadialPosition { +impl ToCss for ShapePosition { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write, @@ -427,11 +427,11 @@ fn convert_to_length_percentage<S: Side>(c: PositionComponent<S>) -> LengthPerce fn parse_at_position<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, -) -> Result<GenericPositionOrAuto<RadialPosition>, ParseError<'i>> { +) -> Result<GenericPositionOrAuto<ShapePosition>, ParseError<'i>> { use crate::values::specified::position::Position; if input.try_parse(|i| i.expect_ident_matching("at")).is_ok() { Position::parse(context, input).map(|pos| { - GenericPositionOrAuto::Position(RadialPosition::new( + GenericPositionOrAuto::Position(ShapePosition::new( convert_to_length_percentage(pos.horizontal), convert_to_length_percentage(pos.vertical), )) @@ -442,6 +442,19 @@ fn parse_at_position<'i, 't>( } } +fn parse_to_position<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, +) -> Result<ShapePosition, ParseError<'i>> { + use crate::values::specified::position::Position; + Position::parse(context, input).map(|pos| { + ShapePosition::new( + convert_to_length_percentage(pos.horizontal), + convert_to_length_percentage(pos.vertical), + ) + }) +} + impl Parse for Circle { fn parse<'i, 't>( context: &ParserContext, @@ -733,7 +746,7 @@ impl ToComputedValue for BasicShapeRect { } } -impl generic::Shape<Angle, Position, LengthPercentage> { +impl generic::Shape<Angle, LengthPercentage> { /// Parse the inner arguments of a `shape` function. /// shape() = shape(<fill-rule>? from <coordinate-pair>, <shape-command>#) fn parse_function_arguments<'i, 't>( @@ -803,7 +816,7 @@ impl Parse for ShapeCommand { // parse 2 offsets as valid (i.e. hline to left 30% works), and similarly // incorrectly parse top or bottom as valid values. let x = if by_to.is_abs() { - convert_to_length_percentage(Position::parse(context, input)?.horizontal) + parse_to_position(context, input)?.horizontal } else { LengthPercentage::parse(context, input)? }; @@ -813,7 +826,7 @@ impl Parse for ShapeCommand { let by_to = ByTo::parse(input)?; // FIXME(Bug 1993311): Should parse y-start and y-end too. let y = if by_to.is_abs() { - convert_to_length_percentage(Position::parse(context, input)?.horizontal) + parse_to_position(context, input)?.horizontal } else { LengthPercentage::parse(context, input)? }; @@ -910,7 +923,7 @@ impl Parse for generic::CoordinatePair<LengthPercentage> { } } -impl generic::ControlPoint<Position, LengthPercentage> { +impl generic::ControlPoint<LengthPercentage> { /// Parse <control-point> = [ <position> | <relative-control-point> ] fn parse<'i, 't>( context: &ParserContext, @@ -921,8 +934,8 @@ impl generic::ControlPoint<Position, LengthPercentage> { // Parse <position> if by_to.is_abs() && coord.is_err() { - let pos = Position::parse(context, input)?; - return Ok(Self::Absolute(pos)); + let pos = parse_to_position(context, input)?; + return Ok(Self::Position(pos)); } // Parse <relative-control-point> = <coordinate-pair> [from [ start | end | origin ]]? @@ -938,7 +951,7 @@ impl generic::ControlPoint<Position, LengthPercentage> { } } -impl generic::CommandEndPoint<Position, LengthPercentage> { +impl generic::CommandEndPoint<LengthPercentage> { /// Parse <command-end-point> = to <position> | by <coordinate-pair> pub fn parse<'i, 't>( context: &ParserContext, @@ -946,7 +959,7 @@ impl generic::CommandEndPoint<Position, LengthPercentage> { by_to: generic::ByTo, ) -> Result<Self, ParseError<'i>> { if by_to.is_abs() { - let point = Position::parse(context, input)?; + let point = parse_to_position(context, input)?; Ok(Self::ToPosition(point)) } else { let point = generic::CoordinatePair::parse(context, input)?; diff --git a/servo/components/style/values/specified/svg_path.rs b/servo/components/style/values/specified/svg_path.rs @@ -10,9 +10,9 @@ use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; use crate::values::generics::basic_shape::GenericShapeCommand; use crate::values::generics::basic_shape::{ ArcSize, ArcSweep, ByTo, CommandEndPoint, ControlPoint, ControlReference, CoordinatePair, - RelativeControlPoint, ShapePosition, + RelativeControlPoint, }; -use crate::values::generics::position::GenericPosition; +use crate::values::generics::position::GenericPosition as Position; use crate::values::CSSFloat; use cssparser::Parser; use std::fmt::{self, Write}; @@ -22,6 +22,9 @@ use std::slice; use style_traits::values::SequenceWriter; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +/// A specified value for `<position>`. +pub type ShapePosition = Position<CSSFloat, CSSFloat>; + /// Whether to allow empty string in the parser. #[derive(Clone, Debug, Eq, PartialEq)] #[allow(missing_docs)] @@ -194,7 +197,7 @@ impl ComputeSquaredDistance for SVGPathData { /// points of the Bézier curve in the spec. /// /// https://www.w3.org/TR/SVG11/paths.html#PathData -pub type PathCommand = GenericShapeCommand<CSSFloat, ShapePosition<CSSFloat>, CSSFloat>; +pub type PathCommand = GenericShapeCommand<CSSFloat, CSSFloat>; /// For internal SVGPath normalization. #[allow(missing_docs)] @@ -301,8 +304,8 @@ impl PathCommand { state.last_control = control1.into(); CubicCurve { point, - control1: ControlPoint::Absolute(c1.into()), - control2: ControlPoint::Absolute(control2.into()), + control1: ControlPoint::Position(c1.into()), + control2: ControlPoint::Position(control2.into()), } } else { state.pos = point.into(); @@ -333,7 +336,7 @@ impl PathCommand { state.last_command = *self; CubicCurve { point, - control1: ControlPoint::Absolute(control1.into()), + control1: ControlPoint::Position(control1.into()), control2, } } else { @@ -361,8 +364,8 @@ impl PathCommand { state.last_control = control; CubicCurve { point, - control1: ControlPoint::Absolute(control1.into()), - control2: ControlPoint::Absolute(control2.into()), + control1: ControlPoint::Position(control1.into()), + control2: ControlPoint::Position(control2.into()), } } else { state.pos = point.into(); @@ -384,8 +387,8 @@ impl PathCommand { let end_point = CoordPair::from(point); CubicCurve { point: CommandEndPoint::ToPosition(state.pos.into()), - control1: ControlPoint::Absolute(end_point.into()), - control2: ControlPoint::Absolute(end_point.into()), + control1: ControlPoint::Position(end_point.into()), + control2: ControlPoint::Position(end_point.into()), } } else { Arc { @@ -547,14 +550,14 @@ impl ops::Div<CSSFloat> for CoordPair { } } -impl CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat> { +impl CommandEndPoint<CSSFloat> { /// Converts <command-end-point> into absolutely positioned type. - pub fn to_abs(self, state_pos: CoordPair) -> Self { + pub fn to_abs(self, state_pos: CoordPair) -> CommandEndPoint<CSSFloat> { // Consume self value. match self { CommandEndPoint::ToPosition(_) => self, CommandEndPoint::ByCoordinate(coord) => { - let pos = GenericPosition { + let pos = Position { horizontal: coord.x + state_pos.x, vertical: coord.y + state_pos.y, }; @@ -564,18 +567,18 @@ impl CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat> { } } -impl ControlPoint<ShapePosition<CSSFloat>, CSSFloat> { +impl ControlPoint<CSSFloat> { /// Converts <control-point> into absolutely positioned control point type. pub fn to_abs( self, state_pos: CoordPair, - end_point: CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>, - ) -> Self { + end_point: CommandEndPoint<CSSFloat>, + ) -> ControlPoint<CSSFloat> { // Consume self value. match self { - ControlPoint::Absolute(_) => self, + ControlPoint::Position(_) => self, ControlPoint::Relative(point) => { - let mut pos = GenericPosition { + let mut pos = Position { horizontal: point.coord.x, vertical: point.coord.y, }; @@ -596,15 +599,15 @@ impl ControlPoint<ShapePosition<CSSFloat>, CSSFloat> { }, _ => (), } - ControlPoint::Absolute(pos) + ControlPoint::Position(pos) }, } } } -impl From<CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>> for CoordPair { +impl From<CommandEndPoint<CSSFloat>> for CoordPair { #[inline] - fn from(p: CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>) -> Self { + fn from(p: CommandEndPoint<CSSFloat>) -> Self { match p { CommandEndPoint::ToPosition(pos) => CoordPair { x: pos.horizontal, @@ -615,11 +618,11 @@ impl From<CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>> for CoordPair { } } -impl From<ControlPoint<ShapePosition<CSSFloat>, CSSFloat>> for CoordPair { +impl From<ControlPoint<CSSFloat>> for CoordPair { #[inline] - fn from(point: ControlPoint<ShapePosition<CSSFloat>, CSSFloat>) -> Self { + fn from(point: ControlPoint<CSSFloat>) -> Self { match point { - ControlPoint::Absolute(pos) => CoordPair { + ControlPoint::Position(pos) => CoordPair { x: pos.horizontal, y: pos.vertical, }, @@ -633,24 +636,24 @@ impl From<ControlPoint<ShapePosition<CSSFloat>, CSSFloat>> for CoordPair { } } -impl From<CoordPair> for CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat> { +impl From<CoordPair> for CommandEndPoint<CSSFloat> { #[inline] fn from(coord: CoordPair) -> Self { CommandEndPoint::ByCoordinate(coord) } } -impl From<CoordPair> for ShapePosition<CSSFloat> { +impl From<CoordPair> for Position<CSSFloat, CSSFloat> { #[inline] fn from(coord: CoordPair) -> Self { - GenericPosition { + Position { horizontal: coord.x, vertical: coord.y, } } } -impl ToCss for ShapePosition<CSSFloat> { +impl ToCss for ShapePosition { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write, @@ -889,7 +892,7 @@ fn parse_coord(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> Result<CoordPair /// Parse a pair of numbers that describes the absolutely positioned endpoint. fn parse_command_point_abs( iter: &mut Peekable<Cloned<slice::Iter<u8>>>, -) -> Result<CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>, ()> { +) -> Result<CommandEndPoint<f32>, ()> { let coord = parse_coord(iter)?; Ok(CommandEndPoint::ToPosition(coord.into())) } @@ -897,7 +900,7 @@ fn parse_command_point_abs( /// Parse a pair of numbers that describes the relatively positioned endpoint. fn parse_command_point_rel( iter: &mut Peekable<Cloned<slice::Iter<u8>>>, -) -> Result<CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>, ()> { +) -> Result<CommandEndPoint<f32>, ()> { let coord = parse_coord(iter)?; Ok(CommandEndPoint::ByCoordinate(coord)) } @@ -908,7 +911,7 @@ fn parse_command_point_rel( /// defaults to the commands coordinate mode (absolute or relative). fn parse_control_point( iter: &mut Peekable<Cloned<slice::Iter<u8>>>, -) -> Result<ControlPoint<ShapePosition<CSSFloat>, CSSFloat>, ()> { +) -> Result<ControlPoint<f32>, ()> { let coord = parse_coord(iter)?; Ok(ControlPoint::Relative(RelativeControlPoint { coord, diff --git a/testing/web-platform/meta/css/css-shapes/shape-functions/shape-function-valid.html.ini b/testing/web-platform/meta/css/css-shapes/shape-functions/shape-function-valid.html.ini @@ -10,3 +10,65 @@ [e.style['clip-path'\] = "shape(from 20px 40px, move to 20px 30px, vline to y-start, vline to y-end)" should set the property value] expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, curve to top left with 10px 30px / 12px 32px)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20% 40%, curve to center with center right / bottom center)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from bottom right, curve to left with center right / bottom center)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, curve to bottom left with 10px 30px from end)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, curve to right center with 10px 30px from start / 12px 32px from end)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, curve to right center with 10px 30px from start/12px 32px from end)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, curve to right center with 10px 30px from end / 12px 32px from origin)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, curve to right center with 10px 30px from origin / 12px 32px from start)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from top left, smooth to top right)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, smooth to center 20%)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from right bottom, smooth by 20px 20px with 12px 32px)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from center 40px, smooth by 20% 20% with 12px 32px from end)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from center, smooth by 20px 20px with 12px 32px from origin)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, arc to top right of 10%)" should set the property value] + expected: FAIL + + [e.style['clip-path'\] = "shape(from 20px 40px, curve by 20px 20px with 10px 30px from origin)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + if (os == "android") and not debug: [PASS, FAIL] + + [e.style['clip-path'\] = "shape(from 20px 40px, curve by 20% 20em with 10.3% 30px from origin / 12pt 5.4% from start)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + if (os == "android") and not debug: [PASS, FAIL] + + [e.style['clip-path'\] = "shape(from 20px 40px, curve by 20% 20em with 10px 30px from start / 12px 32px from end)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + if (os == "android") and not debug: [PASS, FAIL] + + [e.style['clip-path'\] = "shape(from 20px 40px, smooth by 20pt 20px with 12px 32px from start)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + if (os == "android") and not debug: [PASS, FAIL] diff --git a/testing/web-platform/meta/css/motion/parsing/offset-path-shape-parsing.html.ini b/testing/web-platform/meta/css/motion/parsing/offset-path-shape-parsing.html.ini @@ -1,4 +1,40 @@ [offset-path-shape-parsing.html] + [e.style['offset-path'\] = "shape(from 0px 0px, line to 10px 10px)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + + [e.style['offset-path'\] = "shape( from 0px 0px, line to 10px 10px )" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + + [e.style['offset-path'\] = "shape(from 1em 50%, line to 10px 10px)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + + [e.style['offset-path'\] = "shape(from 1ch 50px, line to 10rem 10vh)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + + [e.style['offset-path'\] = "shape(from 1ch -50px, line to -10% 12px)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + + [e.style['offset-path'\] = "shape(from 10px 10px, move by 10px 5px, line by 20px 40%, close)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + + [e.style['offset-path'\] = "shape(from 10px 10px, hline by 10px, vline to 5rem)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + + [e.style['offset-path'\] = "shape(from 10px 10px, vline by 5%, hline to 1vw)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + + [e.style['offset-path'\] = "shape(from 10px 10px, smooth to 50px 1pt)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + [e.style['offset-path'\] = "shape(from 10px 10px, arc to 50px 1pt of 10px 10px)" should set the property value] expected: if (os == "mac") and not debug: [PASS, FAIL] @@ -9,6 +45,10 @@ if (os == "mac") and not debug: [PASS, FAIL] FAIL + [e.style['offset-path'\] = "shape(from 10% 1rem, arc to 50px 1pt of 20% cw large rotate 25deg)" should set the property value] + expected: + if (os == "mac") and not debug: [PASS, FAIL] + [e.style['offset-path'\] = "shape(evenodd from 0px 0px, line to 10px 10px)" should set the property value] expected: FAIL @@ -17,6 +57,9 @@ [e.style['offset-path'\] = "shape(evenodd from 0px 0px, close)" should set the property value] expected: FAIL + + [e.style['offset-path'\] = "shape(from 10px 10px, curve to 50px 20px with 10rem center)" should set the property value] + expected: FAIL [e.style['offset-path'\] = "shape(from 10px 10px, curve to 50px 20px with 10rem 1% 12px)" should not set the property value] expected: FAIL