FABRIC.md: scope TrueType rendering as adjunct to stroke font (4.3.7)

Not implementation -- documentation-only. Reviewing the 4.3.6 stroke
font's full 113-glyph repertoire (mid-4.3.6g checkpoint) prompted the
decision to add TrueType rendering as an adjunct path rather than
continue refining strokes alone. Stroke font stays; nothing reverted.

Adds 4.3.7-4.3.7f (parser core, outline extraction, font data
ingestion, rasterization, glyph cache, TTF-TEXT entry point,
three-arch checkpoint) plus §27.7 documenting four resolved design
decisions: C implementation layer, Q48.16 fixed-point (not float --
confirmed real via Makefile.starkernel grep that GAP-B2's hypothesized
FP-register-clobber-on-interrupt risk is real on all three
architectures, not just hypothetical), capsule-block-encoded font
data, and TrueType as the primary text path once built.

4.3.6g itself stays open -- paused mid-verification when a real
cross-arch framebuffer-resolution difference (aarch64 800x600 ramfb
vs amd64 1280x800 GOP) surfaced; not yet re-run with corrected
coordinates.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-09 21:10:23 -04:00
co-authored by Claude Sonnet 5
parent 2960989100
commit 28731b8536
+106
View File
@@ -4641,6 +4641,62 @@ document and committing that amendment as its own item.*
correctly positioned, on all three architectures, matching the 4.3.3b/4.3.4 completion
pattern (screendump-verified, not just non-crashing). Three-arch acceptance boot clean,
logs committed. *Refs:* §27.6.
> **Paused 2026-08-09, mid-verification.** amd64's 113-glyph grid screendump (1280×800 GOP
> framebuffer) looked correct. Re-running the same grid on aarch64 surfaced a real,
> previously-unaccounted-for cross-arch difference: aarch64 boots with an 800×600 `ramfb`
> device, not amd64's 1280×800 linear GOP framebuffer — the grid's Y coordinates (laid out
> for 800px height) ran off the top of the smaller screen. Not yet re-run with corrected,
> screen-size-aware coordinates on any architecture. This checkbox stays open.
>
> The review this checkpoint exists for happened here, ahead of schedule: seeing the
> stroke-rendered repertoire together prompted the decision to add TrueType rendering as
> an adjunct rather than continue refining the stroke system alone — see 4.3.7 below. The
> stroke font itself is being kept, not reverted; this item still needs to finish (grid
> fixed, all three arches, screendump-verified) before REPL wiring (M8) is scoped, per its
> own "Done when."
- [ ] **4.3.7 — TTF parser core.** A C module (not FORTH — parsing and rasterization are
impractical to interpret) reading a `.ttf`'s `sfnt` directory plus `head`/`maxp`/`loca`/
`glyf`/`cmap` tables, resolving a codepoint to a glyph index and its outline data. All
scaled/derived values in Q48.16, not float — see §27.7. *Done when:* given an embedded test
font's bytes in memory, the parser resolves at least one ASCII codepoint to the correct
`glyf` table offset and reads its outline header (contour count, bounding box), verified
against values independently read from the same font with a reference tool (e.g.
`fonttools`/`ttx`), not just "doesn't crash." *Refs:* §27.7.
- [ ] **4.3.7a — Glyph outline extraction.** Simple and composite glyph outlines from `glyf`
— on-curve/off-curve point lists, quadratic Bézier control points, composite glyph
transforms — in Q48.16. *Done when:* outline point lists for a handful of test glyphs
(including at least one composite, e.g. an accented character if the test font has one)
match reference-tool output within Q48.16 rounding tolerance. *Refs:* §27.7.
- [ ] **4.3.7b — Font data ingestion.** `.ttf` bytes encoded (hex or base64 — pick one, record
why) into capsule blocks per the resolved design decision (§27.7), decoded into a `kmalloc`
buffer at capsule load time. *Done when:* a font capsule loads cleanly (`mkcapsule --lint`),
and the decoded in-memory bytes checksum-match the original `.ttf` file. *Refs:* §27.7.
- [ ] **4.3.7c — Rasterization.** Bézier curve flattening to line segments (reusing the
existing `LINE`/Bresenham primitive where practical), then fill. Antialiasing approach is
an open question — not decided here, resolve when this item is picked up. *Done when:* a
single glyph outline rasterizes to a recognizable filled (or outlined, if AA is deferred)
shape on the CANVAS, screendump-verified. *Refs:* §27.7.
- [ ] **4.3.7d — Glyph raster cache.** Rasterizing on every draw call is too slow for
repeated text; cache rasterized bitmaps keyed by (font, codepoint, size). *Done when:*
drawing the same codepoint/size twice measurably hits the cache on the second call (e.g. a
counter or timing difference), verified live, not just "code that should cache." *Refs:*
§27.7.
- [ ] **4.3.7e — `TTF-TEXT` entry point.** `TTF-TEXT ( c-addr u x y size color -- )`,
analogous to 4.3.6f's `TEXT` but TrueType-backed — becomes the primary text-rendering path
per the resolved relationship to the stroke font (§27.7); `TEXT`/the stroke system remain
available, not deprecated. *Done when:* a UTF-8 string renders correctly via `TTF-TEXT` in
one call, screendump-verified, proportional spacing correct. *Refs:* §27.7.
- [ ] **4.3.7f — Checkpoint: TTF rendering, all three architectures.** Same posture as
4.3.6g. *Done when:* a single screendump per architecture shows a representative sample
string rendered correctly via `TTF-TEXT`, three-arch acceptance boot clean, logs committed.
*Refs:* §27.7.
⋯ *(4.3.x is open-ended — more items get appended here as Console work is scoped item by*
*item, developed on the fly per §25.0. 4.4 below is unaffected by anything added above*
@@ -5369,3 +5425,53 @@ exhausted. Presented at the algorithm level, same caveat as `DECODE-UTF8` — th
construction is 4.3.6f's own implementation work, not settled here.
*Refs:* §25.5 (punch list).
### 27.7 TrueType rendering, adjunct to the stroke font (4.3.74.3.7f)
Scoped 2026-08-09, immediately after the 4.3.6g checkpoint review (which surfaced this
decision ahead of that item finishing — see 4.3.6g's paused note). **Adjunct, not a
replacement:** the stroke-drawn font system (4.3.64.3.6g) stays; nothing from it is being
reverted or deprecated by this work.
**Four design decisions resolved 2026-08-09, before any implementation:**
1. **Implementation layer: C, not FORTH.** TTF parsing (table lookups, glyph index
resolution) and rasterization (Bézier flattening, scanline fill) are impractical to write
as interpreted FORTH — same reasoning that put `LINE`/`CIRCLE`/`ARC`/`ELLIPSE` (4.3.3b) in
C rather than FORTH. A new C module, parallel to those, exposes a handful of new words to
FORTH.
2. **Q48.16 fixed-point throughout, not float.** Checked before deciding, not assumed.
**GAP-B2** (this doc, §"unverified prerequisites") already flagged the *question*
"if the kernel is not built with `-mgeneral-regs-only` (aarch64) / soft-float (riscv64),
a C interrupt handler may clobber FP registers" — as unverified, one grep away from
settled. That grep was run while scoping this item: `Makefile.starkernel`'s
`ARCH_CFLAGS` show amd64/aarch64 with no explicit FPU disable and riscv64 built `lp64d`
(a hard-float ABI, not soft-float) — so hardware FP is implicitly available on all three,
and GAP-B2's hypothesized risk is real, not hypothetical: none of the three
architectures' ISR paths save/restore FP register state. This resolves GAP-B2's open
question (confirmed real) but does not fix the underlying gap itself, which stays open
for whatever eventually does need hardware FP. There is no documented project-wide
"no float" policy — this is a targeted decision for this item. Building the rasterizer in
Q48.16 sidesteps the risk for this work specifically (it never touches FP hardware), and
incidentally keeps it consistent with the determinism convention the rest of the runtime
(Compudynamics, the geometry primitives) already uses Q48.16 for.
3. **Font data storage: encoded into capsule blocks.** A `.ttf` is binary; capsule blocks are
text (64 chars/line, 16 lines/block, per `tools/mkcapsule.c`'s `validate_forth_blocks()`).
Chose hex/base64 encode-at-build/decode-at-load over a parallel build-time embedded-binary
asset (like `capsule_generated.c` bakes in capsule text) specifically to keep font data
inside the existing content-addressed capsule system rather than introduce a second,
parallel asset-embedding mechanism. Hex vs. base64 not yet chosen — 4.3.7b's own call.
4. **Relationship to the stroke font: TrueType becomes the primary text path.** Once
`TTF-TEXT` (4.3.7e) exists, it's the intended path for real text rendering; `TEXT`/the
stroke system (4.3.6f) remain available and are not deprecated — useful for early boot
(before the capsule/VM bootstrap, same reason `font_8x16.c` stays per §27.6), low-memory
contexts, or diagnostic/geometric use. Both continue to exist; callers choose.
**Explicitly not decided here, left to the item that owns them:** antialiasing approach
(4.3.7c), hex vs. base64 encoding (4.3.7b), which `.ttf` file serves as the v1 test/default
font (not chosen yet — needs a licensing check before any specific font is embedded).
*Refs:* §25.5 (punch list), GAP-B2.