[Tex/LaTex] ConTeXt keeps trying to create “missing” font files

contextfontsxetex

I'm running ConTeXt/XeTeX on a file that uses the Gentium Book Basic font. The problem I'm having is that XeTeX appears to spend a large amount of time trying over and over again to create that font or associated auxiliary files (using mktexmf and mktextfm). As far as I can tell, the font is working fine otherwise.

In summary, when I run XeTeX, I get lots of output like this:

(./macros/pagenohead.tex) (./data/front-matter-all.tex
kpathsea: Running mktextfm GentiumBookBasic
/usr/local/texlive/2012/texmf/web2c/mktexnam: Could not map source abbreviation  for GentiumBookBasic.
/usr/local/texlive/2012/texmf/web2c/mktexnam: Need to update ?
mktextfm: Running mf-nowin -progname=mf \mode:=ljfour; mag:=1; nonstopmode; input GentiumBookBasic
This is METAFONT, Version 2.718281 (TeX Live 2012)

kpathsea: Running mktexmf GentiumBookBasic

! I can't find file `GentiumBookBasic'.
<*> ...mag:=1; nonstopmode; input GentiumBookBasic

Please type another input file name
! Emergency stop.
<*> ...mag:=1; nonstopmode; input GentiumBookBasic

Transcript written on mfput.log.
grep: GentiumBookBasic.log: No such file or directory
mktextfm: `mf-nowin -progname=mf \mode:=ljfour; mag:=1; nonstopmode; input GentiumBookBasic' failed to make GentiumBookBasic.tfm.
kpathsea: Appending font creation commands to missfont.log.

kpathsea: Running mktextfm GentiumBookBasic

I actually get this repeated almost 1700 times in a 16-page document… presumably it's happening every time I try to use the font GentiumBookBasic. As a result, it takes about 10 minutes to render this to PDF on a decent server. When I switch to a standard built-in font like "Serif", the document renders in under 9 seconds!

If we try to render our whole 1200-page book without fixing this problem, it might take on the order of 12 hours!

Incidentally, when the PDF eventually comes out the other end, the text that's supposed to be in Gentium looks like it was rendered perfectly well in the Gentium font. So the result is correct; it's just taking much longer and doing much more futile work than it should.

What can I do to get TeX to recognize the font properly and stop trying to recreate its associated files every time the font is used?

The details:

  • ConTeXt ver: 2012.05.30 11:26 MKII fmt: 2012.11.5
  • XeTeX, Version 3.1415926-2.4-0.9998 (TeX Live 2012)

We need to use a font that doesn't come with TeXLive: Gentium Book Basic. So I needed to find out how to get XeTeX to find a 3rd-party font.

I read here that "XeTEX and LuaTEX can use any font installed on the system, not just those in the TEX trees". By contrast, "[Integrating 3rd-party fonts] is unfortunately a messy topic. Forget about it unless you want to delve into many details of the TEX installation. …A possible alternative is to use XeTEX or LuaTEX (see section 2.4), which let you use operating system fonts without any installation in TEX. "

So apparently all I need to do is install Gentium Book Basic in the OS (CentOS Linux in my case), and XeTeX should be able to find it.

In order to install Gentium Book Basic onto the system, I followed the instructions on pages like this:

  • ls Gen*

GenBasBI.ttf
GenBasB.ttf
GenBasI.ttf
GenBasR.ttf
GenBkBasBI.ttf
GenBkBasB.ttf
GenBkBasI.ttf
GenBkBasR.ttf

  • mkdir /usr/share/fonts/TTF
  • cp Gen*.ttf /usr/share/fonts/TTF
  • fc-cache -f -v
  • fc-list | grep Gentium

The latter gives:

 Gentium Basic:style=Bold Italic
 Gentium Book Basic:style=Bold
 Gentium Book Basic:style=Italic
 Gentium Basic:style=Regular
 Gentium Book Basic:style=Bold Italic
 Gentium Book Basic:style=Regular
 Gentium Basic:style=Italic
 Gentium Basic:style=Bold

So it looks to me like Gentium is successfully installed in the OS.

The TeXLive installation docs say the following:

On Windows, fonts shipped with TEX Live are made available to XeTEX
automatically. But if you have installed the xetex package on a
Unix-compatible system, you need to configure your system to be able
to find the fonts shipped with TEX Live via system name lookup, and
not just filename lookup.

To facilitate this, when the xetex package is installed (either at
initial installation or later), the necessary configuration file is
created in TEXMFSYSVAR/fonts/conf/texlive-fontconfig.conf.

To set up the TEX Live fonts for system-wide use (assuming you have
suitable privileges), proceed as follows:

Copy the texlive-fontconfig.conf file to /etc/fonts/conf.d/09-texlive.conf.
Run fc-cache -fsv.

I find this confusing. Is it concerned with letting XeTeX see fonts that didn't come with TeXLive, or letting the rest of the system see fonts that came with TeXLive? It seems to say both. Nevertheless, I supposed it couldn't hurt, so I followed the above instructions, and fc-cache reported that it completed successfully.

Now to how I'm referencing the font in a ConTeXt document. I have fonts defined as follows:

\definefont[SerifS][GentiumBookBasic at \smallfontsize]
\definefont[SerifLB][GentiumBookBasic-Bold at \largefontsize]

etc. These are used in styles as follows:

% 'Small' Italic (8.1pt)
\def\IT#1{{\SerifSI#1}}

% 'Big' Bold (9.2pt)
\def\BO#1{{\SerifLB#1}}

which are referenced in the .tex files:

\IT{Class: }
\BO{Previous Editions}

Now, comparing the above \definefont with the font names reported by fc-list, it's apparent that the former uses names without spaces ("GentiumBookBasic") while the latter uses names with spaces ("Gentium Book Basic"). Could that be a source of the problem?

The command reference page for \definefont in ConTeXt has little to say. The section on \definefontsynonym in the fonts manual says the spaces in the 2nd argument should be stripped out. But I tried it anyway:

\definefont[SerifS][Gentium Book Basic at \smallfontsize]

etc. However the results were no better:

kpathsea: Running mktextfm GentiumGentium
/usr/local/texlive/2012/texmf/web2c/mktexnam: Could not map source abbreviation  for GentiumGentium.

etc.

Kudos to anyone who took time to browse through the above. Any help you can offer is appreciated!

P.S.: I also tried changing the font definitions in our .tex file to use the actual TTF file names (w/o extension) instead of the full font names; e.g.

\definefont[SerifS][GenBkBasR at \smallfontsize]

and even for good measure:

\definefont[SerifS][GenBkBasR.ttf at \smallfontsize]

This didn't seem to make any difference. I still get errors like "I can't find file `GenBkBasR'." (The extension is stripped, when I provide it.)

I even tried using file: as shown in http://context.aanhet.net/svn/contextman/context-reference/en/co-fonts.pdf page 2:

\definefont[SerifS][file:GenBkBasR at \smallfontsize]

and following examples in the typescripts module that Aditya mentioned, I tried

\definefont[SerifS][\s!file:GenBkBasR at \smallfontsize]

(though I don't know what the \s! is for).
But in both cases I got this "worse" error:

kpathsea: Invalid fontname `[GenBkBasR]', contains '['

before getting the usual

kpathsea: Running mktextfm GenBkBasR

/usr/local/texlive/2012/texmf/web2c/mktexnam: Could not map source abbreviation  for GenBkBasR.

etc. And unlike before, TeX failed to complete the render in these cases.

Update

Let me try to pull this question into focus…

  • Why is Xetex (or whatever component of the system) trying to call mktexnam, mktextfm, mktexmf, etc. on Gentium Book Basic – is it because it perceives that some TeX auxiliary files for that font have not been created? Is it failing, each time, to create those files? Yet the font is being rendered properly, so ultimately the system succeeds in getting the data it needs. Is there something I can do to cause TeX to successfully write the auxiliary data files it needs, so it doesn't painstakingly "stumble" over this every time the font is referenced? I've been treating utils like mktex* as "under the hood", and I would like to keep them there, but maybe I'm going to have to understand how they work in order to solve the problem.

  • The first error, mktexnam: Could not map source abbreviation for GentiumBookBasic – is that something I can directly fix, by providing an explicit mapping? How?

Best Answer

Wow. I didn't think this would have such a huge effect.

Reading this,

In these two systems, ConTEXt first attempts to find the font using the official font name. If that doesn't work, then it tries to use the font by file name as a fallback. Since this is not very efficient and also because it may generate —harmless, but alarming looking— warnings it is possible to force ConTEXt into one or the other mode by using a prefix, so you will most often see synonym definitions like this:

\definefontsynonym [MSTimes] [name:TimesNewRoman] [features=default] \definefontsynonym [Iwona-Regular] [file:Iwona-Regular] [features=default]

I decided to try [name:GentiumBookBasic ...] instead of just [GentiumBookBasic ...]. (As shown in my edited question, I had already tried [file:GenBkBasR ...], with no success.) I didn't think using name: would make much difference, if any, since according to the above, the official font name is tried first anyway.

But it made all the difference in the world.

All the warning messages I had seen disappeared. I searched the output in vain for any mention of mktexnam, mktextmf, etc.

And more importantly, the render time went from 9 minutes down to 13.5 seconds!

Soli Deo Gloria

I'm still puzzled as to why I was having the "not very efficient" (i.e. 40 to 60x slowdown!) problem before I started using name:. I suppose ConTEXt was searching for the font by filename first instead of by official font name first, contrary to the documentation (which might refer to a different version). Still, should it have taken that long?

Lessons learned:

  • The warnings I was seeing were apparently due to the fact that ConTeXt was first trying to look up the font by filename--and trying to create auxiliary files for a font with that filename, which didn't exist--before looking for a font with that official font name. The latter worked as a fallback, but the former took a huge amount of time.

  • Always (or at least when these warnings appear) specify, in font definitions, whether you're trying to describe the font by font name or by file name.

  • Yes, XeTeX really does work with fonts that are just installed in the OS, if you reference the font by official name, but apparently not if you try to reference the font by filename.

  • If you need to add attributes like 'italic' to the name of a font in \definefont, you can do it like this: \definefont[SerifLI][name:GentiumBookBasic-Italic at \largefontsize], even though there is no font whose name is "GentiumBookBasic-Italic". This corresponds to a font face that fc-list lists as Gentium Book Basic:style=Italic. This syntax is not unexpected, but the draft fonts chapter didn't seem to explain whether Palatino-Italic was more than just a monolithic font name. So the question of whether I had it right or not was an additional dimension of uncertainty during debugging.