iris: drop bundled Noto Sans, match Compose's platform-font fonts
Iris's call: "remove the font for now; just match what compose does." Removes the six embedded Noto Sans/Noto Sans Mono TTFs (3.6 MB) that TextData::default used to register ahead of the platform's own fonts; fontique's system font discovery was already on by default and now runs unshadowed (Roboto/Roboto Flex on Android, fontconfig on the desktop). .so -3,748,136 bytes (11,193,608 -> 7,445,472), matching the estimate. Verified fallback still lands on visible tofu for CJK/emoji rather than blank, and flagged (not fixed) a fontique Android backend gap that leaves Monospace unresolved -- see RUST.md's "Platform fonts (2026-09-07)" and DECISIONS.md/IRIS.md's dated entries.
This commit is contained in:
1 parent
690161e5e9
commit
896c93a59a
12 files changed
+193
-312
No files matched your search
@@ -5,6 +5,40 @@ they can be judged and reversed later. Detail lives in RUST.md (and IRIS.md
|
||||
for iris API changes); this file is only the summary. Newest first. Items
|
||||
marked **DEFERRED** are ones the agent chose not to decide alone.
|
||||
|
||||
## 2026-09-07 (platform fonts, not bundled ones)
|
||||
|
||||
- **Iris's own decision, carried out as directed**: removed the 3.6 MB of
|
||||
bundled Noto Sans/Noto Sans Mono TTFs from `iris-core` and load text
|
||||
from the platform's own font collection instead (`fontique`'s system
|
||||
discovery, already on by default). Matches what the Compose app does --
|
||||
it takes body text from `FontFamily.Default` and code text from
|
||||
`FontFamily.Monospace`, both platform-resolved, and ships no text font
|
||||
of its own. Rejected alternative (the one this pass had left open
|
||||
2026-09-06): subsetting the bundled Noto Sans to Latin/common
|
||||
punctuation instead of removing it outright, which would have kept
|
||||
identical rendering across devices for a smaller (not zero) size cost;
|
||||
Iris chose to match Compose instead.
|
||||
- `.so` **-3,748,136 bytes** (11,193,608 -> 7,445,472), matching the
|
||||
original 3.6 MB estimate. Fallback still lands on the platform's own
|
||||
tofu for a codepoint no resolved face has (checked with CJK + emoji on
|
||||
desktop) rather than blank space, so the UI_RULES unknown-glyph rule
|
||||
still holds.
|
||||
- **Flagging for Iris, not blocking on it**: this fontique version's
|
||||
Android backend never resolves the `Monospace` generic family at all
|
||||
(confirmed on this checkout's emulator, `mono=None` in the startup
|
||||
diagnostic) -- a pre-existing ordering bug in fontique's own
|
||||
`fonts.xml` parsing, not something this change introduced, but this
|
||||
change is what stopped masking it (the bundled mono font used to be
|
||||
registered ahead of the broken platform lookup, so it always won).
|
||||
Effect: code blocks and the tool-card chevron marks fall through to
|
||||
the same face as body text on Android instead of a genuinely
|
||||
monospaced one -- still visible, not blank, just not monospaced.
|
||||
Compose does not share this gap; it resolves `FontFamily.Monospace`
|
||||
through Android's own `Typeface.MONOSPACE`, not through fontique.
|
||||
docs/RUST.md's "Platform fonts (2026-09-07)" has the full account and
|
||||
why a fix (an OEM-specific named-family pin, or patching around
|
||||
fontique) is left as a follow-up rather than done in this pass.
|
||||
|
||||
## 2026-09-06 (how a tool call looks, P1b)
|
||||
|
||||
- **A card that never got a result says "no result", in yellow, and it is
|
||||
|
||||
@@ -8,6 +8,27 @@ capability that moved. Small and trivial changes do not go here.
|
||||
An entry gives the date, what changed, why, and a short before/after where
|
||||
it helps judge the change without the session that made it. Newest first.
|
||||
|
||||
## 2026-09-07: `TextData` no longer bundles a font
|
||||
|
||||
Iris's call: "remove the font for now; just match what compose does."
|
||||
`TextData::default()` used to embed six Noto Sans/Noto Sans Mono `.ttf`s
|
||||
(3.6 MB, `include_bytes!`) and register them ahead of the platform's own
|
||||
fonts in the `SansSerif`/`Monospace` fallback lists. That registration is
|
||||
gone; `TextData::default()`'s signature is unchanged, but what it produces
|
||||
now depends entirely on `fontique`'s platform discovery (already on by
|
||||
default, previously shadowed) -- Roboto/Roboto Flex on Android, whatever
|
||||
the desktop's fontconfig resolves on Linux. No caller-visible type or
|
||||
method changed, but every consumer of `iris-core` text now renders with
|
||||
whatever the host platform's fonts are, not a fixed bundled face -- worth
|
||||
knowing if you were relying on pixel-identical text across devices.
|
||||
`.so` shrank by 3.75 MB. One real gap surfaced by the switch: this
|
||||
fontique version's Android backend never resolves the `Monospace`
|
||||
generic family (a fontique ordering bug, not new in this change), so
|
||||
`Family::Monospace` text falls through to the same face as
|
||||
`SansSerif` on Android rather than a true monospaced one -- still
|
||||
visible, not blank, just not monospaced. docs/RUST.md's "Platform fonts
|
||||
(2026-09-07)" has the full account.
|
||||
|
||||
## 2026-09-07: a headless harness, replayed touch, and physical-pixel desktop layout
|
||||
|
||||
Layer 1 and 2 of docs/RUST.md's "Three test layers".
|
||||
|
||||
+110
-9
@@ -110,6 +110,7 @@ override, reusing the incremental `target/`), and are the raw file sizes
|
||||
| + `codegen-units = 1` | 15,185,204 | 13,052,736 | -566,008 |
|
||||
| + `opt-level = "s"` | 13,326,076 | 11,193,608 | -1,859,128 |
|
||||
| + `opt-level = "z"` (not adopted, see below) | 12,507,276 | 10,374,808 | -818,800 |
|
||||
| + platform fonts, no bundled Noto (2026-09-07) | 9,577,940 | 7,445,472 | -3,748,136 |
|
||||
|
||||
Adopted: `strip = true`, `lto = "fat"`, `codegen-units = 1`, `opt-level = "s"`.
|
||||
Baseline to final: `libmain.so` **18,546,488 -> 11,193,608 bytes (-39.7%)**,
|
||||
@@ -181,7 +182,99 @@ rather than a fixed-codepoint one -- a real behaviour change (text in a
|
||||
language outside the subset would fall back to tofu or a missing glyph) and
|
||||
out of scope for a size-only pass. Left as a follow-up, flagged for Iris:
|
||||
subsetting would plausibly save 1-2 MB but changes what scripts render
|
||||
correctly, which is a product decision.
|
||||
correctly, which is a product decision. **Superseded 2026-09-07**: Iris
|
||||
decided to remove the embedding outright rather than subset it -- see
|
||||
"Platform fonts (2026-09-07)" below.
|
||||
|
||||
### Platform fonts (2026-09-07)
|
||||
|
||||
Iris's verdict on the open question above: **"remove the font for now;
|
||||
just match what compose does."** The Compose app takes its body text from
|
||||
`FontFamily.Default` (platform Roboto on Android) and its code/tool-output
|
||||
text from `FontFamily.Monospace`, and ships no text font of its own --
|
||||
only its committed Nerd Fonts icon subset (`app/build-icon-font.sh`) for
|
||||
~100 fixed glyphs, a different case (a small, known, closed set of
|
||||
codepoints, unlike arbitrary transcript text). iris had no equivalent icon
|
||||
font to keep; it draws no icons through a font today, so there was nothing
|
||||
parallel to preserve.
|
||||
|
||||
**What changed**: `TextData::register_bundled_fonts` and the six
|
||||
`include_bytes!` Noto Sans/Noto Sans Mono constants are gone from
|
||||
`iris/core/src/primitive/text.rs`, along with the `.ttf`s themselves and
|
||||
their `OFL.txt` (`iris/core/assets/fonts/`, now removed -- nothing else in
|
||||
the tree referenced the licence file). `TextData::default` now does
|
||||
nothing but `FontContext::new()`, which was already discovering the
|
||||
platform's fonts underneath the bundled ones -- `fontique` 0.11.1's
|
||||
`CollectionOptions::system_fonts` defaults to `true`, and both platforms
|
||||
this crate ships on have a real backend behind it: `backend/fontconfig.rs`
|
||||
on Linux (this VM's desktop has a full Noto install, confirmed with
|
||||
`fc-match sans-serif`/`fc-match monospace`), `backend/android.rs` on
|
||||
Android (parses `/system/fonts` and `/system/etc/fonts.xml`, mapping
|
||||
`SansSerif`/`SystemUi` to `["Roboto Flex", "Roboto", "Noto Sans"]` and
|
||||
`Monospace` to `["monospace"]` -- see the fallback finding below for why
|
||||
that last one does not actually resolve on this fontique version). So
|
||||
removing the bundled registration did not need a replacement call; the
|
||||
platform path was already live, just shadowed.
|
||||
|
||||
**Fallback, and the unknown-glyph state (UI_RULES: design it, don't let
|
||||
it default to blank)**. `parley`'s shaper sets both an explicit family
|
||||
list *and* a script/locale-keyed fallback chain per run
|
||||
(`parley-0.11.1/src/shape/mod.rs`'s `query.set_families`/
|
||||
`query.set_fallbacks`), so a codepoint the resolved family lacks still
|
||||
gets a query against fontique's fallback map before giving up. Checked
|
||||
with a throwaway example (`iris/examples/font_check.rs`, deleted after
|
||||
use -- not part of the crate) shaping `"🎉🔥▸▾▲你好"` headless on the
|
||||
desktop at `run-headless.sh`: the emoji and CJK characters drew as
|
||||
visible **tofu boxes** (the platform's own missing-glyph box, not blank
|
||||
space), and the chevron marks (U+25B8/25BE/25B4, the ones
|
||||
`transcript-ui/src/tool.rs`'s `CLOSED_MARK`/`OPEN_MARK`/`UP_MARK` draw)
|
||||
shaped as real triangles. So the failure mode this crate now depends on
|
||||
is "the platform's own tofu," which is the correct unknown-glyph state
|
||||
per UI_RULES, not "nothing drawn." `tool.rs`'s doc comment on those marks
|
||||
is updated to say this is now a bet on the platform's coverage rather
|
||||
than a checked fact about a bundled `cmap`.
|
||||
|
||||
**One real gap, found on this checkout's emulator, not the desktop**:
|
||||
`fonts: 208 families found, default=Some("Roboto Flex") mono=None` in the
|
||||
startup log (`FontDiagnostics`, read via `adb logcat` after installing the
|
||||
`force-gles` debug build -- the emulator's default Vulkan backend has no
|
||||
adapter here, a pre-existing, documented condition unrelated to this
|
||||
change, and aborts with `Could not get adapter!` without that feature).
|
||||
`mono=None` means fontique's Android backend never resolves the
|
||||
`Monospace` generic family at all on this system image: reading
|
||||
`fontique-0.11.1/src/backend/android.rs`, `DEFAULT_GENERIC_FAMILIES`'s
|
||||
`["monospace"]` is looked up against `name_map` *before* the `fonts.xml`
|
||||
parse that would register a family literally named `"monospace"` runs --
|
||||
so even though this AVD's `/system/etc/fonts.xml` does declare
|
||||
`<family name="monospace"><font ...>DroidSansMono.ttf</font></family>`,
|
||||
fontique's own ordering means that declaration is registered too late to
|
||||
be found by the generic-family lookup, on every Android device this
|
||||
fontique version runs on, not just this AVD. The visible effect is not
|
||||
blank text -- `Family::Monospace`'s explicit-family list comes up empty,
|
||||
but the script-based fallback chain (independent of the generic-family
|
||||
list) still resolves a real font, the same one `SansSerif` gets -- so
|
||||
code blocks and the tool-card chevrons render, just without a genuinely
|
||||
monospaced face. Compose does not have this gap: `FontFamily.Monospace`
|
||||
resolves through Android's own `Typeface.MONOSPACE` constant, a different
|
||||
and unconditionally-populated path that fontique does not use. Left as a
|
||||
follow-up rather than fixed here, since a fix means either patching
|
||||
around fontique's Android backend or pinning `Family::Named("Droid Sans
|
||||
Mono")` (fragile: an OEM-specific font name, not guaranteed across real
|
||||
devices) -- out of the scope Iris gave this pass ("remove the font,
|
||||
match Compose"), and a real product-visible difference worth her knowing
|
||||
about rather than silently living with.
|
||||
|
||||
**Verified**: `cargo test -p transcript-fixture` (6 tests, all headless
|
||||
layers) and `cargo clippy -p iris-core --all-targets` both clean;
|
||||
`./run-headless.sh phone --phone --shot` (the bench-fixture transcript,
|
||||
bold/italic/monospace code fences all shaping correctly) and
|
||||
`./run-headless.sh tabs` (the desktop example with several distinct text
|
||||
styles, per this task's "negative case" check) both look right by eye;
|
||||
the emulator's own bench run (`run-bench.sh`, `force-gles` debug build)
|
||||
completed a full fling/stream/type/keyboard cycle with text visibly
|
||||
drawn throughout and no crash. `.so` size: see the APK size table's final
|
||||
row, **11,193,608 -> 7,445,472 bytes**, a 3,748,136-byte drop matching
|
||||
the 3.6 MB estimate almost exactly.
|
||||
|
||||
**naga/wgpu backend features: investigated, not trimmed, because the
|
||||
trim would not change the binary.** `iris/core/Cargo.toml` and
|
||||
@@ -279,14 +372,22 @@ closes it.
|
||||
recent log; a debug button copies it; Dev Updater reads it), write
|
||||
the decision in docs/DECISIONS.md, build it.
|
||||
- [x] APK size: release profile tuned (`42af780`), -35% APK, -40% .so;
|
||||
see "APK size (2026-09-07)". **Open question for Iris**: 3.6 MB of the
|
||||
remaining 11.2 MB .so is six embedded Noto Sans TTFs
|
||||
(`iris/core/src/primitive/text.rs`). Loading the platform's own fonts
|
||||
instead (fontique's system collection: Roboto/Noto on Android, the
|
||||
desktop's own on Linux) removes them and makes text match what the
|
||||
rest of her phone shows (UI_RULES "show what the reader already sees
|
||||
elsewhere"), at the cost of the app no longer looking identical on
|
||||
every device. Not done without her verdict.
|
||||
see "APK size (2026-09-07)". **Iris's verdict, 2026-09-07: "remove the
|
||||
font for now; just match what compose does."** Done same day -- the six
|
||||
bundled Noto Sans TTFs are gone, text now loads from
|
||||
`fontique`'s platform collection (`FontContext::new()`'s default
|
||||
`CollectionOptions::system_fonts`), and `.so` dropped by 3,748,136 bytes
|
||||
(11,193,608 -> 7,445,472), matching the 3.6 MB estimate almost exactly.
|
||||
See "APK size" table's final row and "Platform fonts (2026-09-07)"
|
||||
below for the fallback behaviour and one real gap it surfaced: this
|
||||
fontique version's Android backend never resolves the `Monospace`
|
||||
generic family at all (`mono=None` in the startup diagnostic, measured
|
||||
on this checkout's emulator) -- code/tool-card text still renders (the
|
||||
script fallback chain still lands on a real face, never blank), just
|
||||
not in a genuinely monospaced one. Compose does not have this gap; it
|
||||
resolves `FontFamily.Monospace` through Android's own Typeface
|
||||
constant rather than through fontique. Flagged as a follow-up, not
|
||||
fixed here -- out of the scope Iris gave.
|
||||
- [ ] Scroll clamped at both ends, and Compose's impulse velocity
|
||||
estimator with min/max fling velocity (docs/IRIS_TODO.md, 2026-09-07
|
||||
later). After the culling fix lands (same file).
|
||||
|
||||
Reference in new issue
Block a user