fix(engine): use captureBeyondViewport on all CDP screenshot paths (#1094)

* fix(engine): use captureBeyondViewport on all CDP screenshot paths

Chrome's compositor rounds the viewport boundary inward under multi-tab
load, clipping the bottom/right edge of tall portrait compositions
(1080x1920). The explicit clip rect already constrains output to exact
composition dimensions, making the viewport-boundary pre-clip from
captureBeyondViewport:false both redundant and unreliable.

Set captureBeyondViewport:true on all three CDP screenshot call sites:
pageScreenshotCapture, captureScreenshotWithAlpha, and captureAlphaPng.

Add portrait-edge-bleed regression test: 1080x1920 grid with bright
magenta bottom rows, rendered with 4 workers. Any compositor clipping
at the bottom edge drops PSNR sharply against the golden baseline.

Closes #1009

* fix(engine): address review feedback on captureBeyondViewport

- Add backref comments on captureScreenshotWithAlpha and captureAlphaPng
  pointing to pageScreenshotCapture for the rationale, so the next reader
  doesn't treat the flag as unintentional copy-paste
- Note in test meta.json that the static grid fixture covers the
  capture-side clipping path but not the video-element compositor surface
  timing that produces the t≈37s self-healing in #1009

* test(producer): use video element in portrait-edge-bleed regression test

Replace the static CSS grid with a 1080x1920 portrait video element —
matches the original bug report shape where the compositor surface
allocation timing causes the bottom-edge clipping. The video has a dark
top region and bright magenta bottom 480px, so any viewport clipping at
the bottom edge drops PSNR sharply. Baseline regenerated in Docker with
4 workers.
This commit is contained in:
Miguel Ángel
2026-05-27 11:26:38 -04:00
committed by GitHub
parent 7ea4d1c131
commit 3bbfea38cf
7 changed files with 90 additions and 4 deletions
@@ -135,7 +135,11 @@ export async function pageScreenshotCapture(page: Page, options: CaptureOptions)
format: isPng ? "png" : "jpeg",
quality: isPng ? undefined : (options.quality ?? 80),
fromSurface: true,
captureBeyondViewport: false,
// The explicit clip rect constrains output to exact composition
// dimensions. The viewport-boundary pre-clip from captureBeyondViewport:
// false is redundant, and Chrome's compositor rounds it inward under
// multi-tab load — clipping the bottom/right edge of tall viewports.
captureBeyondViewport: true,
optimizeForSpeed: !isPng,
clip,
});
@@ -168,7 +172,7 @@ export async function captureScreenshotWithAlpha(
const result = await client.send("Page.captureScreenshot", {
format: "png",
fromSurface: true,
captureBeyondViewport: false,
captureBeyondViewport: true, // see pageScreenshotCapture for rationale
optimizeForSpeed: false, // `true` uses a zero-alpha-aware fast path that crushes real alpha values — observed empirically, CDP docs don't spell it out
clip: { x: 0, y: 0, width, height, scale: 1 },
});
@@ -233,7 +237,7 @@ export async function captureAlphaPng(page: Page, width: number, height: number)
const result = await client.send("Page.captureScreenshot", {
format: "png",
fromSurface: true,
captureBeyondViewport: false,
captureBeyondViewport: true, // see pageScreenshotCapture for rationale
optimizeForSpeed: false, // must be false to preserve alpha
clip: { x: 0, y: 0, width, height, scale: 1 },
});