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:
co-authored by
Claude Sonnet 5
parent
70b6918279
commit
2ef8d26c6f
@@ -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.
@@ -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).
|
||||
@@ -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
|
||||
|
||||
@@ -522,3 +522,38 @@ int ttf_glyph_outline(const ttf_font_t *font, uint32_t glyph_index, ttf_outline_
|
||||
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__ */
|
||||
Reference in New Issue
Block a user