Skip to content

CJK fallback glyphs are upscaled to fill double-width cells and float above the latin baseline #24

Description

@AprilNEA

Environment

restty 0.1.35 and 0.2.0 (verified on both), Electron 42.4.1 renderer, macOS (Apple Silicon), WebGPU backend. Primary font: IBM Plex Mono (buffer source), CJK fallback via local families.

Symptom

On mixed CJK/latin lines, CJK glyphs from a fallback font render noticeably larger (~1.2x) than the primary font's em size and sit visibly above the latin baseline — latin words appear to sink. Pure-latin lines are fine. Reproduced with Hiragino Sans GB and Heiti SC as the CJK fallback; end users report it as 'baseline is broken'.

ls 列出文件 file.txt 大小 1024 字节 mixed 混排 CJK   ← CJK floats high, latin sinks

Analysis (from reading the 0.1.35 bundle; the same behavior reproduces on 0.2.0)

  • For fallback entries with fontMaxCellSpan > 1, the scale resolution applies a width-fit: widthAdjust = (cellW * maxSpan) / widthPx (clamped 0.5–2). With a primary mono whose advance is 600/1000 em (IBM Plex Mono, and most monos), two cells = 1.2em, so any CJK face with the standard 1000/1000 advance gets upscaled x1.2 above its em size.
  • The baseline anchor (fallbackMetricAnchorUnits / ascender diff) then places the enlarged glyph high relative to the primary baseline.
  • fontScaleOverrides cannot counteract it: it is only applied in the symbol-font branch of the scale resolution.
  • Arial Unicode MS happens to escape because its tall line metrics trigger the adjustedHeightPx > lineHeight clamp, which shrinks it back — that's the only stock macOS font we found that keeps mixed lines on one baseline.

Suggestion

Match Ghostty's behavior for wide fallback glyphs: render at the primary em size (no width-fit upscale) and center horizontally within the double-width cell, keeping the baseline anchored. That is exactly what the accidental Arial Unicode path produces, and it looks correct.

Happy to provide the standalone Electron harness + screenshots (Hiragino GB vs Arial Unicode side by side) if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions