summaryrefslogtreecommitdiff
path: root/macros/xetex/latex/xecjk/xeCJK.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/xetex/latex/xecjk/xeCJK.dtx')
-rw-r--r--macros/xetex/latex/xecjk/xeCJK.dtx14063
1 files changed, 14063 insertions, 0 deletions
diff --git a/macros/xetex/latex/xecjk/xeCJK.dtx b/macros/xetex/latex/xecjk/xeCJK.dtx
new file mode 100644
index 0000000000..396d478dfb
--- /dev/null
+++ b/macros/xetex/latex/xecjk/xeCJK.dtx
@@ -0,0 +1,14063 @@
+% \iffalse meta-comment
+% !TEX program = XeLaTeX
+%<*internal>
+\iffalse
+%</internal>
+%<*readme>
+xeCJK
+=====
+
+`xeCJK` is a package written for XeLaTeX which allows users to typeset
+CJK scripts easily.
+
+ - Different default fonts for CJK and other characters.
+ - Spaces automatically ignored between CJK characters.
+ - Special effects on full-width CJK punctuation.
+ - Automatic adjustment of the space between CJK and other characters.
+
+Contributing
+------------
+
+This package is a part of the [ctex-kit](https://github.com/CTeX-org/ctex-kit) project.
+
+Issues and pull requests are welcome.
+
+Copyright and Licence
+---------------------
+
+ Copyright (C) 2007--2010 by Wenchang Sun <sunwch@nankai.edu.cn>
+ Copyright (C) 2009--2019 by Leo Liu <leoliu.pku@gmail.com>
+ Copyright (C) 2012--2019 by Qing Lee <sobenlee@gmail.com>
+ ----------------------------------------------------------------------
+
+ This work may be distributed and/or modified under the
+ conditions of the LaTeX Project Public License, either
+ version 1.3c of this license or (at your option) any later
+ version. This version of this license is in
+ http://www.latex-project.org/lppl/lppl-1-3c.txt
+ and the latest version of this license is in
+ http://www.latex-project.org/lppl.txt
+ and version 1.3 or later is part of all distributions of
+ LaTeX version 2005/12/01 or later.
+
+ This work has the LPPL maintenance status `maintained'.
+
+ The Current Maintainers of this work are Leo Liu and Qing Lee.
+
+ This package consists of the files xeCJK.dtx,
+ full-stop.map,
+ fullwidth-stop.map,
+ han-simp.map,
+ han-trad.map,
+ and the derived files xeCJK.pdf,
+ xeCJK.sty,
+ xeCJK.cfg,
+ xeCJK.ins,
+ xeCJKfntef.sty,
+ xeCJK-listings.sty,
+ xunicode-addon.sty,
+ xunicode-extra.def,
+ xeCJK-example-autofake.tex,
+ xeCJK-example-fallback.tex,
+ xeCJK-example-subCJKblock.tex,
+ xeCJK-example-CJKecglue.tex,
+ xeCJK-example-checksingle.tex,
+ xeCJK-example-CJKfntef.tex,
+ xeCJK-example-punctstyle.tex,
+ xeCJK-example-verbatim.tex,
+ xeCJK-example-CM.tex,
+ xeCJK-example-listings.tex,
+ xeCJK-example-mathblock.tex,
+ xunicode-symbols.tex,
+ xunicode-commands.tex,
+ xunicode-combine-marks.tex,
+ xunicode-symbols.pdf,
+ full-stop.tec,
+ fullwidth-stop.tec,
+ han-simp.tec,
+ han-trad.tec, and
+ README.md (this file).
+%</readme>
+%<*internal>
+\fi
+\begingroup
+ \def\temp{LaTeX2e}
+\expandafter\endgroup\ifx\temp\fmtname\else
+\csname fi\endcsname
+%</internal>
+%<*install>
+
+\input ctxdocstrip %
+
+\preamble
+
+ Copyright (C) 2007--2010 by Wenchang Sun <sunwch@nankai.edu.cn>
+ Copyright (C) 2009--2019 by Leo Liu <leoliu.pku@gmail.com>
+ Copyright (C) 2012--2019 by Qing Lee <sobenlee@gmail.com>
+----------------------------------------------------------------------
+
+ This work may be distributed and/or modified under the
+ conditions of the LaTeX Project Public License, either
+ version 1.3c of this license or (at your option) any later
+ version. This version of this license is in
+ http://www.latex-project.org/lppl/lppl-1-3c.txt
+ and the latest version of this license is in
+ http://www.latex-project.org/lppl.txt
+ and version 1.3 or later is part of all distributions of
+ LaTeX version 2005/12/01 or later.
+
+ This work has the LPPL maintenance status `maintained'.
+
+ The Current Maintainers of this work are Leo Liu and Qing Lee.
+
+----------------------------------------------------------------------
+
+\endpreamble
+\postamble
+
+ This package consists of the files xeCJK.dtx,
+ full-stop.map,
+ fullwidth-stop.map,
+ han-simp.map,
+ han-trad.map,
+ and the derived files xeCJK.pdf,
+ xeCJK.sty,
+ xeCJK.cfg,
+ xeCJK.ins,
+ xeCJKfntef.sty,
+ xeCJK-listings.sty,
+ xunicode-addon.sty,
+ xunicode-extra.def,
+ xeCJK-example-autofake.tex,
+ xeCJK-example-fallback.tex,
+ xeCJK-example-subCJKblock.tex,
+ xeCJK-example-CJKecglue.tex,
+ xeCJK-example-checksingle.tex,
+ xeCJK-example-CJKfntef.tex,
+ xeCJK-example-punctstyle.tex,
+ xeCJK-example-verbatim.tex,
+ xeCJK-example-CM.tex,
+ xeCJK-example-listings.tex,
+ xeCJK-example-mathblock.tex,
+ xunicode-symbols.tex,
+ xunicode-commands.tex,
+ xunicode-combine-marks.tex,
+ xunicode-symbols.pdf,
+ full-stop.tec,
+ fullwidth-stop.tec,
+ han-simp.tec,
+ han-trad.tec, and
+ README.md.
+\endpostamble
+
+\generate
+ {
+%</install>
+%<*internal>
+ \usedir{source/xelatex/xecjk}
+ \file{xeCJK.ins} {\from{\jobname.dtx}{install}}
+%</internal>
+%<*install>
+ \usedir{tex/xelatex/xecjk}
+ \file{xeCJK.sty} {\from{\jobname.dtx}{package}}
+ \file{xeCJKfntef.sty} {\from{\jobname.dtx}{fntef}}
+ \file{xeCJK-listings.sty} {\from{\jobname.dtx}{listings}}
+ \file{xunicode-addon.sty} {\from{\jobname.dtx}{xunicode}}
+ \file{xunicode-extra.def} {\from{\jobname.dtx}{xunextra}}
+ \usepreamble\emptypreamble
+ \usepostamble\emptypostamble
+ \usedir{tex/xelatex/xecjk/config}
+ \file{xeCJK.cfg} {\from{\jobname.dtx}{config}}
+ \usedir{doc/xelatex/xecjk/example}
+ \file{xeCJK-example-autofake.tex} {\from{\jobname.dtx}{ex-autofake}}
+ \file{xeCJK-example-fallback.tex} {\from{\jobname.dtx}{ex-fallback}}
+ \file{xeCJK-example-subCJKblock.tex} {\from{\jobname.dtx}{ex-block}}
+ \file{xeCJK-example-CJKecglue.tex} {\from{\jobname.dtx}{ex-ecglue}}
+ \file{xeCJK-example-checksingle.tex} {\from{\jobname.dtx}{ex-single}}
+ \file{xeCJK-example-CJKfntef.tex} {\from{\jobname.dtx}{ex-fntef}}
+ \file{xeCJK-example-punctstyle.tex} {\from{\jobname.dtx}{ex-punctstyle}}
+ \file{xeCJK-example-verbatim.tex} {\from{\jobname.dtx}{ex-verb}}
+ \file{xeCJK-example-CM.tex} {\from{\jobname.dtx}{ex-cm}}
+ \file{xeCJK-example-listings.tex} {\from{\jobname.dtx}{ex-listings}}
+ \file{xeCJK-example-mathblock.tex} {\from{\jobname.dtx}{ex-mathblock}}
+ \file{xunicode-symbols.tex} {\from{\jobname.dtx}{xunicode-symbols}}
+ \nopreamble\nopostamble
+ \usedir{doc/xelatex/xecjk}
+ \file{README.md} {\from{\jobname.dtx}{readme}}
+ }
+
+\endbatchfile
+%</install>
+%<*internal>
+\fi
+%</internal>
+%<*package|config|fntef|listings|xunicode|xunextra>
+%<!(config|xunextra)>\NeedsTeXFormat{LaTeX2e}
+%<!(config|xunextra)>\RequirePackage{expl3}
+%<+!driver>\GetIdInfo$Id: xeCJK.dtx 4449ab5 2019-06-02 23:02:31 +0800 Qing Lee <sobenlee@gmail.com> $
+%<package> {Typesetting CJK scripts with XeLaTeX}
+%<config> {Configuration file for xeCJK package}
+%<fntef> {xeCJK font effect}
+%<listings> {xeCJK patch file for listings}
+%<xunicode> {addon file for xunicode}
+%<xunextra> {extra definition for xunicode}
+%<package>\ProvidesExplPackage{\ExplFileName}
+%<config>\ProvidesExplFile{\ExplFileName.cfg}
+%<fntef>\ProvidesExplPackage{xeCJKfntef}
+%<listings>\ProvidesExplPackage{xeCJK-listings}
+%<xunicode>\ProvidesExplPackage{xunicode-addon}
+%<xunextra>\ProvidesExplFile{xunicode-extra.def}
+%<!driver> {\ExplFileDate}{3.7.4}{\ExplFileDescription}
+%</package|config|fntef|listings|xunicode|xunextra>
+%<*driver>
+\documentclass{ctxdoc}
+\xeCJKDeclareSubCJKBlock{SP} { "2E3A , "301C , "30A0 , "FF65 }
+\xeCJKDeclareSubCJKBlock{Ext-B} { "20000 -> "2A6DF }
+\xeCJKDeclareSubCJKBlock{Hangul}
+ { "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF }
+\setCJKmainfont[SP, Language=Chinese Simplified]{Source Han Serif}
+\setCJKmainfont[Ext-B]{SimSun-ExtB}
+\setCJKmainfont[Hangul, Script=Hangul, Language=Korean]{Source Han Serif}
+\newlist{psopt}{description}{3}
+\setlist[psopt]{%
+ font=\mdseries\ttfamily, align=right,
+ labelsep=.5em, leftmargin=4.5em, labelindent=0pt}
+\newcommand\PSKeyVal[2]{%
+ \item[#1]\makebox[4em][l]{\meta{#2}}\ignorespaces}
+\newcommand\tokslink[1]{\hyperlink{#1}{\ding{51}}}
+\AtBeginDocument{\DeleteShortVerb{\"}}
+\ExplSyntaxOn
+\NewDocumentCommand \PrintPunctList { O{7} m m }
+ {
+ \par
+ \begingroup
+ \CJKfontspec[Language=Chinese ~ Simplified]{Source ~ Han ~ Serif}
+ \tl_clear:N \l_tmpa_tl
+ \int_zero:N \l_tmpa_int
+ \tl_set:Nx \l_tmpb_tl { \tl_to_str:n { c__xeCJK_#2_chars_clist } }
+ \int_set:Nn \l_tmpb_int { \clist_count:c { \l_tmpb_tl } }
+ \clist_map_inline:cn { \l_tmpb_tl }
+ {
+ \int_incr:N \l_tmpa_int
+ \tl_put_right:Nx \l_tmpa_tl
+ {
+ \use_none:n ##1 & \tex_char:D ##1 \scan_stop:
+ \int_compare:nNnF \l_tmpa_int = \l_tmpb_int
+ {
+ \int_compare:nNnTF { \int_mod:nn \l_tmpa_int {#1} } = \c_zero_int
+ { \exp_not:N \\ \scan_stop: } { & }
+ }
+ }
+ }
+ \noindent\hfill\linespread{1}\selectfont
+ \begin{tabular}{|*{#1}{>{\footnotesize\ttfamily U+}c|c|}}
+ \tl_use:N \l_tmpa_tl
+ \end{tabular}\hfill\null
+ \endgroup
+ \par
+ }
+\ExplSyntaxOff
+\begin{document}
+ \DocInput{\jobname.dtx}
+ \IndexLayout
+ \PrintChanges
+ \PrintIndex
+\end{document}
+%</driver>
+% \fi
+%
+% \changes{v3.1.0}{2012/11/13}{放弃对 \tn{outer} 宏的特殊处理。}
+% \changes{v3.1.1}{2012/12/07}{不再依赖 \pkg{xpatch} 宏包。}
+% \changes{v3.2.2}{2013/06/01}{修正某些重音不能正确显示的问题。}
+% \changes{v3.2.3}{2013/06/07}{提供四个 TECkit 映射文件用于句号转换和简繁互换。}
+% \changes{v3.2.4}{2013/07/02}{遵循 \LaTeXiii{} 变量需要预先声明的原则。}
+% \changes{v3.2.6}{2013/07/29}{\texttt{case} 类函数的用法与 \LaTeXiii{} 同步。}
+% \changes{v3.3.2}{2015/05/15}{随 Unicode 7.0.0 更新简繁汉字映射。}
+% \changes{v3.3.3}{2015/09/25}{更新 \LaTeXiii{} 代码。}
+% \changes{v3.5.0}{2017/07/19}{常数 \cs{c_minus_one} 已过时。}
+% \changes{v3.5.0}{2017/07/22}{使用 \texttt{lazy} 函数对 Boolean 表达式
+% 进行最小化运算(\LaTeXiii{} 2017/07/19)。}
+% \changes{v3.6.0}{2018/01/13}{同步 \LaTeXiii{} 2017/12/16。}
+% \changes{v3.6.1}{2018/02/27}{减少 \texttt{bool} 运算。}
+% \changes{v3.7.2}{2019/03/23}{同步 \LaTeXiii{} 2019/03/05。}
+%
+% \CheckSum{10786}
+% \GetFileId{xeCJK.sty}
+%
+% \title{\bfseries\pkg{xeCJK} 宏包}
+% \author{\href{http://www.ctex.org}{CTEX.ORG}}
+% \date{\filedate\qquad\fileversion\thanks{\ctexkitrev{\ExplFileVersion}.}}
+% \maketitle
+%
+% \tableofcontents
+% \vspace{\baselineskip}
+%
+% \begin{documentation}
+%
+% \section{简介}
+%
+% \pkg{xeCJK} 是一个 \XeLaTeX 宏包,用于排版中日韩(CJK)文字。主要功能:
+% \begin{enumerate}
+% \item 分别设置 CJK 和英文字体;
+% \item 自动忽略 CJK 文字间的空格而保留其它空格,允许在非标点汉字和英文
+% 字母 (a -- z, A -- Z) 间断行;
+% \item 提供多种标点处理方式: 全角式、半角式、开明式、行末半角式和 CCT 式;
+% \item 自动调整中英文间空白。
+% \end{enumerate}
+%
+% \pkg{xeCJK} 使用了 \XeTeX 的一些最新特性,需要 \XeTeX{} 0.9995.0 (2009/06/29) 以
+% 后的版本。\pkg{xeCJK} 依赖 \LaTeXiii{} 项目的宏包套件
+% \package{l3kernel} 和 \package{l3packages} 。
+% \pkg{xeCJK} 还需要通过 \package{fontspec} 宏包来调用系统字体。
+% \pkg{xeCJK} 会自动根据需要载入这些宏包。
+%
+% \pkg{xeCJK} 的原始作者是孙文昌,2009 年 5 月起宏包被收入 \ctexkit\ 项目进行
+% 维护,目前主要维护者是刘海洋\footnote{\email{leoliu.pku@gmail.com}} 和
+% 李清\footnote{\email{sobenlee@gmail.com}}。
+%
+% \section{基本用法}
+%
+% 与其他 \LaTeX{} 宏包一样,引入 \pkg{xeCJK} 宏包只要在导言区使用
+% \begin{frameverb}
+% \usepackage{xeCJK}
+% \end{frameverb}
+% 在引入 \pkg{xeCJK} 宏包之后,只要设置 CJK 文字的字体,就可以在文档中使用中日
+% 韩文字了。
+%
+% 可以在各种文档类中使用 \pkg{xeCJK} 宏包,最简单的示例是:
+% \begin{ctexexam}
+% \documentclass{article}
+% \usepackage{xeCJK}
+% \setCJKmainfont{SimSun}
+%
+% \begin{document}
+% 中文 \LaTeX 示例。
+% \end{document}
+% \end{ctexexam}
+% 上述示例设置了中文字体 SimSun(宋体)。运行此示例要求系统安装了设置的字体,
+% 源文件用 UTF-8 编码保存,使用 \XeLaTeX{} 编译。
+%
+% \pkg{xeCJK} 只提供了字体和标点控制等基本 CJK 语言支持。对于中文文档,可以使
+% 用更为高层的 \package{ctex} 宏包或文档类,它将自动调用 \pkg{xeCJK} 并设置好中文
+% 字体,同时提供了进一步的本地化支持。详细内容参看 \package{ctex} 宏包套件的说明。
+%
+% \pkg{xeCJK} 提供了大量选项,可以在宏包调用时作为宏包选项或用 \tn{xeCJKsetup}
+% 命令进行设置,详见 \ref{subsec:opts}~节。除了 \tn{setCJKmainfont} 命令,
+% \pkg{xeCJK} 还提供了许多其他命令设置和选择中文字体,详见
+% \ref{subsec:fontset}~节。其他更详细的功能也都将在下面详细说明。在本文档所在的
+% 文件夹的 |example| 目录下面也有一些例子可以参考。
+%
+% \section{用户手册}
+%
+% \subsection{宏包选项}
+% \label{subsec:opts}
+%
+% \pkg{xeCJK} 以 \meta{key}|=|\meta{var} 的形式提供宏包选项,你可以在调用宏包
+% 的时候直接设置这些选项,也可以在调用宏包之后使用 \tn{xeCJKsetup} 来设置这些选
+% 项。\pkg{xeCJK} 内部调用 \pkg{fontspec} 宏包,可以在调用 \pkg{xeCJK} 的时候,
+% 使用它的宏包选项。\pkg{xeCJK} 会将 \pkg{fontspec} 的选项传递给它。
+%
+% \begin{function}{\xeCJKsetup}
+% \begin{syntax}
+% \tn{xeCJKsetup} \{\meta{key_1}=\meta{val_1}, \meta{key_2}=\meta{val_2}, ...\}
+% \end{syntax}
+% 其中 \meta{key_1}, \meta{key_2} 是设置选项,而 \meta{val_1}, \meta{val_2} 则是对应选项的
+% 设置内容。多个选项可以在一个语句中完成设置。例如
+% \begin{ctexexam}
+% \usepackage[PunctStyle=kaiming]{xeCJK}
+% \end{ctexexam}
+% 等价于
+% \begin{ctexexam}
+% \usepackage{xeCJK}
+% ......
+% \xeCJKsetup{PunctStyle=kaiming}
+% \end{ctexexam}
+% \end{function}
+%
+% 有些选项或命令后面带有 \exptarget\expstar 号,这表示这
+% 个选项或命令只能在导言区中使用,而 \rexptarget\rexpstar
+% 号则表示这个选项或命令只能在导言区使用,并且只影响随后定义的 CJK 字体。其余不带特殊标记的
+% 选项或命令,如果没有特别说明,可以在导言区或正文中使用。%
+% 使用粗体来表示 \pkg{xeCJK} 的默认设置。
+%
+% \begin{function}[EXP,added=2012-11-22]{LocalConfig}
+% \begin{syntax}
+% LocalConfig = \Arg{\TTF|name}
+% \end{syntax}
+% 是否使用本地配置文件 \texttt{xeCJK-\meta{name}.cfg}。\meta{name} 可以是不包含
+% 空格的任意使文件名合法的字符串。如果设置为 |true|,则使用的是 \texttt{xeCJK.cfg};
+% 设置为 |false| 则不载入配置文件。可以把将要在下文介绍到的对 \pkg{xeCJK} 的一些
+% 设置(例如设置常用 CJK 字体、修改字符范围和定义新的标点输出格式等)保存到文件
+% \texttt{xeCJK-\meta{name}.cfg}。然后把这个文件放在本地的 |TDS| 目录下的适当
+% 位置。使用 \TeX~Live 的用户,可以新建下列目录,然后再把
+% \texttt{xeCJK-\meta{name}.cfg} 放在里面:
+% \begin{frameverb}
+% texlive/texmf-local/tex/xelatex/xecjk
+% \end{frameverb}
+% 最后还需要在命令行下执行 |mktexlsr|,刷新文件名数据库以便 \TeX 系统能够找到它。
+% \end{function}
+%
+% 请注意,\pkg{xeCJK} 宏包中只有上述 |LocalConfig| 选项需要在调用 \pkg{xeCJK} 时
+% 设置,而不能通过 \tn{xeCJKsetup} 来设置。
+%
+% \begin{function}{xeCJKactive}
+% \begin{syntax}
+% xeCJKactive = \meta{\TTF}
+% \end{syntax}
+% 打开/关闭对中文的特殊处理。事实上,这个选项会打开/关闭 \XeTeX 的整个字符类机制,依赖
+% 这个机制的宏包都会受到影响。
+% \end{function}
+%
+% \begin{function}{CJKspace}
+% \begin{syntax}
+% CJKspace = \meta{\TFF}
+% \end{syntax}
+% 缺省状态下,\pkg{xeCJK} 会忽略 CJK 文字之间的空格,使用这一选项来保留它们之间的空格。
+% \end{function}
+%
+% \begin{function}[EXP,updated=2016-05-04]{CJKmath}
+% \begin{syntax}
+% CJKmath = \meta{\TFF}
+% \end{syntax}
+% 是否支持在数学环境中直接输入 CJK 字符。使用这个选项后,可以直接在数学环境中
+% 输出 CJK 字符。\pkg{url} 宏包将一个 URL 放在一个特殊的数学环境中排版,所以如果在
+% \tn{path} 等命令的路径参数中含有汉字,则需要启用这个选项,路径中的汉字才能显示。
+% \end{function}
+%
+% \begin{function}{CJKglue}
+% \begin{syntax}
+% CJKglue = \{\tn{hskip} 0pt plus 0.08\tn{baselineskip}\}
+% \end{syntax}
+% 设置 CJK 文字之间插入的 |glue|,上边是 \pkg{xeCJK} 的默认值。一般来说,除非有
+% 特殊需要(例如,改变文字间距等),否则不需要设置这个选项,使用默认值即可。如果要设置
+% 这个选项,为了行末的对齐,设置的 |glue| 最好有一定的弹性。
+% \end{function}
+%
+% \begin{function}{CJKecglue}
+% \begin{syntax}
+% CJKecglue = \Arg{glue}
+% \end{syntax}
+% 设置 CJK 文字与西文、CJK 文字与行内数学公式之间的间距,默认值是一个空格。使用这个
+% 选项设置的 \meta{glue} 最好也要用一定的弹性。请注意,这里设置的 \meta{glue} 只影响
+% \pkg{xeCJK} 根据需要自动添加的空白,源文件中直接输入的 CJK 文字与西文之间的空格不
+% 受影响(直接输出)。有时候 \pkg{xeCJK} 可能不能正确地调整间距,需要手动加空格。
+% \end{function}
+%
+% \begin{function}{xCJKecglue}
+% \begin{syntax}
+% xCJKecglue = \Arg{\TFF|glue}
+% \end{syntax}
+% 缺省状态下,\pkg{xeCJK} 不对源文件中直接输入的 CJK 文字与西文之间的空格进行调整,如
+% 果需要调整,请使用这个选项。如果使用这个选项,将使用 |CJKecglue| 替换源文件中直接输
+% 入的 CJK 文字与西文之间的空格。
+% \end{function}
+%
+% \begin{function}[updated=2013-06-26]{CheckSingle}
+% \begin{syntax}
+% CheckSingle = \meta{\TFF}
+% \end{syntax}
+% 是否避免单个 CJK 文字单独占一个段落的最后一行。需要说明的是,这个选项只有在
+% 段末的最后一个字是 CJK 文字或者标点符号,并且倒数第二和第三个字都是文字才能
+% 正确处理处理孤字的问题。如果这倒数三个字有作为控制序列的参数的情况,那么一般
+% 来说也不能正确处理。
+% \end{function}
+%
+% \begin{function}[added=2015-04-08]{WidowPenalty}
+% \begin{syntax}
+% WidowPenalty = \Arg{penalty|(10000)}
+% \end{syntax}
+% 使用 \texttt{CheckSingle} 选项后,设置段末三个汉字之间的 penalty。
+% 初始值为 \num{10000},即禁止在它们之间折行。
+% \end{function}
+%
+% \begin{function}[added=2012-12-06]{PlainEquation}
+% \begin{syntax}
+% PlainEquation = \meta{\TFF}
+% \end{syntax}
+% 如果使用了 |$$...$$| 的形式来输入行间数学公式,就需要启用本选项,以便
+% |CheckSingle| 选项能够正确识别。推荐使用 |\[...\]| 的形式来输入行间数学公式。
+% \end{function}
+%
+% \begin{function}[added=2012-12-04]{NewLineCS,NewLineCS+,NewLineCS-}
+% \begin{syntax}
+% NewLineCS = \{ \tn{par} \tn{[} \}
+% \end{syntax}
+% 设置造成断行的控制序列,以便 |CheckSingle| 选项能够正确识别。
+% 以上是 \pkg{xeCJK} 的初始设置。
+% \end{function}
+%
+% \begin{function}[added=2012-12-04]{EnvCS,EnvCS+,EnvCS-}
+% \begin{syntax}
+% EnvCS = \{ \tn{begin} \tn{end} \}
+% \end{syntax}
+% 设置 \LaTeX 环境开始和结束的控制序列,以便 |CheckSingle| 选项能够正确识别。
+% 以上是 \pkg{xeCJK} 的初始设置。
+% \end{function}
+%
+% \begin{function}[updated=2012-12-06]{InlineEnv,InlineEnv+,InlineEnv-}
+% \begin{syntax}
+% InlineEnv = \{\meta{env_1}, \meta{env_2}, \meta{env_3}, ...\}
+% \end{syntax}
+% 在使用 |CheckSingle| 选项的时候,\pkg{xeCJK} 会将 CJK 文字后接着的 \LaTeX 环境的
+% 开始 |\begin{...}| 和结束 |\end{...}| 视为断行的地方,如果有某些特殊
+% 的 \LaTeX 环境没有造成断行,可以使用这个选项来声明它,以便 |CheckSingle| 能正确识别。
+% \end{function}
+%
+% \begin{function}{AutoFallBack}
+% \begin{syntax}
+% AutoFallBack = \meta{\TFF}
+% \end{syntax}
+% 当文档中有个别生僻字时,可以使用这个选项,自动使用预先设置好的后备字体来输出这些生僻
+% 字。后备字体的设置方法将在 \ref{subsec:fontset} 节中介绍。
+% \end{function}
+%
+% \begin{function}[rEXP]{AutoFakeBold}
+% \begin{syntax}
+% AutoFakeBold = \Arg{\TFF|数字}
+% \end{syntax}
+% 全局设定当没有声明对应的粗体时,是否使用^^A
+% \textbf{\CJKfontspec[AutoFakeBold]{FandolSong-Regular.otf}伪粗体};
+% 当输入的是数字时,将使用伪粗体,并将使用输入的数字作为伪粗体的默认粗细程度。
+% \end{function}
+%
+% \begin{function}[rEXP]{AutoFakeSlant}
+% \begin{syntax}
+% AutoFakeSlant = \Arg{\TFF|数字}
+% \end{syntax}
+% 全局设定当没有声明对应的斜体时,是否使用^^A
+% \textit{\CJKfontspec[AutoFakeSlant]{FandolSong-Regular.otf}伪斜体};
+% 当输入的是数字时,将使用伪斜体,并将使用输入的数字作为伪斜体的默认倾斜程度。
+% 倾斜程度的取值范围是 $[-0.999, 0.999]$。
+% \end{function}
+%
+% \begin{function}[rEXP]{EmboldenFactor}
+% \begin{syntax}
+% EmboldenFactor = \Arg{数字|(4)}
+% \end{syntax}
+% 设置伪粗体的默认粗细程度。
+% \end{function}
+%
+% \begin{function}[rEXP]{SlantFactor}
+% \begin{syntax}
+% SlantFactor = \Arg{数字|(0.167)}
+% \end{syntax}
+% 设置伪斜体的倾斜程度,范围是 $[-0.999, 0.999]$。
+% \end{function}
+%
+% \begin{function}[updated=2012-11-10]{PunctStyle}
+% \begin{syntax}
+% PunctStyle = \Arg{(quanjiao)|banjiao|kaiming|hangmobanjiao|CCT|plain|...}
+% \end{syntax}
+% 设置标点处理格式。\pkg{xeCJK} 中预先定义好的格式为
+% \begin{optdesc}
+% \item[quanjiao] 全角式:所有标点占一个汉字宽度,相邻两个标点占 1.5 汉字宽度;
+% \item[banjiao] 半角式:所有标点占半个汉字宽度;
+% \item[kaiming] 开明式:句末点号用全角,其他半角;
+% \item[hangmobanjiao] 行末半角式:所有标点占一个汉字宽度,行首行末对齐;
+% \item[CCT] CCT 格式:所有标点符号的宽度略小于一个汉字宽度;
+% \item[plain] 原样(不调整标点间距)。
+% \end{optdesc}
+% 可以使用 \ref{subsec:punctstyle} 中介绍的 \tn{xeCJKDeclarePunctStyle} 定义新的标点
+% 格式。
+% \end{function}
+%
+% \begin{function}[added=2018-01-24]{PunctFamily}
+% \begin{syntax}
+% PunctFamily = \Arg{(false)|family}
+% \end{syntax}
+% 默认情况下,CJK 标点符号的字体与 CJK 正文一致,\opt{PunctFamily} 用于单独对标点符号设置字体。
+% \meta{family} 需要使用随后说明的 \tn{setCJKfamilyfont} 或 \tn{newCJKfontfamily}
+% 预先定义。\opt{false} 表示取消本选项的作用,让标点符号字体与正文一致。
+% \end{function}
+%
+% \begin{function}[EXP]{KaiMingPunct,KaiMingPunct+,KaiMingPunct-}
+% \begin{syntax}
+% KaiMingPunct = \Arg{( . 。? !)}
+% \end{syntax}
+% 设置开明(|kaiming|)标点处理格式时的句末点号,|KaiMingPunct| 后带的 |+| 与 |-|
+% 分别表示从已有的开明句末点号中增加或减少标点。
+% \end{function}
+%
+% \begin{function}[EXP]{LongPunct,LongPunct+,LongPunct-}
+% \begin{syntax}
+% LongPunct = \Arg{( — ⸺ ‥ … )}
+% \end{syntax}
+% 设置长标点,例如破折号“——”与省略号“……”,允许在长标点前后
+% 断行,但是禁止在它们之间断行。
+% \end{function}
+%
+% \begin{function}[EXP]{MiddlePunct,MiddlePunct+,MiddlePunct-}
+% \begin{syntax}
+% MiddlePunct = \Arg{( – — ⸺ · · ・ 〜゠~)}
+% \end{syntax}
+% 设置居中显示的标点,例如间隔号“\textbf{·}”。对于在 CJK 文字之间的居中标点,
+% \pkg{xeCJK} 会根据不同的标点处理格式,调整居中标点与前后文字之间的空白,保证
+% 其确实居中。对于行末出现的居中标点,允许在其后面断行,但禁止在它前面断行。
+% \end{function}
+%
+% \begin{function}[EXP]{PunctWidth}
+% \begin{syntax}
+% PunctWidth = \Arg{length}
+% \end{syntax}
+% 缺省状态下,\pkg{xeCJK} 会根据所选择的标点处理格式自动计算标点所占的宽度,如果对缺
+% 省设置不满意,可以通过这一选项来改变它。为了使得标点所占的宽度能够适应字体大小的变化,
+% 这里设置的 |length| 的单位最好用 |em| 等相对距离单位,而不建议使用诸如 |pt| 之类的
+% 绝对距离单位。这里的设置可用于除了 |plain| 以外的所有标点处理格式。同时,这里的
+% 设置对所有的 CJK 标点都生效,如果只要设置部分标点,请使用 \ref{subsec:punct}~节的
+% \tn{xeCJKsetwidth}。
+% \end{function}
+%
+% \begin{function}[EXP,added=2013-08-22]{PunctBoundWidth}
+% \begin{syntax}
+% PunctBoundWidth = \Arg{length}
+% \end{syntax}
+% 与以上选项类似,但设置的是标点符号出现在行首/尾时的宽度。
+% \end{function}
+%
+% \begin{function}{AllowBreakBetweenPuncts}
+% \begin{syntax}
+% AllowBreakBetweenPuncts = \meta{\TFF}
+% \end{syntax}
+% 缺省状态下,\pkg{xeCJK} 禁止在相邻 CJK 右标点和 CJK 左标点之间换行,可以使用
+% 这一选项改变这一设置。
+% \end{function}
+%
+% \begin{function}[updated=2016-05-13]{RubberPunctSkip}
+% \begin{syntax}
+% RubberPunctSkip = \meta{\TTF|plus|minus}
+% \end{syntax}
+% 缺省状态下,标点符号前/后的间距有一定的弹性。可以伸长到原始边界宽度,可以收缩到
+% 标点另一侧的边界宽度。将本选项设置为 \texttt{plus},将只允许伸长;设置为
+% \texttt{minus} 只允许收缩。设置为 \texttt{false} 将禁用这一特性,
+% 从而使得前/后的间距为固定值。
+% \end{function}
+%
+% \begin{function}[added=2012-12-02]{CheckFullRight}
+% \begin{syntax}
+% CheckFullRight = \meta{\TFF}
+% \end{syntax}
+% 某些控制序列要求不能在它的前面断行。但是在缺省状态下,单个全角右标点的后面总是
+% 可以断行的。因此当这些控制序列出现在全角右标点后面时,可能会出现意料之外的断行。
+% 此时可以使用这个选项来避免这个情况。
+% \end{function}
+%
+% \begin{function}[added=2012-12-02]{NoBreakCS,NoBreakCS+,NoBreakCS-}
+% \begin{syntax}
+% NoBreakCS = \{ \tn{footnote} \tn{footnotemark} \tn{nobreak} \}
+% \end{syntax}
+% 设置不能在全角右标点后断行的控制序列。以上是 \pkg{xeCJK} 的默认设置。如果这些
+% 控制序列在文档中只出现少量几次,也可以不必使用 |CheckFullRight| 选项,而是手工
+% 在这些控制序列前面加上 \ref{subsec:others}~节介绍的 \tn{xeCJKnobreak}。
+% \end{function}
+%
+% \begin{function}[updated=2013-11-16]{Verb}
+% \begin{syntax}
+% Verb = \meta{\TF|(env)|env+}
+% \end{syntax}
+% \texttt{true} 表示在 \tn{verb} 命令或 \texttt{verbatim} 环境里不自动调整中英文
+% 之间的间距。\texttt{env} 选项在 \texttt{verbatim} 环境里自动计算中西文间距和中文
+% 之间的间距,以便于保持代码的对齐;\texttt{env} 选项不调整 \tn{verb} 里的间距,^^A
+% \texttt{env+} 选项还将正文里设置的间距应用到 \tn{verb} 里。^^A
+% 这个选项对使用到 \tn{verbatim@font} 命令的情形均有效,更一般的情况可以使用
+% \ref{subsec:others}~节介绍的 \tn{xeCJKVerbAddon}。\texttt{false} 表示不作任何
+% 处理。以上选项的值除 \texttt{false} 外,都禁止在汉字之间和汉字与西文之间自动换行。
+% \end{function}
+%
+% \begin{function}[rEXP,added=2014-03-01]{LoadFandol}
+% \begin{syntax}
+% LoadFandol = \meta{\TTF}
+% \end{syntax}
+% 当没有在导言区设置 CJK 字体时,是否使用 Fandol 字体。如果启用这个选项,需要
+% 安装 \package{Fandol} 字体系列。
+% \end{function}
+%
+% \subsection{字体设置与选择}
+% \label{subsec:fontset}
+%
+% \begin{function}[EXP,updated=2016-11-18]{\setCJKmainfont}
+% \begin{syntax}
+% \tn{setCJKmainfont} \Arg{font name}\oarg{font features} 或\\
+% \tn{setCJKmainfont} \oarg{font features} \Arg{font name}
+% \end{syntax}
+% 设置正文罗马族的 CJK 字体,影响 \tn{rmfamily} 和 \tn{textrm} 的字体。后面两个
+% 参数继承自 \pkg{fontspec} 宏包, \meta{font features} 表示字体属性选项,
+% \meta{font name} 是字体名。字体名可以是字体族名,也可以是字体的文件名,查
+% 找字体名见 \ref{subsubsec:fontsearch}~节;可用的字体属性选项参见
+% \pkg{fontspec} 宏包的文档。需要说明的是 \pkg{xeCJK} 修改了 |AutoFakeBold|
+% 和 |AutoFakeSlant| 选项,以便配合全局伪粗体和伪斜体的设定。
+%
+% 出于兼容性考虑,字体属性可选项可以放在字体名称前面,也可以放在后面。
+% 如果可选项放在后面,字体名称与可选项之间不要有空格或者换行。
+% \end{function}
+%
+% \begin{function}[label = ]{AutoFakeBold,AutoFakeSlant}
+% \begin{syntax}
+% AutoFakeBold = \Arg{\TF|数字}
+% AutoFakeSlant = \Arg{\TF|数字}
+% \end{syntax}
+% 局部设置当前字体族的伪粗和伪斜属性。如果没有在局部给出这些选项,将使用全局设定。
+% \end{function}
+%
+% \begin{function}[added=2013-06-07]{Mapping}
+% \begin{syntax}
+% Mapping = \Arg{fullwidth-stop|full-stop|han-trad|han-simp|...}
+% \end{syntax}
+% \pkg{xeCJK} 提供了以上四个 \href{http://scripts.sil.org/teckit}{TECKit} 映射
+% 文件,可以在设置字体的时候通过 \texttt{Mapping} 选项来使用它们。其中
+% \texttt{fullwidth-stop} 用于将正常句号“。”转换成全角实心句号“.”,
+% \texttt{full-stop} 的作用相反。\texttt{han-trad} 用于将简体中文转换成繁体中文,
+% \texttt{han-simp} 的作用相反。需要注意的是,简繁互换都是简单机械的字字对译,
+% 不能做到完全准确,使用时要小心。例如简体的“发挥”和“头发”被转换成繁体的
+% “發揮”和“頭發”,显然后者应作“頭髮”。也可以根据实际需要,制作新的映射文件,
+% 请参考 TECKit 的文档。
+% \end{function}
+%
+% \begin{function}[EXP,updated=2016-11-18]{\setCJKsansfont}
+% \begin{syntax}
+% \tn{setCJKsansfont} \Arg{font name}\oarg{font features} 或\\
+% \tn{setCJKsansfont} \oarg{font features} \Arg{font name}
+% \end{syntax}
+% 设置正文无衬线族的 CJK 字体,影响 \tn{sffamily} 和 \tn{textsf} 的字体。
+% \end{function}
+%
+% \begin{function}[EXP,updated=2016-11-18]{\setCJKmonofont}
+% \begin{syntax}
+% \tn{setCJKmonofont} \Arg{font name}\oarg{font features} 或\\
+% \tn{setCJKmonofont} \oarg{font features} \Arg{font name}
+% \end{syntax}
+% 设置正文等宽族的 CJK 字体,影响 \tn{ttfamily} 和 \tn{texttt} 的字体。
+% \end{function}
+%
+% \begin{function}[EXP,updated=2016-11-18]{\setCJKfamilyfont}
+% \begin{syntax}
+% \tn{setCJKfamilyfont} \Arg{family} \Arg{font name}\oarg{font features} 或\\
+% \tn{setCJKfamilyfont} \Arg{family} \oarg{font features} \Arg{font name}
+% \end{syntax}
+% 声明新的 CJK 字体族 \meta{family} 并指定字体。
+% \end{function}
+%
+% \begin{function}[updated=2012-10-27]{\CJKfamily}
+% \begin{syntax}
+% \tn{CJKfamily} \Arg{family}
+% \tn{CJKfamily} + \Arg{family}
+% \tn{CJKfamily} - \Arg{family}
+% \end{syntax}
+% 用于在文档中切换 |CJK| 字体族,\meta{family} 必须预先声明。\tn{CJKfamily} 仅对
+% CJK 字符类有效,\tn{CJKfamily}|+| 对所有字符类均有效,\tn{CJKfamily}|-| 对非 CJK 字
+% 符类有效。当 \tn{CJKfamily}|+| 和 \tn{CJKfamily}|-| 的参数为空时,则使用当前的 |CJK| 字体族。
+% \end{function}
+%
+% \begin{function}[EXP,updated=2016-11-18]{\newCJKfontfamily}
+% \begin{syntax}
+% \tn{newCJKfontfamily} \oarg{family} \cs{\meta{font-switch}} \Arg{font name}\oarg{font features} 或\\
+% \tn{newCJKfontfamily} \oarg{family} \cs{\meta{font-switch}} \oarg{font features} \Arg{font name}
+% \end{syntax}
+% 声明新的 CJK 字体族 \meta{family} 并指定字体,并定义 \cs{\meta{font-switch}},在
+% 文档中可以使用它来切换 CJK 字体族。可以不必指定 \meta{family},这时候 \meta{family}
+% 将等于 \meta{font-switch}。
+% \end{function}
+%
+% 事实上,\tn{newCJKfontfamily} 是 \tn{setCJKfamilyfont} 和
+% \tn{CJKfamily} 的合并。例如
+% \begin{ctexexam}
+% \newCJKfontfamily[song]\songti{SimSun}
+% \end{ctexexam}
+% 等价于
+% \begin{ctexexam}
+% \setCJKfamilyfont{song}{SimSun}
+% \newcommand*{\songti}{\CJKfamily{song}}
+% \end{ctexexam}
+%
+% \begin{function}[updated=2016-11-18]{\CJKfontspec}
+% \begin{syntax}
+% \tn{CJKfontspec} \Arg{font name}\oarg{font features} 或\\
+% \tn{CJKfontspec} \oarg{font features} \Arg{font name}
+% \end{syntax}
+% 在文档中定义新的 CJK 字体族,并马上使用它。
+% \end{function}
+%
+% \begin{function}[rEXP]{\defaultCJKfontfeatures}
+% \begin{syntax}
+% \tn{defaultCJKfontfeatures} \Arg{font features}
+% \end{syntax}
+% 全局设置 CJK 字体族的默认选项。例如,使用
+% \begin{ctexexam}
+% \defaultCJKfontfeatures{Scale=0.962216}
+% \end{ctexexam}
+% 可以将全部 CJK 字体缩小为 |0.962216|。\pkg{xeCJK} 宏包的初始化设置是
+% \begin{frameverb}
+% \defaultCJKfontfeatures{Script=CJK}
+% \end{frameverb}
+% \end{function}
+%
+% \begin{function}[updated=2013-06-30]{\addCJKfontfeatures}
+% \begin{syntax}
+% \tn{addCJKfontfeatures} \Arg{font features}
+% \tn{addCJKfontfeatures} * \Arg{font features}
+% \tn{addCJKfontfeatures} \oarg{block_1, block_2, ...} \Arg{font features}
+% \tn{addCJKfontfeatures} * \oarg{block_1, block_2, ...} \Arg{font features}
+% \end{syntax}
+% 临时增加当前使用的 CJK 字体的选项。第一条命令,仅对当前 CJK 主分区字体有效;
+% 第二条对主分区和其它分区的字体都有效;第三条仅对可选参数中指定的分区有效;
+% 第四条对主分区和可选参数中指定的分区有效。例如,使用
+% \begin{ctexexam}
+% \addCJKfontfeatures{Scale=1.1}
+% \end{ctexexam}
+% 可以将文档中当前使用的 CJK 主分区字体放大为 |1.1|。
+% \end{function}
+%
+% \begin{function}{\CJKrmdefault}
+% 保存 \tn{textrm} 和 \tn{rmfamily} 所使用的 CJK 字体族,默认值是 |rm|。
+% \end{function}
+%
+% \begin{function}{\CJKsfdefault}
+% 保存 \tn{textsf} 和 \tn{sffamily} 所使用的 CJK 字体族,默认值是 |sf|。
+% \end{function}
+%
+% \begin{function}{\CJKttdefault}
+% 保存 \tn{texttt} 和 \tn{ttfamily} 所使用的 CJK 字体族,默认值是 |tt|。
+% \end{function}
+%
+% \begin{function}[updated=2013-01-01]{\CJKfamilydefault}
+% 保存 \tn{textnormal} 和 \tn{normalfont} 所使用的 CJK 字体族。类似西文字体的 \tn{familydefault}。
+% 初始值是 \tn{CJKrmdefault}。如果没有在导言区中修改它,\pkg{xeCJK} 会在导言区
+% 结束的时候根据西文字体的情况自动更新 \tn{CJKfamilydefault}。因此,在导言区里使用
+% \begin{frameverb}
+% \renewcommand\familydefault{\sfdefault}
+% \end{frameverb}
+% 就可以将全文的 CJK 和西文默认字体都改为无衬线字体族。
+% \end{function}
+%
+% \begin{function}[EXP,updated=2016-11-18]{\setCJKmathfont}
+% \begin{syntax}
+% \tn{setCJKmathfont} \Arg{font name}\oarg{font features} 或\\
+% \tn{setCJKmathfont} \oarg{font features} \Arg{font name}
+% \end{syntax}
+% 设置数学公式中的 CJK 字体族。如果使用了 |CJKmath| 选项,但是没有使用
+% \tn{setCJKmathfont} 设置数学公式中的 CJK 字体,那么将使用 \tn{CJKfamilydefault}
+% 作为数学公式中的 CJK 字体。
+% \end{function}
+%
+% \begin{function}[EXP, label=, updated=2016-11-18]{\setCJKfallbackfamilyfont}
+% \begin{syntax}
+% \tn{setCJKfallbackfamilyfont} \Arg{family} \Arg{font name}\oarg{font features} 或\\
+% \tn{setCJKfallbackfamilyfont} \Arg{family} \oarg{font features} \Arg{font name}
+% \end{syntax}
+% 设置 CJK 字体族 \meta{family} 的备用字体。例如,使用
+% \begin{ctexexam}
+% \setCJKmainfont{SimSun}
+% \setCJKfallbackfamilyfont{\CJKrmdefault}{SimSun-ExtB}
+% \end{ctexexam}
+% 可以将 |SimSun-ExtB| 作为 |SimSun| 的备用字体。
+% \end{function}
+%
+% \begin{function}{FallBack}
+% \begin{syntax}
+% FallBack = \{\oarg{font features}\Arg{font name}\}
+% \end{syntax}
+% \pkg{xeCJK} 在 \meta{font features} 里增加了 |FallBack| 这个选项。用来在声明主
+% 字体的时候,同时设置备用字体。例如,上面的例子等价于:
+% \begin{ctexexam}
+% \setCJKmainfont[FallBack=SimSun-ExtB]{SimSun}
+% \end{ctexexam}
+% 如果 |FallBack| 的值为空,将设置的是备用字体。例如,
+% \begin{ctexexam}
+% \setCJKmainfont[FallBack,AutoFakeBold,Scale=.97]{SimSun-ExtB}
+% \end{ctexexam}
+% 等价于
+% \begin{ctexexam}
+% \setCJKfallbackfamilyfont{\CJKrmdefault}[AutoFakeBold,Scale=.97]{SimSun-ExtB}
+% \end{ctexexam}
+% \end{function}
+%
+% \begin{function}[EXP,updated=2013-06-30]{\setCJKfallbackfamilyfont}
+% \begin{syntax}
+% \tn{setCJKfallbackfamilyfont} \Arg{family}
+% \ \{
+% \ \{\oarg{font features_1} \Arg{font name_1}\} ,
+% \ \{\oarg{font features_2} \Arg{font name_2}\} ,
+% \ ......
+% \ \}\oarg{common font features} 或\\
+% \tn{setCJKfallbackfamilyfont} \Arg{family} \oarg{common font features}
+% \ \{
+% \ \{\oarg{font features_1} \Arg{font name_1}\} ,
+% \ \{\oarg{font features_2} \Arg{font name_2}\} ,
+% \ ......
+% \ \}
+% \end{syntax}
+% \tn{setCJKfallbackfamilyfont} 还可以用于设置多层的备用字体。例如,使用
+% \begin{ctexexam}
+% \setCJKmainfont[AutoFakeBold,AutoFakeSlant]{KaiTi_GB2312}
+% \setCJKfallbackfamilyfont{\CJKrmdefault}[AutoFakeSlant]
+% { [BoldFont=SimHei]{SimSun} ,
+% [AutoFakeBold] {SimSun-ExtB} }
+% \end{ctexexam}
+% 之后,就设置了 |SimSun| 是 |KaiTi_GB2312| 的备用字体,而 |SimSun-ExtB| 是
+% |SimSun| 的备用字体。若当前字体族缺字,并没有备用字体,则尝试使用
+% \tn{CJKfamilydefault} 的备用字体。
+% \end{function}
+%
+% \subsubsection{\XeTeX 的字体名查找}
+% \label{subsubsec:fontsearch}
+%
+% 由于在 \pkg{fontspec} 宏包文档中缺少关于如何查看 \XeTeX{} 可用字体名的说明,
+% 这里略作说明。
+%
+% \XeTeX{} 通常使用 fontconfig 库查找和调用字体,因此,可以用 |fc-list| 命令显
+% 示可用的字体。在命令行(Windows 的“命令提示符”,Linux 的 Console)下运行以
+% 下命令:
+% \begin{frameverb}
+% fc-list > fontlist.txt
+% \end{frameverb}
+% 可以将系统中所有安装的字体列表存入 \file{fontlist.txt} 文件中(可能很长)。
+%
+% |fc-list| 命令列出的信息很多,而且在安装字体较多的 Windows 系统上的输出将非
+% 常庞大,如其中可能包含:
+% \begin{frameverb}
+% Times New Roman:style=cursiva,kurzíva,kursiv,Πλάγια,Italic,
+% Kursivoitu,Italique,Dőlt,Corsivo,Cursief,kursywa,Itálico,Курсив,
+% İtalik,Poševno,nghiêng,Etzana
+% Times New Roman:style=Negreta cursiva,tučné kurzíva,fed kursiv,
+% Fett Kursiv,Έντονα Πλάγια,Bold Italic,Negrita Cursiva,
+% Lihavoitu Kursivoi,Gras Italique,Félkövér dőlt,Grassetto Corsivo,
+% Vet Cursief,Halvfet Kursiv,Pogrubiona kursywa,Negrito Itálico,
+% Полужирный Курсив,Tučná kurzíva,Fet Kursiv,Kalın İtalik,
+% Krepko poševno,nghiêng đậm,Lodi etzana
+% Times New Roman:style=Negreta,tučné,fed,Fett,Έντονα,Bold,Negrita,
+% Lihavoitu,Gras,Félkövér,Grassetto,Vet,Halvfet,Pogrubiona,Negrito,
+% Полужирный,Fet,Kalın,Krepko,đậm,Lodia
+% Times New Roman:style=Normal,obyčejné,Standard,Κανονικά,Regular,
+% Normaali,Normál,Normale,Standaard,Normalny,Обычный,Normálne,Navadno,
+% thường,Arrunta
+% 宋体,SimSun:style=Regular
+% 黑体,SimHei:style=Normal,obyčejné,Standard,Κανονικά,Regular,Normaali,
+% Normál,Normale,Standaard,Normalny,Обычный,Normálne,Navadno,Arrunta
+% \end{frameverb}
+% 在 \pkg{fontspec} 或 \pkg{xeCJK} 中使用的字体族名是上面列表中冒号前的部分。
+% 例如可以使用
+% \begin{ctexexam}
+% \setmainfont{Times New Roman}
+% \setCJKmainfont{SimSun} % 或者 \setCJKmainfont{宋体}
+% \end{ctexexam}
+% 来设置字体。
+%
+% 为了方便起见,|fc-list| 命令也可以加上各种选项控制输出格式,例如如果只要列出
+% 所有的中文字体的字体族名,可以用命令:
+% \begin{frameverb}
+% fc-list -f "%{family}\n" :lang=zh > zhfont.txt
+% \end{frameverb}
+% 这样就把字体列表保存在文件 \file{zhfont.txt} 中\footnote{由于汉字编码原因,
+% Windows 下总需要把字体列表输出的文件中防止乱码。}。这样列出的字体列表就比较
+% 简明易用,如 Windows 下预装的中文字体:
+% \begin{frameverb}
+% Arial Unicode MS
+% FangSong,仿宋
+% KaiTi,楷体
+% Microsoft YaHei,微软雅黑
+% MingLiU,細明體
+% NSimSun,新宋体
+% PMingLiU,新細明體
+% SimHei,黑体
+% SimSun,宋体
+% \end{frameverb}
+% 要列出日文和韩文的字体,可以把 |:lang=zh| 选项中的 |zh| 改成 |ja| 或 |ko|。
+%
+% \pkg{fontspec} 和 \pkg{xeCJK} 也可以使用字体的文件名访问字体。例如 Windows
+% 下的宋体也可以使用命令:
+% \begin{frameverb}
+% \setCJKmainfont{simsun.ttc}
+% \end{frameverb}
+% 来设置。设置字体文件名的相关选项和语法在 \pkg{fontspec} 宏包手册中叙述甚详,
+% 这里不再赘述。有个别字体名不规范的中文字体,\pkg{xeCJK} 宏包可能无法正确地通
+% 过字体名访问,那么也可以使用这种方式设置。
+%
+% \subsection{CJK 分区字体设置}
+% \label{subsec:block}
+%
+% 众所周知,CJK 文字数量极其庞大,单一的字体不可能涵盖所有的 CJK 文字。\pkg{xeCJK} 可
+% 以在同一 CJK 字体族下,自动使用不同的字体输出 CJK 字符范围内不同区块里的文字。首先要
+% 声明 CJK 子分区。
+%
+% \begin{function}[EXP]{\xeCJKDeclareSubCJKBlock}
+% \begin{syntax}
+% \tn{xeCJKDeclareSubCJKBlock} \Arg{block} \Arg{block range}
+% \tn{xeCJKDeclareSubCJKBlock} * \Arg{block} \Arg{block range}
+% \end{syntax}
+% 其中 \meta{block range} 是逗号列表,可以是 CJK 字符的 |Unicode| 范围,也可以是单个字符
+% 的 |Unicode|。例如
+% \end{function}
+% \begin{ctexexam}
+% { `中 -> `文 , "3400 -> "4DBF , "5000 -> "7000 , `汉 , `字 , "3500 }
+% \end{ctexexam}
+% 的形式。需要注意的是,这里设置的 \meta{block range} 除非确实需要(例如某些特殊字体使用
+% 了 |Unicode| 中的私人使用区的情况),否则不要超出源代码中预设的
+% \hyperlink{CJKcharclass}{CJK 文字范围}。使用
+% \begin{ctexexam}
+% \xeCJKDeclareSubCJKBlock{SPUA}{ "E400 -> "E4DA , "E500 -> "E5E8 , "E600 -> "E6CE }
+% \xeCJKDeclareSubCJKBlock{Ext-B}{ "20000 -> "2A6DF }
+% \end{ctexexam}
+% 就声明了 |SPUA| 和 |Ext-B| 这两个个子分区。同时在 \ref{subsec:fontset} 节介绍的
+% CJK 字体设置命令的 \meta{font features} 里新建了 |SPUA| 和 |Ext-B| 这两个选项。
+% 新建的这两个选项的使用方法跟 \ref{subsec:fontset} 介绍的 |FallBack| 类似。可以
+% 通过它们来设置字体。
+%
+% 例如,可以使用
+% \begin{ctexexam}
+% \setCJKmainfont[SPUA=SunmanPUA,Ext-B=SimSun-ExtB]{SimSun}
+% \end{ctexexam}
+% 设置文档的主字体是 |SimSun|,|SPUA| 分区的字体是 |SunmanPUA|,而 |Ext-B| 分区
+% 的字体是 |SimSun-ExtB|。
+%
+% \tn{xeCJKDeclareSubCJKBlock} 应该在声明所有的 CJK 字体族之前使用。如果有某个 CJK 字
+% 体族没有设置 \meta{block} 选项,将使用 \tn{CJKfamilydefault} 的 \meta{block} 选项
+% 作为该 CJK 字体族的 \meta{block} 选项。如果希望在使用某 CJK 字体族时,不在 CJK 主
+% 分区与 \meta{block} 之间切换字体,可以使用 \meta{block}|=*| 选项。带星号的命令除了
+% 设置 CJK 子分区以外,还重置标点符号所属的字符类。
+%
+% \begin{function}{\xeCJKCancelSubCJKBlock}
+% \begin{syntax}
+% \tn{xeCJKCancelSubCJKBlock} \Arg{block_1, block_2, ...}
+% \tn{xeCJKCancelSubCJKBlock} \Arg{block_1, block_2, ...}
+% \end{syntax}
+% 在文档中取消对 |CJK| 分区的声明。带星号的命令还重置标点符号所属的字符类。
+% \end{function}
+%
+% \begin{function}{\xeCJKRestoreSubCJKBlock}
+% \begin{syntax}
+% \tn{xeCJKRestoreSubCJKBlock} \Arg{block_1, block_2, ...}
+% \tn{xeCJKRestoreSubCJKBlock} * \Arg{block_1, block_2, ...}
+% \end{syntax}
+% 在文档中恢复对 |CJK| 分区的声明。带星号的命令还重置标点符号所属的字符类。
+% \end{function}
+%
+% \subsection{设置 CJK 字符范围}
+%
+% \begin{function}[EXP]{\xeCJKDeclareCharClass}
+% \begin{syntax}
+% \tn{xeCJKDeclareCharClass} \Arg{class} \Arg{class range}
+% \tn{xeCJKDeclareCharClass} * \Arg{class} \Arg{class range}
+% \end{syntax}
+% \meta{class range} 的格式和 \ref{subsec:block} 节的 \meta{block range} 相同。
+% \meta{class} 的有效值见源代码(第 \ref{sec:xeCJK-class-set} 节)。\pkg{xeCJK} 已
+% 经支持 |Unicode| 中所有 CJK 文字和标点。一般来说,不要轻易改变字符类别。带星号的
+% 命令除了设置字符类别以外,为了确保标点处理的正确性,还重置标点符号所属的字符类。
+% \end{function}
+%
+% \begin{function}[EXP]{\xeCJKResetCharClass}
+% 用于恢复 \pkg{xeCJK} 对各个字符类别的初始化设置。
+% \end{function}
+%
+% \begin{function}[EXP]{\xeCJKResetPunctClass}
+% 用于重置标点符号所属的字符类。
+% \end{function}
+%
+% \begin{function}{\normalspacedchars}
+% \begin{syntax}
+% \tn{normalspacedchars} \Arg{char list}
+% \end{syntax}
+% 在 \meta{char list} 中出现的字符两端不自动添加空格,初始设置是 |/|、|\|、
+% 和 |-| (|U+002D|)。
+% \end{function}
+%
+% \subsection{标点符号的处理}
+%
+% \pkg{xeCJK} 对标点符号的输出宽度的调整是通过调整其左边或右边的空白宽度来实现的。
+% 按照目前的处理方式,对于位于左边的标点符号(如左引号),\pkg{xeCJK} 只能调整它
+% 左边的空白;对于位于右边的标点符号(如右引号),\pkg{xeCJK} 只能调整它右边的空
+% 白;对于居中的标点符号,则调整其左右空白,以保证其居中。对于标点符号的相关设置,
+% 只能在导言区中进行。
+%
+% \subsubsection{设置特定标点符号的宽度和间距}
+% \label{subsec:punct}
+%
+% 这里的设置可用于除 |plain| 以外的所有标点处理格式。
+%
+% \begin{function}[EXP,updated=2013-08-22]{\xeCJKsetwidth}
+% \begin{syntax}
+% \tn{xeCJKsetwidth} \Arg{标点列表} \Arg{length}
+% \tn{xeCJKsetwidth} * \Arg{标点列表} \Arg{length}
+% \end{syntax}
+% \meta{标点列表}可以是单个标点,也可以是多个标点。例如,
+% \begin{ctexexam}
+% \xeCJKsetwidth{。?}{0.7em}
+% \end{ctexexam}
+% 将设置句号和问号所占的宽度为 |0.7em|。带星号的命令,设置标点符号出现在行首/尾
+% 时的宽度。
+% \end{function}
+%
+% \begin{function}[EXP]{\xeCJKsetkern}
+% \begin{syntax}
+% \tn{xeCJKsetkern} \Arg{前标点} \Arg{后标点} \Arg{length}
+% \end{syntax}
+% \pkg{xeCJK} 会根据选定的标点处理格式自动调整相邻的前后两个 |CJK| 标点符号的
+% 空白宽度。如果需要对个别情况进行特殊调整,可以使用这个命令。例如,
+% \begin{ctexexam}
+% \xeCJKsetkern{:}{“}{0.3em}
+% \end{ctexexam}
+% 将设置冒号与左双引号之间的空白宽度为 |0.3em|。
+% \end{function}
+%
+% \subsubsection{定义标点符号处理格式}
+% \label{subsec:punctstyle}
+%
+% \begin{function}[EXP,updated=2013-08-22]{\xeCJKDeclarePunctStyle}
+% \begin{syntax}
+% \tn{xeCJKDeclarePunctStyle} \Arg{style} \Arg{options}
+% \end{syntax}
+% 定义新的标点符号处理格式,已经存在的同名格式将被覆盖。可以设置的选项将在下面介绍。
+% \end{function}
+%
+% \begin{function}[EXP,updated=2013-08-22]{\xeCJKEditPunctStyle}
+% \begin{syntax}
+% \tn{xeCJKEditPunctStyle} \Arg{style} \Arg{options}
+% \end{syntax}
+% 修改已有的标点符号处理格式。
+% \end{function}
+%
+% 下面是可以设置的标点符号格式选项。其中左边一栏是选项名称,中间是选项的输入值类
+% 型,右边则是相关说明。某些选项之间是互斥的,具有优先级关系。要使下一级的选项有
+% 效,则需要先禁用上一级的设置:对于 \meta{boolean} 类型的选项,将其设置为 |false|,
+% 对于 \meta{length} 类型的选项,将其设置为 \tn{maxdimen},而对于 \meta{real} 类型
+% 的选项,将其设置为 |nan|。
+%
+% \begin{psopt}
+% \PSKeyVal{enabled-global-setting}{boolean}
+% 是否使用 \tn{xeCJKsetup} 的 |PunctWidth|、|PunctBoundWidth| 选项和
+% \tn{xeCJKsetwidth}、\tn{xeCJKsetkern} 的设置。默认值是 |true|。
+% \end{psopt}
+%
+% \begin{psopt}
+% \PSKeyVal{fixed-punct-width}{length}
+% 设置单个标点符号的宽度。默认值是 \tn{maxdimen}。
+% \PSKeyVal{fixed-punct-ratio}{real}
+% 设置单个标点符号的输出宽度与实际宽度的比例。默认值是 |1.0|。
+% \PSKeyVal{mixed-punct-width}{length}
+% 设置句末标点符号的宽度。其中句末标点符号通过 \tn{xeCJKsetup} 的 |KaiMingPunct|
+% 来设置。默认值是与 |fixed-punct-width| 选项的值相同。
+% \PSKeyVal{mixed-punct-ratio}{real}
+% 设置句末标点符号的宽度比例。默认值是与 |fixed-punct-ratio| 选项的值相同。
+% \PSKeyVal{middle-punct-width}{length}
+% 设置居中标点符号的宽度。其中居中标点符号通过 \tn{xeCJKsetup} 的 |MiddlePunct|
+% 来设置。默认值是与 |fixed-punct-width| 选项的值相同。
+% \PSKeyVal{middle-punct-ratio}{real}
+% 设置居中标点符号的宽度比例。默认值是与 |fixed-punct-ratio| 选项的值相同。
+% \end{psopt}
+%
+% 以上几个选项设置的是标点的固定宽度或比例,\pkg{xeCJK} 会根据设定的选项计算标点符号
+% 左/右的空白宽度。下面的选项设置的是标点符号左/右的空白宽度或比例,因此不同标点符号
+% 的宽度可能会不同。为了使下面的选项生效,需要先禁用上面的相应选项。优先级自上而下。
+%
+% \begin{psopt}
+% \PSKeyVal{fixed-margin-width}{length}
+% 设置标点的左/右空白宽度。默认值是 \tn{maxdimen}。
+% \PSKeyVal{fixed-margin-ratio}{real}
+% 设置标点的左/右空白宽度与字体中该标点的相应实际边界宽度的比例。默认值是~|1.0|。
+% \PSKeyVal{mixed-margin-width}{length}
+% 设置句末标点的左/右空白宽度。默认值是与 |fixed-margin-width| 的值相同。
+% \PSKeyVal{mixed-margin-ratio}{real}
+% 设置句末标点的左/右空白宽度的比例。默认值是与 |fixed-margin-ratio| 的值相同。
+% \PSKeyVal{middle-margin-width}{length}
+% 设置居中标点的两边空白宽度。默认值是与 |fixed-margin-width| 的值相同。
+% \PSKeyVal{middle-margin-ratio}{real}
+% 设置居中标点的两边空白宽度之和与两边实际两边边界宽度之和的比例。
+% 默认值是与 |fixed-margin-ratio| 的值相同。
+% \end{psopt}
+%
+% 下面选项设置标点符号出现在行首或者行尾时的宽度或比例。
+%
+% \begin{psopt}
+% \PSKeyVal{bound-punct-width}{length}
+% 设置标点符号出现在行首/尾时的宽度。默认值是 \tn{maxdimen}。
+% \PSKeyVal{bound-punct-ratio}{real}
+% 设置标点符号出现在行首/尾时的输出宽度与实际宽度的比例。默认值是 |nan|。
+% \PSKeyVal{bound-margin-width}{length}
+% 设置标点符号出现在行首/尾时的左/右空白宽度。默认值是 \tn{maxdimen}。
+% \PSKeyVal{bound-margin-ratio}{real}
+% 设置标点符号出现在行首/尾时的左/右空白宽度与相应实际边界宽度的比例。默认值是 |0|。
+% \PSKeyVal{enabled-hanging}{boolean}
+% 当以上选项的计算结果得到的宽度小于标点符号的实际边界宽度时,是否允许标点符号
+% 悬挂出页面边界。默认值是 |false|。
+% \end{psopt}
+%
+% \begin{psopt}
+% \PSKeyVal{add-min-bound-to-margin}{boolean}
+% 是否在以上计算结果的基础上再加上标点的左右实际边界宽度中的最小值。这个选项
+% 对居中的标点无效。默认值是 |false|。
+% \end{psopt}
+%
+% \begin{psopt}
+% \PSKeyVal{optimize-margin}{boolean}
+% 使用以上设置空白宽度或比例的选项时,最终输出的标点符号左/右的空白宽度可能大
+% 于原来的实际边界宽度。若此时本选项被设置为 |true|,则使用原来的实际边界宽度。
+% 而使用 |fixed-punct-width| 选项计算得出的左/右宽度可能小于该标点的另一侧宽
+% 度,若此时本选项被启用,则使用该标点的另一侧宽度。默认值为 |false|。
+% \end{psopt}
+%
+% \begin{psopt}
+% \PSKeyVal{margin-minimum}{length}
+% 指定标点符号左/右的最小空白宽度。当经过以上选项设置的空白宽度小于这个选项的值
+% 时,则使用这个选项的值。默认值是 |0pt|。
+% \end{psopt}
+%
+% 下面的选项处理的是前后相邻的两个标点符号之间的空白宽度。这些选项是互斥的,优先级
+% 自上而下。
+%
+% \begin{psopt}
+% \PSKeyVal{enabled-kerning}{boolean}
+% 是否调整前后相邻的两个标点之间的空白宽度。如果设置为 |false|,则每个标点都按
+% 原来的输出宽度输出。默认值是 |true|。
+% \PSKeyVal{min-bound-to-kerning}{boolean}
+% 是否使用当前字体中前面标点实际左右边界的最小值与后面标点实际左右边界的最小值
+% 中的最大值作为两个标点之间的空白宽度。默认值是 |false|。
+% \PSKeyVal{kerning-total-width}{length}
+% 设置两个标点的总共宽度。此时 \pkg{xeCJK} 会自动计算两个标点之间的空白宽度。
+% 默认值是 \tn{maxdimen}。
+% \PSKeyVal{kerning-total-ratio}{real}
+% 设置两个标点的总共输出宽度与实际宽度的比例。默认值是 |0.75|。
+% \PSKeyVal{same-align-margin}{length}
+% 前后两个标点位于同侧时,它们之间的空白宽度。默认值是 \tn{maxdimen}。
+% \PSKeyVal{same-align-ratio}{real}
+% 前后两个标点位于同侧时,它们之间的空白宽度与实际输出宽度的比例。默认值是~|nan|。
+% \PSKeyVal{different-align-margin}{length}
+% 前后两个标点位于异侧时,它们之间的空白宽度。默认值是 \tn{maxdimen}。
+% \PSKeyVal{different-align-ratio}{real}
+% 前后两个标点位于异侧时,它们之间的空白宽度与实际输出宽度的比例。默认值是~|nan|。
+% \PSKeyVal{kerning-margin-width}{length}
+% 设置前后两个标点之间的空白宽度。默认值是 \tn{maxdimen}。
+% \PSKeyVal{kerning-margin-ratio}{real}
+% 设置前后两个标点之间的空白宽度与实际输出空白的比例。默认值是 |1.0|。
+% \end{psopt}
+%
+% \begin{psopt}
+% \PSKeyVal{optimize-kerning}{boolean}
+% 使用以上选项计算出两个标点之间的空白宽度可能小于通过 |min-bound-to-kerning|
+% 选项得出的结果。当出现这一情况时,若此选项被设置为 |true|,则使用该选项的空
+% 白宽度。默认值为 |false|。
+% \end{psopt}
+%
+% \begin{psopt}
+% \PSKeyVal{kerning-margin-minimum}{length}
+% 指定两个标点之间的最小空白宽度。当经过以上选项设置的空白宽度小于这个选项的值
+% 时,则使用这个选项的值。默认值是 |0pt|。
+% \end{psopt}
+%
+% 事实上,\pkg{xeCJK} 的默认设置就相当于中文全角(|quanjiao|)格式。可以使用上面
+% 说明的选项定义新的标点处理格式。例如,使用
+% \begin{ctexexam}
+% \xeCJKDeclarePunctStyle { mine }
+% {
+% fixed-punct-ratio = nan ,
+% fixed-margin-width = 0 pt ,
+% mixed-margin-width = \maxdimen ,
+% mixed-margin-ratio = 0.5 ,
+% middle-margin-width = \maxdimen ,
+% middle-margin-ratio = 0.5 ,
+% add-min-bound-to-margin = true ,
+% bound-punct-width = 0 em ,
+% enabled-hanging = true ,
+% min-bound-to-kerning = true ,
+% kerning-margin-minimum = 0.1 em
+% }
+% \end{ctexexam}
+% 就定义了一个名为 |mine| 的标点处理格式。可以在导言区通过
+% \begin{frameverb}
+% \xeCJKsetup{PunctStyle=mine}
+% \end{frameverb}
+% 在文档中使用这个格式。它的意义是:使用标点符号的实际左右边界中的最小值作为其左/右
+% 空白的宽度,对于句末标点和居中标点,再加上实际边界空白的一半;当标点出现在行首或
+% 行尾时宽度为零,允许悬挂出页面边界;使用相邻两个标点的实际边界中的较小值作为它们
+% 之间的空白宽度,并且最小的空白宽度是 |0.1em|。再例如,使用
+% \begin{ctexexam}
+% \xeCJKEditPunctStyle { hangmobanjiao } { enabled-global-setting = false }
+% \end{ctexexam}
+% 将使得 \tn{xeCJKsetkern} 等的设置对 |hangmobanjiao| 这一格式无效。
+%
+% \subsection{\pkg{xeCJKfntef} 用法说明}
+%
+% \pkg{xeCJK} 包含有一个子宏包 \pkg{xeCJKfntef},可以用它来实现\CJKunderdot{汉字加点}%
+% 和可断行的下划线等。它是 \pkg{CJKfntef} 宏包在 \XeLaTeX 下的替换版本,基本用法完全一致。
+%
+% \pkg{xeCJKfntef} 基于 \package{ulem} 宏包,除了兼容 \pkg{ulem} 定义的一些命令外,
+% 还进行了一些扩充:
+%
+% \begin{function}[updated=2014-11-04]
+% {\CJKunderline,\CJKunderdblline,\CJKunderwave,\CJKsout,\CJKxout}
+% \begin{syntax}
+% \tn{CJKunderline} [*] [-] \oarg{选项} \Arg{内容}
+% \end{syntax}
+% \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.35\linewidth,gobble=6]
+% \CJKunderline{虚室生白,吉祥止止}\\
+% \CJKunderdblline{虚室生白,吉祥止止}\\
+% \CJKunderwave{虚室生白,吉祥止止}\\
+% \CJKsout{虚室生白,吉祥止止}\\
+% \CJKxout{虚室生白,吉祥止止}
+% \end{SideBySideExample}
+% \end{function}
+%
+% \csappto{NoHighlight@Attributes}{\catcode37=14\relax}
+%
+% \begin{Example}[frame=single,numbers=left,gobble=4]
+% \CJKunderline-{南朝}\CJKunderline-{梁}\CJKunderline-{劉勰}%
+% \CJKunderwave-{文心雕龍}\CJKunderwave-{養氣}\\
+% \CJKunderline*[thickness=1pt, hidden=true]{瞻彼阕者,虚室生白,吉祥止止}
+% \end{Example}
+%
+% \begin{function}[updated=2014-11-04]{\CJKunderdot}
+% \begin{syntax}
+% \tn{CJKunderdot} \oarg{选项} \Arg{内容}
+% \end{syntax}
+% 在汉字下加点,可以和上述下划线命令嵌套使用。例如\smallskip
+%
+% \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.35\linewidth,gobble=6]
+% \CJKunderline{虚室生白,\CJKunderdot{吉祥}止止}\\
+% \CJKunderdot{虚室生白,\CJKunderline{吉祥}止止}
+% \end{SideBySideExample}
+% \end{function}
+%
+% \bigskip
+%
+% 对上述六种对象,\pkg{xeCJKfntef} 提供了一些选项,设置点或线的位置和颜色。可以用
+% \tn{xeCJKsetup} 预先统一设置它们,也可以在使用时特别设置。
+%
+% \begin{function}[added=2014-11-04]{skip}
+% \begin{syntax}
+% \tn{xeCJKsetup} \{ underline/skip = \meta{\TTF} \}
+% \tn{xeCJKsetup} \{ underline = \{ skip = \meta{\TTF} , ... \} \}
+% \end{syntax}
+% 默认情况下,下划线会自动跳过中文标点符号,可以设置本选项为 \texttt{false},
+% 禁用这一功能。相应下划线命令后加上 |*| 号,具有相同的效果。
+% \end{function}
+%
+% \begin{function}{subtract}
+% 设置本选项为 \texttt{true},使得下划线的首尾减少一定距离,避免前后的下划线
+% 连在一起,适用于古籍标点整理中的专名号和书名号。在相应下划线命令后加上 |-|
+% 号,具有相同的效果。
+% \end{function}
+%
+% \begin{function}{hidden}
+% 设置本选项为 \texttt{true},将隐藏文本内容,只画下划线。
+% \end{function}
+%
+% \begin{function}{format}
+% \begin{syntax}
+% \tn{xeCJKsetup} \{ underline/format = \tn{color}\{red\} \}
+% \tn{xeCJKsetup} \{ underwave = \{ format = \tn{color}\{red\}, ... \} \}
+% \end{syntax}
+% 设置线或点的格式,比如颜色。
+% \end{function}
+%
+% \begin{function}[added=2016-06-03]{textformat}
+% 设置下划线或点的正文的格式。例如:\smallskip
+% \begin{Example}[frame=single,numbers=left,gobble=6]
+% \CJKunderline[textformat=\color{red}]{虚室生白,吉祥止止}\\
+% \CJKunderdot[textformat=\bfseries, format=\color{blue}]{虚室生白,吉祥止止}
+% \end{Example}
+% \end{function}
+%
+% \begin{function}{symbol}
+% 设置 \tn{CJKunderwave} 或 \tn{CJKunderdot} 的符号。
+% \end{function}
+%
+% 例如,波浪线 \tn{CJKunderwave} 的符号不会随字号而变化,在小字号下不好看。我们可以
+% 将它改为随字号而变化大小:
+%
+% \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.35\linewidth,gobble=4]
+% % \usepackage{fix-cm}
+% \xeCJKsetup{%
+% underwave/symbol=
+% \fontsize{0.5em}{0pt}%
+% \fontencoding{U}\fontfamily{lasy}\selectfont
+% \char 58\relax}
+% \footnotesize
+% \CJKunderwave{瞻彼阕者,虚室生白,吉祥止止}
+% \end{SideBySideExample}
+%
+% \begin{function}{thickness}
+% 设置 \tn{CJKunderline}、\tn{CJKunderdblline} 和 \tn{CJKsout} 的线的厚度。
+% 初始值是 \tn{ULthickness}。
+% \end{function}
+%
+% \begin{function}{depth}
+% 设置线或点的深度(基线到线或点的顶部的距离)。初始值都是 \texttt{0.2em}。
+% \end{function}
+%
+% \begin{function}{boxdepth}
+% \tn{CJKunderdot} 可能会影响到行距,可以设置本选项进行调整。如果不希望
+% \tn{CJKunderdot} 影响行距,可以将本选项设置为 \texttt{0pt}。
+% \end{function}
+%
+% \begin{function}{sep}
+% 设置 \tn{CJKunderdot} 与 \tn{CJKunderline}、\tn{CJKunderdblline} 或
+% \tn{CJKunderwave} 嵌套使用时,点与线或者线与点的距离。
+% \end{function}
+%
+% \begin{function}{gap}
+% 设置 \tn{CJKunderdblline} 的两条线之间的距离。初始值是 \texttt{1.1pt}。
+% \end{function}
+%
+% \begin{function}{height}
+% 设置删除线 \tn{CJKsout} 的高度(线的中心到基线的距离)。初始值是 \texttt{0.35em}。
+%
+% 例如,我们可以设置 \tn{CJKsout} 的厚度和颜色,让它具有类似高亮的效果:\smallskip
+%
+% \begin{Example}[frame=single,numbers=left,gobble=4]
+% \CJKsout*[thickness=2.5ex, format=\color{yellow}]{瞻彼阕者,虚室生白,吉祥止止}
+% \end{Example}
+% \end{function}
+%
+% \medskip
+%
+% \pkg{xeCJKfntef} 还提供给了自定义下划线和符号的 \tn{CJKunderanyline} 和
+% \tn{CJKunderanysymbol}。
+%
+% \begin{function}[updated=2014-11-07]{\CJKunderanyline}
+% \begin{syntax}
+% \tn{CJKunderanyline} [*] [-] \oarg{选项} \Arg{深度} \Arg{下划内容} \Arg{文本内容}
+% \end{syntax}
+% \pkg{xeCJKfntef} 先将 \meta{下划内容} 放进一个盒子(\tn{xeCJKfntefbox})里,然后
+% 向下移动 \meta{深度} 给定的距离,再用于填充。可用的 \meta{选项} 是 \texttt{textformat}、
+% \texttt{skip}、\texttt{hidden}、\texttt{subtract}、\texttt{sep} 和
+% \texttt{boxdepth}。选项 \texttt{sep} 和 \texttt{boxdepth} 的初始值是空,表示
+% 禁用该选项的功能。可以在 \tn{xeCJKsetup} 中通过对象 \texttt{ulem} 来设置。
+% \end{function}
+%
+% 例如,高亮效果也可以如下实现:\smallskip
+%
+% \begin{Example}[frame=single,numbers=left,gobble=4]
+% \CJKunderanyline*{0.5ex}{\color{yellow}\rule{2pt}{2.5ex}}{虚室生白,吉祥止止}
+% \end{Example}
+%
+% \begin{function}[updated=2014-11-04]{\CJKunderanysymbol}
+% \begin{syntax}
+% \tn{CJKunderanysymbol} \oarg{选项} \Arg{深度} \Arg{符号} \Arg{文本内容}
+% \end{syntax}
+% \pkg{xeCJKfntef} 将 \meta{符号} 放进一个盒子(\tn{xeCJKfntefbox})里。
+% \meta{深度} 参数用于设置盒子顶部的深度(基线到盒子顶部的距离)。
+% 可用的 \meta{选项} 是 \texttt{textformat}、\texttt{sep} 和 \texttt{boxdepth},意义与
+% \tn{CJKunderdot} 的相同。
+% \end{function}
+%
+% 例如,给汉字加三角形,可以如下设置:\smallskip
+%
+% \begin{Example}[frame=single,numbers=left,gobble=4]
+% \CJKunderanysymbol[sep=0.1em]{0.2em}{\tiny$\triangle$}
+% {瞻彼阕者,虚室生白,\CJKunderline{吉祥止止}}
+% \end{Example}
+%
+% \begin{function}[updated=2014-11-07]{\xeCJKfntefon}
+% \begin{syntax}
+% \tn{xeCJKfntefon} [*] [-] \oarg{选项}
+% \end{syntax}
+% 功能与用法 \pkg{ulem} 宏包的 \tn{ULon} 相同,扩展了可选参数符号 |*| 和 |-|,
+% 可用的 \meta{选项} 是 \texttt{textformat}、 \texttt{skip}、\texttt{hidden} 和
+% \texttt{subtract}。 这四个选项对 \pkg{ulem} 宏包定义的 \tn{uline} 等命令也有效,需要在
+% \tn{xeCJKsetup} 中通过对象 \texttt{ulem} 来设置。例如\smallskip
+%
+% \begin{Example}[frame=single,numbers=left,gobble=6]
+% \xeCJKsetup{ulem={textformat=\bfseries\color{red}, skip=true}}
+% \uline{虚室生白,吉祥止止}
+% \end{Example}
+% \end{function}
+%
+% \medskip
+%
+% 此外,\pkg{xeCJKfntef} 还提供了指定宽度,让汉字分散对齐的的环境
+% \env{CJKfilltwosides} 和 \env{CJKfilltwosides*}。
+%
+% \begin{function}[updated=2014-11-04]{CJKfilltwosides}
+% \begin{syntax}
+% \tn{begin}\{CJKfilltwosides\} \oarg{位置} \Arg{宽度}
+% 文本内容\verb=\\=
+% 文本内容
+% \tn{end}\{CJKfilltwosides\}
+% \end{syntax}
+% 环境中的内容被放入垂直盒子中,可选参数 \meta{位置} 指定盒子的基线位置。
+% 可以使用 \texttt{t}(顶部)、\texttt{c}(居中)和 \texttt{b}(底部),默认是 \texttt{c}。
+% \meta{宽度} 参数指定盒子的宽度。
+% \env{CJKfilltwosides*} 环境与 \env{CJKfilltwosides} 的区别是,当 \meta{宽度}
+% 不大于零或者不大于盒子的自然宽度时,就取盒子的自然宽度。例如
+% \end{function}
+%
+% \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.5\linewidth,gobble=4]
+% \begin{CJKfilltwosides}{.8\linewidth}
+% 瞻彼阕者,\\
+% 虚室生白,吉祥止止
+% \end{CJKfilltwosides}
+% \end{SideBySideExample}
+%
+% \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.5\linewidth,gobble=4]
+% \begin{CJKfilltwosides*}{0pt}
+% 瞻彼阕者,\\
+% 虚室生白,吉祥止止
+% \end{CJKfilltwosides*}
+% \end{SideBySideExample}
+%
+% \subsection{其他}
+% \label{subsec:others}
+%
+% \begin{function}[updated=2013-11-16]{\xeCJKVerbAddon,\xeCJKOffVerbAddon}
+% 调整文字间距以便于让 CJK 字符占的宽度等于西文等宽字体中两个空格的宽度。如果这两
+% 个空格的宽度小于当前 CJK 正常文字的宽度,将对 CJK 字体进行适当地缩小。这有利于
+% 等宽字体的代码对齐等情形。需要注意的是,\tn{xeCJKVerbAddon} 对 \pkg{xeCJK} 的内
+% 部进行了比较大的修改,使用它之后,将禁止在 CJK 字符类之间自动换行,这与西文在
+% 抄录环境中的情况是一致的。所以不应该单独使用,应该放在分组里限制其作用域,否则
+% 是无效的。当然它可以和其它关于代码抄录的宏包配合使用。例如,可以使用于
+% \package{fancyvrb} 宏包的 \texttt{formatcom} 选项。此时设置的西文字体应该确实
+% 是等宽的以保证对齐。若西文等宽字体发生变动(包括字体大小),则需要在其后面使用
+% \tn{xeCJKVerbAddon},重新计算间距的宽度。\tn{xeCJKOffVerbAddon}
+% 用于在使用 \tn{xeCJKVerbAddon} 的环境中局部取消它的作用。由于 \package{listings}
+% 宏包有自己的代码对齐机制,所以 \tn{xeCJKVerbAddon} 在由 \pkg{listings} 定义的
+% 代码环境中无效。
+% \end{function}
+%
+% \begin{function}[added=2012-12-03]{\xeCJKnobreak}
+% \begin{syntax}
+% ……汉字。\tn{xeCJKnobreak}\tn{footnote}\{脚注\}
+% \end{syntax}
+% \tn{xeCJKnobreak} 用在全角标点符号后面,目的是确保不能在此处断行。如果已经启用了
+% 前面介绍的 |CheckFullRight| 选项,则不需要再用此命令。
+% \end{function}
+%
+% \begin{function}[added=2013-11-09]{\xeCJKShipoutHook}
+% \pkg{xeCJK} 在正文中的一些特殊设置(汉字下加点、在 \env{verbatim} 或
+% \env{lstlisting} 环境中分页)可能会影响到 \TeX 的输出例行程序(output routine)
+% 中的内容(比如页眉和页脚)。\tn{xeCJKShipoutHook} 用于恢复正文中的普通设置。
+% \pkg{xeCJK} 已经处理了页眉和页脚的情况,其它的就需要根据情况自行调用。
+% 比如若使用 \pkg{eso-pic} 或者 \pkg{atbegshi} 实现文字水印,并且正文中使用了
+% 以上所列的特殊形式,就需要在命令 \tn{AtBeginShipout} 的参数的最前面使用
+% \tn{xeCJKShipoutHook}。
+% \end{function}
+%
+% \section{已知问题和兼容性}
+%
+% \XeTeX 在配置文件 \file{unicode-letters.tex} 中将所有 CJK 表意文字的 \tn{catcode}
+% 设置为 $11$。因此汉字可以直接用作控制序列的名字,但是当汉字出现在控制序列后面的
+% 时候,要用空格分隔开,否则就会出现“\texttt{! Undefined control sequence.}”的错误。
+%
+% \pkg{xeCJK} 使用并重新定义了 \pkg{CJK} 宏包的部分宏命令,如 \tn{CJKfamily}、
+% \tn{CJKsymbol} 和 \tn{CJKglue} 等。需要指出,\pkg{xeCJK} 不需要 \pkg{CJK}
+% 的支持,并且 \pkg{xeCJK} 自动禁止在它之后载入 \pkg{CJK} 宏包。
+% 可以在 \pkg{xeCJK} 之\emph{后}载入 \pkg{CJKnumb} 宏包,实现数字的中文化,
+% 也可以用功能更完善的 \package{zhnumber} 宏包。
+%
+% \pkg{xeCJK} 进行了一些处理,使得在使用 \XeTeX 时 \package{listings} 宏包可以
+% 支持 Unicode,因此在 \texttt{listings} 定义的代码环境中可以直接使用中文,不再
+% 需要通过 \texttt{escapechar}。
+%
+% 新版本(\texttt{3.x})的 \pkg{xeCJK} 完全使用 \LaTeXiii{} 的语法来编写。
+% \LaTeXiii{} 放弃了 \tn{outer} 宏的概念,因此相关工具在
+% 遇到 \tn{outer} 宏时可能会存在问题。按照目前 \pkg{xeCJK} 的实现方式,在 CJK 文字
+% 后面遇到 \tn{outer} 宏时会出现类似
+% \begin{frameverb}
+% ! Forbidden control sequence found while scanning use of \use_i:nn
+% \end{frameverb}
+% 的错误。目前已知的有 \package{cprotect} 宏包提供的 \tn{cprotect}。它的定义是
+% \begin{frameverb}
+% \outer\long\def\cprotect{\icprotect}
+% \end{frameverb}
+% 因此,这时可以暂时用 \tn{icprotect} 代替 \tn{cprotect}。事实上,当 \pkg{cprotect}
+% 被引入时,\pkg{xeCJK} 将使用
+% \begin{frameverb}
+% \let\cprotect\icprotect
+% \end{frameverb}
+% 来取消 \tn{cprotect} 的外部宏限制。但由于 \tn{cprotect} 的特殊性,应该只在外部
+% 使用它,即不要让它出现在任何宏的参数中。其它 \tn{outer} 宏的情况,可以在它前面
+% 加上 \tn{relax} 来回避上面的错误。
+%
+% \pkg{xeCJK} 依赖 \XeTeX 的 \tn{XeTeXinterchartoks} 机制,与使用相同机制的宏包(例如
+% \pkg{polyglossia} 和 \pkg{xesearch})可能会存在大小不一的冲突。
+% \pkg{xeCJK} 虽然为此作了一些处理,但与它们共同使用时应该小心。
+%
+%\end{documentation}
+%
+%
+% \StopEventually{}
+%
+%
+%\begin{implementation}
+%
+% \section{\pkg{xeCJK} 代码实现}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=xeCJK>
+% \end{macrocode}
+%
+% \subsection{运行环境检查}
+%
+% \pkg{xeCJK} 必须使用 \XeTeX 引擎的支持。
+% \begin{macrocode}
+\msg_new:nnn { xeCJK } { Require-XeTeX }
+ {
+ The~xeCJK~package~requires~XeTeX~to~function.\\\\
+ You~must~change~your~typesetting~engine~to~"xelatex" \\
+ instead~of~plain~"latex"~or~"pdflatex"~or~"lualatex".\\
+ Loading~xeCJK~will~abort!
+ }
+\sys_if_engine_xetex:F { \msg_critical:nn { xeCJK } { Require-XeTeX } }
+% \end{macrocode}
+%
+% 应该使用较新版本的 \pkg{expl3} 宏包。
+% \begin{macrocode}
+\msg_new:nnn { xeCJK } { l3-too-old }
+ {
+ Support~package~`#1'~too~old. \\\\
+ Please~update~an~up~to~date~version~of~the~bundles\\\\
+ `l3kernel'~and~`l3packages'\\\\
+ using~your~TeX~package~manager~or~from~CTAN.\\
+ \str_if_eq:nnT {#1} { expl3 } { Loading~xeCJK~will~abort! }
+ }
+\@ifpackagelater { expl3 } { 2019/03/05 } { }
+ { \msg_critical:nnn { xeCJK } { l3-too-old } { expl3 } }
+% \end{macrocode}
+%
+% \begin{macro}[pTF,int]{\xeCJK_if_package_loaded:n}
+% 判断宏包是否被引入,可用于文档正文中。
+% \begin{macrocode}
+\prg_new_conditional:Npnn \xeCJK_if_package_loaded:n #1 { p , T , F , TF }
+ {
+ \tl_if_exist:cTF { ver@ #1 . \c_@@_package_ext_tl }
+ { \prg_return_true: } { \prg_return_false: }
+ }
+\tl_const:Nx \c_@@_package_ext_tl { \@pkgextension }
+% \end{macrocode}
+% \end{macro}
+%
+% 下面这些 \pkg{CJK} 系列宏包不应该被使用。
+% \begin{macrocode}
+\msg_new:nnn { xeCJK } { incompatible-package }
+ {
+ The~`#1'~package~and~xeCJK~are~incompatible.\\\\
+ Please~do~not~use~it.
+ }
+\msg_new:nnn { xeCJK } { after-package }
+ {
+ The~`#1'~package~and~xeCJK~are~incompatible.\\\\
+ Please~load~it~after~xeCJK.
+ }
+\clist_map_inline:nn { CJKfntef , CJKnumb }
+ {
+ \xeCJK_if_package_loaded:nT {#1}
+ { \msg_error:nnn { xeCJK } { after-package } {#1} }
+ }
+\clist_map_inline:nn { CJKulem , CJKvert , CJKpunct , CJKutf8 , CJK }
+ {
+ \xeCJK_if_package_loaded:nTF {#1}
+ { \msg_error:nnn { xeCJK } { incompatible-package } {#1} }
+ { \tl_const:cn { ver@ #1 . \c_@@_package_ext_tl } { 9999/99/99 } }
+ }
+% \end{macrocode}
+%
+% 以下日期以前的 \pkg{xtemplate} 宏包关于 \tn{KeyValue} 的 Bug 会影响到后面
+% 标点符号的处理。
+% \begin{macrocode}
+\RequirePackage { xtemplate }
+\@ifpackagelater { xtemplate } { 2012/11/10 } { }
+ { \msg_error:nnn { xeCJK } { l3-too-old } { xtemplate } }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\RequirePackage { xparse , l3keys2e }
+% \end{macrocode}
+%
+% \subsection{内部工具}
+%
+% 分配临时变量。
+% \begin{macrocode}
+\tl_new:N \l_@@_tmp_tl
+\int_new:N \l_@@_tmp_int
+\box_new:N \l_@@_tmp_box
+\dim_new:N \l_@@_tmp_dim
+\bool_new:N \l_@@_tmp_bool
+\skip_new:N \l_@@_tmp_skip
+\clist_new:N \l_@@_tmp_clist
+% \end{macrocode}
+%
+% \begin{macro}
+% {\@@_msg_new:nn ,\@@_error:n,\@@_error:nx,\@@_warning:nx,\@@_info:nxx}
+% 各种信息函数的缩略形式。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_msg_new:nn { \msg_new:nnn { xeCJK } }
+\cs_new_protected_nopar:Npn \@@_msg_new:nnn { \msg_new:nnnn { xeCJK } }
+\cs_new_protected_nopar:Npn \@@_error:n { \msg_error:nn { xeCJK } }
+\cs_new_protected_nopar:Npn \@@_error:nx { \msg_error:nnx { xeCJK } }
+\cs_new_protected_nopar:Npn \@@_warning:n { \msg_warning:nn { xeCJK } }
+\cs_new_protected_nopar:Npn \@@_warning:nx { \msg_warning:nnx { xeCJK } }
+\cs_new_protected_nopar:Npn \@@_warning:nxx { \msg_warning:nnxx { xeCJK } }
+\cs_new_protected_nopar:Npn \@@_warning:nxxx { \msg_warning:nnxxx { xeCJK } }
+\cs_new_protected_nopar:Npn \@@_info:nxx { \msg_info:nnxx { xeCJK } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_allow_break:,\xeCJK_no_break:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_allow_break:
+ { \tex_penalty:D \c_zero_int }
+\cs_new_protected_nopar:Npn \xeCJK_no_break:
+ { \tex_penalty:D \c_@@_nobreak_penalty_int }
+\int_const:Nn \c_@@_nobreak_penalty_int { 10 000 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {\@@_at_end_preamble:n,\@@_after_preamble:n,\@@_after_end_preamble:n}
+% 在 \tn{document} 前后加上各种钩子。
+% \begin{macrocode}
+\tl_new:N \g_@@_at_end_preamble_hook_tl
+\tl_new:N \g_@@_after_preamble_hook_tl
+\tl_new:N \g_@@_after_end_preamble_hook_tl
+\cs_new_protected:Npn \@@_at_end_preamble:n #1
+ { \tl_gput_right:Nn \g_@@_at_end_preamble_hook_tl {#1} }
+\cs_new_protected:Npn \@@_after_preamble:n #1
+ { \tl_gput_right:Nn \g_@@_after_preamble_hook_tl {#1} }
+\cs_new_protected:Npn \@@_after_end_preamble:n #1
+ { \tl_gput_right:Nn \g_@@_after_end_preamble_hook_tl {#1} }
+\xeCJK_if_package_loaded:nTF { etoolbox }
+ {
+ \AtEndPreamble { \g_@@_at_end_preamble_hook_tl }
+ \AfterPreamble { \g_@@_after_preamble_hook_tl }
+ \AfterEndPreamble { \g_@@_after_end_preamble_hook_tl }
+ }
+ {
+ \AtBeginDocument { \g_@@_after_preamble_hook_tl }
+ \cs_new_protected_nopar:Npn \xeCJK@document@left@hook
+ { \group_end: \g_@@_at_end_preamble_hook_tl \group_begin: }
+ \cs_new_protected_nopar:Npn \xeCJK@document@right@hook
+ { \scan_stop: \g_@@_after_end_preamble_hook_tl \tex_ignorespaces:D }
+ \cs_gset_nopar:Npx \document
+ {
+ \xeCJK@document@left@hook
+ \exp_not:o { \document }
+ \xeCJK@document@right@hook
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.7}{2013/11/09}{使用 \pkg{everypage} 往 \tn{shipout} 盒子里加钩子。}
+% \changes{v3.2.16}{2014/12/16}{不再依赖 \pkg{everypage} 宏包。}
+%
+% \begin{macro}{\xeCJKShipoutHook}
+% 在 \tn{shipout} 盒子里加钩子,可以影响到页眉页脚。\tn{AtBeginDvi} 将参数保存在
+% 盒子中,而 \pkg{atbegshi} 的 \tn{AtBeginShipout} 在 \tn{shipout} 盒子构建好之后
+% 才起作用,所以它们都影响不到页眉页脚。我们通过往 \tn{@begindvi} 里加入钩子来完成。
+% 注意,第一次使用 \tn{@begindvi} 之后,它会将自身定义为 \tn{@empty}。
+% \begin{macrocode}
+\@@_after_preamble:n
+ { \tl_put_right:Nn \@begindvi { \xeCJK@first@begindvi } }
+\cs_new_protected_nopar:Npn \xeCJK@first@begindvi
+ {
+ \xeCJKShipoutHook
+ \cs_if_exist:NTF \@begindvi
+ { \tl_gput_right:Nn }
+ { \tl_const:Nn }
+ \@begindvi { \xeCJKShipoutHook }
+ }
+\NewDocumentCommand \xeCJKShipoutHook { }
+ {
+ \bool_if:NF \l_@@_shipout_hook_bool
+ {
+ \bool_set_true:N \l_@@_shipout_hook_bool
+ \tl_use:N \l_@@_shipout_hook_tl
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_add_to_shipout:n}
+% \changes{v3.2.11}{2014/03/14}{不再使用内部名字。}
+% 往 \tn{shipout} 盒子中加入钩子。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_add_to_shipout:n
+ { \tl_put_right:Nn \l_@@_shipout_hook_tl }
+\tl_new:N \l_@@_shipout_hook_tl
+\bool_new:N \l_@@_shipout_hook_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]
+% {\xeCJK_tl_remove_outer_braces:N,\xeCJK_tl_remove_outer_braces:n}
+% \changes{v3.2.4}{2013/07/02}{去掉外层分组括号时,移除空格,避免死循环。}
+% 去掉 |#1| 外层的分组括号。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_tl_remove_outer_braces:N #1
+ { \tl_set:Nx #1 { \exp_args:No \xeCJK_tl_remove_outer_braces:n {#1} } }
+\cs_new:Npn \xeCJK_tl_remove_outer_braces:n #1
+ {
+ \exp_last_unbraced:Nf
+ \@@_tl_remove_outer_braces:w { \tl_trim_spaces:n {#1} } \s__stop
+ }
+\cs_new:Npn \@@_tl_remove_outer_braces:w #1 \s__stop
+ {
+ \tl_if_single:nTF {#1}
+ {
+ \tl_if_head_is_N_type:nTF {#1}
+ { \tl_trim_spaces:n }
+ { \xeCJK_tl_remove_outer_braces:n }
+ }
+ { \tl_trim_spaces:n }
+ {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_cs_clear:N,\xeCJK_cs_gclear:N}
+% 让控制序列的意义为空。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_cs_clear:N #1
+ { \cs_set_eq:NN #1 \prg_do_nothing: }
+\cs_new_protected:Npn \xeCJK_cs_gclear:N #1
+ { \cs_gset_eq:NN #1 \prg_do_nothing: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_swap_cs:NN}
+% 交换 |#1| 和 |#2| 的意义。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_swap_cs:NN #1#2
+ {
+ \cs_set_eq:NN \@@_swap_cs_aux:w #1
+ \cs_set_eq:NN #1 #2
+ \cs_set_eq:NN #2 \@@_swap_cs_aux:w
+ \cs_undefine:N \@@_swap_cs_aux:w
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_font_gset_to_current:c}
+% |#1| 是控制序列的名字,令它等于当前字体命令。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_font_gset_to_current:c #1
+ {
+ \exp_last_unbraced:Nco \cs_gset_eq:NN
+ {#1} \tex_the:D \tex_font:D
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int,pTF]{\xeCJK_glyph_if_exist:N}
+% \changes{v3.1.0}{2012/11/19}{改进 \pkg{fontspec} 宏包中定义的
+% \cs{font_glyph_if_exist:NnTF}。}
+% 判断当前字体中是否含有字符 |#1|。\pkg{fontspec} 中的类似函数在判断为真的时候,
+% 会留有一个 \cs{scan_stop:},造成不必要的边界,同时也不完全可展。因此,我们重新
+% 定义它。
+% \begin{macrocode}
+\prg_new_conditional:Npnn \xeCJK_glyph_if_exist:N #1 { p , T , F , TF }
+ {
+ \tex_iffontchar:D \tex_font:D `#1 \exp_stop_f:
+ \prg_return_true: \else: \prg_return_false: \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}[int]{\c_xeCJK_space_skip_tl}
+% \changes{v3.1.0}{2012/11/18}{字间空格考虑 \tn{spaceskip} 不为零的情况。}
+% \changes{v3.2.0}{2013/05/22}{字间空格考虑到 \tn{spacefactor} 和 \tn{xspaceskip} 的情况。}
+% 当前字体状态下,一个字间空格产生的 |glue| 的长度,包括伸展和收缩部分。
+% \begin{macrocode}
+\tl_const:Nn \c_xeCJK_space_skip_tl
+ {
+ \int_compare:nNnTF \g_@@_space_factor_int = { 1000 }
+ {
+ \skip_if_eq:nnTF \tex_spaceskip:D \c_zero_skip
+ {
+ \tex_fontdimen:D 2 ~ \tex_font:D
+ plus \tex_fontdimen:D 3 ~ \tex_font:D
+ minus \tex_fontdimen:D 4 ~ \tex_font:D
+ }
+ { \tex_spaceskip:D }
+ }
+ {
+ \skip_if_eq:nnTF \tex_spaceskip:D \c_zero_skip
+ {
+ \int_compare:nNnTF \g_@@_space_factor_int < { 2000 }
+ {
+ \_@@_space_skip_scale:nnn
+ { \tex_fontdimen:D 2 ~ \tex_font:D }
+ }
+ {
+ \skip_if_eq:nnTF \tex_xspaceskip:D \c_zero_skip
+ {
+ \_@@_space_skip_scale:nnn
+ {
+ \tex_fontdimen:D 2 ~ \tex_font:D +
+ \tex_fontdimen:D 7 ~ \tex_font:D
+ }
+ }
+ { \tex_xspaceskip:D \use_none:nn }
+ }
+ { \tex_fontdimen:D 3 ~ \tex_font:D }
+ { \tex_fontdimen:D 4 ~ \tex_font:D }
+ }
+ {
+ \int_compare:nNnTF \g_@@_space_factor_int < { 2000 }
+ { \_@@_space_skip_scale:nnn { \tex_spaceskip:D } }
+ {
+ \skip_if_eq:nnTF \tex_xspaceskip:D \c_zero_skip
+ {
+ \_@@_space_skip_scale:nnn
+ {
+ \tex_spaceskip:D +
+ \tex_fontdimen:D 7 ~ \tex_font:D
+ }
+ }
+ { \tex_xspaceskip:D \use_none:nn }
+ }
+ { \tex_gluestretch:D \tex_spaceskip:D }
+ { \tex_glueshrink:D \tex_spaceskip:D }
+ }
+ }
+ }
+\cs_new_nopar:Npn \_@@_space_skip_scale:nnn #1#2#3
+ {
+ \dim_eval:n {#1}
+ plus \fp_eval:n { \g_@@_space_factor_int / 1000 } #2
+ minus
+ \int_div_truncate:nn
+ { 1000 * \int_value:w #3 } { \g_@@_space_factor_int } sp
+ }
+\int_new:N \g_@@_space_factor_int
+\int_gset:Nn \g_@@_space_factor_int { 1000 }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\xeCJK_glue_to_skip:nN}
+% 取得一个 |glue| 的长度,包括伸展和收缩部分。如果参数不是 |glue|,则取其宽度。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_glue_to_skip:nN #1#2
+ {
+ \group_begin:
+ \hbox_set:Nw \l_@@_tmp_box #1 \scan_stop:
+ \int_compare:nNnTF \tex_lastnodetype:D = { 11 }
+ {
+ \exp_args:NNNo \hbox_set_end:
+ \skip_set:Nn #2 { \skip_use:N \tex_lastskip:D }
+ }
+ {
+ \exp_args:NNNo \hbox_set_end:
+ \skip_set:Nn #2 { \dim_use:N \box_wd:N \l_@@_tmp_box }
+ }
+ \exp_args:NNNo \group_end:
+ \skip_set:Nn #2 { \skip_use:N #2 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF,int]{\xeCJK_if_blank_x:n}
+% 判断是否为空或者仅含一个空格。
+% \begin{macrocode}
+\prg_new_conditional:Npnn \xeCJK_if_blank_x:n #1 { p , T , F , TF }
+ {
+ \if_case:w \tex_strcmp:D { } {#1} \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \if_case:w \tex_strcmp:D { ~ } {#1} \exp_stop_f:
+ \prg_return_true: \else: \prg_return_false: \fi:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_int_until_do:nn}
+% \begin{macro}{\@@_int_until_do:wn}
+% 由于定义较为简单,可以比 \cs{int_until_do:nNnn} 稍微快一点点。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_int_until_do:nn #1#2
+ {
+ \@@_int_until_do:wn \use_none:n
+ { \reverse_if:N \if_int_compare:w #1#2 }
+ }
+\cs_new_protected:Npn \@@_int_until_do:wn \use_none:n #1
+ { #1 \exp_after:wN \@@_int_until_do:wn \fi: \use_none:n {#1} }
+\int_new:N \l_@@_begin_int
+\int_new:N \l_@@_end_int
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_peek_catcode_ignore_spaces:NTF}
+% \changes{v3.1.1}{2012/12/04}{新增有省略空格标识的 \texttt{peek} 函数。}
+% 我们在里面设置了一个变量 \cs{l_@@_peek_ignore_spaces_bool} 用于标识后面的空格
+% 是否被省略掉了。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_peek_catcode_ignore_spaces:NTF #1#2#3
+ {
+ \cs_set_eq:NN \l_@@_peek_search_token #1 \scan_stop:
+ \tl_set:Nn \@@_peek_catcode_true:w { \group_align_safe_end: #2 }
+ \tl_set:Nn \@@_peek_catcode_false:w { \group_align_safe_end: #3 }
+ \bool_set_false:N \l_@@_peek_ignore_spaces_bool
+ \group_align_safe_begin:
+ \peek_after:Nw \@@_peek_catcode_ignore_spaces_branches:w
+ }
+\cs_new_protected_nopar:Npn \@@_peek_catcode_ignore_spaces_branches:w
+ {
+ \if_meaning:w \l_peek_token \c_space_token
+ \bool_set_true:N \l_@@_peek_ignore_spaces_bool
+ \exp_after:wN \peek_after:Nw
+ \exp_after:wN \@@_peek_catcode_ignore_spaces_branches:w
+ \tex_romannumeral:D 0
+ \else:
+ \if_catcode:w
+ \exp_not:N \l_peek_token \exp_not:N \l_@@_peek_search_token
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \@@_peek_catcode_true:w
+ \else:
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \@@_peek_catcode_false:w
+ \fi:
+ \fi:
+ }
+\cs_new_eq:NN \l_@@_peek_search_token ?
+\tl_new:N \@@_peek_catcode_true:w
+\tl_new:N \@@_peek_catcode_false:w
+\bool_new:N \l_@@_peek_ignore_spaces_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_peek_after_ignore_spaces:nw}
+% 与 \tn{@ifnextchar} 和 \tn{futurenonspacelet} 类似,会省略掉后面的空格。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_peek_after_ignore_spaces:nw #1
+ {
+ \tl_set:Nn \@@_peek_after_do:w { \group_align_safe_end: #1 }
+ \group_align_safe_begin:
+ \peek_after:Nw \@@_peek_ignore_spaces_branches:w
+ }
+\cs_new_protected_nopar:Npn \@@_peek_ignore_spaces_branches:w
+ {
+ \if_meaning:w \l_peek_token \c_space_token
+ \exp_after:wN \peek_after:Nw
+ \exp_after:wN \@@_peek_ignore_spaces_branches:w
+ \tex_romannumeral:D 0
+ \else:
+ \exp_after:wN \@@_peek_after_do:w
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_token_value_class:N}
+% 用于取得记号 |#1| 所在的 \XeTeX 字符类。|#1| 应为 \tn{catcode} 为 |11| 或 |12|
+% 的显性或隐性记号。
+% \begin{macrocode}
+\cs_new_nopar:Npn \xeCJK_token_value_class:N #1
+ { \tex_XeTeXcharclass:D \xeCJK_token_value_charcode:N #1 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_token_value_charcode:N}
+% \changes{v3.2.4}{2013/06/30}{考虑 \texttt{charcode} 超出 BMP 的情况。}
+% \changes{v3.3.1}{2015/05/08}{\texttt{0.99992} 版修复了 \tn{meaning} 的 Bug。}
+% 当记号 |#1| 的 \texttt{charcode} 大于等于 \texttt{0x10000} 时,\XeTeX\
+% \texttt{0.9999.0} 版以前的 \tn{meaning} 的返回结果比较特殊\footnote{参见
+% \url{http://tug.org/pipermail/xetex/2013-January/023967.html} 和
+% \url{http://tex.stackexchange.com/a/64848}。},需要特别处理。
+% \texttt{0.9999.0} 版以后的 \XeTeX 的 \tn{meaning}
+% 对于超出 BMP 的字符,会返回两个字符,分别对应于其 UTF-16 编码的首尾代理^^A
+% \footnote{参见 \url{http://tug.org/pipermail/xetex/2013-June/024543.html}。}。
+% 这一 Bug 在 TeX Live 2015 的 \texttt{0.99992} 版中得到修复^^A
+% \footnote{参见\url{http://tug.org/pipermail/xetex/2015-May/025941.html}}。
+% \begin{macrocode}
+\cs_new_nopar:Npn \xeCJK_token_value_charcode:N #1
+ { \exp_after:wN \@@_get_charcode:w \token_to_meaning:N #1 \q_stop }
+\group_begin:
+ \cs_set:Npn \@@_tmp:w #1 ~ #2 ~ #3#4#5 \q_stop
+ {
+ \tl_if_empty:nTF { #4#5 }
+ {
+ \cs_new_nopar:Npn \@@_get_charcode:w ##1 ~ ##2 ~ ##3 \q_stop
+ { \int_eval:n { `##3 } }
+ }
+ {
+ \tl_if_empty:nTF {#5}
+ {
+ \cs_new_nopar:Npn \@@_get_charcode:w ##1 ~ ##2 ~ ##3##4 \q_stop
+ {
+ \int_eval:n
+ {
+ \tl_if_empty:nTF { ##4 }
+ { `##3 }
+ { ( `##3 - "D800 ) * "400 + ( `##4 - "DC00 ) + "10000 }
+ }
+ }
+ }
+ {
+ \cs_new_nopar:Npn \@@_get_charcode:w ##1 ~ ##2 ~ ##3##4 \q_stop
+ { \int_eval:n { \tl_if_empty:nTF { ##4 } { `##3 } { "20000 } } }
+ }
+ }
+ }
+ \exp_after:wN \@@_tmp:w \token_to_meaning:N ^^^^^20000 { } \q_stop
+\group_end:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF,int]{\xeCJK_if_CJK_class:N}
+% 判断字符 |#1| 是否为 CJK 字符类,包括文字和标点符号。
+% \begin{macrocode}
+\prg_new_conditional:Npnn \xeCJK_if_CJK_class:N #1 { p , T , F , TF }
+ {
+ \if_cs_exist:w
+ \@@_CJK_class_tl:n { \xeCJK_token_value_class:N #1 }
+ \cs_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+ }
+\cs_new_nopar:Npn \@@_CJK_class_tl:n #1
+ { c_@@_CJK_class_ \int_eval:n {#1} _tl }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF,int]{\xeCJK_if_same_class:NN}
+% 判断两个字符是否同属于一个字符类。
+% \begin{macrocode}
+\prg_new_conditional:Npnn \xeCJK_if_same_class:NN #1#2 { p , T , F , TF }
+ {
+ \if_int_compare:w \xeCJK_token_value_class:N #1 =
+ \xeCJK_token_value_class:N #2 \exp_stop_f:
+ \prg_return_true: \else: \prg_return_false: \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_make_boundary:}
+% 利用 \cs{scan_stop:} 结束 CJK 分组,用于恢复字体等。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_make_boundary:
+ { \bool_if:NT \l_@@_CJK_group_bool { \scan_stop: } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{功能开关}
+%
+% \begin{macro}{xeCJKactive}
+% 事实上,将开启或关闭 \XeTeX 的整个字符类机制。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ xeCJKactive .choice: ,
+ xeCJKactive / true .code:n = { \makexeCJKactive } ,
+ xeCJKactive / false .code:n = { \makexeCJKinactive } ,
+ xeCJKactive .default:n = { true }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\makexeCJKactive, \makexeCJKinactive}
+% \begin{macrocode}
+\NewDocumentCommand \makexeCJKactive { }
+ { \tex_XeTeXinterchartokenstate:D = \c_one_int }
+\NewDocumentCommand \makexeCJKinactive { }
+ { \tex_XeTeXinterchartokenstate:D = \c_zero_int }
+% \end{macrocode}
+% \end{macro}
+%
+% 抑制 |BOM|。
+% \begin{macrocode}
+\char_set_catcode_ignore:n { "FEFF }
+% \end{macrocode}
+%
+% \subsection{字符类别设定}\label{sec:xeCJK-class-set}
+%
+% \begin{variable}{\g_@@_class_seq,\g_@@_new_class_seq}
+% 分别用于记录在 \pkg{xeCJK} 中使用的字符类别名称和新建的字符类别的编号。
+% \begin{macrocode}
+\seq_new:N \g_@@_class_seq
+\seq_new:N \g_@@_new_class_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\xeCJK_new_class:n}
+% 新建一个字符类别。|#1| 是自定义名称。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_new_class:n #1
+ {
+ \int_if_exist:cTF { \@@_class_csname:n {#1} }
+ { \@@_error:nx { class-already-defined } {#1} }
+ {
+ \exp_args:Nc \newXeTeXintercharclass
+ { \@@_class_csname:n {#1} }
+ \clist_new:c { g_@@_#1_range_clist }
+ \seq_gput_right:Nn \g_@@_class_seq {#1}
+ \seq_gput_right:Nv \g_@@_new_class_seq
+ { \@@_class_csname:n {#1} }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_save_class:nn}
+% \changes{v3.1.1}{2012/12/06}
+% {使用 \cs{xeCJK_save_class:nn} 保存 \XeTeX 预定义的字符类别。}
+% 保存 \XeTeX 预定义的字符类别。|#1| 是自定义名称,|#2| 是编号。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_save_class:nn #1#2
+ {
+ \int_if_exist:cTF { \@@_class_csname:n {#1} }
+ { \@@_error:nx { class-already-defined } {#1} }
+ {
+ \int_const:cn { \@@_class_csname:n {#1} } {#2}
+ \clist_new:c { g_@@_#1_range_clist }
+ \seq_gput_right:Nn \g_@@_class_seq {#1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_class_csname:n}
+% 字符类名称对应的控制序列名字。
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_class_csname:n #1 { c_@@_#1_class_int }
+\cs_new_eq:cN { \@@_class_csname:n { Others } } \l_@@_tmp_int
+\@@_msg_new:nn { class-already-defined }
+ {
+ XeTeX~character~class~`#1'~has~been~already~defined.\\\\
+ Please~take~another~name. \\
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.0}{2013/05/20}{增加 \texttt{IVS} 字符类用于处理异体字选择符。}
+% \changes{v3.3.1}{2015/01/22}{\texttt{IVS} 字符类更名为 \texttt{CM}。}
+%
+% \pkg{xeCJK} 需要以下字符类别用于字符输出。其中 |Default|、|CJK|、|FullLeft|、
+% |FullRight|、|Boundary| 为 \XeTeX\ 中预定义的类别,\pkg{xeCJK} 新增加了\
+% |HalfLeft|、|HalfRight|、|NormalSpace| 和 |CM|。其中异体字选择符
+% (Ideographic Variation Selectors)\footnote{\url{http://www.unicode.org/reports/tr37/}}
+% 需要 \XeTeX\ |0.9999.0| 以上的版本^^A
+% \footnote{\url{http://tug.org/pipermail/xetex/2013-March/024118.html}}和相关字体的支持。
+% \begin{center}\xeCJKsetup{PunctStyle=hangmobanjiao}
+% \begin{tabular}{cll}
+% \toprule
+% 类别 & 说明 & 例子 \\ \midrule
+% |Default| & 西文一般符号 & abc123 \\
+% |CJK| & CJK 表意符号 & 汉字ぁぃぅ \\
+% |FullLeft| & 全角左标点 & (《:“ \\
+% |FullRight| & 全角右标点 & ,。)》” \\
+% |HalfLeft| & 半角左标点 & ( [ \{ \\
+% |HalfRight| & 半角右标点 & , . ? ) ] \} \\
+% |NormalSpace| & 前后原始间距的符号 & / \\
+% |Boundary| & 边界 & 空格 \\
+% |CM| & 组合标识 & 异体字选择符\\
+% |HangulJamo| & 朝鲜文字母 & |ᄻ||ᆟ||ᇫ|\\
+% \bottomrule
+% \end{tabular}
+% \end{center}
+%
+% \changes{v3.3.3}{2016/01/20}{兼容 \LaTeXe{} 2016/02/01 的字符类设置。}
+% \changes{v3.3.4}{2016/02/07}{兼容 \XeTeX{} 0.99994 的边界字符类。}
+% \begin{macro}[int]{Default,CJK,FullLeft,FullRight,Boundary}
+% \begin{macrocode}
+\xeCJK_save_class:nn { Default } { 0 }
+% \end{macrocode}
+% \XeTeX{} 0.99994 将字符类总数扩大到 $4096$^^A
+% \footnote{\url{http://tug.org/pipermail/xetex/2016-February/026363.html}}。
+% \begin{macrocode}
+\str_const:Nx \c_@@_xetex_version_str
+ { \int_use:N \tex_XeTeXversion:D \tex_XeTeXrevision:D }
+\fp_compare:nNnTF { \c_@@_xetex_version_str } > { 0.99993 }
+ { \xeCJK_save_class:nn { Boundary } { 4095 } }
+ { \xeCJK_save_class:nn { Boundary } { 255 } }
+% \end{macrocode}
+% \LaTeXe{} 2016/02/01 不再预设置 CJK 字符类。
+% \begin{macrocode}
+\int_compare:nNnTF { \tex_XeTeXcharclass:D "4E00 } = \c_one_int
+ {
+ \xeCJK_save_class:nn { CJK } { 1 }
+ \xeCJK_save_class:nn { FullLeft } { 2 }
+ \xeCJK_save_class:nn { FullRight } { 3 }
+ \int_const:Nn \c_@@_class_begin_int { 3 }
+ }
+ {
+ \xeCJK_new_class:n { CJK }
+ \xeCJK_new_class:n { FullLeft }
+ \xeCJK_new_class:n { FullRight }
+ \int_const:Nn \c_@@_class_begin_int { 0 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.15}{2014/11/10}{增加 \texttt{HangulJamo} 字符类。}
+%
+% \begin{macro}[int]{HalfLeft,HalfRight,NormalSpace,CM,HangulJamo}
+% 新增西文半角左/右标点、前后原始间距的符号和异体字选择符类。
+% \begin{macrocode}
+\xeCJK_new_class:n { HalfLeft }
+\xeCJK_new_class:n { HalfRight }
+\xeCJK_new_class:n { NormalSpace }
+\xeCJK_new_class:n { CM }
+\xeCJK_new_class:n { HangulJamo }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.11}{2014/04/10}
+% {左右角括号 \texttt{U+2329} 和 \texttt{U+232A} 是西文标点符号。}
+% \changes{v3.2.15}{2014/11/09}
+% {把 REVERSE SOLIDUS(\texttt{U+005C})、HYPHEN-MINUS(\texttt{U+002D})和
+% EN DASH(\texttt{U+2013})归入 \texttt{NormalSpace} 类。}
+%
+% \begin{variable}
+% {\c_@@_HalfLeft_chars_clist,\c_@@_HalfRight_chars_clist,\c_@@_NormalSpace_chars_clist}
+% \hypertarget{CJKcharclass}{西文半角左/右标点和前后原始间距的字符类。}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_HalfLeft_chars_clist
+ { "28 , "5B , "60 , "7B , "2329 }
+\clist_const:Nn \c_@@_HalfRight_chars_clist
+ { "21 , "22 , "25 , "27 , "29 , "2C , "2E , "3A , "3B , "3F , "5D , "7D , "232A }
+\clist_const:Nn \c_@@_NormalSpace_chars_clist { "2D , "2F , "5C }
+% \end{macrocode}
+% \end{variable}
+%
+% 以下对全角标点符号的归类来源于 \XeTeX 的脚本
+% \href{http://sourceforge.net/p/xetex/code/ci/master/tree/source/texk/web2c/xetexdir/unicode-char-prep.pl}
+% {\file{unicode-char-prep.pl}} 和 Unicode 数据库\footnote{\url{http://www.unicode.org/reports/tr14/}}。
+%
+% \changes{v3.2.3}{2013/06/09}{根据 \XeTeX 的脚本重新整理全角标点符号。}
+%
+% \begin{variable}{\c_@@_OP_chars_clist}
+% Open Punctuation (OP)
+% \PrintPunctList{OP}{Open Punctuation}
+% 以下代码的第一行是中西文共用的左引号。
+% \begin{macrocode}
+\clist_const:Nn \c_@@_OP_chars_clist
+ {
+ "2018 , "201C ,
+ "3008 , "300A , "300C , "300E , "3010 , "3014 , "3016 , "3018 , "301A , "301D ,
+ "FE17 , "FE35 , "FE37 , "FE39 , "FE3B , "FE3D , "FE3F , "FE41 , "FE43 , "FE47 ,
+ "FE59 , "FE5B , "FE5D , "FF08 , "FF3B , "FF5B , "FF5F , "FF62
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_PR_chars_clist}
+% \changes{v3.3.0}{2014/12/26}{不把 \texttt{U+20A9} 归入 CJK 的 PR 类。}
+% Prefix Numeric (PR)
+% \PrintPunctList{PR}{Prefix Numeric}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_PR_chars_clist
+ { "FE69 , "FF04 , "FFE1 , "FFE5 , "FFE6 }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_FullLeft_chars_clist}
+% 以上两类标点符号出现在文字的左边,不应出现在行尾位置。
+% \begin{macrocode}
+\clist_new:N \c_@@_FullLeft_chars_clist
+\clist_gconcat:NNN \c_@@_FullLeft_chars_clist
+ \c_@@_OP_chars_clist
+ \c_@@_PR_chars_clist
+% \end{macrocode}
+% \end{variable}
+%
+% \changes{v3.3.3}{2015/12/12}
+% {把 EN DASH(\texttt{U+2013})作为半字线连接号归入 \texttt{FullRight} 类。}
+% \changes{v3.3.3}{2015/12/12}
+% {不再把 \texttt{U+2015} 和 \texttt{U+2500} 归入 \texttt{FullRight} 类。}
+% \changes{v3.6.0}{2018/01/14}
+% {把 TWO-EM DASH (\texttt{U+2E3A}) 归入 \texttt{FullRight} 类和设为
+% \texttt{LongPunct} 与 \texttt{MiddlePunct}。}
+%
+% \begin{variable}{\c_@@_CL_chars_clist}
+% Close Punctuation (CL)
+% \PrintPunctList{CL}{Close Punctuation}
+% 以下代码的第一行是中西文共用的一些标点符号。
+% \begin{macrocode}
+\clist_const:Nn \c_@@_CL_chars_clist
+ {
+ "00B7 , "2019 , "201D , "2013 , "2014 , "2025 , "2026 , "2027 , "2E3A ,
+ "3001 , "3002 , "3009 , "300B , "300D , "300F , "3011 , "3015 , "3017 , "3019 ,
+ "301B , "301E , "301F , "FE11 , "FE12 , "FE18 , "FE36 , "FE38 , "FE3A , "FE3C ,
+ "FE3E , "FE40 , "FE42 , "FE44 , "FE48 , "FE50 , "FE52 , "FE5A , "FE5C , "FE5E ,
+ "FF09 , "FF0C , "FF0E , "FF3D , "FF5D , "FF60 , "FF61 , "FF63 , "FF64
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \changes{v3.3.0}{2014/12/26}{不把 NS 类中的一些有禁则的日文归入 \texttt{FullRight} 类。}
+% \changes{v3.6.0}{2018/01/14}
+% {将全角浪线 \texttt{U+FF5E} 等连接号归入 \texttt{FullRight} 类和设为 \texttt{MiddlePunct}。}
+%
+% \begin{variable}{\c_@@_NS_chars_clist}
+% Nonstarter (NS)
+% \PrintPunctList{NS}{Nonstarter}
+% \noindent Hyphens (cl-03)
+% \PrintPunctList{hyphens}{Hyphens}
+% \noindent Iteration marks (cl-09)
+% \PrintPunctList{iteration_marks}{Iteration marks}
+% 根据 W3C 的资料\footnote{\url{http://www.w3.org/TR/jlreq/}},\texttt{cl-03} 和
+% \texttt{cl-09} 在非常松散的情况下可以没有禁则。我们仅将全角浪线 \texttt{U+FF5E} 等连接号归入
+% \texttt{FullRight} 类并在宏包末尾设为 \texttt{MiddlePunct}。
+% \begin{macrocode}
+\clist_const:Nn \c_@@_hyphens_chars_clist
+ { "301C , "30A0 , "FF5E }
+\clist_const:Nn \c_@@_iteration_marks_chars_clist
+ { "3005 , "303B , "309D , "309E , "30FD , "30FE }
+\clist_const:Nn \c_@@_NS_chars_clist
+ { "30FB , "FE54 , "FE55 , "FF1A , "FF1B , "FF65 , "16FE0 }
+\AtEndOfPackage
+ {
+ \cs_set:Npn \@@_tmp:w #1
+ { \char_generate:nn {#1} { 12 } }
+ \@@_add_special_punct:nn { middle }
+ { \clist_map_function:NN \c_@@_hyphens_chars_clist \@@_tmp:w }
+ \cs_undefine:N \@@_tmp:w
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_EX_chars_clist}
+% Exclamation/Interrogation (EX)
+% \PrintPunctList{EX}{Exclamation/Interrogation}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_EX_chars_clist
+ { "FE15 , "FE16 , "FE56 , "FE57 , "FF01 , "FF1F }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_IS_chars_clist}
+% Infix Numeric Separator (IS)
+% \PrintPunctList{IS}{Infix Numeric Separator}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_IS_chars_clist { "FE10 , "FE13 , "FE14 }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_CJ_chars_clist}
+% Conditional Japanese Starter (CJ)。这类字符的禁则是可选的^^A
+% \footnote{\url{https://github.com/CTeX-org/ctex-kit/issues/165}},
+% 为实现的简单计,我们把它们归入 CJK 类,即没有禁则。
+% \PrintPunctList{CJ}{Conditional Japanese Starter}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_CJ_chars_clist
+ {
+ "3041 , "3043 , "3045 , "3047 , "3049 , "3063 , "3083 , "3085 , "3087 , "308E ,
+ "3095 , "3096 , "30A1 , "30A3 , "30A5 , "30A7 , "30A9 , "30C3 , "30E3 , "30E5 ,
+ "30E7 , "30EE , "30F5 , "30F6 , "30FC , "31F0 , "31F1 , "31F2 , "31F3 , "31F4 ,
+ "31F5 , "31F6 , "31F7 , "31F8 , "31F9 , "31FA , "31FB , "31FC , "31FD , "31FE ,
+ "31FF , "FF67 , "FF68 , "FF69 , "FF6A , "FF6B , "FF6C , "FF6D , "FF6E , "FF6F ,
+ "FF70
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_PO_chars_clist}
+% Postfix Numeric (PO)
+% \PrintPunctList{PO}{Postfix Numeric}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_PO_chars_clist { "FE6A , "FF05 , "FFE0 }
+% \end{macrocode}
+% \end{variable}
+%
+% \changes{v3.3.0}{2014/12/26}{不把小写日文假名归入 \texttt{FullRight} 类。}
+%
+% \begin{variable}{\c_@@_FullRight_chars_clist}
+% 以上六类标点符号出现在文字的右边,不应出现在行首位置。
+% \begin{macrocode}
+\clist_new:N \c_@@_FullRight_chars_clist
+\tl_map_inline:nn
+ {
+ \c_@@_CL_chars_clist
+ \c_@@_NS_chars_clist
+ \c_@@_EX_chars_clist
+ \c_@@_IS_chars_clist
+ \c_@@_PO_chars_clist
+ \c_@@_hyphens_chars_clist
+ }
+ {
+ \clist_gconcat:NNN \c_@@_FullRight_chars_clist
+ \c_@@_FullRight_chars_clist #1
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \changes{v3.3.3}{2015/06/25}{补充 Ext-E。}
+% \changes{v3.4.1}{2016/08/18}{补充 Unicode 9.0.0 的西夏文。}
+% \changes{v3.5.0}{2017/07/22}{补充 Ext-F。}
+% \changes{v3.7.3}{2019/04/15}{补充日文假名扩展。}
+%
+% \begin{variable}{\c_@@_CJK_chars_clist}
+% CJK 字符类,包括文字和标点符号。
+% \begin{macrocode}
+\clist_const:Nn \c_@@_CJK_chars_clist
+ {
+% \end{macrocode}
+% \begin{itemize}[nosep,leftmargin=0pt]
+% \item CJK Radicals Supplement (中日韩部首补充)
+% \begin{macrocode}
+ "2E80 -> "2EFF ,
+% \end{macrocode}
+% \item Kangxi Radicals (康熙部首)
+% \begin{macrocode}
+ "2F00 -> "2FDF ,
+% \end{macrocode}
+% \item Ideographic Description Characters (表意文字描述符)
+% \begin{macrocode}
+ "2FF0 -> "2FFF ,
+% \end{macrocode}
+% \item CJK Symbols and Punctuation (中日韩符号和标点)
+% \begin{macrocode}
+ "3000 -> "303F ,
+% \end{macrocode}
+% \item Hiragana (日文平假名)
+% \begin{macrocode}
+ "3040 -> "309F ,
+% \end{macrocode}
+% \item Katakana (日文片假名)
+% \begin{macrocode}
+ "30A0 -> "30FF ,
+% \end{macrocode}
+% \item Bopomofo (注音字母)
+% \begin{macrocode}
+ "3100 -> "312F ,
+% \end{macrocode}
+% \item Hangul Compatibility Jamo (谚文兼容字母)
+% \begin{macrocode}
+ "3130 -> "318F ,
+% \end{macrocode}
+% \item Kanbun (象形字注释标志)
+% \begin{macrocode}
+ "3190 -> "319F ,
+% \end{macrocode}
+% \item Bopomofo Extended (注音字母扩展)
+% \begin{macrocode}
+ "31A0 -> "31BF ,
+% \end{macrocode}
+% \item CJK Strokes (中日韩笔画)
+% \begin{macrocode}
+ "31C0 -> "31EF ,
+% \end{macrocode}
+% \item Katakana Phonetic Extensions (日文片假名语音扩展)
+% \begin{macrocode}
+ "31F0 -> "31FF ,
+% \end{macrocode}
+% \item Enclosed CJK Letters and Months (带圈中日韩字母和月份)
+% \begin{macrocode}
+ "3200 -> "32FF ,
+% \end{macrocode}
+% \item CJK Compatibility (中日韩兼容)
+% \begin{macrocode}
+ "3300 -> "33FF ,
+% \end{macrocode}
+% \item CJK Unified Ideographs Extension-A (中日韩统一表意文字扩展 A)
+% \begin{macrocode}
+ "3400 -> "4DBF ,
+% \end{macrocode}
+% \item Yijing Hexagrams Symbols (易经六十四卦符号)
+% \begin{macrocode}
+ "4DC0 -> "4DFF ,
+% \end{macrocode}
+% \item CJK Unified Ideographs (中日韩统一表意文字)
+% \begin{macrocode}
+ "4E00 -> "9FFF ,
+% \end{macrocode}
+% \item Yi Syllables (彝文音节)
+% \begin{macrocode}
+ "A000 -> "A48F ,
+% \end{macrocode}
+% \item Yi Radicals (彝文字根)
+% \begin{macrocode}
+ "A490 -> "A4CF ,
+% \end{macrocode}
+% \item Hangul Syllables (谚文音节)
+% \begin{macrocode}
+ "AC00 -> "D7AF ,
+% \end{macrocode}
+% \item CJK Compatibility Ideographs (中日韩兼容表意文字)
+% \begin{macrocode}
+ "F900 -> "FAFF ,
+% \end{macrocode}
+% \item Vertical Forms (竖排形式)
+% \begin{macrocode}
+ "FE10 -> "FE1F ,
+% \end{macrocode}
+% \item CJK Compatibility Forms (中日韩兼容形式)
+% \begin{macrocode}
+ "FE30 -> "FE4F ,
+% \end{macrocode}
+% \item Halfwidth and Fullwidth Forms (半角及全角形式)
+% \begin{macrocode}
+ "FF00 -> "FFEF ,
+% \end{macrocode}
+% \item Ideographic Symbols and Punctuation (表意文字符号及标点)
+% \begin{macrocode}
+ "16FE0 -> "16FFF ,
+% \end{macrocode}
+% \item Tangut (西夏文)
+% \begin{macrocode}
+ "17000 -> "187FF ,
+% \end{macrocode}
+% \item Tangut Components (西夏文部首)
+% \begin{macrocode}
+ "18800 -> "18AFF ,
+% \end{macrocode}
+% \item Kana Supplement (日文假名增补)
+% \begin{macrocode}
+ "1B000 -> "1B0FF ,
+% \end{macrocode}
+% \item Kana Extended-A (日文假名扩展 A)
+% \begin{macrocode}
+ "1B100 -> "1B12F ,
+% \end{macrocode}
+% \item Small Kana Extension (小型日文假名扩展)
+% \begin{macrocode}
+ "1B130 -> "1B16F ,
+% \end{macrocode}
+% \item Enclosed Ideographic Supplement (带圈表意文字增补)
+% \begin{macrocode}
+ "1F200 -> "1F2FF ,
+% \end{macrocode}
+% \item CJK Unified Ideographs Extension-B (中日韩统一表意文字扩展 B)
+% \begin{macrocode}
+ "20000 -> "2A6DF ,
+% \end{macrocode}
+% \item CJK Unified Ideographs Extension-C (中日韩统一表意文字扩展 C)
+% \begin{macrocode}
+ "2A700 -> "2B73F ,
+% \end{macrocode}
+% \item CJK Unified Ideographs Extension-D (中日韩统一表意文字扩展 D)
+% \begin{macrocode}
+ "2B740 -> "2B81F ,
+% \end{macrocode}
+% \item CJK Unified Ideographs Extension-E (中日韩统一表意文字扩展 E)
+% \begin{macrocode}
+ "2B820 -> "2CEAF ,
+% \end{macrocode}
+% \item CJK Unified Ideographs Extension-F (中日韩统一表意文字扩展 F)
+% \begin{macrocode}
+ "2CEB0 -> "2EBEF ,
+% \end{macrocode}
+% \item CJK Compatibility Ideographs Supplement (中日韩兼容表意文字增补)
+% \begin{macrocode}
+ "2F800 -> "2FA1F
+% \end{macrocode}
+% \end{itemize}
+% \begin{macrocode}
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_CM_chars_clist}
+% \changes{v3.3.1}{2015/01/22}{补充音调符号。}
+% 包括日文假名浊点和异体字选择符。组合标识是最好是归入 256 类,即透明类,不会影响
+% 状态。但也会产生一定问题。比如下面的例子,位于行尾的“二”造成分组不匹配。
+% \begin{verbatim}
+% \XeTeXinterchartokenstate=1
+% \XeTeXcharclass`二=256
+% \XeTeXinterchartoks 255 1 = {\bgroup}
+% \XeTeXinterchartoks 1 255 = {\egroup}
+% \XeTeXinterchartoks 1 1 = {x}
+% \font\zhfont="SimSun"
+% \zhfont
+% 一二三二
+% \bye
+% \end{verbatim}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_CM_chars_clist
+ {
+% \end{macrocode}
+% \begin{itemize}[nosep,leftmargin=0pt]
+% \item Diacritics (音调符号)
+% \begin{macrocode}
+ "302A -> "302F ,
+% \end{macrocode}
+% \item 日文假名浊点
+% \begin{macrocode}
+ "3099 -> "309A ,
+% \end{macrocode}
+% \item Variation Selectors (异体字选择符)
+% \begin{macrocode}
+ "FE00 -> "FE0F ,
+% \end{macrocode}
+% \item Variation Selectors Supplement (异体字选择符增补)
+% \begin{macrocode}
+ "E0100 -> "E01EF
+% \end{macrocode}
+% \end{itemize}
+% \begin{macrocode}
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_HangulJamo_chars_clist}
+% 朝鲜文字母。
+% \begin{macrocode}
+\clist_const:Nn \c_@@_HangulJamo_chars_clist
+ {
+% \end{macrocode}
+% \begin{itemize}[nosep,leftmargin=0pt]
+% \item Hangul Jamo (谚文字母)
+% \begin{macrocode}
+ "1100 -> "11FF ,
+% \end{macrocode}
+% \item Hangul Jamo Extended-A (谚文扩展 A)
+% \begin{macrocode}
+ "A960 -> "A97F ,
+% \end{macrocode}
+% \item Hangul Jamo Extended-B (谚文扩展 B)
+% \begin{macrocode}
+ "D7B0 -> "D7FF
+% \end{macrocode}
+% \end{itemize}
+% \begin{macrocode}
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{字符类别处理}
+%
+% \begin{macro}[int]{\xeCJK_class_num:n}
+% |#1| 为字符类别名称,用于取得字符类别对应的编号。
+% \begin{macrocode}
+\cs_new_nopar:Npn \xeCJK_class_num:n #1
+ { \use:c { \@@_class_csname:n {#1} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKDeclareCharClass}
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKDeclareCharClass { s > { \TrimSpaces } m m }
+ {
+ \xeCJK_declare_char_class:nn {#2} {#3}
+ \IfBooleanT {#1} { \xeCJKResetPunctClass }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_declare_char_class:nn,\xeCJK_declare_char_class:nN}
+% \begin{macro}{\@@_set_char_class_aux:Nnw}
+% 用于设置字符所属的类别,|#1| 为类别名称,|#2| 为字符的 |Unicode|,相邻字符用
+% 半角逗号隔开,支持类似 |"1100 -> "11FF| 起止范围的使用方式。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_declare_char_class:nn #1#2
+ {
+ \clist_set:Nx \l_@@_tmp_clist {#2}
+ \xeCJK_declare_char_class:nN {#1} \l_@@_tmp_clist
+ }
+\cs_new_protected_nopar:Npn \xeCJK_declare_char_class:nN #1#2
+ {
+ \clist_gconcat:ccN
+ { g_@@_#1_range_clist } { g_@@_#1_range_clist } #2
+ \clist_map_inline:Nn #2
+ {
+ \str_if_eq:nnF {##1} { -> }
+ {
+ \@@_set_char_class_aux:Nnw \xeCJK_set_char_class:nnn {##1}
+ { \xeCJK_class_num:n {#1} }
+ }
+ }
+ \xeCJK_set_char_class:nnn { "3099 } { "309A } { \xeCJK_class_num:n { CM } }
+ }
+\NewDocumentCommand \@@_set_char_class_aux:Nnw
+ { m > { \SplitArgument { 1 } { -> } } m } { #1 #2 }
+\cs_generate_variant:Nn \clist_gconcat:NNN { cc }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_check_num_range:nnNN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_check_num_range:nnNN #1#2#3#4
+ {
+ \bool_lazy_or:nnTF
+ { \xeCJK_if_blank_x_p:n {#1} }
+ { \xeCJK_if_blank_x_p:n {#2} }
+ {
+ \int_set:Nn #3 { \xeCJK_if_blank_x:nTF {#1} {#2} {#1} }
+ \int_set_eq:NN #3 #4
+ }
+ {
+ \int_set:Nn #3 { \int_min:nn {#1} { \tl_if_novalue:nTF {#2} {#1} {#2} } }
+ \int_set:Nn #4 { \int_max:nn {#1} { \tl_if_novalue:nTF {#2} {#1} {#2} } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.3}{2013/06/08}{不再改变 CJK 字符类的 \tn{catcode}。}
+% \changes{v3.2.7}{2013/08/29}{修正 \file{unicode-letters.tex} 中谚文符号
+% \tn{catcode} 不准的问题。}
+% \begin{macrocode}
+\token_if_letter:NF ^^^^ac00
+ {
+ \int_set:Nn \l_@@_begin_int { "AC00 }
+ \int_set:Nn \l_@@_end_int { "D7A3 }
+ \xeCJK_int_until_do:nn { \l_@@_begin_int > \l_@@_end_int }
+ {
+ \char_set_catcode_letter:n { \l_@@_begin_int }
+ \int_incr:N \l_@@_begin_int
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_set_char_class:nnn}
+% \changes{v3.1.1}{2012/12/05}{在文档中设置字符类别时不重复设置 \tn{catcode}。}
+% 设置字符类别,|#1| 和 |#2| 为字符类别起止的 |Unicode|,|#3| 为类别名称对应编号。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_set_char_class:nnn #1#2#3
+ {
+ \@@_check_num_range:nnNN {#1} {#2} \l_@@_begin_int \l_@@_end_int
+ \int_set:Nn \l_@@_tmp_int {#3}
+ \xeCJK_int_until_do:nn { \l_@@_begin_int > \l_@@_end_int }
+ {
+ \tex_XeTeXcharclass:D \l_@@_begin_int = \l_@@_tmp_int
+ \int_incr:N \l_@@_begin_int
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_char_class_eq:nn}
+% \changes{v3.1.1}{2012/12/06}{交换参数的顺序。}
+% 将字符类 |#1| 中的字符全部设置成字符类 |#2|。只适用于 |#1| 的字符类范围为离散的
+% 逗号列表的情况。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_set_char_class_eq:nn #1#2
+ {
+ \int_set:Nn \l_@@_tmp_int { \xeCJK_class_num:n {#2} }
+ \clist_map_inline:cn { c_@@_#1_chars_clist }
+ { \tex_XeTeXcharclass:D ##1 = \l_@@_tmp_int }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\normalspacedchars}
+% 声明前后不加间距的字符。
+% \begin{macrocode}
+\NewDocumentCommand \normalspacedchars { m }
+ {
+ \tl_map_inline:nn {#1}
+ { \tex_XeTeXcharclass:D `##1 = \xeCJK_class_num:n { NormalSpace } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKResetPunctClass}
+% 用于重置标点符号所属的字符类。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKResetPunctClass { }
+ {
+ \clist_gclear:N \g_@@_HalfLeft_range_clist
+ \clist_gclear:N \g_@@_HalfRight_range_clist
+ \clist_gclear:N \g_@@_FullLeft_range_clist
+ \clist_gclear:N \g_@@_FullRight_range_clist
+ \xeCJK_declare_char_class:nN { HalfLeft } \c_@@_HalfLeft_chars_clist
+ \xeCJK_declare_char_class:nN { HalfRight } \c_@@_HalfRight_chars_clist
+ \xeCJK_declare_char_class:nN { FullLeft } \c_@@_FullLeft_chars_clist
+ \xeCJK_declare_char_class:nN { FullRight } \c_@@_FullRight_chars_clist
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\xeCJKResetCharClass}
+% 用于恢复 \pkg{xeCJK} 对字符类别的设置。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKResetCharClass { }
+ {
+ \clist_gclear:N \g_@@_CJK_range_clist
+ \clist_gclear:N \g_@@_NormalSpace_range_clist
+ \clist_gclear:N \g_@@_CM_range_clist
+ \clist_gclear:N \g_@@_HangulJamo_range_clist
+ \xeCJK_declare_char_class:nN { CJK } \c_@@_CJK_chars_clist
+ \xeCJK_declare_char_class:nN { NormalSpace } \c_@@_NormalSpace_chars_clist
+ \xeCJK_declare_char_class:nN { CM } \c_@@_CM_chars_clist
+ \xeCJK_declare_char_class:nN { HangulJamo } \c_@@_HangulJamo_chars_clist
+ \xeCJKResetPunctClass
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% 设置字符类别。
+% \begin{macrocode}
+\xeCJKResetCharClass
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_inter_class_toks:nnn}
+% 在相邻类别之间插入内容。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_inter_class_toks:nnn #1#2#3
+ {
+ \tex_XeTeXinterchartoks:D \xeCJK_class_num:n {#1} ~
+ \xeCJK_class_num:n {#2} = {#3}
+ }
+\cs_generate_variant:Nn \xeCJK_inter_class_toks:nnn { nnx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_get_inter_class_toks:nn}
+% 取出相邻类别之间的内容。
+% \begin{macrocode}
+\cs_new_nopar:Npn \xeCJK_get_inter_class_toks:nn #1#2
+ {
+ \tex_the:D \tex_XeTeXinterchartoks:D \xeCJK_class_num:n {#1} ~
+ \xeCJK_class_num:n {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_clear_inter_class_toks:nn}
+% 清除相邻类别之间的内容。注意,直接赋空值可能会导致 \XeTeX 崩溃。例如
+% \begin{verbatim}
+% \XeTeXinterchartokenstate = 1
+% \XeTeXcharclass`A=10
+% \XeTeXinterchartoks 10 10 = {xx}
+% \begingroup
+% \XeTeXinterchartoks 10 10 = {} AA
+% \endgroup
+% \bye
+% \end{verbatim}
+% 如果把上述例子中的分组 \tn{begingroup} 和 \tn{endgroup} 去掉,则结果正常,甚为怪异。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_clear_inter_class_toks:nn #1#2
+ { \xeCJK_inter_class_toks:nnn {#1} {#2} { \prg_do_nothing: } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_pre_inter_class_toks:nnn}
+% 在相邻类别之间已有的内容前增加内容。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_pre_inter_class_toks:nnn #1#2#3
+ {
+ \xeCJK_inter_class_toks:nnx {#1} {#2}
+ { \exp_not:n {#3} \xeCJK_get_inter_class_toks:nn {#1} {#2} }
+ }
+\cs_generate_variant:Nn \xeCJK_pre_inter_class_toks:nnn { nnx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_app_inter_class_toks:nnn}
+% 在相邻类别之间已有的内容后追加内容。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_app_inter_class_toks:nnn #1#2#3
+ {
+ \xeCJK_inter_class_toks:nnx {#1} {#2}
+ { \xeCJK_get_inter_class_toks:nn {#1} {#2} \exp_not:n {#3} }
+ }
+\cs_generate_variant:Nn \xeCJK_app_inter_class_toks:nnn { nnx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_copy_inter_class_toks:nnnn}
+% 将 |#3| 和 |#4| 之间的内容复制到 |#1| 和 |#2| 之间。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_copy_inter_class_toks:nnnn #1#2#3#4
+ {
+ \tl_set:Nx \l_@@_tmp_tl
+ { \xeCJK_get_inter_class_toks:nn {#3} {#4} }
+ \tl_if_empty:NTF \l_@@_tmp_tl
+ {
+ \tl_set:Nx \l_@@_tmp_tl
+ { \xeCJK_get_inter_class_toks:nn {#1} {#2} }
+ \tl_if_empty:NF \l_@@_tmp_tl
+ { \xeCJK_clear_inter_class_toks:nn {#1} {#2} }
+ }
+ { \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:o \l_@@_tmp_tl } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_replace_inter_class_toks:nnnn}
+% 将 |#1| 和 |#2| 之间出现的 |#3| 用 |#4| 替换。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_replace_inter_class_toks:nnnn #1#2#3#4
+ {
+ \tl_set:Nx \l_@@_tmp_tl
+ { \xeCJK_get_inter_class_toks:nn {#1} {#2} }
+ \tl_if_empty:NF \l_@@_tmp_tl
+ {
+ \tl_replace_all:Nnn \l_@@_tmp_tl {#3} {#4}
+ \xeCJK_inter_class_toks:nnx {#1} {#2}
+ { \exp_not:o \l_@@_tmp_tl }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_clear_Boundary_and_CJK_toks:}
+% \changes{v3.4.2}{2016/10/19}{提高效率,避免重复循环。}
+% 清除边界与 CJK 文字、全角左右标点之间的内容。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_clear_Boundary_and_CJK_toks:
+ { }
+\cs_new_protected_nopar:Npn \@@_update_clear_toks:n #1
+ {
+ \cs_gset_protected_nopar:Npx \xeCJK_clear_Boundary_and_CJK_toks:
+ {
+ \exp_not:o { \xeCJK_clear_Boundary_and_CJK_toks: }
+ \tex_XeTeXinterchartoks:D
+ \xeCJK_class_num:n { Boundary } ~
+ \xeCJK_class_num:n {#1} = { \exp_not:N \prg_do_nothing: }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}
+% {\g_@@_base_class_seq,\g_@@_non_CJK_class_seq,\g_@@_CJK_class_seq}
+% 保存宏包预先定义的字符类。
+% \begin{macrocode}
+\seq_new:N \g_@@_base_class_seq
+\seq_gset_eq:NN \g_@@_base_class_seq \g_@@_class_seq
+\seq_new:N \g_@@_non_CJK_class_seq
+\seq_gset_from_clist:Nn \g_@@_non_CJK_class_seq
+ { Default , HalfLeft , HalfRight , NormalSpace , Boundary }
+\seq_new:N \g_@@_CJK_class_seq
+\cs_new_protected_nopar:Npn \@@_save_CJK_class:n #1
+ {
+ \seq_gput_right:Nn \g_@@_CJK_class_seq {#1}
+ \tl_const:cn
+ { \@@_CJK_class_tl:n { \use:c { \@@_class_csname:n {#1} } } }
+ {#1}
+ \@@_update_clear_toks:n {#1}
+ }
+\clist_map_function:nN
+ { CJK , FullLeft , FullRight , CM , HangulJamo } \@@_save_CJK_class:n
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{字符输出规则}
+%
+% \begin{center}
+% \begin{tabular}{l*9c}
+% \toprule
+% & |Default| & |CJK| & |FullL| & |FullR| & |HalfL|
+% & |HalfR| & |Normal| & |Bound| & |CM| \\ \midrule
+% |Default|
+% &
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% &
+% &
+% &
+% & \tokslink{def-bound}
+% & \tokslink{def-cm}\\
+% |CJK|
+% & \tokslink{def-cjk}
+% & \tokslink{cjk-cjk}
+% & \tokslink{cjk-fl-fr}
+% & \tokslink{cjk-fl-fr}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{cjk-bound}
+% &\\
+% |FullLeft|
+% & \tokslink{def-cjk}
+% & \tokslink{fl-fr-others}
+% & \tokslink{cjk-fl-fr}
+% & \tokslink{cjk-fl-fr}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{fl-fr-bound}
+% & \tokslink{def-cm}\\
+% |FullRight|
+% & \tokslink{def-cjk}
+% & \tokslink{fl-fr-others}
+% & \tokslink{cjk-fl-fr}
+% & \tokslink{cjk-fl-fr}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{fl-fr-bound}
+% & \tokslink{def-cm}\\
+% |HalfLeft|
+% &
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% &
+% &
+% &
+% &
+% & \tokslink{def-cm}\\
+% |HalfRight|
+% &
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% &
+% &
+% &
+% & \tokslink{def-bound}
+% & \tokslink{def-cm}\\
+% |NormalSpace|
+% &
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% & \tokslink{def-cjk}
+% &
+% &
+% &
+% & \tokslink{ns-bound}
+% & \tokslink{def-cm}\\
+% |Boundary|
+% & \tokslink{bound-def}
+% & \tokslink{bound-cjk}
+% & \tokslink{bound-fl-fr}
+% & \tokslink{bound-fl-fr}
+% & \tokslink{bound-def}
+% &
+% & \tokslink{bound-ns}
+% &
+% & \tokslink{def-cm}\\
+% |CM|
+% & \tokslink{def-cm}
+% & \tokslink{def-cm}
+% & \tokslink{def-cm}
+% & \tokslink{def-cm}
+% & \tokslink{def-cm}
+% & \tokslink{def-cm}
+% & \tokslink{def-cm}
+% & \tokslink{def-cm}
+% & \tokslink{def-cm}\\
+% \bottomrule
+% \end{tabular}
+% \end{center}
+%
+% \changes{v3.4.2}{2016/10/19}{避免在破折号之间折行。}
+%
+% \begin{macro}[int]{\xeCJK_class_group_begin:,\xeCJK_class_group_end:}
+% 在 CJK 类开始时,设置 \tn{XeTeXdashbreakstate} 为零,避免破折号之间的折行。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_class_group_begin:
+ {
+ \c_group_begin_token
+ \bool_set_true:N \l_@@_CJK_group_bool
+ \int_gset:Nn \g_@@_space_factor_int { 1000 }
+ \int_zero:N \tex_XeTeXdashbreakstate:D
+ }
+\bool_new:N \l_@@_CJK_group_bool
+\cs_new_eq:NN \xeCJK_class_group_end: \c_group_end_token
+% \end{macrocode}
+% \end{macro}
+%
+% \hypertarget{def-cm}{\texttt{CM}} 字符类与 |CJK| 字符类基本相同,只是从 |CJK|
+% 转移到 |CM| 时,不加入任何内容。
+% \begin{macrocode}
+\AtEndOfPackage
+ {
+ \seq_map_inline:Nn \g_@@_class_seq
+ {
+ \str_if_eq:nnTF {#1} { CM }
+ { \xeCJK_copy_inter_class_toks:nnnn { CM } {#1} { CJK } { CJK } }
+ {
+ \xeCJK_copy_inter_class_toks:nnnn { CM } {#1} { CJK } {#1}
+ \str_if_eq:nnF {#1} { CJK }
+ { \xeCJK_copy_inter_class_toks:nnnn {#1} { CM } {#1} { CJK } }
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \hypertarget{def-HJ}{\texttt{HangulJamo}} 字符类与 |CJK| 字符类基本相同,只是
+% |HangulJamo| 类之间不加入任何内容。
+% \begin{macrocode}
+\AtEndOfPackage
+ {
+ \seq_map_inline:Nn \g_@@_class_seq
+ {
+ \str_if_eq:nnF {#1} { HangulJamo }
+ {
+ \xeCJK_copy_inter_class_toks:nnnn { HangulJamo } {#1} { CJK } {#1}
+ \xeCJK_copy_inter_class_toks:nnnn {#1} { HangulJamo } {#1} { CJK }
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \hypertarget{def-cjk}{}
+% \begin{macrocode}
+\clist_map_inline:nn { Default , HalfLeft , HalfRight , NormalSpace }
+ {
+ \xeCJK_inter_class_toks:nnn {#1} { CJK }
+ {
+ \xeCJK_class_group_begin:
+ \xeCJK_select_font:
+ \xeCJK_clear_inter_class_toks:nn {#1} { CJK }
+ \xeCJK_clear_Boundary_and_CJK_toks:
+ \CJKsymbol
+ }
+ \xeCJK_inter_class_toks:nnn { CJK } {#1} { \xeCJK_class_group_end: }
+ }
+% \end{macrocode}
+%
+% \hypertarget{bound-def}{}
+% \begin{macrocode}
+\clist_map_inline:nn { Default , HalfLeft }
+ {
+ \xeCJK_inter_class_toks:nnn { Boundary } {#1}
+ { \xeCJK_Boundary_and_Default: }
+ \xeCJK_app_inter_class_toks:nnn { CJK } {#1}
+ { \CJKecglue }
+ }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_Boundary_and_Default:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_Default:
+ { \xeCJK_check_for_ecglue: }
+\cs_new_protected_nopar:Npn \@@_check_for_xecglue:
+ {
+ \int_compare:nNnTF \tex_lastnodetype:D = { 11 }
+ { \@@_replace_space: }
+ { \@@_check_for_ecglue: }
+ }
+\cs_new_protected_nopar:Npn \@@_check_for_ecglue:
+ {
+ \xeCJK_if_last_node:nTF { CJK }
+ { \use_i:nn }
+ { \xeCJK_if_last_node:nTF { CJK-widow } }
+ { \xeCJK_remove_node: \CJKecglue }
+ {
+ \xeCJK_if_last_node:nT { CJK-space }
+ { \xeCJK_remove_node: \xeCJK_space_or_xecglue: }
+ }
+ }
+\cs_new_eq:NN \xeCJK_check_for_ecglue: \@@_check_for_ecglue:
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4.0}{2016/05/08}{改进 \texttt{xCJKecglue} 的实现。}
+%
+% \begin{macro}{\@@_replace_space:}
+% 将空格替换为 \tn{CJKecglue}。注意由 \tn{leaders} 等产生的 glue,并不能正确地还回去。
+% 好在 \LaTeXe{} 中常用的 \tn{hrulefill} 和 \tn{dotfill} 定义末尾都有 |\kern\z@| 保护。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_replace_space:
+ {
+ \skip_set_eq:NN \l_@@_last_skip \tex_lastskip:D
+ \tex_unskip:D
+ \xeCJK_if_last_node:nTF { CJK-space }
+ { \xeCJK_remove_node: \CJKecglue }
+ {
+ \xeCJK_if_last_node:nTF { CJK }
+ {
+ \skip_if_eq:nnTF
+ { \l_@@_last_skip }
+ { \c_xeCJK_space_skip_tl }
+ { \xeCJK_remove_node: \CJKecglue }
+ { \skip_horizontal:N \l_@@_last_skip }
+ }
+ { \skip_horizontal:N \l_@@_last_skip }
+ }
+ }
+\skip_new:N \l_@@_last_skip
+% \end{macrocode}
+% \end{macro}
+%
+% \hypertarget{def-bound}{}
+% \begin{macrocode}
+\clist_map_inline:nn { Default , HalfRight }
+ {
+ \xeCJK_inter_class_toks:nnn {#1} { Boundary }
+ {
+ \int_gset_eq:NN \g_@@_space_factor_int \tex_spacefactor:D
+ \peek_meaning_remove:NTF \tex_italiccorrection:D
+ {
+ \tex_italiccorrection:D
+ { \xeCJK_make_node:n { default } }
+ }
+ {
+ \token_if_space:NTF \l_peek_token
+ { { \xeCJK_make_node:n { default-space } } }
+ { { \xeCJK_make_node:n { default } } }
+ }
+ }
+ \xeCJK_pre_inter_class_toks:nnn {#1} { CJK } { \CJKecglue }
+ }
+% \end{macrocode}
+%
+% \changes{v3.2.5}{2013/07/10}
+% {修正 \texttt{CJK} 和 \texttt{NormalSpace} 字符类之间因为边界造成的间距不正确的问题。}
+%
+% \hypertarget{bound-ns}{}
+% \begin{macrocode}
+\xeCJK_inter_class_toks:nnn { Boundary } { NormalSpace }
+ { \xeCJK_Boundary_and_NormalSp: }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_Boundary_and_NormalSp:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_NormalSp:
+ { \xeCJK_check_for_ecglue_normalsp: }
+\cs_new_protected_nopar:Npn \@@_check_for_xecglue_normalsp:
+ {
+ \int_compare:nNnTF \tex_lastnodetype:D = { 11 }
+ { \@@_replace_space: }
+ { \@@_check_for_ecglue_normalsp: }
+ }
+\cs_new_protected_nopar:Npn \@@_check_for_ecglue_normalsp:
+ {
+ \xeCJK_if_last_node:nT { CJK-space }
+ { \xeCJK_remove_node: \xeCJK_space_or_xecglue: }
+ }
+\cs_new_eq:NN \xeCJK_check_for_ecglue_normalsp:
+ \@@_check_for_ecglue_normalsp:
+% \end{macrocode}
+% \end{macro}
+%
+% \hypertarget{ns-bound}{}
+% \begin{macrocode}
+\xeCJK_inter_class_toks:nnn { NormalSpace } { Boundary }
+ {
+ \int_gset_eq:NN \g_@@_space_factor_int \tex_spacefactor:D
+ \peek_meaning_remove:NTF \tex_italiccorrection:D
+ {
+ \tex_italiccorrection:D
+ { \xeCJK_make_node:n { normalspace } }
+ }
+ {
+ \token_if_space:NTF \l_peek_token
+ { { \xeCJK_make_node:n { default-space } } }
+ { { \xeCJK_make_node:n { normalspace } } }
+ }
+ }
+% \end{macrocode}
+%
+% \hypertarget{bound-cjk}{}
+% \begin{macrocode}
+\xeCJK_inter_class_toks:nnn { Boundary } { CJK }
+ {
+ \xeCJK_check_for_glue:
+ \xeCJK_class_group_begin:
+ \xeCJK_clear_Boundary_and_CJK_toks:
+ \xeCJK_select_font:
+ \CJKsymbol
+ }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_check_for_glue:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_check_for_glue:
+ {
+ \int_compare:nNnTF \tex_lastnodetype:D = { 12 }
+ { \@@_check_for_glue_auxi: }
+ {
+ \int_compare:nNnTF \tex_lastnodetype:D = { 10 }
+ { \xeCJK_remove_node: \CJKecglue }
+ { \@@_check_for_glue_auxii: }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_check_for_glue_auxi:
+ {
+ \dim_case:nn { \tex_lastkern:D }
+ {
+ { \@@_node:n { CJK } }
+ { \xeCJK_remove_node: \CJKglue }
+ { \@@_node:n { CJK-space } }
+ { \xeCJK_remove_node: \@@_ccglue_or_space: }
+ { \@@_node:n { CJK-widow } }
+ { \xeCJK_remove_node: \xeCJK_widow_penalty: \CJKglue }
+ { \@@_node:n { default } }
+ { \xeCJK_remove_node: \CJKecglue }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_check_for_glue_auxii:
+ {
+ \xeCJK_if_last_punct:TF
+ { \@@_check_for_glue_auxiii: }
+ { \xeCJK_check_for_xglue: }
+ }
+\cs_new_protected_nopar:Npn \@@_check_for_glue_auxiii:
+ {
+ \bool_if:NT \l_@@_last_penalty_bool
+ { \tex_penalty:D \l_@@_last_penalty_int }
+ \skip_horizontal:N \l_@@_last_skip
+ \tl_if_eq:NNF \l_@@_aligni_tl \c_@@_left_tl { \CJKglue }
+ }
+\cs_new_eq:NN \xeCJK_check_for_xglue: \prg_do_nothing:
+\cs_new_protected_nopar:Npn \@@_check_for_xglue:
+ {
+ \int_compare:nNnT \tex_lastnodetype:D = { 11 }
+ {
+ \skip_set_eq:NN \l_@@_last_skip \tex_lastskip:D
+ \tex_unskip:D
+ \xeCJK_if_last_node:nTF { CJK-space }
+ { \xeCJK_remove_node: \@@_ccglue_or_space: }
+ {
+ \xeCJK_if_last_node:nTF { default-space }
+ { \xeCJK_remove_node: \CJKecglue }
+ { \@@_check_for_xglue_aux: }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_check_for_xglue_aux:
+ {
+ \skip_if_eq:nnTF
+ { \l_@@_last_skip }
+ { \c_xeCJK_space_skip_tl }
+ {
+ \xeCJK_if_last_node:nTF { CJK }
+ { \xeCJK_remove_node: \@@_ccglue_or_space: }
+ {
+ \xeCJK_if_last_node:nTF { default }
+ { \xeCJK_remove_node: \CJKecglue }
+ {
+ \int_compare:nNnTF \tex_lastnodetype:D = { 10 }
+ { \CJKecglue }
+ { \skip_horizontal:N \l_@@_last_skip }
+ }
+ }
+ }
+ { \skip_horizontal:N \l_@@_last_skip }
+ }
+\cs_new_protected_nopar:Npn \@@_ccglue_or_space:
+ { \CJKglue }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF,int]{\xeCJK_if_last_node:n}
+% \begin{macrocode}
+ \prg_new_conditional:Npnn \xeCJK_if_last_node:n #1 { p , T , F , TF }
+ {
+ \if_dim:w \use:c { c_@@_#1_node_dim } = \tex_lastkern:D
+ \prg_return_true: \else: \prg_return_false: \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.1.0}{2012/11/14}{删除多余的 \texttt{default-itcorr} 结点。}
+% \changes{v3.2.4}{2013/07/03}{尽量移除用作判断标志的 \tn{kern}。}
+%
+% \begin{macro}[int]{\xeCJK_declare_node:n,\xeCJK_make_node:n}
+% 用于判断插入的各种 |kern|。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_declare_node:n #1
+ {
+ \int_gincr:N \g_@@_node_int
+ \dim_if_exist:cTF { c_@@_#1_node_dim }
+ { \dim_gset:cn } { \dim_const:cn }
+ { c_@@_#1_node_dim } { \g_@@_node_int sp }
+ }
+\int_new:N \g_@@_node_int
+\int_gset:Nn \g_@@_node_int { 10 }
+\cs_new_protected_nopar:Npn \xeCJK_make_node:n #1
+ { \exp_args:Nc \@@_make_node:N { c_@@_#1_node_dim } }
+\cs_new_nopar:Npn \@@_node:n #1
+ { \use:c { c_@@_#1_node_dim } }
+\cs_new_protected_nopar:Npn \@@_make_node:N #1
+ {
+ \tex_kern:D - #1
+ \tex_kern:D #1
+ }
+\cs_new_protected_nopar:Npn \xeCJK_remove_node:
+ { \tex_unkern:D \tex_unkern:D }
+\xeCJK_declare_node:n { CJK }
+\xeCJK_declare_node:n { CJK-space }
+\xeCJK_declare_node:n { default }
+\xeCJK_declare_node:n { default-space }
+\xeCJK_declare_node:n { CJK-widow }
+\xeCJK_declare_node:n { normalspace }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{CJKglue}
+% CJK 文字之间插入的 |glue|。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ CJKglue .code:n =
+ {
+ \cs_set_protected_nopar:Npn \CJKglue {#1}
+ \xeCJK_glue_to_skip:nN {#1} \l_@@_ccglue_skip
+ }
+ }
+\skip_new:N \l_@@_ccglue_skip
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.16}{2014/12/16}{整理 \texttt{xCJKecglue} 的部分代码。}
+%
+% \begin{macro}{CJKecglue,xCJKecglue}
+% CJK 与西文和数学行内数学公式之间自动添加的空白。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ CJKecglue .code:n =
+ {
+ \cs_set_protected_nopar:Npn \CJKecglue {#1}
+ \xeCJK_glue_to_skip:nN {#1} \l_@@_ecglue_skip
+ } ,
+ xCJKecglue .choice: ,
+ xCJKecglue / true .code:n =
+ {
+ \bool_set_true:N \l_@@_xecglue_bool
+ \cs_set_eq:NN \xeCJK_space_or_xecglue: \CJKecglue
+ \cs_set_eq:NN \xeCJK_check_for_xglue: \@@_check_for_xglue:
+ \cs_set_eq:NN \xeCJK_check_for_ecglue: \@@_check_for_xecglue:
+ \cs_set_eq:NN
+ \xeCJK_check_for_ecglue_normalsp:
+ \@@_check_for_xecglue_normalsp:
+ } ,
+ xCJKecglue / false .code:n =
+ {
+ \bool_set_false:N \l_@@_xecglue_bool
+ \cs_set_eq:NN \xeCJK_space_or_xecglue: \xeCJK_space_glue:
+ \xeCJK_cs_clear:N \xeCJK_check_for_xglue:
+ \cs_set_eq:NN \xeCJK_check_for_ecglue: \@@_check_for_ecglue:
+ \cs_set_eq:NN
+ \xeCJK_check_for_ecglue_normalsp:
+ \@@_check_for_ecglue_normalsp:
+ } ,
+ xCJKecglue / unknown .code:n =
+ {
+ \bool_set_true:N \l_@@_xecglue_bool
+ \cs_set_protected_nopar:Npn \CJKecglue {#1}
+ \xeCJK_glue_to_skip:nN {#1} \l_@@_ecglue_skip
+ \cs_set_eq:NN \xeCJK_space_or_xecglue: \CJKecglue
+ \cs_set_eq:NN \xeCJK_check_for_xglue: \@@_check_for_xglue:
+ \cs_set_eq:NN \xeCJK_check_for_ecglue: \@@_check_for_xecglue:
+ \cs_set_eq:NN
+ \xeCJK_check_for_ecglue_normalsp:
+ \@@_check_for_xecglue_normalsp:
+ } ,
+ xCJKecglue .default:n = { true }
+ }
+\cs_new_eq:NN \xeCJK_space_glue: \c_space_tl
+\skip_new:N \l_@@_ecglue_skip
+\bool_new:N \l_@@_xecglue_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4.1}{2016/05/21}{修复 \texttt{CJKspace} 功能失效。}
+% \changes{v3.7.2}{2019/04/07}{简化 \texttt{CJKspace} 的实现,并修复错误。}
+%
+% \begin{macro}{CJKspace}
+% 是否保留 CJK 文字间的空白,默认不保留。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ CJKspace .choice: ,
+ CJKspace / true .code:n =
+ {
+ \bool_set_true:N \l_@@_reserve_space_bool
+ \cs_set_protected_nopar:Npn \@@_ccglue_or_space:
+ { \xeCJK_space_glue: }
+ } ,
+ CJKspace / false .code:n =
+ {
+ \bool_set_false:N \l_@@_reserve_space_bool
+ \cs_set_protected_nopar:Npn \@@_ccglue_or_space:
+ { \CJKglue }
+ } ,
+ CJKspace .default:n = { true } ,
+ space .meta:n = { CJKspace = true } ,
+ nospace .meta:n = { CJKspace = false }
+ }
+\bool_new:N \l_@@_reserve_space_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \hypertarget{cjk-bound}{}
+% \begin{macrocode}
+\xeCJK_inter_class_toks:nnn { CJK } { Boundary } { \xeCJK_CJK_and_Boundary:w }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_CJK_and_Boundary:w}
+% \changes{v3.2.6}{2013/08/05}{更好的处理边界是 \tn{relax} 的情况。}
+% 当边界是 \tn{relax} 的时候,它可能是由 |\csname ...\endcsname| 的形式产生的,
+% 这样就可能出现问题\footnote{参见 \url{http://bbs.ctex.org/forum.php?mod=viewthread&tid=71563}。}。
+% 原来是都在未定义控制序列前都加上 \cs{exp_not:N},现在是采用分组结束后手工恢复的方式。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_CJK_and_Boundary:w
+ {
+ \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
+ {
+ \bool_if:NTF \l_@@_peek_ignore_spaces_bool
+ { \xeCJK_class_group_end: \xeCJK_space_or_xecglue: }
+ { \xeCJK_class_group_end: \CJKecglue }
+ }
+ {
+ \group_align_safe_begin:
+ \bool_if:NTF \l_@@_peek_ignore_spaces_bool
+ {
+ \token_if_macro:NTF \l_peek_token
+ { \@@_boundary_reserve_space: }
+ { \@@_boundary_group_end:n { CJK-space } }
+ }
+ {
+ \token_if_eq_meaning:NNTF \l_peek_token \scan_stop:
+ { \@@_CJK_and_Boundary_relax:N }
+ { \@@_boundary_group_end:n { CJK } }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_boundary_reserve_space:
+ {
+ \@@_boundary_group_end:n { CJK-space }
+ \xeCJK_space_or_xecglue:
+ }
+\cs_new_protected:Npn \@@_CJK_and_Boundary_relax:N #1
+ {
+ \@@_boundary_group_end:n { CJK }
+ \token_if_eq_meaning:NNTF #1 \scan_stop:
+ {#1} { \cs_set_eq:NN #1 \scan_stop: #1 }
+ }
+\cs_new_protected_nopar:Npn \@@_boundary_group_end:n #1
+ {
+ \group_align_safe_end:
+ \xeCJK_class_group_end:
+ { \xeCJK_make_node:n {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_ignore_spaces:w}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_ignore_spaces:w
+ {
+ \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
+ {
+ \bool_if:NTF \l_@@_peek_ignore_spaces_bool
+ { \xeCJK_space_or_xecglue: } { \CJKecglue }
+ }
+ {
+ \bool_if:NT \l_@@_peek_ignore_spaces_bool
+ {
+ \dim_case:nn { \tex_lastkern:D }
+ {
+ { \@@_node:n { CJK } }
+ { \xeCJK_remove_node: \xeCJK_make_node:n { CJK-space } }
+ { \@@_node:n { default } }
+ { \xeCJK_remove_node: \xeCJK_make_node:n { default-space } }
+ }
+ \group_align_safe_begin:
+ \token_if_macro:NTF \l_peek_token
+ { \@@_reserve_space_aux: }
+ { \group_align_safe_end: }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_reserve_space_aux:
+ {
+ \group_align_safe_end:
+ \xeCJK_space_or_xecglue:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \hypertarget{cjk-cjk}{}
+% \begin{macrocode}
+\xeCJK_inter_class_toks:nnn { CJK } { CJK }
+ { \xeCJK_CJK_and_CJK:N }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_CJK_and_CJK:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_CJK_and_CJK:N
+ { \CJKglue \CJKsymbol }
+% \end{macrocode}
+% \end{macro}
+%
+% \hypertarget{fl-fr-others}{}
+% \begin{macrocode}
+\xeCJK_inter_class_toks:nnn { FullLeft } { CJK }
+ { \xeCJK_FullLeft_and_CJK: \CJKsymbol }
+\xeCJK_inter_class_toks:nnn { FullRight } { CJK }
+ { \xeCJK_FullRight_and_CJK: \CJKsymbol }
+\seq_map_inline:Nn \g_@@_non_CJK_class_seq
+ {
+ \clist_map_inline:nn { FullLeft , FullRight }
+ {
+ \xeCJK_inter_class_toks:nnx {#1} {##1}
+ { \exp_not:c { xeCJK_Default_and_##1:nN } {#1} }
+ \xeCJK_inter_class_toks:nnx {##1} {#1}
+ { \exp_not:c { xeCJK_##1_and_Default: } }
+ }
+ }
+% \end{macrocode}
+%
+% \hypertarget{bound-fl-fr}{}
+% \begin{macrocode}
+\xeCJK_inter_class_toks:nnn { Boundary } { FullLeft }
+ { \xeCJK_Boundary_and_FullLeft:N }
+\xeCJK_inter_class_toks:nnn { Boundary } { FullRight }
+ { \xeCJK_Boundary_and_FullRight:N }
+% \end{macrocode}
+%
+% \hypertarget{fl-fr-bound}{}
+% \begin{macrocode}
+\xeCJK_inter_class_toks:nnn { FullLeft } { Boundary }
+ { \xeCJK_FullLeft_and_Boundary: }
+\xeCJK_inter_class_toks:nnn { FullRight } { Boundary }
+ { \xeCJK_FullRight_and_Boundary: }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_FullLeft_and_Boundary:}
+% \hypertarget{fl-fr-bound}{}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_Boundary:
+ {
+ \@@_punct_if_middle:NTF \g_@@_last_punct_tl
+ {
+ \@@_punct_bound_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end:
+ \exp_after:wN \xeCJK_punct_node:N \g_@@_last_punct_tl
+ \xeCJK_no_break:
+ \@@_punct_glue:NN \c_@@_left_tl \g_@@_last_punct_tl
+ }
+ {
+ \xeCJK_class_group_end:
+ \exp_after:wN \xeCJK_punct_node:N \g_@@_last_punct_tl
+ \@@_nobreak_zero_glue:
+ }
+ \tex_ignorespaces:D
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullRight_and_Boundary:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_Boundary:
+ {
+ \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end:
+ \exp_after:wN \xeCJK_punct_node:N \g_@@_last_punct_tl
+ \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \tex_ignorespaces:D
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_punct_node:N}
+% 保存标点的当前边界宽度和字符码,通过插入 \tn{kern} 实现。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_punct_node:N #1
+ {
+ \@@_punct_bound_unitization:NN #1 \l_@@_tmp_dim
+ \@@_make_node:N \l_@@_tmp_dim
+ \dim_set:Nn \l_@@_tmp_dim { `#1 sp }
+ \@@_make_node:N \l_@@_tmp_dim
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_punct_bound_unitization:NN}
+% 我们不想出现过大的 \tn{kern},因此当边界大于 \SI{1}{pt} 时,以 \cs{c_max_dim} 为标准
+% 对其进行“单位化”。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_punct_bound_unitization:NN #1#2
+ {
+ \dim_set:Nn #2
+ {
+ \dim_max:nn
+ { \c_zero_dim }
+ { \@@_use_punct_dim:nNN { bound } \c_@@_right_tl #1 }
+ }
+ \dim_compare:nNnF {#2} < { 1pt }
+ { \dim_set:Nn #2 { -1pt * \dim_ratio:nn {#2} { \c_max_dim } } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_punct_bound_kern:N}
+% \begin{macro}{\@@_punct_bound_kern:NN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_punct_bound_kern:N #1
+ {
+ \exp_after:wN \@@_punct_bound_kern:NN
+ \g_@@_last_punct_tl #1
+ }
+\cs_new_protected_nopar:Npn \@@_punct_bound_kern:NN #1#2
+ {
+ \xeCJK_get_punct_bounds:NN \l_@@_aligni_tl #1
+ \xeCJK_get_punct_kerning:NN #1 #2
+ \@@_punct_bound_unitization:NN #1 \l_@@_tmp_dim
+ \skip_set:Nn \l_@@_punct_kern_skip
+ { \@@_use_dim_or_skip:nNN { bound_kern } #1 #2 }
+ \dim_compare:nNnF \l_@@_tmp_dim = \l_@@_last_bound_dim
+ { \@@_punct_bound_kern_ratio:NN #1 #2 }
+ \bool_if:NTF \l_@@_last_penalty_bool
+ {
+ \tex_penalty:D \l_@@_last_penalty_int
+ \skip_horizontal:N
+ }
+ { \@@_punct_bound_kern_aux:NNN #1 #2 }
+ \l_@@_punct_kern_skip
+ }
+\skip_new:N \l_@@_punct_kern_skip
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_punct_bound_kern_ratio:NN}
+% 当标点前后的字体情况不一致时,按一定的比例进行压缩。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_punct_bound_kern_ratio:NN #1#2
+ {
+ \dim_set:Nn \l_@@_bound_dim
+ { \@@_use_punct_dim:nNN { bound_width } #1 #2 }
+ \dim_compare:nNnT \l_@@_bound_dim > \c_zero_dim
+ {
+ \dim_compare:nNnF \l_@@_last_bound_dim > \c_zero_dim
+ {
+ \dim_set:Nn \l_@@_last_bound_dim
+ {
+ - \l_@@_last_bound_dim *
+ \dim_ratio:nn { \c_max_dim } { 1pt }
+ }
+ }
+ \@@_punct_bound_kern_ratio_aux:N #2
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_punct_bound_kern_ratio_aux:N #1
+ {
+ \skip_set:Nn \l_@@_punct_kern_skip
+ {
+ \l_@@_punct_kern_skip *
+ \dim_ratio:nn
+ {
+ \l_@@_last_bound_dim
+ + \@@_use_punct_dim:nNN { bound } \c_@@_left_tl #1
+ }
+ { \l_@@_bound_dim }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_nobreak_hskip:N,\@@_nobreak_hskip:n,
+% \@@_punct_bound_kern:N, \@@_punct_bound_breakable_kern:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_nobreak_hskip:N
+ { \xeCJK_no_break: \skip_horizontal:N }
+\cs_new_protected_nopar:Npn \@@_nobreak_hskip:n
+ { \xeCJK_no_break: \skip_horizontal:n }
+\cs_new_eq:NN \@@_punct_bound_kern:N \@@_nobreak_hskip:N
+\cs_new_protected_nopar:Npn \@@_punct_bound_breakable_kern:N
+ {
+ \tl_if_eq:NNTF \l_@@_aligni_tl \c_@@_right_tl
+ {
+ \tl_if_eq:NNTF \l_@@_alignii_tl \c_@@_left_tl
+ { \skip_horizontal:N }
+ { \@@_nobreak_hskip:N }
+ }
+ { \@@_nobreak_hskip:N }
+ }
+\cs_new_protected_nopar:Npn \@@_punct_bound_kern_aux:NNN #1#2
+ {
+ \str_if_eq:nnTF {#1} {#2}
+ { \@@_nobreak_hskip:N }
+ {
+ \@@_punct_if_long:NTF #1
+ { \skip_horizontal:N }
+ {
+ \@@_punct_if_long:NTF #2
+ { \skip_horizontal:N }
+ { \@@_punct_bound_kern:N }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \hypertarget{cjk-fl-fr}{}
+% \begin{macrocode}
+\clist_map_inline:nn { CJK , FullLeft , FullRight }
+ {
+ \clist_map_inline:nn { FullLeft , FullRight }
+ {
+ \xeCJK_inter_class_toks:nnx {#1} {##1}
+ { \exp_not:c { xeCJK_#1_and_##1:N } }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macro}{\@@_punct_bound_rule:NN}
+% 用于抹去标点符号的全部左/右空白。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_punct_bound_rule:NN #1#2
+ {
+ \tex_vrule:D
+ width - \@@_use_punct_dim:nNN { bound } #1 #2 ~
+ depth \c_zero_dim
+ height \c_zero_dim \scan_stop:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_punct_rule:NN}
+% 用于减少标点符号的左/右空白。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_punct_rule:NN #1#2
+ {
+ \tex_vrule:D
+ width \@@_use_punct_dim:nNN { rule } #1 #2 ~
+ depth \c_zero_dim
+ height \c_zero_dim \scan_stop:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_punct_glue:NN}
+% \changes{v3.2.7}{2013/08/23}
+% {标点符号左/右空白的伸展值不超过原始边界,收缩值不小于另一侧边界。}
+% 根据所选的标点处理方式在标点符号左/右增加的空白。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_punct_glue:NN #1#2
+ { \@@_punct_hskip:n { \@@_use_dim_or_skip:nNN { glue } #1 #2 } }
+\cs_new_eq:NN \@@_punct_hskip:n \skip_horizontal:n
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.6.0}{2018/01/23}{总允许长标点与其他标点之间折行。}
+% \begin{macro}{\xeCJK_punct_kern:NN,\@@_punct_kern:NN}
+% 相邻两个标点之间的间距,总允许长标点与其他标点之间折行。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_punct_kern:NN #1#2
+ {
+ \str_if_eq:eeTF {#1} {#2}
+ { \@@_punct_nobreak_kern:NN }
+ {
+ \@@_punct_if_long:NTF #1
+ { \@@_punct_breakable_kern:NN }
+ {
+ \@@_punct_if_long:NTF #2
+ { \@@_punct_breakable_kern:NN }
+ { \@@_punct_nobreak_kern:NN }
+ }
+ }
+ #1 #2
+ }
+\cs_new_eq:NN \xeCJK_punct_kern:NN \@@_punct_kern:NN
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_punct_nobreak_kern:NN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_punct_nobreak_kern:NN #1#2
+ { \@@_nobreak_hskip:n { \@@_use_dim_or_skip:nNN { kern } #1 #2 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.4}{2013/07/06}
+% {使用 \texttt{AllowBreakBetweenPuncts} 时,相应标点符号仍能与边界对齐。}
+% \changes{v3.2.7}{2013/08/23}
+% {处理 \texttt{AllowBreakBetweenPuncts} 与 \pkg{xeCJKfntef} 的兼容问题。}
+%
+% \begin{macro}{\@@_punct_breakable_kern:NN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_punct_breakable_kern:NN #1#2
+ {
+ \exp_after:wN \@@_punct_if_right:NT #1
+ { \@@_punct_rule:NN \c_@@_right_tl #1 }
+ \@@_punct_breakable_kern:n
+ { \@@_use_dim_or_skip:nNN { bound_kern } #1 #2 }
+ \@@_punct_if_right:NF #2
+ { \@@_punct_rule:NN \c_@@_left_tl #2 }
+ }
+\cs_new_eq:NN \@@_punct_breakable_kern:n \skip_horizontal:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\g_@@_last_punct_tl}
+% 用于记录当前的标点符号。
+% \begin{macrocode}
+\tl_new:N \g_@@_last_punct_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\xeCJK_FullLeft_and_CJK:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_CJK:
+ {
+ \@@_punct_if_middle:NTF \g_@@_last_punct_tl
+ {
+ \@@_punct_bound_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_no_break:
+ \@@_punct_glue:NN \c_@@_left_tl \g_@@_last_punct_tl
+ }
+ { }
+ \@@_select_font:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullLeft_and_Default:}
+% \changes{v3.2.0}{2013/05/20}{修正 \pkg{xeCJK} 使西文在部分情况下无法断词的问题。}
+% \changes{v3.7.2}{2018/05/21}{再次修正 FullLeft 类字符与西文连用断词失败的问题。}
+% \cs{@@_nobreak_zero_glue:} 用于确保 FullLeft 类后的西文单词可以断词。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_Default:
+ {
+ \@@_punct_if_middle:NTF \g_@@_last_punct_tl
+ {
+ \@@_punct_bound_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end: \xeCJK_no_break:
+ \@@_punct_glue:NN \c_@@_left_tl \g_@@_last_punct_tl
+ }
+ {
+ \xeCJK_class_group_end:
+ \@@_nobreak_zero_glue:
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_nobreak_zero_glue:
+ {
+ \tex_penalty:D \c_@@_nobreak_penalty_int
+ \skip_horizontal:N \c_zero_skip
+ }
+\cs_new_protected_nopar:Npn \@@_zero_glue:
+ { \skip_horizontal:N \c_zero_skip }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullRight_and_CJK:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_CJK:
+ {
+ \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \@@_select_font:
+ \CJKglue
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullRight_and_Default:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_Default:
+ {
+ \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end:
+ \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_Default_and_FullLeft:nN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_Default_and_FullLeft:nN #1#2
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_left_tl #2
+ \@@_Default_and_FullLeft_glue:N #2
+ \xeCJK_class_group_begin:
+ \xeCJK_select_punct_font:
+ \xeCJK_clear_inter_class_toks:nn {#1} { FullLeft }
+ \xeCJK_clear_Boundary_and_CJK_toks:
+ \tl_gset:Nn \g_@@_last_punct_tl {#2}
+ \@@_punct_rule:NN \c_@@_left_tl #2
+ \CJKpunctsymbol #2
+ }
+\cs_new_protected_nopar:Npn \@@_Default_and_FullLeft_glue:N #1
+ { \@@_punct_glue:NN \c_@@_left_tl #1 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_CJK_and_FullLeft:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullLeft:N #1
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_left_tl #1
+ \@@_CJK_and_FullLeft_glue:N #1
+ \tl_gset:Nn \g_@@_last_punct_tl {#1}
+ \@@_punct_rule:NN \c_@@_left_tl #1
+ \@@_select_punct_font:
+ \CJKpunctsymbol #1
+ }
+\cs_new_protected_nopar:Npn \@@_CJK_and_FullLeft_glue:N #1
+ {
+ \CJKglue
+ \@@_punct_glue:NN \c_@@_left_tl #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_Boundary_and_FullLeft:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_FullLeft:N #1
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_left_tl #1
+ \@@_Boundary_and_FullLeft_glue:N #1
+ \xeCJK_class_group_begin:
+ \xeCJK_select_punct_font:
+ \xeCJK_clear_Boundary_and_CJK_toks:
+ \tl_gset:Nn \g_@@_last_punct_tl {#1}
+ \@@_punct_rule:NN \c_@@_left_tl #1
+ \CJKpunctsymbol #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_Boundary_and_FullLeft_glue:N}
+% \changes{v3.2.0}{2013/05/22}{当全角左标点前面是 \texttt{hlist}、\texttt{none}、
+% \texttt{glue} 和 \texttt{penalty} 等节点时,压缩其左空白。}
+% \changes{v3.2.4}{2013/07/03}{细化边界与全角左标点之间是否压缩空白的判断。}
+% \changes{v3.2.5}{2013/07/13}{细化全角左标点是否位于段首的判断。}
+% \changes{v3.2.5}{2013/07/13}{增加对 \pkg{enumitem} 宏包修改的 \tn{item} 的判断。}
+% 根据 \cs{etex_lastnodetype:D} 的值进行分别处理。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_Boundary_and_FullLeft_glue:N #1
+ {
+ \tl_set_eq:NN \l_@@_alignii_tl \c_@@_left_tl
+ \group_begin: \exp_args:NNc \group_end: \cs_if_exist_use:NTF
+ { @@_bound_type_ \int_use:N \tex_lastnodetype:D _glue:Nn }
+ {#1}
+ { \use:n }
+ { \@@_punct_glue:NN \c_@@_left_tl #1 }
+ }
+\tl_new:N \c_@@_alignii_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_bound_type_-1_glue:Nn}
+% \cs{etex_lastnodetype:D} 为 $-1$ 表示 empty list,常出现在盒子的起始位置,
+% 在段落前使用 \tn{noindent} 就是这种情况。
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { @@_bound_type_ -1 _glue:Nn } #1#2
+ { \@@_zero_glue: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_bound_type_1_glue:Nn}
+% $1$ 表示 hlist node,在这里用来判断是否位于段首。基于正常情况下,\TeX 会在段落开头插入宽度为
+% \tn{parindent} 的水平盒子用于缩进。
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { @@_bound_type_ 1 _glue:Nn } #1#2
+ {
+ \box_set_to_last:N \l_@@_tmp_box
+ \int_compare:nNnTF \tex_lastnodetype:D = { -1 }
+ {
+ \dim_compare:nNnTF
+ { \box_wd:N \l_@@_tmp_box } = \tex_parindent:D
+ { \box_use_drop:N \l_@@_tmp_box }
+ { \box_use_drop:N \l_@@_tmp_box #2 }
+ }
+ { \box_use_drop:N \l_@@_tmp_box #2 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_bound_type_11_glue:Nn}
+% $11$ 表示 glue node,这里判断的目的是当全角左标点出现在 \LaTeX 表格的非 \texttt{p} 列行首时,
+% 能够对齐到单元格的边界。判断基于标准 \LaTeX 表格的列格式(\tn{@tabclassz})定义中,
+% 在 \texttt{l} 列和 \texttt{r} 列前为了防止 \tn{tabcolsep} 被无意 \tn{unskip} 掉,
+% 都加了 |\hskip1sp|,而 \texttt{c} 列前则有 \tn{hfil}。\package{enumitem} 宏包修改了
+% \env{description} 环境中使用的 \tn{item}(\tn{enit@postlabel@i}),
+% 在这里起到影响作用的是 |\penalty\z@ \hskip\labelsep|。
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { @@_bound_type_ 11 _glue:Nn } #1#2
+ {
+ \skip_if_finite:nTF { \tex_lastskip:D }
+ { \@@_bound_glue_auxi:Nn #1 {#2} }
+ { \@@_zero_glue: }
+ }
+\cs_new_protected_nopar:Npn \@@_bound_glue_auxi:Nn #1#2
+ {
+ \@@_if_last_punct_glue:TF
+ { \xeCJK_punct_bound_kern:N #1 }
+ { \@@_bound_glue_auxii:n {#2} }
+ }
+\cs_new_protected_nopar:Npn \@@_bound_glue_auxii:n #1
+ {
+ \skip_set_eq:NN \l_@@_last_skip \tex_lastskip:D
+ \skip_if_eq:nnTF { \l_@@_last_skip } { 1sp }
+ { \@@_zero_glue: }
+ {
+ \skip_if_eq:nnTF { \l_@@_last_skip } { \labelsep }
+ {
+ \tex_unskip:D
+ \int_compare:nNnTF \tex_lastnodetype:D = { 13 }
+ {
+ \int_compare:nNnTF \tex_lastpenalty:D = \c_zero_int
+ { \skip_horizontal:N \l_@@_last_skip }
+ { \skip_horizontal:N \l_@@_last_skip #1 }
+ }
+ { \skip_horizontal:N \l_@@_last_skip #1 }
+ }
+ {#1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_bound_type_12_glue:Nn}
+% $12$ 表示 kern node,用于判断之前的字符是否是 CJK 类,如果是,则插入 \tn{CJKglue}。
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { @@_bound_type_ 12 _glue:Nn } #1#2
+ {
+ \xeCJK_if_last_node:nF { CJK }
+ { \xeCJK_if_last_node:nF { CJK-space } { \use_none:nn } }
+ \xeCJK_remove_node: \CJKglue
+ #2
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_bound_type_13_glue:n}
+% $13$ 表示 penalty node,这里判断的目的是全角左标点出现在 \LaTeX 列表环境的 \tn{item} 后面时,
+% 能对齐到边界。判断基于 \tn{item} 的内部定义 \tn{@item} 对 \tn{everypar} 进行了修改,在这里起
+% 到影响作用的是 |\box\@labels \penalty\z@|。以上判断都比较粗略,暂时也没有想起更好的办法。
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { @@_bound_type_ 13 _glue:Nn } #1#2
+ {
+ \@@_if_last_punct_penalty:TF
+ { \xeCJK_punct_bound_kern:N #1 }
+ {
+ \int_compare:nNnTF \tex_lastpenalty:D = \c_zero_int
+ {
+ \tex_unpenalty:D
+ \int_compare:nNnTF \tex_lastnodetype:D = \c_one_int
+ { \tex_penalty:D \c_zero_int }
+ { \tex_penalty:D \c_zero_int #2 }
+ }
+ {#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_Default_and_FullRight:nN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_Default_and_FullRight:nN #1#2
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_right_tl #2
+ \@@_Default_and_FullRight_glue:N #2
+ \xeCJK_class_group_begin:
+ \xeCJK_select_punct_font:
+ \xeCJK_clear_inter_class_toks:nn {#1} { FullRight }
+ \xeCJK_clear_Boundary_and_CJK_toks:
+ \tl_gset:Nn \g_@@_last_punct_tl {#2}
+ \xeCJK_FullRight_symbol:N #2
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_Boundary_and_FullRight:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_FullRight:N #1
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_right_tl #1
+ \xeCJK_if_last_punct:TF
+ {
+ \tl_set_eq:NN \l_@@_alignii_tl \c_@@_right_tl
+ \xeCJK_punct_bound_kern:N
+ }
+ { \@@_Default_and_FullRight_glue:N }
+ #1
+ \xeCJK_class_group_begin:
+ \xeCJK_select_punct_font:
+ \xeCJK_clear_Boundary_and_CJK_toks:
+ \tl_gset:Nn \g_@@_last_punct_tl {#1}
+ \xeCJK_FullRight_symbol:N #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_CJK_and_FullRight:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullRight:N #1
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_right_tl #1
+ \@@_CJK_and_FullRight_glue:N #1
+ \tl_gset:Nn \g_@@_last_punct_tl {#1}
+ \@@_select_punct_font:
+ \xeCJK_FullRight_symbol:N #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.6.0}{2018/01/23}{解决标点中间被隔开的禁则与压缩问题。}
+% \changes{v3.7.3}{2019/04/15}{修复 penalty 数值错误。}
+%
+% \begin{macro}{\xeCJK_if_last_punct:TF}
+% \changes{v3.6.1}{2018/02/25}{细化判断。}
+% 判断之前是否是一个标点符号。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_if_last_punct:TF
+ {
+ \bool_set_false:N \l_@@_last_penalty_bool
+ \int_compare:nNnTF \tex_lastnodetype:D = { 11 }
+ { \@@_if_last_punct_glue:TF }
+ {
+ \int_compare:nNnTF \tex_lastnodetype:D = { 13 }
+ { \@@_if_last_punct_penalty:TF }
+ { \use_ii:nn }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_glue:TF
+ {
+ \prop_get:NoNTF \g_@@_punct_skip_prop
+ { \skip_use:N \tex_lastskip:D } \l_@@_tmp_tl
+ { \@@_if_last_punct_glue_auxi:TF }
+ { \@@_if_last_punct_glue_auxii:TF }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_glue_auxi:TF
+ {
+ \skip_set_eq:NN \l_@@_last_skip \tex_lastskip:D
+ \tex_unskip:D
+ \int_compare:nNnTF \tex_lastpenalty:D = \c_@@_nobreak_penalty_int
+ { \@@_if_last_punct_auxi:TF { \use_i:nn } }
+ {
+ \xeCJK_if_last_node:TF
+ { \@@_if_last_punct_auxii:TF { \use_i:nn } }
+ { \use:n }
+ }
+ { \skip_horizontal:N \l_@@_last_skip \use_ii:nn }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_glue_auxii:TF
+ {
+ \int_gset_eq:NN \g_@@_space_factor_int \tex_spacefactor:D
+ \skip_if_eq:nnTF { \tex_lastskip:D } { \c_xeCJK_space_skip_tl }
+ { \@@_if_last_punct_glue_auxiii:TF }
+ { \use_ii:nn }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_glue_auxiii:TF
+ {
+ \skip_set_eq:NN \l_@@_tmp_skip \tex_lastskip:D
+ \tex_unskip:D
+ \int_compare:nNnTF \tex_lastnodetype:D = { 11 }
+ {
+ \prop_get:NoNTF \g_@@_punct_skip_prop
+ { \skip_use:N \tex_lastskip:D } \l_@@_tmp_tl
+ { \@@_if_last_punct_glue_auxi:TF { \use_i:nn } }
+ { \use:n }
+ }
+ { \use:n }
+ { \skip_horizontal:N \l_@@_tmp_skip \use_ii:nn }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_penalty:TF
+ {
+ \int_set_eq:NN \l_@@_last_penalty_int \tex_lastpenalty:D
+ \tex_unpenalty:D
+ \bool_set_true:N \l_@@_last_penalty_bool
+ \int_compare:nNnTF \tex_lastnodetype:D = { 11 }
+ { \@@_if_last_punct_glue:TF { \use_i:nn } }
+ { \use:n }
+ { \tex_penalty:D \l_@@_last_penalty_int \use_ii:nn }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_auxi:TF
+ {
+ \tex_unpenalty:D
+ \bool_if:NF \l_@@_last_penalty_bool
+ {
+ \bool_set_true:N \l_@@_last_penalty_bool
+ \int_set_eq:NN \l_@@_last_penalty_int \c_@@_nobreak_penalty_int
+ }
+ \xeCJK_if_last_node:TF
+ { \@@_if_last_punct_auxii:TF { \use_i:nn } }
+ { \use:n }
+ { \xeCJK_no_break: \use_ii:nn }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_auxii:TF
+ {
+ \dim_compare:nNnTF \l_@@_last_kern_dim > \c_zero_dim
+ { \@@_if_last_punct_auxiii:TF }
+ { \@@_make_node:N \l_@@_last_kern_dim \use_ii:nn }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_auxiii:TF
+ {
+ \int_case:nnTF { \tex_XeTeXcharclass:D \l_@@_last_kern_dim }
+ {
+ { \xeCJK_class_num:n { FullRight } }
+ { \tl_set_eq:NN \l_@@_aligni_tl \c_@@_right_tl }
+ { \xeCJK_class_num:n { FullLeft } }
+ { \tl_set_eq:NN \l_@@_aligni_tl \c_@@_left_tl }
+ }
+ { \@@_if_last_punct_auxiv:TF }
+ { \use_ii:nn }
+ }
+\cs_new_protected_nopar:Npn \@@_if_last_punct_auxiv:TF
+ {
+ \dim_set_eq:NN \l_@@_tmp_dim \l_@@_last_kern_dim
+ \xeCJK_if_last_node:TF
+ {
+ \tl_gset:Nx \g_@@_last_punct_tl
+ { \tex_Uchar:D \l_@@_tmp_dim }
+ \dim_set_eq:NN \l_@@_last_bound_dim \l_@@_last_kern_dim
+ \use_i:nn
+ }
+ { \@@_make_node:N \l_@@_tmp_dim \use_ii:nn }
+ }
+\tl_new:N \l_@@_aligni_tl
+\tl_new:N \l_@@_alignii_tl
+\int_new:N \l_@@_last_penalty_int
+\dim_new:N \l_@@_last_bound_dim
+\bool_new:N \l_@@_last_penalty_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJK_if_last_node:TF}
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_if_last_node:TF #1#2
+ {
+ \int_compare:nNnTF \tex_lastnodetype:D = { 12 }
+ {
+ \dim_set_eq:NN \l_@@_last_kern_dim \tex_lastkern:D
+ \tex_unkern:D
+ \int_compare:nNnTF \tex_lastnodetype:D = { 12 }
+ {
+ \dim_compare:nNnTF \tex_lastkern:D = { - \l_@@_last_kern_dim }
+ { \tex_unkern:D #1 }
+ { \tex_kern:D \l_@@_last_kern_dim #2 }
+ }
+ { \tex_kern:D \l_@@_last_kern_dim #2 }
+ }
+ {#2}
+ }
+\dim_new:N \l_@@_last_kern_dim
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.6.0}{2018/01/14}
+% {修正标点同为 \texttt{LongPunct} 与 \texttt{MiddlePunct} 时的实现错误。}
+% \changes{v3.6.0}{2018/01/14}
+% {\texttt{Default} 类与 \texttt{MiddlePunct} 之间不应该有 \tn{CJKglue}。}
+%
+% \begin{macro}
+% {\@@_CJK_and_FullRight_glue:N,\@@_Default_and_FullRight_glue:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_CJK_and_FullRight_glue:N #1
+ {
+ \@@_punct_if_long:NTF #1
+ { \xeCJK_allow_break: }
+ { \xeCJK_no_break: }
+ \@@_punct_if_middle:NT #1
+ {
+ \CJKglue
+ \@@_punct_glue:NN \c_@@_right_tl #1
+ \@@_punct_bound_rule:NN \c_@@_left_tl #1
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_Default_and_FullRight_glue:N #1
+ {
+ \@@_punct_if_long:NTF #1
+ { \xeCJK_allow_break: }
+ { \xeCJK_no_break: }
+ \@@_punct_if_middle:NT #1
+ {
+ \@@_punct_glue:NN \c_@@_right_tl #1
+ \@@_punct_bound_rule:NN \c_@@_left_tl #1
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullLeft_and_FullLeft:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullLeft:N #1
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_left_tl #1
+ \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl #1
+ \@@_punct_kern:NN \g_@@_last_punct_tl #1
+ \tl_gset:Nn \g_@@_last_punct_tl {#1}
+ \CJKpunctsymbol #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullLeft_and_FullRight:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullRight:N #1
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_right_tl #1
+ \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl #1
+ \@@_punct_kern:NN \g_@@_last_punct_tl #1
+ \tl_gset:Nn \g_@@_last_punct_tl {#1}
+ \xeCJK_FullRight_symbol:N #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullRight_and_FullLeft:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullLeft:N #1
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_left_tl #1
+ \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl #1
+ \xeCJK_punct_kern:NN \g_@@_last_punct_tl #1
+ \tl_gset:Nn \g_@@_last_punct_tl {#1}
+ \CJKpunctsymbol #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullRight_and_FullRight:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullRight:N #1
+ {
+ \xeCJK_get_punct_bounds:NN \c_@@_right_tl #1
+ \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl #1
+ \@@_punct_kern:NN \g_@@_last_punct_tl #1
+ \tl_gset:Nn \g_@@_last_punct_tl {#1}
+ \xeCJK_FullRight_symbol:N #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{全角右标点后的断行}
+%
+% \begin{macro}{CheckFullRight}
+% \changes{v3.1.1}{2012/12/02}{处理全角右标点之后的断行问题。}
+% 选项设置。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ CheckFullRight .choice: ,
+ CheckFullRight / true .code:n =
+ {
+ \cs_if_eq:NNF \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight:
+ {
+ \cs_set_eq:NN \@@_save_FullRight_check:
+ \xeCJK_FullRight_and_Boundary:
+ \cs_set_eq:NN \@@_save_FullRight_symbol:N
+ \xeCJK_FullRight_symbol:N
+ \cs_set_eq:NN \xeCJK_FullRight_and_Boundary:
+ \xeCJK_check_FullRight:
+ \cs_set_eq:NN \xeCJK_FullRight_symbol:N
+ \xeCJK_check_FullRight_symbol:Nw
+ }
+ } ,
+ CheckFullRight / false .code:n =
+ {
+ \cs_if_eq:NNT \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight:
+ {
+ \cs_set_eq:NN \xeCJK_FullRight_and_Boundary:
+ \@@_save_FullRight_check:
+ \cs_set_eq:NN \xeCJK_FullRight_symbol:N
+ \@@_save_FullRight_symbol:N
+ }
+ } ,
+ CheckFullRight .default:n = { true }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_FullRight_symbol:N}
+% \begin{macrocode}
+\cs_new_nopar:Npn \xeCJK_FullRight_symbol:N { \CJKpunctsymbol }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_check_FullRight:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_check_FullRight:
+ {
+ \xeCJK_get_punct_bounds:No \c_@@_right_tl \g_@@_last_punct_tl
+ \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \group_align_safe_begin:
+ \tl_case:NoTF \l_peek_token
+ { \l_@@_no_break_cs_case_tl }
+ {
+ \group_align_safe_end:
+ \xeCJK_no_break:
+ \group_insert_after:N \xeCJK_no_break:
+ }
+ { \group_align_safe_end: }
+ \exp_after:wN \xeCJK_punct_node:N \g_@@_last_punct_tl
+ \xeCJK_class_group_end:
+ \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
+ }
+\prg_generate_conditional_variant:Nnn \tl_case:Nn { No } { TF , F }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_check_FullRight_symbol:Nw}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_check_FullRight_symbol:Nw #1
+ {
+ \xeCJK_peek_after_ignore_spaces:nw
+ { \@@_save_FullRight_symbol:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_cs_case_keys_define:nNNnn}
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_cs_case_keys_define:nNNnn #1#2#3#4#5
+ {
+ \tl_new:N #2
+ \seq_new:N #3
+ \keys_define:nn { xeCJK / options }
+ {
+ #1 .code:n =
+ {
+ \seq_set_split:Nnn #3 { } {##1}
+ \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5}
+ } ,
+ #1+ .code:n =
+ {
+ \tl_map_inline:nn {##1}
+ { \seq_if_in:NnF #3 {####1} { \seq_put_right:Nn #3 {####1} } }
+ \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5}
+ } ,
+ #1- .code:n =
+ {
+ \tl_map_inline:nn {##1} { \seq_remove_all:Nn #3 {####1} }
+ \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5}
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_update_cs_case_tl:NNnn #1#2#3#4
+ {
+ \tl_clear:N #1
+ \seq_map_inline:Nn #2 { \tl_put_right:Nn #1 { {##1} {#3} } }
+ #4
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{NoBreakCS}
+% 设置不能在全角右标点之后断行的控制序列。
+% \begin{macrocode}
+\xeCJK_cs_case_keys_define:nNNnn { NoBreakCS }
+ \l_@@_no_break_cs_case_tl \l_@@_no_break_cs_seq { } { }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKnobreak}
+% \changes{v3.1.1}{2012/12/03}{增加 \tn{nobreak} 的 \pkg{xeCJK} 版本。}
+% 为保险起见,我们在这里用了一个循环。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKnobreak { }
+ {
+ \bool_set_true:N \l_@@_tmp_bool
+ \int_while_do:nNnn \tex_lastnodetype:D = { 11 }
+ {
+ \bool_if:NTF \l_@@_tmp_bool
+ {
+ \bool_set_false:N \l_@@_tmp_bool
+ \skip_set_eq:NN \l_@@_last_skip \tex_lastskip:D
+ }
+ { \skip_add:Nn \l_@@_last_skip \tex_lastskip:D }
+ \tex_unskip:D
+ }
+ \xeCJK_if_last_node:TF
+ {
+ \dim_set_eq:NN \l_@@_tmp_dim \l_@@_last_kern_dim
+ \xeCJK_if_last_node:TF
+ {
+ \int_compare:nNnT \tex_lastnodetype:D = { 11 }
+ {
+ \exp_args:NNNo \tex_unskip:D \xeCJK_no_break:
+ \skip_horizontal:n { \skip_use:N \tex_lastskip:D }
+ }
+ \@@_make_node:N \l_@@_last_kern_dim
+ }
+ { }
+ \@@_make_node:N \l_@@_tmp_dim
+ }
+ { }
+ \xeCJK_no_break:
+ \bool_if:NF \l_@@_tmp_bool
+ { \skip_horizontal:N \l_@@_last_skip }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{段末孤字处理}
+%
+% \begin{macro}{CheckSingle}
+% 孤字处理功能选项。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ CheckSingle .choice: ,
+ CheckSingle / true .code:n =
+ {
+ \cs_if_eq:NNF \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
+ {
+ \cs_set_eq:NN \@@_check_single_save:N \xeCJK_CJK_and_CJK:N
+ \cs_set_eq:NN \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
+ }
+ } ,
+ CheckSingle / false .code:n =
+ {
+ \cs_if_eq:NNT \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
+ { \cs_set_eq:NN \xeCJK_CJK_and_CJK:N \@@_check_single_save:N }
+ } ,
+ CheckSingle .default:n = { true } ,
+ CJKchecksingle .meta:n = { CheckSingle = true }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.3.1}{2015/04/08}{新选项 \texttt{WidowPenalty}。}
+%
+% \begin{macro}{WidowPenalty}
+% 设置段末汉字的 penalty,默认值是 \num{10000}。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ WidowPenalty .int_set:N = \l_@@_widow_penalty_int ,
+ WidowPenalty .default:n = { 10 000 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_widow_penalty:}
+% 预防段末孤字而插入的 penalty,值为 \cs{l_@@_widow_penalty_int}。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_widow_penalty:
+ { \tex_penalty:D \l_@@_widow_penalty_int }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4.7}{2017/03/20}{简化 \texttt{CheckSingle} 的实现,不再展开宏。}
+%
+% \begin{macro}[int]{\xeCJK_check_single:Nw}
+% \begin{macro}{\@@_check_single_end:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_check_single:Nw #1
+ {
+ \group_align_safe_begin:
+ \peek_catcode:NTF \c_catcode_letter_token
+ { \xeCJK_check_single:NNw #1 }
+ {
+ \token_if_other:NTF \l_peek_token
+ { \xeCJK_check_single:NNw }
+ { \@@_check_single_end:N }
+ #1
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_check_single_end:N
+ {
+ \group_align_safe_end:
+ \@@_check_single_save:N
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_check_single:NNw}
+% \begin{macro}{\@@_check_single_aux:nNNw}
+% \changes{v3.1.1}{2012/12/04}{改进定义,减少使用 \texttt{peek} 函数的次数。}
+% \changes{v3.2.7}{2013/08/30}{与 \tn{CJKspace} 兼容。}
+% 使用 \cs{group_align_safe_begin:} 和 \cs{group_align_safe_end:} 是为了防止在表格
+% 里面报错。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_check_single:NNw #1#2
+ {
+ \xeCJK_peek_catcode_ignore_spaces:NTF \c_catcode_letter_token
+ {
+ \bool_if:NTF \l_@@_peek_ignore_spaces_bool
+ {
+ \bool_if:NTF \l_@@_reserve_space_bool
+ { \@@_check_single_end:N #1 #2 ~ }
+ { \@@_check_single_space:NN #1#2 }
+ }
+ { \@@_check_single_end:N #1 #2 }
+ }
+ {
+ \token_if_other:NTF \l_peek_token
+ {
+ \bool_if:NTF \l_@@_peek_ignore_spaces_bool
+ { \@@_check_single_space:NN }
+ { \@@_check_single_end:N }
+ }
+ {
+ \bool_if:NTF \l_@@_peek_ignore_spaces_bool
+ { \@@_check_single_aux:nNNw { ~ } }
+ { \@@_check_single_aux:nNNw { } }
+ }
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_check_single_aux:nNNw #1#2#3
+ {
+ \token_if_cs:NTF \l_peek_token
+ { \xeCJK_check_single_cs:NNn }
+ { \xeCJK_check_single_end:NNnw }
+ #2 #3 {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_check_single_end:NNnw}
+% \begin{macro}{\@@_check_single_end_aux:NNn,\@@_check_single_end_equation:NNnw}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_check_single_end_aux:NNn #1#2#3
+ { \@@_check_single_end:N #1 #2 #3 }
+\cs_new_eq:NN \xeCJK_check_single_end:NNnw \@@_check_single_end_aux:NNn
+\cs_new_protected_nopar:Npn \@@_check_single_end_equation:NNnw
+ {
+ \token_if_math_toggle:NTF \l_peek_token
+ { \xeCJK_check_single_equation:NNnNw }
+ { \@@_check_single_end_aux:NNn }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{PlainEquation}
+% \changes{v3.1.1}{2012/12/06}{增加 \texttt{PlainEquation} 选项。}
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ PlainEquation .choice: ,
+ PlainEquation / true .code:n =
+ {
+ \cs_set_eq:NN \xeCJK_check_single_end:NNnw
+ \@@_check_single_end_equation:NNnw
+ } ,
+ PlainEquation / false .code:n =
+ {
+ \cs_set_eq:NN \xeCJK_check_single_end:NNnw
+ \@@_check_single_end_aux:NNn
+ } ,
+ PlainEquation .default:n = { true } ,
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_check_single_space:NN}
+% \changes{v3.1.1}{2012/12/13}
+% {\texttt{CheckSingle} 支持段末“汉字$+$汉字$+$空格$+$汉字/标点”的形式。}
+% \changes{v3.1.2}{2012/12/27}
+% {使用 \cs{xeCJK_if_CJK_class:NTF} 来代替 \cs{int_case:nnn} 判断是否是 CJK 字符类。}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_check_single_space:NN #1#2
+ {
+ \xeCJK_if_CJK_class:NTF #2
+ {
+ \xeCJK_if_CJK_class:NTF \l_peek_token
+ { \@@_check_single_end:N #1 #2 }
+ { \@@_check_single_end:N #1 #2 ~ }
+ }
+ { \@@_check_single_end:N #1 #2 ~ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_check_single_equation:NNnNw}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_check_single_equation:NNnNw #1#2#3#4
+ {
+ \peek_catcode:NTF \c_math_toggle_token
+ {
+ \xeCJK_widow_penalty: \@@_check_single_end:N #1
+ \xeCJK_make_node:n { CJK-widow } #2 #4
+ }
+ { \@@_check_single_end:N #1 #2#3#4 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.3}{2013/06/11}
+% {解决 \texttt{CheckSingle} 选项与 \pkg{tablists} 宏包的冲突。}
+% \changes{v3.2.4}{2013/06/26}
+% {解决使用 \texttt{CheckSingle} 时,某些 \tn{CJKglue} 不能被正确加入的问题。}
+%
+% \begin{macro}[int]{\xeCJK_check_single_cs:NNn}
+% \changes{v3.3.1}{2015/04/06}{补充可能遗漏的空格。}
+% 在使用 \texttt{CheckSingle} 选项时,在 \package{tablists} 宏包定义的
+% \env{tabenum} 环境中会出现下面的错误:
+% \begin{verbatim}
+% ! Forbidden control sequence found while scanning use of \use_ii:nn.
+% <inserted text>
+% \par
+% l.10 \item
+% \end{verbatim}
+% 原因在于 \env{tabenum} 实际上是一个 \TeX 对齐环境(\tn{halign}),\tn{par} 在
+% 其中被重定义为 \tn{cr}。而在下面 \cs{tl_case:NnF} 的分支里有对 \tn{par} 的
+% \tn{ifx} 判断。解决办法是将判断用 \cs{group_align_safe_begin:} 和
+% \cs{group_align_safe_end:} 包起来。或者改用原语 \cs{tex_par:D} 作为判断条件。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_check_single_cs:NNn #1#2#3
+ {
+ \tl_case:NoF \l_peek_token
+ { \l_@@_check_single_cs_case_tl }
+ { \use_iii:nnn }
+ { \xeCJK_check_single_env:nnNn }
+ {
+ \xeCJK_widow_penalty:
+ \@@_check_single_end:N #1
+ \xeCJK_make_node:n { CJK-widow } #2#3
+ }
+ { \@@_check_single_end:N #1 #2#3 }
+ }
+\tl_new:N \l_@@_check_single_cs_case_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_check_single_env:nnNn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_check_single_env:nnNn #1#2#3#4
+ {
+ \str_case_e:noTF {#4}
+ { \l_@@_inline_env_case_tl }
+ {#2}
+ {#1}
+ #3 {#4}
+ }
+\prg_generate_conditional_variant:Nnn \str_case_e:nn { no } { TF }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.1.1}{2012/12/04}{增加 \texttt{NewLineCS} 和 \texttt{EnvCS} 选项。}
+%
+% \begin{macro}{NewLineCS}
+% \begin{macrocode}
+\xeCJK_cs_case_keys_define:nNNnn { NewLineCS }
+ \l_@@_new_line_cs_case_tl \l_@@_new_line_cs_seq
+ { \use_ii:nnn }
+ {
+ \tl_concat:NNN \l_@@_check_single_cs_case_tl
+ \l_@@_new_line_cs_case_tl \l_@@_env_cs_case_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{EnvCS}
+% \begin{macrocode}
+\xeCJK_cs_case_keys_define:nNNnn { EnvCS }
+ \l_@@_env_cs_case_tl \l_@@_env_cs_seq
+ { \use:n }
+ {
+ \tl_concat:NNN \l_@@_check_single_cs_case_tl
+ \l_@@_new_line_cs_case_tl \l_@@_env_cs_case_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{InlineEnv}
+% \changes{v3.1.1}{2012/12/05}{改变行内环境的设置方式,从而使用 \cs{str_case_x:nnn}
+% 代替原来的 \cs{clist_if_in:NnTF} 来判断是否是行内环境。}
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ InlineEnv .code:n =
+ {
+ \seq_set_from_clist:Nn \l_@@_inline_env_seq {#1}
+ \@@_update_inline_env_case_tl:
+ } ,
+ InlineEnv+ .code:n =
+ {
+ \clist_map_inline:nn {#1}
+ {
+ \seq_if_in:NnF \l_@@_inline_env_seq {##1}
+ { \seq_put_right:Nn \l_@@_inline_env_seq {##1} }
+ }
+ \@@_update_inline_env_case_tl:
+ } ,
+ InlineEnv- .code:n =
+ {
+ \clist_map_inline:nn {#1}
+ { \seq_remove_all:Nn \l_@@_inline_env_seq {##1} }
+ \@@_update_inline_env_case_tl:
+ }
+ }
+\seq_new:N \l_@@_inline_env_seq
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_update_inline_env_case_tl:}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_update_inline_env_case_tl:
+ {
+ \tl_clear:N \l_@@_inline_env_case_tl
+ \seq_map_inline:Nn \l_@@_inline_env_seq
+ { \tl_put_right:Nn \l_@@_inline_env_case_tl { {##1} { } } }
+ }
+\tl_new:N \l_@@_inline_env_case_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{增加 CJK 子分区}
+%
+% \begin{variable}{\g_@@_CJK_sub_class_seq}
+% \begin{macrocode}
+\seq_new:N \g_@@_CJK_sub_class_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\xeCJKDeclareSubCJKBlock}
+% 声明 CJK 子区范围,|#1| 为自定义名称,|#2| 为子区的 |Unicode| 范围。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKDeclareSubCJKBlock
+ { s > { \TrimSpaces } m m }
+ {
+ \xeCJK_declare_sub_char_class:nxn { CJK } {#2} {#3}
+ \IfBooleanT {#1} { \xeCJKResetPunctClass }
+ }
+\@onlypreamble \xeCJKDeclareSubCJKBlock
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKCancelSubCJKBlock,\xeCJKRestoreSubCJKBlock}
+% 取消和恢复对 CJK 子区的声明。
+% \begin{macrocode}
+\bool_new:N \l_@@_sub_cancel_bool
+\NewDocumentCommand \xeCJKCancelSubCJKBlock { s m }
+ {
+ \bool_if:NF \l_@@_sub_cancel_bool
+ {
+ \bool_set_true:N \l_@@_sub_cancel_bool
+ \@@_sub_restore_or_cancel:x {#2}
+ \IfBooleanT {#1} { \xeCJKResetPunctClass }
+ }
+ }
+\NewDocumentCommand \xeCJKRestoreSubCJKBlock { s m }
+ {
+ \bool_if:NT \l_@@_sub_cancel_bool
+ {
+ \bool_set_false:N \l_@@_sub_cancel_bool
+ \@@_sub_restore_or_cancel:x {#2}
+ \IfBooleanT {#1} { \xeCJKResetPunctClass }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_sub_restore_or_cancel:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_sub_restore_or_cancel:n #1
+ {
+ \clist_map_inline:nn {#1}
+ {
+ \int_if_exist:cTF { \@@_class_csname:n { CJK/##1 } }
+ {
+ \xeCJK_declare_char_class:nn
+ { CJK \bool_if:NF \l_@@_sub_cancel_bool { /##1 } }
+ { \use:c { g_@@_CJK/##1_range_clist } }
+ }
+ { \@@_error:nx { SubBlock-undefined } {##1} }
+ }
+ }
+\cs_generate_variant:Nn \@@_sub_restore_or_cancel:n { x }
+\@@_msg_new:nn { SubBlock-undefined }
+ {
+ The~CJK~sub~block~`#1'~is~undefined.\\\\
+ Try~to~use~\token_to_str:N \xeCJKDeclareSubCJKBlock \
+ to~declare~it.
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_declare_sub_char_class:nnn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_declare_sub_char_class:nnn #1#2#3
+ {
+ \int_if_exist:cF { \@@_class_csname:n { #1/#2 } }
+ {
+ \xeCJK_new_class:n { #1/#2 }
+ \@@_set_sub_class_toks:nn {#1} {#2}
+ \xeCJK_new_sub_key:n {#2}
+ }
+ \xeCJK_declare_char_class:nn { #1/#2 } {#3}
+ }
+\cs_generate_variant:Nn \xeCJK_declare_sub_char_class:nnn { nx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_sub_class_toks:nn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_set_sub_class_toks:nn #1#2
+ {
+ \seq_map_inline:Nn \g_@@_base_class_seq
+ {
+ \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } {##1} {#1} {##1}
+ \xeCJK_copy_inter_class_toks:nnnn {##1} { #1/#2 } {##1} {#1}
+ \str_if_eq:nnTF {##1} { CJK }
+ {
+ \xeCJK_pre_inter_class_toks:nnn {##1} { #1/#2 }
+ { \@@_switch_font:nn {#1} {#2} }
+ }
+ {
+ \xeCJK_replace_inter_class_toks:nnnn {##1} { #1/#2 }
+ { \CJKsymbol }
+ { \@@_switch_font:nn {#1} {#2} \CJKsymbol }
+ }
+ }
+ \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } { #1/#2 } {#1} {#1}
+ \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
+ {
+ \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } { #1/##1 } {#1} {#1}
+ \xeCJK_copy_inter_class_toks:nnnn { #1/##1 } { #1/#2 } {#1} {#1}
+ \xeCJK_pre_inter_class_toks:nnn { #1/#2 } { #1/##1 }
+ { \@@_switch_font:nn {#2} {##1} }
+ \xeCJK_pre_inter_class_toks:nnn { #1/##1 } { #1/#2 }
+ { \@@_switch_font:nn {##1} {#2} }
+ }
+ \seq_gput_right:Nn \g_@@_CJK_sub_class_seq {#2}
+ \@@_save_CJK_class:n { #1/#2 }
+ \clist_map_inline:nn { CJK , FullLeft , FullRight , HangulJamo }
+ {
+ \xeCJK_pre_inter_class_toks:nnn { #1/#2 } {##1}
+ { \@@_switch_font:nn {#2} {#1} }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{标点处理}
+%
+% \changes{v3.2.7}{2013/08/22}{实现自定义行首/尾标点符号宽度功能。}
+% \changes{v3.7.4}{2019/05/31}{简化行首/尾标点符号宽度的实现。}
+%
+% \tn{XeTeXglyphbounds} 可以得到一个字符的左右边距,用于标点压缩。如果它不可用,则
+% 在文档中只能使用 |plain| 这一标点格式原样输出标点。
+% \begin{macrocode}
+\cs_if_exist:NF \tex_XeTeXglyphbounds:D
+ {
+ \@@_msg_new:nn { XeTeX-too-old }
+ {
+ \token_to_str:N \tex_XeTeXglyphbounds:D \ is~not~defined.\\
+ CJK~punctuation~kerning~will~not~be~available.\\\\
+ You~have~to~update~XeTeX~to~the~version~0.9995.0~or~later.
+ }
+ \@@_error:n { XeTeX-too-old }
+ \AtEndOfPackage
+ {
+ \keys_define:nn { xeCJK / options }
+ {
+ PunctStyle / unknown .code:n =
+ { \@@_error:nx { punct-style-unknown } { \l_keys_value_tl } }
+ }
+ \seq_gclear:N \g_@@_punct_style_seq
+ \keys_set:nn { xeCJK / options } { PunctStyle = plain }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macro}{\xeCJKsetwidth}
+% 手动设置参数中的标点符号的宽度。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKsetwidth { s m m }
+ {
+ \IfBooleanTF {#1}
+ {
+ \tl_map_inline:xn {#2}
+ { \tl_gset:cn { g_@@_punct_bound_width/##1/tl } {#3} }
+ }
+ {
+ \tl_map_inline:xn {#2}
+ { \tl_gset:cn { g_@@_punct_width/##1/tl } {#3} }
+ }
+ }
+\@onlypreamble \xeCJKsetwidth
+\cs_generate_variant:Nn \tl_map_inline:nn { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKsetkern}
+% 手动设置相邻标点的距离。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKsetkern { m m m }
+ { \tl_gset:cn { g_@@_punct/kern/#1/#2/tl } {#3} }
+\@onlypreamble \xeCJKsetkern
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\c_@@_left_tl,\c_@@_right_tl}
+% \begin{macrocode}
+\tl_const:Nn \c_@@_left_tl { left }
+\tl_const:Nn \c_@@_right_tl { right }
+% \end{macrocode}
+% \end{variable}
+%
+% \changes{v3.2.12}{2014/05/12}{新增 \texttt{RubberPunctSkip} 选项。}
+% \changes{v3.4.0}{2016/05/13}{\texttt{RubberPunctSkip} 选项有新的值 \texttt{plus} 和 \texttt{minus}。}
+%
+% \begin{macro}
+% {AllowBreakBetweenPuncts,KaiMingPunct,LongPunct,
+% MiddlePunct,PunctWidth,PunctBoundWidth,RubberPunctSkip}
+% 相关选项声明。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ AllowBreakBetweenPuncts .choice: ,
+ AllowBreakBetweenPuncts / true .code:n =
+ {
+ \bool_set_true:N \l_@@_punct_breakable_bool
+ \cs_set_eq:NN \xeCJK_punct_kern:NN \@@_punct_breakable_kern:NN
+ \cs_set_eq:NN \@@_punct_bound_kern:N
+ \@@_punct_bound_breakable_kern:N
+ } ,
+ AllowBreakBetweenPuncts / false .code:n =
+ {
+ \bool_set_false:N \l_@@_punct_breakable_bool
+ \cs_set_eq:NN \xeCJK_punct_kern:NN \@@_punct_kern:NN
+ \cs_set_eq:NN \@@_punct_bound_kern:N
+ \@@_nobreak_hskip:N
+ } ,
+ AllowBreakBetweenPuncts .default:n = { true } ,
+ KaiMingPunct .code:n = { \@@_set_special_punct:nn { mixed_width } {#1} } ,
+ KaiMingPunct+ .code:n = { \@@_add_special_punct:nn { mixed_width } {#1} } ,
+ KaiMingPunct- .code:n = { \@@_sub_special_punct:nn { mixed_width } {#1} } ,
+ LongPunct .code:n = { \@@_set_special_punct:nn { long } {#1} } ,
+ LongPunct+ .code:n = { \@@_add_special_punct:nn { long } {#1} } ,
+ LongPunct- .code:n = { \@@_sub_special_punct:nn { long } {#1} } ,
+ MiddlePunct .code:n = { \@@_set_special_punct:nn { middle } {#1} } ,
+ MiddlePunct+ .code:n = { \@@_add_special_punct:nn { middle } {#1} } ,
+ MiddlePunct- .code:n = { \@@_sub_special_punct:nn { middle } {#1} } ,
+ PunctWidth .tl_gset:N = \g_@@_punct_width_tl ,
+ PunctBoundWidth .tl_gset:N = \g_@@_punct_bound_width_tl ,
+ PunctWidth .value_required:n = true ,
+ PunctBoundWidth .value_required:n = true ,
+ RubberPunctSkip .choice: ,
+ RubberPunctSkip .default:n = { true } ,
+ RubberPunctSkip / true .code:n =
+ { \cs_set_eq:NN \@@_use_dim_or_skip:nNN \@@_use_punct_skip:nNN } ,
+ RubberPunctSkip / plus .code:n =
+ { \cs_set_eq:NN \@@_use_dim_or_skip:nNN \@@_use_punct_skip_plus:nNN } ,
+ RubberPunctSkip / minus .code:n =
+ { \cs_set_eq:NN \@@_use_dim_or_skip:nNN \@@_use_punct_skip_minus:nNN } ,
+ RubberPunctSkip / false .code:n =
+ { \cs_set_eq:NN \@@_use_dim_or_skip:nNN \@@_use_punct_dim:nNN }
+ }
+\bool_new:N \l_@@_punct_breakable_bool
+% \end{macrocode}
+% \end{macro}
+%
+% 相关选项定义的辅助函数。
+% \begin{macrocode}
+\clist_new:N \g_@@_special_punct_clist
+\clist_gset:Nn \g_@@_special_punct_clist { mixed_width , long , middle }
+\cs_new_nopar:Npn \@@_special_punct_seq:n #1 { g_@@_special_punct_#1_seq }
+\cs_new_nopar:Npn \@@_special_punct_tl:nN #1#2 { g_@@_special_punct_#1_#2_tl }
+\clist_map_inline:Nn \g_@@_special_punct_clist
+ { \seq_new:c { \@@_special_punct_seq:n {#1} } }
+\cs_new_protected_nopar:Npn \@@_set_special_punct:nn #1#2
+ {
+ \seq_map_inline:cn { \@@_special_punct_seq:n {#1} }
+ { \cs_undefine:c { \@@_special_punct_tl:nN {#1} {##1} } }
+ \seq_gclear:c { \@@_special_punct_seq:n {#1} }
+ \tl_map_inline:xn {#2}
+ {
+ \tl_new:c { \@@_special_punct_tl:nN {#1} {##1} }
+ \seq_gput_right:cn { \@@_special_punct_seq:n {#1} } {##1}
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_add_special_punct:nn #1#2
+ {
+ \tl_map_inline:xn {#2}
+ {
+ \seq_if_in:cnF { \@@_special_punct_seq:n {#1} } {##1}
+ {
+ \tl_new:c { \@@_special_punct_tl:nN {#1} {##1} }
+ \seq_gput_right:cn { \@@_special_punct_seq:n {#1} } {##1}
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_sub_special_punct:nn #1#2
+ {
+ \tl_map_inline:xn {#2}
+ {
+ \cs_undefine:c { \@@_special_punct_tl:nN {#1} {##1} }
+ \seq_gremove_all:cn { \@@_special_punct_seq:n {#1} } {##1}
+ }
+ }
+% \end{macrocode}
+%
+% 判断一个标点符号是否为全角右标点和长标点符号。
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_punct_if_right:N #1 { p , T , F , TF }
+ {
+ \if_int_compare:w \xeCJK_token_value_class:N #1 =
+ \xeCJK_class_num:n { FullRight }
+ \prg_return_true: \else: \prg_return_false: \fi:
+ }
+\clist_map_inline:Nn \g_@@_special_punct_clist
+ {
+ \exp_args:Nc
+ \prg_new_conditional:Npnn { @@_punct_if_#1:N } ##1 { p , T , F , TF }
+ {
+ \if_cs_exist:w \@@_special_punct_tl:nN {#1} {##1} \cs_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+ }
+ }
+% \end{macrocode}
+%
+% 一些用于记录的辅助函数。
+% \begin{macrocode}
+\cs_new:Npn \@@_punct_csname:n #1
+ { c_@@_\l_xeCJK_current_font_tl/\l_xeCJK_punct_style_tl/#1/tl }
+\cs_new:Npn \@@_use_punct_dim:nN #1#2
+ { \use:c { \@@_punct_csname:n { dim/#1/#2 } } }
+\cs_new:Npn \@@_use_punct_dim:nNN #1#2#3
+ { \use:c { \@@_punct_csname:n { dim/#1/#2/#3 } } }
+\cs_new:Npn \@@_use_punct_skip:nNN #1#2#3
+ { \use:c { \@@_punct_csname:n { skip/#1/#2/#3 } } }
+\cs_new:Npn \@@_use_punct_skip_plus:nNN #1#2#3
+ { \use:c { \@@_punct_csname:n { skip/plus/#1/#2/#3 } } }
+\cs_new:Npn \@@_use_punct_skip_minus:nNN #1#2#3
+ { \use:c { \@@_punct_csname:n { skip/minus/#1/#2/#3 } } }
+\cs_new_protected:Npn \@@_save_punct_dim:nNn #1#2
+ { \@@_save_punct_width_aux:nnnn { dim } {#1} { #1/#2 } }
+\cs_new_protected:Npn \@@_save_punct_dim:nNNn #1#2#3
+ { \@@_save_punct_width_aux:nnnn { dim } {#1} { #1/#2/#3 } }
+\cs_new_protected:Npn \@@_save_punct_skip:nNNn #1#2#3#4
+ {
+ \@@_save_punct_width_aux:nnnn { skip } {#1} { #1/#2/#3 } {#4}
+ \@@_save_punct_width_aux:nnnn { skip } {#1} { plus/#1/#2/#3 } {#4}
+ \@@_save_punct_width_aux:nnnn { skip } {#1} { minus/#1/#2/#3 } {#4}
+ }
+\cs_new_protected:Npn \@@_save_punct_skip:nNNnnn #1#2#3#4#5#6
+ {
+ \use:x
+ {
+ \@@_save_punct_skip_aux:nnnnn {#1} { #1/#2/#3 }
+ { \dim_eval:n {#4} }
+ { \dim_max:nn { \c_zero_dim } {#5} }
+ { \dim_max:nn { \c_zero_dim } {#6} }
+ }
+ }
+\cs_new_protected:Npn \@@_save_punct_skip_aux:nnnnn #1#2#3#4#5
+ {
+ \@@_save_punct_width_aux:nnnn { skip } {#1}
+ {#2} { #3 ~ plus ~ #4 ~ minus ~ #5 ~ }
+ \@@_save_punct_width_aux:nnnn { skip } {#1}
+ { plus/#2 } { #3 ~ plus ~ #4 ~ }
+ \@@_save_punct_width_aux:nnnn { skip } {#1}
+ { minus/#2 } { #3 ~ minus ~ #5 ~ }
+ }
+\cs_new_protected:Npn \@@_save_punct_width_aux:nnnn #1#2#3#4
+ {
+ \@@_save_punct_width_aux:cxn
+ { \@@_punct_csname:n { #1/#3 } }
+ { \use:c { #1_eval:n } {#4} }
+ {#2}
+ }
+\cs_new_protected:Npn \@@_save_punct_width_aux:Nnn #1#2#3
+ {
+ \tl_const:Nn #1 {#2}
+ \str_if_eq:nnT {#3} { glue }
+ { \prop_gput:Nnn \g_@@_punct_skip_prop {#2} { } }
+ }
+\prop_new:N \g_@@_punct_skip_prop
+\prop_gput:Non \g_@@_punct_skip_prop { \skip_use:N \c_zero_skip } { }
+\cs_generate_variant:Nn \@@_save_punct_width_aux:Nnn { cx }
+\cs_new_eq:NN \@@_use_dim_or_skip:nNN \@@_use_punct_skip:nNN
+% \end{macrocode}
+%
+% \changes{v3.1.0}{2012/11/14}{使用 \pkg{xtemplate} 宏包的机制来组织标点符号的处理。}
+%
+% 定义标点处理模板。
+% \begin{macrocode}
+\DeclareObjectType { xeCJK / punctuation } { 0 }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\DeclareTemplateInterface { xeCJK / punctuation } { basic } { 0 }
+ {
+ enabled-global-setting : boolean = true ,
+ fixed-punct-width : length = \c_max_dim ,
+ fixed-punct-ratio : real = \c_one_fp ,
+ mixed-punct-width : length = \KeyValue { fixed-punct-width } ,
+ mixed-punct-ratio : real = \KeyValue { fixed-punct-ratio } ,
+ middle-punct-width : length = \KeyValue { fixed-punct-width } ,
+ middle-punct-ratio : real = \KeyValue { fixed-punct-ratio } ,
+ fixed-margin-width : length = \c_max_dim ,
+ fixed-margin-ratio : real = \c_one_fp ,
+ mixed-margin-width : length = \KeyValue { fixed-margin-width } ,
+ mixed-margin-ratio : real = \KeyValue { fixed-margin-ratio } ,
+ middle-margin-width : length = \KeyValue { fixed-margin-width } ,
+ middle-margin-ratio : real = \KeyValue { fixed-margin-ratio } ,
+ bound-punct-width : length = \c_max_dim ,
+ bound-punct-ratio : real = \c_nan_fp ,
+ bound-margin-width : length = \c_max_dim ,
+ bound-margin-ratio : real = \c_zero_fp ,
+ enabled-hanging : boolean = false ,
+ add-min-bound-to-margin : boolean = false ,
+ optimize-margin : boolean = false ,
+ margin-minimum : length = \c_zero_dim ,
+ enabled-kerning : boolean = true ,
+ min-bound-to-kerning : boolean = false ,
+ kerning-total-width : length = \c_max_dim ,
+ kerning-total-ratio : real = 0.75 ,
+ optimize-kerning : boolean = false ,
+ same-align-margin : length = \c_max_dim ,
+ same-align-ratio : real = \c_nan_fp ,
+ different-align-margin : length = \c_max_dim ,
+ different-align-ratio : real = \c_nan_fp ,
+ kerning-margin-width : length = \c_max_dim ,
+ kerning-margin-ratio : real = \c_one_fp ,
+ kerning-margin-minimum : length = \c_zero_dim
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\DeclareTemplateCode { xeCJK / punctuation } { basic } { 0 }
+ {
+ enabled-global-setting = \l_@@_enabled_global_setting_bool ,
+ fixed-punct-width = \l_@@_fixed_punct_width_dim ,
+ fixed-punct-ratio = \l_@@_fixed_punct_ratio_fp ,
+ mixed-punct-width = \l_@@_mixed_punct_width_dim ,
+ mixed-punct-ratio = \l_@@_mixed_punct_ratio_fp ,
+ middle-punct-width = \l_@@_middle_punct_width_dim ,
+ middle-punct-ratio = \l_@@_middle_punct_ratio_fp ,
+ fixed-margin-width = \l_@@_fixed_margin_width_dim ,
+ fixed-margin-ratio = \l_@@_fixed_margin_ratio_fp ,
+ mixed-margin-width = \l_@@_mixed_margin_width_dim ,
+ mixed-margin-ratio = \l_@@_mixed_margin_ratio_fp ,
+ middle-margin-width = \l_@@_middle_margin_width_dim ,
+ middle-margin-ratio = \l_@@_middle_margin_ratio_fp ,
+ bound-punct-width = \l_@@_bound_punct_width_dim ,
+ bound-punct-ratio = \l_@@_bound_punct_ratio_fp ,
+ bound-margin-width = \l_@@_bound_margin_width_dim ,
+ bound-margin-ratio = \l_@@_bound_margin_ratio_fp ,
+ enabled-hanging = \l_@@_enabled_hanging_bool ,
+ add-min-bound-to-margin = \l_@@_add_min_bound_to_margin_bool ,
+ optimize-margin = \l_@@_optimize_margin_bool ,
+ margin-minimum = \l_@@_margin_minimum_dim ,
+ enabled-kerning = \l_@@_enabled_kerning_bool ,
+ min-bound-to-kerning = \l_@@_min_bound_to_kerning_bool ,
+ kerning-total-width = \l_@@_kerning_total_width_dim ,
+ kerning-total-ratio = \l_@@_kerning_total_ratio_fp ,
+ optimize-kerning = \l_@@_optimize_kerning_bool ,
+ same-align-margin = \l_@@_same_align_margin_dim ,
+ same-align-ratio = \l_@@_same_align_ratio_fp ,
+ different-align-margin = \l_@@_different_align_margin_dim ,
+ different-align-ratio = \l_@@_different_align_ratio_fp ,
+ kerning-margin-width = \l_@@_kerning_margin_width_dim ,
+ kerning-margin-ratio = \l_@@_kerning_margin_ratio_fp ,
+ kerning-margin-minimum = \l_@@_kerning_margin_minimum_dim
+ }
+ { \AssignTemplateKeys }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_get_punct_bounds:NN}
+% |#1| 为 \cs{c_@@_left_tl} 或 \cs{c_@@_right_tl},|#2| 为标点符号。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_get_punct_bounds:NN #1#2
+ {
+ \tl_if_exist:cF { \@@_punct_csname:n { dim/glue/#1/#2 } }
+ { \@@_get_punct_bounds_aux:NN #1 #2 }
+ }
+\cs_new_protected_nopar:Npn \@@_get_punct_bounds_aux:NN
+ {
+ \tl_if_eq:NNTF \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl
+ { \@@_save_punct_margin_plain:NN }
+ { \@@_save_punct_margin:NN }
+ }
+\cs_new_protected_nopar:Npn \xeCJK_get_punct_bounds:No
+ { \exp_last_unbraced:NNo \xeCJK_get_punct_bounds:NN }
+\cs_new_protected_nopar:Npn \@@_save_punct_margin_plain:NN #1#2
+ {
+ \@@_save_punct_dim:nNNn { rule } #1 #2 { \c_zero_dim }
+ \@@_save_punct_dim:nNNn { glue } #1 #2 { \c_zero_dim }
+ \@@_save_punct_dim:nNNn { offset } #1 #2 { \c_zero_dim }
+ \@@_save_punct_dim:nNNn { margin } #1 #2 { \c_zero_dim }
+ \@@_save_punct_dim:nNNn { bound } \c_@@_left_tl {#2} { \c_zero_dim }
+ \@@_save_punct_dim:nNNn { bound } \c_@@_right_tl {#2} { \c_zero_dim }
+ \@@_save_punct_skip:nNNn { glue } #1 #2 { \c_zero_skip }
+ }
+\cs_new_protected_nopar:Npn \@@_save_punct_margin:NN #1#2
+ {
+ \group_begin:
+ \xeCJK_select_punct_font:
+ \xeCJK_calc_punct_dimen:N #2
+ \group_end:
+ \dim_set:Nn \l_@@_bound_dim
+ { \@@_use_punct_dim:nNN { bound } #1 #2 }
+ \dim_set:Nn \l_@@_reverse_bound_dim
+ {
+ \tl_if_eq:NNTF #1 \c_@@_left_tl
+ { \@@_use_punct_dim:nNN { bound } \c_@@_right_tl }
+ { \@@_use_punct_dim:nNN { bound } \c_@@_left_tl }
+ #2
+ }
+ \UseInstance { xeCJK / punctuation } { \l_xeCJK_punct_style_tl }
+ \xeCJK_punct_margin_process:NN #1 #2
+ \xeCJK_punct_offset_process:NN #1 #2
+ \@@_punct_if_long:NT #2
+ { \@@_long_punct_kerning:N #2 }
+ }
+\dim_new:N \l_@@_bound_dim
+\dim_new:N \l_@@_reverse_bound_dim
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.7.0}{2018/03/12}{修正长标点被隔开时的压缩处理错误。}
+%
+% \begin{macro}[int]{\@@_long_punct_kerning:N}
+% \changes{v3.4.3}{2016/10/27}{考虑破折号边界为负值的情况。}
+% 相同长标点压缩。对于破折号,计算两标点之间的空白,保证它中间不被断开。
+% 注意,破折号的边界可能为负值(比如方正新书宋),此时不必压缩。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_long_punct_kerning:N #1
+ {
+ \dim_set:Nn \l_@@_tmp_dim
+ {
+ \dim_max:nn
+ { \l_@@_bound_dim + \l_@@_reverse_bound_dim }
+ { \c_zero_dim }
+ }
+ \@@_save_punct_dim:nNNn { bound_width } #1 #1 { \l_@@_tmp_dim }
+ \dim_set:Nn \l_@@_tmp_dim
+ {
+ \str_case:nnTF {#1}
+ { { ^^^^2025 } { } { ^^^^2026 } { } }
+ { \c_zero_dim }
+ { -\l_@@_tmp_dim }
+ }
+ \@@_save_punct_dim:nNNn { kern } #1 #1 { \l_@@_tmp_dim }
+ \@@_save_punct_skip:nNNn { kern } #1 #1 { \l_@@_tmp_dim }
+ \dim_add:Nn \l_@@_tmp_dim
+ { \dim_max:nn { \l_@@_bound_dim } { \c_zero_dim } }
+ \@@_save_punct_dim:nNNn { bound_kern } #1 #1 { \l_@@_tmp_dim }
+ \@@_save_punct_skip:nNNn { bound_kern } #1 #1 { \l_@@_tmp_dim }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_get_punct_kerning:NN}
+% 标点压缩。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_get_punct_kerning:NN #1#2
+ {
+ \tl_if_exist:cF { \@@_punct_csname:n { dim/kern/#1/#2 } }
+ {
+ \tl_if_eq:NNTF \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl
+ { \@@_save_punct_kerning_plain:NN }
+ { \@@_save_punct_kerning:NN }
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:Npn \xeCJK_get_punct_kerning:oN
+ { \exp_after:wN \xeCJK_get_punct_kerning:NN }
+\cs_new_protected_nopar:Npn \@@_save_punct_kerning_plain:NN #1#2
+ {
+ \@@_save_punct_dim:nNNn { kern } #1 #2 { \c_zero_dim }
+ \@@_save_punct_dim:nNNn { bound_kern } #1 #2 { \c_zero_dim }
+ \@@_save_punct_dim:nNNn { bound_width } #1 #2 { \c_zero_dim }
+ \@@_save_punct_skip:nNNn { kern } #1 #2 { \c_zero_skip }
+ \@@_save_punct_skip:nNNn { bound_kern } #1 #2 { \c_zero_skip }
+ }
+\cs_new_protected_nopar:Npn \@@_save_punct_kerning:NN
+ {
+ \UseInstance { xeCJK / punctuation } { \l_xeCJK_punct_style_tl }
+ \xeCJK_punct_kerning_process:NN
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_punct_margin_process:NN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_punct_margin_process:NN #1#2
+ {
+ \dim_set:Nn \l_@@_tmp_dim
+ {
+ \bool_if:NTF \l_@@_enabled_global_setting_bool
+ {
+ \cs_if_exist_use:cF { g_@@_punct_width/#2/tl }
+ {
+ \tl_if_empty:NTF \g_@@_punct_width_tl
+ { \@@_calc_punct_width:N #2 }
+ { \g_@@_punct_width_tl }
+ }
+ }
+ { \@@_calc_punct_width:N #2 }
+ }
+ \dim_set:Nn \l_@@_margin_dim
+ {
+ \dim_max:nn
+ { \l_@@_margin_minimum_dim }
+ {
+ \dim_compare:nNnTF \l_@@_tmp_dim < \c_max_dim
+ {
+ \@@_punct_if_middle:NTF #2
+ {
+ ( \l_@@_tmp_dim
+ - ( \@@_use_punct_dim:nN { dimen } #2 )
+ ) / 2
+ }
+ {
+ \bool_if:NTF \l_@@_optimize_margin_bool
+ {
+ \dim_max:nn
+ {
+ \dim_min:nn
+ { \l_@@_bound_dim }
+ { \l_@@_reverse_bound_dim }
+ }
+ }
+ { \use:n }
+ {
+ \l_@@_tmp_dim
+ - \l_@@_reverse_bound_dim
+ - ( \@@_use_punct_dim:nN { dimen } #2 )
+ }
+ }
+ }
+ {
+ \bool_if:NTF \l_@@_optimize_margin_bool
+ { \dim_min:nn { \l_@@_bound_dim } }
+ { \use:n }
+ { \@@_calc_margin_width:N #2 }
+ }
+ }
+ }
+ \@@_save_punct_dim:nNNn { margin } #1 #2 { \l_@@_margin_dim }
+ }
+\dim_new:N \l_@@_margin_dim
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_calc_punct_width:N}
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_calc_punct_width:N #1
+ {
+ \@@_punct_if_middle:NTF #1
+ { \@@_punct_width_or_ratio:nN { middle } }
+ {
+ \@@_punct_if_mixed_width:NTF #1
+ { \@@_punct_width_or_ratio:nN { mixed } }
+ { \@@_punct_width_or_ratio:nN { fixed } }
+ }
+ #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_calc_margin_width:N}
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_calc_margin_width:N #1
+ {
+ \@@_punct_if_middle:NTF #1
+ {
+ \dim_compare:nNnTF \l_@@_middle_margin_width_dim < \c_max_dim
+ { \l_@@_middle_margin_width_dim }
+ {
+ \fp_use:N \l_@@_middle_margin_ratio_fp
+ \tex_dimexpr:D
+ ( \l_@@_bound_dim + \l_@@_reverse_bound_dim ) / 2
+ \scan_stop:
+ }
+ }
+ {
+ \@@_punct_if_mixed_width:NTF #1
+ { \@@_margin_width_or_ratio:n { mixed } }
+ { \@@_margin_width_or_ratio:n { fixed } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_punct_offset_process:NN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_punct_offset_process:NN #1#2
+ {
+ \dim_set:Nn \l_@@_tmp_dim
+ {
+ \bool_if:NTF \l_@@_enabled_global_setting_bool
+ {
+ \cs_if_exist_use:cF { g_@@_punct_bound_width/#2/tl }
+ {
+ \tl_if_empty:NTF \g_@@_punct_bound_width_tl
+ { \@@_punct_width_or_ratio:nN { bound } #2 }
+ { \g_@@_punct_bound_width_tl }
+ }
+ }
+ { \@@_punct_width_or_ratio:nN { bound } #2 }
+ }
+ \dim_set:Nn \l_@@_tmp_dim
+ {
+ \bool_if:NTF \l_@@_enabled_hanging_bool
+ { \use:n }
+ { \dim_max:nn { \l_@@_margin_minimum_dim } }
+ {
+ \dim_compare:nNnTF \l_@@_tmp_dim < \c_max_dim
+ {
+ \@@_punct_if_middle:NTF #2
+ {
+ \l_@@_tmp_dim
+ - \l_@@_margin_dim
+ - ( \@@_use_punct_dim:nN { dimen } #2 )
+ }
+ {
+ \l_@@_tmp_dim
+ - \l_@@_reverse_bound_dim
+ - ( \@@_use_punct_dim:nN { dimen } #2 )
+ }
+ }
+ {
+ \bool_if:NTF \l_@@_optimize_margin_bool
+ { \dim_min:nn { \l_@@_bound_dim } }
+ { \use:n }
+ { \@@_margin_width_or_ratio:n { bound } }
+ }
+ }
+ }
+ \@@_save_punct_dim:nNNn { offset } #1 #2
+ { \l_@@_tmp_dim }
+ \@@_save_punct_dim:nNNn { rule } #1 #2
+ { \l_@@_tmp_dim - \l_@@_bound_dim }
+ \@@_save_punct_dim:nNNn { glue } #1 #2
+ { \l_@@_margin_dim - \l_@@_tmp_dim }
+ \@@_save_punct_skip:nNNnnn { glue } #1 #2
+ { \l_@@_margin_dim - \l_@@_tmp_dim }
+ {
+ \@@_punct_if_middle:NTF #2
+ {
+ ( \@@_use_punct_dim:nN { width } #2 -
+ \@@_use_punct_dim:nN { dimen } #2 ) / 2
+ - \l_@@_margin_dim
+ }
+ { \l_@@_bound_dim - \l_@@_margin_dim }
+ }
+ {
+ \@@_punct_if_middle:NTF #2
+ { .5 \l_@@_margin_dim }
+ { \l_@@_margin_dim - \l_@@_reverse_bound_dim }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.7}{2013/08/25}{标点宽度设置禁用比例选项的值改为 \texttt{nan}。}
+%
+% \begin{macro}{\@@_punct_width_or_ratio:nN}
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_punct_width_or_ratio:nN #1#2
+ {
+ \dim_compare:nNnTF { \use:c { l_@@_#1_punct_width_dim } } < \c_max_dim
+ { \use:c { l_@@_#1_punct_width_dim } }
+ {
+ \fp_compare:nNnTF { \use:c { l_@@_#1_punct_ratio_fp } } ? \c_zero_fp
+ { \c_max_dim }
+ {
+ \fp_use:c { l_@@_#1_punct_ratio_fp }
+ \tex_dimexpr:D \@@_use_punct_dim:nN { width } #2 \scan_stop:
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_margin_width_or_ratio:n}
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_margin_width_or_ratio:n #1
+ {
+ \dim_compare:nNnTF { \use:c { l_@@_#1_margin_width_dim } } < \c_max_dim
+ { \use:c { l_@@_#1_margin_width_dim } }
+ {
+ \fp_use:c { l_@@_#1_margin_ratio_fp }
+ \tex_dimexpr:D \l_@@_bound_dim \scan_stop:
+ }
+ \bool_if:NT \l_@@_add_min_bound_to_margin_bool
+ { + \dim_min:nn \l_@@_bound_dim \l_@@_reverse_bound_dim }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4.4}{2016/11/30}{不压缩长标点与其他标点的间距。}
+%
+% \begin{macro}[int]{\xeCJK_punct_kerning_process:NN}
+% 当标点之一为长标点时,不必进行压缩。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_punct_kerning_process:NN #1#2
+ {
+ \dim_set:Nn \l_@@_margin_dim
+ { \@@_original_kerning_margin:NN #1 #2 }
+ \dim_set:Nn \l_@@_minimum_bound_dim
+ { \@@_punct_min_bound:NN #1 #2 }
+ \@@_punct_if_long:NTF #1
+ { \bool_set_false:N \l_@@_enabled_kerning_bool }
+ {
+ \@@_punct_if_long:NT #2
+ { \bool_set_false:N \l_@@_enabled_kerning_bool }
+ }
+ \dim_set:Nn \l_@@_kerning_margin_dim
+ {
+ \bool_if:NTF \l_@@_enabled_global_setting_bool
+ {
+ \cs_if_exist_use:cF { g_@@_punct/kern/#1/#2/tl }
+ { \@@_punct_kerning_process_aux:NN #1 #2 }
+ }
+ { \@@_punct_kerning_process_aux:NN #1 #2 }
+ }
+ \@@_save_kerning:nnNN { kern } { bound } #1 #2
+ \@@_save_punct_dim:nNNn { bound_width } #1 #2
+ { \l_@@_kerning_margin_dim - \l_@@_tmp_dim }
+ \@@_punct_if_right:NTF #1
+ {
+ \@@_punct_if_right:NTF #2
+ { \@@_save_kerning:nnnNN { bound_kern } { offset } { bound } }
+ { \@@_save_kerning:nnNN { bound_kern } { offset } }
+ }
+ {
+ \@@_punct_if_right:NTF #2
+ { \@@_save_kerning:nnNN { bound_kern } { bound } }
+ { \@@_save_kerning:nnnNN { bound_kern } { bound } { offset } }
+ }
+ #1 #2
+ }
+\cs_new_nopar:Npn \@@_punct_kerning_process_aux:NN #1#2
+ {
+ \bool_if:NTF \l_@@_enabled_kerning_bool
+ { \@@_calc_kerning_margin:NN #1 #2 }
+ { \l_@@_margin_dim }
+ }
+\dim_new:N \l_@@_minimum_bound_dim
+\dim_new:N \l_@@_kerning_margin_dim
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4.0}{2016/05/12}{标点符号的压缩量能伸长到原始空白,能收缩到较小边距。}
+%
+% \begin{macro}{\@@_save_kerning:nnNN}
+% 相邻两个标点符号的间距能伸长到原始空白(未压缩时的状态),能收缩到较小边距。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_save_kerning:nnNN #1#2
+ { \@@_save_kerning:nnnNN {#1} {#2} {#2} }
+\cs_new_protected_nopar:Npn \@@_save_kerning:nnnNN #1#2#3#4#5
+ {
+ \dim_set:Nn \l_@@_tmp_dim
+ {
+ \l_@@_kerning_margin_dim
+ - ( \@@_use_punct_dim:nNN {#2} \c_@@_right_tl #4 )
+ - ( \@@_use_punct_dim:nNN {#3} \c_@@_left_tl #5 )
+ }
+ \@@_save_punct_dim:nNNn {#1} #4 #5 { \l_@@_tmp_dim }
+ \@@_save_punct_skip:nNNnnn {#1} #4 #5
+ { \l_@@_tmp_dim }
+ { \l_@@_margin_dim - \l_@@_kerning_margin_dim }
+ { \l_@@_kerning_margin_dim - \l_@@_minimum_bound_dim }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_original_kerning_margin:NN}
+% 相邻两个标点符号之间的本来空白宽度。
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_original_kerning_margin:NN #1#2
+ {
+ \dim_eval:n
+ {
+ \@@_use_punct_dim:nNN
+ { \@@_punct_if_right:NTF #1 { margin } { bound } } \c_@@_right_tl #1
+ +
+ \@@_use_punct_dim:nNN
+ { \@@_punct_if_right:NTF #2 { bound } { margin } } \c_@@_left_tl #2
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_calc_kerning_margin:NN,\@@_calc_kerning_margin_aux:NN}
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_calc_kerning_margin:NN #1#2
+ {
+ \dim_max:nn
+ { \l_@@_kerning_margin_minimum_dim }
+ {
+ \bool_if:NTF \l_@@_min_bound_to_kerning_bool
+ { \l_@@_minimum_bound_dim }
+ {
+ \bool_if:NTF \l_@@_optimize_kerning_bool
+ { \dim_max:nn { \l_@@_minimum_bound_dim } }
+ { \use:n }
+ { \@@_calc_kerning_margin_aux:NN #1 #2 }
+ }
+ }
+ }
+\cs_new_nopar:Npn \@@_calc_kerning_margin_aux:NN #1#2
+ {
+ \dim_compare:nNnTF \l_@@_kerning_total_width_dim < \c_max_dim
+ { \@@_calc_kerning_margin:nNN \l_@@_kerning_total_width_dim }
+ {
+ \fp_compare:nNnTF \l_@@_kerning_total_ratio_fp ? \c_zero_fp
+ {
+ \xeCJK_if_same_class:NNTF #1 #2
+ { \@@_kerning_width_or_ratio:nNN { same } }
+ { \@@_kerning_width_or_ratio:nNN { different } }
+ }
+ {
+ \@@_calc_kerning_margin:nNN
+ {
+ \fp_use:N \l_@@_kerning_total_ratio_fp
+ \tex_dimexpr:D
+ \@@_use_punct_dim:nN { width } #1 +
+ \@@_use_punct_dim:nN { width } #2
+ \scan_stop:
+ }
+ }
+ }
+ #1 #2
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_kerning_width_or_ratio:nNN}
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_kerning_width_or_ratio:nNN #1#2#3
+ {
+ \dim_compare:nNnTF { \use:c { l_@@_#1_align_margin_dim } } < \c_max_dim
+ { \use:c { l_@@_#1_align_margin_dim } }
+ {
+ \fp_compare:nNnTF { \use:c { l_@@_#1_align_ratio_fp } } ? \c_zero_fp
+ {
+ \dim_compare:nNnTF \l_@@_kerning_margin_width_dim < \c_max_dim
+ { \l_@@_kerning_margin_width_dim \use_none:n }
+ { \fp_use:N \l_@@_kerning_margin_ratio_fp \use:n }
+ }
+ { \fp_use:c { l_@@_#1_align_ratio_fp } \use:n }
+ { \l_@@_margin_dim }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_punct_min_bound:NN}
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_punct_min_bound:NN #1#2
+ {
+ \dim_max:nn
+ {
+ \dim_min:nn
+ { \@@_use_punct_dim:nNN { bound } \c_@@_left_tl #1 }
+ { \@@_use_punct_dim:nNN { bound } \c_@@_right_tl #1 }
+ }
+ {
+ \dim_min:nn
+ { \@@_use_punct_dim:nNN { bound } \c_@@_left_tl #2 }
+ { \@@_use_punct_dim:nNN { bound } \c_@@_right_tl #2 }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_calc_kerning_margin:nNN}
+% |#2| 和 |#3| 为相邻的两个标点,|#1| 为要确定的相邻两个标点总共占的宽度。
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_calc_kerning_margin:nNN #1#2#3
+ {
+ \dim_eval:n
+ {
+ (#1)
+ - ( \@@_use_punct_dim:nNN
+ { \@@_punct_if_right:NTF #2 { bound } { margin } }
+ \c_@@_left_tl #2 )
+ - ( \@@_use_punct_dim:nNN
+ { \@@_punct_if_right:NTF #3 { margin } { bound } }
+ \c_@@_right_tl #3 )
+ - ( \@@_use_punct_dim:nN { dimen } #2 )
+ - ( \@@_use_punct_dim:nN { dimen } #3 )
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_calc_punct_dimen:N}
+% 计算标点的左右实际边距和实际尺寸。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_calc_punct_dimen:N #1
+ {
+ \@@_save_punct_dim:nNNn { bound } \c_@@_left_tl #1
+ { \xeCJK_glyph_bounds:NN 1 #1 }
+ \@@_save_punct_dim:nNNn { bound } \c_@@_right_tl #1
+ { \xeCJK_glyph_bounds:NN 3 #1 }
+ \@@_save_punct_dim:nNn { width } #1
+ { \tex_fontcharwd:D \tex_font:D `#1 }
+ \@@_save_punct_dim:nNn { dimen } #1
+ {
+ ( \@@_use_punct_dim:nN { width } #1 ) -
+ ( \@@_use_punct_dim:nNN { bound } \c_@@_left_tl #1 ) -
+ ( \@@_use_punct_dim:nNN { bound } \c_@@_right_tl #1 )
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_glyph_bounds:NN}
+% 用 \tn{XeTeXglyphbounds} 取得标点符号的上下左右空白。
+% \begin{macrocode}
+\cs_new_nopar:Npn \xeCJK_glyph_bounds:NN #1#2
+ { \tex_XeTeXglyphbounds:D #1 ~ \tex_XeTeXcharglyph:D `#2 \exp_stop_f: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{PunctStyle}
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ PunctStyle .choice: ,
+ PunctStyle .default:n = { quanjiao } ,
+ PunctStyle / halfwidth .meta:n = { PunctStyle = banjiao } ,
+ PunctStyle / fullwidth .meta:n = { PunctStyle = quanjiao } ,
+ PunctStyle / mixedwidth .meta:n = { PunctStyle = kaiming } ,
+ PunctStyle / marginkerning .meta:n = { PunctStyle = hangmobanjiao } ,
+ PunctStyle / plain .code:n =
+ { \tl_set_eq:NN \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl } ,
+ PunctStyle / unknown .code:n =
+ {
+ \IfInstanceExistTF { xeCJK / punctuation } { \l_keys_value_tl }
+ { \tl_set:Nx \l_xeCJK_punct_style_tl { \l_keys_value_tl } }
+ { \@@_error:nx { punct-style-unknown } { \l_keys_value_tl } }
+ }
+ }
+\tl_new:N \l_xeCJK_punct_style_tl
+\tl_const:Nn \c_@@_punct_style_plain_tl { plain }
+\@@_msg_new:nn { punct-style-unknown }
+ {
+ Punctuation~style~"#1"~is~unknown. \\\\
+ The~available~styles~are~listed~as~follow.\\\\
+ "plain,~\seq_use:Nnnn \g_@@_punct_style_seq { ~and~ } { ,~ } { ,~and~ }".\\
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKDeclarePunctStyle}
+% 定义新的标点处理风格,已经存在的同名风格将被覆盖。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKDeclarePunctStyle { > { \TrimSpaces } m m }
+ {
+ \IfInstanceExistTF { xeCJK / punctuation } {#1}
+ { \@@_warning:nx { punct-style-already-defined } {#1} }
+ { \seq_gput_right:Nx \g_@@_punct_style_seq {#1} }
+ \exp_args:Nnx \DeclareInstance { xeCJK / punctuation } {#1} { basic } {#2}
+ }
+\seq_new:N \g_@@_punct_style_seq
+\@@_msg_new:nn { punct-style-already-defined }
+ {
+ Punctuation~style~"#1"~is~already~defined!. \\\\
+ The~existing~style~of~"#1"~will~be~overwritten.\\
+ }
+\@onlypreamble \xeCJKDeclarePunctStyle
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKEditPunctStyle}
+% 对已有的标点处理风格进行修改。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKEditPunctStyle { > { \TrimSpaces } m m }
+ {
+ \IfInstanceExistTF { xeCJK / punctuation } {#1}
+ { \exp_args:Nnx \EditInstance { xeCJK / punctuation } {#1} {#2} }
+ { \@@_error:nx { punct-style-unknown } {#1} }
+ }
+\@onlypreamble \xeCJKEditPunctStyle
+% \end{macrocode}
+% \end{macro}
+%
+% 默认设置即为全角格式。
+% \begin{macrocode}
+\xeCJKDeclarePunctStyle { quanjiao } { }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\xeCJKDeclarePunctStyle { hangmobanjiao } { enabled-kerning = false }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\xeCJKDeclarePunctStyle { banjiao }
+ {
+ fixed-punct-ratio = 0.5 ,
+ optimize-margin = true ,
+ kerning-total-ratio = 0.5 ,
+ optimize-kerning = true
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\xeCJKDeclarePunctStyle { kaiming }
+ {
+ fixed-punct-ratio = 0.5 ,
+ mixed-punct-ratio = 0.8 ,
+ optimize-margin = true ,
+ kerning-total-ratio = 0.5 ,
+ optimize-kerning = true
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\xeCJKDeclarePunctStyle { CCT }
+ {
+ fixed-punct-ratio = 0.7 ,
+ optimize-margin = true ,
+ kerning-total-ratio = 0.6 ,
+ optimize-kerning = true
+ }
+% \end{macrocode}
+%
+% \subsection{后备字体}
+%
+% \begin{macro}{AutoFallBack}
+% 后备字体的宏包选项声明。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ AutoFallBack .choice: ,
+ AutoFallBack / true .code:n =
+ {
+ \cs_if_eq:NNF \CJKsymbol \xeCJK_fallback_test_glyph:N
+ {
+ \cs_set_eq:NN \@@_fallback_save_CJKsymbol:N \CJKsymbol
+ \cs_set_eq:NN \CJKsymbol \xeCJK_fallback_test_glyph:N
+ }
+ } ,
+ AutoFallBack / false .code:n =
+ {
+ \cs_if_eq:NNT \CJKsymbol \xeCJK_fallback_test_glyph:N
+ { \cs_set_eq:NN \CJKsymbol \@@_fallback_save_CJKsymbol:N }
+ } ,
+ AutoFallBack .default:n = { true } ,
+ fallback .meta:n = { AutoFallBack = true }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_fallback_test_glyph:N}
+% 测试当前字体中是否存在当前字符,如存在则直接输出,否则启用后备字体。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_fallback_test_glyph:N #1
+ {
+ \xeCJK_glyph_if_exist:NTF #1
+ { \@@_fallback_save_CJKsymbol:N #1 }
+ {
+ \group_begin:
+ \xeCJK_aftergroup_reset_Boundary:N #1
+ \tl_set_eq:NN \l_@@_fallback_family_tl \l_xeCJK_family_tl
+ \xeCJK_fallback_loop:No #1 { \l_xeCJK_family_tl/FallBack }
+ \group_end:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.5.1}{2017/11/16}{修正 fallback 字体后无法忽略空格的错误。}
+%
+% \begin{macro}[int]{\xeCJK_aftergroup_reset_Boundary:N}
+% 在分组中暂时清空 |#1| 与边界的 toks,分组后恢复。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_aftergroup_reset_Boundary:N #1
+ {
+ \tl_set:Nx \l_@@_tmp_tl
+ { \tex_the:D \tex_XeTeXcharclass:D `#1 ~ \xeCJK_class_num:n { Boundary } }
+ \tl_gset:Nx \g_@@_aftergroup_Boundary_tl
+ { \tex_the:D \tex_XeTeXinterchartoks:D \l_@@_tmp_tl }
+ \tex_XeTeXinterchartoks:D \l_@@_tmp_tl = { \prg_do_nothing: }
+ \group_insert_after:N \g_@@_aftergroup_Boundary_tl
+ }
+\tl_new:N \g_@@_aftergroup_Boundary_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.12}{2014/05/12}{更新 \cs{int_to_Hex:n}。}
+%
+% \begin{macro}[int]{\xeCJK_fallback_loop:Nn}
+% \changes{v3.1.0}{2012/11/19}{调整备用字体的循环方式。}
+% \changes{v3.2.4}{2013/06/30}
+% {使 \tn{CJKfamilydefault} 的 \texttt{FallBack} 设置全局可用。}
+% 循环测试后备字体是否包含字符 |#1|。若后备字体中存在该字符或者再没有后备字体,则
+% 结束循环。当前字体族没有备用字体时,使用 \tn{CJKfamilydefault} 的设置。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_fallback_loop:Nn #1#2
+ {
+ \xeCJK_family_if_exist:nTF {#2}
+ {
+ \tl_set:Nn \l_xeCJK_family_tl {#2}
+ \tl_set_eq:NN \CJK@family \l_@@_fontspec_family_tl
+ \xeCJK_select_font:
+ \xeCJK_glyph_if_exist:NTF #1
+ { \@@_fallback_save_CJKsymbol:N #1 }
+ { \xeCJK_fallback_loop:No #1 { \l_xeCJK_family_tl/FallBack } }
+ }
+ {
+ \str_if_eq:eeTF { \CJKfamilydefault } { \l_@@_fallback_family_tl }
+ {
+ \@@_warning:nxxx { missing-glyph }
+ { \l_xeCJK_family_tl } {#1}
+ { \int_to_Hex:n { `#1 } }
+ \@@_fallback_save_CJKsymbol:N #1
+ }
+ {
+ \tl_set:Nx \l_@@_fallback_family_tl { \CJKfamilydefault }
+ \xeCJK_fallback_loop:Nn #1 { \l_@@_fallback_family_tl }
+ }
+ }
+ }
+\cs_generate_variant:Nn \xeCJK_fallback_loop:Nn { No }
+\@@_msg_new:nn { missing-glyph }
+ {
+ CJKfamily~`\@@_msg_family_map:n {#1}'~
+ ( \prop_item:Nn \g_@@_family_font_name_prop {#1} )~
+ does~not~contain~glyph~`#2'~(U+#3).\\
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\setCJKfallbackfamilyfont}
+% \changes{v3.4.3}{2016/11/18}{允许字体属性可选项在后的新语法。}
+% \begin{macrocode}
+\NewDocumentCommand \setCJKfallbackfamilyfont { m o m }
+ {
+ \@@_pass_args:nnnn
+ { \xeCJK_set_family_fallback:nnn {#1} } {#2} {#3}
+ { }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_set_family_fallback:nnn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_set_family_fallback:nnn #1#2#3
+ {
+ \group_begin:
+ \tl_set:Nn \l_@@_fallback_family_tl {#1}
+ \prop_get:NoNF \g_@@_family_font_name_prop
+ \l_@@_fallback_family_tl \l_@@_font_name_tl
+ { \tl_clear:N \l_@@_font_name_tl }
+ \clist_map_inline:nn {#3}
+ {
+ \tl_put_right:Nn \l_@@_fallback_family_tl { /FallBack }
+ \@@_get_sub_features:Vn \l_@@_fallback_family_tl {##1}
+ \clist_put_left:Nn \l_@@_sub_font_options_clist {#2}
+ \xeCJK_set_family:VVV \l_@@_fallback_family_tl
+ \l_@@_sub_font_options_clist \l_@@_sub_font_name_tl
+ }
+ \group_end:
+ }
+\tl_new:N \l_@@_fallback_family_tl
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{CJK 字体族声明方式}
+%
+% \begin{macrocode}
+\bool_new:N \g_@@_auto_fake_bold_bool
+\bool_new:N \g_@@_auto_fake_slant_bool
+\fp_new:N \g_@@_embolden_factor_fp
+\fp_new:N \g_@@_slant_factor_fp
+% \end{macrocode}
+%
+% \begin{macro}{AutoFakeBold, AutoFakeSlant,EmboldenFactor,SlantFactor}
+% 伪粗体和伪斜体的宏包选项声明。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ AutoFakeBold .choices:nn = { true , false }
+ { \use:c { bool_gset_ \l_keys_choice_tl :N } \g_@@_auto_fake_bold_bool } ,
+ AutoFakeBold / unknown .code:n =
+ {
+ \bool_gset_true:N \g_@@_auto_fake_bold_bool
+ \fp_gset:Nn \g_@@_embolden_factor_fp { \l_keys_value_tl }
+ } ,
+ AutoFakeBold .default:n = { true } ,
+ AutoFakeSlant .choices:nn = { true , false }
+ { \use:c { bool_gset_ \l_keys_choice_tl :N } \g_@@_auto_fake_slant_bool } ,
+ AutoFakeSlant / unknown .code:n =
+ {
+ \bool_gset_true:N \g_@@_auto_fake_slant_bool
+ \fp_gset:Nn \g_@@_slant_factor_fp { \l_keys_value_tl }
+ } ,
+ AutoFakeSlant .default:n = { true } ,
+ EmboldenFactor .fp_gset:N = \g_@@_embolden_factor_fp ,
+ SlantFactor .fp_gset:N = \g_@@_slant_factor_fp ,
+ BoldFont .meta:n = { AutoFakeBold = true } ,
+ boldfont .meta:n = { AutoFakeBold = true } ,
+ SlantFont .meta:n = { AutoFakeSlant = true } ,
+ slantfont .meta:n = { AutoFakeSlant = true }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.4}{2013/07/02}{内部调整分区字体的设置方法。}
+%
+% \begin{macro}[int]{\xeCJK_new_sub_key:n}
+% \begin{variable}{\g_@@_sub_key_seq}
+% 用于定义 CJK 子区字体和备用字体的选项。
+% \begin{macrocode}
+\seq_new:N \g_@@_sub_key_seq
+\cs_new_protected_nopar:Npn \xeCJK_new_sub_key:n #1
+ {
+ \seq_gput_right:Nn \g_@@_sub_key_seq {#1}
+ \keys_define:nn { xeCJK / features }
+ {
+ #1 .code:n =
+ {
+ \tl_if_blank:nTF {##1}
+ {
+ \prop_clear:N \l_@@_sub_key_prop
+ \tl_set:Nx \l_@@_sub_family_name_tl
+ { \l_@@_family_name_tl /#1 }
+ \clist_remove_all:Nn \l_@@_font_options_clist {#1}
+ }
+ {
+ \tl_clear:N \l_@@_sub_family_name_tl
+ \str_if_eq:nnTF {##1} { * }
+ { \prop_put:Nnn \l_@@_sub_key_prop {#1} { \q_no_value } }
+ { \@@_get_sub_features:nn {#1} {##1} }
+ }
+ } ,
+ #1 .default:n = { }
+ }
+ }
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \changes{v3.2.4}{2013/07/02}{改进获取分区字体属性的办法。}
+%
+% \begin{macro}{\@@_get_sub_features:nn,\@@_get_sub_features:w}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_get_sub_features:nn #1#2
+ {
+ \tl_set:Nx \l_@@_tmp_tl { \xeCJK_tl_remove_outer_braces:n {#2} }
+ \clist_clear:N \l_@@_sub_font_options_clist
+ \exp_after:wN \@@_get_sub_features:w \l_@@_tmp_tl
+ \q_mark [ \q_nil ] \q_mark \q_stop
+ \tl_if_empty:NTF \l_@@_sub_font_name_tl
+ { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_font_name_tl }
+ { \tl_replace_all:NnV \l_@@_sub_font_name_tl { * } \l_@@_font_name_tl }
+ \prop_put:Nnx \l_@@_sub_key_prop {#1}
+ {
+ { \exp_not:V \l_@@_sub_font_options_clist }
+ { \exp_not:V \l_@@_sub_font_name_tl }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_get_sub_features:w #1 [#2] #3 \q_mark #4 \q_stop
+ {
+ \quark_if_nil:nTF {#2}
+ { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_tmp_tl }
+ {
+ \tl_set:Nx \l_@@_sub_font_name_tl
+ { \xeCJK_tl_remove_outer_braces:n {#3} }
+ \tl_if_empty:NTF \l_@@_sub_font_name_tl
+ { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_tmp_tl }
+ { \clist_set:Nn \l_@@_sub_font_options_clist {#2} }
+ }
+ }
+\tl_new:N \l_@@_sub_family_name_tl
+\tl_new:N \l_@@_sub_font_name_tl
+\clist_new:N \l_@@_sub_font_options_clist
+\cs_generate_variant:Nn \@@_get_sub_features:nn { V }
+\cs_generate_variant:Nn \tl_replace_all:Nnn { NnV }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{FallBack}
+% \begin{macrocode}
+\xeCJK_new_sub_key:n { FallBack }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{BoldFont,ItalicFont}
+% 调用字体的属性声明,同 \pkg{fontspec} 宏包。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / features }
+ {
+ BoldFont .tl_set:N = \l_@@_font_name_bf_tl ,
+ ItalicFont .tl_set:N = \l_@@_font_name_it_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.6}{2013/07/31}{\texttt{AutoFakeBold} 和 \texttt{AutoFakeSlant}
+% 选项直接使用 \pkg{fontspec} 的设置,修正不能调用相应实际字体的问题。}
+%
+% \begin{macro}[int]{AutoFakeBold, AutoFakeSlant}
+% \begin{macrocode}
+\keys_define:nn { xeCJK / features }
+ {
+ AutoFakeBold .choice: ,
+ AutoFakeBold / true .code:n =
+ {
+ \bool_set_true:N \l_@@_auto_fake_bold_bool
+ \fp_set_eq:NN \l_@@_embolden_factor_fp \g_@@_embolden_factor_fp
+ } ,
+ AutoFakeBold / false .code:n =
+ { \bool_set_false:N \l_@@_auto_fake_bold_bool } ,
+ AutoFakeBold / unknown .code:n =
+ {
+ \bool_set_true:N \l_@@_auto_fake_bold_bool
+ \fp_set:Nn \l_@@_embolden_factor_fp { \l_keys_value_tl }
+ } ,
+ AutoFakeBold .default:n = { true } ,
+ AutoFakeSlant .choice: ,
+ AutoFakeSlant / true .code:n =
+ {
+ \bool_set_true:N \l_@@_auto_fake_slant_bool
+ \fp_set_eq:NN \l_@@_slant_factor_fp \g_@@_slant_factor_fp
+ } ,
+ AutoFakeSlant / false .code:n =
+ { \bool_set_false:N \l_@@_auto_fake_slant_bool } ,
+ AutoFakeSlant / unknown .code:n =
+ {
+ \bool_set_true:N \l_@@_auto_fake_slant_bool
+ \fp_set:Nn \l_@@_slant_factor_fp { \l_keys_value_tl }
+ } ,
+ AutoFakeSlant .default:n = { true }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_family_initial:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_set_family_initial:
+ {
+ \int_gincr:N \g_@@_family_int
+ \prop_clear:N \l_@@_sub_key_prop
+ \tl_clear:N \l_@@_font_name_bf_tl
+ \tl_clear:N \l_@@_font_name_it_tl
+ \tl_clear:N \l_@@_sub_family_name_tl
+ \clist_clear:N \l_@@_fontspec_options_clist
+ \bool_set_eq:NN \l_@@_auto_fake_bold_bool \g_@@_auto_fake_bold_bool
+ \bool_set_eq:NN \l_@@_auto_fake_slant_bool \g_@@_auto_fake_slant_bool
+ \fp_set_eq:NN \l_@@_embolden_factor_fp \g_@@_embolden_factor_fp
+ \fp_set_eq:NN \l_@@_slant_factor_fp \g_@@_slant_factor_fp
+ }
+\int_new:N \g_@@_family_int
+\prop_new:N \l_@@_sub_key_prop
+\clist_new:N \l_@@_fontspec_options_clist
+\bool_new:N \l_@@_auto_fake_bold_bool
+\bool_new:N \l_@@_auto_fake_slant_bool
+\fp_new:N \l_@@_embolden_factor_fp
+\fp_new:N \l_@@_slant_factor_fp
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_set_family:nnn}
+% 设置一个 CJK 新字体族,与 \tn{newfontfamily} 类似,增加 |FallBack| 选项。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_set_family:nnn #1#2#3
+ {
+ \group_begin:
+ \@@_set_family_initial:
+ \tl_set:Nn \l_@@_family_name_tl {#1}
+ \clist_set:Nn \l_@@_font_options_clist {#2}
+ \tl_set:Nn \l_@@_font_name_tl {#3}
+ \clist_concat:NNN \l_@@_font_options_clist
+ \g_@@_default_features_clist \l_@@_font_options_clist
+ \keys_set_known:nVN { xeCJK / features }
+ \l_@@_font_options_clist \l_@@_fontspec_options_clist
+ \@@_binding_sub_family:
+ \@@_parse_font_shape:
+ \@@_check_family:V \l_@@_family_name_tl
+ \@@_gset_family_cs:x { \l_@@_family_name_tl }
+ \@@_save_family_info:
+ \@@_set_sub_block_family:
+ \group_end:
+ }
+\tl_new:N \l_@@_family_name_tl
+\tl_new:N \l_@@_font_name_tl
+\clist_new:N \l_@@_font_options_clist
+\cs_generate_variant:Nn \xeCJK_set_family:nnn { x , VVV , Voo }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.7.2}{2019/03/27}{删除定义新字体族时过滤重复选项的功能。}
+%
+% \begin{macro}{\@@_binding_sub_family:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_binding_sub_family:
+ {
+ \tl_if_empty:NF \l_@@_sub_family_name_tl
+ { \tl_set_eq:NN \l_@@_family_name_tl \l_@@_sub_family_name_tl }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_gset_family_cs:x}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_gset_family_cs:x #1
+ {
+ \cs_gset_protected_nopar:cpx { \@@_family_csname:n {#1} }
+ {
+ \group_begin:
+ \exp_not:n { \cs_set_eq:NN \xeCJK@fontfamily \use_none:n }
+ \exp_not:n { \fontspec_gset_family:Nnn \g_@@_fontspec_family_tl }
+ { \exp_not:V \l_@@_fontspec_options_clist }
+ { \exp_not:V \l_@@_font_name_tl }
+ \@@_gset_family_nfss_cs:xx
+ {#1} { \exp_not:N \g_@@_fontspec_family_tl }
+ \group_end:
+ \tl_set_eq:NN \exp_not:N \l_@@_fontspec_family_tl
+ \exp_not:N \g_@@_fontspec_family_tl
+ }
+ }
+\tl_new:N \g_@@_fontspec_family_tl
+\tl_new:N \l_@@_fontspec_family_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_check_family:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_check_family:n #1
+ {
+ \prop_gpop:NnNT \g_@@_family_font_name_prop {#1} \l_@@_tmp_tl
+ {
+ \prop_gpop:NnNT \g_@@_family_name_prop {#1} \l_@@_tmp_tl
+ {
+ \cs_undefine:c { \@@_family_csname:n {#1} }
+ \cs_undefine:c { \@@_family_nfss_csname:n {#1} }
+ }
+ \@@_warning:nxx { CJKfamily-redef } {#1} { \l_@@_tmp_tl }
+ }
+ }
+\cs_generate_variant:Nn \@@_check_family:n { V }
+\@@_msg_new:nn { CJKfamily-redef }
+ { Redefining~CJKfamily~`\@@_msg_family_map:n {#1}'~(#2). }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_font_shape:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_parse_font_shape:
+ {
+ \tl_if_blank:VTF \l_@@_font_name_bf_tl
+ {
+ \bool_if:NT \l_@@_auto_fake_bold_bool
+ {
+ \clist_put_right:Nx \l_@@_fontspec_options_clist
+ { AutoFakeBold = { \fp_use:N \l_@@_embolden_factor_fp } }
+ }
+ }
+ {
+ \clist_put_right:Nx \l_@@_fontspec_options_clist
+ { BoldFont = { \exp_not:V \l_@@_font_name_bf_tl } }
+ }
+ \tl_if_blank:VTF \l_@@_font_name_it_tl
+ {
+ \bool_if:NT \l_@@_auto_fake_slant_bool
+ {
+ \clist_put_right:Nx \l_@@_fontspec_options_clist
+ { AutoFakeSlant = { \fp_use:N \l_@@_slant_factor_fp } }
+ }
+ }
+ {
+ \clist_put_right:Nx \l_@@_fontspec_options_clist
+ { ItalicFont = { \exp_not:V \l_@@_font_name_it_tl } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}
+% {\g_@@_family_name_prop,\g_@@_family_font_name_prop,\g_@@_family_font_options_prop}
+% \begin{macrocode}
+\prop_new:N \g_@@_family_name_prop
+\prop_new:N \g_@@_family_font_name_prop
+\prop_new:N \g_@@_family_font_options_prop
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_save_family_info:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_save_family_info:
+ {
+ \prop_gput:NVV \g_@@_family_font_name_prop
+ \l_@@_family_name_tl \l_@@_font_name_tl
+ \prop_gput:NVV \g_@@_family_font_options_prop
+ \l_@@_family_name_tl \l_@@_font_options_clist
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_sub_block_family:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_set_sub_block_family:
+ {
+ \prop_map_inline:Nn \l_@@_sub_key_prop
+ {
+ \tl_set:Nx \l_@@_sub_family_name_tl { \l_@@_family_name_tl/##1 }
+ \quark_if_no_value:nTF {##2}
+ { \@@_copy_sub_family:n {##1} }
+ {
+ \xeCJK_set_family:Voo \l_@@_sub_family_name_tl
+ { \use_i:nn ##2 } { \use_ii:nn ##2 }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_copy_sub_family:n #1
+ {
+ \@@_check_family:V \l_@@_sub_family_name_tl
+ \prop_get:NoNT \g_@@_family_font_name_prop
+ \l_@@_family_name_tl \l_@@_sub_font_name_tl
+ {
+ \prop_gput:NVV \g_@@_family_font_name_prop
+ \l_@@_sub_family_name_tl \l_@@_sub_font_name_tl
+ }
+ \prop_get:NoNT \g_@@_family_font_options_prop
+ \l_@@_family_name_tl \l_@@_sub_font_options_clist
+ {
+ \clist_remove_all:Nn \l_@@_sub_font_options_clist { #1 = * }
+ \prop_gput:NVV \g_@@_family_font_options_prop
+ \l_@@_sub_family_name_tl \l_@@_sub_font_options_clist
+ }
+ \cs_gset_protected_nopar:cpx
+ { \@@_family_csname:n { \l_@@_sub_family_name_tl } }
+ {
+ \xeCJK_family_if_exist:xT { \l_@@_family_name_tl }
+ {
+ \@@_gset_family_nfss_cs:xx
+ { \l_@@_sub_family_name_tl }
+ { \exp_not:N \l_@@_fontspec_family_tl }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_copy_family:nn,\@@_copy_family:xx}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_copy_family:nn #1#2
+ {
+ \xeCJK_family_if_exist:nT {#2}
+ {
+ \prop_gput:NnV \g_@@_family_name_prop
+ {#1} \l_@@_fontspec_family_tl
+ \tl_map_inline:nn
+ {
+ \g_@@_family_font_name_prop
+ \g_@@_family_font_options_prop
+ }
+ {
+ \prop_get:NnNT ##1 {#2} \l_@@_tmp_tl
+ { \prop_gput:NnV ##1 {#1} \l_@@_tmp_tl }
+ }
+ \cs_gset_eq:cc
+ { \@@_family_nfss_csname:n {#1} }
+ { \@@_family_nfss_csname:n {#2} }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_copy_family:xx #1#2
+ { \use:x { \@@_copy_family:nn {#1} {#2} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{字体切换}
+%
+% \begin{macro}[int]{\xeCJK_select_font:}
+% \begin{variable}[int]{\l_xeCJK_current_font_tl}
+% 缓存当前字体的原始格式,以加速编译。
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_font_csname:n #1
+ { xeCJK/#1/\f@series/\f@shape/\f@size }
+\tl_new:N \l_xeCJK_current_font_tl
+\tl_set:No \l_xeCJK_current_font_tl
+ { \@@_font_csname:n { \CJK@family } }
+\cs_new_protected_nopar:Npn \xeCJK_select_font:
+ {
+ \exp_args:Nc \cs_if_exist_use:NF { \l_xeCJK_current_font_tl }
+ {
+ \@@_family_use:n { \l_xeCJK_family_tl }
+ \xeCJK_font_gset_to_current:c { \l_xeCJK_current_font_tl }
+ }
+ }
+\tl_new:N \l_@@_current_coor_tl
+\cs_new_eq:NN \xeCJK@setfont \xeCJK_select_font:
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_select_punct_font:}
+% \begin{variable}[int]{\l_xeCJK_current_punct_font_tl}
+% 切换标点符号字体。
+% \begin{macrocode}
+\cs_new_eq:NN \xeCJK_select_punct_font: \xeCJK_select_font:
+\cs_new_protected_nopar:Npn \@@_select_punct_font_aux:
+ {
+ \exp_args:Nc \cs_if_exist_use:NF { \l_xeCJK_current_punct_font_tl }
+ {
+ \@@_family_use:n { \l_xeCJK_punct_family_tl }
+ \xeCJK_font_gset_to_current:c { \l_xeCJK_current_punct_font_tl }
+ }
+ }
+\tl_new:N \CJK@punctfamily
+\tl_new:N \l_xeCJK_punct_family_tl
+\tl_new:N \l_xeCJK_current_punct_font_tl
+\tl_set:No \l_xeCJK_current_punct_font_tl
+ { \@@_font_csname:n { \CJK@punctfamily } }
+\cs_new_eq:NN \@@_select_font: \prg_do_nothing:
+\cs_new_eq:NN \@@_select_punct_font: \prg_do_nothing:
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{macro}{\@@_switch_font:nn}
+% \changes{v3.1.0}{2012/11/18}{改进定义,加快切换速度。}
+% 两个 CJK 分区之间的字体切换。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_switch_font:nn #1#2
+ {
+ \str_if_eq:nnF {#1} {#2}
+ {
+ \@@_info:nxx { CJK-block } {#1} {#2}
+ \str_if_eq:nnTF {#2} { CJK }
+ { \xeCJK_select_font: }
+ { \xeCJK_select_font:n {#2} }
+ }
+ }
+\@@_msg_new:nn { CJK-block } { Switch~from~block~`#1'~to~`#2'. }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_select_font:n,\xeCJK_block_family:nn}
+% 若当前 CJK 字体族没有定义子分区 |#1| 的字体,则使用 \tn{CJKfamilydefault} 的对应
+% 分区字体;若 \tn{CJKfamilydefault} 也没有定义该分区字体,则使用当前 CJK 字体族的
+% 主分区字体。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_select_font:n #1
+ {
+ \exp_args:Nc \cs_if_exist_use:NF
+ { \@@_font_csname:n { \CJK@family/#1 } }
+ {
+ \xeCJK_block_family:nn { \l_xeCJK_family_tl } {#1}
+ \@@_family_use:n { \l_xeCJK_family_tl/#1 }
+ \xeCJK_font_gset_to_current:c
+ { \@@_font_csname:n { \CJK@family/#1 } }
+ }
+ }
+\cs_new_protected_nopar:Npn \xeCJK_block_family:nn #1#2
+ {
+ \xeCJK_family_if_exist:xF { #1/#2 }
+ {
+ \@@_copy_family:xx { #1/#2 }
+ {
+ \cs_if_exist:cTF
+ { \@@_family_csname:n { \CJKfamilydefault/#2 } }
+ { \CJKfamilydefault/#2 } {#1}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {\@@_family_csname:n,\@@_family_nfss_csname:n,
+% \@@_family_use:n,\@@_gset_family_nfss_cs:nn}
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_family_csname:n #1
+ { xeCJK/family/#1 }
+\cs_new_nopar:Npn \@@_family_nfss_csname:n #1
+ { xeCJK/family/nfss/#1 }
+\cs_new_nopar:Npn \@@_family_use:n #1
+ { \use:c { \@@_family_nfss_csname:n {#1} } }
+\cs_new_protected_nopar:Npn \@@_gset_family_nfss_cs:nn #1#2
+ {
+ \prop_gput:Nnn \g_@@_family_name_prop {#1} {#2}
+ \cs_gset_protected_nopar:cpx
+ { \@@_family_nfss_csname:n {#1} }
+ {
+ \exp_not:N \fontencoding { \c_@@_encoding_tl }
+ \tl_set:Nn \exp_not:N \f@family {#2}
+ \exp_not:N \selectfont
+ }
+ }
+\cs_generate_variant:Nn \@@_gset_family_nfss_cs:nn { xx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[TF,int]{\xeCJK_family_if_exist:n}
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \xeCJK_family_if_exist:n #1 { T , F , TF }
+ {
+ \prop_get:NnNTF \g_@@_family_name_prop
+ {#1} \l_@@_fontspec_family_tl
+ { \prg_return_true: }
+ {
+ \cs_if_exist_use:cTF { \@@_family_csname:n {#1} }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+\prg_generate_conditional_variant:Nnn \xeCJK_family_if_exist:n { x } { T , F , TF }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CJKfamily}
+% 用于切换 CJK 字体族。
+% \begin{macrocode}
+\NewDocumentCommand \CJKfamily { t+ t- m }
+ {
+ \xeCJK_family:NNx #1 #2 {#3}
+ \tex_ignorespaces:D
+ }
+\cs_new_protected_nopar:Npn \xeCJK_family:NNn #1#2#3
+ {
+ \tl_if_blank:nTF {#3}
+ {
+ \bool_if:NF #1 { \bool_if:NF #2 { \use_none:nn } }
+ \xeCJK_family_if_exist_use:x { \l_xeCJK_family_tl }
+ }
+ {
+ \bool_if:NTF #2
+ { \xeCJK_family_if_exist_use:n {#3} }
+ {
+ \xeCJK_family_if_exist:nTF {#3}
+ {
+ \tl_set:Nn \l_xeCJK_family_tl {#3}
+ \tl_set_eq:NN \CJK@family \l_@@_fontspec_family_tl
+ \bool_if:NT #1 { \@@_family_use:n {#3} }
+ }
+ { \@@_family_unknown_warning:n {#3} }
+ }
+ }
+ }
+\cs_generate_variant:Nn \xeCJK_family:NNn { NNx }
+\cs_new_protected_nopar:Npn \xeCJK_switch_family:n #1
+ {
+ \xeCJK_family_if_exist:nTF {#1}
+ {
+ \tl_set:Nn \l_xeCJK_family_tl {#1}
+ \tl_set_eq:NN \CJK@family \l_@@_fontspec_family_tl
+ }
+ { \@@_family_unknown_warning:n {#1} }
+ }
+\cs_generate_variant:Nn \xeCJK_switch_family:n { x , o }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.6.0}{2018/01/24}{新增 \opt{PunctFamily} 选项支持对汉字标点单独切换字体。}
+%
+% \begin{macro}{PunctFamily}
+% 设置汉字标点符号的字体。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ PunctFamily .choice: ,
+ PunctFamily .value_required:n = { true } ,
+ PunctFamily / false .code:n =
+ {
+ \tl_clear:N \l_xeCJK_punct_family_tl
+ \tl_clear:N \CJK@punctfamily
+ \xeCJK_cs_clear:N \@@_select_font:
+ \xeCJK_cs_clear:N \@@_select_punct_font:
+ \cs_set_eq:NN \xeCJK_select_punct_font: \xeCJK_select_font:
+ } ,
+ PunctFamily / unknown .code:n =
+ { \xeCJK_punct_family:x {#1} } ,
+ }
+\cs_new_protected_nopar:Npn \xeCJK_punct_family:n #1
+ {
+ \xeCJK_family_if_exist:nTF {#1}
+ {
+ \tl_set:Nn \l_xeCJK_punct_family_tl {#1}
+ \tl_set_eq:NN \CJK@punctfamily \l_@@_fontspec_family_tl
+ \cs_set_eq:NN \@@_select_font: \xeCJK_select_font:
+ \cs_set_eq:NN \@@_select_punct_font: \@@_select_punct_font_aux:
+ \cs_set_eq:NN \xeCJK_select_punct_font: \@@_select_punct_font:
+ }
+ { \@@_family_unknown_warning:n {#1} }
+ }
+\cs_generate_variant:Nn \xeCJK_punct_family:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}[int]{\l_xeCJK_family_tl}
+% 用于保存文档当前正在使用的 CJK 字体族。
+% \changes{v3.2.0}{2013/04/14}{不将其初始化为 \tn{CJKfamilydefault}。}
+% \begin{macrocode}
+\tl_new:N \l_xeCJK_family_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\CJK@family}
+% 用于保存实际的字体族名称。
+% \changes{v3.2.11}{2014/03/29}{引入 \tn{CJK@family} 保存实际的字体族名。}
+% \begin{macrocode}
+\tl_new:N \CJK@family
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_gobble_CJKfamily:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_gobble_CJKfamily:
+ { \cs_set_eq:NN \CJKfamily \@@_gobble_CJKfamily:wn }
+\DeclareExpandableDocumentCommand \@@_gobble_CJKfamily:wn { t+ t- m } { }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_family_if_exist_use:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_family_if_exist_use:n #1
+ {
+ \xeCJK_family_if_exist:nTF {#1}
+ { \@@_family_use:n {#1} }
+ { \@@_family_unknown_warning:n {#1} }
+ }
+\cs_generate_variant:Nn \xeCJK_family_if_exist_use:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_family_unknown_warning:n}
+% \changes{v3.1.2}{2013/01/01}
+% {在没有定义任何 CJK 字体的情况下,不再重复给出字体没有定义的警告。}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_family_unknown_warning:n #1
+ {
+ \prop_if_empty:NF \g_@@_family_font_name_prop
+ {
+ \seq_if_in:NnF \g_@@_unknown_family_seq {#1}
+ {
+ \seq_gput_right:Nn \g_@@_unknown_family_seq {#1}
+ \@@_warning:nx { CJKfamily-Unknown } {#1}
+ }
+ }
+ }
+\cs_generate_variant:Nn \@@_family_unknown_warning:n { x }
+\seq_new:N \g_@@_unknown_family_seq
+\@@_msg_new:nn { CJKfamily-Unknown }
+ {
+ Unknown~CJK~family~`\@@_msg_family_map:n {#1}'~is~being~ignored.\\\\
+ Try~to~use~`\@@_msg_def_family_map:n {#1}'~to~define~it.
+ }
+\cs_new_nopar:Npn \@@_msg_def_family_map:n #1
+ {
+ \str_case_e:nnF {#1}
+ {
+ \CJKrmdefault { \token_to_str:N \setCJKmainfont }
+ \CJKsfdefault { \token_to_str:N \setCJKsansfont }
+ \CJKttdefault { \token_to_str:N \setCJKmonofont }
+ }
+ { \token_to_str:N \setCJKfamilyfont \{ #1 \} }
+ [...]\{...\}
+ }
+\cs_new_nopar:Npn \@@_msg_family_map:n #1
+ {
+ \str_case_e:nnF {#1}
+ {
+ \CJKrmdefault { \token_to_str:N \CJKrmdefault }
+ \CJKsfdefault { \token_to_str:N \CJKsfdefault }
+ \CJKttdefault { \token_to_str:N \CJKttdefault }
+ }
+ {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_pass_args:nnnn}
+% 为了支持字体属性可选项在前在后两种语法,给出两个辅助工具,类似
+% \package{fontspec} 的实现。自带展开功能,额外参数 |#4| 用于后处理。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_pass_args:nnnn #1#2#3#4
+ {
+ \tl_if_novalue:nTF {#2}
+ { \@@_post_arg:w {#1} {#3} {#4} }
+ {
+ \use:x { #1 {#2} {#3} }
+ #4
+ }
+ }
+\NewDocumentCommand \@@_post_arg:w { m m m O { } }
+ {
+ \use:x { #1 {#4} {#2} }
+ #3
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\setCJKmainfont,\setCJKsansfont,\setCJKmonofont}
+% 设置文档的 CJK 普通字体、无衬线和等宽字体。
+% \changes{v3.2.0}{2013/04/14}{定义中加入 \tn{normalfont}。}
+% \changes{v3.4.3}{2016/11/18}{允许字体属性可选项在后的新语法。}
+% \begin{macrocode}
+\NewDocumentCommand \setCJKmainfont { o m }
+ {
+ \@@_pass_args:nnnn
+ { \xeCJK_set_family:nnn { \CJKrmdefault } } {#1} {#2}
+ { \normalfont }
+ }
+\cs_new_eq:NN \setCJKromanfont \setCJKmainfont
+\NewDocumentCommand \setCJKsansfont { o m }
+ {
+ \@@_pass_args:nnnn
+ { \xeCJK_set_family:nnn { \CJKsfdefault } } {#1} {#2}
+ { \normalfont }
+ }
+\NewDocumentCommand \setCJKmonofont { o m }
+ {
+ \@@_pass_args:nnnn
+ { \xeCJK_set_family:nnn { \CJKttdefault } } {#1} {#2}
+ { \normalfont }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\@onlypreamble \setCJKmainfont
+\@onlypreamble \setCJKmathfont
+\@onlypreamble \setCJKsansfont
+\@onlypreamble \setCJKmonofont
+\@onlypreamble \setCJKromanfont
+% \end{macrocode}
+%
+% \begin{macro}{\setCJKfamilyfont, \newCJKfontfamily, \CJKfontspec}
+% \changes{v3.4.3}{2016/11/18}{允许字体属性可选项在后的新语法。}
+% 分别用于预声明 CJK 字体族和声明并马上调用 CJK 字体族。
+% \begin{macrocode}
+\NewDocumentCommand \setCJKfamilyfont { m o m }
+ {
+ \@@_pass_args:nnnn
+ { \xeCJK_set_family:nnn {#1} } {#2} {#3}
+ { }
+ }
+\NewDocumentCommand \newCJKfontfamily { o m o m }
+ {
+ \tl_set:Nx \l_@@_tmp_tl
+ { \tl_if_novalue:nTF {#1} { \cs_to_str:N #2 } {#1} }
+ \cs_new_protected_nopar:Npx #2
+ { \xeCJK_switch_family:n { \l_@@_tmp_tl } }
+ \@@_pass_args:nnnn
+ { \xeCJK_set_family:nnn { \l_@@_tmp_tl } } {#3} {#4}
+ { }
+ }
+\NewDocumentCommand \CJKfontspec { o m }
+ {
+ \@@_pass_args:nnnn
+ { \xeCJK_fontspec:nn } {#1} {#2}
+ { \tex_ignorespaces:D }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_fontspec:nn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_fontspec:nn #1#2
+ {
+ \prop_get:NnNTF \g_@@_fontspec_prop
+ { CJKfontspec/#1/#2/id } \l_xeCJK_family_tl
+ { \xeCJK_switch_family:o { \l_xeCJK_family_tl } }
+ {
+ \@@_fontspec:xnn
+ { CJKfontspec ( \int_eval:n { \g_@@_family_int + 1 } ) }
+ {#1} {#2}
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_fontspec:nnn #1#2#3
+ {
+ \prop_gput:Nnn \g_@@_fontspec_prop { CJKfontspec/#2/#3/id } {#1}
+ \xeCJK_set_family:nnn {#1} {#2} {#3}
+ \xeCJK_switch_family:n {#1}
+ }
+\cs_generate_variant:Nn \xeCJK_fontspec:nn { VV }
+\cs_generate_variant:Nn \@@_fontspec:nnn { x }
+\prop_new:N \g_@@_fontspec_prop
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\defaultCJKfontfeatures, \addCJKfontfeatures}
+% \changes{v3.2.4}{2013/06/30}{可以单独增加当前各个分区字体的属性。}
+% 分别用于设置 CJK 字体的默认属性和增加当前 CJK 字体的属性。
+% \begin{macrocode}
+\clist_new:N \g_@@_default_features_clist
+\NewDocumentCommand \defaultCJKfontfeatures { m }
+ { \clist_gset:Nn \g_@@_default_features_clist {#1} }
+\@onlypreamble \defaultCJKfontfeatures
+\NewDocumentCommand \addCJKfontfeatures { s O { } m }
+ {
+ \xeCJK_add_font_features:Nxx #1 {#2} {#3}
+ \tex_ignorespaces:D
+ }
+\cs_new_eq:NN \addCJKfontfeature \addCJKfontfeatures
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_add_font_features:Nnn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_add_font_features:Nnn #1#2#3
+ {
+ \prop_get:NoNTF \g_@@_family_font_name_prop
+ \l_xeCJK_family_tl \l_@@_font_name_tl
+ {
+ \clist_set:Nn \l_@@_add_font_features_clist {#3}
+ \seq_map_inline:Nn \g_@@_sub_key_seq
+ { \clist_remove_all:Nn \l_@@_add_font_features_clist {##1} }
+ \seq_clear:N \l_@@_sub_key_seq
+ \clist_clear:N \l_@@_add_block_features_clist
+ \clist_map_inline:nn {#2}
+ {
+ \seq_if_in:NnTF \g_@@_sub_key_seq {##1}
+ {
+ \seq_put_right:Nn \l_@@_sub_key_seq {##1}
+ \@@_add_sub_class_features:n {##1}
+ }
+ { \@@_warning:nx { SubBlock-undefined } {##1} }
+ }
+ \bool_lazy_and:nnT
+ {#1}
+ { \seq_if_empty_p:N \l_@@_sub_key_seq }
+ {
+ \seq_map_function:NN
+ \g_@@_sub_key_seq \@@_add_sub_class_features:n
+ }
+ \prop_get:NoNT \g_@@_family_font_options_prop
+ \l_xeCJK_family_tl \l_@@_font_options_clist
+ {
+ \bool_lazy_or:nnT
+ { \seq_if_empty_p:N \l_@@_sub_key_seq }
+ {#1}
+ {
+ \clist_concat:NNN \l_@@_font_options_clist
+ \l_@@_font_options_clist \l_@@_add_font_features_clist
+ }
+ \clist_concat:NNN \l_@@_font_options_clist
+ \l_@@_font_options_clist \l_@@_add_block_features_clist
+ }
+ \xeCJK_fontspec:VV \l_@@_font_options_clist \l_@@_font_name_tl
+ }
+ { \@@_warning:n { addCJKfontfeature-ignored } }
+ }
+\clist_new:N \l_@@_add_font_features_clist
+\clist_new:N \l_@@_add_block_features_clist
+\cs_generate_variant:Nn \xeCJK_add_font_features:Nnn { Nxx , Nnx }
+\@@_msg_new:nn { addCJKfontfeature-ignored }
+ {
+ \token_to_str:N \addCJKfontfeature (s)~ignored.\\\\
+ It~cannot~be~used~with~a~font~that~wasn't~selected~by~xeCJK.
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_add_sub_class_features:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_add_sub_class_features:n #1
+ {
+ \prop_get:NoNTF \g_@@_family_font_name_prop
+ { \l_xeCJK_family_tl/#1 } \l_@@_sub_font_name_tl
+ {
+ \prop_get:NoN \g_@@_family_font_options_prop
+ { \l_xeCJK_family_tl/#1 } \l_@@_sub_font_options_clist
+ }
+ {
+ \prop_get:NxNTF \g_@@_family_font_name_prop
+ { \CJKfamilydefault/#1 } \l_@@_sub_font_name_tl
+ {
+ \prop_get:NxN \g_@@_family_font_options_prop
+ { \CJKfamilydefault/#1 } \l_@@_sub_font_options_clist
+ }
+ {
+ \prop_get:NoN \g_@@_family_font_options_prop
+ \l_xeCJK_family_tl \l_@@_sub_font_options_clist
+ \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_font_name_tl
+ }
+ }
+ \clist_concat:NNN \l_@@_sub_font_options_clist
+ \l_@@_sub_font_options_clist \l_@@_add_font_features_clist
+ \clist_put_right:Nx \l_@@_add_block_features_clist
+ {
+ #1 =
+ {
+ [ \exp_not:V \l_@@_sub_font_options_clist ]
+ { \exp_not:V \l_@@_sub_font_name_tl }
+ }
+ }
+ }
+\cs_generate_variant:Nn \prop_get:NnN { Nx }
+\prg_generate_conditional_variant:Nnn \prop_get:NnN { Nx } { TF }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{LoadFandol}
+% \changes{v3.2.10}{2014/03/01}{当没有设置字体时,使用 Fandol 字体系列。}
+% \changes{v3.3.1}{2015/04/08}{为方便 MacTeX 用户,Fandol 字体改用文件名。}
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ { LoadFandol .bool_gset:N = \g_@@_fandol_bool }
+\cs_new_protected_nopar:Npn \@@_load_fandol:
+ {
+ \xeCJK_set_family:xnn { \CJKrmdefault }
+ { Extension = .otf , BoldFont = FandolSong-Bold , ItalicFont = FandolKai-Regular }
+ { FandolSong-Regular }
+ \xeCJK_set_family:xnn { \CJKsfdefault }
+ { Extension = .otf , BoldFont = FandolHei-Bold } { FandolHei-Regular }
+ \xeCJK_set_family:xnn { \CJKttdefault }
+ { Extension = .otf } { FandolFang-Regular }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.1.2}{2013/01/01}{修正重定义 \tn{CJKfamilydefault} 无效的问题,恢复容错能力。}
+% \changes{v3.2.13}{2014/06/02}{自动调整 \tn{CJKfamilydefault} 时,只将 \tn{familydefault} 展开一次。}
+%
+% 在导言区结束的时候,若没有声明 CJK 字体,则给出一个警告。如果 \tn{CJKfamilydefault}
+% 没有被更改,则在此时根据西文字体的情况更新 \tn{CJKfamilydefault}。
+% 如果 \tn{CJKfamilydefault} 对应的字体族没有定义,则使用 \tn{CJKrmdefault} 作为
+% 默认字体族。若 \tn{CJKrmdefault} 也没有定义,则使用在导言区设置的第一个 CJK 字体
+% 作为默认字体族。最后设置数学字体。
+% \begin{macrocode}
+\@@_at_end_preamble:n
+ {
+ \tl_if_eq:NNT \CJKfamilydefault \l_@@_family_default_init_tl
+ {
+ \group_begin:
+ \cs_set_eq:NN \@@_family_default_wrap:n \exp_not:n
+ \tl_gset:Nx \CJKfamilydefault
+ {
+ \str_case:onF { \familydefault }
+ {
+ { \rmdefault } { \exp_not:N \CJKrmdefault }
+ { \sfdefault } { \exp_not:N \CJKsfdefault }
+ { \ttdefault } { \exp_not:N \CJKttdefault }
+ }
+ { \CJKfamilydefault }
+ }
+ \group_end:
+ }
+ \prop_if_empty:NTF \g_@@_family_font_name_prop
+ {
+ \bool_if:NTF \g_@@_fandol_bool
+ {
+ \@@_warning:n { fandol }
+ \@@_load_fandol:
+ \xeCJK_ensure_default_family:
+ }
+ { \@@_warning:nx { no-CJKfamily } { \CJKfamilydefault } }
+ }
+ { \xeCJK_ensure_default_family: }
+ }
+\cs_new_protected_nopar:Npn \xeCJK_ensure_default_family:
+ {
+ \xeCJK_family_if_exist:xF { \CJKfamilydefault }
+ {
+ \tl_set_eq:NN \l_@@_tmp_tl \CJKfamilydefault
+ \str_if_eq:eeTF { \CJKfamilydefault } { \CJKrmdefault }
+ { \use:n }
+ {
+ \xeCJK_family_if_exist:xTF { \CJKrmdefault }
+ { \tl_gset:Nn \CJKfamilydefault { \CJKrmdefault } }
+ }
+ {
+ \prop_map_inline:Nn \g_@@_family_font_name_prop
+ {
+ \prop_map_break:n
+ { \tl_gset_rescan:Nnn \CJKfamilydefault { } { ##1 } }
+ }
+ }
+ \@@_warning:nxx { CJKfamilydefault-undefined }
+ { \l_@@_tmp_tl } { \CJKfamilydefault }
+ }
+ \xeCJK_switch_family:x { \CJKfamilydefault }
+ \bool_if:NT \g_@@_math_bool { \xeCJK_set_mathfont: }
+ }
+\@@_msg_new:nn { no-CJKfamily }
+ {
+ It~seems~that~you~have~not~declare~a~CJKfamily.\\
+ If~you~want~to~use~xeCJK~in~the~right~way,~you~should~use\\\\
+ `\@@_msg_def_family_map:n {#1}'\\\\
+ in~the~preamble~to~declare~the~default~CJKfamily.\\
+ }
+\@@_msg_new:nn { CJKfamilydefault-undefined }
+ {
+ Undefined~CJK~default~family~`\@@_msg_family_map:n {#1}'~
+ has~been~replaced~by~`\@@_msg_family_map:n {#2}'.\\\\
+ Try~to~use~`\@@_msg_def_family_map:n {#1}'~to~define~it.
+ }
+\@@_msg_new:nn { fandol }
+ {
+ Fandol~is~being~set~as~the~default~font~for~CJK~text.\\
+ Please~make~sure~it~has~been~properly~installed.
+ }
+% \end{macrocode}
+%
+% \subsection{数学字体设置}
+%
+% \begin{macro}{CJKmath}
+% 是否启用 CJK 数学字体的宏包选项。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options } { CJKmath .bool_gset:N = \g_@@_math_bool }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\setCJKmathfont}
+% \changes{v3.4.3}{2016/11/18}{允许字体属性可选项在后的新语法。}
+% 设置 CJK 数学字体。
+% \begin{macrocode}
+\NewDocumentCommand \setCJKmathfont { o m }
+ {
+ \@@_pass_args:nnnn
+ { \xeCJK_set_family:nnn { \c_@@_math_tl } } {#1} {#2}
+ { }
+ }
+\tl_const:Nn \c_@@_math_tl { CJKmath }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_set_mathfont:}
+% \changes{v3.2.6}{2013/08/01}{设置粗体时先检查对应字体是否存在。}
+% \changes{v3.2.7}{2013/11/09}{将 CJK 字符的数学归类由 $7$ 改为 $0$,解决汉字路径的问题。}
+% \changes{v3.2.13}{2014/06/20}{修复参数类型错误。}
+% \changes{v3.4.0}{2016/05/01}{CJKmath 的字符范围遵从 \tn{xeCJKDeclareCharClass} 的设置。}
+% 当没有设置 CJK 数学字体时,使用 \tn{CJKfamilydefault} 作为数学字体。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_set_mathfont:
+ {
+ \xeCJK_family_if_exist:xTF { \c_@@_math_tl }
+ { \@@_set_mathfont_aux: }
+ {
+ \xeCJK_family_if_exist:xT { \CJKfamilydefault }
+ {
+ \@@_copy_family:xx { \c_@@_math_tl } { \CJKfamilydefault }
+ \@@_set_mathfont_aux:
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_set_mathfont_aux:
+ {
+ \tl_const:Nx \c_@@_math_family_tl
+ { \l_@@_fontspec_family_tl }
+ \xeCJK_declare_mathfont:xx
+ { \c_@@_math_tl }
+ { \c_@@_math_family_tl }
+ \int_const:Nn \c_xeCJK_math_fam_int
+ { \use:c { sym \c_@@_math_tl } }
+ \clist_gconcat:NNN \g_@@_math_chars_clist
+ \g_@@_CJK_range_clist \g_@@_FullLeft_range_clist
+ \clist_gconcat:NNN \g_@@_math_chars_clist
+ \g_@@_math_chars_clist \g_@@_FullRight_range_clist
+ \xeCJK_gset_mathcode:Nn \g_@@_math_chars_clist
+ { \c_xeCJK_math_fam_int }
+ \xeCJK_set_mathfont_block:
+ }
+\clist_new:N \g_@@_math_chars_clist
+\prop_new:N \g_@@_fam_prop
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4.0}{2016/05/04}{CJKmath 功能也支持分区字体。}
+%
+% \begin{macro}[int]{\xeCJK_set_mathfont_block:}
+% 分区数学字体。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_set_mathfont_block:
+ {
+ \seq_if_empty:NF \g_@@_CJK_sub_class_seq
+ {
+ \seq_map_function:NN
+ \g_@@_CJK_sub_class_seq
+ \xeCJK_set_mathfont_block:n
+ }
+ }
+\cs_new_protected_nopar:Npn \xeCJK_set_mathfont_block:n #1
+ {
+ \xeCJK_block_family:nn { \c_@@_math_tl } {#1}
+ \prop_get:NoNTF \g_@@_fam_prop
+ \l_@@_fontspec_family_tl \l_@@_tmp_tl
+ { \int_set:Nn \l_@@_fam_int { \l_@@_tmp_tl } }
+ {
+ \xeCJK_declare_mathfont:xx
+ { \c_@@_math_tl / #1 }
+ { \l_@@_fontspec_family_tl }
+ \@@_set_mathfont_block_aux:cn
+ { sym \c_@@_math_tl / #1 } {#1}
+ }
+ \xeCJK_gset_mathcode:cn { g_@@_CJK/#1_range_clist } { \l_@@_fam_int }
+ }
+\cs_new_protected_nopar:Npn \@@_set_mathfont_block_aux:Nn #1#2
+ {
+ \int_set_eq:NN \l_@@_fam_int #1
+ \prop_gput:Nnn \g_@@_block_fam_prop {#2} {#1}
+ }
+\int_new:N \l_@@_fam_int
+\prop_new:N \g_@@_block_fam_prop
+\cs_generate_variant:Nn \@@_set_mathfont_block_aux:Nn { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_declare_mathfont:nn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_declare_mathfont:nn #1#2
+ {
+ \xeCJK_declare_symbol_font:nnnnn {#1} { \c_@@_encoding_tl }
+ {#2} { \mddefault } { \updefault }
+ \cs_if_free:cF
+ { \c_@@_encoding_tl/#2/\bfdefault/\updefault }
+ {
+ \SetSymbolFont {#1} { bold } { \c_@@_encoding_tl }
+ {#2} { \bfdefault } { \updefault }
+ }
+ \prop_gput:Nnx \g_@@_fam_prop {#2} { \exp_not:c { sym #1 } }
+ }
+\cs_generate_variant:Nn \prop_gput:Nnn { Nnx }
+\cs_generate_variant:Nn \xeCJK_declare_mathfont:nn { xx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_declare_symbol_font:nnnnn}
+% 主要功能同 \tn{DeclareSymbolFont},不带编码和重复定义检查。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_declare_symbol_font:nnnnn #1
+ { \@@_declare_symbol_font:cnnnn { sym #1 } }
+\cs_new_protected:Npn \@@_declare_symbol_font:Nnnnn #1
+ {
+ \xeCJK_new_fam:N #1
+ \xeCJK_new_symbol_font:Nnnnn #1
+ }
+\cs_generate_variant:Nn \@@_declare_symbol_font:Nnnnn { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_new_fam:N}
+% 我们从 $255$ 往下分配 \tn{fam},|\count18| 是 \LaTeXe{} 记录最后分配的 \tn{fam} 编号,
+% 作为我们的分配器的下限。事实上,还应该相应地减小 \tn{e@mathgroup@top} 才合理,但这可能会有不利影响,
+% 我们暂未处理。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_new_fam:N #1
+ {
+ \int_compare:nNnTF
+ { \g_@@_fam_allocation_int } > { \g_@@_fam_bottom_int }
+ {
+ \int_set_eq:NN \allocationnumber \g_@@_fam_allocation_int
+ \int_const:Nn #1 { \allocationnumber }
+ \iow_log:x
+ {
+ \token_to_str:N #1 =
+ \token_to_str:N \mathgroup \int_use:N \allocationnumber
+ }
+ \int_gdecr:N \g_@@_fam_allocation_int
+ }
+ { \@@_error:n { fam-exhausted } }
+ }
+\tex_countdef:D \g_@@_fam_bottom_int = 18 ~
+\int_new:N \g_@@_fam_allocation_int
+\int_gset:Nn \g_@@_fam_allocation_int { 255 }
+\@@_msg_new:nn { fam-exhausted }
+ { No~room~for~a~new~fam. }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_new_symbol_font:Nnnnn}
+% \begin{macro}{\@@_new_symbol_font:NN}
+% 功能同 \tn{new@symbolfont},但我们不增加 \tn{c@mv@normal} 和 \tn{c@mv@bold} 之类的计数器。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_new_symbol_font:Nnnnn #1#2#3#4#5
+ { \@@_new_symbol_font:Nc #1 { #2/#3/#4/#5 } }
+\cs_new_protected:Npn \@@_new_symbol_font:NN #1#2
+ {
+ \tl_put_right:Nn \group@list { \group@elt #1 #2 }
+ \cs_set_nopar:Npn \version@elt ##1
+ { \tl_put_right:Nn ##1 { \getanddefine@fonts #1 #2 } }
+ \version@list
+ }
+\cs_generate_variant:Nn \@@_new_symbol_font:NN { Nc }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_gset_mathcode:Nn,
+% \xeCJK_gset_mathcode:Nnn,\xeCJK_gset_mathcode:nnnn}
+% CJK 字符的数学类别固定为 $0$(\tn{mathord})。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_gset_mathcode:Nn #1#2
+ {
+ \clist_map_inline:Nn #1
+ {
+ \@@_set_char_class_aux:Nnw \xeCJK_gset_mathcode:nnnn { ##1 }
+ { 0 } {#2}
+ }
+ }
+\cs_generate_variant:Nn \xeCJK_gset_mathcode:Nn { c }
+\cs_new_protected_nopar:Npn \xeCJK_gset_mathcode:nnnn #1#2#3#4
+ {
+ \@@_check_num_range:nnNN {#1} {#2} \l_@@_begin_int \l_@@_end_int
+ \xeCJK_int_until_do:nn { \l_@@_begin_int > \l_@@_end_int }
+ {
+ \xeCJK_gset_mathcode:Nnn \l_@@_begin_int {#3} {#4}
+ \int_incr:N \l_@@_begin_int
+ }
+ }
+\cs_new_protected_nopar:Npn \xeCJK_gset_mathcode:Nnn #1#2#3
+ { \tex_global:D \tex_Umathcode:D #1 = #2 ~ #3 ~ #1 }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{抄录环境中的间距调整}
+%
+% \changes{v3.1.0}{2012/11/19}{放弃使用放缩字体大小的方式,而只采用调整间距的方式
+% 与西文等宽字体对齐。并且只适用于与抄录环境下。}
+% \changes{v3.2.0}{2013/04/15}{增加 \texttt{Verb} 选项。}
+% \changes{v3.2.1}{2013/05/29}{调整 \texttt{Verb} 选项:在命令 \tn{verb} 里使用时,
+% 不破坏标点禁则,增加值 \texttt{env+}。}
+%
+% \begin{macro}{Verb}
+% \changes{v3.2.5}{2013/07/25}{微调定义。}
+% 如果设置为 \texttt{env},则只在 \LaTeX 的抄录环境里使用 \tn{xeCJKVerbAddon},^^A
+% 而不包括 \tn{verb}。对当前使用环境的判断基于在标准 \LaTeX 的坏境定义里使用
+% \tn{begingroup} 和 \tn{endgroup} 来分组。
+% \begin{macrocode}
+\int_new:N \l_@@_verb_case_int
+\keys_define:nn { xeCJK / options }
+ {
+ Verb .choices:nn =
+ { true , env+ , env , false }
+ { \int_set_eq:NN \l_@@_verb_case_int \l_keys_choice_int } ,
+ Verb .default:n = { env }
+ }
+\cs_new_protected_nopar:Npn \@@_verb_font_hook:
+ {
+ \if_case:w \l_@@_verb_case_int
+ \or:
+ \@@_nobreak_skip_zero:
+ \or:
+ \int_compare:nNnTF \tex_currentgrouptype:D = { 14 }
+ { \xeCJKVerbAddon }
+ { \@@_nobreak_skip: }
+ \or:
+ \int_compare:nNnTF \tex_currentgrouptype:D = { 14 }
+ { \xeCJKVerbAddon }
+ { \@@_nobreak_skip_zero: }
+ \fi:
+ }
+\@@_after_preamble:n
+ {
+ \cs_set_protected_nopar:Npx \verbatim@font
+ { \exp_not:o { \verbatim@font } \@@_verb_font_hook: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_nobreak_skip_zero:,\@@_nobreak_skip:}
+% \changes{v3.2.8}{2013/11/16}{禁止在 \tn{verb} 中断行。}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_nobreak_skip_zero:
+ {
+ \@@_reset_shipout_skip:
+ \cs_set_eq:NN \@@_shipout_check_for_glue: \xeCJK_check_for_glue:
+ \cs_set_eq:NN \@@_shipout_boundary:w \xeCJK_CJK_and_Boundary:w
+ \tl_put_right:Nn \l_@@_reset_shipout_skip_hook_tl
+ {
+ \cs_set_eq:NN \xeCJK_check_for_glue: \@@_shipout_check_for_glue:
+ \cs_set_eq:NN \xeCJK_CJK_and_Boundary:w \@@_shipout_boundary:w
+ }
+ \xeCJK_cs_clear:N \CJKglue
+ \xeCJK_cs_clear:N \CJKecglue
+ \xeCJK_cs_clear:N \xeCJK_check_for_glue:
+ \cs_set_eq:NN \xeCJK_CJK_and_Boundary:w \xeCJK_class_group_end:
+ \cs_set_eq:NN \@@_punct_hskip:n \@@_nobreak_hskip:n
+ \cs_set_eq:NN \@@_punct_breakable_kern:n \@@_nobreak_hskip:n
+ }
+\cs_new_protected_nopar:Npn \@@_nobreak_skip:
+ {
+ \@@_reset_shipout_skip:
+ \xeCJK_glue_to_skip:nN { \CJKglue } \l_@@_ccglue_skip
+ \skip_if_eq:nnTF { \l_@@_ccglue_skip } { \c_zero_skip }
+ { \xeCJK_cs_clear:N \CJKglue }
+ { \cs_set_eq:NN \CJKglue \@@_nobreak_ccglue: }
+ \xeCJK_glue_to_skip:nN { \CJKecglue } \l_@@_ecglue_skip
+ \skip_if_eq:nnTF { \l_@@_ecglue_skip } { \c_zero_skip }
+ { \xeCJK_cs_clear:N \CJKecglue }
+ { \cs_set_eq:NN \CJKecglue \@@_nobreak_ecglue: }
+ \cs_set_eq:NN \@@_punct_hskip:n \@@_nobreak_hskip:n
+ \cs_set_eq:NN \@@_punct_breakable_kern:n \@@_nobreak_hskip:n
+ }
+\cs_new_protected_nopar:Npn \@@_nobreak_ccglue:
+ { \xeCJK_no_break: \skip_horizontal:N \l_@@_ccglue_skip }
+\cs_new_protected_nopar:Npn \@@_nobreak_ecglue:
+ { \xeCJK_no_break: \skip_horizontal:N \l_@@_ecglue_skip }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_reset_shipout_skip:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_reset_shipout_skip:
+ {
+ \cs_set_eq:NN \@@_shipout_CJKglue: \CJKglue
+ \cs_set_eq:NN \@@_shipout_CJKecglue: \CJKecglue
+ \cs_set_eq:NN \@@_shipout_punct_hskip:n \@@_punct_hskip:n
+ \cs_set_eq:NN
+ \@@_shipout_punct_breakable_kern:n \@@_punct_breakable_kern:n
+ \tl_set:Nx \l_@@_off_verb_addon_tl
+ {
+ \bool_if:NTF \l_@@_xecglue_bool
+ { \keys_set:nn { xeCJK / options } { xCJKecglue = true } }
+ { \keys_set:nn { xeCJK / options } { xCJKecglue = false } }
+ \exp_not:n
+ {
+ \cs_set_eq:NN \CJKglue \@@_shipout_CJKglue:
+ \cs_set_eq:NN \CJKecglue \@@_shipout_CJKecglue:
+ \cs_set_eq:NN \@@_punct_hskip:n \@@_shipout_punct_hskip:n
+ \cs_set_eq:NN \@@_punct_breakable_kern:n
+ \@@_shipout_punct_breakable_kern:n
+ \l_@@_reset_shipout_skip_hook_tl
+ }
+ }
+ \xeCJK_add_to_shipout:n { \l_@@_off_verb_addon_tl }
+ \keys_set:nn { xeCJK / options } { xCJKecglue = false }
+ }
+\tl_new:N \l_@@_reset_shipout_skip_hook_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKOffVerbAddon,\xeCJKVerbAddon}
+% \changes{v3.1.0}{2012/11/19}{新增 \tn{xeCJKVerbAddon} 用于抄录环境中的间距调整。}
+% \changes{v3.2.3}{2013/06/04}
+% {新增 \tn{xeCJKOffVerbAddon} 用于局部取消 \tn{xeCJKOffVerbAddon} 的影响;并解决
+% 跨页使用时影响到页眉页脚的问题。}
+% \changes{v3.2.5}{2013/07/13}{禁止自动换行,与西文一致。}
+% \changes{v3.2.8}{2013/11/16}{增加是否是等宽字体的判断。}
+% \tn{xeCJKVerbAddon} 进行了比较大的调整,应该只在分组环境里使用。为了方便调整间距
+% 以利于对齐,这里只把字符分成了两类,并且在 CJK 类与边界(空格)之间也插入
+% \tn{CJKecglue}。以字母“M”的宽度是否等于 \tn{fontdimen2} 来判断当前字体是否是
+% 等宽字体。如果不是等宽字体,则设置间距为零或正文间距。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKVerbAddon { }
+ {
+ \int_compare:nNnF \tex_currentgrouplevel:D = \c_zero_int
+ {
+ \bool_if:NF \l_@@_listings_env_bool
+ {
+ \dim_compare:nNnTF
+ { \tex_fontdimen:D 2 ~ \tex_font:D } =
+ { \tex_fontcharwd:D \tex_font:D \c_@@_mono_letter_int }
+ {
+ \@@_set_verb_exspace:
+ \@@_verb_addon:
+ }
+ {
+ \int_if_odd:nTF { \l_@@_verb_case_int }
+ { \@@_nobreak_skip_zero: }
+ { \@@_nobreak_skip: }
+ }
+ }
+ }
+ }
+\int_const:Nn \c_@@_mono_letter_int { 77 }
+\bool_new:N \l_@@_listings_env_bool
+\NewDocumentCommand \xeCJKOffVerbAddon { }
+ { \tl_use:N \l_@@_off_verb_addon_tl }
+\tl_new:N \l_@@_off_verb_addon_tl
+\cs_new_protected_nopar:Npn \@@_verb_addon:
+ {
+ \bool_if:NF \l_@@_verb_addon_bool
+ {
+ \bool_set_true:N \l_@@_verb_addon_bool
+ \@@_set_char_class_eq:nn { FullLeft } { CJK }
+ \@@_set_char_class_eq:nn { FullRight } { CJK }
+ \@@_set_char_class_eq:nn { HalfLeft } { Default }
+ \@@_set_char_class_eq:nn { HalfRight } { Default }
+ \@@_set_char_class_eq:nn { NormalSpace } { Default }
+ \cs_set_eq:NN \@@_shipout_CJKglue: \CJKglue
+ \cs_set_eq:NN \@@_shipout_CJKecglue: \CJKecglue
+ \cs_set_eq:NN \@@_shipout_check_for_glue: \xeCJK_check_for_glue:
+ \cs_set_eq:NN \@@_shipout_boundary:w \xeCJK_CJK_and_Boundary:w
+ \cs_set_protected_nopar:Npx \xeCJKOffVerbAddon
+ {
+ \@@_reset_char_class:n { FullLeft }
+ \@@_reset_char_class:n { FullRight }
+ \@@_reset_char_class:n { HalfLeft }
+ \@@_reset_char_class:n { HalfLeft }
+ \@@_reset_char_class:n { NormalSpace }
+ \bool_if:NTF \l_@@_xecglue_bool
+ { \keys_set:nn { xeCJK / options } { xCJKecglue = true } }
+ { \keys_set:nn { xeCJK / options } { xCJKecglue = false } }
+ \exp_not:n
+ {
+ \cs_set_eq:NN \CJKglue \@@_shipout_CJKglue:
+ \cs_set_eq:NN \CJKecglue \@@_shipout_CJKecglue:
+ \cs_set_eq:NN \xeCJK_check_for_glue: \@@_shipout_check_for_glue:
+ \cs_set_eq:NN \xeCJK_CJK_and_Boundary:w \@@_shipout_boundary:w
+ }
+ }
+ \xeCJK_add_to_shipout:n { \xeCJKOffVerbAddon }
+ \keys_set:nn { xeCJK / options } { xCJKecglue = false }
+ }
+ \skip_if_eq:nnTF { \l_@@_verb_exspace_skip } { \c_zero_skip }
+ {
+ \xeCJK_cs_clear:N \CJKglue
+ \xeCJK_cs_clear:N \CJKecglue
+ }
+ {
+ \skip_set_eq:NN \l_@@_ccglue_skip \l_@@_verb_exspace_skip
+ \skip_set:Nn \l_@@_ecglue_skip { .5 \l_@@_verb_exspace_skip }
+ \cs_set_eq:NN \CJKglue \@@_nobreak_ccglue:
+ \cs_set_eq:NN \CJKecglue \@@_nobreak_ecglue:
+ }
+ \cs_set_eq:NN \xeCJK_check_for_glue: \CJKecglue
+ \cs_set_eq:NN \xeCJK_CJK_and_Boundary:w \@@_verb_CJK_and_Boundary:w
+ }
+\cs_new_protected_nopar:Npn \@@_verb_CJK_and_Boundary:w
+ { \xeCJK_class_group_end: \CJKecglue }
+\cs_new_protected_nopar:Npn \@@_reset_char_class:n #1
+ {
+ \int_set:Nn \l_@@_tmp_int { \xeCJK_class_num:n {#1} }
+ \clist_map_inline:cn { c_@@_#1_chars_clist }
+ { \tex_XeTeXcharclass:D ##1 = \l_@@_tmp_int }
+ }
+\bool_new:N \l_@@_verb_addon_bool
+\cs_new_eq:NN \CJKfixedspacing \xeCJKVerbAddon
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_verb_exspace:}
+% \changes{v3.1.1}{2012/12/08}{调整间距的计算方法。}
+% \changes{v3.2.4}{2013/06/29}{当计算得出的间距为负时,缩小 CJK 字体。}
+% 在抄录环境中,CJK 文字之间的间距为当前西文字体两个空格的宽度与当前字体大小之差,
+% 而与西文和空格的间距为 CJK 文字之间的间距的一半。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_set_verb_exspace:
+ {
+ \tl_if_exist:cTF { xeCJK/verb/\CJK@family/\curr@fontshape/\f@size }
+ {
+ \skip_set:Nn \l_@@_verb_exspace_skip
+ { \use:c { xeCJK/verb/\CJK@family/\curr@fontshape/\f@size } }
+ }
+ {
+ \tl_set:Nx \l_@@_current_coor_tl { \CJK@family/\curr@fontshape }
+ \prop_get:NoNTF \g_@@_scale_family_prop
+ \l_@@_current_coor_tl \l_xeCJK_family_tl
+ {
+ \xeCJK_switch_family:o { \l_xeCJK_family_tl }
+ \skip_zero:N \l_@@_verb_exspace_skip
+ }
+ {
+ \group_begin: \xeCJK_select_font: \exp_args:NNo \group_end:
+ \@@_set_verb_exspace:n
+ { \dim_use:N \tex_fontcharwd:D \tex_font:D "4E00 ~ }
+ }
+ }
+ }
+\skip_new:N \l_@@_verb_exspace_skip
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_verb_exspace:n}
+% 当两个西文空格的宽度小于一个 CJK 文字的宽度时,对目前使用的 CJK 字体进行适当缩小。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_set_verb_exspace:n #1
+ {
+ \skip_set:Nn \l_@@_verb_exspace_skip
+ { 2 \tex_fontdimen:D 2 ~ \tex_font:D - #1 }
+ \dim_compare:nNnTF \l_@@_verb_exspace_skip < \c_zero_dim
+ {
+ \skip_zero:N \l_@@_verb_exspace_skip
+ \use:x
+ {
+ \@@_set_verb_scale:nn
+ { \dim_to_fp:n { 2 \tex_fontdimen:D 2 ~ \tex_font:D } }
+ { \dim_to_fp:n {#1} }
+ }
+ }
+ {
+ \tl_const:cx { xeCJK/verb/\CJK@family/\curr@fontshape/\f@size }
+ { \skip_use:N \l_@@_verb_exspace_skip }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_verb_scale:nn}
+% 缩小 CJK 字体,并保存相关信息。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_set_verb_scale:nn #1#2
+ {
+ \fp_set:Nn \l_@@_scale_factor_fp { #1 / #2 }
+ \@@_warning:nxx { scale-factor }
+ { \fp_eval:n { trunc ( \l_@@_scale_factor_fp , 4 ) } }
+ { \fp_eval:n { ceil ( #2 / #1 , 4 ) } }
+ \xeCJK_add_font_features:Nnx \c_true_bool
+ { } { Scale = { \fp_use:N \l_@@_scale_factor_fp } }
+ \prop_gput:NVV \g_@@_scale_family_prop
+ \l_@@_current_coor_tl \l_xeCJK_family_tl
+ }
+\@@_msg_new:nn { scale-factor }
+ {
+ `\token_to_str:N \xeCJKVerbAddon'~may~not~work~properly.\\\\
+ You~may~set~`Scale=#1'~to~CJKfamily~
+ `\@@_msg_family_map:n { \l_xeCJK_family_tl }',\\
+ or~set~`Scale=#2'~to~family~
+ `\str_if_eq:eeTF \f@family \ttdefault
+ { \token_to_str:N \ttdefault } { \f@family }'.
+ }
+\fp_new:N \l_@@_scale_factor_fp
+\prop_new:N \g_@@_scale_family_prop
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_visible_space:}
+% \changes{v3.2.5}{2013/07/13}{可视空格考虑传统 \TeX 字体的情况。}
+% 如果文档不使用 \texttt{EU1} 作为默认字体编码,那么默认的打字机字体族很可能是
+% 传统的 \TeX 字体,这时可视空格按照 \texttt{OT1} 编码传统一般就是字体中的 |\char32|。
+% 这里加入 \cs{scan_stop:} 的目的是强制发生状态转移。这样当空格出现在 CJK 文字
+% 后面时,使字体回到西文,保证在当前西文字体而不是在 CJK 字体中检查有没有 |U+2423|。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_visible_space:
+ {
+ \xeCJK_make_boundary:
+ \xeCJK_glyph_if_exist:NTF { ^^^^2423 }
+ { ^^^^2423 }
+ {
+ \int_compare:nNnTF { \tex_XeTeXfonttype:D \tex_font:D } = \c_zero_int
+ {
+ \str_if_eq:eeTF { \f@family } { \ttdefault }
+ { \c_catcode_other_space_tl }
+ { \textvisiblespace }
+ }
+ { \xeCJK_visible_space_fallback: }
+ }
+ }
+\AtEndOfPackage
+ { \cs_gset_eq:NN \fontspec_visible_space: \xeCJK_visible_space: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_visible_space_fallback:}
+% \changes{v3.1.0}{2012/11/19}
+% {调整 \pkg{fontspec} 的后备可视空格符号,以便于使用时对齐。}
+% \pkg{fontspec} 使用 |lmtt| 字体中的可视空格符号(|U+2423|)作为当前字体中相应符号
+% 的后备。但是 |lmtt| 的字体大小未必与当前字体匹配。因此,我们在这里做一些调整,以
+% 保证使用后备可视空格符号时,也能保证对齐。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_visible_space_fallback:
+ { {
+ \cs_if_exist_use:cF { xeCJK/space/\curr@fontshape/\f@size }
+ { \xeCJK_set_visible_space_font: }
+ ^^^^2423
+ } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_set_visible_space_font:}
+% 当前字体空格的宽度与后备字体 |lmtt| 不一样时,就对 \tn{textvisiblespace} 的字体尺寸
+% 按相应的比例放缩。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_set_visible_space_font:
+ {
+ \tl_set:Nx \l_@@_current_coor_tl
+ { xeCJK/space/\curr@fontshape/\f@size }
+ \exp_args:No \@@_set_visible_space_size:n
+ { \dim_use:N \tex_fontdimen:D 2 ~ \tex_font:D }
+ \xeCJK_font_gset_to_current:c { \l_@@_current_coor_tl }
+ }
+\cs_new_protected_nopar:Npn \@@_set_visible_space_size:n #1
+ {
+ \fontencoding { \g_fontspec_encoding_tl }
+ \tl_set:Nx \f@family { lmtt }
+ \selectfont
+ \dim_compare:nNnF {#1} = { \tex_fontdimen:D 2 ~ \tex_font:D }
+ {
+ \fontsize
+ {
+ \dim_eval:n
+ {
+ \f@size pt *
+ \dim_ratio:nn {#1} { \tex_fontdimen:D 2 ~ \tex_font:D }
+ }
+ }
+ { \f@baselineskip }
+ \selectfont
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{\pkg{xeCJK} 其它选项}
+%
+% \begin{macro}{LocalConfig}
+% \changes{v3.1.0}{2012/11/20}{增加 \texttt{LocalConfig} 选项用于载入本地配置文件。}
+% 声明载入本地配置文件的选项。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ LocalConfig .choice: ,
+ LocalConfig / false .code:n =
+ { \bool_gset_false:N \g_@@_config_bool } ,
+ LocalConfig / true .code:n =
+ {
+ \bool_gset_true:N \g_@@_config_bool
+ \tl_gset:Nn \g_@@_config_name_tl { xeCJK }
+ } ,
+ LocalConfig / unknown .code:n =
+ {
+ \bool_gset_true:N \g_@@_config_bool
+ \tl_gset:Nx \g_@@_config_name_tl { xeCJK - \l_keys_value_tl }
+ } ,
+ LocalConfig .default:n = { true }
+ }
+\tl_new:N \g_@@_config_name_tl
+\bool_new:N \g_@@_config_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{CJKnumber,indentfirst}
+% \changes{v3.2.11}{2014/03/14}{放弃 \texttt{indentfirst} 和 \texttt{CJKnumber} 选项。}
+% \texttt{CJKnumber} 和 \texttt{indentfirst} 是过时选项。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ CJKnumber .code:n =
+ { \@@_warning:nxx { option-deprecated } { \l_keys_key_tl } { CJKnumb } } ,
+ indentfirst .code:n =
+ { \@@_warning:nxx { option-deprecated } { \l_keys_key_tl } { indentfirst } } ,
+ normalindentfirst .code:n =
+ { \@@_warning:nxx { option-deprecated } { \l_keys_key_tl } { } }
+ }
+\@@_msg_new:nn { option-deprecated }
+ {
+ The~`#1'~option~is~deprecated.\\
+ \tl_if_empty:nF {#2}
+ { You~may~load~the~package~`#2'~after~xeCJK~to~use~its~function.\\ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{quiet,silent}
+% 将调用 \pkg{xeCJK} 时使用的未知的选项传递给 \pkg{fontspec} 宏包。
+% 对 \pkg{fontspec} 的 |quiet| 和 |silent| 选项进行修改,使其适用于 \pkg{xeCJK}。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ quiet .code:n =
+ {
+ \msg_redirect_module:nnn { xeCJK } { warning } { info }
+ \msg_redirect_module:nnn { xeCJK } { info } { none }
+ \xeCJK_if_package_loaded:nF { fontspec }
+ { \PassOptionsToPackage { quiet } { fontspec } }
+ } ,
+ silent .code:n =
+ {
+ \msg_redirect_module:nnn { xeCJK } { warning } { none }
+ \msg_redirect_module:nnn { xeCJK } { info } { none }
+ \xeCJK_if_package_loaded:nF { fontspec }
+ { \PassOptionsToPackage { silent } { fontspec } }
+ } ,
+ unknown .code:n =
+ {
+ \xeCJK_if_package_loaded:nTF { fontspec }
+ { \@@_error:nx { key-unknown } { \l_keys_key_tl } }
+ { \PassOptionsToPackage { \l_keys_key_tl } { fontspec } }
+ }
+ }
+\@@_msg_new:nn { key-unknown }
+ {
+ Sorry,~but~xeCJK/options~does~not~have~a~key~called~`#1'.\\\\
+ The~key~`#1'~is~being~ignored.
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{\pkg{xeCJK} 初始化设置}
+%
+% \begin{macro}[int]{\CJKsymbol, \CJKpunctsymbol}
+% \begin{macrocode}
+\cs_new_nopar:Npn \CJKsymbol #1 {#1}
+\cs_new_nopar:Npn \CJKpunctsymbol #1 {#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \pkg{xeCJK} 宏包的初始化设置。
+%
+% \begin{macrocode}
+\keys_set:nn { xeCJK / options }
+ {
+ CJKglue = { \skip_horizontal:n { \c_zero_dim plus 0.08 \tex_baselineskip:D } } ,
+ CJKecglue = { ~ } ,
+ xCJKecglue = false ,
+ CheckSingle = false ,
+ PlainEquation = false ,
+ CheckFullRight = false ,
+ CJKspace = false ,
+ CJKmath = false ,
+ xeCJKactive = true ,
+ LocalConfig = true ,
+ LoadFandol = true ,
+ RubberPunctSkip = true ,
+ Verb = env ,
+ EmboldenFactor = 4 ,
+ SlantFactor = 0.167 ,
+ PunctStyle = quanjiao ,
+ NewLineCS = { \par \[ } ,
+ EnvCS = { \begin \end } ,
+ WidowPenalty = { 10 000 } ,
+ NoBreakCS = { \footnote \footnotemark \nobreak } ,
+ KaiMingPunct = { ^^^^3002 ^^^^ff0e ^^^^ff1f ^^^^ff01 } ,
+ LongPunct = { ^^^^2014 ^^^^2e3a ^^^^2025 ^^^^2026 } ,
+ MiddlePunct = { ^^^^2013 ^^^^2014 ^^^^2e3a ^^^^2027 ^^^^00b7 ^^^^30fb ^^^^ff65 } ,
+ AllowBreakBetweenPuncts = false
+ }
+\defaultCJKfontfeatures { Script = CJK }
+% \end{macrocode}
+%
+% 半字线连接号\footnote{见\href{http://www.moe.gov.cn/ewebeditor/uploadfile/2015/01/13/20150113092346124.pdf}
+% {《夹用英文的中文文本的标点符号用法(草案)》5.13 节。}}应为半角宽度。
+% \begin{macrocode}
+\xeCJKsetwidth { ^^^^2013 } { 0.5 em }
+% \end{macrocode}
+%
+% \changes{v3.7.0}{2018/03/16}{不再默认引入 \pkg{xunicode} 宏包。}
+%
+% 执行宏包选项,并载入 \pkg{fontspec} 宏包。
+% \begin{macrocode}
+\ProcessKeysOptions { xeCJK / options }
+\RequirePackage { fontspec } [ 2019/03/15 ]
+% \end{macrocode}
+%
+% \begin{variable}{\c_@@_encoding_tl}
+% 保存 \pkg{fontspec} 声明字体时使用的字体编码。
+% \begin{macrocode}
+\tl_const:Nx \c_@@_encoding_tl { \g_fontspec_encoding_tl }
+% \end{macrocode}
+% \end{variable}
+%
+% \changes{v3.1.0}{2012/11/21}{改用 \pkg{indentfirst} 宏包处理缩进的问题。}
+%
+% 对不能通过 \tn{xeCJKsetup} 设置的选项给出警告。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ LocalConfig .code:n =
+ { \@@_warning:nx { option-invalid } { \l_keys_key_tl } }
+ }
+\@@_msg_new:nn { option-invalid }
+ {
+ The~`#1'~option~only~can~be~set~in~the~optional~argument~to~the\\
+ \token_to_str:N \usepackage \ command~when~xeCJK~is~being~loaded.\\\\
+ Please~do~not~set~it~via~the~\token_to_str:N \xeCJKsetup \ command.
+ }
+% \end{macrocode}
+%
+% \begin{variable}{\CJKrmdefault,\CJKsfdefault,\CJKttdefault,\CJKfamilydefault}
+% \begin{macrocode}
+\tl_if_exist:NF \CJKrmdefault { \tl_gset:Nn \CJKrmdefault { rm } }
+\tl_if_exist:NF \CJKsfdefault { \tl_gset:Nn \CJKsfdefault { sf } }
+\tl_if_exist:NF \CJKttdefault { \tl_gset:Nn \CJKttdefault { tt } }
+\tl_new:N \l_@@_family_default_init_tl
+\cs_new_eq:NN \@@_family_default_wrap:n \use:n
+\tl_set:Nx \l_@@_family_default_init_tl
+ {
+ \exp_not:N \@@_family_default_wrap:n
+ {
+ \tl_if_exist:NTF \CJKfamilydefault
+ { \exp_not:V \CJKfamilydefault }
+ { \exp_not:N \CJKrmdefault }
+ }
+ }
+\tl_gset_eq:NN \CJKfamilydefault \l_@@_family_default_init_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\xeCJKsetup}
+% 在导言区或文档中设置 \pkg{xeCJK} 的接口。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKsetup { +m }
+ {
+ \keys_set:nn { xeCJK / options } {#1}
+ \tex_ignorespaces:D
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJKsetemboldenfactor, \xeCJKsetslantfactor}
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKsetemboldenfactor { m }
+ { \xeCJKsetup { EmboldenFactor = {#1} } }
+\NewDocumentCommand \xeCJKsetslantfactor { m }
+ { \xeCJKsetup { SlantFactor = {#1} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\punctstyle, \xeCJKplainchr}
+% \begin{macrocode}
+\NewDocumentCommand \punctstyle { m } { \xeCJKsetup { PunctStyle = {#1} } }
+\NewDocumentCommand \xeCJKplainchr { } { \xeCJKsetup { PunctStyle = plain } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\CJKsetecglue}
+% \begin{macrocode}
+\NewDocumentCommand \CJKsetecglue { m } { \xeCJKsetup { CJKecglue = {#1} } }
+\cs_new_eq:NN \xeCJKsetecglue \CJKsetecglue
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\CJKspace,\CJKnospace}
+% \begin{macrocode}
+\NewDocumentCommand \CJKspace { } { \xeCJKsetup { CJKspace = true } }
+\NewDocumentCommand \CJKnospace { } { \xeCJKsetup { CJKspace = false } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJKallowbreakbetweenpuncts, \xeCJKnobreakbetweenpuncts}
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKallowbreakbetweenpuncts { }
+ { \xeCJKsetup { AllowBreakBetweenPuncts = true } }
+\NewDocumentCommand \xeCJKnobreakbetweenpuncts { }
+ { \xeCJKsetup { AllowBreakBetweenPuncts = false } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJKenablefallback, \xeCJKdisablefallback}
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKenablefallback { }
+ { \xeCJKsetup { AutoFallBack = true } }
+\NewDocumentCommand \xeCJKdisablefallback { }
+ { \xeCJKsetup { AutoFallBack = false } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJKsetcharclass}
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKsetcharclass { m m m }
+ {
+ \xeCJK_set_char_class:nnn {#1} {#2} {#3}
+ \xeCJKResetPunctClass
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{兼容性修补}
+%
+% \begin{macro}[int]{\hbar}
+% \changes{v3.2.16}{2014/11/20}{修复 \tn{hbar}。}
+% \pkg{fontspec} 会设置 operators 数学字体族(|\fam0|)为 \texttt{EU1} 编码的
+% \tn{rmdefault} 字体。这导致 \LaTeXe{} 定义的 \tn{hbar} 只显示为 $h$。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_fix_hbar:
+ {
+ \cs_if_free:NF \symlegacymaths
+ {
+ \group_begin:
+ \cs_set_nopar:Npn \@@_tmp:w
+ { { \mathchar '26 \mkern -9mu h } }
+ \exp_after:wN \group_end:
+ \if_meaning:w \@@_tmp:w \hbar
+ \cs_set_protected_nopar:Npx \hbar
+ { {
+ \mathchar
+ \int_eval:n { \symlegacymaths * 256 + '26 } ~
+ \mkern -9mu h
+ } }
+ \fi:
+ }
+ }
+\cs_if_exist:NTF \fontspec_maybe_setup_maths:
+ {
+ \cs_gset_protected_nopar:Npx \fontspec_maybe_setup_maths:
+ {
+ \exp_not:o { \fontspec_maybe_setup_maths: }
+ \xeCJK_fix_hbar:
+ }
+ }
+ { \AtBeginDocument { \xeCJK_fix_hbar: } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK@update@fam,\Url@MathSetup}
+% \changes{v3.2.7}{2013/11/09}{使通过 \tn{UrlFont} 等命令设置的 CJK 字体生效。}
+% 使通过 \tn{urlstyle} 或者 \tn{UrlFont} 设置的路径中使用的 CJK 字体生效。
+% 使用 \tn{everymath} 钩子中数学模式中重定义 CJK 数学字体,以确保我们的设置在
+% \tn{check@mathfonts} 之后生效,不会被它覆盖。
+% 更合理的方式是定义一个新的 \tn{mathversion} 来切换。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK@update@fam
+ {
+ \addto@hook \everymath
+ {
+ \@@_update_main_fam:
+ \@@_update_block_fam:
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_update_main_fam:
+ {
+ \group_begin:
+ \xeCJK_select_font:
+ \exp_last_unbraced:NNNo \group_end:
+ \tex_textfont:D \c_xeCJK_math_fam_int \tex_the:D \tex_font:D
+ }
+\cs_new_protected_nopar:Npn \@@_update_block_fam:
+ {
+ \prop_if_empty:NF \g_@@_block_fam_prop
+ {
+ \prop_map_function:NN
+ \g_@@_block_fam_prop
+ \@@_update_block_fam:nn
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_update_block_fam:nn #1#2
+ {
+ \int_set:Nn \l_@@_fam_int {#2}
+ \group_begin:
+ \xeCJK_select_font:n {#1}
+ \exp_last_unbraced:NNNo \group_end:
+ \tex_textfont:D \l_@@_fam_int \tex_the:D \tex_font:D
+ }
+\@@_after_end_preamble:n
+ {
+ \bool_lazy_and:nnT
+ { \g_@@_math_bool }
+ { \cs_if_exist_p:N \Url@MathSetup }
+ { \tl_put_right:Nn \Url@MathSetup { \xeCJK@update@fam } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\fontspec_setup_maths:,\mathrm}
+% \changes{v3.2.6}{2013/08/02}{为 \tn{mathrm} 减少一个可能的数学字体族。}
+% 如果没有设置 \tn{setboldmathrm},即 \cs{g_fontspec_bfmathrm_tl} 为空,那么
+% \tn{mathrm} 的字体实际与 \texttt{operators} 字体族完全一致。这时候应该通过
+% \tn{DeclareSymbolFontAlphabet} 来定义 \tn{mathrm},避免使用它的时候再声明
+% 一个重复的数学字体族。\pkg{fontspec} v2.4a 已经正确定义了 \tn{mathrm}。
+% \begin{macrocode}
+\@ifpackagelater { fontspec } { 2014/06/21 } { }
+ {
+ \cs_gset_protected_nopar:Npx \fontspec_setup_maths:
+ {
+ \exp_not:o
+ {
+ \fontspec_setup_maths:
+ \bool_lazy_or:nnT
+ { \tl_if_empty_p:N \g__fontspec_bfmathrm_tl }
+ { \tl_if_empty_p:N \g_fontspec_bfmathrm_tl }
+ { \DeclareSymbolFontAlphabet \mathrm { operators } }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4.5}{2017/01/02}{更新 \LaTeXiii{} 的过时用法。}
+%
+% \begin{macro}[int]{\(,\),\math,\endmath,\ensuremath}
+% \begin{macro}{\@@_math_robust:N}
+% \changes{v3.2.5}{2013/07/25}
+% {解决汉字后紧跟 \tn{(}\texttt{...}\tn{)} 形式的行内数学公式时,不能加入间距的问题。}
+% \changes{v3.2.6}{2013/08/03}{考虑 \pkg{ulem} 对 \tn{MakeRobust} 的不当定义。}
+% \changes{v3.2.6}{2013/08/03}{考虑 \tn{math} 和 \tn{ensuremath}。}
+% \changes{v3.3.1}{2015/04/14}{兼容 \LaTeXe{} 2015。}
+% \tn{(} 的在 \LaTeXe 中的定义是
+% \begin{verbatim}
+% \def\({\relax\ifmmode\@badmath\else$\fi}
+% \end{verbatim}
+% 这个定义最开始的 \tn{relax} 是为了防止 \tn{(} 出现在表格单元格的开始位置时,模式
+% 判断不正确(因为 \TeX 会先看单元格中第一个不可展的非空格记号是否是 \tn{omit} 或
+% \tn{noalign})。但是它会造成一个边界,使 \pkg{xeCJK} 不能看到 \tn{relax} 后面出现的
+% |$|,从而不能加入间距\footnote{\url{http://tex.stackexchange.com/q/124773}}。使用
+% \hologo{eTeX} 的 \tn{protected} 来定义它,可以不需要 \tn{relax},或者将 \tn{relax}
+% 改成 \cs{scan_align_safe_stop:},都可以避免这些情况。同时 \pkg{fixltx2e} 中还使用了
+% |\MakeRobust\(|,我们需要小心处理。另外 \pkg{ulem} 也定义了一个 \tn{MakeRobust},
+% 如果它被放在 \pkg{fixltx2e} 之前载入,那么 \pkg{fixltx2e} 的定义就会失效(因为
+% \pkg{fixltx2e} 使用 \tn{providecommand}|*| 来定义 \tn{MakeRobust})。但是 \pkg{ulem}
+% 的定义并不完全正确,没有考虑 \TeX 不会略去控制符号后面的空格的情况。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_math_robust:N #1
+ {
+ \group_begin: \exp_args:NcNc \group_end:
+ { @@_math_robust_aux:NN } #1 { \cs_to_str:N #1 ~ }
+ }
+\cs_new_protected_nopar:Npn \@@_math_robust_aux:NN #1#2
+ {
+ \exp_args:Nx \str_case:nnTF { \cs_replacement_spec:N #1 }
+ {
+ { \x@protect #1 \protect #2 } { }
+ { \protect #2 } { }
+ }
+ { \@@_math_robust:NN #1#2 }
+ { \@@_math_robust:NN #1#1 }
+ }
+\cs_new_protected_nopar:Npn \@@_math_robust:NN #1#2
+ {
+ \str_if_eq:eeTF { \cs_argument_spec:N #2 } { }
+ {
+ \exp_args:No \tl_if_head_eq_meaning:nNTF {#2} \scan_stop:
+ {
+ \cs_gset_protected_nopar:Npx #1
+ { \tl_tail:N #2 }
+ }
+ {
+ \cs_if_eq:NNTF #1 \ensuremath
+ {
+ \cs_gset_protected_nopar:Npx #1
+ { \exp_not:o {#2} }
+ }
+ {
+ \@@_warning:nxx { robust-failure }
+ { \token_to_str:N #1 } { \token_to_meaning:N #2 }
+ }
+ }
+ }
+ {
+ \@@_warning:nxx { robust-failure }
+ { \token_to_str:N #1 } { \token_to_meaning:N #2 }
+ }
+ }
+\@@_msg_new:nnn { robust-failure }
+ { xeCJK~can~not~make~`#1'~robust. }
+ {
+ The~current~meaning~of~`#1'~is:\\
+ \iow_indent:n {#2}
+ }
+\cs_if_eq:NNTF \( \math
+ {
+ \@@_math_robust:N \(
+ \cs_set_eq:NN \math \(
+ }
+ {
+ \@@_math_robust:N \(
+ \@@_math_robust:N \math
+ }
+\cs_if_eq:NNTF \) \endmath
+ {
+ \@@_math_robust:N \)
+ \cs_set_eq:NN \endmath \)
+ }
+ {
+ \@@_math_robust:N \)
+ \@@_math_robust:N \endmath
+ }
+\@@_math_robust:N \ensuremath
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \changes{v3.2.5}{2013/07/25}{解决 \pkg{fixltx2e} 和 \pkg{amsthm} 的冲突。}
+% \changes{v3.3.1}{2015/04/15}{删去 \pkg{fixltx2e} 和 \pkg{amsthm} 的冲突补丁。}
+%
+% \changes{v3.1.2}{2013/01/01}
+% {修正非 \tn{UTFencname} 编码下面 \pkg{xunicode} 重定义的 \tn{nobreakspace} 会失效的问题。}
+% \changes{v3.2.5}{2013/07/18}{恢复 \tn{nobreakspace} 的原始定义。}
+% \changes{v3.7.0}{2018/03/18}{对 \tn{nobreakspace} 的恢复放到 \pkg{xunicode-addon} 中处理。}
+%
+% \changes{v3.1.1}{2012/12/13}{对于与 \pkg{xltxtra} 的冲突给出错误警告。}
+% 比较老版本的 \pkg{realscripts} 定义了 \cs{dim_max:nn} 和 \cs{dim_min:nn},这与
+% 新版本的 \pkg{expl3} 冲突。
+% \begin{macrocode}
+\@@_msg_new:nn { conflict-package }
+ {
+ The~`#1'~package~is~too~old. \\
+ Please~update~an~up~to~date~version~of~it\\
+ using~your~TeX~package~manager~or~from~CTAN.
+ }
+\xeCJK_if_package_loaded:nTF { realscripts }
+ {
+ \@ifpackagelater { realscripts } { 2010/10/10 } { }
+ {
+ \@@_error:nx { conflict-package }
+ {
+ \xeCJK_if_package_loaded:nTF { xltxtra }
+ { xltxtra } { realscripts }
+ }
+ }
+ }
+ {
+ \cs_new_eq:NN \@@_dim_max:nn \dim_max:nn
+ \cs_new_eq:NN \@@_dim_min:nn \dim_min:nn
+ \@@_at_end_preamble:n
+ {
+ \xeCJK_if_package_loaded:nT { realscripts }
+ {
+ \@ifpackagelater { realscripts } { 2010/10/10 } { }
+ {
+ \cs_gset_eq:NN \dim_max:nn \@@_dim_max:nn
+ \cs_gset_eq:NN \dim_min:nn \@@_dim_min:nn
+ }
+ }
+ \cs_undefine:N \@@_dim_max:nn
+ \cs_undefine:N \@@_dim_min:nn
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\fontfamily}
+% \begin{macro}[int]{\xeCJK@fontfamily}
+% \changes{v3.1.1}{2012/12/06}{修改主要 \texttt{CJK} 字体族的自动更新方式。}
+% \changes{v3.1.2}{2013/01/01}{不将参数完全展开。}
+% \changes{v3.4.6}{2017/02/23}
+% {将族名参数完全展开,以解决与 \pkg{fontspec} 2017/01/24 v2.5d 的兼容问题。}
+% 修改 \tn{fontfamily},使主要 |CJK| 字体族能随西文主要字体更新。
+% \begin{macrocode}
+\RenewDocumentCommand \fontfamily { m }
+ {
+ \tl_set:Nx \f@family {#1}
+ \xeCJK@fontfamily {#1}
+ }
+\cs_new_protected_nopar:Npn \xeCJK@fontfamily #1
+ {
+ \str_if_eq:nnTF {#1} { \familydefault }
+ { \xeCJK_switch_family:x { \CJKfamilydefault } }
+ { \@@_update_family_aux: }
+ }
+\cs_new_protected_nopar:Npn \@@_update_family_aux:
+ {
+ \str_case_e:nn { \f@family }
+ {
+ { \rmdefault } { \xeCJK_switch_family:x { \CJKrmdefault } }
+ { \sfdefault } { \xeCJK_switch_family:x { \CJKsfdefault } }
+ { \ttdefault } { \xeCJK_switch_family:x { \CJKttdefault } }
+ { \familydefault } { \xeCJK_switch_family:x { \CJKfamilydefault } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%<@@=>
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK@fix@penalty}
+% \changes{v3.1.0}{2012/11/13}{采用通过不修改原语 \tn{/} 的方式对修复倾斜校正。}
+% 对 \LaTeXe 内核中的 \tn{fix@penalty} 被用于诸如 \tn{textit} 之类的文档
+% 字体转换命令的定义之中。这里对它进行补丁的目的是修复其中的倾斜校正,并使得这些
+% 文档命令与紧随其后的汉字之间可以正确的插入 \tn{CJKecglue} 或者忽略其中的空格。
+% 例如 \verb*|这是 \emph{强调} 文本|,第二个空格可以被忽略掉。如果使用 |xCJKecglue|
+% 选项,第一个空格也可以被省略。事实上,在 \tn{sw@slant} 的定义中,\tn{@@italiccorr}
+% 前面的 \tn{lastskip} 和 \tn{lastpenalty} 有四种情况,这里只对它们都为零的情况进行
+% 处理。
+% \begin{macrocode}
+\cs_new_eq:NN \xeCJK@fix@penalty \fix@penalty
+\tl_replace_once:Nnn \xeCJK@fix@penalty { \@@italiccorr } { \xeCJK@italiccorr }
+\tl_replace_once:Nnn \sw@slant { \fix@penalty } { \xeCJK@fix@penalty }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK@italiccorr}
+% 修复倾斜校正,并处理汉字后面的空格。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK@italiccorr
+ {
+ \int_compare:nNnTF \tex_XeTeXinterchartokenstate:D > \c_zero_int
+ { \xeCJK_italic_correction: }
+ { \@@italiccorr }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%<@@=xeCJK>
+% \end{macrocode}
+%
+% \begin{macro}[int]{\xeCJK_italic_correction:}
+% 修复倾斜校正,并处理汉字后面的空格。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_italic_correction:
+ {
+ \int_compare:nNnT \tex_lastnodetype:D = { 12 }
+ { \@@_italic_correction: }
+ }
+\cs_new_protected_nopar:Npn \@@_italic_correction:
+ {
+ \dim_case:nnF { \tex_lastkern:D }
+ {
+ { \@@_node:n { default } }
+ {
+ \xeCJK_remove_node: \tex_italiccorrection:D
+ \xeCJK_make_node:n { default }
+ }
+ { \@@_node:n { CJK } }
+ {
+ \xeCJK_remove_node: \tex_italiccorrection:D
+ \xeCJK_make_node:n { CJK }
+ \@@_italic_correction_aux:
+ }
+ { \@@_node:n { CJK-space } }
+ {
+ \xeCJK_remove_node: \tex_italiccorrection:D
+ \xeCJK_make_node:n { CJK-space }
+ \@@_italic_correction_aux:
+ }
+ }
+ { \tex_italiccorrection:D }
+ }
+% \end{macrocode}
+% \cs{xeCJK_ignore_spaces:w} 里面用到 |peek| 函数来判断后面是不是空格,而此时它
+% 后面还有 $4$ 个 \tn{fi} 或者 |\else...\fi| 没有被展开,将影响 |peek| 函数的
+% 判断。因此我们需要用 $2^4-1=15$ 个 \cs{exp_after:wN} 来展开它们。
+% 显然,这里用 \cs{exp_last_unbraced:Nf} 会比较方便,但是它会吃掉
+% \verb*|\textit{...} | 等后面原来存在的空格作为完全展开的结束。要正确使用它还
+% 需要另外的处理(使用 \cs{exp_stop_f:})。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_italic_correction_aux:
+ {
+ \exp_after:wN \exp_after:wN \exp_after:wN
+ \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
+ \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
+ \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
+ \xeCJK_ignore_spaces:w
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\g_@@_xetex_allocator_int}
+% \changes{v3.3.1}{2015/04/14}{兼容 \LaTeXe{} 2015。}
+% \changes{v3.3.2}{2015/05/15}{\tn{xe@alloc@intercharclass} 总是有定义的。}
+% \LaTeXe{} 2015/01/01 接管了 \tn{newXeTeXintercharclass}。
+% \begin{macrocode}
+\cs_new_eq:NN \g_@@_xetex_allocator_int \xe@alloc@intercharclass
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_set_others_toks:n}
+% 简单处理与同样使用 \tn{XeTeXinterchartoks} 机制的宏包的兼容问题。
+% \begin{macrocode}
+\@@_after_end_preamble:n
+ {
+ \int_compare:nNnF
+ { \c_@@_class_begin_int + \seq_count:N \g_@@_new_class_seq } =
+ { \g_@@_xetex_allocator_int }
+ {
+ \int_step_inline:nnn
+ { \c_@@_class_begin_int + 1 }
+ { \g_@@_xetex_allocator_int }
+ {
+ \seq_if_in:NnF \g_@@_new_class_seq {#1}
+ { \@@_set_others_toks:n {#1} }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_set_others_toks:n #1
+ {
+ \int_set:cn { \@@_class_csname:n { Others } } {#1}
+ \seq_map_inline:Nn \g_@@_CJK_class_seq
+ {
+ \xeCJK_copy_inter_class_toks:nnnn {##1} { Others } {##1} { NormalSpace }
+ \xeCJK_copy_inter_class_toks:nnnn { Others } {##1} { NormalSpace } {##1}
+ \xeCJK_app_inter_class_toks:nnx {##1} { Others }
+ { \xeCJK_get_inter_class_toks:nn { Default } { Others } }
+ \xeCJK_pre_inter_class_toks:nnx { Others } {##1}
+ { \xeCJK_get_inter_class_toks:nn { Others } { Default } }
+ \xeCJK_if_blank_x:nT
+ { \xeCJK_get_inter_class_toks:nn { Others } { Boundary } }
+ {
+ \xeCJK_copy_inter_class_toks:nnnn
+ { Others } { Boundary } { Default } { Boundary }
+ }
+ \xeCJK_if_blank_x:nT
+ { \xeCJK_get_inter_class_toks:nn { Boundary } { Others } }
+ {
+ \xeCJK_copy_inter_class_toks:nnnn
+ { Boundary } { Others } { Boundary } { Default }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_inactive_group_begin:,\@@_inactive_group_end:}
+% 用于保护下面歧义宽度标点的分组。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_inactive_group_begin:
+ { \group_begin: \makexeCJKinactive }
+\cs_new_eq:NN \@@_inactive_group_end: \group_end:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_patch_text_command:}
+% \begin{variable}{\c_@@_ambiguous_char_prop}
+% 单独处理宽度有分歧的几个标点:包括省略号、破折号、间隔号、引号等中西文混用的
+% 符号, 保证其命令形式输出的是西文字体。
+% 如果 \pkg{xunicode} 宏包被载入,则通过 \pkg{xunicode-addon} 处理。
+% \begin{macrocode}
+\prop_const_from_keyval:Nn \c_@@_ambiguous_char_prop
+ {
+ "00B7 = \textperiodcentered \textcentereddot \textcdot ,
+ "2013 = \textendash ,
+ "2014 = \textemdash ,
+ "2018 = \textquoteleft \textgrq ,
+ "2019 = \textquoteright ,
+ "201C = \textquotedblleft \textgrqq ,
+ "201D = \textquotedblright ,
+ "2025 = \texthdotfor ,
+ "2026 = \textellipsis ,
+ "2027 = \texthyphenationpoint ,
+ "2E3A = \texttwoemdash
+ }
+\@@_at_end_preamble:n { \@@_patch_text_command: }
+\cs_new_protected_nopar:Npn \@@_patch_text_command:
+ {
+ \xeCJK_if_package_loaded:nTF { xunicode }
+ { \@@_patch_xunicode_ambiguous_char: }
+ {
+ \exp_args:Nx \@@_patch_tuenc_ambiguous_char:n
+ { \UnicodeEncodingName }
+ \@@_patch_tuenc_accent:
+ \@@_patch_tuenc_composite:
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_patch_xunicode_ambiguous_char:
+ {
+ \RequirePackage { xunicode-addon }
+ \prop_map_inline:Nn \c_@@_ambiguous_char_prop
+ {
+ \tl_map_inline:nn { ##2 }
+ {
+ \xunadd_set_begin_hook:nn { ####1 }
+ { \@@_inactive_group_begin: }
+ \xunadd_set_end_hook:nn { ####1 }
+ { \@@_inactive_group_end: }
+ }
+ }
+ \xunadd_append_begin_hook:n { \xeCJK_make_boundary: }
+ }
+\cs_new_protected_nopar:Npn \@@_patch_tuenc_ambiguous_char:n #1
+ {
+ \prop_map_inline:Nn \c_@@_ambiguous_char_prop
+ {
+ \tl_map_inline:nn { ##2 }
+ {
+ \cs_if_exist:NF ####1
+ { \DeclareTextSymbol ####1 {#1} { ##1 } }
+ \@@_patch_ambiguous_char:nN {#1} ####1
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_patch_ambiguous_char:nN #1#2
+ {
+ \exp_args:Nx \@@_patch_ambiguous_char:nn
+ { #1 \token_to_str:N #2 }
+ { #1 - #2 }
+ }
+\cs_new_protected_nopar:Npx \@@_patch_ambiguous_char:nNn #1#2#3
+ {
+ \exp_args:Nx \exp_not:N \@@_patch_ambiguous_char:nn
+ {
+ \c_backslash_str #1
+ \exp_not:N \token_to_str:N #2 -
+ \exp_not:N \token_to_str:N #3
+ }
+ { #1 - #2#3 }
+ }
+\cs_new_protected_nopar:Npn \@@_patch_ambiguous_char:nn #1#2
+ {
+ \cs_if_free:cF {#1}
+ { \exp_args:Nc \@@_patch_ambiguous_char:Nn {#1} {#2} }
+ }
+\cs_new_protected_nopar:Npn \@@_patch_ambiguous_char:Nn #1#2
+ {
+ \token_if_chardef:NTF #1
+ {
+ \prop_gput:Nnx \c_@@_ambiguous_slot_prop {#2}
+ { \int_eval:n {#1} }
+ \cs_set_protected_nopar:Npx #1
+ { \@@_ambiguous_char:n { \tex_Uchar:D #1 } }
+ }
+ {
+ \prop_gput:Nnx \c_@@_ambiguous_slot_prop {#2}
+ { \int_eval:n { \exp_after:wN ` #1 } }
+ \cs_set_protected_nopar:Npx #1
+ { \@@_ambiguous_char:n { \exp_not:o {#1} } }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_ambiguous_char:n #1
+ {
+ \int_compare:nNnTF \tex_XeTeXinterchartokenstate:D > \c_zero_int
+ { \@@_inactive_group_begin: #1 \@@_inactive_group_end: }
+ {#1}
+ }
+\prop_new:N \c_@@_ambiguous_slot_prop
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{macro}{\@@_patch_tuenc_composite:}
+% \changes{v3.7.2}{2018/05/02}{修复补丁错误。}
+% \tn{DeclareUnicodeComposite} 具有检查字符是否存在的功能,
+% 当符号命令紧跟在 CJK 字符类后面时,需要使字体回到西文状态
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_text_composite_patch:
+ {
+ \str_if_eq:eeT { \f@encoding } { \UnicodeEncodingName }
+ { \xeCJK_make_boundary: }
+ }
+% \end{macrocode}
+% 注意 \cs{xeCJK_text_composite_patch:} 可能会结束分组,从而导致 |##1| 没有定义时是
+% \tn{undefined} 而不是 \tn{relax},所以不能将它与 \tn{relax} 作比较。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_patch_tuenc_composite:
+ {
+ \cs_set_nopar:Npn \@text@composite@x
+ {
+ \xeCJK_text_composite_patch:
+ \cs_if_exist_use:NF
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_patch_tuenc_accent:}
+% \tn{add@unicode@accent} 定义最后用于截断数字展开的 \tn{relax} 会造成边界,可能会影响组合标记。
+% \begin{macrocode}
+\group_begin:
+\char_set_catcode_other:n { "A0 }
+\cs_new_protected_nopar:Npn \@@_patch_tuenc_accent:
+ {
+ \cs_set_protected_nopar:Npn \add@unicode@accent ##1 ##2
+ {
+ \tl_if_blank:nTF { ##2 } { ^^a0 } { ##2 }
+ \tex_Uchar:D \tex_numexpr:D ##1 \scan_stop:
+ }
+ }
+\group_end:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_patch_middle_dot:}
+% \begin{variable}{\c_@@_middle_dot_prop}
+% \changes{v3.2.9}{2013/12/08}
+% {完整处理 \file{encguide.pdf} 的编码符号表中,与旧编码的 \texttt{U+00B7} 冲突。}
+% 常被用作中文间隔号的 \texttt{U+00B7} 与 T1 等旧字体编码下定义的符号命令冲突。
+% 在 \file{encguide.pdf} 的编码符号表中,如下定义有冲突。
+% \begin{verbatim}
+% \DeclareTextComposite{\r}{T1}{u}{183}
+% \DeclareTextSymbol{\cyrchvcrs}{T2A}{183}
+% \DeclareTextSymbol{\cyrchldsc}{T2B}{183}
+% \DeclareTextSymbol{\cyrabhha}{T2C}{183}
+% \DeclareTextSymbol\textvibyy{T3}{183}
+% \DeclareTextComposite{\B}{T4}{t}{183}
+% \DeclareTextComposite{\`}{T5}{\ecircumflex}{183}
+% \DeclareTextDoubleComposite{\`}{T5}{\^}{e}{183}
+% \DeclareTextSymbol{\textperiodcentered}{TS1}{183}
+% \DeclareTextSymbol{\cyrchldsc}{X2}{183}
+% \DeclareTextSymbol{\textperiodcentered}{LY1}{183}
+% \end{verbatim}
+% LGR 编码的符号表有 \texttt{183} 号字符,但在 \file{lgrenc.def} 中未找到相应的
+% 符号命令。
+% \begin{macrocode}
+\prop_const_from_keyval:Nn \c_@@_middle_dot_prop
+ {
+ T2A = \cyrchvcrs ,
+ T2B = \cyrchldsc ,
+ T2C = \cyrabhha ,
+ X2 = \cyrchldsc ,
+ TS1 = \textperiodcentered ,
+ LY1 = \textperiodcentered ,
+ T1 = \r u ,
+ T4 = \B t ,
+ T5 = \` \ecircumflex
+ }
+\@@_at_end_preamble:n { \@@_patch_middle_dot: }
+\cs_new_protected_nopar:Npn \@@_patch_middle_dot:
+ {
+ \prop_map_inline:Nn \c_@@_middle_dot_prop
+ { \@@_patch_middle_dot:nw { ##1 } ##2 \q_stop }
+ \@@_patch_ambiguous_char:nNn { T5 } \` { \^ - e }
+ }
+\cs_new_protected_nopar:Npn \@@_patch_middle_dot:nw #1#2#3 \q_stop
+ {
+ \tl_if_empty:nTF {#3}
+ { \@@_patch_ambiguous_char:nN {#1} #2 }
+ { \@@_patch_ambiguous_char:nNn {#1} #2 {#3} }
+ }
+% \end{macrocode}
+% \pkg{pifont} 宏包的符号 |\ding{183}| 也有冲突。
+% \begin{macrocode}
+\@@_after_end_preamble:n
+ {
+ \xeCJK_if_package_loaded:nT { pifont }
+ {
+ \RenewDocumentCommand \Pifont { m }
+ { \makexeCJKinactive \usefont { U } {#1} { m } { n } }
+ }
+ }
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{macro}{\@@_patch_microtype_get_slot:}
+% 兼容 \pkg{microtype}。
+% \begin{macrocode}
+\@@_at_end_preamble:n
+ {
+ \cs_if_free:NF \MT@get@slot@
+ { \@@_patch_microtype_get_slot: }
+ }
+\cs_new_protected_nopar:Npn \@@_patch_microtype_get_slot:
+ {
+ \cs_new_eq:NN \xeCJK@original@get@slot \MT@get@slot@
+ \cs_set_eq:NN \MT@get@slot@ \xeCJK@microtype@get@slot
+ \cs_set_eq:NN \MT@warn@unknown@once \use_none:n
+ }
+\cs_new_protected_nopar:Npn \xeCJK@microtype@get@slot
+ {
+ \int_compare:nNnT \MT@char < \c_zero_int
+ { \@@_get_ambiguous_slot: }
+ \xeCJK@original@get@slot
+ }
+\cs_new_protected_nopar:Npn \@@_get_ambiguous_slot:
+ {
+ \exp_args:NNx \prop_get:NnNT \c_@@_ambiguous_slot_prop
+ { \MT@encoding - \tex_the:D \MT@toks } \l_@@_tmp_tl
+ { \cs_set_eq:NN \MT@char \l_@@_tmp_tl }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% 简单处理与 \pkg{hyperref} 宏包的兼容问题。
+% \begin{macrocode}
+\@@_after_end_preamble:n
+ {
+ \cs_if_exist_use:NT \pdfstringdefDisableCommands
+ {
+ {
+ \@@_gobble_CJKfamily:
+ \xeCJK_cs_clear:N \@@_inactive_group_begin:
+ \xeCJK_cs_clear:N \@@_inactive_group_end:
+ \xeCJK_cs_clear:N \makexeCJKinactive
+ \xeCJK_cs_clear:N \xeCJK@composite@patch
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \changes{v3.1.0}{2012/11/13}{取消 \tn{cprotect} 的外部宏限制。}
+% 当探测到 \pkg{cprotect} 宏包被引入时,则取消 \tn{cprotect} 宏的 \tn{outer} 定义。
+% \begin{macrocode}
+\@@_after_end_preamble:n
+ {
+ \bool_lazy_and:nnT
+ { \xeCJK_if_package_loaded_p:n { cprotect } }
+ { \cs_if_exist_p:N \icprotect }
+ { \exp_after:wN \tex_let:D \cs:w cprotect \cs_end: \icprotect }
+ }
+% \end{macrocode}
+%
+% \changes{v3.2.11}{2014/03/14}{删除 \tn{xeCJKcaption}。}
+%
+% 由于 \pkg{xeCJK} 禁止 \pkg{CJKulem} 的载入,因此当使用 \pkg{ctex} 宏包的 |fntef|
+% 选项时,就会出现 \tn{normalem} 没有定义的问题。此时改用 \pkg{xeCJKfntef} 以便
+% 载入 \pkg{ulem}。
+%
+% 判断过于繁琐,应该在 \pkg{ctex} 包中妥善处理。这段代码应在 \pkg{ctex} 包发布
+% 新版本后删去。
+% \begin{macrocode}
+\cs_if_eq:NNTF \ifCTEX@fntef \tex_iftrue:D
+ { \AtEndOfPackage { \RequirePackage { xeCJKfntef } } }
+ {
+ \@@_at_end_preamble:n
+ {
+ \xeCJK_if_package_loaded:nF { xeCJKfntef }
+ {
+ \xeCJK_if_package_loaded:nTF { CJKfntef }
+ { \RequirePackage { xeCJKfntef } }
+ {
+ \xeCJK_if_package_loaded:nT { ulem }
+ { \RequirePackage { xeCJKfntef } }
+ }
+ }
+ }
+ }
+% \end{macrocode}
+%
+% 导言区末尾检测到 \pkg{listings} 时,自动载入 \pkg{xeCJK-listings}。
+% \begin{macrocode}
+\@@_at_end_preamble:n
+ {
+ \xeCJK_if_package_loaded:nT { listings }
+ { \RequirePackage { xeCJK-listings } }
+ }
+% \end{macrocode}
+%
+%
+% \changes{v3.3.3}{2015/12/12}{解决与 \pkg{microtype} 宏包的兼容问题。}
+% 由于 \pkg{xeCJK} 假装 \pkg{CJK} 已经被引入了,这回导致 \pkg{everysel} 和
+% \pkg{microtype} 等宏包判断错误。需要在它们判断之前取消定义。
+% \begin{macrocode}
+\@@_at_end_preamble:n
+ {
+ \clist_map_inline:nn { everysel , microtype }
+ {
+ \xeCJK_if_package_loaded:nT {#1}
+ {
+ \cs_undefine:c { ver@CJK . \c_@@_package_ext_tl }
+ \clist_map_break:
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \changes{v3.2.4}{2013/06/25}{不再使用 \texttt{CJKnumber} 选项,可以在
+% \pkg{xeCJK} 之后直接使用 \pkg{CJKnumb} 宏包得到中文数字。}
+%
+% \begin{macro}[int]{\CJKaddEncHook}
+% 为使用 \pkg{CJKnumb} 宏包而作一些处理。另外 \pkg{CJKnumb} 使用的是传统汉字“萬”
+% 和“億”,我们在这里把它们修正为简体字。
+% \changes{v3.2.10}{2014/03/01}{使用 \pkg{CJKnumb} 时,让 \tn{Unicode} 有定义。}
+% \changes{v3.3.1}{2015/05/08}{应用 \texttt{0.99992} 版的新原语 \tn{Ucharcat}。}
+% \begin{macrocode}
+\cs_new_protected:Npn \CJKaddEncHook #1#2
+ {
+ \str_if_eq:nnT {#1} { \CJK@UnicodeEnc }
+ {
+ \group_begin:
+ \cs_set_eq:NN \Unicode \xeCJK_unicode_char:nn
+ \cs_set_eq:NN \def \xdef
+ #2
+ \group_end:
+ \str_gset:Nn \CJK@tenthousand { ^^^^4e07 }
+ \str_gset:Nn \CJK@hundredmillion { ^^^^4ebf }
+ \tl_if_exist:NF \CJK@UnicodeEnc
+ { \tl_const:Nn \CJK@UnicodeEnc { UTF8 } }
+ \cs_if_exist:NF \Unicode
+ { \cs_new_eq:NN \Unicode \xeCJK_unicode_char:nn }
+ }
+ }
+\cs_new_nopar:Npn \xeCJK_unicode_char:nn #1#2
+ { \tex_Uchar:D \tex_numexpr:D (#1) * 256 + (#2) \scan_stop: }
+% \end{macrocode}
+% \end{macro}
+%
+% 最后引入本地配置文件。
+% \begin{macrocode}
+\bool_if:NT \g_@@_config_bool
+ {
+ \ExplSyntaxOff
+ \file_input:n { \g_@@_config_name_tl .cfg }
+ \ExplSyntaxOn
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJKfntef}}
+%
+% \changes{v3.1.1}{2012/12/08}{增加小宏包 \pkg{xeCJKfntef},用于处理下划线的问题。}
+% \changes{v3.2.4}{2013/06/23}{修正 \pkg{xeCJKfntef} 与 \pkg{natbib} 等的冲突。}
+% \changes{v3.2.14}{2014/10/31}{完善 \tn{varCJKunderline} 的实现。}
+% \changes{v3.2.14}{2014/10/31}{解决下划线前后没有 \tn{CJKglue} 或 \tn{CJKecglue} 的问题。}
+% \changes{v3.2.14}{2014/11/03}{\pkg{xeCJKfntef} 不再依赖 \pkg{CJKfntef}。}
+% \changes{v3.2.15}{2014/11/07}{\pkg{xeCJKfntef} 增加 \texttt{hidden} 选项。}
+%
+% \begin{macrocode}
+%<*fntef>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\PassOptionsToPackage { normalem } { ulem }
+\DeclareOption* { \PassOptionsToPackage { \CurrentOption } { ulem } }
+\ProcessOptions \scan_stop:
+% \end{macrocode}
+%
+% \begin{macrocode}
+\RequirePackage { xeCJK }
+\RequirePackage { ulem }
+% \end{macrocode}
+%
+% 虽然我们不再依赖 \pkg{CJKfntef},但基于历史原因,我们仍然载入它。
+% \begin{macrocode}
+\file_if_exist:nT { CJKfntef.sty }
+ { \RequirePackage { CJKfntef } }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\addto@hook \UL@hook { \xeCJK_hook_for_ulem: }
+% \end{macrocode}
+%
+% \changes{v3.4.1}{2016/06/03}{新的下划线选项 \texttt{textformat}。}
+%
+% \begin{macro}[int]{\xeCJK_hook_for_ulem:}
+% \changes{v3.1.0}{2012/11/16}{简化对 \pkg{ulem} 宏包的兼容补丁。}
+% \changes{v3.1.1}{2012/12/08}{完全处理下划线里的标点符号的有关问题。}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_hook_for_ulem:
+ {
+ \xeCJK_ulem_detect_node:
+ \l_@@_ulem_text_format_tl
+ \bool_if:NF \l_@@_ulem_hook_used_bool
+ {
+ \bool_set_true:N \l_@@_ulem_hook_used_bool
+ \@@_ulem_hook:
+ }
+ \xeCJK_ulem_begin_node:
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_hook:
+ {
+ \@@_ulem_initial:
+ \bool_if:NT \l_@@_ulem_subtract_bool
+ {
+ \xeCJK_swap_cs:NN \UL@leaders \xeCJK_ulem_leaders:
+ \cs_set_eq:NN \@@_ulem_var_leaders: \xeCJK_ulem_var_leaders:
+ \cs_set_eq:NN \xeCJK_ulem_right_skip: \@@_ulem_right_skip:
+ }
+ \bool_if:NT \l_@@_ulem_hidden_bool
+ { \cs_set_eq:NN \UL@putbox \@@_ulem_hidden_box: }
+ \bool_if:NTF \l_@@_ulem_skip_bool
+ {
+ \cs_set_eq:NN \@@_ulem_putbox: \UL@putbox
+ \cs_set_eq:NN \@@_ulem_hskip_aux:n \xeCJK_ulem_hskip:n
+ }
+ {
+ \xeCJK_swap_cs:NN \@@_punct_hskip:n \@@_ulem_punct_hskip:n
+ \xeCJK_cs_clear:N \@@_ulem_skip_punct_begin:
+ \xeCJK_cs_clear:N \@@_ulem_skip_punct_end:
+ }
+ \xeCJK_glue_to_skip:nN
+ {
+ \cs_set_eq:NN \ \tex_space:D
+ \cs_set_eq:NN \penalty \tex_penalty:D
+ \cs_set_eq:NN \hskip \skip_horizontal:N
+ \CJKglue
+ } \l_@@_ccglue_skip
+ \xeCJK_glue_to_skip:nN
+ {
+ \cs_set_eq:NN \ \tex_space:D
+ \cs_set_eq:NN \penalty \tex_penalty:D
+ \cs_set_eq:NN \hskip \skip_horizontal:N
+ \CJKecglue
+ } \l_@@_ecglue_skip
+ \xeCJK_glue_to_skip:nN { \xeCJK_space_glue: } \l_@@_space_skip
+ \cs_set_protected_nopar:Npn \CJKglue
+ { \@@_ulem_glue:n \l_@@_ccglue_skip }
+ \cs_set_protected_nopar:Npn \CJKecglue
+ { \@@_ulem_glue:n \l_@@_ecglue_skip }
+ \cs_set_protected_nopar:Npn \xeCJK_space_glue:
+ { \@@_ulem_glue:n \l_@@_space_skip }
+ \cs_set_eq:NN \xeCJK_punct_node:N \use_none:n
+ \cs_set_eq:NN \xeCJK_if_last_punct:TF \use_ii:nn
+ \keys_set:nn { xeCJK / options }
+ { CheckFullRight = false , xCJKecglue = false }
+ }
+\skip_new:N \l_@@_space_skip
+\bool_new:N \l_@@_ulem_hook_used_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\UL@word,\xeCJK_ulem_word:nw}
+% 修改 \tn{UL@word},目的是取得分组中的 \tn{UL@leadtype},以便加入 \cs{xeCJK_ulem_right_skip:}。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_ulem_word:nw #1 ~
+ {
+ \exp_after:wN \UL@start #1 ~
+ \exp_after:wN \if_meaning:w \exp_after:wN \UL@end #1
+ \exp_after:wN \@@_ulem_end:
+ \else:
+ \exp_after:wN \@@_ulem_loop:nw
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_end:
+ {
+ \c_group_end_token
+ \c_group_end_token
+ \tex_unskip:D \tex_unskip:D \tex_unskip:D
+ \xeCJK_ulem_right_skip:
+ \xeCJK_ulem_group_end:
+ \xeCJK_ulem_right_node:
+ \int_set:Nn \tex_spacefactor:D { \UL@spfactor }
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_loop:nw
+ {
+ \reverse_if:N \if_mode_math:
+ \reverse_if:N \if_dim:w \tex_lastskip:D = \c_zero_dim
+ \skip_gset_eq:NN \UL@skip \tex_lastskip:D
+ \tex_unskip:D
+ \UL@stop \UL@leaders
+ \fi:
+ \fi:
+ \xeCJK_ulem_word:nw \prg_do_nothing:
+ }
+\cs_set_eq:NN \UL@word \xeCJK_ulem_word:nw
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_ulem_left:, \xeCJK_ulem_detect_node:}
+% 在下划线开始之前探测之前的 \texttt{node},以便随后插入 \tn{CJKglue} 或 \tn{CJKecglue}。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_ulem_left:
+ {
+ \xeCJK_ulem_left_node:
+ \xeCJK_make_group_tag:
+ }
+\cs_new_eq:NN \xeCJK_ulem_left_node: \prg_do_nothing:
+\cs_new_protected_nopar:Npn \xeCJK_ulem_detect_node:
+ {
+ \scan_stop:
+ \dim_compare:nNnTF \tex_lastkern:D = \c_zero_dim
+ {
+ \xeCJK_cs_clear:N \xeCJK_ulem_left_node:
+ \xeCJK_cs_clear:N \xeCJK_ulem_begin_node:
+ \cs_set_eq:NN \@@_ulem_hskip:n \xeCJK_ulem_hskip:n
+ }
+ {
+ \dim_set_eq:NN \l_@@_tmp_dim \tex_lastkern:D
+ \tex_unkern:D
+ \dim_compare:nNnTF \tex_lastkern:D = { - \l_@@_tmp_dim }
+ {
+ \tex_unkern:D
+ \cs_set_protected_nopar:Npx \xeCJK_ulem_left_node:
+ {
+ \tex_kern:D - \dim_use:N \l_@@_tmp_dim \exp_stop_f:
+ \tex_kern:D \dim_use:N \l_@@_tmp_dim \exp_stop_f:
+ }
+ \cs_set_protected_nopar:Npn \xeCJK_ulem_begin_node:
+ { { \xeCJK_make_node:n { ulem-begin } } }
+ \cs_set_eq:NN \@@_ulem_hskip:n \@@_ulem_hskip_first:n
+ }
+ {
+ \tex_kern:D \l_@@_tmp_dim
+ \xeCJK_cs_clear:N \xeCJK_ulem_left_node:
+ \xeCJK_cs_clear:N \xeCJK_ulem_begin_node:
+ \cs_set_eq:NN \@@_ulem_hskip:n \xeCJK_ulem_hskip:n
+ }
+ }
+ }
+\xeCJK_declare_node:n { ulem-begin }
+\cs_new_eq:NN \xeCJK_ulem_begin_node: \prg_do_nothing:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_hskip_first:n, \xeCJK_ulem_hskip:n}
+% 如果第一次调用的 \tn{CJKglue} 或 \tn{CJKecglue} 由下划线中的第一个文字和之前的
+% 内容产生,就不用画下划线。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_hskip_first:n #1
+ {
+ \xeCJK_if_last_node:nTF { ulem-begin }
+ {
+ \xeCJK_remove_node:
+ \skip_horizontal:n {#1}
+ }
+ { \xeCJK_ulem_hskip:n {#1} }
+ \cs_set_eq:NN \@@_ulem_hskip:n \xeCJK_ulem_hskip:n
+ }
+\cs_new_eq:NN \@@_ulem_hskip:n \@@_ulem_hskip_first:n
+\cs_new_protected_nopar:Npn \xeCJK_ulem_hskip:n #1
+ { { \skip_set:Nn \UL@skip {#1} \UL@leaders } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_ulem_right:, \xeCJK_ulem_right_node:}
+% 在下划线最后的位置保存 \texttt{node}。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_ulem_right:
+ {
+ \scan_stop:
+ \dim_compare:nNnTF \tex_lastkern:D = \c_zero_dim
+ { \xeCJK_cs_gclear:N \xeCJK_ulem_right_node: }
+ {
+ \dim_compare:nNnTF \tex_lastkern:D = { 3sp }
+ { \xeCJK_cs_gclear:N \xeCJK_ulem_right_node: }
+ {
+ \exp_args:NNo \tex_unkern:D
+ \@@_ulem_right_aux:n { \dim_use:N \tex_lastkern:D }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_right_aux:n #1
+ {
+ \dim_compare:nNnTF \tex_lastkern:D = { - #1 }
+ {
+ \tex_unkern:D
+ \cs_gset_protected_nopar:Npn \xeCJK_ulem_right_node:
+ {
+ \tex_kern:D - #1 \exp_stop_f:
+ \tex_kern:D #1 \exp_stop_f:
+ }
+ \tl_gset:Nx \UL@spfactor { \int_use:N \tex_spacefactor:D }
+ }
+ {
+ \tex_kern:D #1 \exp_stop_f:
+ \xeCJK_cs_gclear:N \xeCJK_ulem_right_node:
+ }
+ }
+\cs_new_eq:NN \xeCJK_ulem_right_node: \prg_do_nothing:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_ulem_var_leaders:}
+% 第一次画下划线时,不需要向左平移 \tn{UL@pixel},让左侧有间距。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_ulem_leaders:
+ { \@@_ulem_var_leaders: }
+\cs_new_protected_nopar:Npn \xeCJK_ulem_var_leaders:
+ {
+ \scan_stop:
+ \skip_if_eq:nnF { \UL@skip } { \c_zero_skip }
+ {
+ \UL@leadtype \skip_horizontal:n { \UL@skip + \UL@pixel }
+ \skip_horizontal:n { - \UL@pixel }
+ \cs_gset_eq:NN \@@_ulem_var_leaders: \xeCJK_ulem_leaders:
+ }
+ }
+\cs_new_eq:NN \@@_ulem_var_leaders: \xeCJK_ulem_var_leaders:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_ulem_right_skip:}
+% 在下划线完全画好之后,我们检测最后的情况。用 \tn{unskip} 去掉最后一个下划线,再
+% 重新画一个减少 \tn{UL@pixel} 的。
+% \begin{macrocode}
+\cs_new_eq:NN \xeCJK_ulem_right_skip: \prg_do_nothing:
+\cs_new_protected_nopar:Npn \@@_ulem_right_skip:
+ {
+ \int_case:nn { \tex_lastnodetype:D }
+ {
+ { 1 } { \@@_ulem_right_skip_hbox: }
+ { 11 } { \@@_ulem_right_skip_glue: }
+ { 13 } { \@@_ulem_right_skip_penalty: }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_right_skip_hbox:
+ {
+ \box_set_to_last:N \l_@@_tmp_box
+ \int_compare:nNnTF \tex_lastnodetype:D = { 12 }
+ { \@@_ulem_right_skip_kern: }
+ { \@@_ulem_right_skip_glue: }
+ \box_use_drop:N \l_@@_tmp_box
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_right_skip_kern:
+ {
+ \dim_set:Nn \l_@@_tmp_dim { - \box_wd:N \l_@@_tmp_box }
+ \dim_compare:nNnT \tex_lastkern:D = \l_@@_tmp_dim
+ {
+ \tex_unkern:D
+ \@@_ulem_right_skip_glue:
+ \tex_kern:D \l_@@_tmp_dim
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_right_skip_glue:
+ {
+ \skip_if_eq:nnT { \tex_lastskip:D } { - \UL@pixel }
+ {
+ \tex_unskip:D
+ \skip_set:Nn \l_@@_tmp_skip { \tex_lastskip:D - \UL@pixel }
+ \tex_unskip:D
+ \UL@leadtype \skip_horizontal:N \l_@@_tmp_skip
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_right_skip_penalty:
+ {
+ \int_set_eq:NN \l_@@_tmp_int \tex_lastpenalty:D
+ \tex_unpenalty:D
+ \int_compare:nNnT \tex_lastnodetype:D = \c_one_int
+ { \@@_ulem_right_skip_hbox: }
+ \tex_penalty:D \l_@@_tmp_int
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_hidden_box:}
+% 只画线,不输出盒子。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_hidden_box:
+ {
+ \tl_if_empty:NF \UL@start
+ {
+ \box_use:N \c_@@_null_box
+ \xeCJK_no_break:
+ \xeCJK_ulem_hskip:n { \box_wd:N \UL@box }
+ \box_use:N \c_@@_null_box
+ }
+ }
+\box_new:N \c_@@_null_box
+\hbox_gset:Nn \c_@@_null_box { }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_skip_punct_begin:,\@@_ulem_skip_punct_end:}
+% 让下划线跳过标点符号的设置。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_skip_punct_begin:
+ {
+ \cs_set_eq:NN \UL@putbox \@@_ulem_skip_putbox:
+ \cs_set_eq:NN \xeCJK_ulem_hskip:n \skip_horizontal:n
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_skip_punct_end:
+ {
+ \cs_set_eq:NN \UL@putbox \@@_ulem_putbox:
+ \cs_set_eq:NN \xeCJK_ulem_hskip:n \@@_ulem_hskip_aux:n
+ }
+\cs_new_eq:NN \@@_ulem_putbox: \UL@putbox
+\cs_new_protected_nopar:Npn \@@_ulem_skip_putbox:
+ {
+ \tl_if_empty:NF \UL@start
+ { \box_use_drop:N \UL@box }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_initial:}
+% 这里的设置是为了在下划线状态下,下划线可以自动跳过全角标点符号和正确的在它们
+% 前/后断行,并且与行首行末对齐。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_initial:
+ {
+ \@@_ulem_swap_cs:NN
+ \xeCJK_FullLeft_and_Default: \@@_ulem_FullLeft_and_Default:
+ \xeCJK_FullLeft_and_CJK: \@@_ulem_FullLeft_and_CJK:
+ \xeCJK_FullLeft_and_Boundary: \@@_ulem_FullLeft_and_Boundary:
+ \xeCJK_FullRight_and_Default: \@@_ulem_FullRight_and_Default:
+ \xeCJK_FullRight_and_CJK: \@@_ulem_FullRight_and_CJK:
+ \xeCJK_FullRight_and_Boundary: \@@_ulem_FullRight_and_Boundary:
+ \xeCJK_CJK_and_CJK:N \@@_ulem_CJK_and_CJK:N
+ \xeCJK_CJK_and_Boundary:w \@@_ulem_CJK_and_Boundary:w
+ \xeCJK@fix@penalty \@@_ulem_fix_penalty:
+ \@@_punct_breakable_kern:n \@@_ulem_punct_breakable_kern:n
+ \@@_Default_and_FullLeft_glue:N \@@_ulem_Default_and_FullLeft_glue:N
+ \@@_Default_and_FullRight_glue:N \@@_ulem_Default_and_FullRight_glue:N
+ \@@_CJK_and_FullLeft_glue:N \@@_ulem_CJK_and_FullLeft_glue:N
+ \@@_CJK_and_FullRight_glue:N \@@_ulem_CJK_and_FullRight_glue:N
+ \@@_Boundary_and_FullLeft_glue:N \@@_ulem_Boundary_and_FullLeft_glue:N
+ \q_recursion_tail \q_nil \q_recursion_stop
+ \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
+ {
+ \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
+ {
+ \str_if_eq:nnTF {##1} {####1}
+ {
+ \xeCJK_inter_class_toks:nnn { CJK } { CJK/##1 }
+ { \@@_ulem_between_CJK_blocks:nnN { CJK } {##1} }
+ \xeCJK_inter_class_toks:nnn { CJK/##1 } { CJK/##1 }
+ { \@@_ulem_between_CJK_blocks:nnN { CJK } {##1} }
+ }
+ {
+ \xeCJK_inter_class_toks:nnn { CJK/##1 } { CJK/####1 }
+ { \@@_ulem_between_CJK_blocks:nnN {##1} {####1} }
+ }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_swap_cs:NN #1#2
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \xeCJK_swap_cs:NN #1#2
+ \@@_ulem_swap_cs:NN
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.1.2}{2012/12/27}{解决在下划线状态下使用 \tn{makebox} 时的错误。}
+%
+% \begin{macro}[int]{\xeCJK_if_ulem_patch:TF}
+% 在下划线状态下,\pkg{ulem} 宏包在数学模式或者盒子中使用 \tn{UL@hrest} 恢复
+% \verb*|\ | 等的定义,此时不需要使用 \tn{UL@stop} 和 \tn{UL@start} 来断开下划线而
+% 产生断点。
+% \begin{macrocode}
+\cs_new_nopar:Npn \xeCJK_if_ulem_patch:TF
+ {
+ \if_meaning:w \ \LA@space
+ \exp_after:wN \use_ii:nn
+ \else:
+ \exp_after:wN \use_i:nn
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_CJK_and_Boundary:w}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_CJK_and_Boundary:w
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
+ {
+ \xeCJK_class_group_end: \UL@stop
+ \CJKecglue
+ \UL@start
+ }
+ {
+ \bool_if:NTF \l_@@_peek_ignore_spaces_bool
+ {
+ \xeCJK_class_group_end: \UL@stop
+ \UL@start { \xeCJK_make_node:n { CJK-space } }
+ }
+ {
+ \xeCJK_class_group_end: \UL@stop
+ \UL@start { \xeCJK_make_node:n { CJK } }
+ }
+ \xeCJK_make_group_tag:
+ }
+ }
+ { \@@_ulem_CJK_and_Boundary:w }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_fix_penalty:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_fix_penalty:
+ {
+ \xeCJK_if_ulem_patch:TF
+ { \fix@penalty }
+ { \@@_ulem_fix_penalty: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_CJK_and_CJK:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_CJK_and_CJK:N
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \xeCJK_class_group_end:
+ \UL@stop \@@_ulem_ccglue: \UL@start
+ \@@_ulem_class_group_begin:
+ \xeCJK_select_font:
+ \CJKsymbol
+ }
+ { \@@_ulem_CJK_and_CJK:N }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_class_group_begin:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_class_group_begin:
+ {
+ \xeCJK_class_group_begin:
+ \xeCJK_clear_Boundary_and_CJK_toks:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_between_CJK_blocks:nnN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_between_CJK_blocks:nnN #1#2
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \xeCJK_class_group_end:
+ \UL@stop \@@_ulem_ccglue: \UL@start
+ \xeCJK_class_group_begin:
+ \xeCJK_clear_Boundary_and_CJK_toks:
+ \@@_switch_font:nn {#1} {#2}
+ \CJKsymbol
+ }
+ {
+ \skip_horizontal:N \l_@@_ccglue_skip
+ \@@_switch_font:nn {#1} {#2}
+ \CJKsymbol
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_Default_and_FullLeft_glue:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_Default_and_FullLeft_glue:N #1
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \UL@stop
+ \@@_ulem_skip_punct_begin:
+ \@@_punct_glue:NN \c_@@_left_tl #1
+ \UL@start
+ }
+ { \@@_ulem_Default_and_FullLeft_glue:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_Boundary_and_FullLeft_glue:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_Boundary_and_FullLeft_glue:N #1
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \UL@stop
+ \@@_ulem_skip_punct_begin:
+ \@@_punct_glue:NN \c_@@_left_tl #1
+ \UL@start
+ }
+ { \@@_ulem_Boundary_and_FullLeft_glue:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_CJK_and_FullLeft_glue:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_CJK_and_FullLeft_glue:N #1
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \xeCJK_class_group_end:
+ \UL@stop
+ \@@_ulem_skip_punct_begin:
+ \@@_ulem_punct_ccglue:
+ \@@_punct_glue:NN \c_@@_left_tl #1
+ \UL@start
+ \@@_ulem_class_group_begin:
+ \xeCJK_select_punct_font:
+ }
+ { \@@_ulem_CJK_and_FullLeft_glue:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_Default_and_FullRight_glue:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_Default_and_FullRight_glue:N #1
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \UL@stop
+ \@@_ulem_skip_punct_begin:
+ \@@_punct_if_long:NTF #1
+ { \xeCJK_allow_break: }
+ { \xeCJK_no_break: }
+ \@@_punct_if_middle:NT #1
+ {
+ \@@_punct_glue:NN \c_@@_right_tl #1
+ \@@_punct_bound_rule:NN \c_@@_left_tl #1
+ }
+ \UL@start
+ }
+ { \@@_ulem_Default_and_FullRight_glue:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_CJK_and_FullRight_glue:N}
+% \changes{v3.2.2}{2013/05/30}{修正下划线不能跳过全角右标点的问题。}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_CJK_and_FullRight_glue:N #1
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \xeCJK_class_group_end:
+ \UL@stop
+ \@@_ulem_skip_punct_begin:
+ \@@_punct_if_long:NTF #1
+ { \xeCJK_allow_break: }
+ { \xeCJK_no_break: }
+ \@@_punct_if_middle:NT #1
+ {
+ \@@_ulem_punct_ccglue:
+ \@@_punct_glue:NN \c_@@_right_tl #1
+ \@@_punct_bound_rule:NN \c_@@_left_tl #1
+ }
+ \UL@start
+ \@@_ulem_class_group_begin:
+ \xeCJK_select_punct_font:
+ }
+ { \@@_ulem_CJK_and_FullRight_glue:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_FullLeft_and_Default:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_FullLeft_and_Default:
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \@@_punct_if_middle:NTF \g_@@_last_punct_tl
+ {
+ \xeCJK_get_punct_bounds:No \c_@@_left_tl \g_@@_last_punct_tl
+ \@@_punct_bound_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end: \UL@stop \xeCJK_no_break:
+ \@@_punct_glue:NN \c_@@_left_tl \g_@@_last_punct_tl
+ }
+ { \xeCJK_class_group_end: \UL@stop }
+ \@@_ulem_skip_punct_end:
+ \xeCJK_no_break:
+ \UL@start
+ }
+ { \@@_ulem_FullLeft_and_Default: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_FullLeft_and_Boundary:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_FullLeft_and_Boundary:
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \@@_punct_if_middle:NTF \g_@@_last_punct_tl
+ {
+ \xeCJK_get_punct_bounds:No \c_@@_left_tl \g_@@_last_punct_tl
+ \@@_punct_bound_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end: \UL@stop \xeCJK_no_break:
+ \@@_punct_glue:NN \c_@@_left_tl \g_@@_last_punct_tl
+ }
+ { \xeCJK_class_group_end: \UL@stop }
+ \@@_ulem_skip_punct_end:
+ \xeCJK_no_break:
+ \UL@start
+ \tex_ignorespaces:D
+ }
+ { \@@_ulem_FullLeft_and_Boundary: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_FullLeft_and_CJK:}
+% \changes{v3.2.3}{2013/06/04}
+% {修正全角左标点后下划线与 \tn{CJKunderdot} 连用时结果不正常的问题。}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_FullLeft_and_CJK:
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \xeCJK_FullLeft_and_Default:
+ \@@_ulem_class_group_begin:
+ \xeCJK_select_font:
+ }
+ { \@@_ulem_FullLeft_and_CJK: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_FullRight_and_Default:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_FullRight_and_Default:
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end:
+ \UL@stop
+ \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \@@_ulem_skip_punct_end:
+ \UL@start
+ }
+ { \@@_ulem_FullRight_and_Default: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_FullRight_and_Boundary:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_FullRight_and_Boundary:
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end:
+ \UL@stop
+ \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \@@_ulem_skip_punct_end:
+ \UL@start
+ \tex_ignorespaces:D
+ }
+ { \@@_ulem_FullRight_and_Boundary: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_FullRight_and_CJK:}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_FullRight_and_CJK:
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \xeCJK_class_group_end:
+ \UL@stop
+ \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
+ \@@_ulem_punct_ccglue:
+ \@@_ulem_skip_punct_end:
+ \UL@start
+ \@@_ulem_class_group_begin:
+ \xeCJK_select_font:
+ }
+ { \@@_ulem_FullRight_and_CJK: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_punct_hskip:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_punct_hskip:n
+ {
+ \xeCJK_if_ulem_patch:TF
+ { \xeCJK_ulem_hskip:n }
+ { \@@_ulem_punct_hskip:n }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_punct_breakable_kern:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_punct_breakable_kern:n #1
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \xeCJK_class_group_end:
+ \UL@stop \xeCJK_ulem_hskip:n {#1} \UL@start
+ \@@_ulem_class_group_begin:
+ \xeCJK_select_punct_font:
+ }
+ { \@@_ulem_punct_breakable_kern:n {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ulem_glue:n,\@@_ulem_ccglue:,\@@_ulem_punct_ccglue:}
+% 在下划线状态下的分别代替 \tn{CJKglue} 等。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_ulem_glue:n #1
+ {
+ \xeCJK_if_ulem_patch:TF
+ {
+ \tl_if_empty:NTF \l_@@_group_tag_tl
+ { \UL@stop \@@_ulem_hskip:n {#1} \UL@start }
+ {
+ \str_if_eq:eeTF { \l_@@_group_tag_tl } { \c_@@_group_tag_tl }
+ { \UL@stop \@@_ulem_hskip:n {#1} \UL@start }
+ { \skip_horizontal:n {#1} }
+ }
+ }
+ { \skip_horizontal:n {#1} }
+ }
+\cs_new_protected_nopar:Npn \xeCJK_make_group_tag:
+ { \tl_set:Nx \l_@@_group_tag_tl { \c_@@_group_tag_tl } }
+\tl_new:N \l_@@_group_tag_tl
+\tl_const:Nn \c_@@_group_tag_tl
+ {
+ T \int_use:N \tex_currentgrouptype:D
+ L \int_use:N \tex_currentgrouplevel:D
+ }
+\cs_new_protected_nopar:Npn \@@_ulem_ccglue:
+ { { \skip_set_eq:NN \UL@skip \l_@@_ccglue_skip \UL@leaders } }
+\cs_new_protected_nopar:Npn \@@_ulem_punct_ccglue:
+ { \@@_punct_hskip:n { \l_@@_ccglue_skip } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_ulem_group_begin:,\xeCJK_ulem_group_end:,\xeCJK_ulem_on:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_ulem_group_begin:
+ {
+ \mode_leave_vertical:
+ \c_group_begin_token
+ }
+\cs_new_protected_nopar:Npn \xeCJK_ulem_group_end:
+ { \c_group_end_token }
+\cs_new_protected_nopar:Npn \xeCJK_ulem_on:n
+ { \ULon }
+\cs_new_eq:NN \@@_ulem_on:n \UL@on
+\cs_set_protected:Npn \UL@on #1
+ { \@@_ulem_on:n { \xeCJK_ulem_left: #1 \xeCJK_ulem_right: } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\xeCJKfntefon}
+% \changes{v3.2.15}{2014/11/07}{完善选项。}
+% 扩展 \tn{ULon} 的参数。
+% \begin{macrocode}
+\NewDocumentCommand \xeCJKfntefon { s t- s o }
+ {
+ \mode_leave_vertical:
+ \xeCJK_ulem_boot:NNNn #1#2#3 {#4}
+ \xeCJK_ulem_on:n
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CJKunderline}
+% \begin{macrocode}
+\DeclareDocumentCommand \CJKunderline { s t- s o }
+ {
+ \xeCJK_ulem_group_begin:
+ \xeCJK_fntef_boot:nnNNNn { underline } { uline } #1#2#3 {#4}
+ \xeCJK_fntef_initial:nnn
+ { \l_@@_uline_depth_tl }
+ { \l_@@_uline_sep_tl }
+ {
+ \l_@@_uline_format_tl
+ \tex_vrule:D
+ height \dim_eval:n { \l_@@_uline_thickness_tl }
+ depth \c_zero_dim
+ width .2em
+ }
+ \xeCJK_ulem_on:n
+ }
+\DeclareDocumentCommand \varCJKunderline { }
+ { \CJKunderline - }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CJKunderwave}
+% \begin{macrocode}
+\DeclareDocumentCommand \CJKunderwave { s t- s o }
+ {
+ \xeCJK_ulem_group_begin:
+ \xeCJK_fntef_boot:nnNNNn { underwave } { uwave } #1#2#3 {#4}
+ \xeCJK_fntef_initial:nnn
+ { \l_@@_uwave_depth_tl }
+ { \l_@@_uwave_sep_tl }
+ { \l_@@_uwave_format_tl \l_@@_uwave_symbol_tl }
+ \xeCJK_ulem_on:n
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CJKunderdblline}
+% \begin{macrocode}
+\DeclareDocumentCommand \CJKunderdblline { s t- s o }
+ {
+ \xeCJK_ulem_group_begin:
+ \xeCJK_fntef_boot:nnNNNn { underdblline } { udbline } #1#2#3 {#4}
+ \xeCJK_fntef_initial:nnn
+ { \l_@@_udbline_depth_tl }
+ { \l_@@_udbline_sep_tl }
+ {
+ \l_@@_udbline_format_tl
+ \vbox_top:n
+ {
+ \tex_hrule:D
+ height \dim_eval:n { \l_@@_udbline_thickness_tl }
+ depth \c_zero_dim
+ width .2em
+ \tex_kern:D \dim_eval:n { \l_@@_udbline_gap_tl }
+ \tex_hrule:D
+ height \dim_eval:n { \l_@@_udbline_thickness_tl }
+ depth \c_zero_dim
+ width .2em
+ }
+ }
+ \xeCJK_ulem_on:n
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CJKsout}
+% \begin{macrocode}
+\DeclareDocumentCommand \CJKsout { s t- s o }
+ {
+ \xeCJK_ulem_group_begin:
+ \xeCJK_fntef_boot:nnNNNn { sout } { sout } #1#2#3 {#4}
+ \xeCJK_fntef_initial:nn
+ {
+ \l_@@_sout_format_tl
+ \tex_vrule:D
+ height \dim_eval:n { \l_@@_sout_thickness_tl }
+ depth \c_zero_dim
+ width .2em
+ }
+ {
+ \box_move_up:nn
+ { \l_@@_sout_height_tl - \box_ht:N \l_@@_fntef_box / 2 }
+ { \box_use:N \l_@@_fntef_box }
+ }
+ \xeCJK_ulem_on:n
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CJKxout}
+% \begin{macrocode}
+\DeclareDocumentCommand \CJKxout { s t- s o }
+ {
+ \xeCJK_ulem_group_begin:
+ \xeCJK_fntef_boot:nnNNNn { xout } { xout } #1#2#3 {#4}
+ \xeCJK_fntef_initial:nn
+ {
+ \l_@@_xout_format_tl
+ \tex_kern:D -.1 em $/$
+ \tex_kern:D -.1 em
+ }
+ {
+ \box_move_up:nn
+ { \box_dp:N \l_@@_fntef_box / 2 }
+ { \box_use:N \l_@@_fntef_box }
+ }
+ \xeCJK_ulem_on:n
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CJKunderanyline}
+% \changes{v3.2.15}{2014/11/07}{完善选项。}
+% \begin{macrocode}
+\DeclareDocumentCommand \CJKunderanyline { s t- s o m m }
+ {
+ \xeCJK_ulem_group_begin:
+ \xeCJK_ulem_boot:NNNn #1#2#3 {#4}
+ \xeCJK_fntef_initial:nn
+ {#6}
+ {
+ \box_move_down:nn
+ {#5}
+ { \box_use:N \l_@@_fntef_box }
+ }
+ \tl_if_empty:NF \l_@@_ulem_boxdepth_tl
+ { \box_set_dp:Nn \ULC@box { \l_@@_ulem_boxdepth_tl } }
+ \tl_if_empty:NF \l_@@_ulem_sep_tl
+ {
+ \bool_set_true:N \l_@@_fntef_bool
+ \dim_set:Nn \l_@@_fntef_dim
+ { \l_@@_ulem_sep_tl + \box_dp:N \ULC@box }
+ }
+ \xeCJK_ulem_on:n
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_fntef_boot:nnNNNn}
+% 处理参数问题。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_fntef_boot:nnNNNn #1#2#3#4#5#6
+ {
+ \bool_lazy_or:nnT {#3} {#5}
+ { \bool_set_false:c { l_@@_#2_skip_bool } }
+ \bool_if:NT #4
+ { \bool_set_true:c { l_@@_#2_subtract_bool } }
+ \tl_if_novalue:nF {#6}
+ { \keys_set:nn { xeCJK / options / #1 } {#6} }
+ \bool_set_eq:Nc \l_@@_ulem_skip_bool { l_@@_#2_skip_bool }
+ \bool_set_eq:Nc \l_@@_ulem_hidden_bool { l_@@_#2_hidden_bool }
+ \bool_set_eq:Nc \l_@@_ulem_subtract_bool { l_@@_#2_subtract_bool }
+ \tl_set_eq:Nc \l_@@_ulem_text_format_tl { l_@@_#2_text_format_tl }
+ }
+\cs_new_protected:Npn \xeCJK_ulem_boot:NNNn #1#2#3#4
+ {
+ \bool_lazy_or:nnT {#1} {#3}
+ { \bool_set_false:N \l_@@_ulem_skip_bool }
+ \bool_if:NT #2
+ { \bool_set_true:N \l_@@_ulem_subtract_bool }
+ \tl_if_novalue:nF {#4}
+ { \keys_set:nn { xeCJK / options / ulem } {#4} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_fntef_initial:n}
+% 不支持下划线的嵌套使用。下划线嵌套使用时,里层的下划线会被放在盒子里,不能折行。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_fntef_initial:n
+ {
+ \bool_if:NTF \l_@@_nest_bool
+ { \@@_warning:n { fntef-nesting } }
+ {
+ \bool_set_true:N \l_@@_nest_bool
+ \@@_restore_shipout_fntef:
+ }
+ \xeCJK_fntef_sbox:n
+ }
+\cs_new_protected:Npn \xeCJK_fntef_initial:nn #1
+ {
+ \xeCJK_fntef_initial:n {#1}
+ \bool_if:NF \l_@@_fntef_bool
+ { \dim_zero:N \l_@@_fntef_dim }
+ \markoverwith
+ }
+\cs_new_protected:Npn \xeCJK_fntef_initial:nnn #1#2#3
+ {
+ \xeCJK_fntef_initial:n {#3}
+ \bool_if:NF \l_@@_fntef_bool
+ {
+ \bool_set_true:N \l_@@_fntef_bool
+ \dim_set:Nn \l_@@_fntef_dim {#1}
+ }
+ \markoverwith
+ {
+ \box_move_down:nn
+ { \l_@@_fntef_dim + \box_ht:N \l_@@_fntef_box }
+ { \box_use:N \l_@@_fntef_box }
+ }
+ \dim_set:Nn \l_@@_fntef_dim { #2 + \box_dp:N \ULC@box }
+ }
+\box_new:N \l_@@_fntef_box
+\cs_new_eq:NN \xeCJKfntefbox \l_@@_fntef_box
+\bool_new:N \l_@@_nest_bool
+\bool_new:N \l_@@_fntef_bool
+\@@_msg_new:nn { fntef-nesting }
+ { Nesting~is~not~supported. }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_fntef_dim}
+% 记录下划线或者下划符号的深度,以便它们嵌套使用时能自动调整好距离。
+% \tn{ULdepth} 被 \pkg{ulem} 初始化为 \tn{maxdimen}。下划线嵌套时,\pkg{ulem}
+% 要使用它作计算,可能会溢出。为简便起见,\cs{l_@@_fntef_dim} 与 \tn{ULdepth}
+% 共用一个寄存器。
+% \begin{macrocode}
+\cs_new_eq:NN \l_@@_fntef_dim \ULdepth
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\xeCJK_fntef_sbox:n}
+% 与 \cs{hcoffin_set:Nn} 和 \LaTeXe{} 的 \tn{sbox} 功能类似,确保颜色的正确。
+% 虽然 \texttt{coffin} 可以更方便的操作盒子,但速度要慢一点。并且,我们的需求
+% 也比较简单,就不用它了。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_fntef_sbox:n #1
+ {
+ \hbox_set:Nn \l_@@_fntef_box
+ {
+ \color_group_begin:
+ \color_ensure_current:
+ #1
+ \color_group_end:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% 最合适的是用 \pkg{xtemplate} 宏包来实现,但是比较难于用 \tn{xeCJKsetup} 来统一
+% 设置,所以这里还是用土办法。
+% \begin{macrocode}
+\keys_define:nn { xeCJK / options }
+ {
+ underdot / symbol .tl_set:N = \l_@@_udot_symbol_tl ,
+ underdot / depth .tl_set:N = \l_@@_udot_depth_tl ,
+ underdot / sep .tl_set:N = \l_@@_udot_sep_tl ,
+ underdot / format .tl_set:N = \l_@@_udot_format_tl ,
+ underdot / textformat .tl_set:N = \l_@@_udot_text_format_tl ,
+ underdot / boxdepth .tl_set:N = \l_@@_udot_boxdepth_tl ,
+ symbol / sep .tl_set:N = \l_@@_symbol_sep_tl ,
+ symbol / boxdepth .tl_set:N = \l_@@_symbol_boxdepth_tl ,
+ symbol / textformat .tl_set:N = \l_@@_symbol_text_format_tl ,
+ underline / skip .bool_set:N = \l_@@_uline_skip_bool ,
+ underline / hidden .bool_set:N = \l_@@_uline_hidden_bool ,
+ underline / subtract .bool_set:N = \l_@@_uline_subtract_bool ,
+ underline / thickness .tl_set:N = \l_@@_uline_thickness_tl ,
+ underline / depth .tl_set:N = \l_@@_uline_depth_tl ,
+ underline / sep .tl_set:N = \l_@@_uline_sep_tl ,
+ underline / format .tl_set:N = \l_@@_uline_format_tl ,
+ underline / textformat .tl_set:N = \l_@@_uline_text_format_tl ,
+ underdblline / skip .bool_set:N = \l_@@_udbline_skip_bool ,
+ underdblline / hidden .bool_set:N = \l_@@_udbline_hidden_bool ,
+ underdblline / subtract .bool_set:N = \l_@@_udbline_subtract_bool ,
+ underdblline / thickness .tl_set:N = \l_@@_udbline_thickness_tl ,
+ underdblline / depth .tl_set:N = \l_@@_udbline_depth_tl ,
+ underdblline / sep .tl_set:N = \l_@@_udbline_sep_tl ,
+ underdblline / format .tl_set:N = \l_@@_udbline_format_tl ,
+ underdblline / textformat .tl_set:N = \l_@@_udbline_text_format_tl ,
+ underdblline / gap .tl_set:N = \l_@@_udbline_gap_tl ,
+ underwave / skip .bool_set:N = \l_@@_uwave_skip_bool ,
+ underwave / hidden .bool_set:N = \l_@@_uwave_hidden_bool ,
+ underwave / subtract .bool_set:N = \l_@@_uwave_subtract_bool ,
+ underwave / symbol .tl_set:N = \l_@@_uwave_symbol_tl ,
+ underwave / depth .tl_set:N = \l_@@_uwave_depth_tl ,
+ underwave / sep .tl_set:N = \l_@@_uwave_sep_tl ,
+ underwave / format .tl_set:N = \l_@@_uwave_format_tl ,
+ underwave / textformat .tl_set:N = \l_@@_uwave_text_format_tl ,
+ sout / skip .bool_set:N = \l_@@_sout_skip_bool ,
+ sout / hidden .bool_set:N = \l_@@_sout_hidden_bool ,
+ sout / subtract .bool_set:N = \l_@@_sout_subtract_bool ,
+ sout / thickness .tl_set:N = \l_@@_sout_thickness_tl ,
+ sout / height .tl_set:N = \l_@@_sout_height_tl ,
+ sout / format .tl_set:N = \l_@@_sout_format_tl ,
+ sout / textformat .tl_set:N = \l_@@_sout_text_format_tl ,
+ xout / skip .bool_set:N = \l_@@_xout_skip_bool ,
+ xout / hidden .bool_set:N = \l_@@_xout_hidden_bool ,
+ xout / subtract .bool_set:N = \l_@@_xout_subtract_bool ,
+ xout / format .tl_set:N = \l_@@_xout_format_tl ,
+ xout / textformat .tl_set:N = \l_@@_xout_text_format_tl ,
+ ulem / skip .bool_set:N = \l_@@_ulem_skip_bool ,
+ ulem / hidden .bool_set:N = \l_@@_ulem_hidden_bool ,
+ ulem / subtract .bool_set:N = \l_@@_ulem_subtract_bool ,
+ ulem / sep .tl_set:N = \l_@@_ulem_sep_tl ,
+ ulem / boxdepth .tl_set:N = \l_@@_ulem_boxdepth_tl ,
+ ulem / textformat .tl_set:N = \l_@@_ulem_text_format_tl
+ }
+\clist_map_inline:nn
+ { underdot , underline , underdblline , underwave , sout , xout , ulem }
+ {
+ \keys_define:nn { xeCJK / options }
+ { #1 .meta:nn = { xeCJK / options / #1 } { ##1 } }
+ }
+\keys_set:nn { xeCJK / options }
+ {
+ underdot / symbol = \normalfont . ,
+ underdot / depth = 0.20 em ,
+ underdot / sep = 0.04 em ,
+ symbol / sep = \c_zero_dim ,
+ underline / skip = true ,
+ underline / thickness = \ULthickness ,
+ underline / depth = 0.20 em ,
+ underline / sep = 0.07 em ,
+ underdblline / skip = true ,
+ underdblline / thickness = \ULthickness ,
+ underdblline / depth = 0.20 em ,
+ underdblline / sep = 0.17 em ,
+ underdblline / gap = 1.1 pt ,
+ underwave / skip = true ,
+ underwave / symbol = \sixly \tex_char:D 58 \exp_stop_f: ,
+ underwave / depth = 0.20 em ,
+ underwave / sep = 0.00 em ,
+ sout / skip = true ,
+ sout / thickness = \ULthickness ,
+ sout / height = 0.35 em ,
+ xout / skip = true
+ }
+\cs_if_free:NF \color
+ {
+ \keys_set:nn { xeCJK / options }
+ {
+ underdot / format = \color { red } ,
+ underline / format = \color { blue } ,
+ underdblline / format = \color { blue } ,
+ underwave / format = \color { blue } ,
+ sout / format = \color { red } ,
+ xout / format = \color { blue }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macro}{\CJKunderanysymbol}
+% \begin{macrocode}
+\DeclareDocumentCommand \CJKunderanysymbol { o m m m }
+ {
+ \xeCJK_under_symbol:nnnnnn { symbol } { symbol } {#1} {#2} {#3} {#4}
+ \tex_ignorespaces:D
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CJKunderdot}
+% \tn{CJKunderdot} 是 \tn{CJKunderanysymbol} 的特殊情况。\pkg{CJKfntef} 原来使用
+% 的是数学符号 \tn{cdot},这里改成更合适的 |.|。
+% \begin{macrocode}
+\DeclareDocumentCommand \CJKunderdot { o m }
+ {
+ \xeCJK_under_symbol:nnnnnn { underdot } { udot }
+ {#1}
+ { \l_@@_udot_depth_tl }
+ { \l_@@_udot_format_tl \l_@@_udot_symbol_tl }
+ {#2}
+ \tex_ignorespaces:D
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_under_symbol:nnnnnn}
+% 当处在下划线中时,我们先断开下划线,在分组外设置下划符号。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_under_symbol:nnnnnn
+ {
+ \xeCJK_if_ulem_patch:TF
+ { \@@_under_symbol_auxi:nnnnnn }
+ { \@@_under_symbol_auxii:nnnnnn }
+ }
+\cs_new_protected:Npn \@@_under_symbol_auxi:nnnnnn #1#2#3#4#5#6
+ {
+ \xeCJK_ulem_right: \UL@stop
+ \group_begin:
+ \xeCJK_under_symbol_initial:nnnnn {#1} {#2} {#3} {#4} {#5}
+ \use:c { l_@@_#2_text_format_tl }
+ \UL@start \xeCJK_ulem_right_node:
+ #6
+ \xeCJK_ulem_right: \UL@stop
+ \group_end:
+ \UL@start \xeCJK_ulem_right_node:
+ }
+\cs_new_protected:Npn \@@_under_symbol_auxii:nnnnnn #1#2#3#4#5#6
+ {
+ \mode_leave_vertical:
+ \group_begin:
+ \xeCJK_under_symbol_initial:nnnnn {#1} {#2} {#3} {#4} {#5}
+ \@@_under_symbol_text_format:c { l_@@_#2_text_format_tl }
+ #6
+ \xeCJK_ulem_right:
+ \group_end:
+ \xeCJK_ulem_right_node:
+ }
+\cs_new_protected:Npn \xeCJK_under_symbol_initial:nnnnn #1#2#3#4#5
+ {
+ \tl_if_novalue:nF {#3}
+ { \keys_set:nn { xeCJK / options / #1 } {#3} }
+ \xeCJK_fntef_sbox:n {#5}
+ \bool_if:NTF \l_@@_fntef_bool
+ { \xeCJK_make_under_symbol:n { \l_@@_fntef_dim } }
+ {
+ \bool_set_true:N \l_@@_fntef_bool
+ \xeCJK_make_under_symbol:n {#4}
+ }
+ \tl_if_empty:cF { l_@@_#2_boxdepth_tl }
+ {
+ \box_set_dp:Nn \l_@@_under_symbol_box
+ { \use:c { l_@@_#2_boxdepth_tl } }
+ }
+ \dim_set:Nn \l_@@_fntef_dim
+ { \use:c { l_@@_#2_sep_tl } + \box_dp:N \l_@@_under_symbol_box }
+ \xeCJK_swap_cs:NN \CJKsymbol \@@_under_CJKsymbol:N
+ \@@_restore_shipout_CJKsymbol:
+ }
+\cs_new_protected:Npn \@@_under_symbol_text_format:N #1
+ {
+ \tl_if_empty:NF #1
+ { \xeCJK_ulem_right: #1 \xeCJK_ulem_right_node: }
+ }
+\cs_generate_variant:Nn \@@_under_symbol_text_format:N { c }
+\box_new:N \l_@@_under_symbol_box
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_make_under_symbol:n}
+% 我们量取“一”的宽度作为汉字的宽度。
+% \begin{macrocode}
+\cs_new_protected:Npn \xeCJK_make_under_symbol:n #1
+ {
+ \hbox_set:Nn \l_@@_under_symbol_box
+ {
+ \box_move_down:nn { #1 + \box_ht:N \l_@@_fntef_box }
+ {
+ \hbox_to_zero:n
+ {
+ \xeCJK_select_font:
+ \tex_kern:D \tex_fontcharwd:D \tex_font:D "4E00 \exp_stop_f:
+ \tex_hss:D \box_use:N \l_@@_fntef_box \tex_hss:D
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_restore_shipout_CJKsymbol:}
+% \changes{v3.2.3}{2013/06/04}{解决 \tn{CJKunderdot} 跨页使用时影响到页眉页脚的问题。}
+% \tn{CJKunderdot} 中对 \tn{CJKsymbol} 的修改会影响到页眉和页脚,需要小心处理。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_restore_shipout_CJKsymbol:
+ {
+ \tl_put_right:Nn \l_@@_fntef_shipout_tl
+ { \xeCJK_swap_cs:NN \CJKsymbol \@@_under_CJKsymbol:N }
+ \@@_restore_shipout_fntef:
+ \xeCJK_cs_clear:N \@@_restore_shipout_CJKsymbol:
+ }
+\cs_new_protected:Npn \@@_restore_shipout_fntef:
+ {
+ \tl_put_right:Nn \l_@@_fntef_shipout_tl
+ {
+ \bool_set_false:N \l_@@_fntef_bool
+ \dim_zero:N \l_@@_fntef_dim
+ }
+ \xeCJK_cs_clear:N \@@_restore_shipout_fntef:
+ }
+\tl_new:N \l_@@_fntef_shipout_tl
+\xeCJK_add_to_shipout:n { \l_@@_fntef_shipout_tl }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_under_CJKsymbol:N}
+% 盒子放在汉字的左侧,比较容易处理状态转移的问题。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_under_CJKsymbol:N
+ {
+ \box_use:N \l_@@_under_symbol_box
+ \xeCJK_no_break: \@@_under_CJKsymbol:N
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.7.2}{2019/03/24}{改用 \pkg{xparse} 的新参数类型 \texttt{b}
+% 定义 \env{CJKfilltwosides*} 环境,不再依赖 \pkg{environ} 包。}
+%
+% \begin{macro}{CJKfilltwosides}
+% \changes{v3.2.4}{2013/06/26}{改用 \texttt{minipage} 和 \LaTeX 表格(\texttt{tabular})来实现。}
+% \changes{v3.3.3}{2015/05/30}{确保进入水平模式。}
+% 使用 \texttt{minipage} 和 \LaTeX 表格(\texttt{tabular})来定义 |CJKfilltwosides| 环境。
+% 可选参数 |#1| 表示环境的垂直对齐位置,默认居中;参数 |#2| 表示环境的宽度。
+% 带星号的环境,如果 |#2| 不大于零或者不大于环境最长文本行的宽度,则取环境的自然宽度。
+% \begin{macrocode}
+\DeclareDocumentEnvironment { CJKfilltwosides } { O { c } m }
+ {
+ \use:x { \exp_not:N \minipage [#1] { \dim_eval:n {#2} } }
+ \cs_set_eq:NN \CJKglue \xeCJK_fntef_hfilll:
+ }
+ {
+ \endminipage
+ \ignorespacesafterend
+ }
+\DeclareDocumentEnvironment { CJKfilltwosides* } { O { c } m +b }
+ {
+ \mode_leave_vertical:
+ \cs_set_eq:NN \CJKglue \xeCJK_fntef_hfilll:
+ \tl_set:Nn \arraystretch { 1 }
+ \cs_if_free:NF \extrarowheight
+ { \cs_set_eq:NN \extrarowheight \c_zero_dim }
+ \use:x { \@@_fill_two_sides:nnn {#1} { \dim_eval:n {#2} } } {#3}
+ }
+ { \ignorespacesafterend }
+\cs_new_protected:Npn \@@_fill_two_sides:nnn #1#2#3
+ {
+ \dim_compare:nNnTF {#2} > \c_zero_dim
+ {
+ \hbox_set:Nn \l_@@_tmp_box
+ { \tabular [#1] { @ { } c @ { } } #3 \endtabular }
+ \dim_compare:nNnTF {#2} > { \box_wd:N \l_@@_tmp_box }
+ { \tabular [#1] { @ { } p {#2} @ { } } #3 \endtabular }
+ { \box_use:N \l_@@_tmp_box }
+ }
+ { \tabular [#1] { @ { } c @ { } } #3 \endtabular }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xeCJK_fntef_hfilll:}
+% \pkg{colortbl} 将表格 |c| 列用于填充的 \tn{hfil} 改为了更高阶的 \texttt{fill},
+% 影响到了 \env{CJKfilltwosides*}。因此,我们也要用高阶的 \texttt{filll}。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xeCJK_fntef_hfilll:
+ { \skip_horizontal:N \c_@@_filll_skip }
+\skip_const:Nn \c_@@_filll_skip { \c_zero_dim plus 1 filll }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</fntef>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-listings}}
+%
+% \changes{v3.2.2}{2013/06/04}{增加小宏包 \pkg{xeCJK-listings},用于支持 \pkg{listings} 宏包。}
+% \changes{v3.2.3}{2013/06/06}{完善对 \pkg{listings} 宏包的支持。}
+%
+% 仿照 \package{luatexja} 宏包中 \pkg{lltjp-listings} 的处理,支持 \package{listings} 宏包。
+%
+% \begin{macrocode}
+%<*listings>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\DeclareOption* { \PassOptionsToPackage { \CurrentOption } { xeCJK } }
+\ProcessOptions \scan_stop:
+% \end{macrocode}
+%
+% \begin{macrocode}
+\RequirePackage { xeCJK }
+\RequirePackage { listings }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\lst@AddToHook { Init } { \@@_listings_initial_hook: }
+\lst@AddToHook { SelectCharTable } { \@@_listings_toks_hook: }
+\lst@AddToHook { OutputBox }
+ {
+ \tl_set_eq:NN \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl
+ \l_@@_restore_listings_toks_tl
+ \@@_listings_output_CM:
+ }
+\lst@AddToHook { PreSet } { \bool_set_true:N \l_@@_listings_env_bool }
+% \end{macrocode}
+%
+% \begin{macro}{\@@_listings_initial_hook:}
+% \changes{v3.2.3}{2013/06/04}
+% {解决 \texttt{listings} 坏境中代码行号输出不正确的问题,并解决在其中跨页时对页眉
+% 和页脚的影响。}
+% \changes{v3.2.15}{2014/11/10}{修正 \texttt{breaklines} 无效的问题。}
+% \changes{v3.3.1}{2015/04/20}
+% {解决 \texttt{prebreak} 和 \texttt{postbreak} 功能失效的问题。}
+% 为使代码行号结果正确,需要在 \tn{lst@numberstyle} 中恢复 \tn{XeTeXinterchartoks}。
+% 在 \texttt{listings} 环境中换页时,对 \tn{XeTeXinterchartoks} 的修改会影响到
+% 页眉和页脚,需要在 \tn{shipout} 盒子中恢复成正常定义。加入 \cs{tex_noindent:D}
+% 是为了进入水平模式,防止汉字出现在首行的时候可能会产生额外空行。
+% \tn{lst@prebreak} 和 \tn{lst@postbreak} 是在 \tn{discretionary} 中直接输出的,
+% 应该恢复正常的 \tn{XeTeXinterchartoks}。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_initial_hook:
+ {
+ \tex_noindent:D
+ \bool_gset_false:N \g_@@_listings_CM_bool
+ \tl_put_left:Nn \lst@numberstyle { \l_@@_restore_listings_toks_tl }
+ \xeCJK_add_to_shipout:n { \l_@@_restore_listings_toks_tl }
+ \lst@ifbreaklines
+ \cs_set_eq:NN \@@_listings_CJK_toks_hook: \@@_listings_breaklines_toks:
+ \tl_if_empty:NF \lst@prebreak
+ { \tl_put_left:Nn \lst@prebreak { \l_@@_restore_listings_toks_tl } }
+ \tl_if_empty:NF \lst@postbreak
+ { \tl_put_left:Nn \lst@postbreak { \l_@@_restore_listings_toks_tl } }
+ \fi:
+ \int_set:Nn \l_@@_listings_max_char_int
+ { \lst@ifec 255 \else: 127 \fi: }
+ }
+\int_new:N \l_@@_listings_max_char_int
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_toks_hook:}
+% 采用不同的 \tn{XeTeXinterchartoks} 处理方式,输入的时候是将汉字加入到 \pkg{listings}
+% 的输出队列,实际输出的时候是普通文字。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_toks_hook:
+ {
+ \tl_clear:N \l_@@_restore_listings_toks_tl
+ \seq_map_function:NN
+ \g_@@_class_seq \@@_backup_inter_class_toks:n
+ \seq_map_inline:Nn \g_@@_non_CJK_class_seq
+ {
+ \str_if_eq:nnF { ##1 } { Boundary }
+ {
+ \xeCJK_inter_class_toks:nnn { Boundary } { ##1 }
+ { \@@_listings_process_Default:nN { ##1 } }
+ }
+ }
+ \xeCJK_inter_class_toks:nnn { Boundary } { CM }
+ { \@@_listings_process_CM:nN { 0 } }
+ \@@_listings_CJK_toks_hook:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_backup_inter_class_toks:n}
+% 注意,给 \tn{XeTeXinterchartoks} 赋空值,会导致 \XeTeX 崩溃!
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_backup_inter_class_toks:n #1
+ {
+ \tl_set:Nx \l_@@_tmp_tl
+ { \xeCJK_get_inter_class_toks:nn { Boundary } {#1} }
+ \tl_put_right:Nx \l_@@_restore_listings_toks_tl
+ {
+ \xeCJK_inter_class_toks:nnn { Boundary } {#1}
+ {
+ \tl_if_empty:NTF \l_@@_tmp_tl
+ { \exp_not:N \prg_do_nothing: }
+ { \exp_not:o \l_@@_tmp_tl }
+ }
+ }
+ }
+\tl_new:N \l_@@_restore_listings_toks_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_CJK_toks_hook:,\@@_listings_breaklines_toks:}
+% 根据 \texttt{breaklines} 选项的使用与否,选择不同的处理方式。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_CJK_toks_hook:
+ {
+ \xeCJK_inter_class_toks:nnn { Boundary } { CJK }
+ { \@@_listings_process_CJK:nN { 2 } }
+ \xeCJK_inter_class_toks:nnn { Boundary } { FullLeft }
+ { \@@_listings_process_CJK:nN { 2 } }
+ \xeCJK_inter_class_toks:nnn { Boundary } { FullRight }
+ { \@@_listings_process_CJK:nN { 2 } }
+ \xeCJK_inter_class_toks:nnn { Boundary } { HangulJamo }
+ { \@@_listings_process_CJK:nN { 2 } }
+ \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
+ {
+ \xeCJK_inter_class_toks:nnn { Boundary } { CJK/##1 }
+ { \@@_listings_process_CJK:nN { 2 } }
+ }
+ }
+\cs_new_protected_nopar:Npn \@@_listings_breaklines_toks:
+ {
+ \xeCJK_inter_class_toks:nnn { Boundary } { CJK }
+ { \@@_listings_process_breaklines_CJK:nN { 2 } }
+ \xeCJK_inter_class_toks:nnn { Boundary } { HangulJamo }
+ { \@@_listings_process_breaklines_CJK:nN { 2 } }
+ \xeCJK_inter_class_toks:nnn { Boundary } { FullLeft }
+ { \@@_listings_process_FullLeft:nN { 2 } }
+ \xeCJK_inter_class_toks:nnn { Boundary } { FullRight }
+ { \@@_listings_process_FullRight:nN { 2 } }
+ \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
+ {
+ \xeCJK_inter_class_toks:nnn { Boundary } { CJK/##1 }
+ { \@@_listings_process_breaklines_CJK:nN { 2 } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_process_Default:nN}
+% \changes{v3.2.3}{2013/06/08}{在 \texttt{listings} 坏境中对 \tn{charcode} 大于
+% $255$ 的字符根据其 \tn{catcode} 区分 \texttt{letter} 和 \texttt{other}。}
+% \changes{v3.3.1}{2015/01/27}{对 \pkg{listings} 的字符扩展不影响到其符号表中的
+% 七位或八位字符。}
+% 对于 \tn{charcode} 大于 $255$ 的字符,根据 \tn{catcode} 进行处理。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_process_Default:nN #1#2
+ {
+ \int_compare:nNnTF
+ { \xeCJK_token_value_charcode:N #2 } > \l_@@_listings_max_char_int
+ {
+ \token_if_letter:NTF #2
+ { \lst@ProcessLetter #2 }
+ { \lst@ProcessOther #2 }
+ }
+ { \@@_listings_output_Default:nN {#1} #2 }
+ }
+% \end{macrocode}
+% 输出时,要注意把对应的 \tn{XeTeXinterchartoks} 清空掉,否则会造成死循环。
+% \cs{scan_stop:} 是造边界,输出 \cs{group_end:}。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_output_Default:nN #1#2
+ {
+ \group_begin:
+ \xeCJK_clear_inter_class_toks:nn { Boundary } {#1}
+ \xeCJK_inter_class_toks:nnn {#1} { Boundary } { \group_end: }
+ #2
+ \scan_stop:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_process_CJK:nN}
+% 对 CJK 字符类的处理。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_process_CJK:nN #1#2
+ {
+ \token_if_letter:NTF #2
+ { \@@_listings_process_letter:nN {#1} #2 }
+ { \@@_listings_process_other:nN {#1} #2 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_append:nN}
+% 普通 CJK 字符的宽度为一般基本宽度的两倍,CM 类不增加宽度。这里有一个问题,
+% 对 CJK 字符类中的一些半角字符(例如半角日文假名)没有区分开。\pkg{listings} 通过
+% 重定义 \tn{lst@Append} 将代码写入外部文件,因此需要保留。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_append:nN #1#2
+ {
+ \int_add:Nn \lst@length { #1 - 1 }
+ \lst@Append #2
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_process_letter:nN,\@@_listings_process_other:nN}
+% 在 \texttt{letter} 类中区分汉字和西文字母。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_process_letter:nN
+ {
+ \lst@whitespacefalse
+ \bool_if:NTF \l_@@_listings_letter_bool
+ { \lst@lettertrue }
+ {
+ \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi:
+ \bool_set_true:N \l_@@_listings_letter_bool
+ }
+ \@@_listings_append:nN
+ }
+\bool_new:N \l_@@_listings_letter_bool
+\cs_new_protected_nopar:Npn \@@_listings_process_other:nN #1#2
+ {
+ \lst@whitespacefalse
+ \bool_if:NTF \l_@@_listings_letter_bool
+ {
+ \lst@Output \lst@letterfalse
+ \bool_set_false:N \l_@@_listings_letter_bool
+ }
+ { \lst@ifletter \lst@Output \lst@letterfalse \fi: }
+ \cs_set_eq:NN \lst@lastother #2
+ \@@_listings_append:nN {#1} #2
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.4}{2013/07/05}
+% {使 \pkg{listings} 的 \texttt{breaklines} 选项对 CJK 字符类可用,并保持标点符号的禁则。}
+%
+% \begin{macro}
+% {\@@_listings_process_breaklines_CJK:nN,
+% \@@_listings_process_FullLeft:nN,
+% \@@_listings_process_FullRight:nN}
+% 当使用 \texttt{breaklines} 选项时,立即输出之前的单个文字,以便于断行。并将标点
+% 与它前/后的 CJK 文字放在同一个盒子中,以保持禁则。但是不能区分 letter 和 other。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_process_breaklines_CJK:nN
+ {
+ \lst@whitespacefalse
+ \bool_if:NTF \l_@@_listings_letter_bool
+ {
+ \int_compare:nNnF \l_@@_listings_flag_int = 2 { \lst@Output }
+ \lst@lettertrue
+ }
+ {
+ \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi:
+ \bool_set_true:N \l_@@_listings_letter_bool
+ }
+ \int_set_eq:NN \l_@@_listings_flag_int \c_one_int
+ \@@_listings_append:nN
+ }
+\cs_new_protected_nopar:Npn \@@_listings_process_FullLeft:nN #1#2
+ {
+ \lst@whitespacefalse
+ \bool_if:NTF \l_@@_listings_letter_bool
+ {
+ \int_compare:nNnF \l_@@_listings_flag_int = 2
+ {
+ \int_compare:nNnTF \l_@@_listings_flag_int = 3
+ { \bool_if:NT \l_@@_punct_breakable_bool { \lst@Output } }
+ { \lst@Output }
+ }
+ \lst@lettertrue
+ }
+ {
+ \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi:
+ \bool_set_true:N \l_@@_listings_letter_bool
+ }
+ \int_set:Nn \l_@@_listings_flag_int { 2 }
+ \@@_listings_append:nN {#1} #2
+ }
+\cs_new_protected_nopar:Npn \@@_listings_process_FullRight:nN #1#2
+ {
+ \lst@whitespacefalse
+ \bool_if:NTF \l_@@_listings_letter_bool
+ {
+ \int_compare:nNnT \l_@@_listings_flag_int < 2
+ { \@@_punct_if_long:NT #2 { \lst@Output } }
+ \lst@lettertrue
+ }
+ {
+ \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi:
+ \bool_set_true:N \l_@@_listings_letter_bool
+ }
+ \int_set:Nn \l_@@_listings_flag_int { 3 }
+ \@@_listings_append:nN {#1} #2
+ }
+\int_new:N \l_@@_listings_flag_int
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\lst@AppendLetter,\lst@AppendOther}
+% \begin{macrocode}
+\cs_set_protected_nopar:Npn \lst@AppendLetter
+ {
+ \bool_if:NTF \l_@@_listings_letter_bool
+ {
+ \lst@Output \lst@lettertrue
+ \bool_set_false:N \l_@@_listings_letter_bool
+ }
+ { \reverse_if:N \lst@ifletter \lst@OutputOther \lst@lettertrue \fi: }
+ \lst@ifbreaklines \int_zero:N \l_@@_listings_flag_int \fi:
+ \lst@Append
+ }
+\cs_set_protected_nopar:Npn \lst@AppendOther
+ {
+ \bool_if:NTF \l_@@_listings_letter_bool
+ {
+ \lst@Output \lst@letterfalse
+ \bool_set_false:N \l_@@_listings_letter_bool
+ }
+ { \lst@ifletter \lst@Output \lst@letterfalse \fi: }
+ \lst@ifbreaklines \int_zero:N \l_@@_listings_flag_int \fi:
+ \tex_futurelet:D \lst@lastother \lst@Append
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_process_CM:nN}
+% \texttt{CM} 类作为 \texttt{letter} 处理,不用增加 \tn{lst@length}。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_process_CM:nN
+ {
+ \reverse_if:N \lst@ifflexible
+ \bool_gset_true:N \g_@@_listings_CM_bool
+ \fi:
+ \@@_listings_process_letter:nN
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_output_CM:}
+% 在使用 \texttt{columns=fixed} 选项时,\pkg{listings} 会在输出盒子里的每个字符
+% 之间加入 \tn{hss},这就破坏了 \XeTeX 将基本字和组合标识正确的组合起来。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_listings_output_CM:
+ {
+ \reverse_if:N \lst@ifflexible
+ \bool_if:NT \g_@@_listings_CM_bool
+ {
+ \bool_gset_false:N \g_@@_listings_CM_bool
+ \xeCJK_cs_clear:N \lst@FillOutputBox
+ \cs_set_eq:NN \CJKglue \tex_hss:D
+ }
+ \fi:
+ }
+\bool_new:N \g_@@_listings_CM_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_peek_active_loop:TF}
+% \tn{lstinline} 通过判断参数中第一个字符是否是 \texttt{active} 类来区分
+% 它是否被用在其它宏的参数之中。如果这第一个字符不在 \pkg{listings} 预定义的
+% 符号表中,判断就会出问题。我们在这里通过一个循环跳过这些字符。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_listings_peek_active_loop:TF #1#2#3
+ {
+ \token_if_active:NTF #3
+ { #1#3 }
+ {
+ \token_if_cs:NTF #3
+ { #2#3 }
+ {
+ \int_compare:nNnTF { `#3 } > { \l_@@_listings_max_char_int }
+ { \@@_listings_peek_active_loop:TF { #1#3 } { #2#3 } }
+ { #2#3 }
+ }
+ }
+ }
+\cs_set_eq:NN \lst@IfNextCharActive \@@_listings_peek_active_loop:TF
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_rescan:Nn,
+% \@@_listings_inside_convert:nw,\@@_listings_inline_group:w}
+% 当 \tn{lstinline} 被使用在参数中时,\pkg{listings} 会使用一个循环逐个将
+% \tn{lstinline} 参数中的字符设置为活动字符。我们可以通过 \cs{tl_set_rescan:Nnn}
+% 来完成这里的 \tn{catcode} 转换,避免将 \tn{charcode} 超过 $255$ 的字符都设置为
+% 活动字符。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_listings_rescan:Nn #1#2
+ {
+ \@@_listings_set_escape:
+ \tl_set:Nn \l_@@_tmp_tl {#2}
+ \@@_listings_escape_backslash:
+ \tl_set_rescan:Nno #1 { } { \l_@@_tmp_tl }
+ }
+\cs_new_protected:Npn \@@_listings_inside_convert:nw #1 ~ \@empty
+ {
+ \@@_listings_rescan:Nn \l_@@_tmp_tl {#1}
+ \tl_put_right:No \lst@arg { \l_@@_tmp_tl }
+ }
+\cs_set_eq:NN \lst@InsideConvert@ \@@_listings_inside_convert:nw
+\cs_new_protected_nopar:Npn \@@_listings_inline_group:w
+ {
+ \exp_after:wN \@@_listings_inline_group:n
+ \exp_after:wN { \if_int_compare:w `} = \c_zero_int \fi:
+ }
+\cs_set_eq:NN \lst@InlineGJ \@@_listings_inline_group:w
+\cs_new_protected:Npn \@@_listings_inline_group:n #1
+ {
+ \@@_listings_rescan:Nn \lst@arg {#1}
+ \lst@InlineGJEnd
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_listings_set_escape:}
+% 由于我们在上面的修改,需要保留 |\| 用于转义 \tn{lstinline} 参数中的某些 \TeX
+% 特殊字符,与原来宏包一致。
+% \begin{macrocode}
+\group_begin:
+\cs_set:Npn \@@_tmp:w #1
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \@@_listings_set_escape:
+ { \xeCJK_swap_cs:NN #1 \@@_listings_escape:N }
+ \cs_new_protected:Npn \@@_listings_escape:N ##1
+ { \cs_if_eq:NNTF #1 ##1 { \@@_listings_escape:N } {##1} }
+ }
+\use:n
+ {
+ \char_set_catcode_active:N \\
+ \@@_tmp:w
+ }
+ { \ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \changes{v3.4.8}{2017/05/15}{转义 \tn{lstinline} 参数中的 $\texttt{\textbackslash}_{12}$。}
+% \begin{macro}{\@@_listings_escape_backslash:}
+% \tn{catcode} 为 $12$ 的 |\| 需要双写转义。
+% \begin{macrocode}
+\cs_new_protected_nopar:Npx \@@_listings_escape_backslash:
+ {
+ \tl_replace_all:Nnn \exp_not:N \l_@@_tmp_tl
+ { \c_backslash_str }
+ { \c_backslash_str \c_backslash_str }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</listings>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=xunadd>
+% \end{macrocode}
+%
+% \subsection{\pkg{xunicode-addon}}
+%
+% \changes{v3.2.5}{2013/07/18}
+% {增加小宏包 \pkg{xunicode-addon},为 \pkg{xunicode} 提供判断字符是否存在的功能。}
+% \changes{v3.2.9}{2013/12/08}
+% {文档部分增加 \pkg{xunicode} 定义的符号表。}
+%
+% \begin{macrocode}
+%<*xunicode>
+% \end{macrocode}
+%
+% \pkg{xunicode} 对编码相关的符号命令的定义中用的是诸如 |\char"0022\relax| 的形式。
+% 例如 \tn{textbar} 被展开为 |\char"007C\relax|。并且诸如下述的定义是无效的:
+% \begin{verbatim}
+% \DeclareUTFcomposite[\UTFencname]{x1EBF}{\'}{\^e}
+% \end{verbatim}
+% 我们在这里做的修改是把符号命令定义为实际的字符并且使上述定义生效。另外在使用
+% 这些符号命令的时候,先判断当前字体中是否存在对应的字符,如果不存在,则使用这
+% 些符号命令的默认设置。
+%
+% \begin{macrocode}
+\bool_lazy_or:nnF
+ { \sys_if_engine_xetex_p: }
+ { \sys_if_engine_luatex_p: }
+ {
+ \msg_new:nnnn { xunicode-addon } { xetex-luatex }
+ { This~package~requires~either~XeTeX~or~LuaTeX~to~function.}
+ {
+ You~must~change~your~typesetting~engine~to,~e.g.,\\
+ "xelatex"~or~"lualatex"~instead~of~plain~"latex"~or~"pdflatex".
+ }
+ \msg_critical:nn { xunicode-addon } { xetex-luatex }
+ }
+\RequirePackage { xparse }
+% \end{macrocode}
+%
+% 宏包选项是编码的名字。
+%
+% \begin{macrocode}
+\clist_new:N \g_@@_encname_clist
+\tl_if_exist:NT \UTFencname
+ { \clist_gput_right:Nx \g_@@_encname_clist { \UTFencname } }
+\DeclareOption*
+ { \clist_gput_right:NV \g_@@_encname_clist \CurrentOption }
+\ProcessOptions \scan_stop:
+% \end{macrocode}
+%
+% 若 \pkg{xunicode} 已经被调用,则在宏包结束的时候,重新设置 \tn{UTFencname}
+% 对应的编码命令。否则设置 \tn{UTFencname},如果使用的是 \hologo{LuaLaTeX},则
+% 需要作一些设置,使得 \pkg{xunicode} 可用。
+%
+% \changes{v3.3.3}{2016/02/01}{使用新的 Unicode 编码名称 \texttt{TU}。}
+%
+% \begin{macrocode}
+\@ifpackageloaded { xunicode } { }
+ {
+ \clist_get:NNF \g_@@_encname_clist \UTFencname
+ {
+ \cs_if_exist:NTF \UnicodeEncodingName
+ { \tl_set:Nx \UTFencname { \UnicodeEncodingName } }
+ {
+ \sys_if_engine_xetex:TF
+ { \tl_set:Nn \UTFencname { EU1 } }
+ { \tl_set:Nn \UTFencname { EU2 } }
+ }
+ \clist_gset_eq:NN \g_@@_encname_clist \UTFencname
+ }
+ \sys_if_engine_xetex:TF
+ { \RequirePackage { xunicode } }
+ {
+ \cs_set_eq:NN \@@_tmp:w \XeTeXpicfile
+ \cs_set_eq:NN \XeTeXpicfile \prg_do_nothing:
+ \RequirePackage { xunicode }
+ \cs_set_eq:NN \XeTeXpicfile \@@_tmp:w
+ }
+ }
+\AtEndOfPackage { \@@_reload:N \g_@@_encname_clist }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\ReloadXunicode}
+% 参数可以是多个编码,设置这些编码对应的命令。如果编码没有预先声明,则给出
+% 一个错误警告。
+% \begin{macrocode}
+\RenewDocumentCommand \ReloadXunicode { m }
+ {
+ \clist_set:Nx \l_@@_encname_clist {#1}
+ \@@_reload:N \l_@@_encname_clist
+ }
+\cs_new_protected:Npn \@@_reload:N #1
+ {
+ \cs_set_eq:NN \@@_tmp:w \iftipaonetoken
+ \cs_set_eq:NN \iftipaonetoken \scan_stop:
+ \use:x
+ {
+ \ExplSyntaxOff
+ \char_set_catcode_letter:n { 64 }
+ \exp_not:N \clist_map_function:NN \exp_not:N #1 \@@_reload_aux:n
+ \bool_if:NTF \l__kernel_expl_bool
+ { \ExplSyntaxOn }
+ { \ExplSyntaxOff }
+ \char_set_catcode:nn { 64 } { \char_value_catcode:n { 64 } }
+ }
+ \cs_set_eq:NN \iftipaonetoken \@@_tmp:w
+ }
+\cs_new_protected:Npn \@@_reload_aux:n #1
+ {
+ \cs_if_exist:cTF { T@ #1 }
+ {
+ \tl_set:Nn \UTFencname {#1}
+ \clist_if_in:NnF \g_@@_encname_clist {#1}
+ { \clist_gput_right:Nn \g_@@_encname_clist {#1} }
+ \file_input:n { xunicode.sty }
+ \file_input:n { xunicode-extra.def }
+ }
+ { \msg_error:nnn { xunicode-addon } { encoding-unknown } {#1} }
+ }
+\clist_new:N \l_@@_encname_clist
+\msg_new:nnnn { xunicode-addon } { encoding-unknown }
+ { Encoding~scheme~"#1"~unknown. }
+ {
+ You~may~use \\\\
+ \token_to_str:N \usepackage [ #1 , \encodingdefault ] \{fontenc\} \\\\
+ before~xunicode-addon~or~xunicode.
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFmathsymbols}
+% \changes{v3.2.8}{2013/12/04}{修正 \tn{UseMathAsText} 的功能,恢复 \tn{hbar}
+% 和增加以 \texttt{text} 打头的文本符号命令。}
+% 将文本符号定义为 \tn{protected} 宏后,为了与 \pkg{hyperref} 的书签功能兼容
+% 需要作一点额外处理。
+% \begin{macrocode}
+\RenewDocumentCommand \DeclareUTFmathsymbols { m }
+ {
+ \bool_if:NT \l_@@_math_as_UTF_text_bool
+ {
+ \seq_map_inline:Nn \l_@@_math_as_UTF_text_seq
+ { \@@_declare_math_as_UTF_text:n {##1} }
+ \bool_set_false:N \l_@@_math_as_UTF_text_bool
+ }
+ }
+\seq_new:N \l_@@_math_as_UTF_text_seq
+\seq_set_from_clist:Nn \l_@@_math_as_UTF_text_seq
+ { hbar , Finv , aleph , beth , gimel , daleth , Game }
+\bool_new:N \l_@@_math_as_UTF_text_bool
+\RenewDocumentCommand \UseMathAsText { }
+ {
+ \math@s@text@true
+ \bool_set_true:N \l_@@_math_as_UTF_text_bool
+ }
+\@onlypreamble \UseMathAsText
+\cs_new_protected_nopar:Npn \@@_declare_math_as_UTF_text:n #1
+ {
+ \cs_if_exist:cTF {#1}
+ {
+ \cs_new_eq:cc { keepmathUTF #1 } {#1}
+ \cs_gset_protected_nopar:cpx {#1}
+ {
+ \exp_not:N \mode_if_math:TF
+ { \exp_not:c { keepmathUTF #1 } }
+ { \exp_not:c { text #1 } }
+ }
+ \tl_put_right:Nx \l_@@_hyperref_hook_tl
+ { \cs_set_eq:NN \exp_not:c {#1} \exp_not:c { text #1 } }
+ }
+ { \cs_new_nopar:cpx {#1} { \exp_not:c { text #1 } } }
+ }
+\tl_new:N \l_@@_hyperref_hook_tl
+\AtBeginDocument
+ {
+ \cs_if_free:NF \pdfstringdefDisableCommands
+ { \pdfstringdefDisableCommands { \l_@@_hyperref_hook_tl } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\@@_glyph_if_exist:n}
+% 判断字符在当前字体中是否存在。
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_glyph_if_exist:n #1 { p , T , F , TF }
+ {
+ \tex_iffontchar:D \tex_font:D \tex_numexpr:D #1 \scan_stop:
+ \prg_return_true: \else: \prg_return_false: \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\UndeclareUTFcharacter}
+% 取消编码 |#1| 下的符号命令 |#3|。
+% \begin{macrocode}
+\RenewDocumentCommand \UndeclareUTFcharacter { O { \UTFencname } m m }
+ {
+ \@@_if_csname:nTF {#3}
+ { \UndeclareTextCommand {#3} }
+ { \exp_args:Nc \UndeclareTextCommand { \tl_to_str:n {#3} } }
+ {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\UndeclareUTFcomposite}
+% 取消编码 |#1| 下的复合符号命令 |#3{#4}|。
+% \begin{macrocode}
+\RenewDocumentCommand \UndeclareUTFcomposite { O { \UTFencname } m m m }
+ {
+ \@@_if_csname:nTF {#3}
+ { \@@_undeclare_composite:Nnnn #3 }
+ { \exp_args:Nc \@@_undeclare_composite:Nnnn { \tl_to_str:n {#3} } }
+ {#1} {#4} {#2}
+ }
+\cs_new_protected:Npn \@@_undeclare_composite:Nnnn #1#2#3#4
+ { \cs_undefine:c { \@@_composite_cs:Nnn #1 {#2} {#3} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_composite_cs:Nnn,\@@_composite_cs:nnn}
+% \begin{macrocode}
+\cs_new:Npx \@@_composite_cs:Nnn #1#2#3
+ { \c_backslash_str #2 \exp_not:N \token_to_str:N #1 - \exp_not:N \tl_to_str:n {#3} }
+\cs_new:Npx \@@_composite_cs:nnn #1#2#3
+ { \c_backslash_str #2 #1 - \exp_not:N \tl_to_str:n {#3} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_if_csname:nTF}
+% 判断 |#1| 是否可以作为控制序列的名字。这是因为 \pkg{xunicide} 使用了下面的定义。
+% \begin{verbatim}
+% \DeclareUTFcharacter[\UTFencname]{x0149}{'n}
+% \end{verbatim}
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_csname:n #1 { TF }
+ {
+ \tl_if_single_token:nTF {#1}
+ {
+ \token_if_cs:NTF #1
+ { \prg_return_true: }
+ {
+ \token_if_active:NTF #1
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFcharacter}
+% 定义编码 |#1| 下的符号命令 |#3|,其对应符号的 Unicode 是 |#2|。
+% \begin{macrocode}
+\RenewDocumentCommand \DeclareUTFcharacter { O { \UTFencname } m m }
+ {
+ \cs_if_exist_use:cF
+ { @@_restore_ \tl_to_str:n {#3} : }
+ {
+ \@@_if_csname:nTF {#3}
+ { \@@_declare_character:Nnn #3 }
+ { \@@_declare_character:cnn { \tl_to_str:n {#3} } }
+ {#1} {#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_restore_cmd:N}
+% 恢复 \tn{hbar} 和 \tn{nobreakspace} 为原本定义。
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn
+ { @@_restore_ \tl_to_str:n { \hbar } : }
+ { \@@_restore_cmd:N \hbar }
+\cs_new_protected_nopar:cpn
+ { @@_restore_ \tl_to_str:n { \nobreakspace } : }
+ { \@@_restore_cmd:N \nobreakspace }
+\cs_new_protected_nopar:Npn \@@_restore_cmd:N #1
+ { \@@_restore_cmd:Nx #1 { ? - \token_to_str:N #1 } }
+\cs_new_protected_nopar:Npn \@@_restore_cmd:Nn #1#2
+ {
+ \cs_if_free:cF {#2}
+ { \@@_restore_cmd:Nc #1 {#2} }
+ }
+\cs_new_protected_nopar:Npn \@@_restore_cmd:NN #1#2
+ {
+ \cs_gset_eq:NN #1 #2
+ \cs_undefine:N #2
+ }
+\cs_generate_variant:Nn \@@_restore_cmd:Nn { Nx }
+\cs_generate_variant:Nn \@@_restore_cmd:NN { Nc }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_character:Nnn}
+% 通过 \cs{tex_Uchar:D} 直接由 Unicode |#3| 得到编码 |#2| 下的符号命令
+% |#1| 对应的实际字符。\tn{DeclareUTFSymbol} 的参数格式与 \tn{DeclareTextSymbol}
+% 完全一致。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_character:Nnn #1#2#3
+ {
+ \@@_provide_text_command_default:N #1
+ \exp_after:wN \@@_declare_character:NNxn
+ \tex_Uchar:D \@@_check_slot:n {#3} \exp_stop_f:
+ #1 { \token_to_str:N #1 } {#2}
+ }
+\cs_generate_variant:Nn \@@_declare_character:Nnn { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFSymbol,\DeclareUTFCommand}
+% \tn{DeclareUTFCommand} 只能用于定义不带参数的符号命令。
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFSymbol { m O { \UTFencname } m }
+ { \@@_declare_character:Nnn #1 {#2} {#3} }
+\NewDocumentCommand \DeclareUTFCommand { m O { \UTFencname } m }
+ { \@@_text_command:Nonn #1 { \token_to_str:N #1 } {#2} {#3} }
+\cs_new_protected:Npn \@@_text_command:Nnnn #1#2#3#4
+ { \DeclareTextCommand #1 {#3} { \@@_text_command:nn {#2} {#4} } }
+\cs_generate_variant:Nn \@@_text_command:Nnnn { No }
+\cs_new_protected:Npn \@@_text_command:nn #1#2
+ {
+ \@@_begin_hook:nn {#1} {#2}
+ #2
+ \@@_end_hook:nn {#1} {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_provide_text_command_default:N}
+% 如果控制序列 |#1| 已经存在,但不是符号命令,\pkg{xunicode} 会将它定义为
+% \tn{UTFencname} 编码下的符号命令。但是编码被转换之后,再使用这些控制序列,
+% \pkg{NFSS} 就会报错。为此需要给出这些符号命令的默认定义,与原来的意义相同。
+% 这些命令包括
+% \begin{verbatim}
+% \nobreakspace macro:->\protect \nobreakspace
+% \copyright macro:->\protect \copyright
+% \AA macro:->\r A
+% \aa macro:->\r a
+% \textrhookopeno \long macro:->\textrethookbelow {\textopeno }
+% \hbar macro:->{\mathchar '26\mkern -9muh}
+% \textaolig macro:->{a\kern -.25em o}
+% \end{verbatim}
+% 影响比较大的是 \tn{nobreakspace}、\tn{copyright} 和 \tn{hbar}。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_provide_text_command_default:N #1
+ {
+ \cs_if_exist:cF { ? \token_to_str:N #1 }
+ {
+ \cs_if_free:cF { ? - \token_to_str:N #1 }
+ {
+ \exp_args:NNv \ProvideTextCommandDefault #1
+ { ? - \token_to_str:N #1 }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_character:NNnn}
+% 使用编码 |#4| 下的符号命令 |#2| 的时候先判断它对应的实际字符 |#1| 在当前字体中
+% 是否存在。如果不存在则转换到 \tn{DeclareTextSymbolDefault} 中设置的编码或者使用
+% \cs{Declare\-Text\-Command\-Default} 中设置的命令。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_character:NNnn #1#2#3#4
+ { \DeclareTextCommand #2 {#4} { \@@_text_character:nN {#3} {#1} } }
+\cs_new_protected:Npn \@@_text_character:nN #1#2
+ {
+ \@@_begin_hook:nn {#1} {#2}
+ \@@_glyph_if_exist:nTF { `#2 }
+ {#2} { \cs_if_exist_use:cF { ? #1 } {#2} }
+ \@@_end_hook:nn {#1} {#2}
+ }
+\cs_generate_variant:Nn \@@_declare_character:NNnn { NNx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_check_slot:n}
+% \pkg{xunicode} 中使用的 Unicode 格式是诸如 |x0022| 的形式,这就需要一些转换。
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_check_slot:n #1
+ {
+ \int_eval:n
+ {
+ \tl_if_head_eq_charcode:nNTF {#1} x
+ { " \use_none:n #1 } {#1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFcomposite}
+% 设置编码 |#1| 下的符号命令 |#3| 与它的参数 |#4| 的复合对应的符号的 Unicode 是 |#2|。
+% \begin{macrocode}
+\RenewDocumentCommand \DeclareUTFcomposite { O { \UTFencname } m m m }
+ {
+ \@@_if_csname:nTF {#3}
+ { \@@_declare_composite:Nnnn #3 }
+ { \@@_declare_composite:cnnn { \tl_to_str:n {#3} } }
+ {#1} {#4} {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_composite:Nnnn}
+% 这里使用 \cs{tex_afterassignment:D} 是因为 \pkg{xunicode} 有如下的定义。
+% \begin{verbatim}
+% \DeclareUTFcomposite[\UTFencname]{x02E8\char"02E5}{\tonebar}{25}
+% \DeclareUTFcomposite[\UTFencname]{x02E5\char"02E8}{\tonebar}{52}
+% \end{verbatim}
+% 对复合符号命令的定义用的是 \tn{chardef},这有利于下面字符是否存在的判断。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_composite:Nnnn #1#2#3#4
+ {
+ \tex_afterassignment:D \use_none_delimit_by_q_stop:w
+ \@@_chardef:cn { \@@_composite_cs:Nnn #1 {#2} {#3} }
+ { \@@_check_slot:n {#4} }
+ \q_stop
+ }
+\cs_new_protected:Npn \@@_chardef:Nn #1#2
+ { \tex_chardef:D #1 = \tex_numexpr:D #2 \scan_stop: }
+\cs_generate_variant:Nn \@@_chardef:Nn { c }
+\cs_generate_variant:Nn \@@_declare_composite:Nnnn { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFCompositeCommand}
+% 设置编码 |#2| 下的符号命令 |#1| 与它的参数 |#3| 的复合对应结果是 |#4|。不能直接用
+% \cs{Declare\-Text\-Composite\-Command} 来定义,它与我们的机制冲突。
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFCompositeCommand { m O { \UTFencname } m m }
+ { \cs_set_protected:cpn { \@@_composite_cs:Nnn #1 {#2} {#3} } {#4} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFCompositeSymbol}
+% 设置编码 |#2| 下的符号命令 |#1| 与它的参数 |#3| 的复合对应结果是 |#4|。不能直接用
+% \cs{Declare\-Text\-Composite} 来定义,它与我们的机制冲突。
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFCompositeSymbol { m O { \UTFencname } m m }
+ {
+ \@@_chardef:cn { \@@_composite_cs:Nnn #1 {#2} {#3} }
+ { \@@_check_slot:n {#4} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFComposite}
+% 将 |#1| 设置为编码 |#2| 下的带一个参数的复合符号命令。
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFComposite { m O { \UTFencname } }
+ { \use:x { \@@_declare_composite:Nnn \exp_not:N #1 { \token_to_str:N #1 } {#2} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFEncodedAccent}
+% |#1| 是重音命令,|#2| 是编码,|#3| 是组合重音符号的 Unicode,|#4| 是基本重音符号
+% 的 Unicode。当 |#1| 的参数为空时,输出 |#4|,否则是 |#1| 的参数与 |#3| 的组合。
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFEncodedAccent { m O { \UTFencname } m m }
+ { \@@_declare_encoded:NNnnn \@@_combine_accent:nnNNn #1 {#2} {#3} {#4} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFEncodedAccents}
+% |#1| 是重音命令,|#2| 是编码,|#3| 和 |#4| 都是组合重音符号的 Unicode。
+% 输出 |#1| 与 |#3|、|#4| 的组合。
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFEncodedAccents { m O { \UTFencname } m m }
+ { \@@_declare_encoded:NNnnn \@@_combine_accents:nnNNn #1 {#2} {#3} {#4} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFEncodedSymbol}
+% |#1| 是带参数的符号命令,|#2| 是编码,|#3| 是组合符号的 Unicode,|#4| 是基本符号的
+% Unicode。当 |#1| 的参数为空时,输出 |#4|,否则是 |#1| 的参数与 |#3| 的组合。
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFEncodedSymbol { m O { \UTFencname } m m }
+ { \@@_declare_encoded:NNnnn \@@_combine_symbol:nnNNn #1 {#2} {#3} {#4} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFEncodedCircle}
+% |#1| 是带参数的圆圈符号命令,|#2| 是编码,|#3| 是组合圆圈符号的 Unicode,|#4|
+% 是圆圈符号的 Unicode。当 |#1| 的参数为空时,输出 |#4|,否则是 |#1| 的参数与 |#4| 的组合。
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFEncodedCircle { m O { \UTFencname } m m }
+ { \@@_declare_encoded:NNnnn \@@_combine_circle:nnNNn #1 {#2} {#3} {#4} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareEncodedCompositeCharacter}
+% \begin{macrocode}
+\RenewDocumentCommand \DeclareEncodedCompositeCharacter { m m m m }
+ { \DeclareUTFEncodedSymbol #2 [#1] { "#3 } { "0#4 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareEncodedCompositeAccents}
+% \changes{v3.2.9}{2013/12/07}{修正 \pkg{xunicode} 中的错误定义。}
+% \begin{macrocode}
+\RenewDocumentCommand \DeclareEncodedCompositeAccents { m m m m }
+ { \DeclareUTFEncodedAccents #2 [#1] { "#4 } { "#3 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFDoubleEncodedAccent}
+% \changes{v3.2.10}{2014/02/20}{改进 \tn{t} 等的定义方式。}
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFDoubleEncodedAccent { m O { \UTFencname } m m }
+ { \@@_declare_encoded:NNnnn \@@_combine_double_accent:nnNNn #1 {#2} {#3} {#4} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFDoubleEncodedSymbol}
+% \changes{v3.2.10}{2014/02/21}{改进 \tn{sliding} 等的定义方式。}
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFDoubleEncodedSymbol { m O { \UTFencname } m m }
+ { \@@_declare_encoded:NNnnn \@@_combine_double_symbol:nnNNn #1 {#2} {#3} {#4} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_composite:Nnn}
+% 通过 \texttt{lowercase} 技巧,直接由重音符号的 Unicode 得到实际字符。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_composite:Nnn #1#2#3
+ { \DeclareTextCommand #1 {#3} { \@@_text_composite:nnn {#2} {#3} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_text_composite:nnn}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_text_composite:nnn #1#2#3
+ {
+ \@@_begin_hook:nn {#1} {#3}
+ \cs_if_exist:cTF { \@@_composite_cs:nnn {#1} {#2} {#3} }
+ {
+ \@@_text_composite:cnn
+ { \@@_composite_cs:nnn {#1} {#2} {#3} } {#1} {#3}
+ }
+ { \cs_if_exist_use:cTF { ? #1 } { {#3} } {#3} }
+ \@@_end_hook:nn {#1} {#3}
+ }
+\cs_new_protected:Npn \@@_text_composite:Nnn #1#2#3
+ {
+ \token_if_chardef:NTF #1
+ {
+ \@@_glyph_if_exist:nTF {#1}
+ {#1} { \cs_if_exist_use:cTF { ? #2 } { {#3} } {#3} }
+ }
+ {#1}
+ }
+\cs_generate_variant:Nn \@@_text_composite:Nnn { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_declare_encoded:NNnnn}
+% 通过 \cs{tex_Uchar:D} 直接由重音符号的 Unicode 得到实际字符。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_encoded:NNnnn #1#2#3#4#5
+ {
+ \exp_after:wN \@@_declare_encoded:NNNNxx
+ \tex_Uchar:D \@@_check_slot:n {#4} \exp_after:wN \exp_stop_f:
+ \tex_Uchar:D \@@_check_slot:n {#5} \exp_stop_f:
+ #1 #2 { \token_to_str:N #2 } {#3}
+ }
+\cs_new_protected:Npn \@@_declare_encoded:NNNNnn #1#2#3#4#5#6
+ { \DeclareTextCommand #4 {#6} { #3 {#5} {#6} {#1} {#2} } }
+\cs_generate_variant:Nn \@@_declare_encoded:NNnnn { c }
+\cs_generate_variant:Nn \@@_declare_encoded:NNNNnn { NNNNxx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_text_combine:NnnNNn}
+% 若重音命令 |#2| 与它的参数 |#6| 的复合已经由 \tn{DeclareUTFcomposite} 设置,
+% 并且在当前字体中存在该字符,则直接使用。否则使用组合命令。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_text_combine:NnnNNn #1#2#3#4#5#6
+ {
+ \@@_begin_hook:nn {#2} {#6}
+ \cs_if_exist:cTF { \@@_composite_cs:nnn {#2} {#3} {#6} }
+ {
+ \@@_text_combine:cNnNNn
+ { \@@_composite_cs:nnn {#2} {#3} {#6} } #1 {#2} {#4} {#5} {#6}
+ }
+ { #1 {#6} {#2} {#4} {#5} }
+ \@@_end_hook:nn {#2} {#6}
+ }
+\cs_new_protected:Npn \@@_text_combine:NNnNNn #1#2#3#4#5#6
+ {
+ \token_if_chardef:NTF #1
+ { \@@_glyph_if_exist:nTF {#1} {#1} { #2 {#6} {#3} {#4} {#5} } }
+ {#1}
+ }
+\cs_generate_variant:Nn \@@_text_combine:NNnNNn { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_combine_symbol:nnNNn}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_combine_symbol:nnNNn
+ { \@@_text_combine:NnnNNn \@@_add_symbol:nnNN }
+\cs_new_protected:Npn \@@_add_symbol:nnNN #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
+ {
+ \@@_glyph_if_exist:nTF { `#4 }
+ {#4}
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
+ }
+ {
+ \@@_glyph_if_exist:nTF { `#3 }
+ { #1#3 }
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3 } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_combine_accent:nnNNn,\@@_add_accent:nnNN}
+% 若组合重音符号的 |#3| 和基本重音符号 |#4| 在当前字体中都不存在,则转换到
+% \cs{Declare\-Text\-Accent\-Default} 设置的编码或者使用
+% \tn{DeclareTextCommandDefault} 中设置的命令。\texttt{0.9999} 版以前的 \XeTeX
+% 需要设置 \tn{XeTeXinputnormalization} 为 $1$,才能使用字体中由基础字符和组合符号
+% 对应的实际字符;而 \texttt{0.9999} 版以后的 \XeTeX 默认就启用这个功能,^^A
+% \tn{XeTeXinputnormalization} 似乎是无效的,怀疑是使用 HarfBuzz 库替代 ICU 进行
+% 字体排版的缘故\footnote{\url{http://tug.org/pipermail/xetex/2013-July/024579.html}}。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_combine_accent:nnNNn
+ { \@@_text_combine:NnnNNn \@@_add_accent:nnNN }
+\cs_new_protected:Npn \@@_add_accent:nnNN #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
+ {
+ \@@_glyph_if_exist:nTF { `#4 }
+ {#4}
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
+ }
+ {
+ \@@_glyph_if_exist:nTF { `#3 }
+ { #1#3 }
+ {
+ \@@_glyph_if_exist:nTF { `#4 }
+ { \add@accent { `#4 } {#1} }
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3 } }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_combine_accents:nnNNn,\@@_add_accents:nnNN}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_combine_accents:nnNNn
+ { \@@_text_combine:NnnNNn \@@_add_accents:nnNN }
+\cs_new_protected:Npn \@@_add_accents:nnNN #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#1} }
+ {
+ \@@_glyph_if_exist:nTF { `#3 }
+ { \@@_glyph_if_exist:nTF { `#4 } }
+ { \use_ii:nn }
+ { #1#3#4 }
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3#4 } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_combine_circle:nnNNn,\@@_add_circle:nnNN,\@@_add_circle:nN}
+% 对圆圈中的数字或者字母适当缩小,以适合圆圈的大小。只有字体中存在
+% \texttt{U+25EF} 时,才使用这里的设置,否则还还是 \LaTeX\ 中的设置。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_combine_circle:nnNNn
+ { \@@_text_combine:NnnNNn \@@_add_circle:nnNN }
+\cs_new_protected:Npn \@@_add_circle:nnNN #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
+ {
+ \@@_glyph_if_exist:nTF { `#4 }
+ {#4}
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
+ }
+ {
+ \@@_glyph_if_exist:nTF { `#4 }
+ { \@@_add_circle:nN {#1} #4 }
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#1} }
+ }
+ }
+\cs_new_protected:Npn \@@_add_circle:nN #1#2
+ {
+ \hcoffin_set:Nn \l_@@_tmp_coffin {#1}
+ \hcoffin_set:Nn \l_@@_circle_coffin {#2}
+ \fp_set:Nn \l_@@_circle_scale_fp
+ {
+ \dim_to_decimal_in_unit:nn
+ {
+ \fp_use:N \l_@@_circle_ratio_fp
+ \coffin_wd:N \l_@@_circle_coffin
+ }
+ { \coffin_wd:N \l_@@_tmp_coffin }
+ }
+ \coffin_scale:Nnn \l_@@_tmp_coffin
+ { \l_@@_circle_scale_fp } { \l_@@_circle_scale_fp }
+ \coffin_attach:NnnNnnnn
+ \l_@@_circle_coffin { hc } { vc }
+ \l_@@_tmp_coffin { hc } { vc } { \c_zero_dim } { \c_zero_dim }
+ \coffin_typeset:Nnnnn \l_@@_circle_coffin
+ { H } { l } { \c_zero_dim } { \c_zero_dim }
+ }
+\fp_new:N \l_@@_circle_scale_fp
+\coffin_new:N \l_@@_tmp_coffin
+\coffin_new:N \l_@@_circle_coffin
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\settextcircledratio}
+% 设置圆圈中文字的宽度与圆圈宽度的比例,预设为 \texttt{0.7}。
+% \begin{macrocode}
+\NewDocumentCommand \settextcircledratio { m }
+ { \fp_set:Nn \l_@@_circle_ratio_fp {#1} }
+\fp_new:N \l_@@_circle_ratio_fp
+\settextcircledratio { 0.7 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_combine_double_accent:nnNNn}
+% 使 \tn{t} 等组合重音符号放在参数的第一个字母的右边。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_combine_double_accent:nnNNn
+ { \@@_text_combine:NnnNNn \@@_add_double_accent:nnNN }
+\cs_new_protected:Npn \@@_add_double_accent:nnNN #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
+ {
+ \@@_glyph_if_exist:nTF { `#4 }
+ {#4}
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
+ }
+ {
+ \@@_glyph_if_exist:nTF { `#3 }
+ { \@@_add_double_symbol:nN {#1} #3 }
+ {
+ \@@_glyph_if_exist:nTF { `#4 }
+ { \add@accent { `#4 } {#1} }
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3 } }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_combine_double_symbol:nnNNn}
+% 使 \tn{sliding} 等组合重音符号放在参数的第一个字母的右边。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_combine_double_symbol:nnNNn
+ { \@@_text_combine:NnnNNn \@@_add_double_symbol:nnNN }
+\cs_new_protected:Npn \@@_add_double_symbol:nnNN #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
+ {
+ \@@_glyph_if_exist:nTF { `#4 }
+ {#4}
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
+ }
+ {
+ \@@_glyph_if_exist:nTF { `#3 }
+ { \@@_add_double_symbol:nN {#1} #3 }
+ { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3 } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_add_double_symbol:nN}
+% 如果参数的第一个记号是字母类、其它符号类或者由 \tn{chardef} 定义,则将组合符号
+% 放在它的右边,否则不作处理。
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_add_double_symbol:nN #1#2
+ {
+ \tl_if_head_is_N_type:nTF {#1}
+ {
+ \exp_after:wN \exp_after:wN \exp_after:wN
+ \@@_add_double_symbol_aux:NnN \exp_after:wN \exp_after:wN
+ \tl_head:w #1 \q_stop \exp_after:wN { \use_none:n #1 } #2
+ }
+ { #1#2 }
+ }
+\cs_new_protected:Npn \@@_add_double_symbol_aux:NnN #1#2#3
+ {
+ \bool_lazy_any:nTF
+ {
+ { \token_if_letter_p:N #1 }
+ { \token_if_other_p:N #1 }
+ { \token_if_chardef_p:N #1 }
+ }
+ { #1#3#2 }
+ { #1#2#3 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\AtBeginUTFCommand,\AtEndUTFCommand}
+% 设置在符号命令前后使用的钩子,可选参数用于指定单个符号命名。可以用 |#1|
+% 引用带参数的组合符号命令的参数或者符号命令对应的符号。
+% \changes{v3.2.6}{2013/08/15}{可以指定特定符号命令使用的钩子。}
+% \changes{v3.7.1}{2018/04/30}{修复代码重构而引入的新错误。}
+% \begin{macrocode}
+\NewDocumentCommand \AtBeginUTFCommand { s O { } +m }
+ {
+ \tl_if_blank:nTF {#2}
+ {
+ \IfBooleanTF {#1}
+ { \xunadd_set_begin_hook:n }
+ { \xunadd_append_begin_hook:n }
+ }
+ { \xunadd_set_begin_hook:nn {#2} }
+ {#3}
+ }
+\NewDocumentCommand \AtEndUTFCommand { s O { } +m }
+ {
+ \tl_if_blank:nTF {#2}
+ {
+ \IfBooleanTF {#1}
+ { \xunadd_set_end_hook:n }
+ { \xunadd_append_end_hook:n }
+ }
+ { \xunadd_set_end_hook:nn {#2} }
+ {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xunadd_set_begin_hook:n,\xunadd_set_end_hook:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \xunadd_set_begin_hook:n
+ { \tl_set:Nn \l_@@_begin_hook_tl }
+\cs_new_protected_nopar:Npn \xunadd_append_begin_hook:n
+ { \tl_put_right:Nn \l_@@_begin_hook_tl }
+\cs_new_protected_nopar:Npn \xunadd_set_end_hook:n
+ { \tl_set:Nn \l_@@_end_hook_tl }
+\cs_new_protected_nopar:Npn \xunadd_append_end_hook:n
+ { \tl_put_right:Nn \l_@@_end_hook_tl }
+\cs_new_protected_nopar:Npn \xunadd_set_begin_hook:nn
+ { \@@_set_cmd_hook:nnn { begin } }
+\cs_new_protected_nopar:Npn \xunadd_set_end_hook:nn
+ { \@@_set_cmd_hook:nnn { end } }
+\cs_new_protected:Npn \@@_set_cmd_hook:nnn #1#2#3
+ {
+ \cs_set_protected:cpn
+ {
+ \tl_if_single:nTF {#2}
+ { \use:c { @@_#1_csname:n } { \token_to_str:N #2 } }
+ { \@@_set_cmd_hook_aux:Nnwn #2 \q_stop {#1} }
+ } ##1
+ {#3}
+ }
+\cs_new:Npn \@@_set_cmd_hook_aux:Nnwn #1#2 \q_stop #3
+ { \use:c { @@_#3_csname:n } { \token_to_str:N #1 - \tl_to_str:n {#2} } }
+\cs_new_nopar:Npn \@@_begin_csname:n #1 { @@_begin_#1_hook:n }
+\cs_new_nopar:Npn \@@_end_csname:n #1 { @@_end_#1_hook:n }
+\tl_new:N \l_@@_begin_hook_tl
+\tl_new:N \l_@@_end_hook_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_begin_hook:nn,\@@_end_hook:nn}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_begin_hook:nn #1#2
+ {
+ \tl_use:N \l_@@_begin_hook_tl
+ \cs_if_exist_use:cF { \@@_begin_csname:n { #1 - \tl_to_str:n {#2} } }
+ { \cs_if_exist_use:cF { \@@_begin_csname:n {#1} } { \use_none:n } }
+ {#2}
+ }
+\cs_new_protected:Npn \@@_end_hook:nn #1#2
+ {
+ \cs_if_exist_use:cF { \@@_end_csname:n { #1 - \tl_to_str:n {#2} } }
+ { \cs_if_exist_use:cF { \@@_end_csname:n {#1} } { \use_none:n } }
+ {#2}
+ \tl_use:N \l_@@_end_hook_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\DeclareUTFTIPACommand}
+% \changes{v3.2.10}{2014/02/20}{检查 \tn{t} 和 \tn{sliding} 的参数是否以 \tn{textipa} 开头。}
+% \begin{macrocode}
+\NewDocumentCommand \DeclareUTFTIPACommand { O { \UTFencname } m }
+ { \use:x { \@@_text_tipa_command:Nnn \exp_not:N #2 { \token_to_str:N #2 } {#1} } }
+\cs_new_protected:Npn \@@_text_tipa_command:Nnn #1#2#3
+ {
+ \cs_set_eq:cc { UTF/#3#2 } { #3#2 }
+ \DeclareTextCommand #1 {#3} { \@@_text_tipa_command:nnn {#3} {#2} }
+ }
+\cs_new_protected:Npn \@@_text_tipa_command:nnn #1#2#3
+ {
+ \exp_args:Ncc \@@_check_for_tipa:NNn
+ { \use_none:n #2 } { UTF/#1#2 } {#3}
+ }
+\cs_new_protected:Npn \@@_check_for_tipa:NNn #1#2#3
+ {
+ \tl_if_head_eq_meaning:nNTF {#3} \textipa
+ {
+ \exp_after:wN \tipacatchonechar \exp_after:wN
+ { \exp_after:wN #1 \use_none:n #3 }
+ }
+ { #2 {#3} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\xunadd_get_slot:nn}
+% |#1| 是编码,|#2| 是诸如 \tn{textendash} 或 |\v C| 等形式的文本命令,取得他们对应的字符编码。
+% \begin{macrocode}
+\cs_new_protected:Npn \xunadd_get_slot:nn #1#2
+ { \@@_get_slot:wn #2 \q_nil \q_stop {#1} }
+\cs_new_protected:Npn \@@_get_slot:wn #1#2#3 \q_stop #4
+ {
+ \int_set:Nn \l_xunadd_slot_int { -1 }
+ \bool_set_false:N \l_xunadd_rest_bool
+ \group_begin: \exp_args:Nccc \group_end:
+ { @@_get_slot:NNnn }
+ { #4 \token_to_str:N #1 }
+ { \@@_composite_cs:Nnn #1 {#4} {#2} }
+ {#2}
+ {#3}
+ }
+\int_new:N \l_xunadd_slot_int
+\bool_new:N \l_xunadd_rest_bool
+\cs_new_protected:Npn \@@_get_slot:NNnn #1#2#3#4
+ {
+ \cs_if_free:NF #1
+ {
+ \cs_if_exist:NTF #2
+ { \@@_get_composite_slot:Nn #2 {#4} }
+ { \@@_get_character_slot:Nn #1 { #3 #4 } }
+ }
+ }
+\cs_new_protected:Npn \@@_get_composite_slot:Nn #1#2
+ {
+ \token_if_chardef:NT #1
+ {
+ \int_set:Nn \l_xunadd_slot_int {#1}
+ \quark_if_nil:nF {#2}
+ { \bool_set_true:N \l_xunadd_rest_bool }
+ }
+ }
+\cs_new_protected:Npn \@@_get_character_slot:Nn #1
+ {
+ \exp_after:wN \@@_get_character_slot_aux:wn #1
+ \@@_text_character:nN \q_nil \q_nil \q_stop
+ }
+\cs_new_protected:Npn \@@_get_character_slot_aux:wn
+ #1 \@@_text_character:nN #2#3#4 \q_stop #5
+ {
+ \quark_if_nil:nF {#2}
+ {
+ \int_set:Nn \l_xunadd_slot_int { `#3 }
+ \quark_if_nil:nF {#5}
+ { \bool_set_true:N \l_xunadd_rest_bool }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.7.2}{2018/05/12}{解决与 \pkg{microtype} 宏包的兼容问题。}
+%
+% \begin{macro}[int]{\xunadd@microtype@is@charx}
+% \pkg{microtype} 宏包中使用的函数,我们通过对 \tn{MT@is@charx} 打补丁来实现功能。
+% \begin{macrocode}
+\cs_new_protected:Npn \xunadd@microtype@is@charx #1 \relax
+ {
+ \use:x
+ { \xunadd_get_slot:nn { \MT@encoding } { \tex_the:D \MT@toks } }
+ \int_compare:nNnTF \l_xunadd_slot_int < \c_zero_int
+ { \xunadd@original@is@charx #1 \relax }
+ {
+ \cs_set_nopar:Npx \MT@char@ { \int_use:N \l_xunadd_slot_int }
+ \bool_if:NT \l_xunadd_rest_bool { \MT@norestfalse }
+ }
+ }
+\AtBeginDocument
+ {
+ \cs_if_free:NF \MT@is@charx
+ {
+ \cs_new_eq:NN \xunadd@original@is@charx \MT@is@charx
+ \cs_set_eq:NN \MT@is@charx \xunadd@microtype@is@charx
+ \cs_set_eq:NN \MT@warn@unknown@once \use_none:n
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.2.8}{2013/12/05}{启用 \pkg{xunicode} 中的带圈数字和字母设置。}
+%
+% \begin{macrocode}
+%</xunicode>
+%<*xunextra>
+% \end{macrocode}
+%
+% \changes{v3.7.0}{2018/03/16}{补充定义 \tn{texthyphenationpoint} 和 \tn{texttwoemdash}。}
+%
+% 我们补充定义 HYPHENATION POINT 和 TWO-EM DASH,他们默认被归入 CJK 标点符号。
+% \begin{macrocode}
+\DeclareUTFSymbol\texthyphenationpoint{"2027}
+\DeclareUTFSymbol\texttwoemdash{"2E3A}
+% \end{macrocode}
+%
+% 以下内容选自 \pkg{xunicode},并做了适当修改。
+% \begin{macrocode}
+\DeclareUTFComposite\textsuperscript
+\DeclareUTFComposite\textsubscript
+\DeclareUTFEncodedAccent\textsbleftarrow{"20EE}{"20FF}
+\DeclareUTFEncodedAccent\`{"0300}{"02CB}
+\DeclareUTFEncodedAccent\capitalgrave{"0300}{"02CB}
+\DeclareUTFEncodedAccent\'{"0301}{"02CA}
+\DeclareUTFEncodedAccent\capitalacute{"0301}{"02CA}
+\DeclareUTFEncodedAccent\^{"0302}{"02C6}
+\DeclareUTFEncodedAccent\capitalcircumflex{"0302}{"02C6}
+\DeclareUTFEncodedAccent\~{"0303}{"02DC}
+\DeclareUTFEncodedAccent\capitaltilde{"0303}{"02DC}
+\DeclareUTFEncodedAccent\={"0304}{"02C9}
+\DeclareUTFEncodedAccent\capitalmacron{"0304}{"02C9}
+\DeclareUTFEncodedAccent\textoverline{"0305}{"203E}
+\DeclareUTFEncodedAccent\u{"0306}{"02D8}
+\DeclareUTFEncodedAccent\capitalbreve{"0306}{"02D8}
+\DeclareUTFEncodedAccent\.{"0307}{"02D9}
+\DeclareUTFEncodedAccent\capitaldotaccent{"0307}{"02D9}
+\DeclareUTFEncodedAccent\"{"0308}{"00A8}
+\DeclareUTFEncodedAccent\capitaldieresis{"0308}{"00A8}
+\DeclareUTFEncodedAccent\m{"0309}{"0309}
+\DeclareUTFEncodedAccent\texthookabove{"0309}{"0309}
+\DeclareUTFEncodedAccent\r{"030A}{"02DA}
+\DeclareUTFEncodedAccent\capitalring{"030A}{"02DA}
+\DeclareUTFEncodedAccent\H{"030B}{"02DD}
+\DeclareUTFEncodedAccent\capitalhungarumlaut{"030B}{"02DD}
+\DeclareUTFEncodedAccent\v{"030C}{"02C7}
+\DeclareUTFEncodedAccent\capitalcaron{"030C}{"02C7}
+\DeclareUTFEncodedAccent\textvbaraccent{"030D}{"02C8}
+\DeclareUTFEncodedAccent\textdoublevbaraccent{"030E}{"0022}
+\DeclareUTFEncodedAccent\U{"030E}{"0022}
+\DeclareUTFEncodedAccent\textdoublegrave{"030F}{"02F5}
+\DeclareUTFEncodedAccent\G{"030F}{"02F5}
+\DeclareUTFEncodedAccent\textdotbreve{"0310}{"0310}
+\DeclareUTFEncodedAccent\textroundcap{"0311}{"0311}
+\DeclareUTFEncodedAccent\newtie{"0311}{"0311}
+\DeclareUTFEncodedAccent\capitalnewtie{"0311}{"0311}
+\DeclareUTFEncodedAccent\textturncommaabove{"0312}{"02BB}
+\DeclareUTFEncodedAccent\textcommaabove{"0313}{"02BC}
+\DeclareUTFEncodedAccent\textrevcommaabove{"0314}{"02BD}
+\DeclareUTFEncodedAccent\overbridge{"0346}{"0346}
+\DeclareUTFEncodedAccent\crtilde{"034A}{"034A}
+\DeclareUTFEncodedAccent\dottedtilde{"034B}{"034B}
+\DeclareUTFEncodedAccent\doubletilde{"034C}{"034C}
+\DeclareUTFEncodedAccent\textrightarrowhead{"0350}{"02C3}
+\DeclareUTFEncodedAccent\textlefthalfring{"0351}{"02D3}
+\DeclareUTFEncodedAccent\textrighthalfring{"0357}{"02D2}
+\DeclareUTFDoubleEncodedSymbol\textdoublebrevebelow{"035C}{"035C}
+\DeclareUTFDoubleEncodedAccent\textdoublebreve{"035D}{"035D}
+\DeclareUTFDoubleEncodedAccent\textdoublemacron{"035E}{"035E}
+\DeclareUTFDoubleEncodedSymbol\textdoublemacronbelow{"035F}{"035F}
+\DeclareUTFDoubleEncodedAccent\textdoubletilde{"0360}{"0360}
+\DeclareUTFDoubleEncodedAccent\t{"0361}{"0361}
+\DeclareUTFDoubleEncodedAccent\capitaltie{"0361}{"0361}
+\DeclareUTFDoubleEncodedAccent\texttoptiebar{"0361}{"0361}
+\DeclareUTFDoubleEncodedSymbol\sliding{"0362}{"0362}
+\DeclareUTFTIPACommand\t
+\DeclareUTFTIPACommand\capitaltie
+\DeclareUTFTIPACommand\texttoptiebar
+\DeclareUTFTIPACommand\sliding
+\DeclareUTFEncodedAccent\texthighrise{"1DC4}{"1DC4}
+\DeclareUTFEncodedAccent\textlowrise{"1DC5}{"1DC5}
+\DeclareUTFEncodedAccent\textrisefall{"1DC8}{"1DC8}
+\DeclareUTFEncodedAccent\textfallrise{"1DC9}{"1DC9}
+\DeclareUTFEncodedAccent\textaolig{"1DD5}{"1DD5}
+\DeclareUTFCompositeSymbol\textundertie{H}{"1E2A}
+\DeclareUTFCompositeSymbol\textundertie{h}{"1E2B}
+\DeclareUTFEncodedAccents\textcircumgrave{"0302}{"0301}
+\DeclareUTFSymbol\textFinv{"2132}
+\DeclareUTFSymbol\textaleph{"2135}
+\DeclareUTFSymbol\textbeth{"2136}
+\DeclareUTFSymbol\textgimel{"2137}
+\DeclareUTFSymbol\textdaleth{"2138}
+\DeclareUTFSymbol\textGame{"2141}
+\DeclareUTFCompositeCommand\tonebar{25}{\tonebar{2}\tonebar{5}}
+\DeclareUTFCompositeCommand\tonebar{52}{\tonebar{5}\tonebar{2}}
+\DeclareUTFSymbol\textbigcircle{"25EF}
+\DeclareUTFEncodedCircle\textcircled{"20DD}{"25EF}
+\DeclareUTFCompositeSymbol\textcircled{0}{"24EA}
+\DeclareUTFCompositeSymbol\textcircled{1}{"2460}
+\DeclareUTFCompositeSymbol\textcircled{2}{"2461}
+\DeclareUTFCompositeSymbol\textcircled{3}{"2462}
+\DeclareUTFCompositeSymbol\textcircled{4}{"2463}
+\DeclareUTFCompositeSymbol\textcircled{5}{"2464}
+\DeclareUTFCompositeSymbol\textcircled{6}{"2465}
+\DeclareUTFCompositeSymbol\textcircled{7}{"2466}
+\DeclareUTFCompositeSymbol\textcircled{8}{"2467}
+\DeclareUTFCompositeSymbol\textcircled{9}{"2468}
+\DeclareUTFCompositeSymbol\textcircled{10}{"2469}
+\DeclareUTFCompositeSymbol\textcircled{11}{"246A}
+\DeclareUTFCompositeSymbol\textcircled{12}{"246B}
+\DeclareUTFCompositeSymbol\textcircled{13}{"246C}
+\DeclareUTFCompositeSymbol\textcircled{14}{"246D}
+\DeclareUTFCompositeSymbol\textcircled{15}{"246E}
+\DeclareUTFCompositeSymbol\textcircled{16}{"246F}
+\DeclareUTFCompositeSymbol\textcircled{17}{"2470}
+\DeclareUTFCompositeSymbol\textcircled{18}{"2471}
+\DeclareUTFCompositeSymbol\textcircled{19}{"2472}
+\DeclareUTFCompositeSymbol\textcircled{20}{"2473}
+\DeclareUTFCompositeSymbol\textcircled{21}{"3251}
+\DeclareUTFCompositeSymbol\textcircled{22}{"3252}
+\DeclareUTFCompositeSymbol\textcircled{23}{"3253}
+\DeclareUTFCompositeSymbol\textcircled{24}{"3254}
+\DeclareUTFCompositeSymbol\textcircled{25}{"3255}
+\DeclareUTFCompositeSymbol\textcircled{26}{"3256}
+\DeclareUTFCompositeSymbol\textcircled{27}{"3257}
+\DeclareUTFCompositeSymbol\textcircled{28}{"3258}
+\DeclareUTFCompositeSymbol\textcircled{29}{"3259}
+\DeclareUTFCompositeSymbol\textcircled{30}{"325A}
+\DeclareUTFCompositeSymbol\textcircled{31}{"325B}
+\DeclareUTFCompositeSymbol\textcircled{32}{"325C}
+\DeclareUTFCompositeSymbol\textcircled{33}{"325D}
+\DeclareUTFCompositeSymbol\textcircled{34}{"325E}
+\DeclareUTFCompositeSymbol\textcircled{35}{"325F}
+\DeclareUTFCompositeSymbol\textcircled{36}{"32B1}
+\DeclareUTFCompositeSymbol\textcircled{37}{"32B2}
+\DeclareUTFCompositeSymbol\textcircled{38}{"32B3}
+\DeclareUTFCompositeSymbol\textcircled{39}{"32B4}
+\DeclareUTFCompositeSymbol\textcircled{40}{"32B5}
+\DeclareUTFCompositeSymbol\textcircled{41}{"32B6}
+\DeclareUTFCompositeSymbol\textcircled{42}{"32B7}
+\DeclareUTFCompositeSymbol\textcircled{43}{"32B8}
+\DeclareUTFCompositeSymbol\textcircled{44}{"32B9}
+\DeclareUTFCompositeSymbol\textcircled{45}{"32BA}
+\DeclareUTFCompositeSymbol\textcircled{46}{"32BB}
+\DeclareUTFCompositeSymbol\textcircled{47}{"32BC}
+\DeclareUTFCompositeSymbol\textcircled{48}{"32BD}
+\DeclareUTFCompositeSymbol\textcircled{49}{"32BE}
+\DeclareUTFCompositeSymbol\textcircled{50}{"32BF}
+\DeclareUTFCompositeSymbol\textcircled{A}{"24B6}
+\DeclareUTFCompositeSymbol\textcircled{B}{"24B7}
+\DeclareUTFCompositeSymbol\textcircled{C}{"24B8}
+\DeclareUTFCompositeSymbol\textcircled{D}{"24B9}
+\DeclareUTFCompositeSymbol\textcircled{E}{"24BA}
+\DeclareUTFCompositeSymbol\textcircled{F}{"24BB}
+\DeclareUTFCompositeSymbol\textcircled{G}{"24BC}
+\DeclareUTFCompositeSymbol\textcircled{H}{"24BD}
+\DeclareUTFCompositeSymbol\textcircled{I}{"24BE}
+\DeclareUTFCompositeSymbol\textcircled{J}{"24BF}
+\DeclareUTFCompositeSymbol\textcircled{K}{"24C0}
+\DeclareUTFCompositeSymbol\textcircled{L}{"24C1}
+\DeclareUTFCompositeSymbol\textcircled{M}{"24C2}
+\DeclareUTFCompositeSymbol\textcircled{N}{"24C3}
+\DeclareUTFCompositeSymbol\textcircled{O}{"24C4}
+\DeclareUTFCompositeSymbol\textcircled{P}{"24C5}
+\DeclareUTFCompositeSymbol\textcircled{Q}{"24C6}
+\DeclareUTFCompositeSymbol\textcircled{R}{"24C7}
+\DeclareUTFCompositeSymbol\textcircled{S}{"24C8}
+\DeclareUTFCompositeSymbol\textcircled{T}{"24C9}
+\DeclareUTFCompositeSymbol\textcircled{U}{"24CA}
+\DeclareUTFCompositeSymbol\textcircled{V}{"24CB}
+\DeclareUTFCompositeSymbol\textcircled{W}{"24CC}
+\DeclareUTFCompositeSymbol\textcircled{X}{"24CD}
+\DeclareUTFCompositeSymbol\textcircled{Y}{"24CE}
+\DeclareUTFCompositeSymbol\textcircled{Z}{"24CF}
+\DeclareUTFCompositeSymbol\textcircled{a}{"24D0}
+\DeclareUTFCompositeSymbol\textcircled{b}{"24D1}
+\DeclareUTFCompositeSymbol\textcircled{c}{"24D2}
+\DeclareUTFCompositeSymbol\textcircled{d}{"24D3}
+\DeclareUTFCompositeSymbol\textcircled{e}{"24D4}
+\DeclareUTFCompositeSymbol\textcircled{f}{"24D5}
+\DeclareUTFCompositeSymbol\textcircled{g}{"24D6}
+\DeclareUTFCompositeSymbol\textcircled{h}{"24D7}
+\DeclareUTFCompositeSymbol\textcircled{i}{"24D8}
+\DeclareUTFCompositeSymbol\textcircled{j}{"24D9}
+\DeclareUTFCompositeSymbol\textcircled{k}{"24DA}
+\DeclareUTFCompositeSymbol\textcircled{l}{"24DB}
+\DeclareUTFCompositeSymbol\textcircled{m}{"24DC}
+\DeclareUTFCompositeSymbol\textcircled{n}{"24DD}
+\DeclareUTFCompositeSymbol\textcircled{o}{"24DE}
+\DeclareUTFCompositeSymbol\textcircled{p}{"24DF}
+\DeclareUTFCompositeSymbol\textcircled{q}{"24E0}
+\DeclareUTFCompositeSymbol\textcircled{r}{"24E1}
+\DeclareUTFCompositeSymbol\textcircled{s}{"24E2}
+\DeclareUTFCompositeSymbol\textcircled{t}{"24E3}
+\DeclareUTFCompositeSymbol\textcircled{u}{"24E4}
+\DeclareUTFCompositeSymbol\textcircled{v}{"24E5}
+\DeclareUTFCompositeSymbol\textcircled{w}{"24E6}
+\DeclareUTFCompositeSymbol\textcircled{x}{"24E7}
+\DeclareUTFCompositeSymbol\textcircled{y}{"24E8}
+\DeclareUTFCompositeSymbol\textcircled{z}{"24E9}
+\DeclareUTFCompositeSymbol\textsuperscript{h}{"02B0}
+\DeclareUTFCompositeSymbol\textsuperscript{\texthth}{"02B1}
+\DeclareUTFCompositeSymbol\textsuperscript{j}{"02B2}
+\DeclareUTFCompositeSymbol\textsuperscript{r}{"02B3}
+\DeclareUTFCompositeSymbol\textsuperscript{\textturnr}{"02B4}
+\DeclareUTFCompositeSymbol\textsuperscript{\textturnrrtail}{"02B5}
+\DeclareUTFCompositeSymbol\textsuperscript{\textinvscr}{"02B6}
+\DeclareUTFCompositeSymbol\textsuperscript{w}{"02B7}
+\DeclareUTFCompositeSymbol\textsuperscript{y}{"02B8}
+\DeclareUTFCompositeSymbol\textsuperscript{\textbabygamma}{"02E0}
+\DeclareUTFCompositeSymbol\textsuperscript{\textgammalatinsmall}{"02E0}
+\DeclareUTFCompositeSymbol\textsuperscript{l}{"02E1}
+\DeclareUTFCompositeSymbol\textsuperscript{s}{"02E2}
+\DeclareUTFCompositeSymbol\textsuperscript{x}{"02E3}
+\DeclareUTFCompositeSymbol\textsuperscript{\textrevglotstop}{"02E4}
+\DeclareUTFCompositeSymbol\textsuperscript{\textrevepsilon}{"1D4C}
+\DeclareUTFCompositeSymbol\textsuperscript{\cyrn}{"1D78}
+\DeclareUTFCompositeSymbol\textsuperscript{\textbarsci}{"1DA7}
+\DeclareUTFCompositeSymbol\textsuperscript{V}{"2C7D}
+\DeclareUTFCompositeSymbol\textsuperscript{\textHbar}{"A7F8}
+\DeclareUTFCompositeSymbol\textsuperscript{\textHslash}{"A7F8}
+\DeclareUTFCompositeSymbol\textsuperscript{\oe}{"A7F9}
+\DeclareUTFCompositeSymbol\textsubscript{h}{"2095}
+\DeclareUTFCompositeSymbol\textsubscript{k}{"2096}
+\DeclareUTFCompositeSymbol\textsubscript{l}{"2097}
+\DeclareUTFCompositeSymbol\textsubscript{m}{"2098}
+\DeclareUTFCompositeSymbol\textsubscript{n}{"2099}
+\DeclareUTFCompositeSymbol\textsubscript{p}{"209A}
+\DeclareUTFCompositeSymbol\textsubscript{s}{"209B}
+\DeclareUTFCompositeSymbol\textsubscript{t}{"209C}
+% \end{macrocode}
+%
+% \changes{v3.2.9}{2013/12/07}
+% {增加 \file{xunicode-extra.def} 中,用于加入 \file{puenc.def} 中的符号定义。}
+%
+% 以下定义取自 \pkg{hyperref} 的 \file{puenc.def}。
+% \begin{macrocode}
+\DeclareUTFEncodedAccent\textinvbreve{"0311}{"0311}
+\DeclareUTFEncodedSymbol\textsubbreve{"032E}{"203F}
+\DeclareUTFSymbol\textHT{"0009}
+\DeclareUTFSymbol\textLF{"000A}
+\DeclareUTFSymbol\textCR{"000D}
+\DeclareUTFSymbol\textnumbersign{"0023}
+\DeclareUTFSymbol\textparenleft{"0028}
+\DeclareUTFSymbol\textparenright{"0029}
+\DeclareUTFSymbol\textMVPlus{"002B}
+\DeclareUTFSymbol\textMVComma{"002C}
+\DeclareUTFSymbol\textMVMinus{"002D}
+\DeclareUTFSymbol\textMVPeriod{"002E}
+\DeclareUTFSymbol\textMVDivision{"002F}
+\DeclareUTFSymbol\textMVZero{"0030}
+\DeclareUTFSymbol\textMVOne{"0031}
+\DeclareUTFSymbol\textMVTwo{"0032}
+\DeclareUTFSymbol\textMVThree{"0033}
+\DeclareUTFSymbol\textMVFour{"0034}
+\DeclareUTFSymbol\textMVFive{"0035}
+\DeclareUTFSymbol\textMVSix{"0036}
+\DeclareUTFSymbol\textMVSeven{"0037}
+\DeclareUTFSymbol\textMVEight{"0038}
+\DeclareUTFSymbol\textMVNine{"0039}
+\DeclareUTFSymbol\textMVAt{"0040}
+\DeclareUTFCompositeCommand\.{\i}{i}
+\DeclareUTFCompositeCommand\.{i}{i}
+\DeclareUTFSymbol\textlnot{"00AC}
+\DeclareUTFSymbol\textplusminus{"00B1}
+\DeclareUTFSymbol\textcedilla{"00B8}
+\DeclareUTFSymbol\textmultiply{"00D7}
+\DeclareUTFSymbol\textThorn{"00DE}
+\DeclareUTFSymbol\textdivide{"00F7}
+\DeclareUTFSymbol\textHslash{"0126}
+\DeclareUTFCompositeSymbol\k{\i}{"012F}
+\DeclareUTFCompositeSymbol\.{L}{"013F}
+\DeclareUTFCompositeSymbol\.{l}{"0140}
+\DeclareUTFSymbol\textnapostrophe{"0149}
+\DeclareUTFSymbol\textTslash{"0166}
+\DeclareUTFSymbol\texttslash{"0167}
+\DeclareUTFSymbol\textlongs{"017F}
+\DeclareUTFSymbol\texthausaB{"0181}
+\DeclareUTFSymbol\texthausaD{"018A}
+\DeclareUTFSymbol\textrevE{"018E}
+\DeclareUTFSymbol\texthausaK{"0198}
+\DeclareUTFSymbol\textPUnrleg{"019E}
+\DeclareUTFSymbol\textinve{"01DD}
+\DeclareUTFSymbol\textGslash{"01E4}
+\DeclareUTFSymbol\textgslash{"01E5}
+\DeclareUTFCompositeSymbol\textinvbreve{E}{"0206}
+\DeclareUTFCompositeSymbol\textinvbreve{e}{"0207}
+\DeclareUTFCompositeSymbol\textinvbreve{I}{"020A}
+\DeclareUTFCompositeSymbol\textinvbreve{i}{"020B}
+\DeclareUTFCompositeSymbol\textinvbreve{\i}{"020B}
+\DeclareUTFCompositeSymbol\textinvbreve{O}{"020E}
+\DeclareUTFCompositeSymbol\textinvbreve{o}{"020F}
+\DeclareUTFCompositeSymbol\textinvbreve{U}{"0216}
+\DeclareUTFCompositeSymbol\textinvbreve{u}{"0217}
+\DeclareUTFSymbol\j{"0237}
+\DeclareUTFSymbol\textPUdblig{"0238}
+\DeclareUTFSymbol\textPUqplig{"0239}
+\DeclareUTFSymbol\textslashc{"023C}
+\DeclareUTFSymbol\textniepsilon{"025B}
+\DeclareUTFSymbol\textipagamma{"0263}
+\DeclareUTFSymbol\textniiota{"0269}
+\DeclareUTFSymbol\textniphi{"0278}
+\DeclareUTFSymbol\textniupsilon{"028A}
+\DeclareUTFSymbol\textring{"02DA}
+\DeclareUTFSymbol\texttilde{"02DC}
+\DeclareUTFSymbol\texthungarumlaut{"02DD}
+\DeclareUTFSymbol\textringlow{"02F3}
+\DeclareUTFSymbol\texttildelow{"02F7}
+\DeclareUTFCommand\textnewtie{\textinvbreve\ }
+\DeclareUTFCommand\textdotbelow{\d\ }
+\DeclareUTFSymbol\textmacronbelow{"02CD}
+\DeclareUTFCommand\texttie{\t\ }
+\DeclareUTFSymbol\textnumeralsigngreek{"0374}
+\DeclareUTFSymbol\textnumeralsignlowergreek{"0375}
+\DeclareUTFCompositeSymbol\'{\textAlpha}{"0386}
+\DeclareUTFCompositeSymbol\'{\textEpsilon}{"0388}
+\DeclareUTFCompositeSymbol\'{\textEta}{"0389}
+\DeclareUTFCompositeSymbol\'{\textIota}{"038A}
+\DeclareUTFCompositeSymbol\'{\textOmicron}{"038C}
+\DeclareUTFCompositeSymbol\'{\textUpsilon}{"038E}
+\DeclareUTFCompositeSymbol\'{\textOmega}{"038F}
+\DeclareUTFCompositeSymbol\'{\textIotadieresis}{"0390}
+\DeclareUTFSymbol\textIotadieresis{"03AA}
+\DeclareUTFCompositeSymbol\"{\textIota}{"03AA}
+\DeclareUTFCompositeSymbol\"{\textUpsilon}{"03AB}
+\DeclareUTFCompositeSymbol\'{\textalpha}{"03AC}
+\DeclareUTFCompositeSymbol\'{\textepsilon}{"03AD}
+\DeclareUTFCompositeSymbol\'{\texteta}{"03AE}
+\DeclareUTFCompositeSymbol\'{\textiota}{"03AF}
+\DeclareUTFCompositeSymbol\"{\textupsilonacute}{"03B0}
+\DeclareUTFSymbol\textmugreek{"03BC}
+\DeclareUTFSymbol\textvarsigma{"03C2}
+\DeclareUTFCompositeSymbol\"{\textiota}{"03CA}
+\DeclareUTFCompositeSymbol\"{\textupsilon}{"03CB}
+\DeclareUTFCompositeSymbol\'{\textomicron}{"03CC}
+\DeclareUTFSymbol\textupsilonacute{"03CD}
+\DeclareUTFCompositeSymbol\'{\textupsilon}{"03CD}
+\DeclareUTFCompositeSymbol\'{\textomega}{"03CE}
+\DeclareUTFSymbol\textStigmagreek{"03DA}
+\DeclareUTFSymbol\textstigmagreek{"03DB}
+\DeclareUTFSymbol\textDigammagreek{"03DC}
+\DeclareUTFSymbol\textdigammagreek{"03DD}
+\DeclareUTFSymbol\textKoppagreek{"03DE}
+\DeclareUTFSymbol\textkoppagreek{"03DF}
+\DeclareUTFSymbol\textSampigreek{"03E0}
+\DeclareUTFSymbol\textsampigreek{"03E1}
+\DeclareUTFSymbol\textbackepsilon{"03F6}
+\DeclareUTFCompositeSymbol\`{\CYRE}{"0400}
+\DeclareUTFSymbol\CYRYO{"0401}
+\DeclareUTFCompositeSymbol\"{\CYRE}{"0401}
+\DeclareUTFSymbol\CYRDJE{"0402}
+\DeclareUTFCompositeSymbol\'{\CYRG}{"0403}
+\DeclareUTFSymbol\CYRIE{"0404}
+\DeclareUTFSymbol\CYRDZE{"0405}
+\DeclareUTFSymbol\CYRII{"0406}
+\DeclareUTFSymbol\CYRYI{"0407}
+\DeclareUTFCompositeSymbol\"{\CYRII}{"0407}
+\DeclareUTFSymbol\CYRJE{"0408}
+\DeclareUTFSymbol\CYRLJE{"0409}
+\DeclareUTFSymbol\CYRNJE{"040A}
+\DeclareUTFSymbol\CYRTSHE{"040B}
+\DeclareUTFCompositeSymbol\'{\CYRK}{"040C}
+\DeclareUTFCompositeSymbol\`{\CYRI}{"040D}
+\DeclareUTFSymbol\CYRUSHRT{"040E}
+\DeclareUTFCompositeSymbol\U{\CYRU}{"040E}
+\DeclareUTFSymbol\CYRDZHE{"040F}
+\DeclareUTFSymbol\CYRA{"0410}
+\DeclareUTFSymbol\CYRB{"0411}
+\DeclareUTFSymbol\CYRV{"0412}
+\DeclareUTFSymbol\CYRG{"0413}
+\DeclareUTFSymbol\CYRD{"0414}
+\DeclareUTFSymbol\CYRE{"0415}
+\DeclareUTFSymbol\CYRZH{"0416}
+\DeclareUTFSymbol\CYRZ{"0417}
+\DeclareUTFSymbol\CYRI{"0418}
+\DeclareUTFSymbol\CYRISHRT{"0419}
+\DeclareUTFCompositeSymbol\U{\CYRI}{"0419}
+\DeclareUTFSymbol\CYRK{"041A}
+\DeclareUTFSymbol\CYRL{"041B}
+\DeclareUTFSymbol\CYRM{"041C}
+\DeclareUTFSymbol\CYRN{"041D}
+\DeclareUTFSymbol\CYRO{"041E}
+\DeclareUTFSymbol\CYRP{"041F}
+\DeclareUTFSymbol\CYRR{"0420}
+\DeclareUTFSymbol\CYRS{"0421}
+\DeclareUTFSymbol\CYRT{"0422}
+\DeclareUTFSymbol\CYRU{"0423}
+\DeclareUTFSymbol\CYRF{"0424}
+\DeclareUTFSymbol\CYRH{"0425}
+\DeclareUTFSymbol\CYRC{"0426}
+\DeclareUTFSymbol\CYRCH{"0427}
+\DeclareUTFSymbol\CYRSH{"0428}
+\DeclareUTFSymbol\CYRSHCH{"0429}
+\DeclareUTFSymbol\CYRHRDSN{"042A}
+\DeclareUTFSymbol\CYRERY{"042B}
+\DeclareUTFSymbol\CYRSFTSN{"042C}
+\DeclareUTFSymbol\CYREREV{"042D}
+\DeclareUTFSymbol\CYRYU{"042E}
+\DeclareUTFSymbol\CYRYA{"042F}
+\DeclareUTFSymbol\cyra{"0430}
+\DeclareUTFSymbol\cyrb{"0431}
+\DeclareUTFSymbol\cyrv{"0432}
+\DeclareUTFSymbol\cyrg{"0433}
+\DeclareUTFSymbol\cyrd{"0434}
+\DeclareUTFSymbol\cyre{"0435}
+\DeclareUTFSymbol\cyrzh{"0436}
+\DeclareUTFSymbol\cyrz{"0437}
+\DeclareUTFSymbol\cyri{"0438}
+\DeclareUTFSymbol\cyrishrt{"0439}
+\DeclareUTFCompositeSymbol\U{\cyri}{"0439}
+\DeclareUTFSymbol\cyrk{"043A}
+\DeclareUTFSymbol\cyrl{"043B}
+\DeclareUTFSymbol\cyrm{"043C}
+\DeclareUTFSymbol\cyrn{"043D}
+\DeclareUTFSymbol\cyro{"043E}
+\DeclareUTFSymbol\cyrp{"043F}
+\DeclareUTFSymbol\cyrr{"0440}
+\DeclareUTFSymbol\cyrs{"0441}
+\DeclareUTFSymbol\cyrt{"0442}
+\DeclareUTFSymbol\cyru{"0443}
+\DeclareUTFSymbol\cyrf{"0444}
+\DeclareUTFSymbol\cyrh{"0445}
+\DeclareUTFSymbol\cyrc{"0446}
+\DeclareUTFSymbol\cyrch{"0447}
+\DeclareUTFSymbol\cyrsh{"0448}
+\DeclareUTFSymbol\cyrshch{"0449}
+\DeclareUTFSymbol\cyrhrdsn{"044A}
+\DeclareUTFSymbol\cyrery{"044B}
+\DeclareUTFSymbol\cyrsftsn{"044C}
+\DeclareUTFSymbol\cyrerev{"044D}
+\DeclareUTFSymbol\cyryu{"044E}
+\DeclareUTFSymbol\cyrya{"044F}
+\DeclareUTFCompositeSymbol\`{\cyre}{"0450}
+\DeclareUTFSymbol\cyryo{"0451}
+\DeclareUTFCompositeSymbol\"{\cyre}{"0451}
+\DeclareUTFSymbol\cyrdje{"0452}
+\DeclareUTFCompositeSymbol\'{\cyrg}{"0453}
+\DeclareUTFSymbol\cyrie{"0454}
+\DeclareUTFSymbol\cyrdze{"0455}
+\DeclareUTFSymbol\cyrii{"0456}
+\DeclareUTFSymbol\cyryi{"0457}
+\DeclareUTFCompositeSymbol\"{\cyrii}{"0457}
+\DeclareUTFSymbol\cyrje{"0458}
+\DeclareUTFSymbol\cyrlje{"0459}
+\DeclareUTFSymbol\cyrnje{"045A}
+\DeclareUTFSymbol\cyrtshe{"045B}
+\DeclareUTFCompositeSymbol\'{\cyrk}{"045C}
+\DeclareUTFCompositeSymbol\`{\cyri}{"045D}
+\DeclareUTFSymbol\cyrushrt{"045E}
+\DeclareUTFCompositeSymbol\U{\curu}{"045E}
+\DeclareUTFSymbol\cyrdzhe{"045F}
+\DeclareUTFSymbol\CYROMEGA{"0460}
+\DeclareUTFSymbol\cyromega{"0461}
+\DeclareUTFSymbol\CYRYAT{"0462}
+\DeclareUTFSymbol\cyryat{"0463}
+\DeclareUTFSymbol\CYRIOTE{"0464}
+\DeclareUTFSymbol\cyriote{"0465}
+\DeclareUTFSymbol\CYRLYUS{"0466}
+\DeclareUTFSymbol\cyrlyus{"0467}
+\DeclareUTFSymbol\CYRIOTLYUS{"0468}
+\DeclareUTFSymbol\cyriotlyus{"0469}
+\DeclareUTFSymbol\CYRBYUS{"046A}
+\DeclareUTFSymbol\cyrbyus{"046B}
+\DeclareUTFSymbol\CYRIOTBYUS{"046C}
+\DeclareUTFSymbol\cyriotbyus{"046D}
+\DeclareUTFSymbol\CYRKSI{"046E}
+\DeclareUTFSymbol\cyrksi{"046F}
+\DeclareUTFSymbol\CYRPSI{"0470}
+\DeclareUTFSymbol\cyrpsi{"0471}
+\DeclareUTFSymbol\CYRFITA{"0472}
+\DeclareUTFSymbol\cyrfita{"0473}
+\DeclareUTFSymbol\CYRIZH{"0474}
+\DeclareUTFSymbol\cyrizh{"0475}
+\DeclareUTFCompositeSymbol\C{\CYRIZH}{"0476}
+\DeclareUTFCompositeSymbol\C{\cyrizh}{"0477}
+\DeclareUTFSymbol\CYRUK{"0478}
+\DeclareUTFSymbol\cyruk{"0479}
+\DeclareUTFSymbol\CYROMEGARND{"047A}
+\DeclareUTFSymbol\cyromegarnd{"047B}
+\DeclareUTFSymbol\CYROMEGATITLO{"047C}
+\DeclareUTFSymbol\cyromegatitlo{"047D}
+\DeclareUTFSymbol\CYROT{"047E}
+\DeclareUTFSymbol\cyrot{"047F}
+\DeclareUTFSymbol\CYRKOPPA{"0480}
+\DeclareUTFSymbol\cyrkoppa{"0481}
+\DeclareUTFSymbol\cyrthousands{"0482}
+\DeclareUTFSymbol\CYRISHRTDSC{"048A}
+\DeclareUTFSymbol\cyrishrtdsc{"048B}
+\DeclareUTFSymbol\CYRSEMISFTSN{"048C}
+\DeclareUTFSymbol\cyrsemisftsn{"048D}
+\DeclareUTFSymbol\CYRRTICK{"048E}
+\DeclareUTFSymbol\cyrrtick{"048F}
+\DeclareUTFSymbol\CYRGUP{"0490}
+\DeclareUTFSymbol\cyrgup{"0491}
+\DeclareUTFSymbol\CYRGHCRS{"0492}
+\DeclareUTFSymbol\cyrghcrs{"0493}
+\DeclareUTFSymbol\CYRGHK{"0494}
+\DeclareUTFSymbol\cyrghk{"0495}
+\DeclareUTFSymbol\CYRZHDSC{"0496}
+\DeclareUTFSymbol\cyrzhdsc{"0497}
+\DeclareUTFSymbol\CYRZDSC{"0498}
+\DeclareUTFCompositeSymbol\c{\CYRZ}{"0498}
+\DeclareUTFSymbol\cyrzdsc{"0499}
+\DeclareUTFCompositeSymbol\c{\cyrz}{"0499}
+\DeclareUTFSymbol\CYRKDSC{"049A}
+\DeclareUTFSymbol\cyrkdsc{"049B}
+\DeclareUTFSymbol\CYRKVCRS{"049C}
+\DeclareUTFSymbol\cyrkvcrs{"049D}
+\DeclareUTFSymbol\CYRKHCRS{"049E}
+\DeclareUTFSymbol\cyrkhcrs{"049F}
+\DeclareUTFSymbol\CYRKBEAK{"04A0}
+\DeclareUTFSymbol\cyrkbeak{"04A1}
+\DeclareUTFSymbol\CYRNDSC{"04A2}
+\DeclareUTFSymbol\cyrndsc{"04A3}
+\DeclareUTFSymbol\CYRNG{"04A4}
+\DeclareUTFSymbol\cyrng{"04A5}
+\DeclareUTFSymbol\CYRPHK{"04A6}
+\DeclareUTFSymbol\cyrphk{"04A7}
+\DeclareUTFSymbol\CYRABHHA{"04A8}
+\DeclareUTFSymbol\cyrabhha{"04A9}
+\DeclareUTFSymbol\CYRSDSC{"04AA}
+\DeclareUTFCompositeSymbol\CYRSDSC{\CYRS}{"04AA}
+\DeclareUTFSymbol\cyrsdsc{"04AB}
+\DeclareUTFCompositeSymbol\k{\cyrs}{"04AB}
+\DeclareUTFSymbol\CYRTDSC{"04AC}
+\DeclareUTFSymbol\cyrtdsc{"04AD}
+\DeclareUTFSymbol\CYRY{"04AE}
+\DeclareUTFSymbol\cyry{"04AF}
+\DeclareUTFSymbol\CYRYHCRS{"04B0}
+\DeclareUTFSymbol\cyryhcrs{"04B1}
+\DeclareUTFSymbol\CYRHDSC{"04B2}
+\DeclareUTFSymbol\cyrhdsc{"04B3}
+\DeclareUTFSymbol\CYRTETSE{"04B4}
+\DeclareUTFSymbol\cyrtetse{"04B5}
+\DeclareUTFSymbol\CYRCHRDSC{"04B6}
+\DeclareUTFSymbol\cyrchrdsc{"04B7}
+\DeclareUTFSymbol\CYRCHVCRS{"04B8}
+\DeclareUTFSymbol\cyrchvcrs{"04B9}
+\DeclareUTFSymbol\CYRSHHA{"04BA}
+\DeclareUTFSymbol\cyrshha{"04BB}
+\DeclareUTFSymbol\CYRABHCH{"04BC}
+\DeclareUTFSymbol\cyrabhch{"04BD}
+\DeclareUTFSymbol\CYRABHCHDSC{"04BE}
+\DeclareUTFCompositeSymbol\k{\CYRABHCH}{"04BE}
+\DeclareUTFSymbol\cyrabhchdsc{"04BF}
+\DeclareUTFCompositeSymbol\k{\cyrabhch}{"04BF}
+\DeclareUTFSymbol\CYRpalochka{"04C0}
+\DeclareUTFCompositeSymbol\U{\CYRZH}{"04C1}
+\DeclareUTFCompositeSymbol\U{\cyrzh}{"04C2}
+\DeclareUTFSymbol\CYRKHK{"04C3}
+\DeclareUTFSymbol\cyrkhk{"04C4}
+\DeclareUTFSymbol\CYRLDSC{"04C5}
+\DeclareUTFSymbol\cyrldsc{"04C6}
+\DeclareUTFSymbol\CYRNHK{"04C7}
+\DeclareUTFSymbol\cyrnhk{"04C8}
+\DeclareUTFSymbol\CYRCHLDSC{"04CB}
+\DeclareUTFSymbol\cyrchldsc{"04CC}
+\DeclareUTFSymbol\CYRMDSC{"04CD}
+\DeclareUTFSymbol\cyrmdsc{"04CE}
+\DeclareUTFCompositeSymbol\U{\CYRA}{"04D0}
+\DeclareUTFCompositeSymbol\U{\cyra}{"04D1}
+\DeclareUTFCompositeSymbol\"{\CYRA}{"04D2}
+\DeclareUTFCompositeSymbol\"{\cyra}{"04D3}
+\DeclareUTFSymbol\CYRAE{"04D4}
+\DeclareUTFSymbol\cyrae{"04D5}
+\DeclareUTFCompositeSymbol\U{\CYRE}{"04D6}
+\DeclareUTFCompositeSymbol\U{\cyre}{"04D7}
+\DeclareUTFSymbol\CYRSCHWA{"04D8}
+\DeclareUTFSymbol\cyrschwa{"04D9}
+\DeclareUTFCompositeSymbol\"{\CYRSCHWA}{"04DA}
+\DeclareUTFCompositeSymbol\"{\cyrschwa}{"04DB}
+\DeclareUTFCompositeSymbol\"{\CYRZH}{"04DC}
+\DeclareUTFCompositeSymbol\"{\cyrzh}{"04DD}
+\DeclareUTFCompositeSymbol\"{\CYRZ}{"04DE}
+\DeclareUTFCompositeSymbol\"{\cyrz}{"04DF}
+\DeclareUTFSymbol\CYRABHDZE{"04E0}
+\DeclareUTFSymbol\cyrabhdze{"04E1}
+\DeclareUTFCompositeSymbol\={\CYRI}{"04E2}
+\DeclareUTFCompositeSymbol\={\cyri}{"04E3}
+\DeclareUTFCompositeSymbol\"{\CYRI}{"04E4}
+\DeclareUTFCompositeSymbol\"{\cyri}{"04E5}
+\DeclareUTFCompositeSymbol\"{\CYRO}{"04E6}
+\DeclareUTFCompositeSymbol\"{\cyro}{"04E7}
+\DeclareUTFSymbol\CYROTLD{"04E8}
+\DeclareUTFSymbol\cyrotld{"04E9}
+\DeclareUTFCompositeSymbol\"{\CYROTLD}{"04EA}
+\DeclareUTFCompositeSymbol\"{\cyrotld}{"04EB}
+\DeclareUTFCompositeSymbol\"{\CYREREV}{"04EC}
+\DeclareUTFCompositeSymbol\"{\cyreref}{"04ED}
+\DeclareUTFCompositeSymbol\={\CYRU}{"04EE}
+\DeclareUTFCompositeSymbol\={\cyru}{"04EF}
+\DeclareUTFCompositeSymbol\"{\CYRU}{"04F0}
+\DeclareUTFCompositeSymbol\"{\cyru}{"04F1}
+\DeclareUTFCompositeSymbol\H{\CYRU}{"04F2}
+\DeclareUTFCompositeSymbol\H{\cyru}{"04F3}
+\DeclareUTFCompositeSymbol\"{\CYRCH}{"04F4}
+\DeclareUTFCompositeSymbol\"{\cyrch}{"04F5}
+\DeclareUTFSymbol\CYRGDSC{"04F6}
+\DeclareUTFSymbol\cyrgdsc{"04F7}
+\DeclareUTFCompositeSymbol\"{\CYRERY}{"04F8}
+\DeclareUTFCompositeSymbol\"{\cyrery}{"04F9}
+\DeclareUTFSymbol\CYRHHK{"04FC}
+\DeclareUTFSymbol\cyrhhk{"04FD}
+\DeclareUTFSymbol\sofpasuq{"05C3}
+\DeclareUTFSymbol\hebalef{"05D0}
+\DeclareUTFSymbol\hebbet{"05D1}
+\DeclareUTFSymbol\hebgimel{"05D2}
+\DeclareUTFSymbol\hebdalet{"05D3}
+\DeclareUTFSymbol\hebhe{"05D4}
+\DeclareUTFSymbol\hebvav{"05D5}
+\DeclareUTFSymbol\hebzayin{"05D6}
+\DeclareUTFSymbol\hebhet{"05D7}
+\DeclareUTFSymbol\hebtet{"05D8}
+\DeclareUTFSymbol\hebyod{"05D9}
+\DeclareUTFSymbol\hebfinalkaf{"05DA}
+\DeclareUTFSymbol\hebkaf{"05DB}
+\DeclareUTFSymbol\heblamed{"05DC}
+\DeclareUTFSymbol\hebfinalmem{"05DD}
+\DeclareUTFSymbol\hebmem{"05DE}
+\DeclareUTFSymbol\hebfinalnun{"05DF}
+\DeclareUTFSymbol\hebnun{"05E0}
+\DeclareUTFSymbol\hebsamekh{"05E1}
+\DeclareUTFSymbol\hebayin{"05E2}
+\DeclareUTFSymbol\hebfinalpe{"05E3}
+\DeclareUTFSymbol\hebpe{"05E4}
+\DeclareUTFSymbol\hebfinaltsadi{"05E5}
+\DeclareUTFSymbol\hebtsadi{"05E6}
+\DeclareUTFSymbol\hebqof{"05E7}
+\DeclareUTFSymbol\hebresh{"05E8}
+\DeclareUTFSymbol\hebshin{"05E9}
+\DeclareUTFSymbol\hebtav{"05EA}
+\DeclareUTFSymbol\doublevav{"05F0}
+\DeclareUTFSymbol\vavyod{"05F1}
+\DeclareUTFSymbol\doubleyod{"05F2}
+\DeclareUTFSymbol\textscd{"1D05}
+\DeclareUTFSymbol\textPUsck{"1D0B}
+\DeclareUTFSymbol\textPUscm{"1D0D}
+\DeclareUTFSymbol\textPUscp{"1D18}
+\DeclareUTFSymbol\textPUrevscr{"1D19}
+\DeclareUTFSymbol\textiinferior{"1D62}
+\DeclareUTFSymbol\textrinferior{"1D63}
+\DeclareUTFSymbol\textuinferior{"1D64}
+\DeclareUTFSymbol\textvinferior{"1D65}
+\DeclareUTFSymbol\textbetainferior{"1D66}
+\DeclareUTFSymbol\textgammainferior{"1D67}
+\DeclareUTFSymbol\textrhoinferior{"1D68}
+\DeclareUTFSymbol\textphiinferior{"1D69}
+\DeclareUTFSymbol\textchiinferior{"1D6A}
+\DeclareUTFSymbol\textbarsci{"1D7B}
+\DeclareUTFSymbol\textbarp{"1D7D}
+\DeclareUTFSymbol\textbarscu{"1D7E}
+\DeclareUTFSymbol\textPUrhooka{"1D8F}
+\DeclareUTFSymbol\textPUrhooke{"1D92}
+\DeclareUTFSymbol\textPUrhookepsilon{"1D93}
+\DeclareUTFSymbol\textPUrhookopeno{"1D97}
+\DeclareUTFCompositeSymbol\textsubbreve{H}{"1E2A}
+\DeclareUTFCompositeSymbol\textsubbreve{h}{"1E2B}
+\DeclareUTFCompositeSymbol\.{\textlongs}{"1E9B}
+\DeclareUTFSymbol\textcompwordmark{"200C}
+\DeclareUTFSymbol\texthdotfor{"2025}
+\DeclareUTFSymbol\textprime{"2032}
+\DeclareUTFSymbol\textsecond{"2033}
+\DeclareUTFSymbol\textthird{"2034}
+\DeclareUTFSymbol\textbackprime{"2035}
+\DeclareUTFSymbol\textlefttherefore{"2056}
+\DeclareUTFSymbol\textfourth{"2057}
+\DeclareUTFSymbol\textdiamonddots{"2058}
+\DeclareUTFSymbol\textzerosuperior{"2070}
+\DeclareUTFSymbol\textisuperior{"2071}
+\DeclareUTFSymbol\textfoursuperior{"2074}
+\DeclareUTFSymbol\textfivesuperior{"2075}
+\DeclareUTFSymbol\textsixsuperior{"2076}
+\DeclareUTFSymbol\textsevensuperior{"2077}
+\DeclareUTFSymbol\texteightsuperior{"2078}
+\DeclareUTFSymbol\textninesuperior{"2079}
+\DeclareUTFSymbol\textplussuperior{"207A}
+\DeclareUTFSymbol\textminussuperior{"207B}
+\DeclareUTFSymbol\textequalsuperior{"207C}
+\DeclareUTFSymbol\textparenleftsuperior{"207D}
+\DeclareUTFSymbol\textparenrightsuperior{"207E}
+\DeclareUTFSymbol\textnsuperior{"207F}
+\DeclareUTFSymbol\textzeroinferior{"2080}
+\DeclareUTFSymbol\textoneinferior{"2081}
+\DeclareUTFSymbol\texttwoinferior{"2082}
+\DeclareUTFSymbol\textthreeinferior{"2083}
+\DeclareUTFSymbol\textfourinferior{"2084}
+\DeclareUTFSymbol\textfiveinferior{"2085}
+\DeclareUTFSymbol\textsixinferior{"2086}
+\DeclareUTFSymbol\textseveninferior{"2087}
+\DeclareUTFSymbol\texteightinferior{"2088}
+\DeclareUTFSymbol\textnineinferior{"2089}
+\DeclareUTFSymbol\textplusinferior{"208A}
+\DeclareUTFSymbol\textminusinferior{"208B}
+\DeclareUTFSymbol\textequalsinferior{"208C}
+\DeclareUTFSymbol\textparenleftinferior{"208D}
+\DeclareUTFSymbol\textparenrightinferior{"208E}
+\DeclareUTFSymbol\textainferior{"2090}
+\DeclareUTFSymbol\texteinferior{"2091}
+\DeclareUTFSymbol\textoinferior{"2092}
+\DeclareUTFSymbol\textxinferior{"2093}
+\DeclareUTFSymbol\textschwainferior{"2094}
+\DeclareUTFSymbol\texthinferior{"2095}
+\DeclareUTFSymbol\textkinferior{"2096}
+\DeclareUTFSymbol\textlinferior{"2097}
+\DeclareUTFSymbol\textminferior{"2098}
+\DeclareUTFSymbol\textninferior{"2099}
+\DeclareUTFSymbol\textpinferior{"209A}
+\DeclareUTFSymbol\textsinferior{"209B}
+\DeclareUTFSymbol\texttinferior{"209C}
+\DeclareUTFSymbol\textpeseta{"20A7}
+\DeclareUTFSymbol\textDeleatur{"20B0}
+\DeclareUTFSymbol\textguarani{"20B2}
+\DeclareUTFSymbol\texthslash{"210F}
+\DeclareUTFSymbol\textIm{"2111}
+\DeclareUTFSymbol\textell{"2113}
+\DeclareUTFSymbol\textwp{"2118}
+\DeclareUTFSymbol\textRe{"211C}
+\DeclareUTFSymbol\textriota{"2129}
+\DeclareUTFSymbol\textangstrom{"212B}
+\DeclareUTFSymbol\textfax{"213B}
+\DeclareUTFSymbol\textinvamp{"214B}
+\DeclareUTFSymbol\textoneseventh{"2150}
+\DeclareUTFSymbol\textoneninth{"2151}
+\DeclareUTFSymbol\textonetenth{"2152}
+\DeclareUTFSymbol\textonethird{"2153}
+\DeclareUTFSymbol\texttwothirds{"2154}
+\DeclareUTFSymbol\textonefifth{"2155}
+\DeclareUTFSymbol\texttwofifths{"2156}
+\DeclareUTFSymbol\textthreefifths{"2157}
+\DeclareUTFSymbol\textfourfifths{"2158}
+\DeclareUTFSymbol\textonesixth{"2159}
+\DeclareUTFSymbol\textfivesixths{"215A}
+\DeclareUTFSymbol\textoneeighth{"215B}
+\DeclareUTFSymbol\textthreeeighths{"215C}
+\DeclareUTFSymbol\textfiveeighths{"215D}
+\DeclareUTFSymbol\textseveneighths{"215E}
+\DeclareUTFSymbol\textrevc{"2184}
+\DeclareUTFSymbol\textzerothirds{"2189}
+\DeclareUTFSymbol\textnleftarrow{"219A}
+\DeclareUTFSymbol\textnrightarrow{"219B}
+\DeclareUTFSymbol\texttwoheadleftarrow{"219E}
+\DeclareUTFCommand\textntwoheadleftarrow{\textlstrikethru\texttwoheadleftarrow}
+\DeclareUTFSymbol\texttwoheaduparrow{"219F}
+\DeclareUTFSymbol\texttwoheadrightarrow{"21A0}
+\DeclareUTFCommand\textntwoheadrightarrow{\textlstrikethru\texttwoheadrightarrow}
+\DeclareUTFSymbol\texttwoheaddownarrow{"21A1}
+\DeclareUTFSymbol\textleftarrowtail{"21A2}
+\DeclareUTFSymbol\textrightarrowtail{"21A3}
+\DeclareUTFSymbol\textmapsto{"21A6}
+\DeclareUTFSymbol\texthookleftarrow{"21A9}
+\DeclareUTFSymbol\texthookrightarrow{"21AA}
+\DeclareUTFSymbol\textlooparrowleft{"21AB}
+\DeclareUTFSymbol\textlooparrowright{"21AC}
+\DeclareUTFSymbol\textnleftrightarrow{"21AE}
+\DeclareUTFSymbol\textlightning{"21AF}
+\DeclareUTFSymbol\textdlsh{"21B5}
+\DeclareUTFSymbol\textcurvearrowleft{"21B6}
+\DeclareUTFSymbol\textcurvearrowright{"21B7}
+\DeclareUTFSymbol\textleftharpoonup{"21BC}
+\DeclareUTFSymbol\textleftharpoondown{"21BD}
+\DeclareUTFSymbol\textupharpoonright{"21BE}
+\DeclareUTFSymbol\textupharpoonleft{"21BF}
+\DeclareUTFSymbol\textrightharpoonup{"21C0}
+\DeclareUTFSymbol\textrightharpoondown{"21C1}
+\DeclareUTFSymbol\textdownharpoonright{"21C2}
+\DeclareUTFSymbol\textdownharpoonleft{"21C3}
+\DeclareUTFSymbol\textrightleftarrows{"21C4}
+\DeclareUTFSymbol\textupdownarrows{"21C5}
+\DeclareUTFSymbol\textleftrightarrows{"21C6}
+\DeclareUTFSymbol\textleftleftarrows{"21C7}
+\DeclareUTFSymbol\textupuparrows{"21C8}
+\DeclareUTFSymbol\textrightrightarrows{"21C9}
+\DeclareUTFSymbol\textdowndownarrows{"21CA}
+\DeclareUTFSymbol\textleftrightharpoons{"21CB}
+\DeclareUTFSymbol\textrightleftharpoons{"21CC}
+\DeclareUTFSymbol\textnLeftarrow{"21CD}
+\DeclareUTFSymbol\textnLeftrightarrow{"21CE}
+\DeclareUTFSymbol\textnRightarrow{"21CF}
+\DeclareUTFSymbol\textLeftarrow{"21D0}
+\DeclareUTFSymbol\textUparrow{"21D1}
+\DeclareUTFSymbol\textRightarrow{"21D2}
+\DeclareUTFSymbol\textDownarrow{"21D3}
+\DeclareUTFSymbol\textLeftrightarrow{"21D4}
+\DeclareUTFSymbol\textUpdownarrow{"21D5}
+\DeclareUTFSymbol\textNwarrow{"21D6}
+\DeclareUTFSymbol\textNearrow{"21D7}
+\DeclareUTFSymbol\textSearrow{"21D8}
+\DeclareUTFSymbol\textSwarrow{"21D9}
+\DeclareUTFSymbol\textLleftarrow{"21DA}
+\DeclareUTFSymbol\textRrightarrow{"21DB}
+\DeclareUTFSymbol\textleftsquigarrow{"21DC}
+\DeclareUTFSymbol\textrightsquigarrow{"21DD}
+\DeclareUTFSymbol\textdashleftarrow{"21E0}
+\DeclareUTFSymbol\textdasheduparrow{"21E1}
+\DeclareUTFSymbol\textdashrightarrow{"21E2}
+\DeclareUTFSymbol\textdasheddownarrow{"21E3}
+\DeclareUTFSymbol\textpointer{"21E8}
+\DeclareUTFSymbol\textdownuparrows{"21F5}
+\DeclareUTFSymbol\textleftarrowtriangle{"21FD}
+\DeclareUTFSymbol\textrightarrowtriangle{"21FE}
+\DeclareUTFSymbol\textleftrightarrowtriangle{"21FF}
+\DeclareUTFSymbol\textforall{"2200}
+\DeclareUTFSymbol\textcomplement{"2201}
+\DeclareUTFSymbol\textpartial{"2202}
+\DeclareUTFSymbol\textexists{"2203}
+\DeclareUTFSymbol\textnexists{"2204}
+\DeclareUTFSymbol\textemptyset{"2205}
+\DeclareUTFSymbol\texttriangle{"2206}
+\DeclareUTFSymbol\textnabla{"2207}
+\DeclareUTFSymbol\textin{"2208}
+\DeclareUTFSymbol\textnotin{"2209}
+\DeclareUTFSymbol\textsmallin{"220A}
+\DeclareUTFSymbol\textni{"220B}
+\DeclareUTFSymbol\textnotowner{"220C}
+\DeclareUTFSymbol\textsmallowns{"220D}
+\DeclareUTFSymbol\textprod{"220F}
+\DeclareUTFSymbol\textamalg{"2210}
+\DeclareUTFSymbol\textsum{"2211}
+\DeclareUTFSymbol\textmp{"2213}
+\DeclareUTFSymbol\textdotplus{"2214}
+\DeclareUTFSymbol\textDivides{"2215}
+\DeclareUTFSymbol\textsetminus{"2216}
+\DeclareUTFSymbol\textast{"2217}
+\DeclareUTFSymbol\textcirc{"2218}
+\DeclareUTFSymbol\textbulletoperator{"2219}
+\DeclareUTFSymbol\textpropto{"221D}
+\DeclareUTFSymbol\textinfty{"221E}
+\DeclareUTFSymbol\textangle{"2220}
+\DeclareUTFSymbol\textmeasuredangle{"2221}
+\DeclareUTFSymbol\textsphericalangle{"2222}
+\DeclareUTFSymbol\textmid{"2223}
+\DeclareUTFSymbol\textnmid{"2224}
+\DeclareUTFSymbol\textparallel{"2225}
+\DeclareUTFSymbol\textnparallel{"2226}
+\DeclareUTFSymbol\textwedge{"2227}
+\DeclareUTFCommand\textowedge{\textcircled\textwedge}
+\DeclareUTFSymbol\textvee{"2228}
+\DeclareUTFCommand\textovee{\textcircled\textvee}
+\DeclareUTFSymbol\textcap{"2229}
+\DeclareUTFSymbol\textcup{"222A}
+\DeclareUTFSymbol\textint{"222B}
+\DeclareUTFSymbol\textiint{"222C}
+\DeclareUTFSymbol\textiiint{"222D}
+\DeclareUTFSymbol\textoint{"222E}
+\DeclareUTFSymbol\textoiint{"222F}
+\DeclareUTFSymbol\textointclockwise{"2232}
+\DeclareUTFSymbol\textointctrclockwise{"2233}
+\DeclareUTFSymbol\texttherefore{"2234}
+\DeclareUTFSymbol\textbecause{"2235}
+\DeclareUTFSymbol\textvdotdot{"2236}
+\DeclareUTFSymbol\textsquaredots{"2237}
+\DeclareUTFSymbol\textdotminus{"2238}
+\DeclareUTFSymbol\texteqcolon{"2239}
+\DeclareUTFSymbol\textsim{"223C}
+\DeclareUTFSymbol\textbacksim{"223D}
+\DeclareUTFCommand\textnbacksim{\textlstrikethru\textnbacksim}
+\DeclareUTFSymbol\textwr{"2240}
+\DeclareUTFSymbol\textnsim{"2241}
+\DeclareUTFSymbol\texteqsim{"2242}
+\DeclareUTFCommand\textneqsim{\textlstrikethru\texteqsim}
+\DeclareUTFSymbol\textsimeq{"2243}
+\DeclareUTFSymbol\textnsimeq{"2244}
+\DeclareUTFSymbol\textcong{"2245}
+\DeclareUTFSymbol\textncong{"2247}
+\DeclareUTFSymbol\textapprox{"2248}
+\DeclareUTFSymbol\textnapprox{"2249}
+\DeclareUTFSymbol\textapproxeq{"224A}
+\DeclareUTFCommand\textnapproxeq{\textlstrikethru\textapproxeq}
+\DeclareUTFSymbol\texttriplesim{"224B}
+\DeclareUTFCommand\textntriplesim{\textlstrikethru\texttriplesim}
+\DeclareUTFSymbol\textbackcong{"224C}
+\DeclareUTFCommand\textnbackcong{\textlstrikethru\textbackcong}
+\DeclareUTFSymbol\textasymp{"224D}
+\DeclareUTFCommand\textnasymp{\textlstrikethru\textasymp}
+\DeclareUTFSymbol\textBumpeq{"224E}
+\DeclareUTFCommand\textnBumpeq{\textlstrikethru\textBumpeq}
+\DeclareUTFSymbol\textbumpeq{"224F}
+\DeclareUTFCommand\textnbumpeq{\textlstrikethru\textbumpeq}
+\DeclareUTFSymbol\textdoteq{"2250}
+\DeclareUTFCommand\textndoteq{\textlstrikethru\textdoteq}
+\DeclareUTFSymbol\textdoteqdot{"2251}
+\DeclareUTFCommand\textnDoteq{\textlstrikethru\textdoteqdot}
+\DeclareUTFSymbol\textfallingdoteq{"2252}
+\DeclareUTFCommand\textnfallingdoteq{\textlstrikethru\textfallingdoteq}
+\DeclareUTFSymbol\textrisingdoteq{"2253}
+\DeclareUTFCommand\textnrisingdoteq{\textlstrikethru\textrisingdoteq}
+\DeclareUTFSymbol\textcolonequals{"2254}
+\DeclareUTFSymbol\textequalscolon{"2255}
+\DeclareUTFSymbol\texteqcirc{"2256}
+\DeclareUTFCommand\textneqcirc{\textlstrikethru\texteqcirc}
+\DeclareUTFSymbol\textcirceq{"2257}
+\DeclareUTFCommand\textncirceq{\textlstrikethru\textcirceq}
+\DeclareUTFSymbol\texthateq{"2259}
+\DeclareUTFCommand\textnhateq{\textlstrikethru\texthateq}
+\DeclareUTFSymbol\texttriangleeq{"225C}
+\DeclareUTFSymbol\textneq{"2260}
+\DeclareUTFSymbol\textne{"2260}
+\DeclareUTFSymbol\textequiv{"2261}
+\DeclareUTFSymbol\textnequiv{"2262}
+\DeclareUTFSymbol\textleq{"2264}
+\DeclareUTFSymbol\textle{"2264}
+\DeclareUTFSymbol\textgeq{"2265}
+\DeclareUTFSymbol\textge{"2265}
+\DeclareUTFSymbol\textleqq{"2266}
+\DeclareUTFCommand\textnleqq{\textlstrikethru\textleqq}
+\DeclareUTFSymbol\textgeqq{"2267}
+\DeclareUTFCommand\textngeqq{\textlstrikethru\textgeqq}
+\DeclareUTFSymbol\textlneqq{"2268}
+\DeclareUTFSymbol\textgneqq{"2269}
+\DeclareUTFSymbol\textll{"226A}
+\DeclareUTFCommand\textnll{\textlstrikethru\textll}
+\DeclareUTFSymbol\textgg{"226B}
+\DeclareUTFCommand\textngg{\textlstrikethru\textgg}
+\DeclareUTFSymbol\textbetween{"226C}
+\DeclareUTFSymbol\textnless{"226E}
+\DeclareUTFSymbol\textngtr{"226F}
+\DeclareUTFSymbol\textnleq{"2270}
+\DeclareUTFSymbol\textngeq{"2271}
+\DeclareUTFSymbol\textlesssim{"2272}
+\DeclareUTFSymbol\textgtrsim{"2273}
+\DeclareUTFSymbol\textnlesssim{"2274}
+\DeclareUTFSymbol\textngtrsim{"2275}
+\DeclareUTFSymbol\textlessgtr{"2276}
+\DeclareUTFSymbol\textgtrless{"2277}
+\DeclareUTFSymbol\textngtrless{"2278}
+\DeclareUTFSymbol\textnlessgtr{"2279}
+\DeclareUTFSymbol\textprec{"227A}
+\DeclareUTFSymbol\textsucc{"227B}
+\DeclareUTFSymbol\textpreccurlyeq{"227C}
+\DeclareUTFSymbol\textsucccurlyeq{"227D}
+\DeclareUTFSymbol\textprecsim{"227E}
+\DeclareUTFCommand\textnprecsim{\textlstrikethru\textprecsim}
+\DeclareUTFSymbol\textsuccsim{"227F}
+\DeclareUTFCommand\textnsuccsim{\textlstrikethru\textsuccsim}
+\DeclareUTFSymbol\textnprec{"2280}
+\DeclareUTFSymbol\textnsucc{"2281}
+\DeclareUTFSymbol\textsubset{"2282}
+\DeclareUTFSymbol\textsupset{"2283}
+\DeclareUTFSymbol\textnsubset{"2284}
+\DeclareUTFSymbol\textnsupset{"2285}
+\DeclareUTFSymbol\textsubseteq{"2286}
+\DeclareUTFSymbol\textsupseteq{"2287}
+\DeclareUTFSymbol\textnsubseteq{"2288}
+\DeclareUTFSymbol\textnsupseteq{"2289}
+\DeclareUTFSymbol\textsubsetneq{"228A}
+\DeclareUTFSymbol\textsupsetneq{"228B}
+\DeclareUTFSymbol\textcupdot{"228D}
+\DeclareUTFSymbol\textcupplus{"228E}
+\DeclareUTFSymbol\textsqsubset{"228F}
+\DeclareUTFCommand\textnsqsubset{\textlstrikethru\textsqsubset}
+\DeclareUTFSymbol\textsqsupset{"2290}
+\DeclareUTFCommand\textnsqsupset{\textlstrikethru\textsqsupset}
+\DeclareUTFSymbol\textsqsubseteq{"2291}
+\DeclareUTFCommand\textnsqsubseteq{\textlstrikethru\textsqsubseteq}
+\DeclareUTFSymbol\textsqsupseteq{"2292}
+\DeclareUTFCommand\textnsqsupseteq{\textlstrikethru\textsqsupseteq}
+\DeclareUTFSymbol\textsqcap{"2293}
+\DeclareUTFSymbol\textsqcup{"2294}
+\DeclareUTFSymbol\textoplus{"2295}
+\DeclareUTFSymbol\textominus{"2296}
+\DeclareUTFSymbol\textotimes{"2297}
+\DeclareUTFSymbol\textoslash{"2298}
+\DeclareUTFSymbol\textodot{"2299}
+\DeclareUTFSymbol\textcircledcirc{"229A}
+\DeclareUTFSymbol\textcircledast{"229B}
+\DeclareUTFSymbol\textcircleddash{"229D}
+\DeclareUTFSymbol\textboxplus{"229E}
+\DeclareUTFSymbol\textboxminus{"229F}
+\DeclareUTFSymbol\textboxtimes{"22A0}
+\DeclareUTFSymbol\textboxdot{"22A1}
+\DeclareUTFSymbol\textvdash{"22A2}
+\DeclareUTFSymbol\textdashv{"22A3}
+\DeclareUTFCommand\textndashv{\textlstrikethru\textdashv}
+\DeclareUTFSymbol\texttop{"22A4}
+\DeclareUTFCommand\textndownvdash{\textlstrikethru\texttop}
+\DeclareUTFSymbol\textbot{"22A5}
+\DeclareUTFCommand\textnupvdash{\textlstrikethru\textbot}
+\DeclareUTFSymbol\textvDash{"22A8}
+\DeclareUTFSymbol\textVdash{"22A9}
+\DeclareUTFSymbol\textVvdash{"22AA}
+\DeclareUTFCommand\textnVvash{\textlstrikethru\textVvdash}
+\DeclareUTFSymbol\textVDash{"22AB}
+\DeclareUTFSymbol\textnvdash{"22AC}
+\DeclareUTFSymbol\textnvDash{"22AD}
+\DeclareUTFSymbol\textnVdash{"22AE}
+\DeclareUTFSymbol\textnVDash{"22AF}
+\DeclareUTFSymbol\textlhd{"22B2}
+\DeclareUTFSymbol\textrhd{"22B3}
+\DeclareUTFSymbol\textunlhd{"22B4}
+\DeclareUTFSymbol\textunrhd{"22B5}
+\DeclareUTFSymbol\textmultimapdotbothA{"22B6}
+\DeclareUTFSymbol\textmultimapdotbothB{"22B7}
+\DeclareUTFSymbol\textmultimap{"22B8}
+\DeclareUTFSymbol\textveebar{"22BB}
+\DeclareUTFSymbol\textbarwedge{"22BC}
+\DeclareUTFSymbol\textstar{"22C6}
+\DeclareUTFSymbol\textdivideontimes{"22C7}
+\DeclareUTFSymbol\textbowtie{"22C8}
+\DeclareUTFSymbol\textltimes{"22C9}
+\DeclareUTFSymbol\textrtimes{"22CA}
+\DeclareUTFSymbol\textleftthreetimes{"22CB}
+\DeclareUTFSymbol\textrightthreetimes{"22CC}
+\DeclareUTFSymbol\textbacksimeq{"22CD}
+\DeclareUTFCommand\textnbacksimeq{\textlstrikethru\textbacksimeq}
+\DeclareUTFSymbol\textcurlyvee{"22CE}
+\DeclareUTFSymbol\textcurlywedge{"22CF}
+\DeclareUTFSymbol\textSubset{"22D0}
+\DeclareUTFCommand\textnSubset{\textlstrikethru\textSubset}
+\DeclareUTFSymbol\textSupset{"22D1}
+\DeclareUTFCommand\textnSupset{\textlstrikethru\textSupset}
+\DeclareUTFSymbol\textCap{"22D2}
+\DeclareUTFSymbol\textCup{"22D3}
+\DeclareUTFSymbol\textpitchfork{"22D4}
+\DeclareUTFSymbol\textlessdot{"22D6}
+\DeclareUTFSymbol\textgtrdot{"22D7}
+\DeclareUTFSymbol\textlll{"22D8}
+\DeclareUTFSymbol\textggg{"22D9}
+\DeclareUTFSymbol\textlesseqgtr{"22DA}
+\DeclareUTFSymbol\textgtreqless{"22DB}
+\DeclareUTFSymbol\textcurlyeqprec{"22DE}
+\DeclareUTFCommand\textncurlyeqprec{\textlstrikethru\textcurlyeqprec}
+\DeclareUTFSymbol\textcurlyeqsucc{"22DF}
+\DeclareUTFCommand\textncurlyeqsucc{\textlstrikethru\textcurlyeqsucc}
+\DeclareUTFSymbol\textnpreccurlyeq{"22E0}
+\DeclareUTFSymbol\textnsucccurlyeq{"22E1}
+\DeclareUTFSymbol\textnqsubseteq{"22E2}
+\DeclareUTFSymbol\textnqsupseteq{"22E3}
+\DeclareUTFSymbol\textsqsubsetneq{"22E4}
+\DeclareUTFSymbol\textsqsupsetneq{"22E5}
+\DeclareUTFSymbol\textlnsim{"22E6}
+\DeclareUTFSymbol\textgnsim{"22E7}
+\DeclareUTFSymbol\textprecnsim{"22E8}
+\DeclareUTFSymbol\textsuccnsim{"22E9}
+\DeclareUTFSymbol\textntriangleleft{"22EA}
+\DeclareUTFSymbol\textntriangleright{"22EB}
+\DeclareUTFSymbol\textntrianglelefteq{"22EC}
+\DeclareUTFSymbol\textntrianglerighteq{"22ED}
+\DeclareUTFSymbol\textvdots{"22EE}
+\DeclareUTFSymbol\textcdots{"22EF}
+\DeclareUTFSymbol\textudots{"22F0}
+\DeclareUTFSymbol\textddots{"22F1}
+\DeclareUTFSymbol\textbarin{"22F6}
+\DeclareUTFSymbol\textdiameter{"2300}
+\DeclareUTFSymbol\textbackneg{"2310}
+\DeclareUTFSymbol\textwasylozenge{"2311}
+\DeclareUTFSymbol\textinvbackneg{"2319}
+\DeclareUTFSymbol\textclock{"231A}
+\DeclareUTFSymbol\textulcorner{"231C}
+\DeclareUTFSymbol\texturcorner{"231D}
+\DeclareUTFSymbol\textllcorner{"231E}
+\DeclareUTFSymbol\textlrcorner{"231F}
+\DeclareUTFSymbol\textfrown{"2322}
+\DeclareUTFSymbol\textsmile{"2323}
+\DeclareUTFSymbol\textKeyboard{"2328}
+\DeclareUTFSymbol\textlangle{"2329}
+\DeclareUTFSymbol\textrangle{"232A}
+\DeclareUTFSymbol\textAPLinv{"2339}
+\DeclareUTFSymbol\textTumbler{"233C}
+\DeclareUTFSymbol\textstmaryrdbaro{"233D}
+\DeclareUTFSymbol\textnotslash{"233F}
+\DeclareUTFSymbol\textnotbackslash{"2340}
+\DeclareUTFSymbol\textboxbackslash{"2342}
+\DeclareUTFSymbol\textAPLleftarrowbox{"2347}
+\DeclareUTFSymbol\textAPLrightarrowbox{"2348}
+\DeclareUTFSymbol\textAPLuparrowbox{"2350}
+\DeclareUTFSymbol\textAPLdownarrowbox{"2357}
+\DeclareUTFSymbol\textAPLinput{"235E}
+\DeclareUTFSymbol\textRequest{"2370}
+\DeclareUTFSymbol\textBeam{"2393}
+\DeclareUTFSymbol\texthexagon{"2394}
+\DeclareUTFSymbol\textAPLbox{"2395}
+\DeclareUTFSymbol\textForwardToIndex{"23ED}
+\DeclareUTFSymbol\textRewindToIndex{"23EE}
+\DeclareUTFSymbol\textbbslash{"244A}
+\DeclareUTFSymbol\textCircledA{"24B6}
+\DeclareUTFSymbol\textCleaningF{"24BB}
+\DeclareUTFCommand\textCleaningFF{\b\textCleaningF}
+\DeclareUTFSymbol\textCleaningP{"24C5}
+\DeclareUTFCommand\textCleaningPP{\b\textCleaningP}
+\DeclareUTFSymbol\textCuttingLine{"2504}
+\DeclareUTFSymbol\textUParrow{"25B2}
+\DeclareUTFSymbol\textbigtriangleup{"25B3}
+\DeclareUTFSymbol\textForward{"25B6}
+\DeclareUTFSymbol\texttriangleright{"25B7}
+\DeclareUTFSymbol\textRHD{"25BA}
+\DeclareUTFSymbol\textDOWNarrow{"25BC}
+\DeclareUTFSymbol\textbigtriangledown{"25BD}
+\DeclareUTFSymbol\textRewind{"25C0}
+\DeclareUTFSymbol\texttriangleleft{"25C1}
+\DeclareUTFSymbol\textLHD{"25C4}
+\DeclareUTFSymbol\textdiamond{"25C7}
+\DeclareUTFSymbol\textlozenge{"25CA}
+\DeclareUTFSymbol\textLEFTCIRCLE{"25D6}
+\DeclareUTFSymbol\textRIGHTCIRCLE{"25D7}
+\DeclareUTFSymbol\textboxbar{"25EB}
+\DeclareUTFSymbol\textCloud{"2601}
+\DeclareUTFSymbol\textFiveStar{"2605}
+\DeclareUTFSymbol\textFiveStarOpen{"2606}
+\DeclareUTFSymbol\textPhone{"260E}
+\DeclareUTFSymbol\textboxempty{"2610}
+\DeclareUTFSymbol\textCheckedbox{"2611}
+\DeclareUTFSymbol\textCrossedbox{"2612}
+\DeclareUTFSymbol\textCoffeecup{"2615}
+\DeclareUTFSymbol\textHandCuffLeft{"261A}
+\DeclareUTFSymbol\textHandCuffRight{"261B}
+\DeclareUTFSymbol\textHandLeft{"261C}
+\DeclareUTFSymbol\textHandRight{"261E}
+\DeclareUTFSymbol\textRadioactivity{"2622}
+\DeclareUTFSymbol\textBiohazard{"2623}
+\DeclareUTFSymbol\textAnkh{"2625}
+\DeclareUTFSymbol\textYinYang{"262F}
+\DeclareUTFSymbol\textfrownie{"2639}
+\DeclareUTFSymbol\textsmiley{"263A}
+\DeclareUTFSymbol\textblacksmiley{"263B}
+\DeclareUTFSymbol\textsun{"263C}
+\DeclareUTFSymbol\textleftmoon{"263D}
+\DeclareUTFSymbol\textrightmoon{"263E}
+\DeclareUTFSymbol\textmercury{"263F}
+\DeclareUTFSymbol\textPUfemale{"2640}
+\DeclareUTFSymbol\textearth{"2641}
+\DeclareUTFSymbol\textmale{"2642}
+\DeclareUTFSymbol\textjupiter{"2643}
+\DeclareUTFSymbol\textsaturn{"2644}
+\DeclareUTFSymbol\texturanus{"2645}
+\DeclareUTFSymbol\textneptune{"2646}
+\DeclareUTFSymbol\textpluto{"2647}
+\DeclareUTFSymbol\textaries{"2648}
+\DeclareUTFSymbol\texttaurus{"2649}
+\DeclareUTFSymbol\textgemini{"264A}
+\DeclareUTFSymbol\textcancer{"264B}
+\DeclareUTFSymbol\textleo{"264C}
+\DeclareUTFSymbol\textvirgo{"264D}
+\DeclareUTFSymbol\textlibra{"264E}
+\DeclareUTFSymbol\textscorpio{"264F}
+\DeclareUTFSymbol\textsagittarius{"2650}
+\DeclareUTFSymbol\textcapricornus{"2651}
+\DeclareUTFSymbol\textaquarius{"2652}
+\DeclareUTFSymbol\textpisces{"2653}
+\DeclareUTFSymbol\textspadesuitblack{"2660}
+\DeclareUTFSymbol\textheartsuitwhite{"2661}
+\DeclareUTFSymbol\textdiamondsuitwhite{"2662}
+\DeclareUTFSymbol\textclubsuitblack{"2663}
+\DeclareUTFSymbol\textspadesuitwhite{"2664}
+\DeclareUTFSymbol\textheartsuitblack{"2665}
+\DeclareUTFSymbol\textdiamondsuitblack{"2666}
+\DeclareUTFSymbol\textclubsuitwhite{"2667}
+\DeclareUTFSymbol\textquarternote{"2669}
+\DeclareUTFSymbol\texttwonotes{"266B}
+\DeclareUTFSymbol\textsixteenthnote{"266C}
+\DeclareUTFSymbol\textflat{"266D}
+\DeclareUTFSymbol\textnatural{"266E}
+\DeclareUTFSymbol\textsharp{"266F}
+\DeclareUTFSymbol\textrecycle{"2672}
+\DeclareUTFSymbol\textWheelchair{"267F}
+\DeclareUTFSymbol\textFlag{"2691}
+\DeclareUTFSymbol\textMineSign{"2692}
+\DeclareUTFSymbol\textdsmilitary{"2694}
+\DeclareUTFSymbol\textdsmedical{"2695}
+\DeclareUTFSymbol\textdsjuridical{"2696}
+\DeclareUTFSymbol\textdschemical{"2697}
+\DeclareUTFSymbol\textdsbiological{"2698}
+\DeclareUTFSymbol\textdscommercial{"269A}
+\DeclareUTFSymbol\textmanstar{"269D}
+\DeclareUTFSymbol\textdanger{"26A0}
+\DeclareUTFSymbol\textFemaleFemale{"26A2}
+\DeclareUTFSymbol\textMaleMale{"26A3}
+\DeclareUTFSymbol\textFemaleMale{"26A4}
+\DeclareUTFSymbol\textHermaphrodite{"26A5}
+\DeclareUTFSymbol\textNeutral{"26AA}
+\DeclareUTFSymbol\textPUuncrfemale{"26B2}
+\DeclareUTFSymbol\texthexstar{"26B9}
+\DeclareUTFSymbol\textSoccerBall{"26BD}
+\DeclareUTFSymbol\textSunCload{"26C5}
+\DeclareUTFSymbol\textRain{"26C6}
+\DeclareUTFSymbol\textnoway{"26D4}
+\DeclareUTFSymbol\textMountain{"26F0}
+\DeclareUTFSymbol\textTent{"26FA}
+\DeclareUTFSymbol\textScissorRightBrokenBottom{"2701}
+\DeclareUTFSymbol\textScissorRight{"2702}
+\DeclareUTFSymbol\textScissorRightBrokenTop{"2703}
+\DeclareUTFSymbol\textScissorHollowRight{"2704}
+\DeclareUTFSymbol\textPhoneHandset{"2706}
+\DeclareUTFSymbol\textTape{"2707}
+\DeclareUTFSymbol\textPlane{"2708}
+\DeclareUTFSymbol\textEnvelope{"2709}
+\DeclareUTFSymbol\textPeace{"270C}
+\DeclareUTFSymbol\textWritingHand{"270D}
+\DeclareUTFSymbol\textPencilRightDown{"270E}
+\DeclareUTFSymbol\textPencilRight{"270F}
+\DeclareUTFSymbol\textPencilRightUp{"2710}
+\DeclareUTFSymbol\textNibRight{"2711}
+\DeclareUTFSymbol\textNibSolidRight{"2712}
+\DeclareUTFSymbol\textCheckmark{"2713}
+\DeclareUTFSymbol\textCheckmarkBold{"2714}
+\DeclareUTFSymbol\textXSolid{"2715}
+\DeclareUTFSymbol\textXSolidBold{"2716}
+\DeclareUTFSymbol\textXSolidBrush{"2717}
+\DeclareUTFSymbol\textPlusOutline{"2719}
+\DeclareUTFSymbol\textPlus{"271A}
+\DeclareUTFSymbol\textPlusThinCenterOpen{"271B}
+\DeclareUTFSymbol\textPlusCenterOpen{"271C}
+\DeclareUTFSymbol\textCross{"271D}
+\DeclareUTFSymbol\textCrossOpenShadow{"271E}
+\DeclareUTFSymbol\textCrossOutline{"271F}
+\DeclareUTFSymbol\textCrossMaltese{"2720}
+\DeclareUTFSymbol\textDavidStar{"2721}
+\DeclareUTFSymbol\textFourAsterisk{"2722}
+\DeclareUTFSymbol\textJackStar{"2723}
+\DeclareUTFSymbol\textJackStarBold{"2724}
+\DeclareUTFSymbol\textClowerTips{"2725}
+\DeclareUTFSymbol\textFourStar{"2726}
+\DeclareUTFSymbol\textFourStarOpen{"2727}
+\DeclareUTFSymbol\textFiveStarOpenCircled{"272A}
+\DeclareUTFSymbol\textFiveStarCenterOpen{"272B}
+\DeclareUTFSymbol\textFiveStarOpenDotted{"272C}
+\DeclareUTFSymbol\textFiveStarOutline{"272D}
+\DeclareUTFSymbol\textFiveStarOutlineHeavy{"272E}
+\DeclareUTFSymbol\textFiveStarConvex{"272F}
+\DeclareUTFSymbol\textFiveStarShadow{"2730}
+\DeclareUTFSymbol\textAsteriskBold{"2731}
+\DeclareUTFSymbol\textAsteriskCenterOpen{"2732}
+\DeclareUTFSymbol\textEightStarTaper{"2734}
+\DeclareUTFSymbol\textEightStarConvex{"2735}
+\DeclareUTFSymbol\textSixStar{"2736}
+\DeclareUTFSymbol\textEightStar{"2737}
+\DeclareUTFSymbol\textEightStarBold{"2738}
+\DeclareUTFSymbol\textTwelveStar{"2739}
+\DeclareUTFSymbol\textSixteenStarLight{"273A}
+\DeclareUTFSymbol\textSixFlowerPetalRemoved{"273B}
+\DeclareUTFSymbol\textSixFlowerOpenCenter{"273C}
+\DeclareUTFSymbol\textAsterisk{"273D}
+\DeclareUTFSymbol\textSixFlowerAlternate{"273E}
+\DeclareUTFSymbol\textFiveFlowerPetal{"273F}
+\DeclareUTFSymbol\textFiveFlowerOpen{"2740}
+\DeclareUTFSymbol\textEightFlowerPetal{"2741}
+\DeclareUTFSymbol\textSunshineOpenCircled{"2742}
+\DeclareUTFSymbol\textSixFlowerAltPetal{"2743}
+\DeclareUTFSymbol\textSnowflakeChevron{"2744}
+\DeclareUTFSymbol\textSnowflake{"2745}
+\DeclareUTFSymbol\textSnowflakeChevronBold{"2746}
+\DeclareUTFSymbol\textSparkle{"2747}
+\DeclareUTFSymbol\textSparkleBold{"2748}
+\DeclareUTFSymbol\textAsteriskRoundedEnds{"2749}
+\DeclareUTFSymbol\textEightFlowerPetalRemoved{"274A}
+\DeclareUTFSymbol\textEightAsterisk{"274B}
+\DeclareUTFSymbol\textCircleShadow{"274D}
+\DeclareUTFSymbol\textSquareShadowBottomRight{"274F}
+\DeclareUTFSymbol\textSquareTopRight{"2750}
+\DeclareUTFSymbol\textSquareCastShadowBottomRight{"2751}
+\DeclareUTFSymbol\textSquareCastShadowTopRight{"2752}
+\DeclareUTFSymbol\textDiamandSolid{"2756}
+\DeclareUTFSymbol\textRectangleThin{"2758}
+\DeclareUTFSymbol\textRectangle{"2759}
+\DeclareUTFSymbol\textRectangleBold{"275A}
+\DeclareUTFSymbol\textperp{"27C2}
+\DeclareUTFCommand\textnotperp{\textlstrikethru\textperp}
+\DeclareUTFSymbol\textveedot{"27C7}
+\DeclareUTFSymbol\textwedgedot{"27D1}
+\DeclareUTFSymbol\textleftspoon{"27DC}
+\DeclareUTFSymbol\textlbrackdbl{"27E6}
+\DeclareUTFSymbol\textrbrackdbl{"27E7}
+\DeclareUTFSymbol\textcirclearrowleft{"27F2}
+\DeclareUTFSymbol\textcirclearrowright{"27F3}
+\DeclareUTFSymbol\textlongleftarrow{"27F5}
+\DeclareUTFSymbol\textlongrightarrow{"27F6}
+\DeclareUTFSymbol\textlongleftrightarrow{"27F7}
+\DeclareUTFSymbol\textLongleftarrow{"27F8}
+\DeclareUTFSymbol\textLongrightarrow{"27F9}
+\DeclareUTFSymbol\textLongleftrightarrow{"27FA}
+\DeclareUTFSymbol\textlongmapsto{"27FC}
+\DeclareUTFSymbol\textLongmapsfrom{"27FD}
+\DeclareUTFSymbol\textLongmapsto{"27FE}
+\DeclareUTFSymbol\textnwsearrow{"2921}
+\DeclareUTFSymbol\textneswarrow{"2922}
+\DeclareUTFSymbol\textlhooknwarrow{"2923}
+\DeclareUTFSymbol\textrhooknearrow{"2924}
+\DeclareUTFSymbol\textlhooksearrow{"2925}
+\DeclareUTFSymbol\textrhookswarrow{"2926}
+\DeclareUTFSymbol\textleadsto{"2933}
+\DeclareUTFSymbol\textrcurvearrowne{"2934}
+\DeclareUTFSymbol\textlcurvearrowse{"2935}
+\DeclareUTFSymbol\textlcurvearrowsw{"2936}
+\DeclareUTFSymbol\textrcurvearrowse{"2937}
+\DeclareUTFSymbol\textlcurvearrowdown{"2938}
+\DeclareUTFSymbol\textrcurvearrowdown{"2939}
+\DeclareUTFSymbol\textrcurvearrowleft{"293A}
+\DeclareUTFSymbol\textrcurvearrowright{"293B}
+\DeclareUTFSymbol\textleftrightharpoon{"294A}
+\DeclareUTFSymbol\textrightleftharpoon{"294B}
+\DeclareUTFSymbol\textupdownharpoonrightleft{"294C}
+\DeclareUTFSymbol\textupdownharpoonleftright{"294D}
+\DeclareUTFSymbol\textleftleftharpoons{"2962}
+\DeclareUTFSymbol\textupupharpoons{"2963}
+\DeclareUTFSymbol\textrightrightharpoons{"2964}
+\DeclareUTFSymbol\textdowndownharpoons{"2965}
+\DeclareUTFSymbol\textleftbarharpoon{"296A}
+\DeclareUTFSymbol\textbarleftharpoon{"296B}
+\DeclareUTFSymbol\textrightbarharpoon{"296C}
+\DeclareUTFSymbol\textbarrightharpoon{"296D}
+\DeclareUTFSymbol\textupdownharpoons{"296E}
+\DeclareUTFSymbol\textdownupharpoons{"296F}
+\DeclareUTFSymbol\textllparenthesis{"2987}
+\DeclareUTFSymbol\textrrparenthesis{"2988}
+\DeclareUTFSymbol\textinvdiameter{"29B0}
+\DeclareUTFSymbol\textobar{"29B6}
+\DeclareUTFSymbol\textobslash{"29B8}
+\DeclareUTFSymbol\textobot{"29BA}
+\DeclareUTFSymbol\textNoChemicalCleaning{"29BB}
+\DeclareUTFSymbol\textolessthan{"29C0}
+\DeclareUTFSymbol\textogreaterthan{"29C1}
+\DeclareUTFSymbol\textboxslash{"29C4}
+\DeclareUTFSymbol\textboxbslash{"29C5}
+\DeclareUTFSymbol\textboxast{"29C6}
+\DeclareUTFSymbol\textboxcircle{"29C7}
+\DeclareUTFSymbol\textboxbox{"29C8}
+\DeclareUTFSymbol\textValve{"29D3}
+\DeclareUTFSymbol\textmultimapboth{"29DF}
+\DeclareUTFSymbol\textshuffle{"29E2}
+\DeclareUTFSymbol\textuplus{"2A04}
+\DeclareUTFSymbol\textbigdoublewedge{"2A07}
+\DeclareUTFSymbol\textbigdoublevee{"2A08}
+\DeclareUTFSymbol\textJoin{"2A1D}
+\DeclareUTFSymbol\textfatsemi{"2A1F}
+\DeclareUTFSymbol\textcircplus{"2A22}
+\DeclareUTFSymbol\textminusdot{"2A2A}
+\DeclareUTFSymbol\textdottimes{"2A30}
+\DeclareUTFSymbol\textdtimes{"2A32}
+\DeclareUTFSymbol\textodiv{"2A38}
+\DeclareUTFSymbol\textinvneg{"2A3C}
+\DeclareUTFSymbol\textsqdoublecap{"2A4E}
+\DeclareUTFSymbol\textcapdot{"2A40}
+\DeclareUTFSymbol\textsqdoublecup{"2A4F}
+\DeclareUTFSymbol\textdoublewedge{"2A55}
+\DeclareUTFSymbol\textdoublevee{"2A56}
+\DeclareUTFSymbol\textdoublebarwedge{"2A5E}
+\DeclareUTFSymbol\textveedoublebar{"2A63}
+\DeclareUTFSymbol\texteqdot{"2A66}
+\DeclareUTFCommand\textneqdot{\textlstrikethru\texteqdot}
+\DeclareUTFSymbol\textcoloncolonequals{"2A74}
+\DeclareUTFSymbol\textleqslant{"2A7D}
+\DeclareUTFCommand\textnleqslant{\textlstrikethrux\textleqslant}
+\DeclareUTFSymbol\textgeqslant{"2A7E}
+\DeclareUTFCommand\textngeqslant{\textlstrikethru\textgeqslant}
+\DeclareUTFSymbol\textlessapprox{"2A85}
+\DeclareUTFCommand\textnlessapprox{\textlstrikethru\textnlessapprox}
+\DeclareUTFSymbol\textgtrapprox{"2A86}
+\DeclareUTFCommand\textngtrapprox{\textlstrikethru\textgtrapprox}
+\DeclareUTFSymbol\textlneq{"2A87}
+\DeclareUTFSymbol\textgneq{"2A88}
+\DeclareUTFSymbol\textlnapprox{"2A89}
+\DeclareUTFSymbol\textgnapprox{"2A8A}
+\DeclareUTFSymbol\textlesseqqgtr{"2A8B}
+\DeclareUTFSymbol\textgtreqqless{"2A8C}
+\DeclareUTFSymbol\texteqslantless{"2A95}
+\DeclareUTFSymbol\texteqslantgtr{"2A96}
+\DeclareUTFSymbol\textleftslice{"2AA6}
+\DeclareUTFSymbol\textrightslice{"2AA7}
+\DeclareUTFSymbol\textpreceq{"2AAF}
+\DeclareUTFCommand\textnpreceq{\textlstrikethru\textpreceq}
+\DeclareUTFSymbol\textsucceq{"2AB0}
+\DeclareUTFCommand\textnsucceq{\textlstrikethru\textsucceq}
+\DeclareUTFSymbol\textprecneq{"2AB1}
+\DeclareUTFSymbol\textsuccneq{"2AB2}
+\DeclareUTFSymbol\textpreceqq{"2AB3}
+\DeclareUTFCommand\textnpreceqq{\textlstrikethru\textpreceqq}
+\DeclareUTFSymbol\textsucceqq{"2AB4}
+\DeclareUTFCommand\textnsucceqq{\textlstrikethru\textsucceqq}
+\DeclareUTFSymbol\textprecneqq{"2AB5}
+\DeclareUTFSymbol\textsuccneqq{"2AB6}
+\DeclareUTFSymbol\textprecapprox{"2AB7}
+\DeclareUTFCommand\textnprecapprox{\textlstrikethru\textprecapprox}
+\DeclareUTFSymbol\textsuccapprox{"2AB8}
+\DeclareUTFCommand\textnsuccapprox{\textlstrikethru\textsuccapprox}
+\DeclareUTFSymbol\textprecnapprox{"2AB9}
+\DeclareUTFSymbol\textsuccnapprox{"2ABA}
+\DeclareUTFSymbol\textsubseteqq{"2AC5}
+\DeclareUTFCommand\textnsubseteqq{\textlstrikethru\textsubseteqq}
+\DeclareUTFSymbol\textsupseteqq{"2AC6}
+\DeclareUTFCommand\textnsupseteqq{\textlstrikethru\textsupseteqq}
+\DeclareUTFSymbol\textdashV{"2AE3}
+\DeclareUTFCommand\textndashV{\textlstrikethru\textdashV}
+\DeclareUTFSymbol\textDashv{"2AE4}
+\DeclareUTFCommand\textnDashv{\textlstrikethru\textDashv}
+\DeclareUTFSymbol\textDashV{"2AE5}
+\DeclareUTFCommand\textnDashV{\textlstrikethru\textDashV}
+\DeclareUTFSymbol\textdownmodels{"2AEA}
+\DeclareUTFCommand\textndownmodels{\textlstrikethru\textdownmodels}
+\DeclareUTFSymbol\textupmodels{"2AEB}
+\DeclareUTFCommand\textnupmodels{\textlstrikethru\textupmodels}
+\DeclareUTFSymbol\textupspoon{"2AEF}
+\DeclareUTFSymbol\textinterleave{"2AF4}
+\DeclareUTFSymbol\textsslash{"2AFD}
+\DeclareUTFSymbol\textpentagon{"2B20}
+\DeclareUTFSymbol\textvarhexagon{"2B21}
+\DeclareUTFSymbol\textjinferior{"2C7C}
+\DeclareUTFSymbol\textslashdiv{"2E13}
+\DeclareUTFSymbol\textinterrobangdown{"2E18}
+\DeclareUTFSymbol\textfivedots{"2E2D}
+\DeclareUTFSymbol\textPUheng{"A727}
+\DeclareUTFSymbol\textPUlhookfour{"A72C}
+\DeclareUTFSymbol\textPUscf{"A730}
+\DeclareUTFSymbol\textPUaolig{"A735}
+\DeclareUTFSymbol\textoo{"A74F}
+\DeclareUTFSymbol\textcircumlow{"A788}
+\DeclareUTFSymbol\textfi{"FB01}
+\DeclareUTFSymbol\textfl{"FB02}
+\DeclareUTFSymbol\textGaPa{"1D13B}
+\DeclareUTFSymbol\textHaPa{"1D13C}
+\DeclareUTFSymbol\textViPa{"1D13D}
+\DeclareUTFSymbol\textAcPa{"1D13E}
+\DeclareUTFSymbol\textSePa{"1D13F}
+\DeclareUTFSymbol\textZwPa{"1D140}
+\DeclareUTFSymbol\textfullnote{"1D15D}
+\DeclareUTFSymbol\texthalfnote{"1D15E}
+\DeclareUTFSymbol\textVier{"1D15F}
+\DeclareUTFSymbol\textAcht{"1D160}
+\DeclareUTFSymbol\textSech{"1D161}
+\DeclareUTFSymbol\textZwdr{"1D162}
+\DeclareUTFSymbol\textMundus{"1F30D}
+\DeclareUTFSymbol\textMoon{"1F319}
+\DeclareUTFSymbol\textManFace{"1F468}
+\DeclareUTFSymbol\textWomanFace{"1F469}
+\DeclareUTFSymbol\textFax{"1F4E0}
+\DeclareUTFSymbol\textFire{"1F525}
+\DeclareUTFSymbol\textBicycle{"1F6B2}
+\DeclareUTFSymbol\textGentsroom{"1F6B9}
+\DeclareUTFSymbol\textLadiesroom{"1F6BA}
+\DeclareUTFCommand\textcopyleft{\textcircled\textrevc}
+\DeclareUTFCommand\textccsa{\textcircled\textcirclearrowleft}
+\DeclareUTFSymbol\textglqq{"201E}
+\DeclareUTFSymbol\textgrqq{"201C}
+\DeclareUTFSymbol\textglq{"201A}
+\DeclareUTFSymbol\textgrq{"2018}
+\DeclareUTFSymbol\textflqq{"00AB}
+\DeclareUTFSymbol\textfrqq{"00BB}
+\DeclareUTFSymbol\textflq{"2039}
+\DeclareUTFSymbol\textfrq{"203A}
+\DeclareUTFSymbol\textneg{"00AC}
+\DeclareUTFSymbol\textcdot{"00B7}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</xunextra>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \begin{macrocode}
+%<@@=xeCJK>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK.cfg}}
+%
+% \begin{macrocode}
+%<*config>
+% \end{macrocode}
+%
+% 预设的配置文件 \file{xeCJK.cfg} 为一个空文件。可以在里面增加设置,然后保存到
+% 本地目录下面。
+% \begin{macrocode}
+
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</config>
+% \end{macrocode}
+%
+% \Finale
+%
+% \endinput
+%
+% \DisableImplementation
+%
+% \begin{implementation}
+%
+% \makeatletter
+% \let\special@index\@gobble
+% \makeatother
+%
+% \section{例子}
+%
+% \subsection{\pkg{xeCJK-example-autofake.tex}}
+%
+% \begin{macrocode}
+%<*ex-autofake>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{article}
+\usepackage[AutoFakeBold,AutoFakeSlant]{xeCJK}
+\setCJKmainfont[BoldFont=simhei.ttf, SlantedFont=simkai.ttf]{simsun.ttc}
+\setCJKsansfont[AutoFakeSlant=false,
+ BoldFont=simhei.ttf, SlantedFont=simkai.ttf]{simsun.ttc}
+\setCJKmonofont[ItalicFont=simkai.ttf]{simsun.ttc}
+\begin{document}
+\centering
+\begin{tabular}{lllll}
+\hline
+ {\bf rm} & md & up & \verb|\rmfamily\mdseries\upshape| &
+ {\rmfamily\mdseries\upshape English 中文字体} \\
+ & md & it & \verb|\rmfamily\mdseries\itshape| &
+ {\rmfamily\mdseries\itshape English 中文字体} \\
+ & md & sl & \verb|\rmfamily\mdseries\slshape| &
+ {\rmfamily\mdseries\slshape English 中文字体} \\ \cline{2-5}
+ & bf & up & \verb|\rmfamily\bfseries\upshape| &
+ {\rmfamily\bfseries\upshape English 中文字体} \\
+ & bf & it & \verb|\rmfamily\bfseries\itshape| &
+ {\rmfamily\bfseries\itshape English 中文字体} \\
+ & bf & sl & \verb|\rmfamily\bfseries\slshape| &
+ {\rmfamily\bfseries\slshape English 中文字体} \\ \hline
+ {\bf sf} & md & up & \verb|\sffamily\mdseries\upshape| &
+ {\sffamily\mdseries\upshape English 中文字体} \\
+ & md & it & \verb|\sffamily\mdseries\itshape| &
+ {\sffamily\mdseries\itshape English 中文字体} \\
+ & md & sl & \verb|\sffamily\mdseries\slshape| &
+ {\sffamily\mdseries\slshape English 中文字体} \\ \cline{2-5}
+ & bf & up & \verb|\sffamily\bfseries\upshape| &
+ {\sffamily\bfseries\upshape English 中文字体} \\
+ & bf & it & \verb|\sffamily\bfseries\itshape| &
+ {\sffamily\bfseries\itshape English 中文字体} \\
+ & bf & sl & \verb|\sffamily\bfseries\slshape| &
+ {\sffamily\bfseries\slshape English 中文字体} \\ \hline
+ {\bf tt} & md & up & \verb|\ttfamily\mdseries\upshape| &
+ {\ttfamily\mdseries\upshape English 中文字体} \\
+ & md & it & \verb|\ttfamily\mdseries\itshape| &
+ {\ttfamily\mdseries\itshape English 中文字体} \\
+ & md & sl & \verb|\ttfamily\mdseries\slshape| &
+ {\ttfamily\mdseries\slshape English 中文字体} \\ \cline{2-5}
+ & bf & up & \verb|\ttfamily\bfseries\upshape| &
+ {\ttfamily\bfseries\upshape English 中文字体} \\
+ & bf & it & \verb|\ttfamily\bfseries\itshape| &
+ {\ttfamily\bfseries\itshape English 中文字体} \\
+ & bf & sl & \verb|\ttfamily\bfseries\slshape| &
+ {\ttfamily\bfseries\slshape English 中文字体} \\ \hline
+\end{tabular}
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-autofake>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-fallback.tex}}
+%
+% \begin{macrocode}
+%<*ex-fallback>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{article}
+\usepackage[AutoFallBack]{xeCJK}
+\usepackage{xeCJKfntef}
+\usepackage{array}
+\setCJKmainfont[AutoFakeBold,AutoFakeSlant]{KaiTi_GB2312}
+\setCJKfallbackfamilyfont{\CJKrmdefault}[BoldFont=SimHei]
+ { [SlantedFont=FangSong]{SimSun} ,
+ [BoldFont=*] {SimSun-ExtB} }
+\begin{document}
+漢字源𣴑考
+
+\textbf{漢字源𣴑考}
+
+\textsl{漢字源𣴑考}
+
+\CJKunderwave{漢字源𣴑考}
+\begin{table}[ht]
+\caption{生僻字测试}
+\medskip\centering
+\begin{tabular}{*4{|c>{\ttfamily U+}l}|}
+㐀 & 3400 & 㐁 & 3401 & 㐂 & 3402 & 㐃 & 3403 \\
+㐄 & 3404 & 㐅 & 3405 & 㐆 & 3406 & 㐇 & 3407 \\
+㐈 & 3408 & 㐉 & 3409 & 㐊 & 340A & 㐋 & 340B \\
+㐌 & 340C & 㐍 & 340D & 㐎 & 340E & 㐏 & 341F \\
+㐐 & 3410 & 㐑 & 3411 & 㐒 & 3412 & 㐓 & 3413 \\
+㐔 & 3414 & 㐕 & 3415 & 㐖 & 3416 & 㐗 & 3417 \\
+㐘 & 3418 & 㐙 & 3419 & 㐚 & 341A & 㐛 & 341B \\
+㐜 & 341C & 㐝 & 341D & 㐞 & 341E & 㐟 & 341F \\[1ex]
+𠀀 & 20000 & 𠀁 & 20001 & 𠀂 & 20002 & 𠀃 & 20003 \\
+𠀄 & 20004 & 𠀅 & 20005 & 𠀆 & 20006 & 𠀇 & 20007 \\
+𠀈 & 20008 & 𠀉 & 20009 & 𠀊 & 2000A & 𠀋 & 2000B \\
+𠀌 & 2000C & 𠀍 & 2000D & 𠀎 & 2000E & 𠀏 & 2000F \\
+𠀐 & 20010 & 𠀑 & 20011 & 𠀒 & 20012 & 𠀓 & 20013 \\
+𠀔 & 20014 & 𠀕 & 20015 & 𠀖 & 20016 & 𠀗 & 20017 \\
+𠀘 & 20018 & 𠀙 & 20019 & 𠀚 & 2001A & 𠀛 & 2001B \\
+𠀜 & 2001C & 𠀝 & 2001D & 𠀞 & 2001E & 𠀟 & 2001F \\
+\end{tabular}
+\end{table}
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-fallback>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-subCJKblock.tex}}
+%
+% \begin{macrocode}
+%<*ex-block>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{article}
+\usepackage{xeCJK}
+\usepackage{array}
+\xeCJKDeclareSubCJKBlock{Ext-A} { "3400 -> "4DBF }
+\xeCJKDeclareSubCJKBlock{Ext-B} { "20000 -> "2A6DF }
+\xeCJKDeclareSubCJKBlock{Kana} { "3040 -> "309F, "30A0 -> "30FF, "31F0 -> "31FF, }
+\xeCJKDeclareSubCJKBlock{Hangul}{ "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF }
+\setCJKmainfont[Ext-A=SimHei,Ext-B=SimSun-ExtB]{SimSun}
+\setCJKmainfont[Kana]{Meiryo}
+\setCJKmainfont[Hangul]{Malgun Gothic}
+\parindent=2em
+\begin{document}
+\long\def\showtext{%
+中日韩越统一表意文字(英语:CJKV Unified Ideographs),旧称中日韩统一表意文字(英语:CJK Unified Ideographs),也称统一汉字(英语:Unihan),目的是要把分别来自中文、日文、韩文、越文、壮文中,对于相同起源、本义相同、形状一样或稍异的表意文字(主要为汉字,但也有仿汉字如:方块壮字、日文汉字(かんじ / kanji)、韩文汉字(한자 / hanja)、越南的喃字(Chữ Nôm)与越文汉字(Chữ Nho,在越南也称作儒字),应赋予其在ISO 10646及统一码标准中有相同编码。此计划原本只包含中文、日文及韩文中所使用的汉字,是以旧称中日韩统一表意文字(CJK)。后来,此计划加入了越文的喃字,所以合称中日韩越统一表意文字(CJKV)。
+
+CJK統合漢字(シージェーケーとうごうかんじ、CJK Unified Ideographs)は、ISO/IEC 10646 (Universal Multiple-Octet Coded Character Set, 略称 UCS) および Unicodeにて採用されている符号化用漢字集合およびその符号表である。CJK統合漢字の名称は、中国語(Chinese)、日本語(Japanese)、韓国語(Korean)で使われている漢字をひとまとめにしたことからきている。CJK統合漢字の初版である Unified Repertoire and Ordering (URO) 第二版は1992年に制定されたが、1994年にベトナムで使われていた漢字も含めることにしたため、CJKVと呼ばれる事もある。CJKVは、中国語・日本語・韓国語・ベトナム語 (英語: Chinese-Japanese-Korean-Vietnamese) の略。特に、その4言語で共通して使われる、または使われていた文字体系である漢字(チュノムを含む)のこと。ソフトウェアの国際化、中でも文字コードに関する分野で用いられる。
+
+\CJKspace
+한중일월 통합 한자(또는 한중일 통합 한자)는 유니코드에 담겨 있는 한자들의 집합으로, 한국, 중국, 일본에서 쓰이는 한자를 묶은 것이기 때문에 머리 글자를 따서 한중일(CJK) 통합 한자라고 불렀는데, 최근에는 베트남에서 쓰이는 한자도 추가되었기에 한중일월(CJKV) 통합 한자로 부르게 되었다.
+
+처음에 유니코드에는 65,536($=2^{16}$)자만 들어갈 수 있었기 때문에, 가장 많은 문자가 배당되는 한자를 위해서 한국, 중국, 일본에서 사용하는 한자 중에 모양이 유사하며 그 뜻이 같은 글자를 같은 코드로 통합했다. 따라서 문자 코드만으로 그 한자가 사용되는 언어를 알아 낼 수 없는데, 다만 중국의 간체자나 번체자, 일본의 구자체나 신자체 등 분명하게 모양이 다른 글자는 별도의 부호를 할당하고 있다. 이런 문자 할당 정책에 반발하여 TRON과 같은 인코딩이 만들어지기도 했으나, 실제로 통합된 한자의 차이가 별로 크지 않기 때문에 문제가 되지 않는다는 의견도 있다.
+\CJKnospace}
+\showtext
+
+\bigskip
+\xeCJKCancelSubCJKBlock{Kana,Hangul}
+\showtext
+
+\bigskip
+\xeCJKRestoreSubCJKBlock{Hangul}
+\showtext
+
+\begin{table}[ht]
+\caption{生僻字测试}
+\medskip\centering
+\begin{tabular}{*4{|c>{\ttfamily U+}l}|}
+㐀 & 3400 & 㐁 & 3401 & 㐂 & 3402 & 㐃 & 3403 \\
+㐄 & 3404 & 㐅 & 3405 & 㐆 & 3406 & 㐇 & 3407 \\
+㐈 & 3408 & 㐉 & 3409 & 㐊 & 340A & 㐋 & 340B \\
+㐌 & 340C & 㐍 & 340D & 㐎 & 340E & 㐏 & 341F \\
+㐐 & 3410 & 㐑 & 3411 & 㐒 & 3412 & 㐓 & 3413 \\
+㐔 & 3414 & 㐕 & 3415 & 㐖 & 3416 & 㐗 & 3417 \\
+㐘 & 3418 & 㐙 & 3419 & 㐚 & 341A & 㐛 & 341B \\
+㐜 & 341C & 㐝 & 341D & 㐞 & 341E & 㐟 & 341F \\[1ex]
+𠀀 & 20000 & 𠀁 & 20001 & 𠀂 & 20002 & 𠀃 & 20003 \\
+𠀄 & 20004 & 𠀅 & 20005 & 𠀆 & 20006 & 𠀇 & 20007 \\
+𠀈 & 20008 & 𠀉 & 20009 & 𠀊 & 2000A & 𠀋 & 2000B \\
+𠀌 & 2000C & 𠀍 & 2000D & 𠀎 & 2000E & 𠀏 & 2000F \\
+𠀐 & 20010 & 𠀑 & 20011 & 𠀒 & 20012 & 𠀓 & 20013 \\
+𠀔 & 20014 & 𠀕 & 20015 & 𠀖 & 20016 & 𠀗 & 20017 \\
+𠀘 & 20018 & 𠀙 & 20019 & 𠀚 & 2001A & 𠀛 & 2001B \\
+𠀜 & 2001C & 𠀝 & 2001D & 𠀞 & 2001E & 𠀟 & 2001F \\
+\end{tabular}
+\end{table}
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-block>
+% \end{macrocode}
+%
+%
+% \subsection{\pkg{xeCJK-example-CJKecglue.tex}}
+%
+% \begin{macrocode}
+%<*ex-ecglue>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{minimal}
+\usepackage{xeCJK}
+\setCJKmainfont[BoldFont=SimHei]{SimSun}
+\long\def\showtext{%
+ 这是 English 中文 {\itshape Chinese} 中文 \TeX\
+ 间隔 \textit{Italic} 中文\textbf{字体} a 数学 $b$ 数学 $c$ $d$\par
+ 这是English中文{\itshape Chinese}中文\TeX\
+ 间隔\textit{Italic}中文\textbf{字体}a数学$b$数学$c$ $d$\par
+This is an example. 这是一个例子}
+\begin{document}
+\showtext
+
+\hrulefill\bigskip
+
+\xeCJKsetup{xCJKecglue=\quad}
+\showtext
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-ecglue>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-checksingle.tex}}
+%
+% \begin{macrocode}
+%<*ex-single>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{minimal}
+\usepackage{xeCJK}
+\setCJKmainfont{SimSun}
+\long\def\showtext{一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十。
+\[x^2+y^2\]
+一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十。
+$$x^2+y^2$$
+一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十。
+\begin{equation}
+x^2+y^2
+\end{equation}
+一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十。}
+\begin{document}
+\hsize=30em
+\parindent=0pt
+\showtext
+
+\hrulefill\bigskip
+
+\xeCJKsetup{CheckSingle}
+\showtext
+
+\hrulefill\bigskip
+
+\xeCJKsetup{PlainEquation}
+\showtext
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-single>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-CJKfntef.tex}}
+%
+% \begin{macrocode}
+%<*ex-fntef>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{ctexart}
+\usepackage{xcolor}
+\usepackage{xeCJKfntef}
+\xeCJKDeclareSubCJKBlock{test}{ `殆 , `已 }
+\setCJKmainfont[test=SimHei]{SimSun}
+
+\def\showtext{%
+ 庄子曰:“吾生也有涯,而知也无涯。以有涯随无涯,殆已!已而为知者,殆而已矣!%
+ 为善无近名,为恶无近刑,缘督以为经,可以保身,可以全生,可以养亲,可以尽年。”}
+\newcommand\CJKfntef[1]{%
+ \csname#1\endcsname{\showtext}\par
+ \csname#1\endcsname*{\showtext}\par
+ \CJKunderdot{\showtext\csname#1\endcsname{\showtext}}\par
+ \CJKunderdot{\showtext\csname#1\endcsname*{\showtext}}\par
+ \csname#1\endcsname{\showtext\CJKunderdot{\showtext}}\par
+ \csname#1\endcsname*{\showtext\CJKunderdot{\showtext}}\par\bigskip}
+
+\begin{document}
+
+\section{\textsf{xeCJKfntef} 的\CJKunderdot{简单测试文件}}
+
+\CJKunderline{汉 字}\CJKunderline{加下划线}
+\varCJKunderline{汉字}\varCJKunderline{加下划线}
+\CJKunderanyline{0.5em}{\sixly \kern-.021em\char58 \kern-.021em}{自定义下划线}
+\CJKunderanyline{0.2em}{\kern-.03em\vtop{\kern.2ex\hrule width.2em\kern 0.11em
+ \hrule height 0.1em}\kern-.03em}{自定义下划线}
+
+\CJKunderanyline{0.5em}{-}{\showtext}
+
+\CJKunderanysymbol{0.2em}{-}{\showtext}
+
+\CJKunderdot{\showtext}
+
+\hrule depth \dp\strutbox width 0 pt \relax
+
+\begin{CJKfilltwosides}{40mm}
+两端分散对齐\\
+分散对齐\\
+\CJKunderdot{汉字可加点}\\
+\CJKunderline{汉字可加下划线}
+\end{CJKfilltwosides}
+
+\hrule depth \dp\strutbox width 0 pt \relax
+
+\CJKfntef{CJKunderline}
+\CJKfntef{CJKunderwave}
+\CJKfntef{CJKunderdblline}
+\CJKfntef{CJKsout}
+\CJKfntef{CJKxout}
+
+\def\Book{\CJKunderwave-}
+\def\Noun{\CJKunderline-}
+
+如上所述,\Book{中國文學史}原是\Noun{復旦大學出版社}出版的,\Book{中國文學史新著}則由\Noun{上海文藝出版社}出版。現承\Noun{復旦大學出版社}\Noun{賀聖遂}先生的盛情和\Noun{上海文藝出版總社}\Noun{楊益萍}、\Noun{何承偉}先生以及有關負責人\Noun{陳鳴華}先生的高誼,此書增訂本改由兩社聯合出版。\Noun{賀聖遂}先生並與\Noun{杜榮根}副社長、\Noun{韓結根}編審共同擔任此書的責任編輯。對上述諸位先生謹在這裡表示衷心的感謝。對\Book{中國文學史新著}原版的責任編輯\Noun{戴俊}先生(現為\Noun{上海三聯書店}副總經理)也在此一併致謝。
+
+\Noun{與文學史的}\Noun{應有任務}\Noun{對文學發展過程}\Noun{的內在聯繫的描述}\Noun{還有很大的距離}\Noun{至於距離的所在}\Noun{本書原已有說明}\Book{此不贅述}\Book{為了對學術負責}\Book{我們決定重寫一部並迅即出版}
+
+\Noun{南朝}\Noun{梁}\Noun{劉勰}\Book{文心雕龍}\Book{養氣}
+
+\Noun{鎌池和馬}\Book{魔法禁書目錄}\Book{某科學的超電磁砲}
+
+\Noun{西尾維新}\Book{化物語}\Book{偽物語}\Book{貓物語}%
+\Book{傾物语}\Book{囤物語}\Book{鬼物語}\Book{戀物語}\Book{花物語}
+
+\Noun{岡田麿里}\Book{我們仍未知道那天所看見的花的名字。}\Book{絕園的暴風雨}
+
+\Noun{虚淵玄}\Book{Fate/Zero}\Book{PSYCHO-PASS}\Book{ALDNOAH.ZERO}
+
+\Noun{劉海洋}\Book{\LaTeX 入門}
+
+\def\NAME{%
+ \x{御坂美琴}\x{白井黑子}\x{戰場原緋多木}\x{阿良良木歷}%
+ \x{宿海仁太}\x{本間芽衣子}\x{瀧川吉野}\x{鎖部葉風}%
+ \x{衛宮切嗣}\x{言峰綺禮}\x{常守朱}\x{狡嚙慎也}%
+ \x{界塚伊奈帆}\x*{艾瑟依拉姆·沃斯·艾莉歐斯亞}}
+
+\let\x\Noun\NAME
+
+\let\x\Book\NAME
+
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-fntef>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-punctstyle.tex}}
+%
+% \begin{macrocode}
+%<*ex-punctstyle>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{article}
+\usepackage[draft,columns=1,margin=false,headings=false]{typogrid}
+\usepackage{xeCJK}
+\usepackage{xeCJKfntef}
+\setCJKmainfont{SimSun}
+\xeCJKsetup{AllowBreakBetweenPuncts}
+\xeCJKDeclarePunctStyle { mine }
+ {
+ fixed-punct-ratio = nan ,
+ fixed-margin-width = 0 pt ,
+ mixed-margin-width = \maxdimen ,
+ mixed-margin-ratio = 0.5 ,
+ middle-margin-width = \maxdimen ,
+ middle-margin-ratio = 0.5 ,
+ add-min-bound-to-margin = true ,
+ min-bound-to-kerning = true ,
+ kerning-margin-minimum = 0.1 em ,
+ bound-punct-width = 0 em ,
+ enabled-hanging = true
+ }
+\xeCJKDeclarePunctStyle { JIS } { bound-punct-ratio = .5 }
+
+\begin{document}
+\setlength\parindent{2em}
+\newcommand\showexample[1]{%
+ \texttt{------ #1 ------}\par\xeCJKsetup{PunctStyle=#1}\showtexts\par}
+
+\newcommand\showtexts{%
+《第一回\quad 甄士隐梦幻识通灵\quad 贾雨村风尘怀闺秀》\\
+《第一回\quad 甄士隐梦幻识通灵\quad 贾雨村风尘怀闺秀》
+
+列位看官:你道此书从何而来?说起根由,虽近荒唐,细按则深有趣味。待在下将此来历注明,方使阅者了然不惑。
+
+\CJKunderline*{原来女娲氏炼石补天之时,于大荒山无稽崖炼成高经十二丈、方经二十四丈顽石三万六千五百零一块。娲皇氏只用了三万六千五百块,只单单剩了一块未用,便弃在此山青埂峰下。谁知此石自经煆炼之后,灵性已通,因见众石俱得补天,独自己无材不堪入选,遂自怨自叹,日夜悲号惭愧。}
+
+一日,正当嗟悼之际,俄见一僧一道远远而来,生得骨格不凡,丰神迥别,说说笑笑,来至峰下,坐于石边,高谈快论:先是说些云山雾海、神仙玄幻之事,后便说到红尘中荣华富贵。此石听了,不觉打动凡心,也想要到人间去享一享这荣华富贵,但自恨粗蠢,不得已,便口吐人言,向那僧道说道:“大师,弟子蠢物,不能见礼了!适闻二位谈那人世间荣耀繁华,心切慕之。弟子质虽粗蠢,性却稍通,况见二师仙形道体,定非凡品,必有补天济世之材,利物济人之德。如蒙发一点慈心,携带弟子得入红尘,在那富贵场中,温柔乡里受享几年,自当永佩洪恩,万劫不忘也!”二仙师听毕,齐憨笑道:“善哉,善哉!那红尘中有却有些乐事,但不能永远依恃;况又有‘美中不足,好事多磨’八个字紧相连属,瞬息间则又乐极悲生,人非物换,究竟是到头一梦,万境归空,倒不如不去的好。”这石凡心已炽,那里听得进这话去,乃复苦求再四。二仙知不可强制,乃叹道:“此亦静极思动,无中生有之数也!既如此,我们便携你去受享受享,只是到不得意时,切莫后悔!”石道:“自然,自然。”那僧又道:“若说你性灵,却又如此质蠢,并更无奇贵之处。如此也只好踮脚而已。也罢!我如今大施佛法,助你助,待劫终之日,复还本质,以了此案。你道好否?”石头听了,感谢不尽。那僧便念咒书符,大展幻术,将一块大石登时变成一块鲜明莹洁的美玉,且又缩成扇坠大小的可佩可拿。那僧托于掌上,笑道:“形体倒也是个宝物了!还只没有实在的好处,须得再镌上数字,使人一见便知是奇物方妙。然后好携你到那昌明隆盛之邦、诗礼簪缨之族、花柳繁华地、温柔富贵乡去安身乐业。”石头听了,喜不能禁,乃问:“不知赐了弟子那哪几件奇处?又不知携了弟子到何地方?望乞明示,使弟子不惑。”那僧笑道:“你且莫问,日后自然明白的。”说着,便袖了这石,同那道人飘然而去,竟不知投奔何方何舍。
+
+\hfill
+——曹雪芹《红楼梦》\unskip\unkern}
+
+
+\showexample{mine}
+\showexample{quanjiao}
+\showexample{JIS}
+\showexample{banjiao}
+\showexample{CCT}
+\showexample{kaiming}
+\showexample{hangmobanjiao}
+\showexample{plain}
+
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-punctstyle>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-verbatim.tex}}
+%
+% \begin{macrocode}
+%<*ex-verb>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass[a4paper]{article}
+\usepackage{xeCJK}
+\usepackage{fullpage}
+\xeCJKDeclareSubCJKBlock{Hangul}
+ { "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF }
+\setCJKmainfont{Adobe Song Std}
+\setCJKmainfont[Hangul]{Adobe Myungjo Std}
+%%\setmonofont{Inconsolata}
+%%\setmonofont{Source Code Pro}
+%%\setCJKmonofont{Adobe Kaiti Std}
+\setmonofont{TeX Gyre Cursor}
+\setCJKmonofont{Adobe Fangsong Std}
+\begin{document}
+
+\begin{verbatim}
+*************************************************************
+* *
+* 精致甲版红楼梦 - 精致工作室特别奉献(2010年9月) *
+* *
+* GBK简体、GBK繁体、Big5繁体、PDF简体、PDF繁体 *
+* *
+* 为 GBK、Big5 特别度身订制,并经反复修订,方便纯文本阅读 *
+* *
+* 精致甲、乙版红楼梦下载专页 *
+* http://www.speedy7.com/cn/stguru/gb2312/redmansions.htm *
+* http://www.speedy7.com/cn/stguru/big5/redmansions.htm *
+* *
+* 此电子文件可随意传播、发布、下载。 *
+* 传播时建议保留此版本说明供查阅与识别。 *
+* 未经修订者同意,不得将此版本用于商业用途。 *
+* 如您对红楼梦不具深入了解,请勿随便修改其中的内容。 *
+* *
+*************************************************************
+\end{verbatim}
+
+\verb|a 汉 字 b|
+
+\verb*|a 汉 字 b|
+
+\begin{verbatim}
+lang_set = {
+ ["English"] = lang.en,
+ ["Français"] = lang.fr,
+ ["Español"] = lang.es,
+ ["中文"] = lang.zh,
+ ["日本語"] = lang.ja,
+ ["한국어"] = lang.ko,
+}
+\end{verbatim}
+
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-verb>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-CM.tex}}
+%
+% \begin{macrocode}
+%<*ex-cm>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{article}
+\usepackage{xeCJK}
+\usepackage{hologo}
+
+\setCJKmainfont{HanaMinA} %% http://fonts.jp/hanazono/
+
+\begin{document}
+
+\hologo{XeTeX} でIVSを使うテスト。
+
+消󠄀化󠄀器󠄂 / 消󠄁火器󠄃 / 消󠄂化󠄁器󠄄
+
+消󠄃火器󠄅 / 消化󠄂器󠄆 / 消火器󠄇
+
+消化󠄃器󠄈 / 消火器󠄉 / 辻󠄂辻󠄃辻󠄄辻󠄅 
+
+\CJKfontspec{Meiryo}
+
+か
+
+がか゚
+
+ぼぽ
+
+ぼぽ
+
+ばぱ
+
+ばぱ
+
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-cm>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-listings.tex}}
+%
+% \begin{macrocode}
+%<*ex-listings>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{article}
+\usepackage[margin=1in]{geometry}
+\usepackage{listings,xcolor}
+\usepackage{showexpl}
+
+\usepackage{xeCJK}
+\setCJKmainfont{HanaMinA}
+\setCJKmonofont{SimSun}
+\xeCJKDeclareSubCJKBlock{Kana} { "3040 -> "309F, "30A0 -> "30FF, "31F0 -> "31FF }
+\setCJKmonofont[Kana]{Meiryo}
+\setmonofont{Latin Modern Mono Light}
+
+\makeatletter
+\lstset{%
+ basicstyle=\small\ttfamily,breakindent=4\lst@width,
+ numbers=left,numberstyle=\tiny\color{gray},
+ commentstyle=\color{green!50!black},keywordstyle=\color{blue}\bfseries,
+ identifierstyle=\color{violet},stringstyle=\color{brown},
+ escapebegin=\normalfont}
+\lstnewenvironment{cppcode}[1][]
+ {\lstset{language=C++,#1}}
+ {}
+\makeatother
+
+\begin{document}
+
+\section{\lstinline{\\lstinline} 测试}
+
+\section{\lstinline|甲*乙| 测试}
+
+\lstinline|abc汉字abc|
+
+\lstinline|甲*乙|
+
+\lstinline[mathescape]|数学公式$x^2+y^2$|
+
+\section{\lstinline{lstlisting} 环境测试}
+
+\begin{lstlisting}[basicstyle=\rmfamily]
+纯文字text测试
+ 纯文字text测试
+文字+文字
+文字(符号)文字
+辻󠄂辻󠄃辻󠄄辻󠄅
+かがか゚
+\end{lstlisting}
+
+\begin{lstlisting}
+text纯文字测试
+\end{lstlisting}
+
+\begin{lstlisting}
+text 纯文字测试
+\end{lstlisting}
+
+\begin{lstlisting}
+text,纯文字测试
+\end{lstlisting}
+
+\section{自定义环境测试}
+
+\begin{LTXexample}[pos=t,varwidth,numbersep=5pt,columns=fixed]
+\begin{cppcode}[escapechar=`,morekeywords=返回]
+#define 返回 return
+#include <iostream>
+/*
+ * 块注释
+ * `逃逸字符,测试$f(x)$`
+ */
+int main()
+{
+ // 行注释
+ const char *欢迎 = "hello 世界(ワールド)";
+ std::cout << 欢迎 << std::endl;
+ 返回 0;
+}
+\end{cppcode}
+\end{LTXexample}
+
+\section{\texttt{breaklines} 测试}
+
+\begin{lstlisting}[linewidth=10em,frame=single,rulecolor=\color{black},breaklines]
+断行文字text测试,断行文字text测试,断行文字text测试,断行文字text测试
+断行文字text测试,断行文字text测试,断行文字text测试,断行文字text测试
+\end{lstlisting}
+
+\section{\lstinline|\\lstinputlisting| 测试}
+
+\lstinputlisting[language={[AlLaTeX]TeX}]{\jobname}
+
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-listings>
+% \end{macrocode}
+%
+% \subsection{\pkg{xeCJK-example-mathblock.tex}}
+%
+% \begin{macrocode}
+%<*ex-mathblock>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{article}
+
+\usepackage{url}
+\usepackage[CJKmath]{xeCJK}
+
+\setCJKmainfont[BoldFont=SimHei]{SimSun}
+\setCJKmonofont{KaiTi}
+
+\ExplSyntaxOn
+\tl_const:Nn \c_test_text_tl { 天地玄黃宇宙洪荒日月盈昃辰宿列張寒來暑往秋收冬藏閏餘成歲律呂調陽 }
+\cs_new:Npn \test_color:n #1
+ { \exp_args:No \str_range:nnn { \mdfivesum {#1} } { 1 } { 6 } }
+\tl_map_inline:Nn \c_test_text_tl
+ {
+ \xeCJKDeclareSubCJKBlock {#1} { `#1 }
+ \setCJKmainfont
+ [ #1 , Color = \test_color:n {#1} , BoldFont = SimHei ] { SimSun }
+ \setCJKmonofont [ #1 ] { KaiTi }
+ }
+\cs_new_protected_nopar:Npn \TEST
+ {
+ \exp_args:No \path { \c_test_text_tl } \par
+ \c_test_text_tl \par
+ $ \c_test_text_tl $
+ }
+\ExplSyntaxOff
+
+\begin{document}
+
+\TEST
+
+\bigskip
+
+\bfseries\mathversion{bold}\TEST
+
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ex-mathblock>
+% \end{macrocode}
+%
+% \subsection{\pkg{xunicode-symbols.tex}}
+%
+% \begin{macrocode}
+%<*xunicode-symbols>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=xunsym>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass[a4paper]{article}
+\usepackage[margin=2cm]{geometry}
+\usepackage{fontspec}
+\usepackage{xunicode-addon}
+\usepackage{longtable,tabu,booktabs}
+\usepackage{zref-base}
+
+\setmainfont{FreeSerif}
+\newfontfamily\falllbackfont{Segoe UI Symbol}
+
+\makeatletter
+\ExplSyntaxOn
+\cs_new_protected_nopar:Npx \@@_restore_catcode:
+ { \char_set_catcode:nn { 0 } { \char_value_catcode:n { 0 } } }
+\file_if_exist:nTF { xunicode-commands.tex }
+ { \char_set_catcode_comment:n { 0 } }
+ { \char_set_catcode_ignore:n { 0 } }
+^^@ \tl_new:N \l_@@_command_tl
+^^@ \int_new:N \l_@@_command_int
+^^@ \iow_new:N \g_@@_command_iow
+^^@ \iow_new:N \g_@@_combine_mark_iow
+^^@ \ior_new:N \g_@@_unicode_ior
+^^@ \prop_new:N \l_@@_command_prop
+^^@ \prop_new:N \l_@@_combine_mark_prop
+^^@ \prop_new:N \l_@@_combine_marks_prop
+^^@ \cs_new_protected_nopar:Npn \SaveUTFCommands
+^^@ {
+^^@ \group_begin:
+^^@ \@@_restore_catcode:
+^^@ \cs_set_eq:NN \DeclareTextAccent \use_none:nnn
+^^@ \cs_set_eq:NN \DeclareUTFComposite \use_none:n
+^^@ \cs_set_eq:NN \DeclareUTFEncodedAccent \use_none:nnn
+^^@ \cs_set_eq:NN \DeclareUTFDoubleEncodedAccent \use_none:nnn
+^^@ \cs_set_eq:NN \DeclareUTFDoubleEncodedSymbol \use_none:nnn
+^^@ \cs_set_eq:NN \DeclareUTFCommand \use_none:nn
+^^@ \cs_set_eq:NN \DeclareUTFTIPACommand \use_none:n
+^^@ \cs_set_eq:NN \DeclareUTFCompositeCommand \use_none:nnn
+^^@ \cs_set_eq:NN \DeclareUTFSymbol \@@_save_UTF_command:Nn
+^^@ \cs_set_eq:NN \DeclareUTFCompositeSymbol \@@_save_UTF_command:Nnn
+^^@ \cs_set_eq:NN \DeclareEncodedCompositeCharacter \@@_save_combine_mark:nnnn
+^^@ \cs_set_eq:NN \DeclareEncodedCompositeAccents \@@_save_combine_marks:nnnn
+^^@ \DeclareDocumentCommand \DeclareUTFcharacter { O { \UTFencname } m m }
+^^@ { \@@_save_UTF_command:NNn \l_@@_command_prop {##3} {##2} }
+^^@ \DeclareDocumentCommand \DeclareUTFcomposite { O { \UTFencname } m m m }
+^^@ { \@@_save_UTF_command:NNnn \l_@@_command_prop {##3} {##4} {##2} }
+^^@ \ReloadXunicode { \UTFencname }
+^^@ \ior_open:NnTF \g_@@_unicode_ior { UnicodeData.txt }
+^^@ {
+^^@ \iow_open:Nn \g_@@_command_iow { xunicode-commands.tex }
+^^@ \iow_open:Nn \g_@@_combine_mark_iow { xunicode-combine-marks.tex }
+^^@ \ior_map_inline:Nn \g_@@_unicode_ior { \@@_make_table:w ##1 \q_stop }
+^^@ \@@_write_combine_marks:
+^^@ \ior_close:N \g_@@_unicode_ior
+^^@ \iow_close:N \g_@@_command_iow
+^^@ \iow_close:N \g_@@_combine_mark_iow
+^^@ \group_end:
+^^@ }
+^^@ {
+^^@ \group_end:
+^^@ \msg_fatal:nn { @@ } { UnicodeData }
+^^@ }
+^^@ }
+^^@ \msg_new:nnn { @@ } { UnicodeData }
+^^@ { File~`UnicodeData.txt`~not~found. }
+^^@ \cs_new_protected:Npn \@@_save_UTF_command:Nn
+^^@ { \@@_save_UTF_command:NNn \l_@@_command_prop }
+^^@ \cs_new_protected:Npn \@@_save_UTF_command:Nnn
+^^@ { \@@_save_UTF_command:NNnn \l_@@_command_prop }
+^^@ \cs_new_protected:Npn \@@_save_UTF_command:NNn #1#2#3
+^^@ { \@@_save_UTF_text_command:Nxx #1 { \use_none:n #3 } { \token_to_str:N #2 } }
+^^@ \cs_new_protected:Npn \@@_save_UTF_command:NNnn #1#2#3#4
+^^@ {
+^^@ \@@_save_UTF_text_command:Nxx #1 { \use_none:n #4 }
+^^@ {
+^^@ \token_to_str:N #2 \c_left_brace_str
+^^@ \tl_if_single:nTF {#3} { \token_to_str:N #3 } { \tl_to_str:n {#3} }
+^^@ \c_right_brace_str
+^^@ }
+^^@ }
+^^@ \cs_new_protected:Npn \@@_save_combine_mark:nnnn #1#2#3#4
+^^@ { \@@_save_UTF_text_command:Nxx \l_@@_combine_mark_prop {#3} { \token_to_str:N #2 } }
+^^@ \cs_new_protected:Npn \@@_save_combine_marks:nnnn #1#2#3#4
+^^@ { \@@_save_UTF_text_command:Nxx \l_@@_combine_marks_prop { { "#4 } { "#3 } } { \token_to_str:N #2 } }
+^^@ \cs_new_protected:Npn \@@_save_UTF_text_command:Nxx #1#2#3
+^^@ { \use:x { \@@_save_UTF_text_command:Nnn \exp_not:N #1 {#2} {#3} } }
+^^@ \cs_new_protected:Npn \@@_save_UTF_text_command:Nnn #1#2#3
+^^@ {
+^^@ \prop_get:NnNTF #1 {#2} \l_@@_command_tl
+^^@ { \prop_put:Nno #1 {#2} { \l_@@_command_tl , #3 } }
+^^@ { \prop_put:Nnn #1 {#2} {#3} }
+^^@ }
+^^@ \cs_new_protected:Npn \@@_make_table:w #1 ; #2 ; #3 \q_stop
+^^@ {
+^^@ \prop_get:NnNT \l_@@_command_prop {#1} \l_@@_command_tl
+^^@ {
+^^@ \iow_now:Nx \g_@@_command_iow
+^^@ { \token_to_str:N \UnicodeTextSymbol { "#1 } { \l_@@_command_tl } {#2} }
+^^@ }
+^^@ \prop_get:NnNT \l_@@_combine_mark_prop {#1} \l_@@_command_tl
+^^@ {
+^^@ \iow_now:Nx \g_@@_combine_mark_iow
+^^@ { \token_to_str:N \UnicodeCombineMark { "#1 } { \l_@@_command_tl } {#2} }
+^^@ }
+^^@ }
+^^@ \cs_new_protected:Npn \@@_write_combine_marks:
+^^@ {
+^^@ \prop_map_inline:Nn \l_@@_combine_marks_prop
+^^@ {
+^^@ \iow_now:Nx \g_@@_combine_mark_iow
+^^@ { \token_to_str:N \UnicodeCombineMarks ##1 {##2} }
+^^@ }
+^^@ }
+^^@ \ExplSyntaxOff
+^^@ \SaveUTFCommands
+^^@ \ExplSyntaxOn
+\@@_restore_catcode:
+\int_new:N \g_@@_symbol_int
+\int_new:N \g_@@_table_int
+\DeclareDocumentCommand \UnicodeTextSymbol { m v m }
+ {
+ \int_gincr:N \g_@@_symbol_int
+ \use_none:n #1 &
+ \scan_stop:
+ \reverse_if:N \tex_iffontchar:D \tex_font:D #1 \exp_stop_f: \falllbackfont \fi:
+ \tex_char:D #1 \exp_stop_f: &
+ \tl_set:Nn \l_tmpa_clist {#2}
+ \clist_use:Nn \l_tmpa_clist { \par }
+ \strut
+ & #3 \\
+ }
+\cs_set_eq:NN \UnicodeCombineMark \UnicodeTextSymbol
+\DeclareDocumentCommand \UnicodeCombineMarks { m m v }
+ {
+ \int_gincr:N \g_@@_symbol_int
+ \use_none:n #1 ~ \use_none:n #2 &
+ \tex_char:D #1 \exp_stop_f: \tex_char:D #2 \exp_stop_f: &
+ \tl_set:Nn \l_tmpa_clist {#3}
+ \clist_use:Nn \l_tmpa_clist { \par }
+ \strut \\
+ }
+\DeclareDocumentCommand \UTFTABLE { m m }
+ {
+ \int_gincr:N \g_@@_table_int
+ \exp_args:Nx \@@_make_table:nnn { UTFTABLE - \int_use:N \g_@@_table_int } {#1} {#2}
+ }
+\cs_new_protected_nopar:Npn \@@_make_table:nnn #1#2#3
+ {
+ \section{#2~(\zref@extractdefault{#1}{default}{0})}
+ \zref@refused{#1}
+ \noindent
+ \begin{longtabu} to \linewidth {>{\ttfamily\footnotesize}rc>{\ttfamily\footnotesize}X>{\tiny}X}
+ \toprule\rowfont{\normalfont\normalsize}
+ \multicolumn1c{USV} & Symbol & Macro(s) & Description \\
+ \midrule \endhead
+ \bottomrule \endfoot
+ \int_gzero:N \g_@@_symbol_int
+ \input{#3}
+ \end{longtabu}
+ \group_begin:
+ \zref@setcurrent{default}{\int_use:N\g_@@_symbol_int}
+ \zref@wrapper@immediate{\zref@labelbyprops{#1}{default}}
+ \group_end:
+ }
+\cs_generate_variant:Nn \@@_make_table:nnn { x }
+\ExplSyntaxOff
+
+\begin{document}
+
+\UTFTABLE{Symbols}{xunicode-commands.tex}
+
+\UTFTABLE{Combining Marks}{xunicode-combine-marks.tex}
+
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</xunicode-symbols>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+\endinput