Skip to content

fix(html): scale the text with the fit, where webkit holds it back - #811

Merged
andiwand merged 1 commit into
mainfrom
fix-viewport-webkit-text-scale
Sep 2, 2026
Merged

fix(html): scale the text with the fit, where webkit holds it back#811
andiwand merged 1 commit into
mainfrom
fix-viewport-webkit-text-scale

Conversation

@andiwand

@andiwand andiwand commented Sep 2, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Closes #761.

What was wrong

Not the meta tag, and not the script failing to run. In fit_width_by_view on iOS the view does fit: body{zoom:0.4867} is applied, odr.getZoom() returns 0.49, the A4 page box lands at the screen width. The type does not follow.

Webkit reads a css zoom as a scale the reader asked for and holds text at the size it would have had without one. It expresses that through text-size-adjust, dividing the stated percentage by the zoom:

text-size-adjust under zoom:k used font size
auto — the default, and what we ship inflated by a factor its cluster heuristics pick; 12pt → 47px in the sample
none or 100% inflated by exactly 1/k
k·100% the specified size

So #761's "heading unchanged, body text ~2×, reflowed" is a correctly fitted page with the text left behind. The same held for odr.setZoom, which was equally wrong on iOS.

The change

viewport_js states the zoom back as the percentage whenever it applies one. Blink reads the same percentage as a plain multiplier — 50% under zoom:0.5 halves the text a second time — so a probe at startup measures whether stating it holds the type, and it is only stated where it does. @media print resets it beside the zoom.

apply() and the startup block go through one zoomBody, which also restates a zoom the css stated (viewport_width, initial_zoom), so those pages carry the adjustment too.

Measured

iPhone 17 Pro / iOS 26 simulator, Pixel 9 Pro / Chrome 139 emulator, desktop Chrome, macOS WebKit — a WKWebView harness serving the emitted html, plus test/browser/viewport.

--odr-fit:view, the sample ODT, after:

viewport zoom stated font sizes
402 0.487 48.67% 12pt→16px, 16pt→21.3px, 26pt→34.7px
600 0.726 72.64% all exact
874 1 100% all exact
  • Android: probe declines, text-size-adjust stays auto, page fitted, type exact — unchanged.
  • Desktop Chrome: tests.html all passed; both top-level banners PASS.
  • macOS WebKit: both top-level banners PASS. The property does not exist there.
  • odr_test --gtest_filter='html*:*Html*': 346 passed, 6 pre-existing skips.

Reference output

The print rule and viewport.js changed, so every emitted document moves by that one rule — on screen nothing does. compare-html --driver chrome over the private corpus: the differing set is not reproducible run to run (4, then 3, then 1 file, same pair of trees), and splitting the change proves it — the reference against the new script alone matches all files, the print rule alone flakes. Pre-existing rasterisation noise, not this change.

Regenerated anyway, so the reference stays what the renderer emits:

Two findings not acted on here

  1. Webkit draws no text below 9 css px, and text-size-adjust cannot defeat it (16px at zoom:0.25 → 36px; 40px → 40px). At the deepest fits this floors table text — 12pt at zoom 0.487 renders at 9px instead of 7.8px, laying the sample out 9% taller. Non-table text is unaffected.
  2. Already shipping, separate: in automatic mode on iOS, webkit boosts body text — 12pt → 23px, 16pt → 24px, the sample 1949px tall against 1702px. iOS renders therefore do not match the reference renders. A static text-size-adjust:100% in the shipped css fixes it and is a measured no-op in Blink, but it also makes an A4 page's body text genuinely tiny on a phone, so it is left out of a bug fix.

Not covered by the browser checks

page.html's 400 identical lines do not produce the cluster shape that triggers the inflation, so a check added there detected only the 9px floor and was dropped. The limitation is recorded in the harness README instead; the oracle is a real document served to a real webkit.

Webkit reads a css `zoom` as a scale the reader asked for and holds text
at the size it would have had without one, so `fit_width_by_view` fitted
the page box and left the type at its natural measure. It states that
compensation as `text-size-adjust` divided by the zoom, so the script now
states the zoom back as the percentage. Blink reads the same percentage
as a plain multiplier, so a probe decides whether to state it at all.

Closes #761.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018cMYRXLJdiCkH65Jm2W9B5
@andiwand
andiwand force-pushed the fix-viewport-webkit-text-scale branch from c259500 to 89f6798 Compare September 2, 2026 20:47
@andiwand
andiwand enabled auto-merge (squash) September 2, 2026 20:58
@andiwand
andiwand disabled auto-merge September 2, 2026 21:08
@andiwand
andiwand merged commit d5d525a into main Sep 2, 2026
36 checks passed
@andiwand
andiwand deleted the fix-viewport-webkit-text-scale branch September 2, 2026 21:08
andiwand added a commit to opendocument-app/OpenDocument.test.output that referenced this pull request Sep 3, 2026
Regenerated for opendocument-app/OpenDocument.core#811, which advanced the
private pin and left this one behind. Every view's `@media print` block resets
`text-size-adjust` beside the zoom, and `viewport.js` states the applied zoom as
that percentage where webkit needs it. On screen nothing moves: the rule is
print-only and the property is inert in blink.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bF15rJXQB1Jo3g3CJZCcQ
andiwand added a commit that referenced this pull request Sep 3, 2026
#811 gave every view a print-only `text-size-adjust` reset and rewrote
`viewport.js`, and advanced the private pin only. `compare-html` renders what is
not byte-identical, so the public compare went from rendering nothing to
rendering all 411 files, where the pdf and svg views screenshot
nondeterministically — two pdf pages came out "different" on main.

The reverted `docx` reference on the output repo's main belongs to a branch that
has not landed; it returns with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bF15rJXQB1Jo3g3CJZCcQ
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.

apple: fit_width_by_view leaves a paged document at actual size in WKWebView

1 participant