/**
 * DrawElement Capture Service
 *
 * `canvas.drawElementImage(element, x, y)` reads DOM paint records directly into
 * a canvas, bypassing the full compositor pipeline. Requires the Chrome flag
 * `--enable-features=CanvasDrawElement` (already added globally) and a
 * `<canvas layoutsubtree>` wrapper around the composition root.
 *
 * Performance: ~46% faster than Page.captureScreenshot on local GPU.
 * Alpha: pixel-perfect (PSNR=∞) on GPU. Falls back to screenshot in Docker
 * (SwiftShader) when transparent output is requested — SwiftShader drops promoted
 * compositor sub-layers on a transparent canvas destination (Chromium bug, filed
 * Blink>Canvas, 2026-06-08).
 */
import type { Page } from "puppeteer-core";
/**
 * Resolve which capture mode to use when `useDrawElement` is true.
 *
 * Cases that fall back to screenshot (see docs/fast-capture-limitations.md):
 *  - SwiftShader (software rasterizer, i.e. Docker/CI with no GPU): drawElement
 *    yields NO speedup here and is slightly slower. Its entire advantage is
 *    skipping the GPU→CPU screenshot readback IPC — on SwiftShader there is no
 *    GPU, so both paths block on identical software rasterization (measured
 *    parity: font-variant-numeric baseline 7822ms vs fast 7979ms, page-side
 *    draw/readback/encode all ~0ms). The drawElement path only adds a per-frame
 *    CDP round-trip on top of the same raster cost, and on a transparent
 *    destination additionally drops promoted sub-layers (Chromium bug
 *    521434899). The speedup is real only on a hardware GPU (macOS 1.6×), so
 *    SwiftShader always routes to the platform baseline.
 *
 * The former <video> gate (a proxy for the word-by-word caption opacity pattern)
 * was removed once Chrome 151 fixed crbug 521861819: video + nested-fade comps now
 * render correctly on the drawElement path (verified PSNR=inf vs baseline). 151 is
 * the pinned floor. See docs/fast-capture-limitations.md Lim 2.
 */
export declare function resolveDrawElementCaptureMode(isSwiftShader: boolean, transparent: boolean): "drawelement" | "screenshot";
/**
 * Instrument `HTMLCanvasElement.getContext` before any page script runs.
 *
 * Accelerated canvas contexts (webgl/webgl2/webgpu) present via compositor
 * texture swap — the canvas element never repaints, so its paint record never
 * invalidates and drawElementImage serves the FIRST frame's snapshot for the
 * whole render (confirmed: typegpu comp frozen at t=0, 21 dB; 2d canvas is
 * unaffected at 56 dB). The fix is to composite those canvases manually:
 * this wrapper records them in `window.__hf_accel_canvases` so
 * captureDrawElementFrame can hide them from paint records and drawImage
 * their live content underneath the drawElementImage output.
 *
 * WebGL contexts additionally get `preserveDrawingBuffer: true` forced —
 * without it the drawing buffer is cleared after each compositor present and
 * drawImage(glCanvas) reads blank.
 *
 * Must be registered via page.evaluateOnNewDocument BEFORE navigation.
 */
export declare function instrumentAcceleratedCanvases(): void;
export interface GpuBackendInfo {
    /** SwiftShader (software rasterizer) — e.g. Docker headless-shell. */
    isSwiftShader: boolean;
    /**
     * Raw UNMASKED_RENDERER_WEBGL string (e.g. "ANGLE (Apple, ANGLE Metal
     * Renderer: Apple M4 Pro, ...)", "ANGLE (NVIDIA, GeForce RTX 3080 Direct3D11
     * vs_5_0 ps_5_0, D3D11)"), or null when WebGL / the debug extension is
     * unavailable. LOCAL USE ONLY — this is unbounded driver-supplied text and
     * must not be shipped to telemetry verbatim; send
     * {@link classifyGpuRenderer}'s bucket instead.
     */
    renderer: string | null;
}
/**
 * Low-cardinality bucket for a raw WebGL renderer string: `<backend>/<vendor>`
 * (e.g. `metal/apple`, `d3d11/nvidia`, `swiftshader/other`).
 *
 * drawElement failure modes proved compositor-backend-specific during the
 * macOS rollout, so the win32/D3D11 cohort needs damage attributable to an
 * ANGLE backend + GPU vendor. The raw string can't do that job in telemetry:
 * it is unbounded, driver-authored, carries specific GPU model names, and is
 * joined across parallel sessions — high cardinality by construction. The
 * bucket keeps the analytic signal (which backend, which vendor) and drops
 * everything else, matching how `deGateReason` is a sanitized bucket rather
 * than the full fallback trigger. Pure; exported for tests.
 */
export declare function classifyGpuRenderer(renderer: string | null | undefined): string | undefined;
/**
 * Detect the page's WebGL backend: SwiftShader vs a real GPU, plus the raw
 * renderer string for telemetry.
 *
 * `isSwiftShader` is true inside Docker headless-shell with
 * --use-angle=swiftshader. Call once after window.__hf is ready; cache the
 * result on the session.
 */
export declare function detectGpuBackend(page: Page): Promise<GpuBackendInfo>;
/**
 * Back-compat wrapper over {@link detectGpuBackend} for callers that only
 * need the SwiftShader boolean.
 */
export declare function detectSwiftShader(page: Page): Promise<boolean>;
/**
 * Inject a `<canvas layoutsubtree>` around the composition root.
 *
 * The canvas must wrap `[data-composition-id]` for drawElementImage to read
 * its paint records. Idempotent — skips injection if `__hf_de_canvas` exists.
 * Must be called after window.__hf is ready (so the composition root is in the DOM).
 */
export declare function injectDrawElementCanvas(page: Page, width: number, height: number): Promise<void>;
/**
 * Capture one frame via canvas.drawElementImage, synchronized to the canvas
 * `paint` event.
 *
 * `drawElementImage` draws from a snapshot recorded at the paint event; called
 * outside one it returns the PREVIOUS frame's snapshot (WICG html-in-canvas).
 * Capturing unsynchronized therefore yields one-frame-stale content, or an
 * `InvalidStateError: No cached paint record` when no paint has landed since
 * the last DOM mutation (the intermittent macOS crash). The fix is the API's
 * intended usage: force an invalidation, await the canvas `paint` event, and
 * draw inside its handler — the snapshot is then the CURRENT frame. Measured
 * cost of the paint wait is ~1.3 ms/frame; the encode dominates.
 *
 * Encoding MUST match what the downstream encoder expects:
 *   - "png"  → `toDataURL("image/png")` — preserves alpha (transparent output).
 *   - "jpeg" → `toDataURL("image/jpeg", q)` — opaque output. The producer's
 *     streaming encoder pipes frames to ffmpeg as mjpeg; feeding it PNG bytes
 *     makes ffmpeg's jpeg decoder fail ("Can not process SOS before SOF").
 *
 * Alpha (png) is preserved correctly on GPU (PSNR=∞ vs captureScreenshot). Do
 * NOT call in Docker with transparent output — use the screenshot fallback
 * instead (see routing in frameCapture.ts initializeSession).
 */
export declare function captureDrawElementFrame(page: Page, width: number, height: number, format?: "jpeg" | "png", quality?: number, syncToPaintEvent?: boolean): Promise<Buffer>;
/**
 * Initialize the in-page JPEG encode Worker for a session. Must be called
 * after page navigation (post-`initializeSession`) and before any
 * `produceDrawElementFrame` calls.
 *
 * Safe to call multiple times for the same page (e.g. session reuse after
 * navigation): the exposeFunction binding survives navigation, but the
 * in-page Worker is re-created. Pending promises from a prior navigation are
 * rejected with a "session reused" error.
 */
export declare function initDrawElementWorkerEncode(page: Page): Promise<void>;
/**
 * Clean up the worker encode state for a session being closed. Rejects any
 * pending frame promises and removes the WeakMap entry. Safe to call even if
 * `initDrawElementWorkerEncode` was never called for this page.
 */
export declare function cleanupDrawElementWorkerEncode(page: Page): void;
/**
 * Pipelined drawElement frame capture: produce phase only.
 *
 * Performs seek-prep, paint-wait, drawElementImage, compositing, and
 * `createImageBitmap` on the main thread, then transfers the bitmap to the
 * in-page encode worker. Returns as soon as the bitmap is transferred — the
 * worker encodes asynchronously. The returned `encodeResult` resolves when
 * the worker posts the encoded frame back to node.
 *
 * Call `initDrawElementWorkerEncode` once per page before using this function.
 *
 * JPEG only (png falls back to synchronous `captureDrawElementFrame`).
 */
export declare function produceDrawElementFrame(page: Page, width: number, height: number, quality?: number, syncToPaintEvent?: boolean): Promise<{
    encodeResult: Promise<Buffer>;
}>;
/**
 * P6 prototype (HF_DE_BATCH): batch-produce N consecutive frames in ONE CDP
 * round-trip. In-page loop per frame: `__hf.seek(t)` → paint-wait
 * (__hfDeInvalidate: sentinel dirty + requestPaint, then the canvas `paint`
 * event) → drawElementImage composite → createImageBitmap →
 * postMessage to the encode worker. Bitmaps are posted per-frame (encode starts
 * immediately); only the CDP protocol round-trips are amortized N-fold.
 * Micro-pipeline inside the batch: frame i+1's seek/paint-wait overlaps frame
 * i's createImageBitmap (the canvas is only redrawn after i's bitmap resolves).
 *
 * macOS-GPU sync path only (the worker-encode gate guarantees this at the call
 * site). On an in-page failure at frame k, frames < k are already at the worker
 * (their promises resolve normally); pending entries for frames >= k are
 * rejected here and `failedAt` tells the caller to re-capture k.. via the
 * per-frame path (which owns the screenshot-fallback semantics).
 */
export declare function produceDrawElementFrameBatch(page: Page, times: number[], width: number, height: number, quality?: number): Promise<{
    encodeResults: Array<Promise<Buffer>>;
    failedAt: number | null;
    error?: string;
}>;
//# sourceMappingURL=drawElementService.d.ts.map