Fix browser screenshot capture for parked webviews
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Paseo Browser Capture Harness</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background: #202020;
|
||||
overflow: hidden;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
#paseo-browser-resident-webviews {
|
||||
position: fixed;
|
||||
left: -20000px;
|
||||
top: 0;
|
||||
width: 1280px;
|
||||
height: 800px;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#target-webview {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
width: 1280px;
|
||||
height: 800px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="paseo-browser-resident-webviews" aria-hidden="true"></div>
|
||||
|
||||
<script>
|
||||
const RESIDENT_VIEWPORT_WIDTH = 1280;
|
||||
const RESIDENT_VIEWPORT_HEIGHT = 800;
|
||||
const host = document.getElementById("paseo-browser-resident-webviews");
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const activeTokens = new Set();
|
||||
let nextTokenId = 0;
|
||||
|
||||
const webview = document.createElement("webview");
|
||||
webview.id = "target-webview";
|
||||
webview.setAttribute("data-paseo-browser-id", "capture-harness");
|
||||
webview.setAttribute("partition", "persist:paseo-capture-harness");
|
||||
webview.setAttribute("allowpopups", "true");
|
||||
webview.setAttribute("spellcheck", "false");
|
||||
webview.setAttribute("autosize", "on");
|
||||
webview.src = params.get("targetUrl") || "bright.html";
|
||||
host.appendChild(webview);
|
||||
|
||||
function applyParking() {
|
||||
host.style.position = "fixed";
|
||||
host.style.left = "-20000px";
|
||||
host.style.top = "0";
|
||||
host.style.width = `${RESIDENT_VIEWPORT_WIDTH}px`;
|
||||
host.style.height = `${RESIDENT_VIEWPORT_HEIGHT}px`;
|
||||
host.style.overflow = "hidden";
|
||||
host.style.opacity = "0";
|
||||
host.style.pointerEvents = "none";
|
||||
host.style.zIndex = "";
|
||||
host.style.clipPath = "";
|
||||
host.style.visibility = "";
|
||||
host.style.transform = "";
|
||||
webview.style.display = "inline-flex";
|
||||
webview.style.flex = "0 0 auto";
|
||||
webview.style.width = `${RESIDENT_VIEWPORT_WIDTH}px`;
|
||||
webview.style.height = `${RESIDENT_VIEWPORT_HEIGHT}px`;
|
||||
webview.style.border = "0";
|
||||
webview.style.background = "transparent";
|
||||
}
|
||||
|
||||
function applyCapturePrep() {
|
||||
host.style.position = "fixed";
|
||||
host.style.left = "0";
|
||||
host.style.top = "0";
|
||||
host.style.width = "1px";
|
||||
host.style.height = "1px";
|
||||
host.style.overflow = "hidden";
|
||||
host.style.opacity = "1";
|
||||
host.style.pointerEvents = "none";
|
||||
host.style.zIndex = "1";
|
||||
host.style.clipPath = "";
|
||||
host.style.visibility = "";
|
||||
host.style.transform = "";
|
||||
}
|
||||
|
||||
function waitFrames(count) {
|
||||
return new Promise((resolve) => {
|
||||
function step(remaining) {
|
||||
if (remaining <= 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
requestAnimationFrame(() => step(remaining - 1));
|
||||
}
|
||||
step(count);
|
||||
});
|
||||
}
|
||||
|
||||
function state() {
|
||||
const hostRect = host.getBoundingClientRect();
|
||||
const webviewRect = webview.getBoundingClientRect();
|
||||
return {
|
||||
hostStyle: {
|
||||
left: host.style.left,
|
||||
top: host.style.top,
|
||||
width: host.style.width,
|
||||
height: host.style.height,
|
||||
overflow: host.style.overflow,
|
||||
opacity: host.style.opacity,
|
||||
pointerEvents: host.style.pointerEvents,
|
||||
},
|
||||
hostRect: {
|
||||
x: hostRect.x,
|
||||
y: hostRect.y,
|
||||
width: hostRect.width,
|
||||
height: hostRect.height,
|
||||
},
|
||||
webviewRect: {
|
||||
x: webviewRect.x,
|
||||
y: webviewRect.y,
|
||||
width: webviewRect.width,
|
||||
height: webviewRect.height,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
window.captureHarness = {
|
||||
async waitForFrames(count = 2) {
|
||||
await waitFrames(count);
|
||||
return state();
|
||||
},
|
||||
async prepareForPixelCapture() {
|
||||
const token = `capture-${++nextTokenId}`;
|
||||
activeTokens.add(token);
|
||||
applyCapturePrep();
|
||||
await waitFrames(2);
|
||||
webview.getBoundingClientRect();
|
||||
return { token, state: state() };
|
||||
},
|
||||
async restorePixelCapture(token) {
|
||||
activeTokens.delete(token);
|
||||
if (activeTokens.size === 0) {
|
||||
applyParking();
|
||||
}
|
||||
await waitFrames(2);
|
||||
return state();
|
||||
},
|
||||
async restoreParking() {
|
||||
activeTokens.clear();
|
||||
applyParking();
|
||||
await waitFrames(2);
|
||||
return state();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user