capsules/fonts: JetBrainsMono-Regular.ttf as a raw-blob capsule (item 4.3.7b)

mkcapsule.c already ingests arbitrary non-.4th files as raw byte blobs
(validate_forth_blocks only applies to .4th filenames), so no hex/base64
text-encoding or tool changes are needed -- corrects the design premise
in FABRIC.md's 4.3.7b item text (see the FABRIC.md correction note this
commit carries). ttf_load_from_capsule() resolves the font capsule by
name, validates its content hash, and points ttf_font_t at the capsule
arena bytes directly, zero-copy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-10 21:50:35 -04:00
co-authored by Claude Sonnet 5
parent 70b6918279
commit 2ef8d26c6f
5 changed files with 139 additions and 2 deletions
+46 -1
View File
@@ -4753,10 +4753,31 @@ document and committing that amendment as its own item.*
> kernel-boot change yet" posture as 4.3.7 — no FORTH/capsule wiring exists for this module,
> so no three-arch QEMU acceptance applies here either.
- [ ] **4.3.7b — Font data ingestion.** `.ttf` bytes encoded (hex or base64 — pick one, record
- [x] **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.
> **Done 2026-08-10, on the corrected design (§27.7's 2026-08-10 correction, not the
> hex/base64 premise this item's own text was written against — see that note for the
> full story of why).** `capsules/fonts/JetBrainsMono-Regular.ttf` added; `mkcapsule.c`
> ingests it unmodified as capsule `fonts:JetBrainsMono-Regular.ttf` (raw bytes, no text
> encoding, no tool changes needed — it already handles arbitrary files). Verified two ways:
> `mkcapsule --lint capsules/` passes clean (29 `.4th` files, 0 violations — the `.ttf`
> isn't `.4th` so lint correctly skips it rather than misapplying text-block rules to it);
> and a byte-exact round-trip check — built `capsule_generated.c`, extracted the
> `capsule_arena[]` bytes at the font's descriptor `offset`/`length` (270224 bytes) back out
> with a throwaway script, `cmp`'d against the source `.ttf`: identical.
>
> No `kmalloc` copy, since none is needed: `ttf_load_from_capsule()` (new, in `ttf.c`/`ttf.h`,
> `#ifdef __STARKERNEL__`-gated) resolves the capsule via `capsule_find_by_name()`, validates
> its content hash via `capsule_validate(..., verify_hash=1)`, and points `ttf_font_t` at the
> `capsule_arena` bytes directly (`capsule_get_payload()`) — zero-copy, since the arena is
> already a `const` array baked into the kernel image and `ttf_parse()` only ever reads
> through a `const uint8_t*`. Compiles clean (`-Wall -Werror -Wextra`) both with and without
> `-D__STARKERNEL__`, against the real amd64 `Makefile.starkernel` flags including
> `-include include/starforth_config.h -DPARITY_MODE=0`. Not callable from FORTH yet — no
> capsule-birth/init.4th wiring exists for it; that's 4.3.7e's job once `TTF-TEXT` needs it.
> Same "not a kernel-boot change" posture as 4.3.7/4.3.7a; no three-arch QEMU run applies.
- [ ] **4.3.7c — Rasterization.** Bézier curve flattening to line segments (reusing the
existing `LINE`/Bresenham primitive where practical), then fill. Antialiasing approach is
@@ -5561,4 +5582,28 @@ font (not chosen yet — needs a licensing check before any specific font is emb
SIL OFL 1.1 (permissive, embedding/redistribution allowed) — resolves the licensing-check
blocker above.
**Correction 2026-08-10, superseding both the paragraph above and decision #3:** the
"open question" recorded above was wrong — a grep-shallow check (`grep -n "blob\|binary"`)
missed the actual mechanism. A full read of `tools/mkcapsule.c` shows raw-binary-blob
ingestion already exists, end to end, and decision #3's hex/base64-encoding premise is
unnecessary:
- `process_file()` reads *any* regular file under `capsules/` (recursively, via `nftw`) into
a `CapsuleEntry` as raw bytes. `validate_forth_blocks()` — the 64-char/16-line text check —
only runs when the filename ends in `.4th`; every other file is accepted as-is, unvalidated
and unmodified.
- `generate_output()`'s payload-arena emission (`const uint8_t capsule_arena[] = { 0x%02X, ...
}`) is a plain byte array, not a string literal — binary-safe, no NUL-termination
assumption, already exercises correctly on non-text content.
- Kernel-side, `capsule_find_by_name()` (`include/starkernel/capsule.h`) returns a
`CapsuleDesc*` (`offset`/`length` into the arena) independent of `capsule_exec_payload()`
(`capsule_loader.h`) — lookup and FORTH execution are already separate calls. A caller can
fetch a capsule's raw bytes by name and simply never call `capsule_exec_payload()` on it.
So: drop `.ttf` bytes into `capsules/` as-is (e.g. `capsules/fonts/JetBrainsMono-Regular.ttf`
→ capsule name `fonts:JetBrainsMono-Regular.ttf`), fetch via `capsule_find_by_name()`, done —
no hex/base64 text-encoding, no `mkcapsule.c` changes, no parallel asset mechanism. Decision
#3 is superseded by this. 4.3.7b's remaining work is just wiring a `kmalloc` copy (or
direct-arena reference — 4.3.7b's own call) behind that lookup.
*Refs:* §25.5 (punch list), GAP-B2.
Binary file not shown.
+30
View File
@@ -0,0 +1,30 @@
# capsules/fonts/
Font capsule for FABRIC.md items 4.3.7/4.3.7b (TrueType rendering, adjunct
to the stroke font — §27.7).
| File | License | Provenance |
|------|---------|------------|
| `JetBrainsMono-Regular.ttf` | SIL Open Font License, Version 1.1 | The JetBrains Mono Project Authors, copyright 2020 (https://github.com/JetBrains/JetBrainsMono). License string confirmed by reading the font's own embedded `name` table directly (`strings -e b JetBrainsMono-Regular.ttf`) — not taken on trust from the filename. |
Chosen as the v1 test/default TTF font 2026-08-10 (FABRIC.md §27.7 "Update
2026-08-10"), resolving that item's licensing-check blocker.
**Embedded as a raw-binary capsule, not text-encoded.** `tools/mkcapsule.c`'s
`process_file()` reads any regular file under `capsules/` as raw bytes and
only runs the 64-char/16-line `.4th` text-block validation
(`validate_forth_blocks()`) when the filename ends in `.4th` — everything
else, including this `.ttf`, is stored byte-for-byte in the generated
`capsule_arena[]` and content-hashed (xxHash64) exactly like every other
capsule. Capsule name: `fonts:JetBrainsMono-Regular.ttf` (colon-separated
relative path, per `build_capsule_name()`). Fetch it with
`capsule_find_by_name()` (`include/starkernel/capsule.h`) — that returns
`offset`/`length` into the arena without ever routing through
`capsule_exec_payload()`, so nothing tries to interpret the font bytes as
FORTH source. This superseded FABRIC.md §27.7 decision #3 (hex/base64
text-encoding) — see that section's 2026-08-10 correction note.
No SIL OFL 1.1 full license text is bundled here yet — only the font's own
embedded attribution string. Add the full `OFL.txt` alongside this file if/
when redistribution requirements are checked in detail (OFL requires the
license text to accompany the font).
+27
View File
@@ -182,6 +182,33 @@ typedef struct {
*/
int ttf_glyph_outline(const ttf_font_t *font, uint32_t glyph_index, ttf_outline_t *out);
#ifdef __STARKERNEL__
#include "capsule.h"
/**
* ttf_load_from_capsule - Resolve a font capsule by name and parse it,
* zero-copy (FABRIC.md item 4.3.7b). `out` borrows the capsule payload
* directly from `arena` — no kmalloc, no decode step, since the capsule
* is already a raw-byte match of the source `.ttf` (see
* capsules/fonts/README.md and FABRIC.md §27.7's 2026-08-10 correction:
* capsule storage needs no hex/base64 text-encoding, `tools/mkcapsule.c`
* already embeds arbitrary files as raw bytes). Validates the capsule's
* content hash (`capsule_validate(..., verify_hash=1)`) before parsing.
*
* @param capsule_name Colon-separated capsule name, e.g.
* "fonts:JetBrainsMono-Regular.ttf"
* @return TTF_OK, TTF_ERR_TABLE_MISSING if the capsule isn't found, or a
* capsule-validation/ttf_parse TTF_ERR_* code
*/
int ttf_load_from_capsule(
const CapsuleDirHeader *dir,
const CapsuleDesc *descs,
const CapsuleNameEntry *names,
const uint8_t *arena,
const char *capsule_name,
ttf_font_t *out);
#endif /* __STARKERNEL__ */
#ifdef __cplusplus
}
#endif
+36 -1
View File
@@ -521,4 +521,39 @@ int ttf_glyph_outline(const ttf_font_t *font, uint32_t glyph_index, ttf_outline_
out->point_count = 0;
out->contour_count = 0;
return decode_glyph_r(font, glyph_index, out, 0);
}
}
/* ===========================================================================
* 4.3.7b — font data ingestion (capsule-backed, zero-copy)
* ===========================================================================
*/
#ifdef __STARKERNEL__
int ttf_load_from_capsule(
const CapsuleDirHeader *dir,
const CapsuleDesc *descs,
const CapsuleNameEntry *names,
const uint8_t *arena,
const char *capsule_name,
ttf_font_t *out) {
const CapsuleDesc *cap;
const uint8_t *payload;
CapsuleValidateResult vr;
if (!dir || !descs || !names || !arena || !capsule_name || !out)
return TTF_ERR_BAD_TABLE;
cap = capsule_find_by_name(dir, descs, names, capsule_name);
if (!cap) return TTF_ERR_TABLE_MISSING;
vr = capsule_validate(cap, arena, dir->arena_size, 1);
if (vr != CAPSULE_VALID) return TTF_ERR_BAD_TABLE;
payload = capsule_get_payload(cap, arena);
if (!payload) return TTF_ERR_BAD_TABLE;
return ttf_parse(payload, (uint32_t) cap->length, out);
}
#endif /* __STARKERNEL__ */