From 64c20c78ebe9c5a23f88e01acface66009eaae5b Mon Sep 17 00:00:00 2001 From: Robert Allan James Date: Tue, 11 Aug 2026 19:39:54 -0400 Subject: [PATCH] FABRIC.md: item 4.4i -- glyph-draw call-site audit, not cleanly separable Investigation only, no code change. draw_cursor_glyph() itself is single-call-site as claimed, but found two things the item's original framing missed: 1. A second, independent fb_draw_glyph() call site in erase_line_range() (partial-line/partial-screen erase), inconsistent with full-screen erase which already uses a pixel fb_fill_rect(). 2. fb_cell_w()/fb_cell_h() are hardcoded 8*scale/16*scale literals matching font_8x16.c specifically, not derived from any generic font-metric abstraction; UNDERLINE_ROW hardcodes "row 14 of 16" of that same fixed grid. So 4.4j has three things to retarget/generalize, not one. Font data verified directly from JetBrainsMono-Regular.ttf's hmtx table (parsed by hand, no fontTools available): all 95 printable ASCII glyphs share one advance width (600/1000 em units) -- genuinely monospace for the glyphs in use, not just by filename. Co-Authored-By: Claude Sonnet 5 --- FABRIC.md | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/FABRIC.md b/FABRIC.md index 8ea5a1d..f27812b 100644 --- a/FABRIC.md +++ b/FABRIC.md @@ -5252,7 +5252,7 @@ document and committing that amendment as its own item.* > [evidence/amd64/qemu-screenshot-20260811-173006-4.4h-colored-prompt.png](evidence/amd64/qemu-screenshot-20260811-173006-4.4h-colored-prompt.png) > — `[Hera]` renders orange, `ok>` renders cyan, confirmed by direct visual inspection. -- [ ] **4.4i — Verify the VT100 CSI/SGR parser's glyph-draw call site is cleanly separable.** +- [x] **4.4i — Verify the VT100 CSI/SGR parser's glyph-draw call site is cleanly separable.** Verification only, no code change. `vt100.c`'s CSI/SGR state machine (escape parsing, cursor tracking, 16/256-color SGR) calls `draw_cursor_glyph()` from a single site in `put_char()` — confirm nothing else in the parser depends on `font_8x16.c`-specific assumptions. @@ -5266,6 +5266,46 @@ document and committing that amendment as its own item.* compatibility question is answered from the actual font data, in writing here. *Refs:* §27.8. + > **Done 2026-08-11 — NOT cleanly separable as originally framed; two real gaps found and + > recorded here for 4.4j to address, not silently worked around.** + > + > **1. `draw_cursor_glyph()` itself is single-call-site, as claimed** — called only from + > `put_char()` (`vt100.c:442`), which is itself called from a single site in the main + > character-dispatch loop (`vt100.c:486`). Retargeting that one call is clean. + > + > **2. But there's a second, independent `fb_draw_glyph()` call site the item's framing + > missed:** `erase_line_range()` (`vt100.c:235-241`), used by both `erase_display()` and + > `erase_line()` for partial-line/partial-screen erase, draws a blank space glyph + > (`fb_draw_glyph(px, py, 0x20, fg, bg)`) per cell rather than filling a pixel rectangle. + > Full-screen erase (`erase_display(2)`, `vt100.c:261`) uses `fb_fill_rect()` instead — pixel- + > based, no font dependency. So today's erase behavior is already inconsistent between modes, + > and 4.4j must retarget *this* call site too, not just `draw_cursor_glyph()`'s. + > + > **3. The cell-grid model itself is hardcoded to `font_8x16`'s fixed metrics, not derived + > from a generic "current font" abstraction:** `fb_cell_w()`/`fb_cell_h()` + > (`framebuffer.c:129-130`) return `8u * g_fb.scale` / `16u * g_fb.scale` literally — not + > read from font data, just baked-in constants matching `font_8x16.c`'s glyph size. `vt100.c` + > builds `g_vt.cols`/`g_vt.rows` and all cursor pixel math (`px_of()`/`py_of()`) on top of + > these. Additionally, `UNDERLINE_ROW` (`vt100.c:49`, value 14) is explicitly commented + > "row 14 of 16" — hardcodes a position within `font_8x16`'s 16-scanline glyph grid. Neither + > of these is a call-site problem exactly (nothing here calls `font_8x16.c` functions + > directly), but both are real assumptions 4.4j needs to replace, not just the two draw + > calls. + > + > **4. Font data confirmed via `hmtx` table (not assumed from the filename):** + > `JetBrainsMono-Regular.ttf` — read directly with a minimal `sfnt`/`cmap`-format-4/`hmtx` + > parser (no `fontTools` available in this environment). `unitsPerEm=1000`, + > `numberOfHMetrics=1717`. All 95 printable ASCII glyphs (`0x20`–`0x7E`) resolve via `cmap` + > and share **exactly one** advance width: `600` font units, no exceptions. Genuinely + > monospace for the glyph set actually in use, confirmed from the font's own data — at any + > single chosen point size, `TTF-TEXT` advances will tile uniformly, compatible with the + > existing fixed-cell cursor model in principle (once that model no longer hardcodes + > `font_8x16`'s specific 8×16 dimensions per point 3 above). + > + > **Net effect on 4.4j's scope:** three things to retarget/generalize, not one — + > `draw_cursor_glyph()`'s call, `erase_line_range()`'s call, and the `fb_cell_w()`/ + > `fb_cell_h()`/`UNDERLINE_ROW` metrics that currently assume `font_8x16` specifically. + - [ ] **4.4j — Retarget the glyph-draw call site from `font_8x16.c` to `TTF-TEXT`.** Depends on 4.4i. **Boundary, corrected 2026-08-11:** `font_8x16.c`/VT100 keeps rendering everything through and including **POST** (the parity/dictionary-hash self-test) — not just the