Resolve the percentage values of inset properties against proper box.
[WebKit-https.git] / LayoutTests / imported / w3c / web-platform-tests / css / cssom / support / getComputedStyle-insets.js
1 export const testEl = document.createElement("div");
2 export const containerForInflow = document.createElement("div");
3 export const containerForAbspos = document.createElement("div");
4 export const containerForFixed = document.createElement("div");
5
6 testEl.id = "test";
7 containerForInflow.id = "container-for-inflow";
8 containerForAbspos.id = "container-for-abspos";
9 containerForFixed.id = "container-for-fixed";
10
11 containerForInflow.appendChild(testEl);
12 containerForAbspos.appendChild(containerForInflow);
13 containerForFixed.appendChild(containerForAbspos);
14 document.body.appendChild(containerForFixed);
15
16 const stylesheet = document.createElement("style");
17 stylesheet.textContent = `
18   #container-for-inflow {
19     /* Content area: 100px tall, 200px wide */
20     height: 100px;
21     width: 200px;
22     padding: 1px 2px;
23     border-width: 2px 4px;
24     margin: 4px 8px;
25   }
26   #container-for-abspos {
27     /* Padding area: 200px tall, 400px wide */
28     height: 184px;
29     width: 368px;
30     padding: 8px 16px;
31     border-width: 16px 32px;
32     margin: 32px 64px;
33     position: relative;
34   }
35   #container-for-fixed {
36     /* Padding area: 300px tall, 600px wide */
37     height: 172px;
38     width: 344px;
39     padding: 64px 128px;
40     border-width: 128px 256px;
41     margin: 256px 512px;
42     position: absolute;
43     transform: scale(1);
44     visibility: hidden;
45   }
46   [id ^= container] {
47     border-style: solid;
48   }
49 `;
50 document.head.prepend(stylesheet);
51
52 function runTestsWithWM(data, testWM, cbWM) {
53   const {
54     style,
55     containingBlockElement,
56     containingBlockArea,
57     preservesPercentages,
58     preservesAuto,
59     canStretchAutoSize,
60     staticPositionX,
61     staticPositionY,
62   } = data;
63
64   let cbHeight = containingBlockElement ? containingBlockElement.clientHeight : NaN;
65   let cbWidth = containingBlockElement ? containingBlockElement.clientWidth : NaN;
66   if (containingBlockElement && containingBlockArea == "content") {
67     const cs = getComputedStyle(containingBlockElement);
68     cbHeight -= parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom);
69     cbWidth -= parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight);
70   }
71
72   const staticPositionTop = cbWM.blockStart == "top" || cbWM.inlineStart == "top"
73     ? staticPositionY : cbHeight - staticPositionY;
74   const staticPositionLeft = cbWM.blockStart == "left" || cbWM.inlineStart == "left"
75     ? staticPositionX : cbWidth - staticPositionX;
76   const staticPositionBottom = cbWM.blockStart == "bottom" || cbWM.inlineStart == "bottom"
77     ? staticPositionY : cbHeight - staticPositionY;
78   const staticPositionRight = cbWM.blockStart == "right" || cbWM.inlineStart == "right"
79     ? staticPositionX : cbWidth - staticPositionX;
80
81   function serialize(declarations) {
82     return Object.entries(declarations).map(([p, v]) => `${p}: ${v}; `).join("");
83   }
84
85   function wmName(wm) {
86     return Object.values(wm.style).join(" ");
87   }
88
89   function checkStyle(declarations, expected, msg) {
90     test(function() {
91       testEl.style.cssText = style + "; " + serialize(Object.assign({}, declarations, testWM.style));
92       if (containingBlockElement) {
93         containingBlockElement.style.cssText = serialize(Object.assign({}, cbWM.style));
94       }
95       const cs = getComputedStyle(testEl);
96       for (let [prop, value] of Object.entries(expected)) {
97         assert_equals(cs[prop], value, `'${prop}'`);
98       }
99     }, `${wmName(testWM)} inside ${wmName(cbWM)} - ${msg}`);
100
101     testEl.style.cssText = "";
102     if (containingBlockElement) {
103       containingBlockElement.style.cssText = "";
104     }
105   }
106
107   checkStyle({
108     top: "1px",
109     left: "2px",
110     bottom: "3px",
111     right: "4px",
112   }, {
113     top: "1px",
114     left: "2px",
115     bottom: "3px",
116     right: "4px",
117   }, "Pixels resolve as-is");
118
119   checkStyle({
120     top: "1em",
121     left: "2em",
122     bottom: "3em",
123     right: "4em",
124     "font-size": "10px",
125   }, {
126     top: "10px",
127     left: "20px",
128     bottom: "30px",
129     right: "40px",
130   }, "Relative lengths are absolutized into pixels");
131
132   if (preservesPercentages) {
133     checkStyle({
134       top: "10%",
135       left: "25%",
136       bottom: "50%",
137       right: "75%",
138     }, {
139       top: "10%",
140       left: "25%",
141       bottom: "50%",
142       right: "75%",
143     }, "Percentages resolve as-is");
144   } else {
145     checkStyle({
146       top: "10%",
147       left: "25%",
148       bottom: "50%",
149       right: "75%",
150     }, {
151       top: cbHeight * 10 / 100 + "px",
152       left: cbWidth * 25 / 100 + "px",
153       bottom: cbHeight * 50 / 100 + "px",
154       right: cbWidth * 75 / 100 + "px",
155     }, "Percentages are absolutized into pixels");
156
157     checkStyle({
158       top: "calc(10% - 1px)",
159       left: "calc(25% - 2px)",
160       bottom: "calc(50% - 3px)",
161       right: "calc(75% - 4px)",
162     }, {
163       top: cbHeight * 10 / 100 - 1 + "px",
164       left: cbWidth * 25 / 100 - 2 + "px",
165       bottom: cbHeight * 50 / 100 - 3 + "px",
166       right: cbWidth * 75 / 100 - 4 + "px",
167     }, "calc() is absolutized into pixels");
168   }
169
170   if (canStretchAutoSize) {
171     // Force overconstraintment by setting size or with insets that would result in
172     // negative size. Then the resolved value should be the computed one according to
173     // https://drafts.csswg.org/cssom/#resolved-value-special-case-property-like-top
174
175     checkStyle({
176       top: "1px",
177       left: "2px",
178       bottom: "3px",
179       right: "4px",
180       height: "0px",
181       width: "0px",
182     }, {
183       top: "1px",
184       left: "2px",
185       bottom: "3px",
186       right: "4px",
187     }, "Pixels resolve as-is when overconstrained");
188
189     checkStyle({
190       top: "100%",
191       left: "100%",
192       bottom: "100%",
193       right: "100%",
194     }, {
195       top: cbHeight + "px",
196       left: cbWidth + "px",
197       bottom: cbHeight + "px",
198       right: cbWidth + "px",
199     }, "Percentages absolutize the computed value when overconstrained");
200   }
201
202   if (preservesAuto) {
203     checkStyle({
204       top: "auto",
205       left: "auto",
206       bottom: "3px",
207       right: "4px",
208     }, {
209       top: "auto",
210       left: "auto",
211       bottom: "3px",
212       right: "4px",
213     }, "If start side is 'auto' and end side is not, 'auto' resolves as-is");
214
215     checkStyle({
216       top: "1px",
217       left: "2px",
218       bottom: "auto",
219       right: "auto",
220     }, {
221       top: "1px",
222       left: "2px",
223       bottom: "auto",
224       right: "auto",
225     }, "If end side is 'auto' and start side is not, 'auto' resolves as-is");
226
227     checkStyle({
228       top: "auto",
229       left: "auto",
230       bottom: "auto",
231       right: "auto",
232     }, {
233       top: "auto",
234       left: "auto",
235       bottom: "auto",
236       right: "auto",
237     }, "If opposite sides are 'auto', they resolve as-is");
238   } else if (canStretchAutoSize) {
239     checkStyle({
240       top: "auto",
241       left: "auto",
242       bottom: "3px",
243       right: "4px",
244     }, {
245       top: cbHeight - 3 + "px",
246       left: cbWidth - 4 + "px",
247       bottom: "3px",
248       right: "4px",
249     }, "If start side is 'auto' and end side is not, 'auto' resolves to used value");
250
251     checkStyle({
252       top: "1px",
253       left: "2px",
254       bottom: "auto",
255       right: "auto",
256     }, {
257       top: "1px",
258       left: "2px",
259       bottom: cbHeight - 1 + "px",
260       right: cbWidth - 2 + "px",
261     }, "If end side is 'auto' and start side is not, 'auto' resolves to used value");
262
263     checkStyle({
264       top: "auto",
265       left: "auto",
266       bottom: "auto",
267       right: "auto",
268     }, {
269       top: staticPositionTop + "px",
270       left: staticPositionLeft + "px",
271       bottom: staticPositionBottom + "px",
272       right: staticPositionRight + "px",
273     }, "If opposite sides are 'auto', they resolve to used value");
274   } else {
275     checkStyle({
276       top: "auto",
277       left: "auto",
278       bottom: "3px",
279       right: "4px",
280     }, {
281       top: "-3px",
282       left: "-4px",
283       bottom: "3px",
284       right: "4px",
285     }, "If start side is 'auto' and end side is not, 'auto' resolves to used value");
286
287     checkStyle({
288       top: "1px",
289       left: "2px",
290       bottom: "auto",
291       right: "auto",
292     }, {
293       top: "1px",
294       left: "2px",
295       bottom: "-1px",
296       right: "-2px",
297     }, "If end side is 'auto' and start side is not, 'auto' resolves to used value");
298
299     checkStyle({
300       top: "auto",
301       left: "auto",
302       bottom: "auto",
303       right: "auto",
304     }, {
305       top: "0px",
306       left: "0px",
307       bottom: "0px",
308       right: "0px",
309     }, "If opposite sides are 'auto', they resolve to used value");
310   }
311 }
312
313 const writingModes = [{
314   style: {
315     "writing-mode": "horizontal-tb",
316     "direction": "ltr",
317   },
318   blockStart: "top",
319   blockEnd: "bottom",
320   inlineStart: "left",
321   inlineEnd: "right",
322 }, {
323   style: {
324     "writing-mode": "horizontal-tb",
325     "direction": "rtl",
326   },
327   blockStart: "top",
328   blockEnd: "bottom",
329   inlineStart: "right",
330   inlineEnd: "left",
331 }, {
332   style: {
333     "writing-mode": "vertical-lr",
334     "direction": "ltr",
335   },
336   blockStart: "left",
337   blockEnd: "right",
338   inlineStart: "top",
339   inlineEnd: "bottom",
340 }, {
341   style: {
342     "writing-mode": "vertical-lr",
343     "direction": "rtl",
344   },
345   blockStart: "left",
346   blockEnd: "right",
347   inlineStart: "bottom",
348   inlineEnd: "top",
349 }, {
350   style: {
351     "writing-mode": "vertical-rl",
352     "direction": "ltr",
353   },
354   blockStart: "right",
355   blockEnd: "left",
356   inlineStart: "top",
357   inlineEnd: "bottom",
358 }, {
359   style: {
360     "writing-mode": "vertical-rl",
361     "direction": "rtl",
362   },
363   blockStart: "right",
364   blockEnd: "left",
365   inlineStart: "bottom",
366   inlineEnd: "top",
367 }];
368
369 export function runTests(data) {
370   for (let testWM of writingModes) {
371     for (let cbWM of writingModes) {
372       runTestsWithWM(data, testWM, cbWM);
373     }
374   }
375 }