# Patch font with LuaTeX

I don’t like the spacing of \textperiodcentered = U+00B7 in the OpenType cut of Latin Modern. Different from Computer Modern—and in fact, from just about any font I have on my system—LM gives the character fairly wide sidebearings. I think it’s a bug, anyway, and have so reported it to the Bogusław Jackowski et al. at GUST.

But while I wait for Jacko to fix this, can LuaTeX font patching (see, e.g., non-invasive kerning/spacing modification: what options are there?) be used to adjust the sidebearings of this character at run-time? How would such patching be implemented?

(By experimentation, I determined that a kern of −0.25em on either side of the dot gives it the same spacing as the period “.”, so that’s the amount I’d want to shave off the glyph’s bounding box.)

The code below illustrates the issue. In my actual code, I’m using the Unicode MIDDLE DOT (U+00B7) “·”, and its use is within a macro whose definition is copied (via \cs_set_eq:) to another, so neither redefining \textperiodcentered nor \newunicodechar can directly help. (This is a problem with my code, and one which I’ll be fixing; the question above is still interesting to me.)

\documentclass{article}
\newif\ifot\ottrue
\ifot
\usepackage{fontspec} % uses LM OpenType
\fi
\begin{document}
\ifot LMRoman OTF: \else Computer Modern: \fi
800\textperiodcentered 555\textperiodcentered 1212
\end{document}


The results from two separate runs (first with \ottrue, next with \otfalse) are these:

The Computer Modern version is typographically correct, or at least is similar to the result using any other font. Try to render the text “800·555·1212” (using U+00B7 “·”) in any application, comparing LMRoman to other fonts; rarely does it have such wide sidebearings. (The Lucida fonts, e.g., the one used on this website, are the others where I’ve seen this.)

• Please augment your code snippets so that they become a self-contained, compilable example. Incidentally, what happens if you provide an explicit \setmainfont instruction? – Mico Jul 3 '13 at 2:55
• @Mico, no difference; the extra ¼em on either side of the midpoint “·” is built-in to the OT version of Latin Modern. – J. C. Salomon Jul 3 '13 at 3:39
• BTW, Jacko has confirmed that this is a bug, the LM team having incorrectly assumed that U+00B7 was a math operator; but fixing this bug will change font metrics in a backwards-incompatible way—which may yet happen, but not anytime soon. – J. C. Salomon Jul 3 '13 at 18:40

Starting from this answer, the following feature file should do what you want:

languagesystem DFLT dflt;
languagesystem latn dflt;
feature kern {
pos periodcentered <-250 0 -500 0> ;
} kern;


(According to the spec, the values in the angle brackets mean x placement, y placement, x advance and y advance, in that order, given in design units aka. em.)

You would load the feature file (lets call it LMRoman.fea) with:

\setmainfont[FeatureFile=LMRoman.fea]{Latin Modern Roman}


You get the same spacing with the type1 lmodern if you use the real char with the help of textcomp:

\documentclass{article}
\usepackage{lmodern} % uses LM Type1
\usepackage[T1]{fontenc}
\usepackage{textcomp}

\begin{document}
800\textperiodcentered 555\textperiodcentered 1212
\end{document}


1. The LM Type1 font has U+00B7, and the character in the type1 font can displayed as the OpenType version. For example:

\documentclass{article}
\usepackage{lmodern}
\begin{document}
800\char189 555\char189 1212
\end{document}

2. The command \textperiodcentered act as \cdot in text mode. And these two command are mapping to the same character.

% filename: test.tex
\documentclass{article}
\usepackage{lmodern}
\pagestyle{empty}
\begin{document}
\textperiodcentered$\cdot$
\end{document}


Using pdffonts test.pdf getting the font's info in the PDF output:

name                                 type              emb sub uni object ID
------------------------------------ ----------------- --- --- --- ---------
SQTJQN+LMMathSymbols10-Regular       Type 1            yes yes no       4  0

3. So, this is not a bug of font, and is a bug of character mapping.

Let's do some experiments with texdef:

> texdef -t latex textperiodcentered

\textperiodcentered:
macro:->\OMS-cmd \textperiodcentered \OMS\textperiodcentered

> texdef -t latex -p textcomp textperiodcentered

\textperiodcentered:
macro:->\TS1-cmd \textperiodcentered \TS1\textperiodcentered


What does this mean? Let's go slowly. A command such as \<dENC>-cmd where <dENC> is the uppercase name of a known encoding, checks to see if the command <cENC><arg> is defined, where <cENC> is the current encoding and <arg> is the first token after \<dENC>-cmd (“d” for ”default”). If it is, then <cENC><arg> is used, otherwise <dENC><arg> is used.

Example (I'll skip over inessential details). LaTeX sees \textperiodcentered and expands it into

\OMS-cmd \textperiodcentered \OMS\textperiodcentered


If the current encoding is OT1 (as in your \otfalse setting), LaTeX tries to see whether \OT1\textperiodcentered (it's an impossible command to issue without some tricks, the inner backslash is part of the name) is defined, which it isn't. So the “default branch” is followed, which amounts to do

{\fontencoding{OMS}\selectfont \OMS\textperiodcentered}


and so printing \char"1 from the font associated to the OMS encoding, usually the math symbols font, where it has no sidebearings that in math are added automatically.

If the current encoding is EU1 (as in your \ottrue setting), the check for definedness of \EU1\textperiodcentered succeeds, so what's done is simply

\EU1\textperiodcentered


without any unnecessary grouping, which prints \char"00B7 in the current font. This glyph has sidebearings by choice of the font designers.

What textcomp does is to change the default encoding associated to \textperiodcentered to TS1, but the effect is similar; only difference is that a character from the text companion font will be used by default.

If you want to change the working of \textperiodcentered, it's sufficient to modify its definition for the EU1 (XeLaTeX) or EU2 (LuaLaTeX) encoding. The macro \encodingdefault will expand to the correct one.

\documentclass{article}
\usepackage{fontspec}
\AtBeginDocument{%
\DeclareTextCommand{\textperiodcentered}{\encodingdefault}{\kern-.25em\char"00B7\kern-.25em }%
}
\begin{document}

800\textperiodcentered 555\textperiodcentered 1212
\end{document}


In conclusion it's definitely not a bug, but expected behavior. OpenType fonts can have a “U+2E31 WORD SEPARATOR MIDDLE DOT” character, which has no side bearings (not Latin Modern OT, I'm afraid).

Other fonts have a less spaced centered period; a good guess seems to be a width of 0.25em, as the following example shows:

\documentclass{article}
\usepackage{fontspec}
\usepackage{xparse}
\NewDocumentCommand{\periodsep}{}{\makebox[.25em]{\symbol{"00B7}}}

\begin{document}

\newcommand{\test}{800\periodsep 555\periodsep 1212\par
800\symbol{"00B7}555\symbol{"00B7}1212\par\medskip}

\test

\fontspec{Linux Libertine O}\test

\fontspec{TeX Gyre Termes}\test

\fontspec{TeX Gyre Pagella}\test
\end{document}


If your application doesn't directly use the character, but generates it via a macro, this seems to be the best approach.

Alternatively, you could accept any width for the centered period unless it's over a fixed threshold, by changing the definition of \periodsep to

\NewDocumentCommand{\periodsep}{}
{%
\ifdim\fontcharwd\font"00B7>.3em % threshold value
\makebox[.25em]{\symbol{"00B7}}%
\else
\symbol{"00B7}%
\fi
}

• Thanks for the explanation. In the actual file, I was using U+00B7 “·” within a macro which a second name is \cs_set_eq: to (see the basic idea in my question Generate l3keys meta key from subkey) so I can’t directly use your suggestion, though. – J. C. Salomon Jul 3 '13 at 17:13
• @J.C.Salomon I don't see why you can't. – egreg Jul 3 '13 at 18:05
• It can work if I use \newunicodechar{·}{\textperiodcentered} before defining the macro that uses the middle-dot character. But that’s only needed for Latin Modern, and I haven’t checked the package font options at the time I’m setting the phone-number-formatting options. See gist.github.com/jcsalomon/5921380 – J. C. Salomon Jul 3 '13 at 18:32
• @J.C.Salomon I've added something about your real problem. – egreg Jul 3 '13 at 21:52