fontspec
fontspec copied to clipboard
Very weird interaction between `Ligatures = TeX` and `WordSpace`.
Consider the following minimal example,
\documentclass{article}
\usepackage{fontspec}
\ExplSyntaxOn
\def\showfontdimen{
\dim_to_decimal:n{\fontdimen3\font}\quad
\dim_to_decimal:n{\fontdimen4\font}
}
\ExplSyntaxOff
\setmainfont{Latin Modern Roman}[WordSpace = {1, 0.5, 0.5}]
\begin{document}
\showfontdimen
\newfontfamily\lm{Latin Modern Roman}[WordSpace = {1, 0.5, 0.5}]
\lm\showfontdimen
\end{document}
The output is,

This is as expected.
The, change the newfontfamily line to,
\newfontfamily\lm{Latin Modern Roman}[WordSpace = {1, 0.5, 0.5}, Ligatures = TeX]
The new output is,

It is as if the newfontfamily halved the word space stretch and shrink again. I put an empty configure file at the directly of compilation, and thus the default features in the default configuration file is not the issue here.
I think I see what is going on here. For both XeTeX and LuaTeX, Ligatures=TeX is a "fake" approach to loading the font in a different way to achieve a certain effect.
For both engines, surprisingly, I believe this is triggering an optimisation that occurs when the same font is loaded more than once. Rather than loading the font from scratch, the engine re-uses its current definition for the font — and therefore picks up on the "adjusted" word space values (or more technically, \fontdimens).
It's possible to trick the engine to avoid this by loading the font a second time with something like Scale=1.0001 — imperceptibly smaller, but enough of a change for the engine to consider it a brand new font.
I'm not sure if there's much I can do about this, unfortunately. I don't even know how I would document it in the manual! I'll try to add a couple of sentences in the description for the WordSpace feature.
Actually if what I said above was true, you'd expect to get the same results from something like this
\newfontfamily\1{Latin Modern Roman}[WordSpace = {2, 0.25, 0.25}]
\newfontfamily\2{Latin Modern Roman}[WordSpace = {1, 0.5, 0.5},Ligatures=TeX]
And turns out these do give different results. So something more insidious is going on...
(A bit unrelated and not a bug report)
Actually the whole 'WordSpace' feature is a bit confusing to me. The second and third are scaling to \fontdimen3 and fontdimen4, while I think what's more useful would be able to set them as scaling wrt to \fontdimen2. I am not sure that how XeTeX do it. At least in LuateX, for monospaced font the original are already zero, for these two. That is WordSpace = {1, 2, 2} would be the same as WordSpace = {1, 0, 0}. I tried this with Latin mono and the sans mono, consolas. Though I cannot figure out how the font loader determine it is a monospaced font. On the other hand, for other faces, the fontloader mechanically calculate them as 1/3 and 1/2 of \fontdimen2 regardless of the font design. (To be fair, opentype itself only have equivalent to dimen2 and nothing else for fontloader to make a more informative calculation.) These amounts, especially the shrinkability are adequate for modern, which has 1/3 me normal space. But too much for most text fonts, usually ranging from 1/5 to 1/4 em.
So if I want to say "plus 25% and minus 15% of normal space". I would need to write wordspace = {1, 0.5, 0.45}, which is very much unintuitive IMHO. The current syntax, which scale the original value, I think would make a lot more sense if the each font does have its own value of dimen3 and dimen4, like dimen2. But the fact is that it does not.
however, on the other hand, the current form has the advantage of most straightforward to understand and requires least jusgement from user.
Thanks for the comments! I agree with you, definitely. It’s been a LONG TIME since this code was written — I like your suggest of having relative weights of \fontdimen2. I’ll try to come up with a new option to do that as well as the current behaviour (since it’s existed too long to change it, I think).
That will be a very useful feature.
My own macro, which in the end push to a token list containing fontspec options, work as the following,
- For \fontdimen2, if the given value is less than 10, use it as the actual scaling factor. Otherwise, treat it as the absolute value as in units of a thousandth em. And calculate the required scaling factor.
- For dimension 3 and 4, again If less than 10, taken it as a scaling factor of the new dimension 2, and calculate the required scaling factor. Otherwise take it as an absolute value as above.
I found it quite useful, it allows me to say, 1, 0.15, 0.15 % keep the original native space, stretch and shrink 15% or 250, 80, 50, % use a quarter em as the native space, and stretch to at most about a third em, and shrink to a fifth em (the conventional optimal spacing) Or a combination of the two.
But I guess it would be too confusing for most users. My choice of 10 as a cut off value is that hardly one want to scale it ten times, and even rare one want 0.01em word spacing.