Repository navigation
Resize the headless viewport with Browser.setContentsSize - #458
Merged
Merged
Conversation
Chromium 154 clears Emulation.setDeviceMetricsOverride when the session that set it detaches, so the override PATCH /display applies on the headless path is undone as soon as the server disconnects. Size the window around the page instead, which persists independently of any CDP session. Also match the chrome://extensions Developer mode toggle by either role: Chromium 154 changed cr-toggle from role=button to role=switch.
…efused Chromium rejects Browser.setContentsSize for a maximized, minimized or fullscreen window. Production headless launches maximized, so restore maximized and minimized windows to normal first. Leave fullscreen windows alone, since leaving fullscreen would exit kiosk mode, and fall back to the previous device metrics override whenever Chromium refuses the resize, so no request fails that succeeded before. Keep SetDeviceMetricsOverride for that fallback, and cover maximized and kiosk headless browsers in the resize e2e.
sjmiller609
marked this pull request as ready for review
October 21, 2026 13:34
sjmiller609
approved these changes
Oct 21, 2026
Contributor
|
Taking liberty to merge this one, and will QA the path before launching:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This fixes two things that break once the images move to Chromium 154. The images here are still pinned to Chrome for Testing 152, so nothing fails on main today. I'm landing this first so the version bump doesn't regress headless display resizing. Wherever Chromium declines the new approach, it falls back to today's behaviour, so no request that succeeds on main fails with this change.
Headless
PATCH /displaystops resizing the page on Chromium 154On the headless fast path,
setViewportViaCDPcalledcdpclient.SetDeviceMetricsOverride. That attaches to the first page target, sendsEmulation.setDeviceMetricsOverride, and detaches. This only worked because Chromium used to keep the emulated view size after the session detached. In Chromium 154,EmulationHandler::Disable()(content/browser/devtools/protocol/emulation_handler.cc) callsWebContentsImpl::ClearDeviceEmulationSize()when the session is torn down. The override is undone as soon as the server disconnects:PATCH /displaystill returns 200, butinnerWidth/innerHeightnever change.Fix: a new
cdpclient.SetContentsSizelooks up the window for the first page target and sendsBrowser.setContentsSize, so the window's web contents are exactly WxH. The size belongs to the window, not to a CDP session, so it holds after the server disconnects.Browser.setContentsSizeis available in 152 and is already listed incdp_protocol_pinned.json.Chromium rejects
setContentsSizewithRestore window to normal state before setting content sizeunless the window is normal. Each window state is handled like this:setContentsSizeBrowser.setWindowBounds {windowState: normal}, thensetContentsSize. Headless browsers launched with--start-maximizedare maximized, and in headless that only means "fill the 800x600 headless screen", so nothing is lost. After a resize the window reportsnormal.--kiosk, HTML5 fullscreen)SetDeviceMetricsOverride, exactly as on main: the viewport changes on 152 and stays as it was on 154+.setContentsSizerefused with a CDP errorWarnlogNo page target, context and connection errors are returned as they are today, without a second attempt.
SetDeviceMetricsOverrideis unchanged.TestMV3ServiceWorkerRegistrationcan't find the Developer mode toggle on Chromium 154Chromium 154 changed the WebUI
cr-toggleelement (ui/webui/resources/cr_elements/cr_toggle/cr_toggle.ts) fromrole="button"+aria-pressedtorole="switch"+aria-checked, sogetByRole('button', { name: 'Developer mode' })stops matching. The locator now accepts either role.Tests
TestSetContentsSize(cdpclient) covers the call order for normal, maximized and minimized windows, a fullscreen window returningErrWindowFullscreenwithout touching the window, a CDP refusal, and a missing page target.TestContentsSizeRefused(api) checks which errors fall back.TestDisplayResizeChromiumWindowgains two scenarios:headless_start_maximized:--start-maximized. It asserts the exact inner size and the window ending upnormal.headless_kiosk:--kiosk. It asserts thatPATCH /displayreturns 200 and that the window staysfullscreen, with the same window ID. The viewport isn't asserted, because on 154+ the fallback leaves it unchanged, as on main.Validation
go vetis clean on the touched packages;go test -race ./lib/cdpclient/andgo test ./cmd/api/api/pass.kernel-images-apiinto three headless images, on Chrome 152.0.7977.42 (onkernel/chromium-headless:70d2dba), 154.0.8037.97 and 155.0.8059.79.headless_default,headless_start_maximized,headless_kioskandTestMV3ServiceWorkerRegistrationpassed on all three. Inner size was exactly 1920x1080 and then 1280x720 for the default and maximized scenarios.headless_start_maximizedandheadless_kioskboth fail withPATCH /display: 500 ... Restore window to normal state before setting content size.-parallel=4: 53 passed, 0 failed. That coversTestPlaywrightExecuteAPI(WebMCP), BiDi, the CDP proxy tests,TestChromiumConfigureMultipartPowerset,TestDisplayResolutionChange,TestExtensionUploadAndActivationandTestScreenshotHeadless.headless_defaultfailed once at 34 s withnavigateBlank'spage.goto('about:blank')timing out, before anyPATCH /displaywas sent. It's a startup timing flake under load, not related to this change.Note
Medium Risk
Changes headless display resize CDP behavior on a user-facing API path; fallback preserves prior semantics for kiosk/fullscreen, but maximized headless windows end in normal state after resize.
Overview
Prepares headless
PATCH /displayfor Chromium 154 by resizing the viewport withBrowser.setContentsSize(via newcdpclient.SetContentsSize) instead of relying only onEmulation.setDeviceMetricsOverride, which 154+ clears when the CDP session ends.setViewportViaCDPtriesSetContentsSizefirst: maximized/minimized windows are restored to normal before sizing; fullscreen windows returnErrWindowFullscreenand are not demoted. On fullscreen or other Chromium refusals, it logs and falls back toSetDeviceMetricsOverride(kiosk/154+ behavior unchanged from main). Connection and missing-page-target errors do not trigger fallback.E2E adds
headless_start_maximizedandheadless_kioskscenarios with optional viewport assertions and expectedwindowStateafter resize. Playwright MV3 test accepts Developer mode asswitchorbuttonfor Chromium 154 WebUI.Reviewed by Cursor Bugbot for commit f9ffd8b. Bugbot is set up for automated code reviews on this repo. Configure here.