denise-text
Fonts, a bounded glyph cache, line layout and word wrapping for Denise, a direct-rendering UI toolkit in Rust for embedded Linux and systems without a desktop environment.
One TextEngine holds every font an application uses and one GlyphAtlas that
caches what has been rasterised. Measurement and drawing both go through it, so a
label measured during layout and drawn a moment later rasterises its glyphs
exactly once.
use ;
use Pen;
use ;
#
Three tiers, and what each costs
Measured as the increase in a stripped, statically linked
aarch64-unknown-linux-musl binary:
| Tier | Feature | Cost | What it buys |
|---|---|---|---|
| Built-in bitmap | none | 0 | Latin plus æøå, whole-number scales |
| TrueType | truetype |
+270 KB | Real fonts, proportional metrics, anti-aliasing |
| Baked | none; bake in a build script |
the tables | A real face at the sizes it was baked at, no parser on the panel |
| Shaped | shaping |
+3.1 MB | Ligatures, bidi, complex scripts, font fallback |
A style that names no font carries FontId::DEFAULT, which is a redirection
rather than a face. TextEngine::set_default_font points it at a registered
source, and everything drawn from an unnamed style follows — so an application
registers a face and says one more line, rather than threading a TextStyle
through every widget it builds.
FontId::DEFAULT is the built-in bitmap until something says otherwise, which is
what a board with no fonts installed gets and why the bitmap face is always
registered first.
For scale: the whole of Denise, DRM, evdev and the widgets is about 840 KB, so the shaping tier is four times the rest of the toolkit put together. It is there because some panels genuinely need it, and off by default because most do not — a temperature readout and a Norwegian name do not need a shaper.
Wrapping
Greedy, returning slices that borrow the input, and explicit \n always breaks. A
word wider than the line overflows on a line of its own rather than being cut
between characters: breaking mid-word means knowing where a grapheme ends, and half
of an æ is nothing.
Where this sits
Depends on denise and
denise-render.
denise-ui re-exports TextStyle and passes
the tier features through, so an application picks its text tier once.
#![forbid(unsafe_code)].
Status
M5 complete, M6 in progress. The glyph cache is benchmarked in CI. Part of Denise — see the repository README and docs/design.md for the whole picture.
MIT licensed.