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,
|
> 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.
|
> 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`
|
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`),
|
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.
|
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
|
- [ ] **4.3.7c — Rasterization.** Bézier curve flattening to line segments (reusing the
|
||||||
existing `LINE`/Bresenham primitive where practical), then fill. Antialiasing approach is
|
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
|
SIL OFL 1.1 (permissive, embedding/redistribution allowed) — resolves the licensing-check
|
||||||
blocker above.
|
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.
|
*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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -521,4 +521,39 @@ int ttf_glyph_outline(const ttf_font_t *font, uint32_t glyph_index, ttf_outline_
|
|||||||
out->point_count = 0;
|
out->point_count = 0;
|
||||||
out->contour_count = 0;
|
out->contour_count = 0;
|
||||||
return decode_glyph_r(font, glyph_index, out, 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