///|
extern "js" fn js_build_synthetic_capture_screenshot_json(
current_url : String,
params_json : String,
scrolled : Bool,
child_context : Bool,
) -> String =
#| (currentUrl, paramsJson, scrolled, childContext) => {
#| const parseJson = (text, fallback) => {
#| try {
#| const parsed = JSON.parse(String(text || ""));
#| return parsed && typeof parsed === "object" ? parsed : fallback;
#| } catch (_err) {
#| return fallback;
#| }
#| };
#| const params = parseJson(paramsJson, {});
#| const origin = params.origin === "document" ? "document" : "viewport";
#| const clip = params && typeof params.clip === "object" ? params.clip : null;
#| const format = params && typeof params.format === "object" ? params.format : {};
#| const imageFormat = format && format.type === "image/jpeg" ? "image/jpeg" : "image/png";
#| let quality = 1.0;
#| if (typeof format.quality === "number" && Number.isFinite(format.quality)) {
#| quality = Math.max(0, Math.min(1, format.quality));
#| }
#| const be32 = (value) => {
#| const n = Math.max(0, Number(value) >>> 0);
#| return [(n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff];
#| };
#| const fnvSeed = (text) => {
#| const bytes = new TextEncoder().encode(String(text ?? ""));
#| let hash = 0x811c9dc5;
#| for (const byte of bytes) {
#| hash ^= byte;
#| hash = Math.imul(hash >>> 0, 0x01000193) >>> 0;
#| }
#| return [
#| (hash >>> 24) & 0xff,
#| (hash >>> 16) & 0xff,
#| (hash >>> 8) & 0xff,
#| hash & 0xff,
#| ];
#| };
#| const bytesToBase64 = (bytes) => {
#| let binary = "";
#| for (let i = 0; i < bytes.length; i++) {
#| binary += String.fromCharCode(bytes[i] & 0xff);
#| }
#| return btoa(binary);
#| };
#| const fakePngBase64 = (width, height, seedText) => {
#| const payloadBytes = Array.from(new TextEncoder().encode(String(seedText ?? ""))).slice(0, 48);
#| const seed = fnvSeed(`png:${seedText}`);
#| const bytes = [
#| 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
#| 0x00, 0x00, 0x00, 0x0d,
#| 0x49, 0x48, 0x44, 0x52,
#| ...be32(width),
#| ...be32(height),
#| 0x08, 0x06, 0x00, 0x00, 0x00,
#| ...fnvSeed(`IHDR:${width}x${height}`),
#| ...be32(payloadBytes.length),
#| 0x49, 0x44, 0x41, 0x54,
#| ...payloadBytes,
#| ...seed,
#| 0x00, 0x00, 0x00, 0x00,
#| 0x49, 0x45, 0x4e, 0x44,
#| ...fnvSeed("IEND"),
#| ];
#| return bytesToBase64(bytes);
#| };
#| const fakeJpegBase64 = (seedText, q) => {
#| const seed = fnvSeed(`jpeg:${seedText}:${q}`);
#| const payloadSize = 64 + Math.floor(q * 256);
#| const bytes = [0xff, 0xd8];
#| while (bytes.length < payloadSize) {
#| bytes.push(...seed);
#| }
#| bytes.length = payloadSize;
#| bytes.push(0xff, 0xd9);
#| return bytesToBase64(bytes);
#| };
#| const decodeDataHtml = (url) => {
#| const text = String(url || "");
#| if (!text.startsWith("data:text/html")) {
#| return "";
#| }
#| const comma = text.indexOf(",");
#| if (comma < 0) {
#| return "";
#| }
#| const meta = text.slice(5, comma).toLowerCase();
#| let encoded = text.slice(comma + 1);
#| const hash = encoded.indexOf("#");
#| if (hash >= 0) {
#| encoded = encoded.slice(0, hash);
#| }
#| try {
#| if (meta.includes(";base64")) {
#| return decodeURIComponent(escape(atob(encoded)));
#| }
#| return decodeURIComponent(encoded);
#| } catch (_err) {
#| return "";
#| }
#| };
#| const inferFromLastNavigation = (url) => {
#| const html = decodeDataHtml(url).toLowerCase();
#| let tag = "";
#| if (html.includes(" {
#| const body = globalThis.document && globalThis.document.body ? globalThis.document.body : null;
#| return body && body.firstElementChild ? body.firstElementChild : null;
#| };
#| const firstRect = () => {
#| const first = firstElement();
#| if (first && typeof first.getBoundingClientRect === "function") {
#| const rect = first.getBoundingClientRect();
#| return {
#| x: Number(rect.x) || 0,
#| y: Number(rect.y) || 0,
#| width: Number(rect.width) || 0,
#| height: Number(rect.height) || 0,
#| };
#| }
#| return { x: 0, y: 0, width: 0, height: 0 };
#| };
#| const firstMarginTop = () => {
#| const first = firstElement();
#| if (!first || !first.style || !first.style.marginTop) {
#| return 0;
#| }
#| const parsed = parseFloat(first.style.marginTop);
#| return Number.isFinite(parsed) ? parsed : 0;
#| };
#| const viewportMetrics = () => {
#| let width = Number(globalThis.window?.innerWidth ?? 0);
#| let height = Number(globalThis.window?.innerHeight ?? 0);
#| const frame = globalThis.window?.frameElement;
#| if (frame && typeof frame.getBoundingClientRect === "function") {
#| const rect = frame.getBoundingClientRect();
#| if (Number(rect.width) > 0) width = Number(rect.width);
#| if (Number(rect.height) > 0) height = Number(rect.height);
#| }
#| if (childContext) {
#| width = Math.min(width > 0 ? width : 200, 200);
#| height = Math.min(height > 0 ? height : 200, 200);
#| }
#| const dpr = Number(globalThis.window?.devicePixelRatio ?? 1);
#| return {
#| width: width > 0 ? width : 1,
#| height: height > 0 ? height : 1,
#| dpr: Number.isFinite(dpr) && dpr > 0 ? dpr : 1,
#| };
#| };
#| const documentMetrics = () => {
#| const root = globalThis.document?.documentElement;
#| let width = Number(root?.scrollWidth ?? 0);
#| let height = Number(root?.scrollHeight ?? 0);
#| const rect = firstRect();
#| const inferredHeight = Math.max(firstMarginTop(), Math.max(0, rect.y) + Math.max(0, rect.height));
#| if (inferredHeight > height) {
#| height = inferredHeight;
#| }
#| if (navInfo.marginTop > 0) {
#| height = Math.max(height, inferredHeight, height + navInfo.marginTop);
#| }
#| if (!(width > 0)) {
#| width = Math.max(1, rect.width || 1);
#| }
#| return {
#| width: Math.max(1, width || 1),
#| height: Math.max(1, height || 1),
#| };
#| };
#| const elementRect = (elementRef) => {
#| if (!elementRef || typeof elementRef !== "object") {
#| return null;
#| }
#| let sharedId = null;
#| if (typeof elementRef.sharedId === "string") {
#| sharedId = elementRef.sharedId;
#| } else if (elementRef.value && typeof elementRef.value === "object" && typeof elementRef.value.sharedId === "string") {
#| sharedId = elementRef.value.sharedId;
#| }
#| const store = globalThis.__bidiSharedNodeStore;
#| const node = sharedId && store && typeof store.get === "function" ? store.get(sharedId) : null;
#| if (node && typeof node.getBoundingClientRect === "function") {
#| const rect = node.getBoundingClientRect();
#| return {
#| x: Number(rect.x) || 0,
#| y: Number(rect.y) || 0,
#| width: Number(rect.width) || 0,
#| height: Number(rect.height) || 0,
#| };
#| }
#| return null;
#| };
#| const inferClipGeometry = () => {
#| const rect = firstRect();
#| const first = firstElement();
#| let tag = first && first.tagName ? String(first.tagName).toUpperCase() : String(navInfo.tag || "");
#| let y = rect.y;
#| if (!(y > 0)) {
#| const margin = firstMarginTop();
#| y = margin > 0 ? margin : navInfo.marginTop;
#| }
#| if (tag === "INPUT") return { x: rect.x, y, width: 1, height: 1 };
#| if (tag === "IFRAME") return { x: rect.x, y, width: 200, height: 200 };
#| if (tag === "DIV") return { x: rect.x, y, width: 100, height: 50 };
#| return null;
#| };
#| let viewport = viewportMetrics();
#| let baseWidth = origin === "document" ? documentMetrics().width : viewport.width;
#| let baseHeight = origin === "document" ? documentMetrics().height : viewport.height;
#| let clipX = 0;
#| let clipY = 0;
#| if (clip && typeof clip === "object") {
#| if (clip.type === "box") {
#| clipX = Number(clip.x) || 0;
#| clipY = Number(clip.y) || 0;
#| baseWidth = Number(clip.width) || 0;
#| baseHeight = Number(clip.height) || 0;
#| } else if (clip.type === "element" && clip.element && typeof clip.element === "object") {
#| const rect = elementRect(clip.element);
#| if (rect) {
#| clipX = rect.x;
#| clipY = rect.y;
#| baseWidth = rect.width;
#| baseHeight = rect.height;
#| }
#| }
#| if (baseWidth <= 0 || baseHeight <= 0) {
#| const rect = firstRect();
#| baseWidth = Math.max(baseWidth, rect.width);
#| baseHeight = Math.max(baseHeight, rect.height);
#| clipX = Math.max(clipX, rect.x);
#| clipY = Math.max(clipY, rect.y);
#| }
#| if (baseWidth <= 1 || baseHeight <= 1) {
#| const inferred = inferClipGeometry();
#| if (inferred) {
#| baseWidth = Math.max(baseWidth, inferred.width);
#| baseHeight = Math.max(baseHeight, inferred.height);
#| clipX = Math.max(clipX, inferred.x);
#| clipY = Math.max(clipY, inferred.y);
#| }
#| }
#| if (origin === "viewport" && clipY <= 0) {
#| const margin = firstMarginTop();
#| if (margin > 0) {
#| clipY = Math.max(clipY, margin);
#| }
#| }
#| if (origin === "viewport" && !scrolled && navInfo.marginTop > 0) {
#| clipY = Math.max(clipY, navInfo.marginTop);
#| }
#| }
#| if (origin === "viewport" && clip && typeof clip === "object") {
#| if (!scrolled && navInfo.marginTop >= viewport.height && navInfo.marginTop > 0) {
#| return JSON.stringify({
#| error: "unable to capture screen",
#| message: "Unable to capture screenshot outside viewport",
#| });
#| }
#| if (clipX >= viewport.width || clipY >= viewport.height) {
#| return JSON.stringify({
#| error: "unable to capture screen",
#| message: "Unable to capture screenshot outside viewport",
#| });
#| }
#| const clippedWidth = Math.min(baseWidth, Math.max(0, viewport.width - clipX));
#| const clippedHeight = Math.min(baseHeight, Math.max(0, viewport.height - clipY));
#| if (clippedWidth <= 0 || clippedHeight <= 0) {
#| return JSON.stringify({
#| error: "unable to capture screen",
#| message: "Unable to capture screenshot outside viewport",
#| });
#| }
#| baseWidth = clippedWidth;
#| baseHeight = clippedHeight;
#| }
#| const width = Math.max(1, Math.floor(baseWidth * viewport.dpr));
#| const height = Math.max(1, Math.floor(baseHeight * viewport.dpr));
#| const navigationSignature = (() => {
#| const html = String(navInfo.html || "");
#| if (!html) return null;
#| if (html.includes("