Système de polices (NFSS / encodage)

La chaîne OT1/cmr/m/n/10 qui apparaît dans un avertissement LaTeX n’est pas un code à déchiffrer : c’est une adresse. LaTeX ne désigne jamais une fonte par son nom, il la vise avec cinq coordonnées : encodage, famille, série, forme, taille. Ce dispositif s’appelle NFSS. Cette page suit ces cinq coordonnées jusque dans le source et le fichier journal : pourquoi \bfseries demande la série bx et non b, si un ordre de gras après \fontseries{c} aboutit vraiment à bc, et ce que signale au juste l’avertissement de substitution Font shape ... undefined.

NFSS : une fonte, cinq coordonnées

La sélection des fontes dans LaTeX2e repose sur le NFSS (New Font Selection Scheme), dont la thèse centrale tient en une phrase : toute fonte de texte est entièrement déterminée par cinq attributsencodage, famille, série, forme, taille. NFSS a été conçu par Frank Mittelbach et Rainer Schöpf ; la mention de copyright du source du noyau ltfssbas.dtx remonte à 1989. Avant lui, sous LaTeX 2.09, on ne pouvait même pas combiner \bf et \it : personne n’avait encore séparé la graisse et le dessin des lettres en axes indépendants.

  • Encodage — l’ordre des glyphes dans la fonte, c’est-à-dire l’emplacement auquel correspond chaque caractère saisi. Pour le texte, les deux principaux sont OT1 (TeX text) et T1 (TeX extended text, dit Cork). Détaillé plus bas.
  • Famille — un ensemble de fontes partageant un dessin de lettres. Computer Modern Roman est cmr, sa sans est cmss, sa typewriter cmtt ; parmi les fontes commerciales, Times est ptm, Helvetica phv, Courier pcr.
  • Série — un axe unique qui fusionne graisse et chasse : m (medium), b (bold), bx (bold extended), c (condensed), bc (bold condensed), sb (semibold), etc.
  • Forme — le dessin des lettres : n (droit), it (italique), sl (penché), sc (petites capitales). Plus rare : ui, une italique sans inclinaison.
  • Taille — la taille de dessin, une dimension comme 10pt ; sans unité, pt est supposé.

Le seul point qui déroute, c’est que la série fusionne graisse et chasse en une seule valeur. Dans le schéma standard, les graisses vont de ul à ub (ultra light à ultra bold) et les chasses de uc à ux (ultra condensed à ultra expanded) ; les deux sont concaténées, et m est omis — sauf qu’un m unique subsiste lorsque graisse et chasse sont toutes deux medium. Ainsi « gras, chasse normale » s’écrit b, « bold extended » bx, « graisse normale, étroit » c, et « gras étroit » bc. Ces cinq valeurs écrites encoding/family/series/shape/size forment le nom formel d’une fonte dans LaTeX, et \showthe\font affiche celle qui est en cours.

log
% \showthe\font in a default article, and what the log answers:
> \OT1/cmr/m/n/10 .

% the same five values head every overfull-box report:
Overfull \hbox (121.83368pt too wide) detected at line 3
\OT1/cmr/m/n/10 Supercalifragilisticexpialidocious

% and the first four of them name a shape that had to be substituted:
LaTeX Font Warning: Font shape `T1/cmss/bx/sc' undefined
(Font)              using `T1/cmss/bx/n' instead on input line 4.

Pourquoi \bfseries demande la série bx et non b

La réponse : \bfseries ne lit tout simplement pas \bfdefault. Le \bfdefault du noyau vaut bien b, mais \bfseries vérifie d’abord si la famille courante est égale à \rmdefault, \sfdefault ou \ttdefault ; si oui, il utilise à la place une valeur par défaut dédiée : \bfseries@rm, \bfseries@sf ou \bfseries@tt. Or latex.ltx initialise ces trois macros à bx. \bfdefault n’est consulté que si la famille courante n’est aucune des trois — autrement dit, tant que vous tapez \bfseries dans la fonte du corps, \bfdefault est contourné.

latex.ltx
% TeX Live 2024, latex.ltx (the LaTeX2e kernel), abridged
\def\bfseries@rm{bx}
\def\bfseries@sf{bx}
\def\bfseries@tt{bx}

\DeclareRobustCommand\bfseries{%
  \not@math@alphabet\bfseries\mathbf
  \expand@font@defaults
  \maybe@update@bfseries@defaults
  \ifx\f@family\rmdef@ult      \fontseries\bfseries@rm
  \else\ifx\f@family\sfdef@ult \fontseries\bfseries@sf
  \else\ifx\f@family\ttdef@ult \fontseries\bfseries@tt
  \else                        \fontseries\bfdefault
  \fi\fi\fi
  \UseHook{bfseries}%
  \selectfont
}

Mais pourquoi bx par défaut ? À cause du nombre de fontes que Knuth a réellement dessinées. Comptez les métriques Computer Modern de TeX Live 2024 : le gras simple n’existe qu’en un seul fichier, cmb10.tfm. Le bold extended, lui, se décline en cmbx5, cmbx6, cmbx7, cmbx8, cmbx9, cmbx10 et cmbx12 — sept tailles de dessin. Seul cmbx peut composer du gras convenable jusque dans les notes de bas de page et les indices ; NFSS demande donc bx à Computer Modern.

Jusqu’ici c’est une particularité de Computer Modern, mais le noyau fait le ménage. À \begin{document}, \init@series@setup s’exécute et rétrograde \bfseries@rm en b dès lors que \rmdefault n’appartient pas à cmr, cmss, cmtt, lcmss, lcmtt, lmr, lmss, lmtt. Autrement dit, bx est un héritage propre à Computer Modern et Latin Modern : dès que l’on passe à Times ou à TeX Gyre, \bfseries se met discrètement à demander b. La mesure le confirme : avec \renewcommand\rmdefault{ptm}, \bfseries@rm et la série obtenue valent tous deux b.

Réglage dans le documentSérie demandée par \bfseriesRaison
article (default)bx\rmdefault vaut cmr, la valeur initiale de \bfseries@rm subsiste
\usepackage{lmodern}bxlmr figure lui aussi sur la liste Computer Modern du noyau
\renewcommand\rmdefault{ptm}b\init@series@setup le trouve hors liste et abaisse \bfseries@rm
\fontseries{b}\selectfontbune valeur nommée au bas niveau ne passe pas par les macros par défaut
\DeclareFontSeriesDefault[rm]{bf}{sb}sbla façon prévue de réorienter le gras d’une seule méta-famille

La conclusion pratique est nette : pour changer ce que « gras » signifie, préférez \DeclareFontSeriesDefault[rm]{bf}{b} à \renewcommand{\bfdefault}{b}. Le second fonctionne — réécrire \bfdefault amène \maybe@update@bfseries@defaults à écraser les trois valeurs dédiées — mais il ne permet de viser ni le romain seul ni la sans seule. Et devant le symptôme classique « j’ai demandé du gras et rien n’a grossi », c’est cette correspondance qu’il faut soupçonner d’abord : votre fonte n’a peut-être tout simplement pas de bx.

Les séries fusionnent : c plus b donne bc

Depuis la version 2020 de LaTeX2e (\IncludeInRelease{2020/02/02} dans latexrelease.sty), une demande de série fusionne au lieu d’écraser. Demandez du gras alors que vous composez en étroit (c) et vous n’obtenez pas b mais bc, gras étroit. La table qui en décide est construite avec \DeclareFontSeriesChangeRule, et le noyau en aligne plus de deux cents lignes. On lit {c}{b}{bc}{} ainsi : « si la série courante est c et que b est demandé, aller à bc ; pas de repli ».

latex.ltx
% the rule table (latex.ltx, from ltfssaxes.dtx), a handful of the 200-odd entries
\def\DeclareFontSeriesChangeRule#1#2#3#4{%
  \@namedef{series@#1@#2}{{#3}{#4}}}
\DeclareFontSeriesChangeRule {c}{b}{bc}{}     % condensed + bold      -> bc
\DeclareFontSeriesChangeRule {b}{c}{bc}{b}    % bold + condensed      -> bc, else b
\DeclareFontSeriesChangeRule {bx}{c}{bc}{bx}  % bold extended + cond. -> bc, else bx
\DeclareFontSeriesChangeRule {m}{b}{b}{bx}    % medium + bold         -> b,  else bx

Les règles ne se déclenchent toutefois pas sans condition. \selectfont fusionne d’abord sans substitution, puis vérifie si le encoding/family/series/shape obtenu existe réellement ; sinon il restaure les anciennes valeurs et recommence la fusion en mode substitution. Computer Modern n’a aucun dessin étroit : \fontseries{c}\selectfont émet donc un avertissement et retombe sur m, et un gras appliqué ensuite ne peut atteindre que b — d’où la conclusion, tentante, que la fusion « n’a pas lieu ». Essayez avec une famille qui possède vraiment un étroit et les règles fonctionnent. Helvetica (phv) fournit m, c, b et bc en T1 ; l’exemple ci-dessous le montre en vrai.

document.tex
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{helvet}          % sets \sfdefault to phv
\begin{document}\makeatletter
\sffamily                    % -> phv/m   (Helvetica)
\fontseries{c}\selectfont    % -> phv/c   font file phvr8tn (Helvetica Narrow)
\bfseries                    % -> phv/bc  font file phvb8tn (Helvetica Bold Narrow)
\typeout{[series] \f@series\space -> \fontname\font}
\makeatother\end{document}

% [series] bc -> phvb8tn
%
% The same document with Computer Modern instead reports:
%   LaTeX Font Warning: Font shape `OT1/cmr/c/n' undefined
%   [series] m  (the condensed request was substituted away before bold arrived)

Sélecteurs de bas niveau et \selectfont

Les sélecteurs de bas niveau définissent un attribut à la fois : \fontencoding{T1}, \fontfamily{ptm}, \fontseries{b}, \fontshape{it}, \fontsize{12}{14}. Il n’y a qu’une règle — les définir ne change rien tant que \selectfont n’est pas appelé — et la section précédente en donne la raison. \fontseries n’écrit la valeur nulle part : il l’empile sur une liste d’attente nommée \delayed@f@adjustment, et c’est \selectfont qui effectue d’un seul coup la fusion, la vérification d’existence et l’éventuelle substitution. Oubliez le \selectfont entre un réglage et le texte, et ce texte sortira dans la fonte précédente.

document.tex
\documentclass{article}
\usepackage[T1]{fontenc}
\begin{document}
% Correct: set the attributes, commit with \selectfont, then the text
{\fontfamily{ptm}\fontseries{b}\selectfont Bold Times}

% Wrong: the words before \selectfont are still in the old font
{\fontfamily{ptm} Some \fontseries{b}\selectfont text.}

% \usefont gives four attributes at once and commits on the spot
{\usefont{T1}{ptm}{b}{it} Bold italic Times}

% Change only the size; reuse the current baselineskip
\makeatletter
{\fontsize{14}{\f@baselineskip}\selectfont Fourteen point}
\makeatother
\end{document}

Le raccourci qui transmet quatre des cinq attributs d’un coup est \usefont{encodage}{famille}{série}{forme} : la taille est reprise de la valeur courante et le changement est validé sur place. Entourez-le d’un groupe { } pour en limiter la portée. Passer la macro interne \f@baselineskip comme second argument de \fontsize est l’idiome habituel pour changer le corps sans toucher à l’interlignage (ne jamais réécrire une macro interne, mais lire sa valeur pour la transmettre est sans danger). Cela dit — on écrit rarement tout cela soi-même. \textbf ne fait qu’appeler \fontseries, \sffamily que \fontfamily ; on descend au bas niveau seulement pour nommer une fonte précise ou intégrer une nouvelle fonte à une classe ou un paquet.

Les macros par défaut : \rmdefault et compagnie

La famille que choisissent \textrm ou \rmfamily n’est pas codée en dur : elle réside dans une macro. Il y en a trois — \rmdefault (romain), \sfdefault (sans), \ttdefault (typewriter) — valant par défaut cmr, cmss, cmtt dans la classe article. Pour changer la fonte du corps, on réécrit donc ces macros, pas les commandes. Et comme l’a montré la section précédente, ces trois valeurs déterminent aussi ce que le gras demandera : mieux vaut y voir non des alias mais la politique de fontes du document.

preamble.tex
% Re-point the three meta-families for the whole document
\renewcommand{\rmdefault}{ptm}  % roman   -> Times
\renewcommand{\sfdefault}{phv}  % sans    -> Helvetica
\renewcommand{\ttdefault}{pcr}  % mono    -> Courier

% The body font itself is these four (defaults: OT1, \rmdefault, m, n)
%   \encodingdefault \familydefault \seriesdefault \shapedefault
% and \familydefault points at \rmdefault, so the line above changes the body.

% Retarget bold and medium per meta-family (LaTeX2e 2020-02-02 and later)
\DeclareFontSeriesDefault[rm]{bf}{b}
\DeclareFontSeriesDefault[sf]{md}{l}

Fichiers .fd et \DeclareFontShape : où les coordonnées rencontrent les fichiers

Ce qui relie les cinq coordonnées à de vrais fichiers de fontes, c’est le fichier de définition de fonte (.fd). Son nom est l’encodage en minuscules suivi de la famille — ot1cmr.fd pour cmr en OT1, t1phv.fd pour phv en T1 — et LaTeX le charge automatiquement dès qu’il en a besoin. kpsewhich ot1cmr.fd indique où se trouve le vôtre. À l’intérieur, une ligne \DeclareFontFamily, puis un \DeclareFontShape par combinaison série/forme.

ot1cmr.fd
% TeX Live 2024, tex/latex/base/ot1cmr.fd (excerpt)
\DeclareFontFamily{OT1}{cmr}{\hyphenchar\font45 }
\DeclareFontShape{OT1}{cmr}{m}{n}%
     {<5><6><7><8><9><10><12>gen*cmr%
      <10.95>cmr10%
      <14.4>cmr12%
      <17.28><20.74><24.88>cmr17}{}
%%%%%%% bold series
\DeclareFontShape{OT1}{cmr}{b}{n}
     {%
      <5><6><7><8><9><10><10.95><12>%
      <14.4><17.28><20.74><24.88>cmb10%
      }{}
%%%%%%%% bold extended series
\DeclareFontShape{OT1}{cmr}{bx}{n}
   {%
      <5><6><7><8><9>gen*cmbx%
      <10><10.95>cmbx10%
      <12><14.4><17.28><20.74><24.88>cmbx12%
      }{}

Les lire revient à suivre les plages de tailles entre chevrons. <5><6><7><8><9>gen*cmbx signifie « de 5 à 9 points, utiliser la fonte réelle dont le nom est le radical suivi de la taille (cmbx5, cmbx6, …) » ; <12><14.4>...cmbx12 signifie « à partir de 12 points, mettre cmbx12 à l’échelle ». Le bloc b ci-dessus illustre la situation décrite plus haut : toutes les tailles, de 5 à 24,88 points, ne sont que du cmb10 étiré. Il existe aussi ssub (substitution silencieuse) et sub (substitution avec avertissement) ; t1phv.fd contient par exemple \DeclareFontShape{T1}{phv}{bx}{n}{<->ssub * phv/b/n}{} — Helvetica n’a pas de bx, on livre donc b sans rien dire.

Lire l’avertissement Font shape ... undefined

Cet avertissement est un compte rendu : cette combinaison ne figurait pas dans le .fd, j’ai donc pris de moi-même la plus proche. Il apparaît toujours sur deux lignes — les quatre coordonnées demandées sur la première, les quatre réellement employées plus un numéro de ligne sur la seconde. Ce n’est pas une erreur, la compilation va donc à son terme ; le PDF obtenu n’est simplement pas celui qui a été demandé. Dans les exemples ci-dessus, Computer Modern n’a pas d’étroit, donc c est devenu m, et T1/cmss n’a pas de petites capitales, donc le droit n a été utilisé.

log
% a missing shape inside a family that does exist
LaTeX Font Warning: Font shape `T1/cmss/bx/sc' undefined
(Font)              using `T1/cmss/bx/n' instead on input line 4.

% a family that does not exist at all: \DeclareFontSubstitution kicks in
LaTeX Font Warning: Font shape `T1/nosuchfont/m/n' undefined
(Font)              using `T1/cmr/m/n' instead on input line 4.

% and at the end of the run, the summary line that is easy to miss
LaTeX Font Warning: Some font shapes were not available, defaults substituted.

Il n’y a que trois causes. (1) La fonte n’a tout simplement pas ce dessin — Helvetica n’a pas d’italique, sl prend donc le relais. On ne fait pas surgir ce qui n’existe pas : changez de fonte ou acceptez le substitut. (2) Le nom de famille est mal orthographié — si cmr apparaît en seconde ligne, c’est l’ultime recours de \DeclareFontSubstitution qui s’est déclenché, généralement une faute de frappe ou un paquet oublié. (3) L’encodage n’est pas le bon — demander en T1 une famille qui n’a qu’un .fd OT1, par exemple. Enfin, la ligne récapitulative de fin, Some font shapes were not available, defaults substituted., se lit trop vite — mais si elle est là, un passage de votre document est composé dans une fonte que vous n’avez pas choisie.

Encodages de fonte : OT1, T1 et TU

Un encodage de fonte est la convention qui dit à quel emplacement (glyphe) de la fonte correspond chaque caractère saisi. C’est le premier des cinq attributs et le seul sans commande d’auteur comme \textbf — en changer est l’affaire d’un paquet, celle de fontenc. OT1 est le « TeX text » 7 bits d’origine de Knuth (le défaut). N’ayant place que pour 128 caractères, é et ñ y sont construits par composition d’une lettre de base et d’un accent (\accent), et c’est cette composition qui fait que les mots accentués ne se coupent pas et qu’ils ressortent altérés à la copie depuis le PDF. T1 (TeX extended text, dit aussi encodage Cork d’après la réunion TUG de 1990 à Cork) est un encodage 8 bits de 256 glyphes qui porte chaque lettre accentuée comme un glyphe unique : les deux problèmes disparaissent d’un coup.

Rien ne montre mieux qu’un encodage n’est qu’une convention sur l’ordre des emplacements que le signe livre dans OT1. OT1 n’a pas d’emplacement pour le sterling : \textsterling, dans ot1enc.def, va donc chercher l’emplacement du dollar de la fonte italique (en Computer Modern, cet emplacement contient £). Et si la fonte courante n’a aucune inclinaison, il bascule d’abord sur \fontshape{ui} — sinon le £ seul sortirait penché. D’où le commentaire d’avertissement, dans ot1cmr.fd, précisant que la déclaration ui sert au \pounds de LaTeX et ne doit pas être supprimée.

TU (TeX Unicode) permet d’adresser directement, par point de code Unicode, les fontes OpenType installées sur le système ; c’est le défaut de XeLaTeX et LuaLaTeX. Il a remplacé les anciens EU1 (pour XeTeX) et EU2 (pour LuaTeX) : d’après le journal des modifications de fontspec, TU apparaît en v2.5, le 30 janvier 2016, et devient le défaut en v2.5c, le 20 janvier 2017. Dans TeX Live 2024, les chaînes EU1 et EU2 ne figurent plus nulle part dans fontspec.sty. Il existe encore T2A (cyrillique), LGR (grec) et TS1 (l’encodage Text Companion : monnaies, copyright et autres symboles de texte) ; pour les mathématiques, OML (italique mathématique), OMS (symboles) et OMX (grands symboles). À noter : les commandes de symboles de TS1 ont rejoint le noyau en 2020, si bien que le paquet textcomp d’aujourd’hui ne définit plus aucun symbole — la page des symboles raconte cette histoire.

EncodageCe qu’il couvreLargeur / notes
OT1Le TeX text original de Knuth (défaut)7 bits ; accents composés, donc pas de césure
T1TeX extended text (Cork) ; langues occidentales8 bits, 256 glyphes ; accents uniques, césure possible
TUTeX Unicode ; fontes OpenType adressées directementDéfaut sous Xe/LuaLaTeX ; a remplacé EU1 / EU2
T2ACyrillique8 bits (T2B / T2C sont apparentés)
LGRGrecL’encodage à 256 glyphes aujourd’hui standard pour le grec
TS1Text Companion (symboles de texte)Monnaie, copyright, etc. ; les commandes sont passées dans le noyau en 2020
OML / OMS / OMXItalique mathématique / symboles / grands symbolesRéservés aux maths, jamais au texte courant

inputenc et fontenc : l’entrée et la sortie

Séparons deux notions faciles à confondre. L’encodage d’entrée régit la façon dont les octets du source .tex sont lus comme caractères (UTF-8 et consorts) — historiquement le rôle du paquet inputenc. L’encodage de fonte régit dans quel glyphe de la fonte de sortie chacun de ces caractères s’écoule, et c’est le rôle de fontenc. Retenez l’entrée (inputenc) et la sortie (fontenc) et vous ne les confondrez plus. Le pdfLaTeX moderne lit le source en UTF-8 par défaut : il n’est donc presque jamais nécessaire de charger inputenc explicitement. L’encodage de fonte, lui, mérite toujours d’être défini. fontenc est un paquet pour pdfLaTeX ; sous XeLaTeX et LuaLaTeX, on utilise fontspec, et comme TU y est le défaut, le problème ne se pose guère.

Avec pdfLaTeX, écrire \usepackage[T1]{fontenc}

Si vous composez avec pdfLaTeX, l’usage est de mettre \usepackage[T1]{fontenc} dans le préambule. Cela bascule l’encodage de fonte du document vers T1 et balaie les défauts du OT1 par défaut : mots accentués non césurés, texte altéré à la copie depuis le PDF. La documentation de fontenc le dit : elle prend en charge des langues occidentales répandues comme le français, l’allemand, l’italien et le polonais, et grâce à elle LaTeX césure les mots comportant des lettres accentuées tandis que la sortie reste copiable-collable. Quand plusieurs encodages sont donnés en option, le dernier de la liste devient le défaut (\encodingdefault est réglé sur lui) — pour un document mêlant du grec, écrivez donc \usepackage[LGR,T1]{fontenc} : le corps reste en T1, et l’on bascule vers LGR uniquement là où c’est nécessaire.

document.tex
\documentclass{article}
\usepackage[T1]{fontenc}   % font encoding -> T1 (Cork)
% Input is UTF-8 by default on pdfLaTeX, so inputenc is usually unneeded.
\begin{document}
% With T1 these words hyphenate and survive copy-and-paste out of the PDF.
Na\"ive r\"esum\"e, \"uberfl\"ussig, Stra\ss{}e.
\end{document}