Whose responsibility is it to load fonts in LaTeX (or XeLaTeX)? (and how do I know which ones, if mine?)

I ran into a headache-inducing problem with LaTeX (actually I used XeLaTeX to compile, but I think this issue is independent) recently due to unwittingly attempting to modify the dimensions of a math font before it was loaded.

What should be my expectations?

1. LaTeX should have loaded it.
2. TikZ (pgf) should have loaded it.
3. \fontdimen should have loaded it.
4. \textfont2 should have loaded it.
5. The user should have loaded it. (I have never before been required to do something like this in the past. To my knowledge, it is not documented anywhere that I must do this.)

Based on the answer to this specific question, I would like to determine standardized programming practices. What is actually the standard for LaTeX and package writers (should a package always include a font check)? Should a bug be reported for any of the steps 1 through 4?

Failure Message in Log:

!Font \nullfont has only 7 fontdimen parameters.


I am aware of what this message means. pgf (TikZ) switched to math mode before executing the baseline key, which included modifications to a font (the math font), that has not yet been loaded. I am aware that since the implementation of LaTeX2e, fonts are not longer loaded until they are needed. fontspec loads fonts immediately (correct me if I am wrong).

Strong words (that gave me and my colleague a laugh. This guy surely knows what he is talking about!) from Ijon Tichy about the changes in LaTeX2e since LaTeX 2.09:

Man muss dazu wissen, dass die tfm-Dateien eines Fonts bei LaTeX seit NFSS2, also letztlich seit LaTeX2e, erst geladen werden, wenn die Fonts das erste Mal verwendet werden. Vorher, also bei LaTeX 2.09, war das AFAIK noch anders. Dort wurden Fonts direkt über \font-Anweisungen im Format bzw. in der Dokumentpräambel geladen. Daher kann es solche Probleme mit alten LaTeX-2.09-Stilen geben, die mit dem heutigen LaTeX verwendet werden.

Translation: One must be aware of the fact that tfm font files in LaTeX are only loaded when they are first needed ever since NFSS2, or most recently since LaTeX2e. The AFAIK was implemented differently in LaTeX 2.09 (than in LaTeX2e). In LaTeX 2.09, fonts were loaded directly through the \font instructions within the format as well as the document preamble. Therefore, packages that use a LaTeX 2.09 coding style could potentially cause problems in LaTeX2e.

Example Code

\documentclass{article}
\usepackage{tikz} % Absolute positioning, advanced vector graphics
\newcommand{\ampel}[1]{% input: color
\begin{tikzpicture}[baseline=-\the\dimexpr\fontdimen22\textfont2\relax] %<- Magical vertical alignment code that gives LaTeX a hiccup.
\node[yshift=.4mm,align=center,fill=#1, shape=circle] (O)at (0,0) {};
\end{tikzpicture}
}%
\begin{document}
\ampel{green!70!black}
\end{document}


Workaround

One can explicitly load the math font.

1. Add $\null$ after \begin{document}
2. Add the following to the preamble:

\makeatletter
\AtBeginDocument{\sbox\@tempboxa{$\null$}}
\makeatother

3. Explicitly check for math fonts (see egreg's answer)

\makeatletter
\AtBeginEnvironment{tikzpicture}{\check@mathfonts}
\makeatother


I would like to add a note about my discoveries while narrowing down the problem. I had two versions of the same document, one written in German and the other in English. The English version was typesetting fine. The German version would not typeset. I discovered that there was a footnote including a \url{} in the English version that was commented out in the German version. This \url occurred before the first \ampel call. This means that \url{} loads the math fonts.

Before you use \textfont2, you must ensure it has been defined, which it is only after LaTeX has typeset at least one formula, even an empty one, in the current font size. This is because it wants to support math at any font size and also to avoid wasting math groups.

The command that's actually in charge of defining the math fonts given the current conditions is \check@mathfonts:

\documentclass{article}
\usepackage{tikz}
\usepackage{etoolbox}

\makeatletter
\AtBeginEnvironment{tikzpicture}{\check@mathfonts}
\makeatother

\newcommand{\ampel}[1]{% input: color
\begin{tikzpicture}[baseline=-\the\dimexpr\fontdimen22\textfont2\relax]
\node[yshift=.4mm,align=center,fill=#1, shape=circle] (O)at (0,0) {};
\end{tikzpicture}%
}

\begin{document}

X\ampel{green!70!black}X

\Huge

X\ampel{green!70!black}X

\end{document}


Using execute at begin picture is not good, because the optional argument is evaluated before the picture starts and that hook examined. And no, just doing \sbox0{} at begin document (adding \null is irrelevant) is not sufficient, if you plan to change font size in your document: for instance your \ampel might go in a section title (with \protect in front of it, but this is another matter): try with that method and the result in the second case, after \Huge, would come out wrong.

• Am I to understand that your answer is #5 in my list of who is to blame? I appreciate your answer and comments, but I am not sure that it addresses the question precisely. I know how to solve the issue (as shown in the workaround). I am targeting a fundamental issue (responsibility), however. – Jonathan Komar Sep 18 '15 at 9:39
• @macmadness86 You are using a TeX primitive which is not part of the LaTeX interface: you are expected under those circumstances to know what you are doing! – Joseph Wright Sep 18 '15 at 9:46
• @JosephWright Now that is an answer I can deal with. So, the answer is indeed #5! Thank you Joseph! (May I suggest that you upgrade your answer, egreg, to include this critical piece of information, because you already invested time in your answer? Otherwise, Joseph, you could add an answer.) – Jonathan Komar Sep 18 '15 at 9:49
• @macmadness86 Why do you think it doesn't address the question? I told you precisely that you need to issue \check@mathfonts before using \textfont2 in any way; and I told you that LaTeX does this when trying to typeset a formula. Whose is the “responsibility”? It's yours, because you're using a low level command. – egreg Sep 18 '15 at 9:54
• @macmadness86 Maybe you can file a feature request for a key such as baseline at math axis that takes care of the whole business. – egreg Sep 18 '15 at 9:56

\textfont2 is a primitive, therefore a check must be implemented by the user to see whether a font has been loaded or not.