refactor(font): Japanese UI P5 PR C — ResolvedGlyph resolver + P4 deletion + CJK UI fallback - #3
Conversation
…op dead pgmspace include Final-review follow-ups (M6-1, M5-1): the three GfxRenderer metric-function comments still described getMaxAscender/getMaxAdvanceY as Task-4 stubs, but Task 6 shipped the max(primary, fallback) bodies — corrected to describe the shipped behaviour. Also dropped the now-dead test/support (pgmspace.h) include from the font_resolver test target: after the P4 deletion, none of its TUs reference PROGMEM. Comment/build-hygiene only; no behaviour change. 104/104 host tests green.
…y tests; comment fixes
Review-cycle (cycle 1, Codex + 5 Claude reviewers + Validator) — outcomeOne real regression was found and fixed in
Also folded into Deferred follow-ups (validated VALID but non-blocking — recorded here since the TODO file is out of this worktree)
|
CI runs bin/clang-format-fix with clang-format-21; this applies its exact output across the PR C files (2-space continuation indent, include grouping, array/comment alignment). Whitespace-only; host suite 104/104 green.
Flash size — confirmed from CI (the plan's +210 KB target was a mis-estimate)CI
This is +37 KB, not the plan's +210 KB target — and that is correct. The +210 KB figure was the absolute size of the new P5 font, but the plan's estimate did not subtract the P4 font that this PR deletes ( First-principles arithmetic:
The positive delta is itself the proof the P5 font is linked: if it had been GC'd/unlinked, deleting the 204 KB P4 font would have shown a large negative delta (~−200 KB). It is neither the +420 KB ODR-duplication canary nor the ~0 link-skip case. Single copy, correctly linked. |
Summary
PR C (final) of the Japanese UI Support P5 re-architecture. Replaces the old P4 CJK "synthesizer / ring / sentinel" machinery with CJK-as-an-ordinary-
EpdFontvia a source-alignedResolvedGlyphresolver chain, so Japanese (CJK) text renders correctly across the firmware UI (titles, menus, filenames, status bar, chapter list, language picker) with zero CJK-specific branches left in the blitter. The reader body-text path is untouched.Prerequisite PRs A + B (plan Tasks 1–3) are already merged on
master; this PR is plan Tasks 4–8 plus a comment-hygiene cleanup.Changes
feat(font)ResolvedGlyph +EpdFontFamily::resolveGlyph— a{const EpdGlyph* glyph; const EpdFontData* data;}pair that is always source-aligned (glyph and data always from the sameEpdFontData), eliminating the P4 owner-mismatch bug structurally. AddssetFallback()+ a no-fallback fast path that never double-probes SD/ring-buffer fonts.refactor(font)deletes ALL P4 machinery:CjkUiFallback.h,cjk_ui_font_20.h(209k-line obsolete fork blob), thecjkUiFallback_flag/enableCjkUiFallback(),EpdFontFamily::hasCjkUiFallback(), and the GfxRendererisSynthesized/custom-CJK-blitter/getGlyphBitmapguard branches + P4 tests. Migrates everygetGlyph/getDatapair in GfxRenderer to a singleresolveGlyphcall; refactorsEpdFont::getTextBoundsinto a family-awaregetTextBoundsImpl(minimal seam, all measurement semantics preserved) with a cross-font kern guard.feat(font)family vertical-metric floor viamax(primary, fallback)(getMaxAscender/getMaxAdvanceY) — no magic constants, never names "CJK"; Latin-only fonts (no fallback) are structurally unchanged.feat(ui)registers the converted 20px CJK font (cjk_ui_20_font_data, flash/PROGMEM) as the fallback on the three UI families (smallFontFamily,ui10FontFamily,ui12FontFamily) insrc/main.cpp; reader/body families are deliberately NOT registered.test(font)new host gtests:font_resolver(resolver + metric floor + measurement consistency) andfont_boundary(kern/ligature no-match for CJK, advance-additivity across the Latin↔CJK boundary, converter null-table guard).chore(font)comment hygiene: corrected stale metric-helper docs; dropped a now-deadpgmspacetest include.Flash size (must be confirmed by CI — this machine has no PlatformIO)
master(the CJK font blob is flash-resident PROGMEM; zero DRAM overhead).cjk_ui_20.cppis compiled exactly once (single library TU).build_src_filter/ double-compilation if seen.Flash:figures (master clean build vs this branch) from the CI build in this PR before merge.Test Plan
CjkFontParity(3420 codepoints bit-perfect),CjkFontSelf,FontResolver(+metric/measurement),FontBoundary, and the pre-existing differential-rounding suites (EpdFont+Fp4Math, no regression).CjkUiFallback/isSynthesized/hasCjkUiFallback/cjk_ui_font_20etc. — grep clean acrosslib/ src/ test/).pio run) + flash delta within target (see above).ESP.getFreeHeap()unchanged (PROGMEM, no new DRAM).Deferred follow-ups (final whole-branch review — none blocking; all currently inert)
getTextBoundsImplguards cross-font kern withprevData == glyphData; the renderer draw/measure paths rely on the primary's table returning 0 for CJK (true today — CJK font has null kern tables and the primary excludes CJK). Add a symmetric guard/comment only if a future fallback ever carries its own kern table.setFallbackprecondition asserts the fallback'sglyphMissHandler == nullptrbut not the primary's (UI primaries are all static built-ins today).resolveGlyphREPLACEMENT_GLYPH symmetry clause, arotatedAscenderalias).