Skip to content

WebView: withMinimumDeviceScaleFactor (macOS + Windows) — fix blur on low-DPI displays#35

Closed
jakepenn wants to merge 2 commits into
minimal_masterfrom
webview-mac-min-device-scale
Closed

WebView: withMinimumDeviceScaleFactor (macOS + Windows) — fix blur on low-DPI displays#35
jakepenn wants to merge 2 commits into
minimal_masterfrom
webview-mac-min-device-scale

Conversation

@jakepenn

@jakepenn jakepenn commented Jun 4, 2026

Copy link
Copy Markdown
Member

Problem

The player webview renders blurry on low-DPI displays (1× / 100%-scaled monitors; reported on a 1920×1080 panel). The frontend fits a fixed-size design into the host window; the host editor scales the WebView via an ancestor AffineTransform, which enlarges the WebView's bounds without changing its CSS layout. At 1 device px per CSS px, the OS upscale of that enlarged surface bilinear-blurs the content — most visibly text. High-DPI (2×) displays hide it because the page already rasterises at 2×.

Change

Adds withMinimumDeviceScaleFactor(double) — a floor on the WebView's rasterisation device scale — to both AppleWkWebView and WinWebView2 options. Raises rasterisation density (and window.devicePixelRatio) so transform-based fits have headroom and stay crisp. It's a floor, so a high-DPI display is a no-op.

macOS: private WKWebView SPI _setOverrideDeviceScaleFactor: via a guarded objc_msgSend (an @interface category can't live in the juce namespace). Re-applied in viewDidChangeBackingProperties and floored at max(min, backingScaleFactor). respondsToSelector + @try → silent no-op if the SPI is dropped. CSS viewport is unchanged.

Windows: ICoreWebView2Controller3::put_RasterizationScale set to max(min, monitorScale), with ShouldDetectMonitorScaleChanges disabled so WebView2 doesn't reset the floor on DPI changes (re-applied from the scale-factor notifier with the live monitor scale). No-op on runtimes without Controller3. Note: raising RasterizationScale also shrinks the CSS viewport (CSS px = bounds / scale), so it's only appropriate for responsively-laid-out content — documented on the option.

Consumer opt-in lands separately in minimal_core (MKUEmbeddedWebView.withMinimumDeviceScaleFactor(2.0) on both backends).

Status / testing

  • macOS — compiles + links clean (AU/VST3). Pending on-device verification: _setOverrideDeviceScaleFactor: must take effect; check window.devicePixelRatio reads 2 on a 1× display.
  • Windowsnot yet built (no Windows toolchain on hand). Needs a Windows compile + on-device check that window.devicePixelRatio reads 2 and layout is unchanged-but-sharp.

🤖 Generated with Claude Code

jakepenn and others added 2 commits June 4, 2026 16:34
…sity

Adds AppleWkWebView::withMinimumDeviceScaleFactor(double). On a standard-DPI
(1x) display the WKWebView rasterises at one device pixel per CSS pixel; when
the host scales the editor up via an ancestor AffineTransform (which enlarges
the WebView's peer bounds without changing its CSS layout) the OS upscales
that 1x raster and the content reads as blurry — most visibly text. Raising
the effective device scale gives the renderer headroom so the upscale stays
sharp. It is a floor: a Retina display already exceeds it, so it's a no-op
there.

This affects rasterisation density and window.devicePixelRatio only — CSS
layout is unchanged, so it cannot shift or reflow the UI (unlike a CSS
zoom-based fit). macOS impl uses the private WKWebView SPI
_setOverrideDeviceScaleFactor: via a guarded objc_msgSend, re-applied in
viewDidChangeBackingProperties so it survives moves between displays of
differing backingScaleFactor. respondsToSelector + @Try make it a silent
no-op if a future OS drops the SPI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the Windows counterpart to the macOS withMinimumDeviceScaleFactor floor,
on WinWebView2 options. Implemented with ICoreWebView2Controller3::
put_RasterizationScale: the floor is max(requested, monitor scale), and
ShouldDetectMonitorScaleChanges is turned off so WebView2 doesn't reset it on
DPI changes — it's re-applied from the scale-factor notifier with the live
monitor scale instead. No-op on WebView2 runtimes without Controller3.

Same purpose as the macOS path: on a 100%-scaled monitor the content otherwise
rasterises at 1 device px per CSS px, so the host's ancestor-transform scaling
leaves the OS upscaling a 1x raster (blurry, most visibly text). Note that
raising RasterizationScale also shrinks the CSS viewport (CSS px = bounds /
scale), so it's only appropriate for responsively-laid-out content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jakepenn jakepenn changed the title WebView (macOS): withMinimumDeviceScaleFactor — fix blur on 1× displays WebView: withMinimumDeviceScaleFactor (macOS + Windows) — fix blur on low-DPI displays Jun 4, 2026
@jakepenn jakepenn closed this Jun 5, 2026
@jakepenn jakepenn deleted the webview-mac-min-device-scale branch June 5, 2026 15:02
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