blob: 007702f1de37dc128086b76594ebbcde11f94892 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<style>
body, html {
width: 100%;
height: 100%;
margin: 0;
}
#iframe {
width: 100vw;
height: 100vh;
border: 0;
padding: 0;
overflow: scroll;
}
#clip {
width: 50%;
height: 20%;
overflow: hidden;
}
</style>
</head>
<body>
<div id="clip">
<iframe id="iframe">
</iframe>
</div>
<script>
window.loaded = false;
window.notifyBrowser = false;
const kMarginOfError = 1;
const tinyTimeout = 50;
window.addEventListener("load", () => {
window.loaded = true;
if (window.notifyBrowser)
notifyWhenLoaded();
});
function notifyWhenLoaded() {
if (loaded)
window.domAutomationController.send("LOADED");
else
window.notifyBrowser = true;
}
// Waits until the |visualViewport| reaches the given size (approximately).
// Notifies the browser when this happens.
function notifyVisualViewportChanged(width, height) {
if ((Math.abs(visualViewport.width - width) < kMarginOfError) &&
(Math.abs(visualViewport.height - height) < kMarginOfError)) {
return window.domAutomationController.send("SIZED");
}
window.setTimeout(() => {
notifyVisualViewportChanged(width, height);
}, tinyTimeout);
}
function isEmptyRect(rect) {
return (rect.width * rect.height) === 0;
}
function intersect(rect1, rect2) {
let minX1 = rect1.x, maxX1 = minX1 + rect1.width
minY1 = rect1.y, maxY1 = minY1 + rect1.height,
minX2 = rect2.x, maxX2 = minX2 + rect2.width,
minY2 = rect2.y, maxY2 = minY2 + rect2.height;
return !(isEmptyRect(rect1) ||
isEmptyRect(rect2) ||
(minX1 > maxX2) ||
(minX2 > maxX1) ||
(minY1 > maxY2) ||
(minY2 > maxY1));
}
function visualViewportAsRect() {
return {
x: visualViewport.offsetLeft,
y: visualViewport.offsetTop,
width: Math.round(visualViewport.width),
height: Math.round(visualViewport.height)
};
}
function rectAsString(rect) {
return `${rect.x},${rect.y},${rect.width},${rect.height}`;
}
// Waits until the given element is inside the |visualViewport|.
function notifyWhenVisible(el) {
if (intersect(el.getBoundingClientRect(), visualViewportAsRect())) {
window.domAutomationController.send("VISIBLE");
} else {
window.setTimeout(() => {
notifyWhenVisible(el);
}, tinyTimeout);
}
}
let lastLayoutViewportX;
let lastLayoutViewportY;
let lastVisualViewportX;
let lastVisualViewportY;
let lastScale;
function notifyWhenViewportStable(numFrames) {
const kUnchangedFramesConsideredStable = 10;
if (lastLayoutViewportX !== window.scrollX ||
lastLayoutViewportY !== window.scrollY ||
lastVisualViewportX !== window.visualViewport.offsetLeft ||
lastVisualViewportY !== window.visualViewport.offsetTop ||
lastScale !== window.visualViewport.scale) {
lastLayoutViewportX = window.scrollX;
lastLayoutViewportY = window.scrollY;
lastVisualViewportX = window.visualViewport.offsetLeft;
lastVisualViewportY = window.visualViewport.offsetTop;
lastScale = window.visualViewport.scale;
numFrames = 0;
}
numFrames++;
if (numFrames == kUnchangedFramesConsideredStable) {
window.domAutomationController.send("VIEWPORT_STABLE");
} else {
requestAnimationFrame(notifyWhenViewportStable.bind(null, numFrames));
}
}
</script>
</body>
</html>