8000 [css-backgrounds-3] Add examples to test algorithms for #7103. · w3c/csswg-drafts@12f0d5a · GitHub
Skip to content

Commit 12f0d5a

Browse files
Loiroorioldbaron
authored andcommitted
[css-backgrounds-3] Add examples to test algorithms for #7103.
This was originally https://people.igalia.com/obrufau/testcases/shadow-radius/ See #7103 (comment)
1 parent ea91840 commit 12f0d5a

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
<!DOCTYPE html>
2+
<style>
3+
body {
4+
display: flex;
5+
height: 100vh;
6+
margin: 0;
7+
}
8+
#output {
9+
flex: 1;
10+
border-left: 1px solid;
11+
margin-left: 1em;
12+
overflow: auto;
13+
}
14+
#output, form {
15+
padding: 1em;
16+
}
17+
hr {
18+
border: none;
19+
border-top: 1px dotted;
20+
}
21+
label {
22+
display: flex;
23+
width: max-content;
24+
margin: .5em 0;
25+
}
26+
</style>
27+
<form>
28+
<label>
29+
<input type="radio" name="algorithm" value="do-not-polyfill" checked>
30+
Do not polyfill
31+
</label>
32+
<label>
33+
<input type="radio" name="algorithm" value="increase-by-spread">
34+
Increase radius by spread
35+
</label>
36+
<label>
37+
<input type="radio" name="algorithm" value="current-spec">
38+
Current spec
39+
</label>
40+
<label>
41+
<input type="radio" name="algorithm" value="percentage-min-axis">
42+
Percentage of min axis
43+
</label>
44+
<label>
45+
<input type="radio" name="algorithm" value="percentage-max-axis">
46+
Percentage of max axis
47+
</label>
48+
<label>
49+
<input type="radio" name="algorithm" value="percentage-same-axis">
50+
Percentage of same axis
51+
</label>
52+
<label>
53+
<input type="radio" name="algorithm" value="percentage-same-axis-ratio">
54+
Percentage of same axis,<br>ceiling to keep ratio if possible
55+
</label>
56+
</form>
57+
<div id="output"></div>
58+
<script>
59+
const output = document.getElementById("output");
60+
const {algorithm} = document.forms[0].elements;
61+
const testCases = [
62+
{width: 50, height: 50, spread: 50, borderRadius: "0px"},
63+
{width: 50, height: 50, spread: 50, borderRadius: "1px"},
64+
{width: 10, height: 10, spread: 70, borderRadius: "100%"},
65+
{width: 200, height: 40, spread: 50, borderRadius: "100px / 20px"},
66+
{width: 200, height: 40, spread: 50, borderRadius: "20px / 4px"},
67+
{width: 500, height: 50, spread: 30, borderRadius: "15px"},
68+
{width: 500, height: 50, spread: 30, borderRadius: "1px 1px 49px 49px"},
69+
{width: 500, height: 50, spread: 30, borderRadius: "50%"},
70+
{width: 500, height: 50, spread: 30, borderRadius: "50% 50% 1px 50%"},
71+
];
72+
function show() {
73+
output.textContent = "";
74+
for (let testCase of testCases) {
75+
output.append(JSON.stringify(testCase));
76+
const inner = document.createElement("div");
77+
inner.style.width = testCase.width + "px";
78+
inner.style.height = testCase.height + "px";
79+
inner.style.borderRadius = testCase.borderRadius;
80+
inner.style.backgroundColor = "#fff";
81+
const outer = document.createElement("div");
82+
outer.appendChild(inner);
83+
if (algorithm.value === "do-not-polyfill") {
84+
inner.style.boxShadow = `0 0 0 ${testCase.spread}px #000`;
85+
outer.style.padding = testCase.spread + "px";
86+
output.appendChild(outer);
87+
} else {
88+
outer.style.backgroundColor = "#000";
89+
outer.style.borderStyle = "solid";
90+
outer.style.borderWidth = testCase.spread + "px";
91+
outer.style.width = "max-content";
92+
output.appendChild(outer);
93+
outer.style.borderRadius = resolve(testCase, inner);
94+
}
95+
output.append(document.createElement("hr"));
96+
}
97+
}
98+
function resolve(testCase, element) {
99+
function parseLength(value, percentageBasis) {
100+
if (value.endsWith("%")) {
101+
return parseFloat(value) * percentageBasis / 100;
102+
}
103+
return parseFloat(value);
104+
}
105+
function parseCorner(value) {
106+
const raw = value.split(" ");
107+
if (raw.length === 1) {
108+
raw[1] = raw[0];
109+
}
110+
return AAB7 [
111+
parseLength(raw[0], testCase.width),
112+
parseLength(raw[1], testCase.height),
113+
];
114+
}
115+
const cs = getComputedStyle(element);
116+
const radii = {
117+
topLeft: parseCorner(cs.borderTopLeftRadius),
118+
topRight: parseCorner(cs.borderTopRightRadius),
119+
bottomLeft: parseCorner(cs.borderBottomLeftRadius),
120+
bottomRight: parseCorner(cs.borderBottomRightRadius),
121+
};
122+
const f = Math.min(
123+
testCase.width / (radii.topLeft[0] + radii.topRight[0]),
124+
testCase.width / (radii.bottomLeft[0] + radii.bottomRight[0]),
125+
testCase.height / (radii.topLeft[1] + radii.bottomLeft[1]),
126+
testCase.height / (radii.topRight[1] + radii.bottomRight[1])
127+
);
128+
if (f < 1) {
129+
for (let corner in radii) {
130+
radii[corner] = radii[corner].map(v => v * f);
131+
}
132+
}
133+
let r;
134+
switch (algorithm.value) {
135+
case "increase-by-spread": {
136+
const map = (value) => value + testCase.spread;
137+
r = {
138+
topLeft: radii.topLeft.map(map),
139+
topRight: radii.topRight.map(map),
140+
bottomLeft: radii.bottomLeft.map(map),
141+
bottomRight: radii.bottomRight.map(map),
142+
};
143+
break;
144+
}
145+
case "current-spec": {
146+
const map = (value) => {
147+
if (value >= testCase.spread) {
148+
return value + testCase.spread;
149+
}
150+
let r = value / testCase.spread;
151+
return value + testCase.spread * (1 + (r - 1)**3);
152+
}
153+
r = {
154+
topLeft: radii.topLeft.map(map),
155+
topRight: radii.topRight.map(map),
156+
bottomLeft: radii.bottomLeft.map(map),
157+
bottomRight: radii.bottomRight.map(map),
158+
};
159+
break;
160+
}
161+
case "percentage-min-axis": {
162+
const min = Math.min(testCase.width, testCase.height);
163+
const ratio = 1 + 2 * testCase.spread / min;
164+
const map = (value) => value * ratio;
165+
r = {
166+
topLeft: radii.topLeft.map(map),
167+
topRight: radii.topRight.map(map),
168+
bottomLeft: radii.bottomLeft.map(map),
169+
bottomRight: radii.bottomRight.map(map),
170+
};
171+
break;
172+
}
173+
case "percentage-max-axis": {
174+
const min = Math.max(testCase.width, testCase.height);
175+
const ratio = 1 + 2 * testCase.spread / min;
176+
const map = (value) => value * ratio;
177+
r = {
178+
topLeft: radii.topLeft.map(map),
179+
topRight: radii.topRight.map(map),
180+
bottomLeft: radii.bottomLeft.map(map),
181+
bottomRight: radii.bottomRight.map(map),
182+
};
183+
break;
184+
}
185+
case "percentage-same-axis": {
186+
debugger;
187+
const xRatio = 1 + 2 * testCase.spread / testCase.width;
188+
const yRatio = 1 + 2 * testCase.spread / testCase.height;
189+
const map = ([x, y]) => [x * xRatio, y * yRatio];
190+
r = {
191+
topLeft: map(radii.topLeft),
192+
topRight: map(radii.topRight),
193+
bottomLeft: map(radii.bottomLeft),
194+
bottomRight: map(radii.bottomRight),
195+
};
196+
break;
197+
}
198+
case "percentage-same-axis-ratio": {
199+
debugger;
200+
const xRatio = 1 + 2 * testCase.spread / testCase.width;
201+
const yRatio = 1 + 2 * testCase.spread / testCase.height;
202+
const map = ([x, y]) => [x * xRatio, y * yRatio];
203+
const map2 = ([x, y]) => [x * yRatio, y * xRatio];
204+
r = {
205+
topLeft: map(radii.topLeft),
206+
topRight: map(radii.topRight),
207+
bottomLeft: map(radii.bottomLeft),
208+
bottomRight: map(radii.bottomRight),
209+
};
210+
const other = {
211+
topLeft: map2(radii.topLeft),
212+
topRight: map2(radii.topRight),
213+
bottomLeft: map2(radii.bottomLeft),
214+
bottomRight: map2(radii.bottomRight),
215+
};
216+
const shadowWidth = testCase.width + 2 * testCase.spread;
217+
const shadowHeight = testCase.height + 2 * testCase.spread;
218+
const adjust = (prop1, prop2, idx) => {
219+
if (r[prop1][idx] < other[prop1][idx] || r[prop2][idx] < other[prop2][idx]) {
220+
const desiredGrowths = [
221+
Math.max(0, other[prop1][idx] - r[prop1][idx]),
222+
Math.max(0, other[prop2][idx] - r[prop2][idx]),
223+
];
224+
const desiredGrowth = desiredGrowths[0] + desiredGrowths[1];
225+
const available = (idx ? shadowHeight : shadowWidth) - r[prop1][idx] - r[prop2][idx];
226+
const factor = Math.min(1, available / desiredGrowth);
227+
r[prop1][idx] += desiredGrowths[0] * factor;
228+
r[prop2][idx] += desiredGrowths[1] * factor;
229+
}
230+
}
231+
adjust("topLeft", "topRight", 0);
232+
adjust("bottomLeft", "bottomRight", 0);
233+
adjust("topLeft", "bottomLeft", 1);
234+
adjust("topRight", "bottomRight", 1);
235+
break;
236+
}
237+
default: {
238+
throw "Not implemented: " + algorithm.value;
239+
break;
240+
}
241+
}
242+
return `${r.topLeft[0]}px ${r.topRight[0]}px ${r.bottomRight[0]}px ${r.bottomLeft[0]}px / ${r.topLeft[1]}px ${r.topRight[1]}px ${r.bottomRight[1]}px ${r.bottomLeft[1]}px`;
243+
}
244+
show();
245+
document.querySelector("form").addEventListener("change", show);
246+
</script>

0 commit comments

Comments
 (0)