[Tex/LaTex] How to define phantoms for depth and height

macrostex-core

In the third "dangerous bend" on page 178 of of The TeXbook there's the following description of \vphantom:

Even more useful than \phantom is \vphantom, which makes an invisible
box whose height and depth are the same as those of the corresponding
\phantom, but the width is zero.

In Appendix B (page 360) one finds the definitions for \vphantom, \hphantom and \phantom:

\newif\ifv@ \newif\ifh@
\def\vphantom{\v@true\h@false\ph@nt}
\def\hphantom{\v@false\h@true\ph@nt}
\def\phantom{\v@true\h@true\ph@nt}
\def\ph@nt{\ifmmode\def\next{\mathpalette\mathph@nt}%
  \else\let\next=\makeph@nt\fi \next}
\def\makeph@nt#1{\setbox0=\hbox{#1}\finph@nt}
\def\mathph@nt#1#2{\setbox0=\hbox{$\m@th#1{#2}$}\finph@nt}
\def\finph@nt{\setbox2=\null \ifv@ \ht2=\ht0 \dp2=\dp0 \fi
  \ifh@ \wd2=\wd0 \fi \box2 }

And here are the definitions in the LaTeX kernel (ltmath.dtx, page 256 of source2e.pdf):

\newif\ifv@
\newif\ifh@
\def\vphantom{\v@true\h@false\ph@nt}
\def\hphantom{\v@false\h@true\ph@nt}
\def\phantom{\v@true\h@true\ph@nt}
\def\ph@nt{%
  \ifmmode
    \expandafter\mathpalette\expandafter\mathph@nt
  \else
    \expandafter\makeph@nt
  \fi}
\def\makeph@nt#1{%
  \setbox\z@\hbox{\color@begingroup#1\color@endgroup}\finph@nt}
\def\mathph@nt#1#2{%
  \setbox\z@\hbox{$\m@th#1{#2}$}\finph@nt}
\def\finph@nt{%
  \setbox\tw@\null
  \ifv@ \ht\tw@\ht\z@ \dp\tw@\dp\z@\fi
  \ifh@ \wd\tw@\wd\z@\fi \box\tw@}

Since \vphantom preserves total height (=height+depth), I wonder why there's no depth-only and height-only phantoms? More precisely, how can the above definitions be extended to define \dphantom (for depth only) and \htphantom (for height only)? The former would produce an invisible box whose depth is the same as that of the corresponding \phantom but whose width and height are zero, and the latter would produce an invisible box whose height is the same as that of the corresponding \phantom but its width and depth are zero.

Best Answer

For example, the switch \ifv@ can be split into two switches for the height and depth: \ifv@ht@ and \ifv@dp@.

The the macros are changed in this way (unchanged macros are commented):

plain TeX

% \newif\ifh@            
\newif\ifv@ht@ \newif\ifv@dp@
\def\vphantom {\v@ht@true \v@dp@true \h@false\ph@nt}
\def\hphantom {\v@ht@false\v@dp@false\h@true \ph@nt}
\def\htphantom{\v@ht@true \v@dp@false\h@false\ph@nt}  
\def\dpphantom{\v@ht@false\v@dp@true \h@false\ph@nt}  
\def\phantom  {\v@ht@true \v@dp@true \h@true \ph@nt}      
%\def\ph@nt{\ifmmode\def\next{\mathpalette\mathph@nt}%
%  \else\let\next=\makeph@nt\fi \next}
%\def\makeph@nt#1{\setbox0=\hbox{#1}\finph@nt}
%\def\mathph@nt#1#2{\setbox0=\hbox{$\m@th#1{#2}$}\finph@nt}
\def\finph@nt{%
  \setbox2=\null
  \ifv@ht@ \ht2=\ht0 \fi
  \ifv@dp@ \dp2=\dp0 \fi  
  \ifh@ \wd2=\wd0 \fi   
  \box2 %
}

% Macro \test, which visualizes the bounding box
\def\test#1#2{%
  \leavevmode
  \hbox{%  
    \vrule  
    \vbox{%  
      \hrule 
      \vtop{%
        \hbox{#1{#2}}%
        \hrule
      }%
    }%
    \vrule
  }%
}

g \test\phantom{g} \test\hphantom{g} \test\vphantom{g}
\test\htphantom{g} \test\dpphantom{g}
\bye

Test result

LaTeX

LaTeX has inherited these macros from plain TeX. It has only changed \makeph@nt to add color support. But this command does not need to be changed. The following example redefines these macros for LaTeX:

\documentclass{article}

\makeatletter
\newif\ifv@ht@ \newif\ifv@dp@
\renewcommand*{\vphantom} {\v@ht@true \v@dp@true \h@false\ph@nt}
\renewcommand*{\hphantom} {\v@ht@false\v@dp@false\h@true \ph@nt}
\newcommand*  {\htphantom}{\v@ht@true \v@dp@false\h@false\ph@nt}
\newcommand*  {\dpphantom}{\v@ht@false\v@dp@true \h@false\ph@nt}
\renewcommand*{\phantom}  {\v@ht@true \v@dp@true \h@true \ph@nt}
\renewcommand*{\finph@nt}{%
  \setbox2=\null
  \ifv@ht@ \ht2=\ht0 \fi
  \ifv@dp@ \dp2=\dp0 \fi
  \ifh@ \wd2=\wd0 \fi
  \box2 %
}
\makeatother

\begin{document}
  % Macro \test visualizes the bounding box
  \newcommand*{\test}[2]{%
    \begingroup
      \setlength{\fboxsep}{0pt}%
      \fbox{#1{#2}}%
    \endgroup
  }
  g \test\phantom{g} \test\hphantom{g} \test\vphantom{g}
  \test\htphantom{g} \test\dpphantom{g}
\end{document}

Result