Skip to content

[4539] 键帽组合符 U+20E3 走 emoji 字体回退链,修复渲染为 <#20E3> 占位符 - #4704

Open
bnspopi wants to merge 1 commit into
MoganLab:mainfrom
bnspopi:bnspopi/200_27/fix_keycap_u20e3_font_fallback
Open

bnspopi wants to merge 1 commit into
MoganLab:mainfrom
bnspopi:bnspopi/200_27/fix_keycap_u20e3_font_fallback

Conversation

@bnspopi

@bnspopi bnspopi commented Oct 11, 2026

Copy link
Copy Markdown

问题

Fixes #4539。符号面板「数字·箭头」中 0–9、#、* 与 U+20E3(COMBINING ENCLOSING KEYCAP)组成的键帽序列渲染为 <#20E3> 占位符,同面板的箭头正常。

根因

lolly::data::unicode_get_range 把 U+2000–U+23FF 整体归为 mathsymbols,U+20E3 落在其中。smart_font_rep::resolve 只对 range == "emoji" 启用 emoji 回退链(Noto Color Emoji → Noto Sans Symbols → Noto Sans Symbols2 → DejaVu Sans),U+20E3 因此走数学字体链;默认数学字体没有该字形,resolve 一路落到 error 字体,渲染为占位符。箭头(U+2190 块)能显示是因为数学字体本身覆盖它们,掩盖了同区间内这个组合用符号的缺口。

issue 中已确认自带的 Asana-Math.otf cmap 含 U+20E3。

改动

src/Graphics/Fonts/smart_font.cpp

  • 新增 unicode_code_of:取单字符码点,多字符 / TeXmacs 标记返回 -1。
  • resolve 中 emoji_chain = (range == "emoji") || code == 0x20E3,U+20E3 与 emoji 共用同一条回退链。不改 lolly 的区间划分:U+2000 块里其它数学符号的路由保持原样,改动只针对这一个码点。
  • 回退链末尾追加 Asana Math。只在 Noto Color Emoji / Noto Sans Symbols / Noto Sans Symbols2 / DejaVu Sans 都不支持时才到达,对现有 emoji 路由无影响。

tests/Graphics/Fonts/smart_font_test.cpp

  • test_keycap_combining_font_support:Asana Math / Noto Sans Symbols / Noto Sans Symbols2 至少一款 supports ("<#20E3>")。
  • test_keycap_combining_fallback:sys-chinese 下 resolve ("<#20E3>") 返回的字体不是 error 字体且支持该字符。与现有 test_misc_symbols_fallback 同一写法。
xmake b smart_font_test && xmake r smart_font_test

顺带发现(未改)

unicode_get_range 里 code == 0x200D(ZWJ)归入 emoji 的分支排在 mathsymbols 判断之后,而 U+200D 也在 U+2000–U+23FF 内,所以该分支实际不可达,ZWJ 当前返回 mathsymbols。本 PR 不动 lolly;如需修,应把 ZWJ / 变体选择符等 emoji 修饰符的判断提到 mathsymbols 之前。

说明

  • 本机没有 xmake 构建环境,未能本地编译与运行 smart_font_test,烦请以 CI 为准。
  • 渲染效果:键帽符作为零宽组合字形叠在前一个字符上,与 Unicode 的组合语义一致;若希望像彩色 emoji 那样整体成图,需要字形层做序列合字,超出本 issue 范围。

🤖 Generated with Claude Code

符号面板「数字·箭头」里 0-9、#、* 与 U+20E3(COMBINING ENCLOSING KEYCAP)
组成的键帽序列显示为 <#20E3> 占位符,同面板的箭头正常。

根因:lolly::data::unicode_get_range 把 U+2000-U+23FF 整体归为 mathsymbols,
U+20E3 因此在 smart_font_rep::resolve 中走数学字体链;默认数学字体没有该
字形,而 emoji 回退链(Noto Color Emoji -> Noto Sans Symbols -> Noto Sans
Symbols2 -> DejaVu Sans)只对 range == "emoji" 生效,U+20E3 永远到不了,
最终落到 error 字体渲染占位符。

修复(smart_font.cpp):
- 新增 unicode_code_of 取单字符码点;resolve 中 U+20E3 与 emoji 共用同一条
  回退链,不改 lolly 的区间划分(U+2000 块里的其它数学符号不受影响)。
- 回退链末尾追加自带的 Asana Math(issue 已确认其 cmap 含 U+20E3),只在
  前面各字体都不支持时才到达,对现有 emoji 无影响。

测试(smart_font_test.cpp):
- test_keycap_combining_font_support:至少一款自带回退字体支持 <#20E3>;
- test_keycap_combining_fallback:sys-chinese 下 resolve ("<#20E3>") 不落到
  error 字体且所选字体支持该字符。

Fixes MoganLab#4539

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

符号面板「数字·箭头」中键帽组合字符(基础字符+U+20E3)无法显示,渲染为 <#20E3> 占位符

1 participant