Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE html>
<title>CSSOM View - getBoxQuads() during custom element connection</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/geometry-utils.js"></script>
<style>
geometry-source {
display: block;
position: absolute;
width: 80px;
height: 24px;
border: 2px solid;
}
geometry-source > span {
box-sizing: border-box;
position: absolute;
left: var(--x);
top: var(--y);
width: 8px;
height: 6px;
border: 1px solid;
}
geometry-overlay {
display: block;
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
#canvas {
position: relative;
}
</style>
<div id="canvas"></div>
<script>
const markerPositions = [
[3, 4],
[14, 5],
[25, 6],
[36, 7],
[47, 8],
[58, 9],
];
const observations = [];
const sources = [];
customElements.define("geometry-overlay", class extends HTMLElement {
connectedCallback() {
observations.push([...this.source.children].map(marker =>
marker.getBoxQuads({relativeTo: this.relativeTo})[0]));
}
});
test(() => {
assert_equals(typeof Element.prototype.getBoxQuads, "function",
"Element.prototype.getBoxQuads");
const itemCount = 300;
const canvas = document.getElementById("canvas");
for (let i = 0; i < itemCount; ++i) {
const source = document.createElement("geometry-source");
source.style.left = `${(i % 100) * 2}px`;
source.style.top = `${Math.floor(i / 100) * 2}px`;
for (const [x, y] of markerPositions) {
const marker = document.createElement("span");
marker.style.setProperty("--x", `${x}px`);
marker.style.setProperty("--y", `${y}px`);
source.appendChild(marker);
}
canvas.appendChild(source);
sources.push(source);
}
canvas.offsetTop;
for (const source of sources) {
const overlay = document.createElement("geometry-overlay");
overlay.source = source;
overlay.relativeTo = canvas;
canvas.appendChild(overlay);
}
assert_equals(observations.length, itemCount,
"every connected callback collected geometry");
for (let itemIndex = 0; itemIndex < observations.length; ++itemIndex) {
assert_equals(observations[itemIndex].length, markerPositions.length,
`item ${itemIndex} has one quad per marker`);
}
const sampleIndices = [...new Set([
0,
Math.floor(itemCount / 2),
itemCount - 1,
])];
for (const itemIndex of sampleIndices) {
const source = sources[itemIndex];
const stableQuads = [...source.children].map(marker =>
marker.getBoxQuads({relativeTo: canvas})[0]);
for (let markerIndex = 0; markerIndex < markerPositions.length;
++markerIndex) {
assert_quad_approx_equals(
observations[itemIndex][markerIndex], stableQuads[markerIndex],
`item ${itemIndex}, marker ${markerIndex}`);
}
}
}, "getBoxQuads() returns current geometry from connectedCallback");
test(() => {
const container = document.createElement("div");
container.style.cssText =
"position:relative; overflow:auto; width:100px; height:100px";
const oldChild = document.createElement("div");
oldChild.style.cssText =
"position:absolute; right:0; bottom:0; width:20px; height:20px";
container.appendChild(oldChild);
document.body.appendChild(container);
oldChild.getBoxQuads();
const overflowChild = document.createElement("div");
overflowChild.style.cssText =
"position:absolute; left:200px; top:200px; width:20px; height:20px";
container.appendChild(overflowChild);
const quad = oldChild.getBoxQuads({relativeTo: container})[0];
assert_approx_equals(quad.p2.x, container.clientWidth, 0.01,
"right edge follows the resized containing block");
assert_approx_equals(quad.p3.y, container.clientHeight, 0.01,
"bottom edge follows the resized containing block");
}, "getBoxQuads() updates reused OOF geometry after scrollbars appear");
</script>