Skip to content

fix(font): align fallback styling and glyph sizing with Ghostty#6

Merged
simota merged 1 commit into
mainfrom
fix/glyph-render-parity
Jul 13, 2026
Merged

fix(font): align fallback styling and glyph sizing with Ghostty#6
simota merged 1 commit into
mainfrom
fix/glyph-render-parity

Conversation

@simota

@simota simota commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Side-by-side comparison with Ghostty on a faint+italic mixed CJK/Latin line showed three glyph-rendering divergences: full-width shifted out of its cell after an italic run, rendered at ~60% of its proper size, and italic Latin drawn with a synthesized slant instead of the real italic face. Each root cause was verified against Ghostty's source and fixed in noa-font.

Changes

  • Synthetic bold/italic is no longer applied to shared fallback faces (CJK/emoji/Nerd Font). Ghostty synthesizes styles only for the primary family's regular face and renders fallback faces upright (CodepointResolver.zig relaxes style to regular; completeStyles is primary-only), so is_native_style_face now short-circuits for fallback faces and synthesis_for skips them.
  • Fit-to-cell downscale now applies only to Nerd Font icon faces. Ghostty never shrinks ordinary text glyphs — only its generated Nerd Font/Powerline constraint table is cell-constrained — so / and friends rasterize at natural size and may overflow their cell, exactly like Ghostty. (U+203B correctly stays 1 column: Ghostty's width tables treat East-Asian-Ambiguous as narrow, so print_width was already parity-correct.)
  • Native style faces are resolved via PostScript-name suffix when font-kit 0.14.3's CoreText backend reports byte-identical Font::properties() for every static face of a family (verified for Menlo and Helvetica; Courier New / Hiragino Sans are unaffected). Italic text now uses the real Menlo Italic instead of regular outlines + synthetic shear.

Test plan

  • 5 red-first regression tests in noa-font (written and confirmed failing before the fix, green after): fallback shear/embolden suppression, upright/italic raster identity for , natural-size raster for /, Menlo native-italic detection.
  • cargo test --workspace green (noa-pty/noa-ipc failures under the sandbox are pre-existing device/socket permission artifacts, green when run unsandboxed); cargo clippy -p noa-font --all-targets clean; cargo fmt --all -- --check clean.
  • Remaining manual step: on-screen visual comparison against Ghostty (cargo run -p noa with italic + full-width punctuation content).

Risk

Medium-low. Behavior-only change contained to noa-font (no public signature, frozen-contract, or cache-key changes; noa-render untouched — verified by grep and diff). Rollback is a single-commit revert. On-screen visual parity is not yet confirmed, and font environments differ across machines (tests self-skip when a required font is absent).

Three glyph-rendering divergences from Ghostty, reported via a
side-by-side comparison of a faint+italic mixed CJK/Latin line and each
verified against Ghostty's source:

- Synthetic bold/italic was applied to shared fallback faces
  (CJK/emoji/Nerd Font). A left-flush full-width glyph such as )
  resolved under an italic style got a faux shear that pushed its ink
  out of its own cell into the neighbor. Ghostty synthesizes styles
  only for the primary family's regular face and renders fallback
  faces upright (CodepointResolver.zig getIndex relaxes to regular;
  completeStyles synthesizes primary-only), so is_native_style_face
  now treats fallback faces as native and synthesis_for skips them.

- Ordinary text glyphs were downscaled kitty-style to fit their cell
  span, shrinking East-Asian-Ambiguous symbols such as ※ and ① that
  wide-metric macOS fallback fonts cover (12x12 instead of 20x20 at
  24px). Ghostty never fits ordinary text — only its generated Nerd
  Font/Powerline icon table is cell-constrained
  (nerd_font_attributes.zig) — so fit_width is now passed only for
  Nerd Font fallback faces and everything else rasterizes at natural
  size, overflowing its cell like Ghostty does.

- Menlo's native italic face was never detected: font-kit 0.14.3's
  CoreText backend reports byte-identical Font::properties() for every
  static face of some families (verified for Menlo and Helvetica), so
  italic text rendered as regular outlines plus a synthetic shear
  while Ghostty uses the real Menlo Italic. resolve_required_style now
  detects the unreliable-properties case (two distinctly-named faces
  with identical properties) and resolves the style by PostScript name
  suffix instead.

Repro tests were written red-first and turn green with this change.
The old narrow_fallback_glyph_fits_within_its_cell_span pin asserted
the non-parity fit behavior for ① and is inverted accordingly.
@simota simota merged commit fc50f8b into main Jul 13, 2026
1 check passed
@simota simota deleted the fix/glyph-render-parity branch July 13, 2026 05:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant