. 11
( 13)


fi; bye.
In a monospaced font like cmtt10, all characters will be exactly 9u# wide. Both cmr10
and cmtt10 use the roman driver, but roman omits the ligatures and changes the inter-
word spacing when it is producing monospaced fonts.
The program ¬les of Computer Modern have slightly di¬erent conventions
from those of plain . Here, for example, are the programs for two of the
simplest punctuation marks:
cmchar "Period";
numeric dot_diam#; dot_diam# = if monospace: 5/4 fi dot_size#;
adjust_fit(0,0); pickup fine.nib;
pos1(dot_diam,0); pos2(dot_diam,90);
x1l=good.x(x1l+.5w-x1); bot y2l=0; z1=z2; dot(1,2); % dot
penlabels(1,2); endchar;

(Figure Ec&Ed will be inserted here; too bad you can™t see it now.)

iff not monospace: cmchar "Em dash";
italcorr .61803x_height#*slant + .5u#;
pickup crisp.nib; pos1(vair,90); pos2(vair,90);
y1r=y2r=good.y(y1r+.61803h-y1); lft x1=-eps; rt x2=w+eps;
filldraw stroke z1e--z2e; % crossbar
penlabels(1,2); endchar;
Appendix E: Examples 307

The new structural features in these programs are: (1) ˜cmchar™, which appears at cmchar

the very beginning of each character program; (2) ˜i¬ boolean expression :™, which
adjust ¬t
precedes cmchar if the character is to be generated only when the boolean expression relax
is true; (3) ˜adjust ¬t™, which can change the amount of white space at the character™s always if
left and/or right; (4) pens called ˜¬ne.nib ™ and ˜crisp.nib ™; (5) new macros ˜pos ™, ˜dot ™, outer
and ˜stroke ™, discussed further below. sidebearings
bounding box
The base ¬le cmbase.mf begins as follows:
adjust ¬t
letter ¬t
% The base file for Computer Modern (a supplement to plain.mf)
cmbase:=1; % when cmbase is known, this file has been input
let cmchar = relax; % ˜cmchar™ should precede each character
let generate = input; % ˜generate™ should follow the parameters
newinternal slant, superness, · · · % purely numeric parameters
boolean serifs, monospace, · · · % boolean parameters
These few lines are straightforward enough. Although cmchar is de¬ned to be the
same as relax, which does nothing, the de¬nition of cmchar will be changed by certain
utility programs below; this will prove to be a convenience when characters are designed,
tested, and maintained.
The next few lines of cmbase are trickier. They implement the ˜i¬ ™ feature,
which bypasses unwanted characters at high speed.
let semi_ = ;; let colon_ = :; let endchar_ = endchar;
def iff expr b =
if b: let next_ = use_it else: let next_ = lose_it fi;
next_ enddef;
def use_it = let : = restore_colon; enddef;
def restore_colon = let : = colon_; enddef;
def lose_it = let endchar = fi; inner cmchar; let ; = fix_ semi_
if false enddef;
def fix_ = let ; = semi_; let endchar = endchar_; outer cmchar; enddef;
def always_iff = let : = endgroup; killboolean enddef;
def killboolean text t = use_it enddef;
outer cmchar;
(The lose_it routine assumes that every character program will end with ˜endchar;™.)
The most interesting part of cmbase is probably the way it allows the “side-
bearings” of each character to be ¬ne-tuned. The amount of space at the left and right
edges of the character™s “bounding box” can be adjusted without actually shifting the
picture, and without changing the width that was speci¬ed in beginchar. Here™s
how it works: After a beginchar command and an optional italcorr, each Computer
Modern character program is supposed to say
adjust ¬t( left sidebearing adjustment , right sidebearing adjustment );
sidebearing adjustments are given in true, “sharped” units. The adjust ¬t routine
essentially adds extra space at the left and right, corresponding to the sidebearing
adjustments. An ad-hoc dimension called “letter ¬t #” is also added to all sidebearings,
behind the scenes.
308 Appendix E: Examples

Our example program for the "." says simply ˜adjust ¬t(0, 0)™; this means font quad
that only letter ¬t is added. The program for em-dash says ˜adjust ¬t(letter ¬t #, b
serif ¬t
letter ¬t #)™, hence the sidebearings are increased by 2letter ¬t at each side. The total sans-serif
character width of the em-dash comes to 18u# + 4letter ¬t # (which is indeed one em, monospace
shrink ¬t
the value of font quad speci¬ed in the roman driver ¬le). l
The program for lowercase ˜b™ in ¬le romanl.mf says ˜adjust ¬t(serif ¬t #, 0)™; r
this adds the serif ¬t parameter at the left, to compensate for the possible appearance
of a serif at the left of this character. The serif ¬t is zero in cmr10, but it has a negative u
value in a sans-serif font, and a positive value when serifs are extralong. jut
mono charwd
The nice thing about adjust ¬t is that it™s an “add-on” speci¬cation that
doesn™t a¬ect the rest of the character design. The program can still be written as
if 0 were the left edge and w were the right edge; afterwards the ¬t can be adjusted
without changing the program or the shapes.
There are two versions of adjust ¬t, one for normal fonts and one for mono-
space fonts. Both of them are slightly complicated by something called shrink ¬t , which
will be explained later; for the moment, let™s just imagine that shrink ¬t = 0. Here is
the routine for the normal case:
def normal_adjust_fit(expr left_adjustment,right_adjustment) =
l := -hround(left_adjustment*hppp)-letter_fit;
interim xoffset := -l;
charwd := charwd+2letter_fit#+left_adjustment+right_adjustment;
r := l+hround(charwd*hppp)-shrink_fit;
w := r-hround(right_adjustment*hppp)-letter_fit;
Variables l and r are set to the actual pixel boundaries of the character; thus, plain
™s bounding box has 0 ¤ x ¤ w, but Computer Modern™s has l ¤ x ¤ r.
Rounding has been done very carefully so that the sidebearings will have consistent
relationships across an entire font. Notice that w has been recalculated; this means
that adjust ¬t can a¬ect the digitization, but”we hope”in a bene¬cial way.
In a monospaced font, the adjust ¬t routine changes the unit-width param-
eter, u , so that the total width after adjustment comes out to be constant. Similar
adjustments are made to parameters like jut , the nominal serif length. The width of
all characters in a monospaced font will be mono charwd # in true units, mono charwd
in pixels. The italic correction of all characters will be mono charic #.
def mono_adjust_fit(expr left_adjustment,right_adjustment) =
numeric expansion_factor; mono_charwd# = 2letter_fit#
+ expansion_factor*(charwd+left_adjustment+right_adjustment);
forsuffixes $=u,jut, · · · :
$ := $.#*expansion_factor*hppp; endfor
l := -hround(left_adjustment*expansion_factor*hppp)-letter_fit;
interim xoffset := -l;
r := l+mono_charwd-shrink_fit;
w := r-hround(right_adjustment*expansion_factor*hppp)-letter_fit;
charwd := mono_charwd#; charic := mono_charic#;
It took the author umpteen trials to get this routine right.
Appendix E: Examples 309

The xo¬set calculations in adjust ¬t are enough to shift the character by the xo¬set
shipped out
proper amount when it™s being shipped out. We just have to take care of getting the
extra endchar
correct character width in pixels, and cmbase does this by setting endchar
extra_endchar := extra_endchar&"r:=r+shrink_fit;w:=r-l;"; maketicks
change width
No other changes to plain ™s endchar routine are needed; but we font setup
do need to rede¬ne makebox and maketicks, in order to show the adjusted bounding
box. It™s convenient to change makebox so that it also slants the box, in a slanted font,
and so that it draws vertical lines one unit apart as aids to the designer; several more
horizontal lines are also drawn:
def makebox(text rule) =
for y=0,asc_height,body_height,x_height,bar_height,
-desc_depth,-body_depth: rule((l,y)t_,(r,y)t_); endfor % horizontals
for x=l,r: rule((x,-body_depth)t_,(x,body_height)t_); endfor % verticals
for x=u*(1+floor(l/u)) step u until r-1:
rule((x,-body_depth)t_,(x,body_height)t_); endfor % more verticals
if charic<>0:
rule((r+charic*pt,h.o_),(r+charic*pt,.5h.o_)); fi % italic correction
def maketicks(text rule) =
for y=0,h.o_,-d.o_:
rule((l,y),(l+10,y)); rule((r-10,y),(r,y)); endfor % horizontals
for x=l,r: rule((x,10-d.o_),(x,-d.o_));
rule((x,h.o_-10),(x,h.o_)); endfor % verticals
if charic<>0:
rule((r+charic*pt,h.o_-10),(r+charic*pt,h.o_)); fi % italic correction
(Examples of the new makebox routine appear in the illustrations for period and em-
dash earlier in this appendix, and also in Chapter 23.)
Plain ™s change width routine must also be generalized:
def change_width = if not monospace: % change width by +1 or -1
if r+shrink_fit-l = floor(charwd*hppp): w := w+1; r := r+1;
else: w := w-1; r := r-1; fi fi enddef;
The Computer Modern font setup routine is invoked at the beginning of each
driver ¬le. This is what converts sharped units to pixels; font setup also computes
additional quantities that are important to the font as a whole. It™s a long macro, but
here are its important features:
def font_setup =
define_pixels(u,jut, · · · );
define_whole_pixels(letter_fit,fine,crisp, · · · );
define_whole_vertical_pixels(body_height,cap_height, · · · );
define_whole_blacker_pixels(hair,stem,curve, · · · );
define_whole_vertical_blacker_pixels(vair,slab, · · · );
define_corrected_pixels(o, · · · );
310 Appendix E: Examples

if monospace: mono_charwd# := 9u#; define_whole_pixels(mono_charwd); lowres ¬x
mono_charic# := max(0,body_height#*slant);
let adjust_fit = mono_adjust_fit; shrink ¬t
else: let adjust_fit = normal_adjust_fit; fi
lowres_fix(stem,curve) 1.2; low resolutions
Initialize pen nibs, see below
currenttransform:=identity slanted slant
yscaled aspect_ratio scaled granularity; currentbreadth
shrink_fit := 1+hround(2letter_fit#*hppp)-2letter_fit; numeric pickup
clear pen memory
if not string mode: if mode <= smoke: shrink_fit := 0; fi fi
If letter ¬t # = 0, the ˜shrink ¬t ™ is set to 1; otherwise shrink ¬t is 0, 1, or 2, depending
on how letter ¬t has rounded to an integer. This amount is essentially subtracted
from w before each character in the font has been drawn. Experience shows that this
trick greatly improves the readability of fonts at medium and low resolutions.
Many of the Computer Modern characters are drawn with ¬lldraw, which
is a mixture of outline-¬lling and ¬xed-pen drawing. Several macros are included in
cmbase to facilitate ¬lldrawing, especially ˜pos ™ and ˜stroke ™:
vardef pos@#(expr b,d) =
(x@#r-x@#l,y@#r-y@#l)=(b-currentbreadth,0) rotated d;
x@#=.5(x@#l+x@#r); y@#=.5(y@#l+y@#r) enddef;
vardef stroke text t =
forsuffixes e=l,r: path_.e:=t; endfor
path_.l -- reverse path_.r -- cycle enddef;
Thus pos is like penpos , except that it subtracts currentbreadth from the overall
breadth. (Cf. the program for left parentheses in Chapter 12.) The stroke rou-
tine is a simpli¬ed alternative to penstroke, such that penstroke is equivalent to
˜¬ll stroke ™ if the speci¬ed path isn™t a cycle.
The value of currentbreadth is maintained by rede¬ning plain ™s
˜numeric pickup ™ macro so that it includes the new line
if known breadth_[q]: currentbreadth:=breadth_[q]; fi
The clear pen memory macro is rede¬ned so that its second line now says
numeric pen_lft_[],pen_rt_[],pen_top_[],pen_bot_[],breadth_[];
relevant entries of the breadth array will be de¬ned by font setup, as we™ll see soon.
The example programs for period and em-dash say ˜pickup ¬ne.nib ™ and
˜pickup crisp.nib ™. These nibs are initialized by font setup in the following way:
forsuffixes $ = fine,crisp, · · · :
$.breadth := $;
pickup if $=0: nullpen else: pencircle scaled $; $ := $-eps fi;
$.nib := savepen; breadth_[$.nib] := $;
forsuffixes $$ = lft,rt,top,bot: shiftdef($.$$,$$ 0); endfor endfor
Appendix E: Examples 311

If, for example, we have ¬ne = 4, this code sets ¬ne.breadth := 4, ¬ne.nib := 1, eps
¬ne := 4 ’ eps , and breadth [1] := 4 ’ eps . (A small amount eps has been subtracted ¬ne.lft
so that pos will usually ¬nd b ’ currentbreadth > 0.) Furthermore, four subroutines serif
¬ne.lft , ¬ne.rt , ¬ne.top , and ¬ne.bot are de¬ned, so that it™s easy to refer to the edges dot
of ¬ne.nib when it has not been picked up. These four subroutines are created by a dump.
slightly tricky shiftdef macro: utility ¬les
def shiftdef(suffix $)(expr delta) = rtest.mf
vardef $ primary x = x+delta enddef enddef;

OK, we™ve just about covered everything in cmbase that handles the extra
always i¬
administrative complexity inherent in a large-scale design. The rest of the base ¬le
simply contains subroutines like serif and dot , for recurring features of the characters
themselves. Such subroutines needn™t be shown here.
To make a binary ¬le called cm.base, there™s a trivial ¬le ˜cm.mf™:
% This file creates ˜cm.base™, assuming that plain.base is preloaded
input cmbase; dump.

Besides parameter ¬les, driver ¬les, program ¬les, and the base ¬le, the Com-
puter Modern routines also include a number of utility ¬les that provide a convenient
environment for designing new characters and improving old ones. We™ll conclude this
appendix by studying the contents of those utility ¬les.
Let™s suppose, for example, that test proofs have revealed problems with the
characters ˜k™ and ˜S™, so we want to ¬x them. Instead of working with the font as a
whole, we can copy the programs for those two characters (and only those two) into a
temporary ¬le called ˜test.mf™. Then we can run on the ¬le ˜rtest.mf™,
which says the following:
% try all characters on ˜test.mf™ using the parameters of cmr10
if unknown cmbase: input cmbase fi
def generate suffix t = enddef;
input cmr10; font_setup;
let echar = endchar;
def endchar = echar; stop "done with char "&decimal charcode&". " enddef;
let iff = always_iff;
input test; bye
This will produce proofs of ˜k™ and ˜S™, using the cmr10 parameters. Notice the simple
trick by which rtest is able to stay in charge after inputting cmr10, without letting
the roman driver come into action: ˜generate™ is rede¬ned so that it becomes innocu-
ous. Furthermore rtest changes endchar so that will stop and display
each character before moving on to the next. The ˜iff™ convention is changed to
˜always_iff™, so that every test character will be tested even if the boolean expression
is unde¬ned; this makes it easier to copy from program ¬les into the test ¬le and back
again, since the iff indications do not have to be touched.
If you invoke with ˜\mode=lowres; input rtest™, you™ll generate
a low-resolution font called rtest with the parameters of cmr10, but containing only
the characters in the test ¬le. If you leave out the mode, you get proof mode as usual.
312 Appendix E: Examples

There are similar pseudo-drivers ttest.mf (for cmtt10 instead of cmr10), pseudo-driver ¬le
btest.mf (for cmbx10), etc.; these make it possible to try the test characters with many
di¬erent parameter settings. There™s also ztest.mf, which inputs parameters from a
temporary ¬le ˜z.mf™ that contains special parameters of interest at the moment. (If
¬le z.mf does not exist, you™ll get a chance to specify another parameter ¬le, online.)
A more elaborate pseudo-driver ¬le called ˜6test.mf™ allows you to test up to
six parameter settings simultaneously, and to see the results all at once on your screen,
as illustrated in Chapter 23. Here is the program that does the necessary magic:

% try all characters on ˜test.mf™ using six different sets of parameters
if unknown cmbase: input cmbase fi
mag=.5; % the user can override this equation
mode_setup; let mode_setup=\;
boolean running;
def abort = hide(scrollmode; running := false) enddef;
def pause = stop "done with char "&decimal charcode&". " enddef;
let iff = always_iff;
def ligtable text t=enddef;
def charlist text t=enddef;
def extensible text t=enddef;
string currenttitle;
let semi = ;; let echar = endchar; let endchar = enddef;
def cmchar expr s = currenttitle := s;
let ; = testchar semi quote def chartext = enddef;
def testchar = semi let ; = semi;
running := true; errorstopmode;
for k=1 upto 6:
if running: if known params[k]: scantokens params[k]; font_setup;
currenttitle & ", " & fontname[k];
chartext echar; fi fi endfor
pause; enddef;
string params[],fontname[];
params[1] = "roman_params"; fontname[1] = "cmr10";
params[2] = "sans_params"; fontname[2] = "cmssbx10";
params[3] = "ital_params"; fontname[3] = "cmti10";
params[4] = "tt_params"; fontname[4] = "cmtt10";
params[5] = "bold_params"; fontname[5] = "cmb10";
params[6] = "quote_params"; fontname[6] = "cmssqi8";
w_rows = floor 1/2 screen_rows; w_cols = floor 1/3 screen_cols;
def open(expr k,i,j)=
openwindow k from ((i-1)*w_rows,(j-1)*w_cols) to (i*w_rows,j*w_cols)
at (-10,140) enddef;
def openit =
open(1,1,1); open(2,1,2); open(3,1,3);
open(4,2,1); open(5,2,2); open(6,2,3); enddef;
Appendix E: Examples 313

begingroup delimiters begintext generate; errorstopmode
def makedef(expr s)(text t) =
expandafter def scantokens s = t enddef; flushtext enddef; openwindow
def flushtext suffix t = enddef;
for k=1 upto 6: if known params[k]: expandafter
makedef(params[k]) scantokens
expandafter expandafter expandafter begintext
scantokens ("input "&fontname[k]); fi endfor abort
endgroup; inconsistent
input test; bye LA ROCHEFOUCALD

Parameters are moved from parameter ¬les into macros, using a trick discussed near
the beginning of Appendix D. Then cmchar is rede¬ned so that the entire text of
each character-to-be-tested will be embedded in another macro called chartext . Each
instance of chartext is repeatedly applied to each of the six font setups.
An error that occurs with the ¬rst or second set of parameters may be so bad
that you won™t want to see what happens with the third, fourth, ¬fth, and sixth sets.
For example, when test.mf contains characters that are being newly designed, some
equations might have been omitted or mistyped, so the results will be ludicrous. In
this case you can interrupt the program and type ˜I abort™. The 6test routine has an
abort macro that will stop at the end of the current font setup and move directly to
the next character, without trying any of the remaining parameter combinations.
It™s possible to include material in test.mf that isn™t part of a character
program. For example, you might want to rede¬ne a subroutine in the base ¬le. Only
the character programs themselves (i.e., the sequences of tokens between ˜cmchar™ and
˜endchar;™) are subject to six-fold repetition.
Some large characters may not appear in full, because there might not be
room for them on the screen at the stated magni¬cation. You can make everything
smaller by running with, say, ˜\mag=1/3; input 6test™. The computer
will stop with an error message, saying that the equation ˜mag=.5™ is inconsistent; but
you can safely proceed, because you will have the magni¬cation you want.

An ensampull yn doyng ys more commendabull
ys techyng o­er prechyng.
” JOHN MIRK, The Festyuall (c. 1400)

Old people love to give good advice,
to console themselves for no longer being able to give bad examples.
” LA ROCHEFOUCALD, Maximes (1665)
(page 314)

Font Metric
Appendix F: Font Metric Information 315

The TEX typesetting system assumes that some “intelligence” has been built TeX
into the fonts it uses. In other words, information stored with TEX™s fonts will fontmaking
have important e¬ects on TEX™s behavior. This has two consequences: (a) Type- sharp
setting is quite ¬‚exible, since few conventions are frozen into TEX itself. (b) Font box
designers must work a little harder, since they have to tell TEX what to do. The xo¬set
purpose of this appendix is to explain how you, as a font designer, can cope accents
with (b) in order to achieve spectacular successes with (a). charwd
The information used by TEX is embedded in compact binary ¬les called chardp
TEX Font Metric (tfm) ¬les. Although the ˜t™ in ˜tfm™ stands for TEX, this is charic
italic correction
an artifact of history, because other formatting systems can work with tfm ¬les
too. The ¬les should have been called just ˜fm™, but it™s too late now.
is able to produce two di¬erent kinds of binary output ¬les.
One, a ˜gf™ ¬le, contains digitized character shapes and some additional infor-
mation needed by programs that drive printing devices; such ¬les are discussed
in Appendix G. The other type of output is a tfm ¬le, which contains font infor-
mation used by formatting routines like TEX; such ¬les are our present concern.
You get a tfm ¬le if and only if ™s internal quantity ˜fontmaking ™
is positive at the end of your job. (Plain ™s mode setup routine
usually sets fontmaking to an appropriate value automatically.)
The tfm ¬le contains some information about each character, some information
about combinations of characters, and some information about the font as a whole. We
shall consider these three kinds of information in turn. All of the font metric data that
refers to physical dimensions should be expressed in device-independent, “sharp” units;
when a particular font is produced with di¬erent modes or magni¬cations, all its tfm
¬les should be identical.
A formatting program like TEX needs to know the size of each character™s
“bounding box.” For example, when TEX typesets a word like ˜box™, it places the ¬rst
letter ˜b™ into a little box in such a way that the pixel whose lower left
corner is at (0, 0) will appear on the baseline of the current line being typeset, at the
left edge of the box. (We assume for simplicity that xo¬set and yo¬set were zero when
˜b™ was shipped out). The second letter, ˜o™, is placed in a second little box adjacent
to the ¬rst one, so we obviously must tell TEX how wide to make the ˜b™.
In fact, TEX also wants to know the height and depth of each letter. This
˜ o˜˜
a¬ects the placing of accents, if you wish to typeset ˜b ˜xy™, and it also avoids overlap
. ...
when adjacent lines contain boxes that go unusually far above or below the baselines.
A total of four dimensions is given for each character, in sharp units (i.e., in
units of printer™s points):
charwd , the width of the bounding box.
charht , the height (above the baseline) of the bounding box.
chardp , the depth (below the baseline) of the bounding box. This is a pos-
itive number if the character descends below the baseline, even though the
corresponding y values are negative.
charic , the character™s “italic correction.” TEX adds this amount to the width
of the box (at the right-hand side) in two cases: (a) When the user speci¬es
an italic correction explicitly, by typing \/ immediately after the character.
316 Appendix F: Font Metric Information

(b) When an isolated character is used in math mode, unless it has a subscript isolated
but no superscript. For example, the italic correction is applied to ˜P ™ in the
formulas ˜P (x)™ and ˜P 2 ™, but not in the formula ˜Pn ™; it is applied to position shipout
the superscript but not the subscript in ˜Pn ™. charexists
programs, you specify charwd , charht , and chardp in a beginchar
In plain some char values
command, and you specify charic (if it™s positive) in an italcorr command. But
ligtable programs
beginchar and italcorr are macros, not primitives of . What really hap- ligtable
records the value of its internal quantities charwd , charht ,
pens is that
chardp , and charic at the time of a shipout command. These values (and all other
dimensions to be mentioned below) must be less than 2048pt # in absolute value.
A font contains at most 256 character codes; the charexists operator can be
used to tell which codes have already appeared. If two or more characters are shipped
out with the same code number (possibly with di¬erent charext values), the charwd ,
charht , chardp , and charic of the ¬nal one are assumed to apply to them all.
At most 15 di¬erent nonzero heights, 15 di¬erent nonzero depths, and 63
di¬erent nonzero italic corrections may appear in a single font. If these limits are
exceeded, will change one or more values, by as little as possible, until
the restriction holds. A warning message is issued if such changes are necessary; for
example, ˜(some charht values had to be adjusted by as much as 0.12pt)™ means
that you had too many di¬erent nonzero heights, but found a way to
reduce the number to at most 15 by changing some of them; none of them had to be
changed by more than 0.12 points. No warning is actually given unless the maximum
amount of perturbation exceeds 16 pt.
The next kind of information that TEX wants is concerned with pairs of adja-
cent characters that are typeset from the same font. For example, TEX moves the ˜x™
slightly closer to the ˜o™ in the word ˜box™, and it moves the ˜o™ slightly away from
the ˜b™, because of information stored in the tfm ¬le for the font you™re now reading.
This space adjustment is called kerning. Otherwise (if the three characters had simply
been placed next to each other according to their charwd values) the word would have
been ˜box™, which looks slightly worse. Similarly, there™s a di¬erence between ˜di¬er-
ence™ and ˜difference™, because the tfm ¬le tells TEX to substitute the ligature ˜¬™ when
there are two f™s in a row.
Ligature information and kerning information is speci¬ed in short “ligtable
programs” of a particularly simple form. Here™s an example that illustrates most of
the features (although it is not a serious example of typographic practice):
ligtable "f": "f" =: oct"013", "i" |=: oct"020", skipto 1;
ligtable "o": "b": "p": "e" kern .5u#, "o" kern .5u#, "x" kern-.5u#,
1:: "!" kern u#;
This sequence of instructions can be paraphrased as follows:
Dear TEX, when you™re typesetting an ˜f™ with this font, and when the following
character also belongs to this font, look at it closely because you might need
to do something special: If that following character is another ˜f™, replace the
two f™s by character code oct"013" [namely ˜¬™]; if it™s an ˜i™, retain the ˜f™
but replace the ˜i™ by character code oct"020" [a dotless ˜±™]; otherwise skip
down to label ˜1::™ for further instructions. When you™re typesetting an ˜o™
or ˜b™ or ˜p™, if the next input to TEX is ˜e™ or ˜o™, add a half unit of space
Appendix F: Font Metric Information 317

between the letters; if it™s an ˜x™, subtract a half unit; if it™s an exclamation boundarychar
ligtable command
point, add a full unit. The last instruction applies also to exclamation points
following ˜f™ (because of the label ˜1::™). ligtable program
When a character code appears in front of a colon, the colon “labels” the starting optional skip
place for that character™s ligature and kerning program, which continues to the end of ,
the ligtable statement. A double colon denotes a “local label”; a skipto instruction
ligtable step
advances to the next matching local label, which must appear before 128 ligtable steps kern
intervene. The special label ||: can be used to initiate ligtable instructions for an ligature op
invisible “left boundary character” that is implicitly present just before every word; an
invisible “right boundary character” equal to boundarychar is also implicitly present ”=:¿
just after every word, if boundarychar lies between 0 and 255. =:”
The general syntax for ligtable programs is pretty easy to guess from these ”=:”
examples, but we ought to exhibit it for completeness: ”=:”¿
ligtable command ’’ ligtable ligtable program optional skip label
ligtable program ’’ ligtable step | ligtable program , ligtable step ::
optional skip ’’ , skipto code | empty ””:
ligtable step ’’ code ligature op code code
| code kern numeric expression charlist
| label ligtable step cmex10
ligature op ’’ =: | |=: | |=:> | =:| | =:|> | |=:| | |=:|> | |=:|>>
label ’’ code : | code :: | ||:
code ’’ numeric expression | string expression
A code should have a numeric value between 0 and 255, inclusive, after having been
rounded to the nearest integer; or it should be a string of length 1, in which case it
denotes the corresponding ASCII code (Appendix C). For example, "A" and 64.61
both specify the code value 65. Vertical bars to the left or right of ˜=:™ tell TEX to
retain the original left and/or right character that invoked a ligature. Additional ˜>™
signs tell TEX to advance its focus of attention instead of doing any further ligtable
operations at the current character position.
Caution: Novices often go overboard on kerning. Things usually work out
best if you kern by at most half of what looks right to you at ¬rst, since kerning should
not be noticeable by its presence (only by its absence). Kerning that looks right in a
logo or in a headline display often interrupts the rhythm of reading when it appears in
ordinary textual material.
You can improve TEX™s e¬ciency by ordering the steps of a ligtable program
so that the most frequent alternatives come ¬rst. TEX will stop reading the program
when it ¬nds the ¬rst “hit.”
Several characters of a font can be linked together in a series by means of a
charlist command. For example,
charlist oct"000": oct"020": oct"022": oct"040": oct"060"
is used in the font cmex10 to specify the left parentheses that TEX uses in displayed
math formulas, in increasing order of size. TEX follows charlists to make variable-size
delimiters and variable-width accents, as well as to link text-size operators like ˜ ™ to
the display-size ˜ ™.
318 Appendix F: Font Metric Information

TEX builds up large delimiters by using “extensible” characters, which are extensible
speci¬ed by giving top, middle, bottom, and repeatable characters in an extensible
command. For example, the extensible left parentheses in cmex10 are de¬ned by charlist command
extensible oct"060": oct"060", 0, oct"100", oct"102"; labeled code
extensible command
this says that character code oct"060" speci¬es an extensible delimiter constructed
four codes
from itself as the top piece, from character number oct"100" as the bottom piece, and ,
from character number oct"102" as the piece that should be repeated as often as nec- ,
essary to reach a desired size. In this particular example there is no middle piece, but
headerbyte command
characters like curly braces have a middle piece as well. A zero value in the top, middle, headerbyte
or bottom position means that no character should be used in that part of the con- :
fontdimen command
struction; but a zero value in the ¬nal position means that character number zero is the fontdimen
repeater. The width of an extensible character is taken to be the width of the repeater. :
byte list
The ¬rst eight di¬erent sizes of parentheses available to TEX in cmex10, when
the user asks for ˜\left(™, look like this: numeric list
«« ,
¬ ¬¬


According to what we know from the examples of charlist and extensible above, the
¬rst four of these are the characters in positions oct"000", oct"020", oct"022", and
oct"040". The other four have character oct"060" on top; character oct"100" is at the
bottom; and there are respectively zero, one, two, and three occurrences of character
oct"102" in the middle.
Here is the formal syntax:
charlist command ’’ charlist labeled code
labeled code ’’ code
| label labeled code
extensible command ’’ extensible label four codes
four codes ’’ code , code , code , code
Notice that a label can appear in a ligtable, charlist, or extensible command. These
appearances are mutually exclusive: No code may be used more than once as a la-
bel. Thus, for example, a character with a ligature/kerning program cannot also be
extensible, nor can it be in a charlist (except as the ¬nal item).
The last type of information that appears in a tfm ¬le applies to the font as a
whole. Two kinds of data are involved, bytes and numerics; and they are speci¬ed in
“headerbyte” and “fontdimen” commands, according to the following general syntax:
headerbyte command ’’ headerbyte numeric expression : byte list
fontdimen command ’’ fontdimen numeric expression : numeric list
byte list ’’ code
| byte list , code
numeric list ’’ numeric expression
| numeric list , numeric expression
Appendix F: Font Metric Information 319

We shall defer discussion of header bytes until later, because they are usually unneces- font slant
sary. But fontdimen commands are important. Numeric parameters of a font can be
font normal space
speci¬ed by saying, e.g., isolated
italic correction
fontdimen 3: 2.5, 6.5, 0, 4x font normal stretch
font normal shrink
which means that parameters 3“6 are to be 2.5, 6.5, 0, and 4x, respectively. These are
the parameters that TEX calls \fontdimen3 thru \fontdimen6. (Parameter numbering font x height
is old-fashioned: There is no \fontdimen0.) x-height
font quad
The ¬rst seven fontdimen parameters have special signi¬cance, so plain - font extra space
has seven macros to specify them symbolically, one at a time: design size
at size
font slant (\fontdimen1) is the amount of slant per point; TEX uses this
information when raising or lowering an accent character.
font normal space (\fontdimen2) is the interword spacing. If the value is
zero, all characters of this font will be considered to be “isolated” in math
mode, so the italic correction will be added more often than otherwise.
font normal stretch (\fontdimen3) is the stretchability of interword spac-
ing, as explained in The TEXbook.
font normal shrink (\fontdimen4) is the shrinkability of interword spacing,
as explained in The TEXbook.
font x height (\fontdimen5) is the height of characters for which accents
are correctly positioned. An accent over a character will be raised by the
di¬erence between the character™s charht and this value. The x-height is also
the unit of height that TEX calls one ˜ex™.
font quad (\fontdimen6) is the unit of width that TEX calls one ˜em™.
font extra space (\fontdimen7) is the additional amount added to the nor-
mal interword space between sentences, depending on the “spacefactor” as
de¬ned in The TEXbook.
Parameters are zero unless otherwise speci¬ed.
Math symbol fonts for TEX are required to have at least 22 fontdimen param-
eters, instead of the usual seven; math extension fonts need at least 13. Appendix G of
The TEXbook explains the precise signi¬cance of these additional parameters, which
control such things as the placement of superscripts and subscripts.

The design size of a font is not one of the fontdimen parameters; it™s an internal
quantity of that is actually output among the header bytes as explained
below. When a TEX user asks for a font ˜at™ a certain size, the font is scaled by the ratio
between the “at size” and the design size. For example, cmr10 has a design size of 10 pt;
if a TEX user requests ˜cmr10 at 15pt™, the result is the same as ˜cmr10 scaled 1500™
(or, in plain terms, cmr10 with mag=1.5).
What does the design size really mean? It™s an imprecise notion, because there
need be no connection between the design size and any speci¬c measurement in a font.
Typographers have always been vague when they speak about “10 point” fonts, because
some fonts look larger than others even though the horizontal and vertical dimensions
are the same. It™s something like dress sizes or shoe sizes.
In general, the design size is a statement about the approximate size of the
type. Type with a larger design size generally looks bigger than type with a smaller
design size. Two fonts with the same design size are supposed to work well together;
320 Appendix F: Font Metric Information

for example, cmr9 and cmtt9 both have 9 pt design size, although the uppercase letters designsize
of cmtt9 are quite a bit smaller (˜A™ versus ˜A™).
check sum
The designsize must be at least 1pt #. And, as with all tfm dimensions, it Ramshaw
must be less than 2048pt #. Any other value is changed to 128pt #. Xerox
font coding scheme
looks at the value of designsize only when the job ends, so you font identi¬er
needn™t set it before characters are shipped out. At the end of a job, when the tfm ¬le substring
BCPL strings
is being written, checks to make sure that every dimension of the font is
less than 16 times the design size in absolute value, because this limitation is imposed
by the tfm ¬le format. Thus, for example, if the design size is 10 pt, you cannot have
a character whose width or height is 160 pt or more. If one or more dimensions prove
to be too big, will tell you how many of them had to be changed.
The headerbyte command is similar to fontdimen, but it gives 8-bit code
data instead of numeric information. For example,
headerbyte 33: 0, 214, 0, "c"
says that bytes 33“36 of the tfm ¬le header will be 0, 214, 0, and 99. The ¬rst four
header bytes (numbers 1“4) are automatically set to a check sum, unless you have
speci¬ed other values for at least one of those bytes. (This check sum will match a
similar value in the gf ¬le, so that other typesetting software can check the consistency
of the di¬erent ¬les they use.) Similarly, the next four header bytes (numbers 5“8) are
set automatically to the design size times 220 , unless you have speci¬ed something else.
TEX looks only at the ¬rst eight header bytes, so you needn™t use the header-
byte command if you are simply producing a font for standard TEX. But other soft-
ware that reads tfm ¬les may have a need for more header information. For example,
the original tfm format (developed by Lyle Ramshaw at Xerox Palo Alto Research
Center) included font coding scheme information in bytes 9“48 of the header, and
font identi¬er information in bytes 49“68. The design size of certain fonts was also
packed into byte 72. Each font in the “Xerox world” is uniquely identi¬ed by its font
identi¬er and its design size, rather than by its font ¬le name.
The “font coding scheme” is merely a comment that can be used to help
understand large collections of fonts; it™s usually a nice thing to know. Some of the
coding scheme names in common use are
TeX text TeX math italic
TeX typewriter text TeX math symbols
XEROX text TeX math extension
ASCII TeX extended ASCII
The coding-scheme string should not include parentheses.
Here are macros that can be used, if desired, to convert plain ™s
font identi¬er and font coding scheme into the format required by Ramshaw™s
original tfm ¬les:
def BCPL_string(expr s,n) = % string s becomes an n-byte BCPL string
for l:=if length(s)>=n: n-1 else: length(s) fi: l
for k:=1 upto l: , substring (k-1,k) of s endfor
for k:=l+2 upto n: , 0 endfor endfor enddef;
Appendix F: Font Metric Information 321

inner end; outer
def bye = if fontmaking>0:
headerbyte 9: BCPL_string(font_coding_scheme_,40); end
font metric command
special "codingscheme " & font_coding_scheme_;
headerbyte 49: BCPL_string(font_identifier_,20); WILDE
special "identifier " & font_identifier_;
headerbyte 72: max(0, 254 - round 2designsize); fi
end enddef;
outer bye,end;
These macros could be included among the local.mf extensions to plain.mf at partic-
ular installations. When a user says ˜bye™ instead of ˜end™, the additional headerbyte
documentation will then be automatically inserted into the tfm ¬le.
Let us now conclude this appendix by summarizing what we™ve learned. A
programmer can provide various types of information about how to typeset
with a font, by using font metric commands. Simple versions of these commands,
su¬cient for simple fonts, are standard operations in plain ; examples have
appeared in Chapter 11 and the beginning of Appendix E. The general cases are
handled by ¬ve types of font metric commands:
font metric command ’’ ligtable command
| charlist command
| extensible command
| fontdimen command
| headerbyte command
This completes the syntax of that was left slightly un¬nished in Chapter 26.

Such things induced me to untangle the chaos
by introducing order where it had never been before:
I think I may say I have had the good fortune to succeed
with an exactness & a precision leaving nothing more to be desired,
by the invention of Typographic points.
” PIERRE FOURNIER, Manuel Typographique (1764)

One should absorb the color of life,
but one should never remember its details.
Details are always vulgar.
” OSCAR WILDE, The Picture of Dorian Gray (1890)
(page 322)

Appendix G: Generic Font Files 323

™s main output goes into a gf or “Generic Font” ¬le, so-called because gf
device driver
it can easily be translated into any other digital font format, although it does dvi
not match the speci¬cations of any “name brand” manufacturer. The purpose day
of this appendix is to explain exactly what kinds of information go into the gf year
¬le, and under what circumstances puts things there. time
Special commands
A gf ¬le is a compact binary representation of a digitized font, containing all
the information needed by “device driver” software that produces printed documents proo¬ng
from TEX™s dvi ¬les. The exact internal representation scheme of gf ¬les doesn™t proofrule
concern us here, but we ought to know what type of data is encoded.
The ¬rst thing in a gf ¬le is a string that explains its origin.
writes strings of the form

METAFONT output 1986.06.24:1635

based on the values of the internal quantities day , month , year , and time when the
gf ¬le was started. (In this case day = 24, month = 6, year = 1986, and time =
16 — 60 + 35 = 995.)
After the opening string, the gf ¬le contains a sequence of “special” commands
interspersed with shipped-out character images. Special commands are intended to
provide a loophole for future extensions to ™s set of primitives, so that
itself will not have to change. Some specials are prede¬ned, but others
will undoubtedly be created in years to come. (TEX has an analogous \special
command, which puts an arbitrary string into a dvi ¬le.)
A special command gets into the gf ¬le when you say ˜special string ™ or
˜numspecial numeric ™ at a time when proo¬ng ≥ 0. A special string should come
before numspecial, and it should either be a keyword all by itself or it should consist
of a keyword followed by a space followed by additional information. Keywords that
specify operations requiring numeric arguments should be followed by numbers pro-
duced by numspecial. For example, the ˜proofrule™ macro in Appendix B expands
into a sequence of ¬ve special commands,

special "rule";
numspecial x1 ; numspecial y1 ;
numspecial x2 ; numspecial y2 ;

this represents a rule on the proofsheet that runs from point (x1 , y1 ) to point (x2 , y2 ).
If you say ˜grayfont gray5™, the grayfont macro in Appendix B expands to ˜special
"grayfont gray5"™. Software that reads gf ¬les will examine all of the special strings,
until coming to a space or to the end of the string. If the resulting keyword isn™t
known to the program, the special string will be ignored, together with all numspecials
that immediately follow. But when the keyword is known, the program will be able to
determine the corresponding arguments. For example, the GFtoDVI program described
in Appendix H knows about the plain keywords ˜rule™ and ˜grayfont™.
might also create special commands on its own initiative, but
only when proo¬ng is strictly greater than zero. There are two cases: (1) When a
title statement occurs, the special string ˜"title " & title ™ is output. (This is how
the phrase ˜The letter O™ got onto your proofsheets in the experiments of Chapter 5.)
(2) Just before a character image is shipped out, implicitly executes the
324 Appendix G: Generic Font Files

following sequence of instructions: xo¬set
if round xo¬set = 0: special "xoffset"; numspecial round xo¬set ; ¬ shipout
if round yo¬set = 0: special "yoffset"; numspecial round yo¬set ; ¬
A shipout command sends a digitized picture to the gf ¬le, if proo¬ng ≥ 0, chardp
but nothing is output if proo¬ng < 0. Furthermore the current values of charwd , chardx
charht , chardp , charic , chardx , and chardy are stored away for the current charcode ; chardy
these values are stored in all cases, regardless of the value of proo¬ng . The current charexists
character code is henceforth said to “exist.” picture
When a picture is shipped out, its pixels of positive value are considered to be
“black,” and all other pixels are considered to be “white.” The pattern of blacks and oriental
whites is encoded in such a way that doubling the resolution approximately doubles bye
the length of the gf output, in most cases.
reports its progress by typing ˜[c]™ on the terminal when character hppp
code c is being shipped out. (The ˜[™ is typed before output conversion begins, and ¬le name
design size
the ˜]™ is typed after; hence you can see how much time output takes.) If charext is check sum
nonzero, after being rounded to an integer, the typed message is ˜[c.x]™ instead; for charwd
example, ˜[65.3]™ refers to character 65 with extension code 3.
TEX allows only 256 characters per font, but extensions of TEX intended for
oriental languages will presumably use the charext feature. All characters with the
same code share the same width, height, and depth, but they can correspond to distinct
graphics if they have di¬erent extension codes.
A special command generally refers to the picture that follows it, rather than
the picture that precedes it. Special commands before the ¬rst digitized picture might,
however, give instructions about the font as a whole. Special commands that follow
the ¬nal picture invariably refer to the font as a whole. (For example, the ˜bye™ macro
at the end of Appendix F creates two special strings that will appear after the ¬nal
character of a font.)
No gf ¬le will be written unless a character is shipped out or a special com-
mand is performed at a time when proo¬ng ≥ 0, or unless a title statement is encoun-
tered at a time when proo¬ng > 0. When one of these things ¬rst happens, the gf
¬le receives its name. If no input commands have yet occurred, will set
the job name to ˜mfput™; otherwise the job name will already have been determined.
The full name of the gf ¬le will be ˜ jobname . resolution gf™, where the resolution
is based on the current value of hppp . (If hppp ¤ 0, the resolution will be omitted;
otherwise it will be converted to an equivalent number of pixels per inch, in the hori-
zontal dimension.) Subsequent input operations or changes to hppp will not change
the name of the gf ¬le.
The end of a gf ¬le contains a bunch of numeric data needed for typesetting.
First come the design size and the check sum; these match precisely the data in the
tfm ¬le, unless the header bytes of the tfm have explicitly been set to something else.
Then come the values of hppp and vppp . (These are the values at the end of the job,
so hppp might not agree with the resolution value in the gf ¬le name.)
Finally, the gf ¬le gets the charwd , chardx , and chardy of each existing char-
acter code. The values of chardx and chardy represent desired “escapements” when
characters are typeset on a particular device (cf. Chapter 12). The charwd values are
identical to the widths in the tfm ¬le.
Appendix G: Generic Font Files 325

The check sum is based entirely on the charwd data; two fonts with the same device driver
character widths will have the same check sum, but two fonts with di¬erent character
widths will almost never have the same check sum.
The purpose of check sums can be understood by considering the following
scenario: A font named cmr10 might be generated by at any time, pro-
ducing a tfm ¬le called cmr10.tfm and a gf ¬le called, say, cmr10.300gf. A document
named doc, which uses cmr10, might be generated by TEX at any time, producing a
dvi ¬le called doc.dvi; TEX had to read cmr10.tfm in order to produce this dvi ¬le.
Now on some future date, a “device driver” program will be used to print doc.dvi,
using the font cmr10.300gf. Meanwhile, the font may have changed. If the current
gf ¬le doesn™t match the tfm ¬le that was assumed by TEX, mysterious glitches will
probably occur in the printed document, because dvi information is kept concise by
the assumption that the device driver knows the tfm widths of all characters. Potential
problems are kept to a minimum if TEX puts the assumed design size and check sum
of each font into the dvi ¬les it produces; a device driver can then issue a warning
message when it ¬nds a gf ¬le that is inconsistent with TEX™s assumptions.

But if our Letter-Cutter will have no Forge,
yet he must of necessity accommodate
himself with a Vice, Hand-Vice, Hammers,
Files, Small and Fine Files (commonly called Watch-makers Files)
of these he saves all, as they wear out.
” JOSEPH MOXON, Mechanick Exercises (1683)

The natural de¬nition lists all possible generic characters.
” LINNÆUS, Philosophia Botanica (1751)
(page 326)

Hardcopy Proofs
Appendix H: Hardcopy Proofs 327

A font cannot be proved correct like a mathematical theorem; a font must be GFtoDVI
seen to be believed. Moreover, if some characters of a font are faulty, the best proof
way to ¬x them is to look at diagrams that indicate what went wrong. Therefore smoke
is incomplete by itself; additional programs are needed to convert low resolution proofs
the output of into graphic form. special
gray font
The purpose of this appendix is to discuss two such auxiliary programs, labels
which serve as examples of many others that could be devised. The ¬rst of proo¬ng
these, called GFtoDVI, takes gf ¬les and converts them into dvi ¬les, which can
be printed just like the output of TEX. Each character image in the gf ¬le will
have a printed page to itself, with labeled points and with bounding boxes just as
in the illustrations we have seen throughout this book. (Indeed, the illustrations
in this book were produced by GFtoDVI.) The second auxiliary program to be
discussed below is TEX itself; we shall look at a set of TEX macros designed to
facilitate font testing.
1. Large scale proofs. The gf ¬les produced by plain when it is in proof
mode or smoke mode can be converted to annotated diagrams by running them through
GFtoDVI, as we know from the experiments in Chapter 5. It™s also possible to study
low-resolution characters with GFtoDVI, especially if plain ™s ˜gfcorners™
feature has been used. We shall now take a thorough look at what GFtoDVI can do.
All communication from to GFtoDVI comes through the gf ¬le
and from options that you might type when you run GFtoDVI. If there are no “special”
commands in the gf ¬le (cf. Appendix G), each page of GFtoDVI™s output will show just
the “black” pixels of a character; furthermore there will be a title line at the top of the
page, showing the date and time of the run, together with the character
code number and extension code (if they are nonzero). The black pixels are typeset via
characters of a so-called “gray font,” described in detail below; by changing the gray
font you can produce a variety of di¬erent outputs from a single gf ¬le.
To get other things on your proof sheets, “special” commands must appear in
the gf ¬le. For example, will automatically output a title command, if
proo¬ng > 0, as explained in Appendix G; GFtoDVI will typeset this title on the title
line of the next character image that follows the command. If there are several title
statements, they all will appear; they are supposed to ¬t on a single line.
The most important special commands tell GFtoDVI to create labeled points
on the character diagram. When you say, for example, ˜labels(1, 2)™ in a plain -
program, at a time when proo¬ng > 1, the macros of Appendix B will convert
this to the special commands
special " 01"; numspecial x1 ; numspecial y1 ;
special " 02"; numspecial x2 ; numspecial y2 ;
GFtoDVI will then put a dot labeled ˜1™ at point (x1 , y1 ) and a dot labeled ˜2™ at (x2 , y2 ).
Labels are placed in one of four positions relative to their dots”either at the
top, the left, the right, or the bottom. GFtoDVI will ordinarily try to place all labels
so that they don™t interfere with each other, and so that they stay clear of other dots.
But if you want to exercise ¬ne control over the placement yourself, you can say, for
example, ˜labels.top (1a, 2a)™; in this case the speci¬ed labels will appear above their
dots, regardless of whether or not other labels and/or dots are thereby overprinted.
328 Appendix H: Hardcopy Proofs

The gf ¬le in this case will contain labels.top
special " 11a"; numspecial x1a ; numspecial y1a ;
special " 12a"; numspecial x2a ; numspecial y2a . over¬‚ow equation
GFtoDVI looks at the character following a leading blank space to determine what sort lcode
of labeling convention is desired; the subsequent characters are the text of the label. rule
The command ˜labels.top (1a, 2a)™ in plain is just an abbreviation dvi
for ˜makelabel.top ("1a", z1a ); makelabel.top ("2a", z2a )™, when proo¬ng > 1; the
makelabel macro is really the fundamental one, and you should use it directly if you
want more unusual e¬ects. Suppose, for example, you just want to put a dot but no
label at point z5 ; then you can say ˜makelabel("", z5 )™. And suppose you want to put a
label to the left of point z5 but with no dot; you can say ˜makelabel.lft .nodot ("5", z5 )™.
Furthermore you could say ˜makelabel.lft .nodot ("5", z5 ’ (2, 3))™ to move that label
left by 2 pixels and down by 3 pixels, thereby getting the e¬ect of a label that is
diagonally adjacent to its dot. Labels without dots can also be used to put words on a
GFtoDVI recognizes nine varieties of labels in all, based on the ¬rst two char-
acters of the special string command:
makelabel (special " 0"): choose the label position automatically.
makelabel.top (special " 1"): center the label just above the dot.
makelabel.lft (special " 2"): place the label just left of the dot.
makelabel.rt (special " 3"): place the label just right of the dot.
makelabel.bot (special " 4"): center the label just below the dot.
makelabel.top .nodot (special " 5"): like top , but omit the dot.
makelabel.lft .nodot (special " 6"): like lft , but omit the dot.
makelabel.rt .nodot (special " 7"): like rt , but omit the dot.
makelabel.bot .nodot (special " 8"): like bot , but omit the dot.
The ¬rst case is called autolabeling; this is the normal command. Autolabeling always
places a dot, whether or not that dot overlaps other dots, but you don™t always get a
label. Autolabels are typeset only after all explicit labels have been established; then
GFtoDVI tries to place as many of the remaining labels as possible.
If there™s no place to put an autolabel, an “over¬‚ow equation” is put in the
upper right corner of the proofsheet. For example, the over¬‚ow equation ˜5 = 5r +
(-4.9,0)™ means that there was no room for label 5, whose dot is 4.9 pixels to the left
of the dot for 5r (which is labeled).
You can avoid over¬‚ow equations by sending GFtoDVI the special command
" /" instead of " 0"; this is a variant of autolabeling that does everything as usual
except that the label will simply be forgotten if it can™t be placed. To do this with
, set ˜lcode := " /"™ near the beginning of your program; lcode is
the string that makelabel uses to specify autolabeling.
The next most important kind of annotation for proofs is a straight line or
“rule.” Plain ™s command for this is ˜proofrule(z1 , z2 )™, which expands to
special "rule"; numspecial x1 ; numspecial y1 ;
numspecial x2 ; numspecial y2 .
GFtoDVI has trouble drawing diagonal rules, because standard dvi format includes no
provision for drawing straight lines unless they are vertical or horizontal. Therefore
Appendix H: Hardcopy Proofs 329

you might get an error message unless x1 = x2 (vertical rule) or y1 = y2 (horizontal slant font
rule). However, a limited escape from this restriction is available via a “slant font,” by
which GFtoDVI is able to typeset diagonal lines as sequences of characters. Only one titlefont
slope is permitted per job, but this is better than nothing (see below). labelfont
To control the weight of proof rules, you say, e.g., ˜proofrulethickness slantfont
1.5mm #™ in a plain program; this expands to grayfontarea
special "rulethickness"; numspecial 1.5mm #. design size
Each horizontal or vertical rule is drawn as if by a pen of the current rulethickness, hence endchar
mode setup
you can get di¬erent weights of lines in a single diagram. If the current rulethickness is /
negative, no rule will appear; if it is zero, a default rulethickness based on a parameter
of the gray font will be used; if it is positive, the stated thickness will be increased if
necessary until it equals an integer number of pixels, and that value will be used to
draw the rule. At the beginning of each character the current rulethickness is zero.
You can reposition an entire diagram on its page by saying ˜proofo¬set (x, y)™;
this expands to
special "offset"; numspecial x; numspecial y
and it tells GFtoDVI to shift everything except the title line on the next character image,
x pixels to the right and y pixels upward.
GFtoDVI uses four fonts to typeset its output: (1) The title font is used for
the top line on each page. (2) The label font is used for all labels. (3) The gray
font is used for dots and for black pixels. (4) The slant font is used for diagonal rules.
Appropriate default fonts will be used at each installation unless you substitute speci¬c
fonts yourself, by using the special commands titlefont, labelfont, grayfont, or
slantfont. GFtoDVI also understands special strings like ˜"grayfontarea /usr/dek"™,
which can be used to specify a nonstandard ¬le area or directory name for the gray
font. Furthermore the gf ¬le might say, e.g.,
special "labelfontat"; numspecial 20
if you want the label font to be loaded at 20 pt instead of its design size. The area name
and the at size must be given after the font name itself; in other words, ˜"grayfont"™
cancels a previous ˜"grayfontarea"™.
The four fonts used by GFtoDVI must be established before the ¬rst character
bitmap appears in the gf ¬le. This means that the special font commands must be given
before the ¬rst shipout or endchar in your program; but they shouldn™t appear until
after mode setup, so that your gf ¬le will have the correct name. If it™s inconvenient
to specify the fonts that way, you can change them at run time when you use GFtoDVI:
Just type ˜/™ following the name of the gf ¬le that™s being input, and you will be asked
to type special strings online. For example, the run-time dialog might look like this:
This is GFtoDVI, Version 2.0
GF file name: io.2602gf/
Special font substitution: labelfont cmbx10
OK; any more? grayfont black
OK; any more?
After the ¬nal carriage return, GFtoDVI does its normal thing, ignoring font speci¬ca-
tions in the ¬le that con¬‚ict with those just given.
330 Appendix H: Hardcopy Proofs

2. Gray fonts. A proof diagram constructed by GFtoDVI can be regarded as an array Gray fonts
of rectangles, where each rectangle is either blank or ¬lled with a special symbol that
we shall call ˜ ™. A blank rectangle represents a white pixel, while represents a black
pixel. Additional labels and reference lines are often superimposed on this array of
rectangles; hence it is usually best to choose a symbol that has a somewhat gray
appearance, although any symbol can actually be used.
In order to construct such proofs, GFtoDVI needs to work with a special type
of font known as a “gray font”; it™s possible to obtain a wide variety of di¬erent sorts of
proofs by using di¬erent sorts of gray fonts. The next few paragraphs explain exactly
what gray fonts are supposed to contain, in case you want to design your own.
The simplest gray font contains only two characters, namely and another
symbol that is used for dots that identify key points. If proofs with relatively large
pixels are desired, a two-character gray font is all that™s needed. However, if the pixel
size is to be relatively small, practical considerations make a two-character font too
ine¬cient, since it requires the typesetting of tens of thousands of tiny little characters;
printing-device drivers rarely work very well when they are presented with data that is
so di¬erent from ordinary text. Therefore a gray font with small pixels usually has a
number of characters that replicate in such a way that comparatively few characters
actually need to be typeset.
Since many printing devices are not able to cope with arbitrarily large or
complex characters, it is not possible for a single gray font to work well on all machines.
In fact, must have a width that is an integer multiple of the printing device™s units
of horizontal and vertical positioning, since rounding the positions of grey characters
would otherwise produce unsightly streaks on proof output. Thus, there is no way to
make the gray font as device-independent as normal fonts of type can be.
This understood, we can now take a look at what GFtoDVI expects to see in a
gray font. The character always appears in position 1. It must have positive height h
and positive width w; its depth and italic correction are ignored.
Positions 2“120 of a gray font are reserved for special combinations of ™s and
blanks, stacked on top of each other. None of these character codes need be present in
the font; but if they are, the slots must be occupied by characters of width w that have
certain con¬gurations of ™s and blanks, prescribed for each character position. For
example, position 3 of the font should either contain no character at all, or it should
contain a character consisting of two ™s, one above the other; one of these ™s should
rest on the baseline, and the other should appear immediately below.
It will be convenient to use a horizontal notation like ˜ ™ to stand for a
vertical stack of ™s and blanks. The convention will be that the stack is built from
bottom to top, and the topmost rectangle should sit on the baseline. Thus, ˜ ™ stands
actually for a character of height h and depth 4h that looks like this:
←’ baseline

We use a horizontal notation in this discussion instead of a vertical one because column
vectors take too much space, and because the horizontal notation corresponds to binary
numbers in a convenient way.
Positions 1“63 of a gray font are reserved for the patterns , , , , , and
so on up to , just as in the normal binary notation of the numbers 1“63, with
™s substituted for 1™s and blanks for 0™s. Positions 64“70 are reserved for the special
Appendix H: Hardcopy Proofs 331

patterns , , , , , , of length seven; positions 71“78 charlist
are, similarly, reserved for the length-eight patterns through . The length-
font slant
nine patterns through are assigned to positions 79“87, the length-ten
patterns to positions 88“97, the length-eleven patterns to positions 98“108, and the
length-twelve patterns to positions 109“120.
Position 0 of a gray font is reserved for the “dot” character, which should
have positive height h and positive width w . When GFtoDVI wants to put a dot
at some place (x, y) on the ¬gure, it positions the dot character so that its reference
point is at (x, y). The dot will be considered to occupy a rectangle whose corners are
at (x ± w , y ± h ); the rectangular box for a label will butt up against the rectangle
enclosing the dot.
All other character positions of a gray font (namely, positions 121“255) are
unreserved, in the sense that they have no prede¬ned meaning. But GFtoDVI may
access them via the charlist feature of tfm ¬les, starting with any of the characters in
positions 1“120. In such a case each succeeding character in a list should be equivalent
to two of its predecessors, horizontally adjacent to each other. For example, in
charlist 53: 121: 122: 123
character 121 will stand for two 53™s, character 122 for two 121™s (i.e., four 53™s), and
character 123 for two 122™s (i.e., eight 53™s). Since position 53 contains the pattern
, character 123 in this example would have height h, depth 5h, and width 8w, and
it would stand for the pattern
←’ baseline

Such a pattern is, of course, rather unlikely to occur in a gf ¬le, but GFtoDVI would be
able to use if it were present. Designers of gray fonts should provide characters only
for patterns that they think will occur often enough to make the doubling worthwhile.
For example, the character in position 120 ( ), or whatever is the tallest stack
of ™s present in the font, is a natural candidate for repeated doubling.
Here™s how GFtoDVI decides what characters of the gray font will be used,
given a con¬guration of black and white pixels: If there are no black pixels, stop.
Otherwise look at the top row that contains at least one black pixel, and the eleven
rows that follow. For each such column, ¬nd the largest k such that 1 ¤ k ¤ 120
and the gray font contains character k and the pattern assigned to position k appears
in the given column. Typeset character k (unless no such character exists) and erase
the corresponding black pixels; use doubled characters, if they are present in the gray
font, if two or more consecutive equal characters need to be typeset. Repeat the same
process on the remaining con¬guration, until all the black pixels have been erased.
If all characters in positions 1“63 are present, this process is guaranteed to
take care of at least six rows each time; and with characters 64“120 as well, it usually
takes care of twelve, since all patterns that contain at most one “run” of ™s are present.
Some of the fontdimen parameters discussed in Appendix F are important in
gray fonts. The font slant value s, if nonzero, will cause GFtoDVI to skew its output;
in this case the character will presumably be a parallelogram with a corresponding
slant, rather than the usual rectangle. ™s coordinate (x, y) will appear in
physical position (xw + yhs, yh) on the proofsheets. (This is appropriate for proo¬ng
unslanted fonts whose pixels will become slanted by mechanical obliquing.)
332 Appendix H: Hardcopy Proofs

Parameter fontdimen 8 of a gray font speci¬es the thickness of rules that go font normal space
font quad
on the proofs. If this parameter is zero, TEX™s default rule thickness (0.4 pt) will be
font x height
used. The other parameters of a gray font are ignored by GFtoDVI, but it is conventional grayf.mf
to set font normal space and font quad to w, font x height to h. large pixels
pix picture
For best results the designer of a gray font should choose w and h so that the pix wd
user™s dvi-to-hardcopy software will not make any rounding errors. Furthermore, the pix ht
dot should be an even number 2m of pixels in diameter, and the rule thickness should
work out to an even number 2n of pixels; then the dots and rules will be centered on dotsize
the correct positions, in the common case of integer coordinates. Gray fonts are almost font identi¬er
always intended for particular output devices, even though ˜dvi™ stands for “device
independent”; we use dvi ¬les for proofs chie¬‚y because software to print
dvi ¬les is already in place.
The program for a fairly versatile gray font generator, called
˜grayf.mf™, appears on the next few pages. It should be invoked by a parameter
¬le that establishes values of several quantities:
If large pixels is of type boolean, only 15 characters will be generated; oth-
erwise there will be 123.
If pix picture is of type picture, it should be the desired pixel image ˜ ™,
and in this case pix wd and pix ht should be the width and height in pixels.
Otherwise a default gray pixel pattern will be used.
If rep is known, it should be a positive integer; the default pixel pattern will
be replicated so that the ¬nal proofs will be rep times bigger than usual, and
the pattern will be clipped slightly at the edges so that discrete pixels can be
seen plainly.
If lightweight is of type boolean, the default pixel pattern will be only half
as dark as usual.
If dotsize is known, it should be the diameter of the special dot character, in
pixel units.
The font identi¬er should be speci¬ed.
(The rep and lightweight options are ignored if pix picture is explicitly given.) Since
gray fonts are inherently device-dependent, we do not start with “sharp” dimensions
as in normal fonts; we go backwards and compute the sharp units from pixel units.
The name of each gray font should include the name of the device for which it
is intended. (A “favorite” proof device can also be chosen at each installation, for which
the alternate font names ˜gray™ and ˜black™ are valid; these installation-dependent fonts
are the defaults for proof mode and smoke mode.)
Here, for example, is a suitable parameter ¬le ˜graycheap.mf™, which generates
a vanilla-¬‚avored gray font for the hypothetical cheapo printer:
% Gray font for Cheapo with proofsheet resolution 50 pixels per inch
if mode<>cheapo: errmessage "This file is for cheapo only"; fi
font_identifier "GRAYCHEAP";
input grayf
(The proofsheet resolution will be 50 per inch, because cheapo has 200 pixels per
inch, and the default pix picture in grayf will be four pixels square in this case.)
If the default pixel pattern turns out to be such a dark gray that the labels and
rules are obscured, the statement ˜boolean lightweight™ should be added. A solid
Appendix H: Hardcopy Proofs 333

black font with slightly higher-resolution images can be generated by the following ¬le tfm
% Black font for Cheapo with proofsheet resolution 66.7 pixels per inch
if mode<>cheapo: errmessage "This file is for cheapo only"; fi
picture pix_picture; pix_wd := pix_ht := 3;
pix_picture := unitpixel scaled 3;
font_identifier "BLACKCHEAP";
input grayf
And here is a ¬le ˜graycheap5.mf™ that generates a gray font suitable for studying large
proofs of low-resolution characters:
% Gray font for Cheapo with proofsheet resolution 10 pixels per inch
if mode<>cheapo: errmessage "This file is for cheapo only"; fi
rep=5; boolean large_pixels;
font_identifier "GRAYCHEAP";
input grayf
Now let™s look at the program ¬le ˜grayf.mf™ itself. It begins with a simple
test to ensure that mag and rep are positive integers, if they™re known; then comes
some less obvious code that handles magni¬cation in a nonstandard way:
% More-or-less general gray font generator
% See Appendix H of The METAFONTbook for how to use it
forsuffixes m = mag,rep:
if unknown m: m := 1;
elseif (m<1) or (m<>floor m):
errmessage "Sorry, " & str m & " must be a positive integer";
m := 1; fi endfor
mg := mag; mag := 1; mode_setup;
if mg>1: hppp := hppp*mg; vppp := vppp*mg;
"if charcode>0:currentpicture:=currentpicture scaled mg;fi"
& extra_endchar; fi;
This circumlocution is the easiest way to guarantee that the tfm ¬le will be completely
una¬ected by magni¬cation.
The next part of grayf computes the pixel representation, pix picture .
if picture pix_picture: rep := 1;
cull pix_picture keeping (1,infinity);
else: for z=(0,2),(1,0),(2,3),(3,1):
fill unitsquare shifted z; endfor
if not boolean lightweight:
addto currentpicture also
currentpicture rotated 90 xscaled -1; fi
if unknown scale: scale := max(1,round(pixels_per_inch/300)); fi
pix_wd := pix_ht := 4scale;
334 Appendix H: Hardcopy Proofs

if rep>1: picture pix; charlist
currentpicture := currentpicture shifted-(1,1); pix := currentpicture;
for r=1 upto rep-1: addto currentpicture also pix shifted(4r,0); endfor charht
cullit; pix := currentpicture;
for r=1 upto rep-1: addto currentpicture also pix shifted(0,4r); endfor
unfill unitsquare xscaled 4rep yscaled 2 shifted-(1,1);
unfill unitsquare yscaled 4rep xscaled 2 shifted-(1,1); cullit; fi
picture pix_picture; pix_picture := currentpicture scaled scale;
pix_wd := pix_ht := 4scale*rep; fi
The lightweight pattern has 4 of every 16 pixels turned on; the normal pattern has
twice as many.
Character 0 is the dot, which is quite simple:
def # = *72.27/pixels_per_inch enddef;
if unknown dotsize: dotsize := 2.5pix_wd/rep; fi
fill fullcircle scaled dotsize scaled mg; endchar;
The special coding scheme of gray fonts is implemented next:
numeric a[]; newinternal b,k;
def next_binary =
k := 0; forever: if k>b: a[incr b] := 0; fi
exitif a[k]=0; a[k] := 0; k := k+1; endfor
a[k] := 1 enddef;
def next_special_binary =
if a[0]=1: for k=0 upto b: a[k] := 0; endfor a[incr b]
else: k := 0; forever: exitif a[incr k]=1; endfor
a[k-1] fi := 1 enddef;
def make_char =
clearit; next_binary;
for k=0 upto b: if a[k]=1:
addto currentpicture also pix_picture shifted(0,-k*pix_ht); fi endfor
charcode := charcode+1; chardp := b*charht;
scantokens extra_endchar; shipout currentpicture enddef;
Now we are ready to generate all the pixel characters.
charwd := pix_wd#; charht := pix_ht#; chardx := pix_wd*mg;
b := -1;
if boolean large_pixels:
for k=1 upto 7: make_char; charlist k:k+120; endfor
charcode := 120; b := -1;
addto pix_picture also pix_picture shifted (chardx,0);
charwd := 2charwd; chardx := 2chardx;
for k=1 upto 7: make_char; endfor
else: for k=1 upto 63: make_char; endfor
let next_binary = next_special_binary;
for k=64 upto 120: make_char; endfor
Appendix H: Hardcopy Proofs 335

for k=121,122: charcode := k; aspect ratio
Slant fonts
addto currentpicture also currentpicture shifted (chardx,0);
charwd := 2charwd; chardx := 2chardx; tfm
scantokens extra_endchar; shipout currentpicture; endfor
font slant
charlist 120:121:122; fi
The program closes by establishing fontwide parameters:
font_coding_scheme "GFGRAY";
font_size 8(pix_wd#);
font_normal_space pix_wd#;
font_x_height pix_ht#;
font_quad pix_wd#;
fontdimen 8: if known rulethickness: rulethickness
else: pix_wd#/(2rep) fi;
(The extra complications of an aspect ratio or a slant have not been addressed.)
3. Slant fonts. GFtoDVI also makes use of another special type of font, if it is necessary
to typeset slanted rules. The format of such so-called “slant fonts” is quite a bit simpler
than the format of gray fonts.
A slant font contains exactly n characters, in positions 1 to n, for some positive
integer n. The character in position k represents a slanted line k units tall, starting at
the baseline. These lines all have a ¬xed slant ratio s. The vertical “unit” is usually
chosen to be an integral number of pixels, small enough so that it su¬ces to draw rules
that are an integer number of units high; in fact, it should probably be no larger than
the thickness of the rules being drawn.
The following simple algorithm is used to typeset a rule that is m units high:
Compute q = m/n ; then typeset q characters of approximately equal size, namely
(m mod q) copies of character number m/q and q ’ (m mod q) copies of character
number m/q . For example, if n = 15 and m = 100, we have q = 7; a 100-unit-high
rule will be composed of 7 pieces, using characters 14, 14, 14, 14, 14, 15, 15.
GFtoDVI looks at the charht of character n only, so the tfm ¬le need not be
accurate about the heights of the other characters. (This is fortunate, since tfm format
allows at most 15 di¬erent nonzero heights per font.)
The charwd of character k should be k/n times s times the charht of n.
The font slant parameter should be s. It is customary to set the parameter
fontdimen 8 to the thickness of the slanted rules, but GFtoDVI doesn™t look at it.
Here™s an example of a slant-font parameter ¬le, ˜slantcheap6™, for the cheapo
printer and a slant of 1/6:
% Slant font for Cheapo with slope 1/6
if mode<>cheapo: errmessage "This file is for cheapo only"; fi
s=1/6; % the slant ratio
n=30; % the number of characters
r#=.4pt#; % thickness of the rules
u=1; % vertical unit
font_identifier "SLANTCHEAP6";
input slant
336 Appendix H: Hardcopy Proofs

The corresponding program ¬le ˜slant.mf™ looks like this: testfont.tex

% More-or-less general slant font generator for GFtoDVI
% The calling file should set the font_identifier and
% n = number of characters
% s = slant ratio
% r# = rule thickness (in sharp units)
% u = vertical unit (in pixels)
if unknown mag: mag := 1;
elseif (mag<1) or (mag<>floor mag):
errmessage "Sorry, mag must be a positive integer"; mag := 1; fi
mg := mag; mag := 1; mode_setup; u# := u*72.27/pixels_per_inch;
pixels_per_inch := pixels_per_inch*mg; fix_units;
define_whole_pixels(u); define_blacker_pixels(r);
pickup pencircle scaled r; ruler := savepen;
for k=1 upto n:
pickup ruler; draw origin--(k*u*s,k*u); % draw the line
unfill (lft-1,bot -1)--(rt 1,bot -1)
--(rt 1,0)--(lft-1,0)--cycle; % clip the ends
unfill ((lft -1,0)--(rt 1,0)
--(rt 1,top 1)--(lft -1,top 1)--cycle) shifted (k*u*s,k*u);
endchar; endfor
font_size 16pt#;
font_slant s;
fontdimen 8: r#;
font_coding_scheme "GFSLANT";

4. Font samples. The real test of a font is its appearance at the ¬nal size, after it has
actually been typeset. The TEX typesetting system can be used with the following
example macro ¬le ˜testfont.tex™ (in addition to plain TEX format) to put a new font
through its paces.
We shall comment on typical uses of testfont as we examine its parts. At
the beginning, testfont.tex turns o¬ several of TEX™s normal features.
% A testbed for font evaluation
\tracinglostchars=0 % missing characters are OK
\tolerance=1000 % and so are loose lines
\raggedbottom % pages can be short
\nopagenumbers % and they won™t be numbered
\parindent=0pt % nor will paragraphs be indented
\hyphenpenalty=200 % hyphens are discouraged
\doublehyphendemerits=30000 % and two in a row are terrible
\newlinechar=˜@ % we want to type multiline messages
\chardef\other=12 % and redefine "catcodes"
\newcount\m \newcount\n \newcount\p \newdimen\dim % temporary variables
Appendix H: Hardcopy Proofs 337

Then there are macros to print the time and date”an extremely valuable
thing to have on any proofsheet.
January\or February\or March\or April\or May\or June\or
July\or August\or September\or October\or November\or December\fi
\space\number\day, \number\year}
\def\hours{\n=\time \divide\n 60
\m=-\n \multiply\m 60 \advance\m \time
\def\twodigits#1{\ifnum #1<10 0\fi \number#1}
An online “menu” of the available test routines will be typed at your terminal
if you request \help.
{\catcode˜\|=0 \catcode˜\\=\other % use | as the escape, temporarily
\init switches to another font;@%
\end or \bye finishes the run;@%
\table prints the font layout in tabular format;@%


. 11
( 13)