How to make existing \strut-based code work with accented letters?

\strut-based solutions assume that heights cannot exceed 8.5 pt and depth - 3.5 pt. But with accented letters this assumption is not true. In the second example the last line is lower than in the first example. How to make the baselines the same in both examples without changing the main macro?

Example 1:

\input template
\font\tenrm=rm-lmr10 \tenrm
\marginalstar
X
\char'101
\bye


Example 2:

\input template
\font\tenrm=rm-lmr10 \tenrm
\marginalstar
X
\char'200
\bye


template.tex:

\def\marginalstar{\strut\vadjust{\kern-\dp\strutbox\smash{\llap{* }}\kern\dp\strutbox}}
\nopagenumbers
\hsize1em
\emergencystretch=1em
\noindent


If there does not exist a workaround so that existing code would work with accented letters, what guidelines should be followed in writing new code? Are \strut-based solutions bad and how to avoid them? How to make so that in all cases where \strut would be used, it was possible to do without it? (for example - to draw rules in tables; page 82 of TeXbook gives another example)

EDIT Two more examples to illustrate the point. In the second example the right border is torn.

Example 3:

\font\tenrm=rm-lmr10 \tenrm
\hsize=5em
\hrule
\settabs 2 \columns
\+ \strut\vrule\hfill W\hfill\vrule& \hfill X \hfill\strut\vrule&\cr
\hrule
\+ \strut\vrule\hfill \char'101\hfill\vrule& \hfill Z \hfill\strut\vrule&\cr
\hrule
\bye


Example 4:

\font\tenrm=rm-lmr10 \tenrm
\hsize=5em
\hrule
\settabs 2 \columns
\+ \strut\vrule\hfill W\hfill\vrule& \hfill X \hfill\strut\vrule&\cr
\hrule
\+ \strut\vrule\hfill \char'200\hfill\vrule& \hfill Z \hfill\strut\vrule&\cr
\hrule
\bye


So according to @David Carlisle it should be:

\setbox\strutbox=\hbox{\vrule height9.5pt depth2.5pt width0pt}


Because:

$tftopl rm-lmr10|grep CHARHT|sort|tail -n1 (CHARHT R 0.9205)$ tftopl rm-lmr10|grep CHARDP|sort|tail -n1
(CHARDP R 0.25)


Right?

• yes if in fact your height/depth do fit in 12pt then 9.5/2.5 sounds good but note you may have other things in the line such as $x_2$ so in some cases you may need a depth of more than 2.5 but so be it – David Carlisle Oct 20 '15 at 7:06

\strut is not a built in command it is simply

  \setbox\strutbox=\hbox{\vrule height8.5pt depth3.5pt width\z@}
\def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}


which is designed to fit 10pt computer modern English text set on a 12pt baseline.

If you have any other type of text you need to adjust \strutbox to have suitable height and depth,

In this case you get \lineskip of 1pt between the lines as the accented A is 9.20499pt high an the \strut is 3.5pt deep so they can not fit on a 12pt baselineskip.

You probably need to change the baselineskip to say 12.5pt and adjust the strut to be 9.3 high and 3.2 deep or some such, or you could try to squeeze it in to 12pt with a strut 9.2 high and 2.8 deep

to address the questions in comments in latex you could do

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\begin{document}

\showoutput
\expandafter\show\the\font
\sbox0{Ă \v{A}\c{c}g(Q)$\sum_0^n(x)_7^n$}
\typeout{\the\ht0+\the\dp0=\the\dimexpr\ht0+\dp0\relax}
\usebox{0}

\end{document}


which shows that latex/plain tex isn't really the issue it is the font choice. Using ec fonts as above, it looks like you can just get away with a strut of 9pt high and 3pt deep which isn't quite what you get from latex which resets it after every size change to

    \setbox\strutbox\hbox{%
\vrule\@height.7\baselineskip
\@depth.3\baselineskip
\@width\z@}%


so for a 12pt baseline that's 8.4pt+3.6pt but you could redefine \set@fontsize to use .75 and .25 as the multipliers if you have a lot of accented capitals and no large descenders in the font.

• I added some more examples to the question. Does LaTeX use \strut or there are other approaches? – Igor Liferenko Oct 20 '15 at 6:53
• @IgorLiferenko yes latex uses \strut and every font size command resets the strutbox accordingly, but \strut is not really the issue. If you need to set text that has 3.5pt descenders and 9.5pt high accented capitals then it does not fit in a 12pt baseline and changing \strut does not change that. – David Carlisle Oct 20 '15 at 7:03
• Does LaTeX support accented letters by default? Where in the LaTeX source is the definition of default \strut? – Igor Liferenko Oct 21 '15 at 8:33
• @IgorLiferenko it depends what you mean by support and default, commands such as \^ are defined in the format and the base latex distribution includes inputenc package that allows accented letters in a range of input encodings such as latin1 and utf8. \strut is defined on latex.ltx line 588 (Identical to plain definition) – David Carlisle Oct 21 '15 at 9:22
• By "default" I mean that when I type for example Ă, in the pdf output I get proper utf-8 symbol Ă (not composed of accents), copyable and searchable. Also, after compiling \offinterlineskip \strut Ă \hrule \strut Ă \bye, the distance between baselines must be 12pt. Will this work in LaTeX by default (i.e., without additional configuration)? And if not, what configuration must be done to work as described? – Igor Liferenko Oct 22 '15 at 0:39

Update adds a patch of LaTeX's \selectfont to modify its way of defining \strutbox as per OP's request in a comment. To be further adapted to one's needs. When \set@fontsize is called, the new font isn't yet loaded, thus, I ended up adding some extra code at the very end of \selectfont rather than patching \set@fontsize.

TeX has a mechanism for setting lines \baselineskip apart which most of the time works fine. As explained in @DavidCarlisle's answer, the \strutbox is defined with an ad hoc .7:.3:1 rule for height:depth:baselineskip. Unfortunately this means that adding a \strut to a situation where things were otherwise well aligned will sometimes cause misalignments. Here below is an example where the depth coming from the strut plus the height coming from an accented character on the next line will have a total exceeding the baselineskip, because the .7\baselineskip falls short of the height of the accented character.

\documentclass[12pt]{article}
\usepackage [utf8]{inputenc}
\usepackage [T1]{fontenc}
\usepackage {multicol}

\begin{document}\pagestyle{empty}\thispagestyle{empty}

Without struts:
\begin{multicols}{2}
Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat de droit\par
\columnbreak
\'Etat de droit \'Etat de droit \'Etat de droit \'Etat de droit \'Etat
de droit \'Etat de droit \'Etat de droit\par
\end{multicols}

With two added struts (the one on the left does no harm), the
alignment is off!:

\begin{multicols}{2}
\strut Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat de droit\par
\columnbreak
\strut État de droit État de droit État de droit État de droit État
de droit État de droit État de droit\par
\end{multicols}
\end{document}


produces

This was discussed in a thread on a French newsgroup, the situation is worse with lmodern:

\documentclass[12pt]{article}
\usepackage [utf8]{inputenc}
\usepackage [T1]{fontenc}
\usepackage {multicol}
\usepackage{lmodern}

\begin{document}\pagestyle{empty}\thispagestyle{empty}

Without struts:
\begin{multicols}{2}
Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat de droit\par
\columnbreak
\'Etat de droit \'Etat de droit \'Etat de droit \'Etat de droit \'Etat
de droit \'Etat de droit \'Etat de droit\par
\end{multicols}

With two added struts (the one on the left does no harm), the
alignment is off!:

\begin{multicols}{2}
\strut Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat de droit\par
\columnbreak
\strut État de droit État de droit État de droit État de droit État
de droit État de droit État de droit\par
\end{multicols}

With more struts at the right, alignment even more off:
\begin{multicols}{2}
\strut Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat de droit\par
\columnbreak
\strut État de droit État de droit État de droit \strut État de droit État
de droit État de droit État de droit\par
\end{multicols}

\end{document}


Code for patching \selectfont.

\documentclass[12pt]{article}
\usepackage [utf8]{inputenc}
\usepackage [T1]{fontenc}
\usepackage {multicol}
\usepackage{lmodern}

% patch \selectfont
\makeatletter
\newbox\igor@tempbox
% or \@tempboxa but perhaps some code calls \selectfont
% not expecting \@tempboxa to be modified

\def\igor@fixstrutbox{\setbox\igor@tempbox\hbox{ÉÈÙÀĂÅ}%
% first we reset the \strutbox to not inherit a situation which
% could go through unmodified but would depend upon the sequence
% of earlier font changes, if you didn't make the change now.
%
\setbox\strutbox\hbox{\vrule
\@height.7\baselineskip
\@depth.3\baselineskip
\@width\z@}%
\ifdim\ht\igor@tempbox>\ht\strutbox
% comment out these two lines in real use cases
\typeout{IGOR: MODIFYING DEFAULT STRUTBOX\on@line.}%
\typeout{IGOR: old=\the\ht\strutbox, new=\the\ht\igor@tempbox}%
\setbox\strutbox\hbox{\vrule
\@height\ht\igor@tempbox % add some extra?
\@depth\dimexpr\baselineskip-\ht\igor@tempbox\relax
\@width\z@}\fi }%

\expandafter\def
\csname selectfont \expandafter\expandafter\expandafter
\endcsname
\expandafter\expandafter\expandafter
{\csname selectfont \endcsname\igor@fixstrutbox}%
\makeatother

\begin{document}\pagestyle{empty}\thispagestyle{empty}

Without struts (no problems):
\begin{multicols}{2}
Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat de droit\par
\columnbreak
État de droit État de droit État de droit État de droit État
de droit État de droit État de droit\par
\end{multicols}

With struts: (careful to put a strut also on left first line.)

\begin{multicols}{2}
\strut Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat de droit\par
\columnbreak
\strut État de droit État de droit État de droit État de droit État
de droit État de droit État de droit\par
\end{multicols}

\Large

Changed size.
\begin{multicols}{2}
\strut Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat\par\hrule
\columnbreak
\strut État de droit État de droit État de droit \strut État de droit État
de droit État de droit État de droit\par\hrule
\end{multicols}

\sffamily

Other font.
\begin{multicols}{2}
\strut Etat de droit Etat de droit Etat de droit Etat de droit Etat de droit
Etat de droit Etat de droit Etat de droit\par\hrule
\columnbreak
\strut État de droit État de droit État de droit \strut État de droit État
de droit État de droit État de droit\par\hrule
\end{multicols}

\end{document}


Log (with \igor@fixstrutbox containing only É, and that was with an earlier version of the code):

(/usr/local/texlive/2015/texmf-dist/tex/latex/lm/t1lmr.fd
File: t1lmr.fd 2009/10/30 v1.6 Font defs for Latin Modern
)
IGOR: MODIFYING DEFAULT STRUTBOX on input line 30.
IGOR: old=10.14995pt, new=11.004pt
IGOR: MODIFYING DEFAULT STRUTBOX on input line 51.
IGOR: old=15.39993pt, new=15.68199pt
LaTeX Font Info:    Try loading font information for T1+lmss on input line 62.
(/usr/local/texlive/2015/texmf-dist/tex/latex/lm/t1lmss.fd
File: t1lmss.fd 2009/10/30 v1.6 Font defs for Latin Modern
)
IGOR: MODIFYING DEFAULT STRUTBOX on input line 73.
IGOR: old=10.14995pt, new=11.004pt


Switch to sans serif caused no adjustment, but if \igor@fixstrutbox is set-up with \hbox{ĂÉÈÅ} rather, one gets (again with earlier code, not re-compiled).

IGOR: MODIFYING DEFAULT STRUTBOX on input line 30.
IGOR: old=10.14995pt, new=11.004pt
IGOR: MODIFYING DEFAULT STRUTBOX on input line 51.
IGOR: old=15.39993pt, new=15.68199pt
LaTeX Font Info:    Try loading font information for T1+lmss on input line 62.
(/usr/local/texlive/2015/texmf-dist/tex/latex/lm/t1lmss.fd
File: t1lmss.fd 2009/10/30 v1.6 Font defs for Latin Modern
)
IGOR: MODIFYING DEFAULT STRUTBOX on input line 62.
IGOR: old=15.68199pt, new=15.97498pt
IGOR: MODIFYING DEFAULT STRUTBOX on input line 73.
IGOR: old=10.14995pt, new=11.004pt


The same with only \hbox{Ă} showing that this character is taller in sans serif than É at least in \Large font size.

I have edited the \igor@fixstrutbox to always reset first the \strutbox to the default LaTeX definition, because if not the decision to keep the \strutbox or modify it would depend on the history of earlier font changes, as LaTeX calls only in certain circumstances \set@fontsize which gives non \relax meaning to \size@update (executed by \selectfont). I have not updated the image and logs above after that change.

• you could try nntp.aioe.org which even works on port 80 (useful when only html connections are allowed). For posting to it I am not sure, my Thunderbird is configure to use the smtp server of my Internet provider. Yes, I noticed that the link I gave has broken encoding. Will try to find an alternative one. – user4686 Oct 23 '15 at 9:19
• here is a better link for the thread on fr.comp.text.tex dating back to January 2013. I wanted initially to post such a link, but for some reason the search on narkive.com did not work on my browser. After having found it on the dubious other site, I knew the date and the title of the thread, thus could load more and more posts until going back to the right time. – user4686 Oct 23 '15 at 9:36
• My examples are fixed via either 1) not use \strut's in such places or 2) modify the definition of \strutbox inside \set@fontsize (if using LaTeX). – user4686 Oct 23 '15 at 9:41
• my proposed patch assumes \baselineskip itself to be at least as big as the height of the characters used in the \igor@tempbox. If not the depth of the \strut will be zero and its height will be the height of the material inside \igor@tempbox. My code caters only for ascenders: if the \strut is used in a line with a character having a big descender, and if the \strut now has a height too big to fit together with the big descender we will be in the \lineskip situation again. – user4686 Oct 25 '15 at 12:42
• I agree with the news thread - \strut is a hack. It should be possible to do without strut in all situations where we need strut. I think I understand where the problem lies: the computation for the interline glue between the two boxes is done purely by looking at their heights and depths, and if a rule is added at top or bottom - the depth of the box will be zero and everything else will be added to the height. For example, \halign is equivalent to \vbox{\hbox...\hbox...}. In ruled table examples in TeXbook \strut is used, and \offinterlineskip is issued to kill all interline glue insertion. – Igor Liferenko Oct 26 '15 at 8:15

I am providing another answer, which exploits a feature of XeTeX, its parameter \XeTeXuseglyphmetrics. The idea is the following:

\XeTeXuseglyphmetrics 0


and all character boxes will have identical heights and depths. Set the height of the strutbox to this common height, and its depth to the value needed so that the sum of the two add up to \baselineskip.

Then you can reset

\XeTeXuseglypmetrices 1


for the default boxes.

This is illustrated by the xetex code below. It containes a \fbox macro which frames its material adding no extra height or depth or width. The \TEST macro is supposed to display some such boxes, containing characters and struts, or only a strut, or also normal characters and a \vrule. We see most of the time lineskip glue added because always height + depth exceeds baselineskip if we find an accented letter and a strut (the strut has too big a depth).

Then at bottom we set up a better strut, and see that there no more extra vertical interline spaces. This final step done with "Times New Roman" which is a system font on my Mac.

forgot the code:

\newdimen\fboxrule
\fboxrule 0.4pt

\def\mycolor {rgb 0 0 1}
\def\fbox #1{\leavevmode
{\special{color push \mycolor}%
\hbox{\vtop{\vbox{%
\hrule height \fboxrule
\kern -\fboxrule
\hbox{\vrule width \fboxrule\kern-\fboxrule
\special{color pop}%
#1%
\special{color push \mycolor}%
\kern-\fboxrule\vrule width \fboxrule}%
}\kern-\fboxrule
\hrule height\fboxrule}}%
\special{color pop}%
}%
}

\def\TEST {\noindent
\fbox{\strut\kern1cm
{\def\mycolor{rgb 1 0 0 }\fbox {A}\fbox{E}\fbox{C}\fbox{gg}%
\kern1cm\strut}}
ABCD
\fbox{\strut\kern.5cm\strut}
\vrule height\ht\strutbox
depth \dp\strutbox

\noindent
\fbox{\strut\kern1cm
{\def\mycolor{rgb 1 0 0 }\fbox {A}\fbox{É}\fbox{Ç}\fbox{gg}%
\kern1cm\strut}}
ABCD
\fbox{\strut\kern.5cm\strut}
\vrule height\ht\strutbox
depth \dp\strutbox
\par
}

\font\lmfont=rm-lmr10

\lmfont

Latin Modern

\the\ht\strutbox, \the\dp\strutbox, \the\baselineskip

\XeTeXuseglyphmetrics=1

\TEST

\XeTeXuseglyphmetrics=0

\TEST

\font\times="Times New Roman"

\times

Times New Roman

\XeTeXuseglyphmetrics=1

\TEST

\XeTeXuseglyphmetrics=0

\TEST

\setbox0\hbox{A}\the\ht0, \the\dp0, common height plus depth of strut=
\the\dimexpr\ht0+\dp\strutbox\relax, bigger than
\the\baselineskip

With better strut:

\setbox\strutbox\hbox{\vrule height\ht0
depth\dimexpr\baselineskip-\ht0\relax}

\XeTeXuseglyphmetrics=0

\TEST

\XeTeXuseglyphmetrics=1

\TEST

\nopagenumbers
\bye

• Why with Latin Modern \XeTeXuseglyphmetrics=0 does not work? – Igor Liferenko Oct 28 '15 at 3:29
• I don't know. I observed it yesterday, even briefly thought about asking the question on xetex dev list, but figured I should first read more of the manual. Then I forgot. Possibly the feature works only for OpenType fonts. – user4686 Oct 28 '15 at 11:44
• I have an idea how to get rid of the \strut problem - it is necessary to lower the accents a little bit. The same problem was solved in CS-fonts. See my question here (the first one, before the edit): tex.stackexchange.com/questions/275218/…. Do you know how to do that? – Igor Liferenko Nov 8 '15 at 20:50
• @IgorLiferenko no I don't. If lowered accents are aesthetically pleasing, then perhaps indeed it is worthwhile to go through the whole thing; but the \strut problem in itself can be cured more easily as in my answers. The problem with the \strut is that it seems to be designed with too big a depth. One may also argue that glyphs should not have a depth; the collisions are argued to be rare, and the TeX solution to separate more the lines is bad as it acts globally on a local problem. Ideally one (luatex?) perhaps should move horizontally the glyphs when a collision is detected. – user4686 Nov 8 '15 at 21:15