![请解释一下 bytefield、unicode-math 和 mathtools 之间的奇怪交互](https://linux22.com/image/264506/%E8%AF%B7%E8%A7%A3%E9%87%8A%E4%B8%80%E4%B8%8B%20bytefield%E3%80%81unicode-math%20%E5%92%8C%20mathtools%20%E4%B9%8B%E9%97%B4%E7%9A%84%E5%A5%87%E6%80%AA%E4%BA%A4%E4%BA%92.png)
bytefield
mathtools
与和结合使用时会产生不同的结果unicode-math
一起使用时。这是我的“好” MWE:
% !TEX TS-program = XeLaTeX
\documentclass[a4paper]{article}
%\usepackage{mathtools} % This breaks things
%\usepackage{unicode-math} % when used with this
\usepackage{bytefield}
\begin{document}
\begin{bytefield}{16}
\bitheader{0,15}\\
\begin{rightwordgroup}{Header}
\bitbox{16}{Without}\\
\bitbox{16}{Etc}
\end{rightwordgroup}\\
\end{bytefield}
\end{document}
如果我按原样运行它,我会得到:
现在,如果我取消注释两个都标记的线,支架的对齐变得不稳定:
两者unicode-math
任一mathtools
独自的不会产生这种效果。
请问有什么想法吗?
amsmath
正如@Qrrbrbirlbel 所说,您可以通过交换来获得完全相同的行为mathtools
。
答案1
编辑2:完全重写,并对所有复杂之处进行基本完整的解释。
这是因为XeTeX 如何决定使用哪种 fontdimen 参数的复杂性,正如 Heiko 在回答该问题时指出的那样。在另一个回答中,Khaled Hosny 确认细节存在错误。
要使括号垂直居中,bytefield
请将表示数学轴位置的\fontdimen22
设置\textfont2
为 0pt。这对于旧式字体非常有效,但对于 OpenType 字体则不然,因为 OpenType 字体有许多其他参数可供使用(并且参数的顺序不同)。
如果unicode-math
没有加载,则使用的字体是旧式字体,并使用正确的 fontdimen 参数。
如果unicode-math
加载了,那么数学字体就是 OpenType 字体(默认情况下latinmodern-math.otf
),因此我们可能会遇到问题,但 XeTeX 能够重新映射 fontdimen 参数以使 TeX(和bytefield
)满意。这需要在检索值和存储值时进行映射。到目前为止,一切(?)都运行良好。
现在让我们把话题转到一边。当将数学列表转换为框时(如 TeXbook 附录 G 中所述),(Xe)TeX 会查看各种数学字体的 fontdimen 参数,最重要的是\textfont2
(以及\script(script)font2
,以及\...font3
类似物)。嗯,实际上,我不确定 XeTeX 会查看哪些参数。当然,它需要根据字体类型考虑不同的参数,而 Khaled Hosny 似乎在说,最后定义的字体会经过测试以确定它是 OpenType 还是旧式字体。这是一个错误。
只要我们不在数学模式中加载任何其他字体,最后定义的字体就有正确的类型,并且正确的 fontdimen 参数(设置为 0pt)用于放置数学轴。如中的示例我上面提到的问题如图所示,将一些文本存储在框中,即使不对框进行任何操作,也不执行任何 (TeX) 分配,也会对设置数学材料产生影响。考虑到错误的性质,我们可以预料到,“框中的文本”设置的字体会影响外部结果,因为它会改变最后一种字体是 OpenType 还是旧式字体。
现在,amsmath
在哪里出现?它定义了\resetMathstrut@
,重建一个高度和深度等于一条线的框(类似于\strut
,但用于数学模式),并在 处调用该函数\every@math@size
(不确定具体何时调用,但在数学模式中的某个地方)。定义不是很清楚,但让我解释一下。
\def\resetMathstrut@
{%
\setbox \z@ \hbox
{%
\mathchardef \@tempa \mathcode `\(\relax
\def \@tempb ##1"##2##3{\the \textfont "##3\char "}%
\expandafter \@tempb \meaning \@tempa \relax
}%
\ht \Mathstrutbox@ \ht \z@
\dp \Mathstrutbox@ \dp \z@
}
代码将包含括号的水平框存储到框中\z@
(0 的“简写”),然后将的高度和深度设置为新框 的高度\ht
和深度,使该框的垂直尺寸与括号相同。括号是如何排版的?嗯,由于 TeX 显示标记的方式(即和十六进制数字……代码会因数学活动括号而失败?),的数学代码被转换为十六进制。然后加载数字(十六进制),即 的数学字体(从十六进制数字中提取),并排版该字体中作为右括号的字符(再次使用数学代码的一部分)。在这个过程中,没有进入数学模式,但在框内选择了数学字体。\dp
\Mathstrutbox@
\z@
(
\meaning
\mathchar
\@tempa
\mathchar"
amsmath
\textfont
##3
(
现在我们准备好了。amsmath
加载时,unicode-math
会进行额外的重新定义,特别是\resetMathstrut@
,这会变成
\def\resetMathstrut@
{%
\setbox \z@ \hbox {$($}%
\ht \Mathstrutbox@ \ht \z@
\dp \Mathstrutbox@ \dp \z@
}
该定义要简单得多,并且与版本基本相同amsmath
:用数学字体排版括号,并使用其高度和深度来设置的尺寸\Mathstrutbox@
。天真地说,唯一可能发生的情况是\everymath
令牌寄存器(由 LaTeX 重命名为\frozen@everymath
)包含全局分配,这与周围的数学发生冲突(好吧,\everyhbox
也可以发挥作用,但实际上没有)。这将是 LaTeX 中的一个错误。但 LaTeX 已被广泛使用,并且代码现在对嵌套数学模式具有很强的鲁棒性(对此有有趣的评论)。因此我有点困惑,当我发现即使在内部数学模式之前清空也无法解决干扰时,source2e
我更加困惑。\frozen@everymath
当然,读完上述内容,精明的读者可以猜到发生了什么,比我快十几个小时:嵌套数学运算不应该对周围的数学列表产生任何影响,但由于 XeTeX 错误,它混淆了 fontdimen 参数。
由于我不完全了解 XeTeX 行为的细节,我不确定我之前提出的修复方法(恢复加载\resetMathstrut@
后的旧定义unicode-math
)是否在所有情况下都有效或恰好有效。我不知道是否可以修补bytefield
或任何其他宏以使您的文档正常工作。根据 XeTeX 所做测试的细节以及字体,可能无法在宏级别纠正行为。
与此同时,这里有一个可能有效的代码,可以\resetMathstrut@
先保存unicode-math
,然后再恢复。
\documentclass[a4paper]{article}
\usepackage{fixltx2e}
\usepackage{mathtools}
\makeatletter
\let\oldresetMathstrut@\resetMathstrut@
\makeatother
\usepackage{unicode-math}
\makeatletter
\let\resetMathstrut@\oldresetMathstrut@
\makeatother
\usepackage{bytefield}
\begin{document}
\begin{bytefield}{16}
\bitheader{0,15}\\
\begin{rightwordgroup}{Header}
\bitbox{16}{Without}\\
\bitbox{16}{Etc}
\end{rightwordgroup}\\
\end{bytefield}
\end{document}