Skip to content

fix(browser): preserve the latest viewport after screenshot capture - #1416

Merged
vastsa merged 2 commits into
vastsa:mainfrom
AR307:codex/upstream-browser-capture-resize
Oct 5, 2026
Merged

vastsa merged 2 commits into
vastsa:mainfrom
AR307:codex/upstream-browser-capture-resize

Conversation

@AR307

@AR307 AR307 commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Problem and reproduction

When the embedded browser is resized during a screenshot, Chromium can finish
by restoring its capture-time viewport. The native view has already received
the new bounds, but the document keeps the old innerWidth/innerHeight.

On main def015ebb, a local responsive page begins at 800 x 500. Starting a
full-page capture and updating the browser hole before it completes leaves the
document at 800 x 500 instead of the requested 960 x 620 or 820 x 510. This was
reproduced in real Electron/Chromium across 12 alternating-size iterations,
covering both the screenshot API and raw Page.captureScreenshot.

Fix

  • BrowserPane serializes screenshot operations per retained page.
  • During capture it retains the latest requested bounds without updating the
    native viewport; success or failure applies the latest visible bounds.
  • BrowserHost sends both screenshot entry points through that owner.
  • The queued operation captures the original page/WebContents identity, so tab
    switching or closure cannot redirect it to a different page.
  • Sibling pages remain independent; a failed capture does not poison the queue.

This does not reload a page, repeat a screenshot, add a timeout/retry policy,
change screenshot format, or alter CDP/URL/permission rules. No storage, provider,
MC or agent lifecycle changes are included.

Validation

  • The two new size-restoration service cases fail on the original code.
  • Five production Host/Pane/CDP cases pass after the fix: both capture entry
    points, failure recovery, concurrent requests/sibling pages, and tab closure.
  • Existing browser session/CDP checks pass: 18 browser cases in total.
  • node scripts/e2e-browser-capture-resize.mjs passes with real Chromium and a
    local responsive page: 12/12 final viewports equal the latest requested size.
    The PNG was visually inspected; the script retains its JSON/PNG/profile.
  • Targeted TypeScript checking of BrowserPane, BrowserHost and the Electron
    probe previously passed.
  • Full pnpm build:js, desktop typecheck and current agent-runtime bundle pass.
  • PR base ancestry and git diff --check pass.
  • The identical Rust host source was rebuilt in the separate drag candidate
    with Cargo 1.90.0. No Rust source is changed by either fix.

Environment: Windows, Node 24.19.0, Electron 43.6.0, Chromium 150.0.7871.250.
Current production sources are bundled for the probe; only compatible external
build tools/Electron are reused from an installed dependency tree.

Tested candidate: 4f68894.
Upstream base: 10e824e.

Limitations: packaged-app E2E and macOS/Linux native validation have not been
run. The probe drives the real host and browser hole but does not automate
the entire plugin toolbar. No live provider calls are required or claimed.

Review notes

Ownership stays in BrowserPane, which already controls native bounds and guest
lifetime. BrowserHost remains routing glue. Existing hidden/visible and
per-session/per-tab ownership remain intact. The caller receives errors even
though the internal queue tail allows a later independent capture to proceed.

AR307 and others added 2 commits October 5, 2026 09:17
Coordinate screenshot capture with the pane that owns native bounds so
Chromium cannot restore a stale viewport after a concurrent resize.
Pin queued captures to their originating page and preserve caller errors.
@vastsa
vastsa merged commit 810037f into vastsa:main Oct 5, 2026
4 checks passed
@vastsa

vastsa commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Thanks for the detailed Chromium reproduction and the per-page capture design. Pinning queued captures to their original guest and restoring the latest bounds on both success and failure addresses the race at its source. The refreshed integration candidate passed the 12-iteration viewport E2E and all CI checks. Merged with appreciation for the thorough validation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants