From a6ae161450ab3336594dc532703566120c8e473d Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Wed, 4 Jun 2025 10:26:57 +0100 Subject: [PATCH 1/2] [css-borders-4] Constrain radii for concave opposite corners If the hulls of opposite corners overlap, find a scale factor that would prevent the overlap, and apply to all radii. Resolution: https://github.com/w3c/csswg-drafts/issues/12098#issuecomment-2898621830 Closes #12098 --- css-borders-4/Overview.bs | 57 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/css-borders-4/Overview.bs b/css-borders-4/Overview.bs index 3b92ae024f1..da5ee86d6b1 100644 --- a/css-borders-4/Overview.bs +++ b/css-borders-4/Overview.bs @@ -394,7 +394,8 @@ Each shadow of [=/element=]'s 'box shadow' is shaped by the [=border contour pat To compute an [=/element=] |element|'s border contour path given an an [=edge=] |targetEdge| and an optional number |spread| (default 0): 1. Let |outerLeft|, |outerTop|, |outerRight|, |outerBottom| be |element|'s [=unshaped edge|unshaped=] [=border edge=]. 1. Let |topLeftHorizontalRadius|, |topLeftVericalRadius|, |topRightHorizontalRadius|, |topRightVerticalRadius|, |bottomRightHorizontalRadius|, - |bottomRightVerticalRadius|, |bottomLeftHorizontalRadius|, and |bottomLeftVerticalRadius| be |element| [=border edge=]'s radii. + |bottomRightVerticalRadius|, |bottomLeftHorizontalRadius|, and |bottomLeftVerticalRadius| be |element| [=border edge=]'s radii, + scaled by |element|'s [=opposite corner scale factor=]. 1. Let |topLeftShape|, |topRightShape|, |bottomRightShape|, and |bottomLeftShape| be |element|'s [=computed value|computed=] 'corner-*-shape' values. 1. Let |targetLeft|, |targetTop|, |targetRight|, |targetBottom| [=unshaped edge|unshaped=] |targetEdge|. 1. Let |path| be a new path [[SVG2]]. @@ -503,6 +504,47 @@ To compute the corner path given a rectangle |cornerRect|, a rectangl 1. Return |cornerPath|. +

+Constraining opposite radii

+ +When concave 'corner-shape' values are present (the [=superellipse parameter=] is negative), diagonally opposite corners might overlap each other. + +
+

The following example would create overlapping corners if not constrained.

+
+		div {
+			corner-shape: scoop;
+			border-top-left-radius: 80%;
+			border-bottom-right-radius: 80%;
+		}
+	
+
+ +To prevent this, the four radii are constrained to prevent overlaps. +This is done by computing a hull polygon for each of the opposite corners, and finding the highest downscale factor which, if applied to both corners, would make it so that the polygons would not intersect. + +
+To compute the opposite corner scale factor given an [=/element=] |element|: + 1. Let |rect| be |element|'s [=border box=]. + 1. Let |topRightHull| be a the [=normalized corner hull=] given |element|'s [=computed value|computed=] 'corner-top-right-shape', + mapped to the rectangle (|rect|'s [=width dimension=] - |element|'s [=computed value|computed=] horizontal 'border-top-right-radius', 0, |rect|'s [=computed value|computed=] 'border-top-right-radius'). + 1. Let |bottomRightHull| be a the [=normalized corner hull=] given |element|'s [=computed value|computed=] 'corner-bottom-right-shape', + rotated by 90deg with (0.5, 0.5) as an origin, + and mapped to the rectangle (|rect|'s [=width dimension=] - |element|'s [=computed value|computed=] horizontal 'border-bottom-right-radius', |rect|'s [=height dimension=] - |element|'s [=computed value|computed=] vertical 'border-bottom-right-radius', + |element|'s [=computed value|computed=] 'border-bottom-right-radius'). + 1. Let |bottomLeftHull| be a the [=normalized corner hull=] given |element|'s [=computed value|computed=] 'corner-bottom-right-shape', + rotated by 180deg with (0.5, 0.5) as an origin, + and mapped to the rectangle (0, |rect|'s [=height dimension=] - |element|'s [=computed value|computed=] vertical 'border-bottom-left-radius', + |element|'s [=computed value|computed=] 'border-bottom-left-radius'). + 1. Let |topLeftHull| be a the [=normalized corner hull=] given |element|'s [=computed value|computed=] 'corner-top-left-shape', + rotated by 270deg with (0.5, 0.5) as an origin, + mapped to (0, 0, |element|'s [=computed value|computed=] 'border-top-left-radius'). + 1. Let |scaleFactorA| be the highest number which, if both |topLeftHull| and |bottomRightHull| were scaled by, using their first point as the origin, those polygons would not intersect. + 1. Let |scaleFactorB| be the highest number which, if both |topRightHull| and |bottomLeftHull| were scaled by, using their first point as the origin, those polygons would not intersect. + 1. Return min(1, |scaleFactorA|, |scaleFactorB|). +
+ +

'corner-shape' values

@@ -660,6 +702,19 @@ To compute the normalized superellipse half corner given a [=superell 1. Return |convexHalfCorner|. +
+To compute the normalized corner hull given a [=superellipse parameter=] |curvature|: + 1. Let |normalizedHalfCorner| be the [=normalized superellipse half corner=] given |curvature|. + 1. Let |axisLineA| be a line between (0, 1) and (1, 1). + 1. Let |axisLineB| be a line between (1, 0) and (1, 1). + 1. Let |halfCornerPoint| be (|normalizedHalfCorner|, 1 - |normalizedHalfCorner|). + 1. Let |lineFromCenterToHalfCorner| be a line between (0, 0) and |halfCornerPoint|. + 1. Let |tangentLine| be the line perpendicular to |lineFromCenterToHalfCorner|, at |halfCornerPoint|. + 1. Let |intersectionA| be the intersection between |axisLineA| and |tangentLine|. + 1. Let |intersectionB| be the intersection between |axisLineB| and |tangentLine|. + 1. Return a pentagon between the points « (0, 0), (0, 1), |intersectionA|, |intersectionB|, (1, 0), (0, 0) ». +
+ To interpolate a [=superellipse parameter=] |s| to an interpolation value between 0 and 1, return the [=normalized superellipse half corner=] given |s|. To convert a <> |interpolationValue| back to a [=superellipse parameter=], switch on |interpolationValue|: From 62afcc828fcbb53b885612a38060789cbaa833c0 Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Wed, 4 Jun 2025 12:34:27 +0100 Subject: [PATCH 2/2] Fix hull computation for convex/concave --- css-borders-4/Overview.bs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/css-borders-4/Overview.bs b/css-borders-4/Overview.bs index da5ee86d6b1..cef117c9dd2 100644 --- a/css-borders-4/Overview.bs +++ b/css-borders-4/Overview.bs @@ -526,17 +526,17 @@ This is done by computing a hull polygon for each of the opposite corners, and f
To compute the opposite corner scale factor given an [=/element=] |element|: 1. Let |rect| be |element|'s [=border box=]. - 1. Let |topRightHull| be a the [=normalized corner hull=] given |element|'s [=computed value|computed=] 'corner-top-right-shape', + 1. Let |topRightHull| be a the [=normalized inner corner hull=] given |element|'s [=computed value|computed=] 'corner-top-right-shape', mapped to the rectangle (|rect|'s [=width dimension=] - |element|'s [=computed value|computed=] horizontal 'border-top-right-radius', 0, |rect|'s [=computed value|computed=] 'border-top-right-radius'). - 1. Let |bottomRightHull| be a the [=normalized corner hull=] given |element|'s [=computed value|computed=] 'corner-bottom-right-shape', + 1. Let |bottomRightHull| be a the [=normalized inner corner hull=] given |element|'s [=computed value|computed=] 'corner-bottom-right-shape', rotated by 90deg with (0.5, 0.5) as an origin, and mapped to the rectangle (|rect|'s [=width dimension=] - |element|'s [=computed value|computed=] horizontal 'border-bottom-right-radius', |rect|'s [=height dimension=] - |element|'s [=computed value|computed=] vertical 'border-bottom-right-radius', |element|'s [=computed value|computed=] 'border-bottom-right-radius'). - 1. Let |bottomLeftHull| be a the [=normalized corner hull=] given |element|'s [=computed value|computed=] 'corner-bottom-right-shape', + 1. Let |bottomLeftHull| be a the [=normalized inner corner hull=] given |element|'s [=computed value|computed=] 'corner-bottom-right-shape', rotated by 180deg with (0.5, 0.5) as an origin, and mapped to the rectangle (0, |rect|'s [=height dimension=] - |element|'s [=computed value|computed=] vertical 'border-bottom-left-radius', |element|'s [=computed value|computed=] 'border-bottom-left-radius'). - 1. Let |topLeftHull| be a the [=normalized corner hull=] given |element|'s [=computed value|computed=] 'corner-top-left-shape', + 1. Let |topLeftHull| be a the [=normalized inner corner hull=] given |element|'s [=computed value|computed=] 'corner-top-left-shape', rotated by 270deg with (0.5, 0.5) as an origin, mapped to (0, 0, |element|'s [=computed value|computed=] 'border-top-left-radius'). 1. Let |scaleFactorA| be the highest number which, if both |topLeftHull| and |bottomRightHull| were scaled by, using their first point as the origin, those polygons would not intersect. @@ -703,16 +703,17 @@ To compute the normalized superellipse half corner given a [=superell
-To compute the normalized corner hull given a [=superellipse parameter=] |curvature|: +To compute the normalized inner corner hull given a [=superellipse parameter=] |curvature|: + 1. If |curvature| is greater than or equal to zero, return a triangle betwen « (1, 1), (1, 0), (0, 1) ». + 1. Let |axisLineA| be a line between (1, 0) and (1, 1). + 1. Let |axisLineB| be a line between (0, 1) and (1, 1). 1. Let |normalizedHalfCorner| be the [=normalized superellipse half corner=] given |curvature|. - 1. Let |axisLineA| be a line between (0, 1) and (1, 1). - 1. Let |axisLineB| be a line between (1, 0) and (1, 1). 1. Let |halfCornerPoint| be (|normalizedHalfCorner|, 1 - |normalizedHalfCorner|). 1. Let |lineFromCenterToHalfCorner| be a line between (0, 0) and |halfCornerPoint|. 1. Let |tangentLine| be the line perpendicular to |lineFromCenterToHalfCorner|, at |halfCornerPoint|. 1. Let |intersectionA| be the intersection between |axisLineA| and |tangentLine|. 1. Let |intersectionB| be the intersection between |axisLineB| and |tangentLine|. - 1. Return a pentagon between the points « (0, 0), (0, 1), |intersectionA|, |intersectionB|, (1, 0), (0, 0) ». + 1. Return a pentagon between the points « (1, 1), (1, 0), |intersectionA|, |intersectionB|, (0, 1), (1, 1) ».
To interpolate a [=superellipse parameter=] |s| to an interpolation value between 0 and 1, return the [=normalized superellipse half corner=] given |s|.