<< . .

. 38
( : 45)



. . >>

rule((r+charic*pt,h.o_-10),(r+charic*pt,h.o_)); fi % italic correction
enddef;
(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
currenttransform
mono_charic# := max(0,body_height#*slant);
granularity
let adjust_fit = mono_adjust_fit; shrink ¬t
w
else: let adjust_fit = normal_adjust_fit; fi
medium
lowres_fix(stem,curve) 1.2; low resolutions
¬lldraw
Initialize pen nibs, see below
pos
stroke
currenttransform:=identity slanted slant
penpos
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
savepen
enddef;
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:
clear_pen_memory;
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
shiftdef
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
cm.base
of ¬ne.nib when it has not been picked up. These four subroutines are created by a dump.
slightly tricky shiftdef macro: utility ¬les
test.mf
def shiftdef(suffix $)(expr delta) = rtest.mf
endchar
vardef $ primary x = x+delta enddef enddef;
stop

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
mode_setup;
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;
currentwindow:=k;
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
scrollmode
def makedef(expr s)(text t) =
quote
expandafter def scantokens s = t enddef; flushtext enddef; openwindow
openit
def flushtext suffix t = enddef;
currentwindow
for k=1 upto 6: if known params[k]: expandafter
makedef(params[k]) scantokens
cmchar
expandafter expandafter expandafter begintext
interrupt
scantokens ("input "&fontname[k]); fi endfor abort
endgroup; inconsistent
MIRK
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.




­en
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)




F
Font Metric
Information
Appendix F: Font Metric Information 315


The TEX typesetting system assumes that some “intelligence” has been built TeX
tfm
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
bounding
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
yo¬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
charht
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
beginchar
but no superscript. For example, the italic correction is applied to ˜P ™ in the
italcorr
formulas ˜P (x)™ and ˜P 2 ™, but not in the formula ˜Pn ™; it is applied to position shipout
2
the superscript but not the subscript in ˜Pn ™. charexists
charext
programs, you specify charwd , charht , and chardp in a beginchar
In plain some char values
kerning
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
1
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
ligtable
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 ,
skipto
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
ASCII
| code kern numeric expression charlist
| label ligtable step cmex10
accents
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

<< . .

. 38
( : 45)



. . >>