diff options
Diffstat (limited to 'macros/xetex/latex/xecjk/xeCJK.dtx')
-rw-r--r-- | macros/xetex/latex/xecjk/xeCJK.dtx | 14063 |
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 |