commit 54f246505e4713a66f6090adb64d9373ce8f2e84
parent 1ccc9e2e57fa5751dfb6592ff221b6f983f66f8d
Author: Noam Rosenthal <nrosenthal@chromium.org>
Date: Tue, 21 Oct 2025 10:31:00 +0000
Bug 1994836 [wpt PR 55490] - Apply new border-radius/spread algo, a=testonly
Automatic update from web-platform-tests
Apply new border-radius/spread algo
Use the new coverage-based algorithm that takes into account the
percentage of the radius from the overall width/height.
Also rename OutsetForMarginOrShadow to OutsetWithCornerCorrection,
as it better describes what it does.
See https://github.com/w3c/csswg-drafts/pull/12896
Bug: 448651073
Change-Id: I1eaca184c94bf9ad5b7c37a2091eb1f428406efc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7013748
Reviewed-by: Kyle Charbonneau <kylechar@chromium.org>
Commit-Queue: Noam Rosenthal <nrosenthal@google.com>
Reviewed-by: Philip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1531048}
--
wpt-commits: cc6a94ac8793499299b00dde8b97c41aa5c95216
wpt-pr: 55490
Diffstat:
9 files changed, 165 insertions(+), 29 deletions(-)
diff --git a/testing/web-platform/tests/css/css-backgrounds/box-shadow-radius-000-ref.html b/testing/web-platform/tests/css/css-backgrounds/box-shadow-radius-000-ref.html
@@ -28,8 +28,8 @@
border: solid transparent;
width: 58px;
height: 58px;
- top: 21px;
- left: 21px;
+ top: 22px;
+ left: 22px;
}
.trap > .ref {
border: solid silver;
@@ -81,12 +81,12 @@
.half > .test {
border-radius: 8px;
box-shadow: 0 0 0 16px;
- /* shadow radius = 21px */
+ /* shadow radius = 22px */
top: 36px; left: 36px;
width: 28px; height: 28px;
}
.half > .ref {
- border-radius: 21px;
+ border-radius: 22px;
}
.half.floor > .ref {
border-width: 14px;
@@ -98,12 +98,12 @@
.fourth > .test {
border-radius: 5px;
box-shadow: 0 0 0 20px;
- /* shadow radius = 14.45px */
+ /* shadow radius = 16.56px */
top: 40px; left: 40px;
width: 20px; height: 20px;
}
.fourth > .ref {
- border-radius: 15px;
+ border-radius: 17px;
}
.fourth.floor > .ref {
border-width: 18px;
@@ -115,12 +115,12 @@
.eighth > .test {
border-radius: 2px;
box-shadow: 0 0 0 16px;
- /* shadow radius = 5.28 */
+ /* shadow radius = 7.28 */
top: 36px; left: 36px;
width: 28px; height: 28px;
}
.eighth > .ref {
- border-radius: 5.28px;
+ border-radius: 7.28px;
}
.eighth.floor > .ref {
border-width: 14px;
diff --git a/testing/web-platform/tests/css/css-backgrounds/box-shadow-radius-000.html b/testing/web-platform/tests/css/css-backgrounds/box-shadow-radius-000.html
@@ -84,12 +84,12 @@
.half > .test {
border-radius: 8px;
box-shadow: 0 0 0 16px;
- /* shadow radius = 21px */
+ /* shadow radius = 22px */
top: 36px; left: 36px;
width: 28px; height: 28px;
}
.half > .ref {
- border-radius: 21px;
+ border-radius: 22px;
}
.half.floor > .ref {
border-width: 14px;
@@ -101,12 +101,12 @@
.fourth > .test {
border-radius: 5px;
box-shadow: 0 0 0 20px;
- /* shadow radius = 14.45px */
+ /* shadow radius = 16.56px */
top: 40px; left: 40px;
width: 20px; height: 20px;
}
.fourth > .ref {
- border-radius: 15px;
+ border-radius: 17px;
}
.fourth.floor > .ref {
border-width: 18px;
@@ -118,12 +118,12 @@
.eighth > .test {
border-radius: 2px;
box-shadow: 0 0 0 16px;
- /* shadow radius = 5.28 */
+ /* shadow radius = 7.28 */
top: 36px; left: 36px;
width: 28px; height: 28px;
}
.eighth > .ref {
- border-radius: 5.28px;
+ border-radius: 7.28px;
}
.eighth.floor > .ref {
border-width: 14px;
diff --git a/testing/web-platform/tests/css/css-backgrounds/box-shadow-radius-generated-ref.html b/testing/web-platform/tests/css/css-backgrounds/box-shadow-radius-generated-ref.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<title>Box Shadow Border Radius (Outset)</title>
+<link rel="help" href="https://www.w3.org/TR/css-backgrounds-3/#shadow-shape">
+<div id="shadow"></div>
+<div id="target"></div><style>
+ #shadow {
+ position: absolute;
+ background: black;
+ top: calc(100px - var(--spread) * 1px);
+ left: calc(100px - var(--spread) * 1px);
+ width: calc((var(--width) + var(--spread) * 2) * 1px);
+ height: calc((var(--height) + var(--spread) * 2) * 1px);
+ }
+
+ #target {
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ width: calc(var(--width) * 1px);
+ height: calc(var(--height) * 1px);
+ border-radius: var(--radius);
+ box-shadow: 0 0 0 var(--spread) black;
+ background: green;
+ }
+</style>
+
+<script>
+ const {searchParams} = new URL(location.href);
+ const width = +searchParams.get('width');
+ const height = +searchParams.get('height');
+ const spread = +searchParams.get('spread');
+ for (const param of searchParams) {
+ document.documentElement.style.setProperty(`--${param[0]}`, param[1]);
+ }
+ function adjusted_radius(radius_css) {
+ let [radius_width, radius_height] = radius_css.split(' ');
+ if (typeof radius_height === 'undefined')
+ radius_height = radius_width;
+
+ if (radius_width.endsWith('%'))
+ radius_width = parseFloat(radius_width) / 100 * width;
+ else
+ radius_width = parseFloat(radius_width);
+
+ if (radius_height.endsWith('%'))
+ radius_height = parseFloat(radius_height) / 100 * height;
+ else
+ radius_height = parseFloat(radius_height);
+
+ const coverage = Math.min(
+ 2 * radius_width / width,
+ 2 * radius_height / height
+ ) || 0;
+
+ return [radius_width, radius_height].map(value => {
+ if (value > spread || coverage > 1)
+ return value + spread;
+ else
+ return value + spread * (1 - (1 - value / spread)**3 * (1 - coverage ** 3));
+ }).map(v => v + 'px').join(' ');
+ }
+
+ const target = document.getElementById('target');
+ const shadow = document.getElementById('shadow');
+ const computed_style = getComputedStyle(target);
+ for (const radius_prop of ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'])
+ shadow.style[radius_prop] = adjusted_radius(computed_style[radius_prop]);
+
+</script>
+
diff --git a/testing/web-platform/tests/css/css-backgrounds/box-shadow-radius-generated.html b/testing/web-platform/tests/css/css-backgrounds/box-shadow-radius-generated.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>Box Shadow Border Radius (Outset)</title>
+<link rel="help" href="https://www.w3.org/TR/css-backgrounds-3/#shadow-shape">
+<link rel="match" href="box-shadow-radius-generated-ref.html">
+<!-- Allow differences of antialised pixels along rounded edges -->
+<meta name="fuzzy" content="0-32;0-128">
+<meta name="variant" content="?width=50&height=50&spread=50&radius=0px">
+<meta name="variant" content="?width=50&height=50&spread=50&radius=1px">
+<meta name="variant" content="?width=10&height=10&spread=70&radius=100%">
+<meta name="variant" content="?width=200&height=40&spread=50&radius=100px%20/%2020px">
+<meta name="variant" content="?width=200&height=40&spread=50&radius=20px%20/%204px">
+<meta name="variant" content="?width=300&height=50&spread=30&radius=15px">
+<meta name="variant" content="?width=300&height=50&spread=30&radius=25px">
+<meta name="variant" content="?width=300&height=60&spread=30&radius=20px%2020px%2040px%2040px">
+<meta name="variant" content="?width=300&height=50&spread=30&radius=1px%201px%2049px%2049px">
+<meta name="variant" content="?width=300&height=60&spread=30&radius=0px%200px%2030px%2030px">
+<meta name="variant" content="?width=300&height=50&spread=30&radius=50%">
+<meta name="variant" content="?width=300&height=50&spread=30&radius=50%%2050%%201px%2050%">
+<meta name="variant" content="?width=200&height=40&spread=50&radius=10%%2090%%205%%">
+<meta name="variant" content="?width=200&height=40&spread=50&radius=0%2050%%2050%">
+<meta name="variant" content="?width=250&height=30&spread=100&radius=10px">
+<style>
+ #target {
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ width: calc(var(--width) * 1px);
+ height: calc(var(--height) * 1px);
+ border-radius: var(--radius);
+ box-shadow: 0 0 0 calc(var(--spread) * 1px) black;
+ background: green;
+ }
+</style>
+
+<script>
+ for (const param of new URL(location.href).searchParams)
+ document.documentElement.style.setProperty(`--${param[0]}`, param[1]);
+</script>
+
+<div id="target"></div>
+\ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-borders/corner-shape/corner-shape-inset-shadow-ref.html b/testing/web-platform/tests/css/css-borders/corner-shape/corner-shape-inset-shadow-ref.html
@@ -11,7 +11,7 @@
width: var(--width);
height: var(--height);
box-sizing: border-box;
- corner-shape: bevel square scoop;
+ corner-shape: bevel notch squircle scoop;
border-radius: 30%;
border: var(--border-width) solid purple;
overflow: clip;
@@ -24,7 +24,7 @@
display: block;
background: green;
corner-shape: inherit;
- border-radius: inherit;
+ border-radius: 48px;
position: relative;
box-sizing: inherit;
left: calc(var(--offset-x) + var(--spread));
diff --git a/testing/web-platform/tests/css/css-borders/corner-shape/corner-shape-inset-shadow.html b/testing/web-platform/tests/css/css-borders/corner-shape/corner-shape-inset-shadow.html
@@ -8,7 +8,7 @@
width: 200px;
height: 200px;
box-sizing: border-box;
- corner-shape: bevel square scoop;
+ corner-shape: bevel notch squircle scoop;
border-radius: 30%;
background: green;
border: 5px solid purple;
diff --git a/testing/web-platform/tests/css/css-borders/corner-shape/resources/corner-shape.js b/testing/web-platform/tests/css/css-borders/corner-shape/resources/corner-shape.js
@@ -100,8 +100,8 @@ function add_corner(ctx, ax, ay, bx, by, curvature) {
function render_rect_with_corner_shapes(style, ctx, width, height) {
const corner_params = resolve_corner_params(style, width, height);
- function draw_outer_corner(corner) {
- const params = corner_params[corner];
+ function draw_outer_corner(corner, spread) {
+ const params = (spread ? resolve_corner_params(style, width, height, spread) : corner_params)[corner];
add_corner(ctx, ...params.outer_rect, params.shape);
}
@@ -109,12 +109,12 @@ function render_rect_with_corner_shapes(style, ctx, width, height) {
add_corner(ctx, ...corner_params[corner].inner_rect, corner_params[corner].shape);
}
- function draw_outer_path() {
+ function draw_outer_path(spread) {
ctx.beginPath();
- draw_outer_corner("top-right");
- draw_outer_corner("bottom-right");
- draw_outer_corner("bottom-left");
- draw_outer_corner("top-left");
+ draw_outer_corner("top-right", spread);
+ draw_outer_corner("bottom-right", spread);
+ draw_outer_corner("bottom-left", spread);
+ draw_outer_corner("top-left", spread);
ctx.closePath();
ctx.fill("nonzero");
}
@@ -122,9 +122,8 @@ function render_rect_with_corner_shapes(style, ctx, width, height) {
for (const {spread, offset, color} of (style.shadow || [])) {
ctx.save();
ctx.translate(offset[0] - spread, offset[1] - spread);
- ctx.scale((width + spread * 2) / width, (height + spread * 2) / height);
ctx.fillStyle = color;
- draw_outer_path();
+ draw_outer_path(spread);
ctx.restore();
}
@@ -136,7 +135,7 @@ function render_rect_with_corner_shapes(style, ctx, width, height) {
];
ctx.fillStyle = "black";
- draw_outer_path();
+ draw_outer_path(0);
ctx.save();
ctx.beginPath();
diff --git a/testing/web-platform/tests/css/css-borders/corner-shape/resources/corner-utils.js b/testing/web-platform/tests/css/css-borders/corner-shape/resources/corner-utils.js
@@ -48,7 +48,33 @@ function superellipse_t_for_y(y, curvature) {
} else return 1 - Math.log(y) / Math.log(1 / curvature);
}
-function resolve_corner_params(style, width, height, outset = null) {
+function adjust_corner_for_spread([rx, ry], spread, width, height) {
+ rx = +rx;
+ ry = +ry;
+ spread = +spread;
+ const coverage = 2 * Math.min(rx / width, ry / height);
+
+ return [rx, ry].map(value => {
+ if (value > spread || coverage > 1)
+ return value + spread;
+ else
+ return value + spread * (1 - (1 - value / spread)**3 * (1 - coverage ** 3));
+ });
+}
+
+function adjust_spread(original_style, spread, width, height) {
+ return {...original_style,
+ "border-top-left-radius": adjust_corner_for_spread(original_style["border-top-left-radius"], spread, width, height),
+ "border-top-right-radius": adjust_corner_for_spread(original_style["border-top-right-radius"], spread, width, height),
+ "border-bottom-right-radius": adjust_corner_for_spread(original_style["border-bottom-right-radius"], spread, width, height),
+ "border-bottom-left-radius": adjust_corner_for_spread(original_style["border-bottom-left-radius"], spread, width, height),
+ };
+}
+
+function resolve_corner_params(original_style, width, height, spread = 0) {
+ const style = spread ? adjust_spread(original_style, spread, width, height) : original_style;
+ width += spread * 2;
+ height += spread * 2;
const params = {
"top-right": {
outer: [
diff --git a/testing/web-platform/tests/css/css-overflow/overflow-clip-margin-010-ref.html b/testing/web-platform/tests/css/css-overflow/overflow-clip-margin-010-ref.html
@@ -22,7 +22,7 @@
height: 140px;
margin: -20px;
- border-radius:0px 27.5px 40px 50px;
+ border-radius:0px 27.52px 40px 50px;
overflow: clip;
}
.child {