Skip to content

WebView (macOS): don't promote WKWebView to layer-backed for bg colour (fixes secondary-monitor blur) - #34

Merged
jakepenn merged 1 commit into
minimal_masterfrom
webview-mac-drop-wantslayer-blur
Jun 4, 2026
Merged

jakepenn merged 1 commit into
minimal_masterfrom
webview-mac-drop-wantslayer-blur

Conversation

@jakepenn

@jakepenn jakepenn commented Jun 4, 2026

Copy link
Copy Markdown
Member

Problem

Some users report the player webview rendering blurry on a secondary monitor (Retina ↔ non-Retina, or two displays at different scales).

Root cause: the macOS background-colour path (AppleWkWebView::withBackgroundColour, which we use to suppress the first-paint white flash) promoted the WKWebView to a layer-backed view:

[webView setWantsLayer: YES];
layer.backgroundColor = CGColorGetConstantColor (kCGColorClear);

That promotion pins the view's root-layer contentsScale at creation time. When the host window then moves to a display with a different backingScaleFactor, high-DPI content is composited into a stale backing and reads as pixelated/blurry. A plain (layer-hosting) WKWebView — what CHOC, wry and Safari use — lets WebKit keep the backing scale in sync across display moves automatically.

Change

Drop the setWantsLayer:YES + transparent layer.backgroundColor block. The WKWebView stays layer-hosting (its default). First-paint flash suppression is unchanged — it relied on drawsBackground = NO and setUnderPageBackgroundColor, both kept. The under-page background now shows the chrome colour rather than a clear layer.

The viewDidChangeBackingProperties re-stamp (added in #32 to chase the pinning) is left in place as a harmless backing-scale safety net.

Testing

  • First-paint white flash still suppressed (no flicker on load) with the chrome background colour
  • Webview sharp when the plugin window is moved between displays of differing backing scale
  • Verified in plugin host on a dual-monitor Retina + non-Retina setup

🤖 Generated with Claude Code

The background-colour path (withBackgroundColour, used to kill the
first-paint white flash) promoted the WKWebView via setWantsLayer:YES
plus a transparent layer.backgroundColor. That promotion pins the
view's root-layer contentsScale at creation time, so moving the host
window to a display with a different backingScaleFactor leaves
high-DPI content composited into a stale backing — it reads as blurry
on the secondary monitor.

Drop the setWantsLayer/clear-layer block. Left layer-hosting (the
WKWebView default, as used by CHOC/wry/Safari) WebKit keeps the
backing scale in sync across display moves on its own. drawsBackground
= NO plus setUnderPageBackgroundColor still suppress the first-paint
flash without touching the layer.

The viewDidChangeBackingProperties re-stamp added earlier to chase the
pinning is left in place as a harmless backing-scale safety net.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jakepenn
jakepenn merged commit 2a1af99 into minimal_master Jun 4, 2026
1 check failed
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.

1 participant