Skip to content

Commit 96ba06e

Browse files
committed
fix(xeCJK): xunicode-symbols.tex 改为多级字体 fallback (#878)
原 fallback 是单层 if-else: Segoe UI Symbol 存在则锁定为唯一 fallback, Noto Sans Symbols 2 永远轮不到。在 Windows 上即使装了 Noto Sans Symbols 2, 也会因为 Segoe UI Symbol 总是被优先选中而出现大段 Missing character。 改为按 Noto Sans Symbols 2 → Symbola → Segoe UI Symbol → DejaVu Sans 顺序逐字符尝试,首个能渲染该字符的字体即用之;主字体 FreeSerif 自身覆盖 的字符仍走主字体。多级 fallback 通过嵌套 \tex_iffontchar:D + \cs_if_exist_use:N 实现,缺失的候选字体自动跳过。 文档侧在 \subsection{xunicode-symbols.tex} 处补充字体依赖说明,提醒 用户本地缺字时可补装 Noto Sans Symbols 2 或直接使用 pre-release 中 预编译的 PDF。 新增 changes 条目 (v3.10.0, 2026/06/23)。 Refs #878
1 parent 358feb2 commit 96ba06e

1 file changed

Lines changed: 38 additions & 5 deletions

File tree

xeCJK/xeCJK.dtx

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14994,6 +14994,25 @@ int main()
1499414994
%
1499514995
% \subsection{\pkg{xunicode-symbols.tex}}
1499614996
%
14997+
% 该文档用于生成 \pkg{xunicode} 中所声明字符的对照表。每一个字符
14998+
% 先尝试用主字体 |FreeSerif| 渲染;若主字体不覆盖该码位,则按顺序
14999+
% 回退到 |Noto Sans Symbols 2|、|Symbola|、|Segoe UI Symbol|、
15000+
% |DejaVu Sans| 中第一个能渲染该字符的字体。
15001+
%
15002+
% 在 \CTeX{} 团队的发版构建中,运行环境同时安装了 |FreeSerif|
15003+
% (Ubuntu \pkg{fonts-freefont-ttf})和 |Noto Sans Symbols 2|,
15004+
% 因此 pre-release 内附的 \file{xunicode-symbols.pdf} 通常已能完整
15005+
% 渲染所有字符。用户在本地通过 |l3build install --full| 重新编译时,
15006+
% 输出是否完整取决于本机已安装的字体;若仅依赖系统自带字体(例如
15007+
% Windows 上仅有 |Segoe UI Symbol|),表中的部分字符会出现
15008+
% “Missing character” 提示。此时建议补装 |Noto Sans Symbols 2|
15009+
% 或直接使用 pre-release 中已编译好的版本。
15010+
%
15011+
% \changes{v3.10.0}{2026/06/23}{\file{xunicode-symbols.tex} 改为按
15012+
% \pkg{Noto Sans Symbols 2}/\pkg{Symbola}/\pkg{Segoe UI Symbol}/\pkg{DejaVu Sans}
15013+
% 逐字符尝试的多级 fallback,缓解 Windows 等仅有
15014+
% \pkg{Segoe UI Symbol} 时部分字符缺失的问题(\#878)。}
15015+
%
1499715016
% \begin{macrocode}
1499815017
%<*xunicode-symbols>
1499915018
% \end{macrocode}
@@ -15011,11 +15030,14 @@ int main()
1501115030
\usepackage{zref-base}
1501215031

1501315032
\setmainfont{FreeSerif}
15033+
\IfFontExistsTF{Noto Sans Symbols 2}
15034+
{\newfontfamily\xunsymNoto{Noto Sans Symbols 2}}{}
15035+
\IfFontExistsTF{Symbola}
15036+
{\newfontfamily\xunsymSymbola{Symbola}}{}
1501415037
\IfFontExistsTF{Segoe UI Symbol}
15015-
{\newfontfamily\falllbackfont{Segoe UI Symbol}}
15016-
{\IfFontExistsTF{Noto Sans Symbols 2}
15017-
{\newfontfamily\falllbackfont{Noto Sans Symbols 2}}
15018-
{\let\falllbackfont\relax}}
15038+
{\newfontfamily\xunsymSegoe{Segoe UI Symbol}}{}
15039+
\IfFontExistsTF{DejaVu Sans}
15040+
{\newfontfamily\xunsymDejaVu{DejaVu Sans}}{}
1501915041

1502015042
\makeatletter
1502115043
\ExplSyntaxOn
@@ -15130,7 +15152,18 @@ int main()
1513015152
\int_gincr:N \g_@@_symbol_int
1513115153
\use_none:n #1 &
1513215154
\scan_stop:
15133-
\reverse_if:N \tex_iffontchar:D \tex_font:D #1 \exp_stop_f: \falllbackfont \fi:
15155+
\reverse_if:N \tex_iffontchar:D \tex_font:D #1 \exp_stop_f:
15156+
\cs_if_exist_use:N \xunsymNoto
15157+
\reverse_if:N \tex_iffontchar:D \tex_font:D #1 \exp_stop_f:
15158+
\cs_if_exist_use:N \xunsymSymbola
15159+
\reverse_if:N \tex_iffontchar:D \tex_font:D #1 \exp_stop_f:
15160+
\cs_if_exist_use:N \xunsymSegoe
15161+
\reverse_if:N \tex_iffontchar:D \tex_font:D #1 \exp_stop_f:
15162+
\cs_if_exist_use:N \xunsymDejaVu
15163+
\fi:
15164+
\fi:
15165+
\fi:
15166+
\fi:
1513415167
\tex_char:D #1 \exp_stop_f: &
1513515168
\tl_set:Nn \l_tmpa_clist {#2}
1513615169
\clist_use:Nn \l_tmpa_clist { \par }

0 commit comments

Comments
 (0)