Skip to content

The live fit is gated on being in a frame, so a top-level host can only have it frozen (viewport_width) #726

Description

@andiwand

Filing this from the Android side after taking 6.10.0 (opendocument-app/OpenDocument.droid#609). Short version: the app wired viewportWidth, measured a regression, and reverted it — and the reason generalises past Android.

What Android has today, and where it comes from

PageView is a top-level WebView with useWideViewPort and loadWithOverviewMode set. Those two make the WebView pick a page scale that fits the content, but only where the page has not pinned one — and that is exactly the distinction write_viewport_meta already draws:

view meta tag what the WebView does
fit_width (slide, pdf page, text document with margins) width=device-width,user-scalable=yes scales the page down to fit, at load and again on every rotation
actual_size (sheet, plain text, xml, archive listing) width=device-width,initial-scale=1.0,user-scalable=yes holds 1:1, content overflows to the right

Measured on 6.10.0, API 36 / WebView 133 and API 31 / WebView 91: style-various-1.pptx fills the width in portrait, and fills it again after a turn to landscape; file_example_XLSX_50.xlsx sits at full size with column D cut off at the edge.

So the fit on Android is already core's decision, executed by the host — not a workaround of the kind iOS carries (#706). The absent initial-scale is doing real work.

What happens if Android takes viewport_width

Wired end to end through CoreLoader, built, and measured against the same documents:

  • At load: no visible change. The WebView was already fitting; the css factor just moves who applies it.
  • After a rotation: a regression. --odr-fit becomes a number, so measures is false in viewport_js and resized() returns after remember(). The factor was decided while translating and cannot follow the viewport. A deck opened in portrait keeps a portrait-sized slide centred in a landscape screen — where before it filled the width.

Reverted. The droid PR takes 6.10.0 and sets neither viewportWidth nor initialZoom.

The general shape

framed is a proxy for "will the host fit this for me":

// Only a frame is fitted here: the viewport meta tag covers the top-level
// document but is inert in a frame.
var framed = window.top !== window.self;

That proxy is wrong in both directions once you leave the browser:

The page cannot test the thing the guard is testing. Only the host knows. Which leaves three modes where four are wanted:

  1. the host fits it, via the meta tag — today's top-level default
  2. a static css factor — viewport_width
  3. the view measures itself, live — framed only
  4. the view measures itself, live, at top level — missing

Suggestion

Let a host ask for (4) explicitly: a flag meaning "fit paged output, measured by the view", which drops the framed guard for that document and leaves --odr-fit: auto. viewport_width keeps its own meaning — "I already know the width, write it into the css" — which is still the right answer for an embedder under a CSP that cannot run the script.

Worth keeping it opt-in rather than widening the default: the guard is there because fitting every fit_width view at load moved 86 of 377 public reference renders, and shrinking a wide page in a desktop window is not what #706 or #708 asked for. An opt-in disturbs neither.

Is it worth doing?

Honest answer, from the side that just declined to use it:

  • iOS: yes. WKWebView has no loadWithOverviewMode equivalent, so top-level output is not fitted at all and the app patches it by rewriting the meta tag. (4) would delete that workaround. Note that (2) would not — it would hand iOS the same frozen-on-rotation behaviour Android just measured, on a device people rotate at least as often.
  • Embedders: already served by (3). Nothing to do.
  • Android: no, not as a fix. The WebView already does (4), live, steered by core's own per-view decision. Adopting a core-side fit would mean turning loadWithOverviewMode off and handing the job over. Two things it would buy, both small:
    • Core fits the page box (page plus gutter); the WebView fits the content. A document with a table wider than its page makes the WebView zoom right out and the body text tiny, where core would fit the page and let the table overflow — the better read. Reasoned from both sides, not measured: no fixture in the corpus mixes the two widths.
    • The anchor logic in viewport_js would hold the reading position across a rotation exactly. The browser's own guess drifted about one line in a long .odt here — Served pages leave fitting to the app, and each app gets it wrong differently #706's "a page or more" was the iOS resize, and Android's guess is much better than that.

So: worth doing for iOS, and for having one answer to this instead of three. Not worth doing for Android's rendering. If it lands, droid would adopt it to drop loadWithOverviewMode and to get page-box fitting — not because anything is broken.

Environment

odrcore 6.10.0 (app.opendocument:odr-core-android from maven central), OpenDocument.droid at opendocument-app/OpenDocument.droid#609. Emulators: API 36 / WebView 133.0.6943.137 and API 31 / WebView 91.0.4472.114. Documents: test/data/input/odr-public/pptx/style-various-1.pptx, odt/about.odt, xlsx/file_example_XLSX_50.xlsx.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions