# Please explain a strange interaction between bytefield, unicode-math, and mathtools

bytefield gives me different results when used in association with mathtools and unicode-math when used together. Here's my 'good' 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}
\bitbox{16}{Without}\\
\bitbox{16}{Etc}
\end{rightwordgroup}\\
\end{bytefield}
\end{document}


If I run this as-is, I get:

Now, if I uncomment both the lines marked, the alignment of the brace goes wonky:

Either unicode-math or mathtools alone doesn't produce this effect.

As noted by @Qrrbrbirlbel, you can get exactly the same behaviour by swapping amsmath for mathtools.

-
How did you find this? –  enthdegree Mar 12 '13 at 23:21
@enthdegree : I cloned a new from an old document (and preamble). The new document needed a bytefield diagram, which formatted badly (as above). I then built an MWE using the same preamble, and, commenting and uncommenting lumps of the preamble, found the two lines that made it happen and unhappen. –  Brent.Longborough Mar 13 '13 at 8:42
@Brent.Longborough Another mistery. If you compile the provided MWE (with the two conflicting packages commented out) with pdflatex and xelaatex, you get the same result. But if you use lualatex you get a bigger and badly positioned brace. This suggest a font problem, but a diff of the .log files shows no significative differences... –  JLDiaz Mar 14 '13 at 0:07
@JLDiaz : Thank you! I'll open that as a separate question. (Later, I'm a bit bogged down now with the catastrophic announcement from Google) –  Brent.Longborough Mar 14 '13 at 11:58
There is code loaded by unicode-math that is only run if amsmath is loaded, and furthercode that is only run if mathtools is loaded. See the files unicode-math-xetex.sty and unicode-math-luatex.sty. –  Andrew Swann Mar 20 '13 at 12:11

Edit2: Complete rewrite, with mostly complete explanation of all the intricacies.

This is due to a complication in how XeTeX decides what fontdimen parameter to use, as Heiko notes in his answer to that question. In another answer, Khaled Hosny confirms that the details are buggy.

To center the brace vertically, bytefield sets the \fontdimen22 of \textfont2, which indicates the position of the math axis, to 0pt. This works perfectly fine for old-style fonts, but not for OpenType ones, which have plenty other parameters to work with (and parameters are ordered differently).

If unicode-math is not loaded, then the font used is old-style, and the correct fontdimen parameter is used.

If unicode-math is loaded, then the math font is an OpenType font (by default latinmodern-math.otf), so we could expect problems, but XeTeX has the ability to remap fontdimen parameters to make TeX (and bytefield) happy. This requires a mapping both when retrieving the values and when storing them. Everything(?) works fine so far.

Let us make an aside now. When turning a math list into boxes (as described in Appendix G of the TeXbook), (Xe)TeX looks at fontdimen parameters of various math fonts, most importantly \textfont2 (and \script(script)font2, and the \...font3 analogs). Well, really, I am not sure what parameters XeTeX looks at. Of course, it needs to consider different parameters depending on the type of font, and Khaled Hosny seems to be saying that the last defined font is tested for whether it is OpenType or old-style. This is a bug.

As long as we don't load any additional font within math mode, the last defined font has the right type, and the correct fontdimen parameter, which was set to 0pt, is used to place the math axis. As the example in my question quoted above shows, storing some text in a box, even without doing anything with the box, and without performing any (TeX) assignment, has an effect on setting the math material. As we can expect given the nature of the bug, the font in which the "text in a box" is set affects the outer result, since it changes whether the last font was OpenType or old-style.

Now, where does amsmath come in? It defines \resetMathstrut@, which rebuilds a box of height and depth equal to that of a line (like \strut, but for math mode), and places a call to that function at \every@math@size (not sure when that is called exactly, but somewhere within math mode). The definition is not terribly clear, but let me explain it.

\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@
}


The code stores a horizontal box containing a parenthesis into the box \z@ ("short-hand" for 0), then sets the height \ht and depth \dp of the \Mathstrutbox@ equal to those of the new box \z@, making that box's vertical dimensions be that of a parenthesis. How is the parenthesis typeset? Well, the math code of ( is converted to hexadecimal thanks to how TeX displays the \meaning of the \mathchar token \@tempa (namely as \mathchar" and hexadecimal digits... would the amsmath code fail with a math active parenthesis?). Then load the \textfont number ##3 (in hexadecimal), which is the math font for ( (as extracted from the hexadecimal digits), and typeset whichever character of that font is a right parenthesis (again using part of the math code). Nowhere in this process has math mode been entered, but the math font was selected, within the box.

We are ready now. When amsmath is loaded, unicode-math makes extra redefinitions, in particular of \resetMathstrut@, which becomes

\def\resetMathstrut@
{%
\setbox \z@ \hbox {$($}%
\ht \Mathstrutbox@ \ht \z@
\dp \Mathstrutbox@ \dp \z@
}


That definition is much simpler, and does essentially the same as the amsmath version: typeset a parenthesis with the math font, and use its height and depth to set the dimensions of the \Mathstrutbox@. Naively, the only thing that could happen is that the \everymath token register (renamed to \frozen@everymath by LaTeX) contained global assignments, which clashed with the surrounding maths (well, \everyhbox could also play a role, but does not). This would be a bug in LaTeX. But LaTeX has been used extensively, and the code is now robust against nesting math modes (source2e has interesting comments on that). I was thus a bit puzzled, and even more so when finding out that even emptying \frozen@everymath before the inner math mode did not fix the interference.

Of course, having read the above, the astute reader can guess what happens, a dozen hours faster than me: the nested math, which should not have any influence on the surrounding math list, mixes up the fontdimen parameters because of the XeTeX bug.

Since I don't fully understand the details of the XeTeX behaviour, I am not sure whether the fix that I proposed earlier (reverting the old definition of \resetMathstrut@ after unicode-math is loaded) would work in all cases or just happens to work. I don't know either whether it is possible to patch bytefield, or any other macro, to make your document work properly. Depending on the details of what test XeTeX does, and on what font, it may be impossible to correct the behaviour at the macro level.

In the meantime, here is a code that might work, saving \resetMathstrut@ before unicode-math and restoring it afterwards.

\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}
`