Ghost Fonts
Volume Number: 6
Issue Number: 1
Column Tag: TechNote
By Kurt Matthies, Dennis Ward, Macreations
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
Copyright 1989 Macreations
This paper describes the technique known as Ghost Fonts, developed at
Macreations to manage font name/number combinations in Macintosh- application
documents. We invite all other Macintosh developers to adopt the Ghost Font technique.
The address to obtain the no-cost license to do so appears at the end of this article.
Licensees will receive automatic updates as we extend and improve the Ghost Font idea.
Font Management without Ghost Fonts
Initially, Macintosh font creators were required to register their fonts with
Apple, who arbitrated and assigned font numbers. This policy assured the isomorphic
relationship between font name and numbers, i.e., each font number corresponded to
one and only one font family name. Therefore, Geneva was #3, Courier #22, Helvetica
#21, etc. Developers relied on this assumption and published programs that stored the
font number representation of the font in application data files. The problem with this
approach, however, was that Apple reserved 128 of the available 256 numbers for
Apple/Adobe fonts, and the number of requests for font number assignments soon
exceeded the available numbers.
Not surprisingly, the clamor for font assignments made Apple soon decide that it
shouldn’t be in the business of managing font number assignments after all--so it
publicly changed the policy, and the Font/DA Mover program was rewritten to assign
font numbers on a first-come-first-served basis. Unfortunately, this did little to
solve the problem. Confusion reigned because applications created their data files with
embedded font numbers--the file would thus be fine until it was moved to a machine
where the fonts had been assigned different numbers, then the application either got
the font wrong, or worse, the system crashed because a font number was referenced
that didn’t exist on that machine.
In the midst of this mess, Apple released Macintosh Technical Note #191, which
was titled Font Names. This tech note recommended that applications reference fonts by
name, not by number. The Font Manager routines GetFontName and GetFNum form the
basis for this management scheme, and examples of using these functions, as well as a
suggested data structure and strategy for implementation are found in that note. Many
programs on the market today use this technique (but not all--apparently Microsoft
and a few others don’t read Apple’s programming documentation very carefully).
Unfortunately for users, there are two issues not addressed by the Apple solution:
first, there is no suggested way to use fonts referenced in a document but which are not
installed in the current system (the problem that used to cause crashes); and second,
what of the case where the same font is assigned a different number on two systems?
When a file is moved between systems with mismatching font IDs, applications must
detect this case and resolve the font number conflict. Macreations’ Ghost Font strategy
offers a solution to both of these problems.
Ghost Fonts in Tycho™
During the development of our table editor, Tycho, we realized that if an
application stores a document’s fonts by name in its data file, then that font can be used
in the editing process, whether or not it exists in the current System! At Macreations,
we define Ghost Fonts as those fonts that are referenced in a document but are not
resident in the current System.
What this means is that if I’m using Palatino for the Entry cell settings font of a
Tycho table (for those of you who are not familiar with our product, Entry cells make
up the the body of a table) on my Mac II at the office, I can bring the Tycho file home
and continue to edit the document using the Palatino font, even if I don’t have that font
installed on the Mac Plus that I use at home. The text appears on my Plus in the default
application font, which happens to be Geneva. I can change the size or face of the
effected text, apply the uninstalled Palatino font to newly created cells or text, or
otherwise format the document just as if Palatino were installed on the machine. The
next day, when I open the edited data file back on the office Mac II, all Palatino
referenced text appears in the correct font, since Palatino is installed on that machine.
User Interface Is Intuitive
Ghost Fonts are listed in the application’s font menu. To help distinguish the
Ghost Fonts from the real ones, we place them at the bottom of the menu, set off from
the real fonts with a dotted line, and preceded by a special character--Tycho prefixes
the font name with an asterisk (*). For example, Palatino appears in the font menu as
*Palatino if it is a Ghost Font. Menu feedback--the updating of the font menu with a
check mark reflecting the current text selection--is no different using Ghost Fonts
than in any other document processing software. The novelty of the divided font menu
and the asterisk is very quickly overcome and users soon take Ghost Fonts for granted.
Managing the User Interface
Figure 1 demonstrates the Ghost Font user interface. Each document can contain
its own unique set of Ghost Fonts. Take, for example, a standard system with its
complement of fonts--Chicago 12, the Geneva family, Monaco 9 and 12, the New York,
Helvetica and Times families. Now use that machine to open a few documents created on
one that contains most of the available Apple/Adobe fonts. Chances are that these
documents will contain style runs from these more expressive fonts and then again, not
all in the same combination. One document might contain Bookman and Palatino,
another Garamond and Zapf Chancery. A third might use only Helvetica. To support
Ghost Fonts in an application that manages multiple open documents, the font menu
must change to reflect the current document. As the user pulls down the font menu, the
correct Ghost Font combination for the top document should be shown.
Figure 1 - An example of the font menu using Ghost Fonts. Fonts above the dotted line
are resident in the system. Ghost Fonts appear below the line.
Implementation Strategy
Tycho can be thought of as a word processor for tables. Any number of cells can
be defined and each cell can contain an unlimited number of text style runs. Because of
the sheer number of style combinations in a Tycho document, for program efficiency
our internal representation of a font is numeric; this is true for most other
applications, as well. The cornerstone of our implementation strategy is the resolution
of all font references whenever the document is opened or saved. The major assumption
we’re making is the system font list will not change during the time the document is
resident. Beware--when using programs like Master Juggler and Suitcase II, that
manage font sets independently of the System, it’s possible to remove fonts from the
System while other programs are resident and using those fonts. We discourage this
practice, as do Master Juggler and Suitcase II--they hint at the consequences for
taking such an action. Users who operate with such reckless software abandon get
exactly what they deserve--file corruption, disk crashes, and the ever present bomb
box.
Font representation by number is also the basis for the QuickDraw call TextFont
, which sets the current GrafPort’s font and thus determines all subsequent text
drawing. What you may not know is if you pass the number of a non-resident font to
TextFont , it will draw all subsequent text in the application default font, whose value
is kept in the parameter RAM (that small area of memory kept alive by the battery on
your Mac; the parameter RAM holds other interesting data such as the current country
and longitude of your Mac, your mouse and keyboard preferences as set in the Control
Panel, your alarm setting, port configurations, and other custom information). The
Macintosh global at location $984--apFontID-- contains this application font number
and in most cases, its value will be the number that corresponds to Geneva. (Note that
while TextEdit seems to have no problem with Ghost Fonts, text wrap and line layout
will probably differ between the real font and the substituted one.)
Saving the Document Font List
When a document using Ghost Fonts is saved, a font list must be saved with the
data file. This list contains one instance of all font names and numbers used in the
document. Its purpose is to provide a mapping of all the fonts referenced in this file.
Remember, the internal format of fonts in the file is numeric, so this map gives you
the ability to find the name associated with any font number referenced in the file. One
possible structure for the list is:
/* 1 */
typedef struct FontMap {
short fontNumber;
char fontName [64];
} FontMap, *FontMapPtr, **FontMapHdl;
typedef struct FontList {
short count;
FontMap fontMap [1];
} FontList, *FontListPtr, **FontListHdl;
Font names are maintained as Pascal string (a Pascal string consists of a length
byte followed by the characters of the string). The fontName structure member is
defined here as a static array of 64 characters for simplicity. Your implementation
can and should be more efficient and only write the necessary characters to the file. If
you process the list sequentially, you’ll have no trouble calculating the next array
element address when you read it back in. Note the FontMap member of the FontList
structure is defined as a one-element array, but in practice, data instantiations of this
type must be fit to the correct number of entries.
We build the font list from our text style list. It helps if your file structure
consolidates all style information in one place. The following code fragment runs
through a style list and writes the font list to disk. It uses a temporary buffer to keep
track of font numbers already encountered so that each font is listed only once. Once