Skip to content

Draw Han in the UI language's own font - #1121

Merged
KnifeLemon merged 2 commits into
mainfrom
fix/cjk-font-region
Nov 4, 2026
Merged

KnifeLemon merged 2 commits into
mainfrom
fix/cjk-font-region

Conversation

@KnifeLemon

@KnifeLemon KnifeLemon commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

Fixes #1095

The reporter's trace holds, with one correction: the order that decides is Avalonia's sorted family list rather than the resource enumeration, and it isn't all Han that stays Japanese.

Cause

FontFamilies("zh-CN") is Noto Sans, Arabic, Devanagari, Thai, Noto Sans SC, ..., but the font manager never got past the first entry. For each composite entry it asks that family's collection to match the character, and FontCollectionBase.TryMatchCharacter, when the requested family lacks it, sweeps every other family in the collection. Noto Sans has no Han, so the sweep at entry 0 answered, and with no culture to score (TextBlock passes none) the first family won: Noto Sans JP, in every UI language.

A run then stays in that font until it hits a character the font lacks. That is why only some characters looked wrong: 跟随系统 was 跟随系 in JP and 统 in SC.

Checked along the way:

  • The files are what they should be: NotoSansSC-Regular.otf is family "Noto Sans SC" and has all four characters, with outlines that differ from JP and KR (hashed SKFont.GetGlyphPath).
  • Family names, weights and the parsing of the chain are fine.
  • Noto Sans first isn't the problem in itself: any first entry without Han would trigger the sweep, and it should stay first for Latin and the ellipsis.
  • Setup and Typeface.Default aren't affected: they end up in the system collection, whose platform match follows the UI culture (on this PC: YaHei UI, JhengHei UI, Yu Gothic UI).

Fix

FileeFontCollection now wraps the embedded collection and matches a character only in the family asked for, so SoftPalette's order decides. It has to be a wrapper: the font manager calls an internal, non-virtual overload on anything derived from FontCollectionBase, so overriding wouldn't run.

UI language 将 before 将 after
zh-CN Noto Sans JP Noto Sans SC
zh-TW Noto Sans JP Microsoft JhengHei UI (Windows), PingFang TC (macOS, seen in CI)
ja Noto Sans JP Noto Sans JP
ko Noto Sans JP Noto Sans KR
others Noto Sans JP Noto Sans KR (the chain's order)

Latin stays in Noto Sans. Annotate's label fallback asks the same font manager, so it follows too.

zh-TW has no embedded font, so on Linux it would land on Noto Sans SC; Noto Sans CJK TC joins the system list for machines that have it. That name is untested, there's no Linux machine here.

Limits

Avalonia keeps a run in the previous fallback font while that font has the character, so in a zh-CN UI a file name like 한글将 draws 将 in Noto Sans KR. Only mixed foreign text is affected.

Tests

LocalizationResourceTests resolves the characters through TryMatchCharacter and through a real TextLayout, in regular, semibold and bold. Without the fix 8 of the 16 fail (ja passes either way, its right answer was the accidental one); with it LocalizationResourceTests + LocalizationTests pass 232/232 and AnnotateWindowTests 79/79. The tests skip if the fonts weren't fetched; CI fetches them.

🤖 Generated with Claude Code

KnifeLemon and others added 2 commits November 4, 2026 22:31
Avalonia's embedded font collection, asked for a character its requested
family lacks, answers with the first family of its own that has it. A
composite family's first entry, Noto Sans, has no Han, so that answer was
always Noto Sans JP and the chain's next entries were never reached: every
language drew Han in Japanese shapes up to the first character the font
lacks, which is why only some characters in a line looked wrong.

FileeFontCollection now matches a letter only in the family asked for, so
the order of SoftPalette's chain decides. zh-TW reaches the system's
Traditional fonts this way, and Linux gets Noto Sans CJK TC in that list.

Fixes #1095

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
macOS answers PingFang TC, which is right. The test only knew Windows' font
and didn't skip there, as a system collection also lists the names it was
asked for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

[Bug]: zh-CN UI renders some Han characters with Japanese/Korean glyph forms (bundled Noto Sans SC not used)

1 participant