4

I am writing a document for which I would like to use a main font, let's call it myfont, which I have as several .otf files. To do so, I use XeTeX along with the fontspec package and the setmainfont command :

\usepackage{fontspec}
\setmainfont[Mapping=tex-text,
  BoldFont={myfont-bold.otf}, 
  ItalicFont={myfont-italic.otf},
  BoldItalicFont={myfont-bolditalic.otf}
]{myfont.otf}

The problem I have with myfont is that I don't like the digits. Therefore, I'd like to use another font, but only for digits. It could be possible if the setmainfont command had a numbers option, which it doesn't. I would also like to precise that the font does not have support for lined digits, and only comes with Old Style.

The way I see it, there would be two ways to do so :

1/ Make all digits use the math font

If I could make every digit call the math font, there would be no problem, as the math font digits look alright. The main problem being that I have no idea if and how this could be done.

2/ Substitute characters manually

This is what is suggested by two resources I have found : here and here - the latter referencing the former. Their solution was to use the fontspec package and to manually swap characters using :

\usepackage{fontspec}
\XeTeXinterchartokenstate=1
\chardef\CharNormal=0
\makeatletter
% Test for old and new versions of the latex kernel
\ifx\e@alloc@intercharclass@top\@undefined
    \chardef\CharBound=255
\else
    \chardef\CharBound=\e@alloc@intercharclass@top
\fi
\makeatother
\newXeTeXintercharclass\CharNumbers
\XeTeXcharclass`0=\CharNumbers
\XeTeXcharclass`1=\CharNumbers
\XeTeXcharclass`2=\CharNumbers
\XeTeXcharclass`3=\CharNumbers
\XeTeXcharclass`4=\CharNumbers
\XeTeXcharclass`5=\CharNumbers
\XeTeXcharclass`6=\CharNumbers
\XeTeXcharclass`7=\CharNumbers
\XeTeXcharclass`8=\CharNumbers
\XeTeXcharclass`9=\CharNumbers
\newtoks\TokSetfont
\TokSetfont={\begingroup\fontspec{Latin Modern Mono}}
\XeTeXinterchartoks\CharNormal\CharNumbers=\TokSetfont
\XeTeXinterchartoks\CharBound\CharNumbers=\TokSetfont
\XeTeXinterchartoks\CharNumbers\CharNormal={\endgroup}
\XeTeXinterchartoks\CharNumbers\CharBound={\endgroup}

The problem with this solution is that it does not seem to work ; it makes XeLaTeX compilation extremely slow, returning memory errors, and in the end the digits stay unchanged. The original solution was given in this answer, and as comments suggest, an infinite loop appears to be running.

Since the posts are rather old, and the solutions do not seem to work anymore, I figured I would ask again if anyone had an idea about how to change the main font for digits only. I am fully aware that this is an extremely unimportant thing to do, but still : any ideas ?

[EDIT] For convenience, a minimal working example with free fonts :

% !TeX program = xelatex
\documentclass{article}

\usepackage{fontspec}
\setmainfont[
    BoldFont={Georgia Bold}, 
    ItalicFont={Georgia Italic},
    BoldItalicFont={Georgia Bold Italic},
    SmallCapsFont={Latin Modern Roman Caps}
    ]{Linux Libertine O}

\begin{document}

Everything \textbf{just} \textsc{Works}, \\
but I don't like this ``1''

\end{document}
fkrz
  • 63
  • Welcome to Tex–LaTeX Stack Exchange! In my opinion, what you want to do is not ‘extremely unimportant’ — many older fonts have their lowercase numbers in a separate, small caps font, and they’d be much easier to use if someone found a way to do what you want. – Thérèse Jul 09 '18 at 19:42
  • @Thérèse Well, we already have a solution for those: that's what virtual fonts are for, basically. They allow you to use the oldstyle figures and small-caps from the extended type1 fonts supplied with the main ones. I guess, however, you mean a document-level solution. – cfr Jul 09 '18 at 22:53
  • A complete example would make things easier, especially if it uses fonts everyone has. Do you really need xltxtra? It isn't recommended these days for most cases. – cfr Jul 09 '18 at 22:54
  • Hello @cfr — I knew about virtual fonts for .pfb fonts, but the older fonts I had in mind were older .otf fonts, such as Linotype’s Stempel Schneidler. Are virtual fonts relevant there too? – Thérèse Jul 10 '18 at 02:04
  • @Thérèse Oh, no. I didn't know they did that. I'm not sure. You can use them for truetype fonts. I'd guess you should be able to do it for opentype, too, if you can get the engine to use regular TFMs etc. That is, I don't see why it shouldn't work, since the newer engines can fall back to TeX fonts. However, I would not want to bet much on this without actually trying it. – cfr Jul 10 '18 at 02:14
  • @Thérèse Of course, you'd lose any opentype features. Would that be a concern with the older fonts or were they not really using those then? – cfr Jul 10 '18 at 02:17
  • @cfr Schneidler has the aalt, case, dnom, frac, kern, liga, numr, ordn, sinf, smcp, and sups features. I’d certainly want to keep case and sups, and of course kern and liga. – Thérèse Jul 10 '18 at 02:26
  • @Thérèse You can keep them in the sense that you can implement most of it in traditional fonts with enough work. But you can't keep them 'in the font', so to speak. All you'll take from the font is the glyph: everything else has to be in the TFM/VF. At least, that's how I understand it and how I've treated truetype, for example. Kerning is kept, except if there are too many pairs for the format and then some get dropped in conversion. Ligs just depend on the encoding of your virtual font. You can keep as many as you can fit. Can't remember what case does. Sups you make a different family. – cfr Jul 10 '18 at 02:38
  • @Thérèse Essentially, you end up reimplementing the features in the traditional fonts you convert to. There are some limitations to what's possible, but you can do a great deal if you have the patience. But whether the font itself has the features becomes irrelevant unless you go the autoinst conversion route when you can leverage the features to produce type1 fonts which implement them. But I tend not to convert them unless I have to. (And sometimes the licence prohibits it.) – cfr Jul 10 '18 at 02:42
  • @Thérèse But I am pretty sure none of this is news to you ... :-). – cfr Jul 10 '18 at 02:43
  • @cfr And I’m pretty sure I haven’t the patience! ;-) – Thérèse Jul 10 '18 at 02:45
  • @cfr Unfortunately, these are not fonts everyone has, and I am not sure how this website would appreciate me sharing proprietary fonts as .otf files. Therefore, I don't know what more I could add to make this a working example.

    EDIT : also, I used xltxtra precisely to load the .otf fonts and allow the compilation ; did I misunderstood its necessity ?

    – fkrz Jul 10 '18 at 13:34
  • You don't need xltxtra to load them, no. Just fontspec. True, people can't help without the fonts. But they also can't help without compilable code. So make it easy for people with the fonts to help you. – cfr Jul 10 '18 at 23:04
  • If you think people can help without the fonts, just switch fonts to ones people have. As far as I can tell, your question is really not font-specific, so an example with proprietary fonts just reduces the pool of potential helpers unnecessarily. – cfr Jul 10 '18 at 23:05
  • @cfr You are absolutely right. Fontspec works just fine without xltxtra, and I edited with a MWE including free fonts – fkrz Jul 11 '18 at 09:28

1 Answers1

3

The bottleneck is using \fontspec. Rather declare a new font family, so font allocation is not redone at each start of a run of digits.

\documentclass{article}
\usepackage{fontspec}

\setmainfont{TeX Gyre Termes}
\newfontfamily{\digits}{TeX Gyre Heros}

\XeTeXinterchartokenstate=1
\chardef\CharNormal=0
\makeatletter
% Test for old and new versions of the latex kernel
\ifx\e@alloc@intercharclass@top\@undefined
    \chardef\CharBound=255
\else
    \chardef\CharBound=\e@alloc@intercharclass@top
\fi
\makeatother
\newXeTeXintercharclass\CharNumbers
\XeTeXcharclass`0=\CharNumbers
\XeTeXcharclass`1=\CharNumbers
\XeTeXcharclass`2=\CharNumbers
\XeTeXcharclass`3=\CharNumbers
\XeTeXcharclass`4=\CharNumbers
\XeTeXcharclass`5=\CharNumbers
\XeTeXcharclass`6=\CharNumbers
\XeTeXcharclass`7=\CharNumbers
\XeTeXcharclass`8=\CharNumbers
\XeTeXcharclass`9=\CharNumbers

\XeTeXinterchartoks\CharNormal\CharNumbers={\begingroup\digits}
\XeTeXinterchartoks\CharBound\CharNumbers={\begingroup\digits}
\XeTeXinterchartoks\CharNumbers\CharNormal={\endgroup}
\XeTeXinterchartoks\CharNumbers\CharBound={\endgroup}

\begin{document}

\count255=0

\loop\ifnum\count255<1000
\advance\count255 1
Text 123 text1text\endgraf
123\endgraf
\repeat

\end{document}

I tried these 2000 paragraphs with and without the interchar tokens and the compilation time is comparable.

enter image description here

egreg
  • 1,121,712