Skip to content

fix(text): give the text engine glyph fallback, real units, and the fonts asked for - #153

Merged
LeadcodeDev merged 1 commit into
chantier/audit-remediationfrom
fix/text-fallback-measure-fonts
Aug 8, 2026
Merged

fix(text): give the text engine glyph fallback, real units, and the fonts asked for#153
LeadcodeDev merged 1 commit into
chantier/audit-remediationfrom
fix/text-fallback-measure-fonts

Conversation

@LeadcodeDev

Copy link
Copy Markdown
Owner

Round 3 du chantier d'audit — lot texte & polices, 10 constats vérifiés.

Deux familles de défaut, avec des conséquences très différentes :

A. Du texte qui n'est jamais lisible.

ConstatSévéritéSymptôme
Fallback de glyphe absentHighTout texte non-latin (CJK, arabe, devanagari) rendu en tofu. Le moteur choisissait une fonte et dessinait ce qu'elle produisait, .notdef compris.
line-height en % / emHighRésolu à 0 à la mesure → taffy réserve une boîte de hauteur nulle → le texte n'est jamais peint.
font-weight / font-styleHighTotalement ignorés dès qu'une police custom ou Google est déclarée : gras et italique redeviennent silencieusement du regular.
codeblock auto-scrollHighL'offset venait de la hauteur totale du code au lieu des lignes révélées : le bloc reste vide pendant la majorité du reveal.
codeblock / terminalMediumN'utilisaient jamais les polices custom/Google du scénario.
is_emojiMediumClassait ©, et comme emoji : couleur du style perdue ou tofu — y compris dans un exemple livré.

B. Mesure et peinture qui divergent — donc validate devient aveugle.

C'est le point le plus grave pour la fiabilité de génération : la passe geometry inspecte la mesure. Quand la peinture fait autre chose, le débordement existe à l'écran et le validateur déclare le scénario propre.

ConstatSévéritéDivergence
caption largeurCriticalIgnore la largeur donnée par le layout, peint une ligne large qui sort du device.
letter-spacing relatifHighRésolu à la peinture, ignoré à la mesure.
caption line-heightMediumfont_size * 1.4 en dur à la peinture, line_height_for à la boîte.
Terminal typefaceTerminal et TerminalIntrinsic résolvaient leur fonte par deux chemins distincts pouvant diverger.

Terminal et TerminalIntrinsic partagent désormais un unique resolve_typeface : la boîte mesurée et les glyphes dessinés ne peuvent plus diverger, et font-family est enfin honoré.

Correction documentaire

CLAUDE.md et rules/module-structure.md désignaient engine::text::cosmic comme le moteur de texte. Ce module n'a aucun appelant sur le chemin de rendu — le vrai chemin est engine::renderer::text + rustmotion-components::intrinsic. Le module reste compilé (candidat pour un futur moteur de shaping réel), mais son doc-comment dit maintenant clairement qu'il est dormant. Sans ça, la prochaine session peut passer son temps à éditer du code mort en croyant modifier le rendu.

Vérification

cargo test -p rustmotion-core -p rustmotion-components sur cette branche seule : 116 + 6 + 3 + 5 + 211 + 3 tests, 0 échec.

…onts asked for
Ten confirmed audit findings on text measure/paint. Three of them make text
that is simply never legible; four more make the geometry validator blind to
overflow it is supposed to catch, because measure and paint disagree.
- No missing-glyph fallback: any non-Latin text (CJK, Arabic, Devanagari)
rendered as tofu boxes. The engine picked one typeface and drew whatever
it produced, including .notdef.
- `line-height` in `%` or `em` resolved to 0 at measure time, so taffy
reserved a zero-height box and the text was never painted at all.
- `letter-spacing` in relative units was resolved at paint but ignored at
measure — the box was too small, the glyphs overflowed it, and because
the *measure* was what the geometry pass inspected, `validate` reported
the scenario clean.
- `caption` ignored the width the layout gave it and painted one wide line
past the device edge, again invisible to `validate`. Its `line-height`
was also hardcoded to `font_size * 1.4` at paint while the box was
measured with `line_height_for`.
- `font-weight` and `font-style` were dropped entirely as soon as a custom
or Google font was declared — bold and italic silently became regular.
- `codeblock` and `terminal` never used the scenario's custom/Google
fonts. `Terminal` and `TerminalIntrinsic` also resolved their typeface
through two separate code paths that could disagree; they now share one
`resolve_typeface`, so the box measured and the glyphs drawn cannot
diverge.
- `codeblock` auto-scroll derived its offset from the full code height
instead of the revealed lines, leaving the block empty for most of the
reveal.
- `is_emoji` classified ©, ™ and ✓ as emoji, so the style's colour was
dropped (or a tofu drawn) — including in a shipped example.
Also corrects two entry documents that named `engine::text::cosmic` as the
text engine. It has no callers on the render path; the real path is
`engine::renderer::text` + `rustmotion-components::intrinsic`. The module
keeps building, now with a doc comment saying plainly that it is dormant, so
the next reader does not spend a session editing dead code.
Tests: 116 + 6 + 3 + 5 + 211 + 3 pass on this branch alone.
@LeadcodeDevLeadcodeDev added bug Something isn't working documentation Improvements or additions to documentation labels Aug 8, 2026
@LeadcodeDevLeadcodeDev self-assigned this Aug 8, 2026
@LeadcodeDev
LeadcodeDev merged commit c056b41 into chantier/audit-remediationAug 8, 2026
3 checks passed
LeadcodeDev added a commit that referenced this pull request Aug 10, 2026
…onts asked for (#153)
Ten confirmed audit findings on text measure/paint. Three of them make text
that is simply never legible; four more make the geometry validator blind to
overflow it is supposed to catch, because measure and paint disagree.
- No missing-glyph fallback: any non-Latin text (CJK, Arabic, Devanagari)
rendered as tofu boxes. The engine picked one typeface and drew whatever
it produced, including .notdef.
- `line-height` in `%` or `em` resolved to 0 at measure time, so taffy
reserved a zero-height box and the text was never painted at all.
- `letter-spacing` in relative units was resolved at paint but ignored at
measure — the box was too small, the glyphs overflowed it, and because
the *measure* was what the geometry pass inspected, `validate` reported
the scenario clean.
- `caption` ignored the width the layout gave it and painted one wide line
past the device edge, again invisible to `validate`. Its `line-height`
was also hardcoded to `font_size * 1.4` at paint while the box was
measured with `line_height_for`.
- `font-weight` and `font-style` were dropped entirely as soon as a custom
or Google font was declared — bold and italic silently became regular.
- `codeblock` and `terminal` never used the scenario's custom/Google
fonts. `Terminal` and `TerminalIntrinsic` also resolved their typeface
through two separate code paths that could disagree; they now share one
`resolve_typeface`, so the box measured and the glyphs drawn cannot
diverge.
- `codeblock` auto-scroll derived its offset from the full code height
instead of the revealed lines, leaving the block empty for most of the
reveal.
- `is_emoji` classified ©, ™ and ✓ as emoji, so the style's colour was
dropped (or a tofu drawn) — including in a shipped example.
Also corrects two entry documents that named `engine::text::cosmic` as the
text engine. It has no callers on the render path; the real path is
`engine::renderer::text` + `rustmotion-components::intrinsic`. The module
keeps building, now with a doc comment saying plainly that it is dormant, so
the next reader does not spend a session editing dead code.
Tests: 116 + 6 + 3 + 5 + 211 + 3 pass on this branch alone.
@LeadcodeDev
LeadcodeDev deleted the fix/text-fallback-measure-fonts branch August 11, 2026 09:44
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't workingdocumentationImprovements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@LeadcodeDev