Created: June 8, 1992
When the application selects this logical font into a device context (DC) using the SelectObject function, the font is matched to a physical font, one that can be output by the device. This process is called realization; font mapping is the primary operation of the realization. The goal of the realization is to find a font available for the output device that most closely resembles the logical font. Determining this closeness is what font mapping is all about.
Note to the squeamish: In the case that the idealized font does not exist, the font mapper in Windows is not perfect, resorting to what it defines as the closest match. As a result, many disgruntled developers have referred to it with such crafty misnames as "font mangler" and the like. As with most software, the trick to using the font mapper is to understand how it operates and to work with it, instead of against it.
An application can get data about the physical font that is actually realized by using the GetTextMetrics, GetTextFace, and GetOutlineTextMetrics functions. (GetOutlineTextMetrics is relevant only to TrueType® fonts.) First, select the logical font; then use these functions to get the details on the realized font.
Note For the duration of this article, the font's attributes are referenced using their field names as defined in the LOGFONT structure. While this structure is not a parameter to the CreateFont function, that function's parameters map directly to the structure. Inside the graphics device interface (GDI), all fonts are defined by a LOGFONT structure.
Font enumeration, like font realization, is based on a specific physical device identified by a DC. Different devices enumerate a different set of physical fonts, so an enumerated logical font from one device may not exactly match a physical font from another device. For example, a given printer may enumerate a hardware-based font named Courier 10cpi, but that font has no exact match on the display device. The application can "help out" in this process by choosing an ideal match from the fonts enumerated by the display device and using that font for selection into the display device.
Usually the desired font is chosen by the user, a process that can be greatly simplified by an application's use of the ChooseFont common dialog. This dialog box presents the user with the list of enumerated fonts and returns to the application a logical font to use. The application can control exactly which types of fonts are presented to the user, thereby limiting the enumeration as desired.
If enumeration and exact choice is not an option, an application still needs to describe the font as unambiguously as possible to get a reasonable level of consistency in the mapping process. It is a good idea to always specify an lfFaceName, lfPitchAndFamily, lfHeight, and lfCharSet attribute. The use and abuse of default values is discussed in greater detail below in "Don't-Care Values."
CellHeight = (PointSize * VerticalResolution) / 72 + InternalLeading;and conversely,
PointSize = ((CellHeight - InternalLeading) * 72) / VerticalResolution;In these equations:
MyFont.lfHeight = -((PointSize * GetDeviceCaps(hDC, LOGPIXELSY)) / 72);Also, the TEXTMETRIC structure is returned during font enumeration, so it is possible to anticipate a font's internal leading if a specific physical font is being targeted. Anticipation is not possible with scalable fonts because the fonts do not enumerate specific sizes and may not scale linearly.
A fundamental difference exists in the font mapping process between Windows version 3.0 and version 3.1. Both versions share a core mapper that uses weighted penalties to choose the closest matching physical font, but Windows version 3.1 also has a shortcut layer that attempts to bypass the core mapper by looking for exact matches and only resorting to the core mapper when a certain level of exactness cannot be achieved. The basic idea is that if an application requests a logical font in the "right" way (see above), finding a matching physical font can be quick and to the point without excess processing. The shortcut layer is only for speed purposes; the functional behavior is unchanged.
The system-based fonts are the non-TrueType fonts that are installed via the Control Panel. (TrueType fonts are also installed via the Control Panel.). A few are installed automatically when Windows is set up. The raster fonts usually come in several sizes per face name, and because the fonts do not scale, these are the only sizes that are available for the realization.
The vector fonts that come with Windows (Modern, Roman, and Script) are scalable fonts defined by polylines and are the only fonts that can be printed on plotter devices. They are commonly referred to as the "stick fonts" because they are made up of line segments, which results in rather poor typographic quality. Most applications avoid the vector fonts by requesting a font with the lfCharSet attribute set to something other than OEM_CHARSET (specifically, ANSI_CHARSET or SYMBOL_CHARSET), the charset of the vector fonts, and it is common to see these fonts screened out of the font enumeration lists shown to the user.
Device fonts are those fonts that are provided by the device driver, either through hardware fonts or by downloading to the device. Usually these exist only for printer drivers, but bolt-on font engines also provide the concept for display drivers. Device fonts are controlled more by the device than by GDI. GDI only has access to descriptive information about the font and not to the actual bit information, and, more importantly, the device driver acts as its own font mapper in choosing the best match among the available device fonts. Windows sends the device driver the requested logical font, and the device chooses the best match from its available hardware and downloaded fonts. During the font-mapping process, the font mapper inspects only the one device font. If the device has no fonts, there is no device font for the font mapper to inspect.
TrueType font technology is new for Windows version 3.1 and introduces to the system a class of fonts that are scalable and compatible with all raster devices. On printers, these fonts are either built into the hardware, downloaded to the hardware, or drawn to a bitmap that is then blted to the page. TrueType fonts, like raster and vector fonts, are added to the Windows environment through the Control Panel and managed by GDI. Because of their scalability, TrueType fonts are not penalized for height, width, or aspect ratio, but they are treated like the other types of fonts in all other respects.
The interesting part, of course, is the relative size of the penalties. At the end of this article is a table that lists the specific penalties and their values. A quick inspection of this table reveals that the penalties are heavily weighted to discourage physical fonts whose major typographical features are not similar to the logical font. The big-ticket items are charset, output precision, variable instead of fixed pitch, face name, family type, and height. The lesser penalties only come into play in cases where the logical font is too vague to home in on a desired physical font.
The height penalty is often a cause for confusion. The goal for the mapper is to choose a font that is as large as possible without being taller than the requested height. For example, when using raster fonts (height problems only apply to fonts that do not scale arbitrarily), if the logical font has a height of 11 and the available physical fonts have heights of 10 and 12, the shorter font is chosen. If the logical font has a height of 8 and there is no font shorter than 10, the font with a height of 10 is chosen. A few applications have attempted to "guarantee" the selection of the smallest legible font by asking for an undersized font. That trick, though, can cause undesirable results if a super-small font such as SMALLE.FON is available on the system because the font maps to a 6-pixel-high font, which is not exactly legible.
In the case where two different fonts have exactly the same penalty, the first font that was inspected is the one that is selected. An application does not have control of this ordering. Nondevice fonts are assessed an extra penalty to encourage the selection of a device font over an identical nondevice font. The selection priority is first, device; second, raster; and third, TrueType.
The shortcut mechanism is used only if the device is a raster device that can accept raster fonts or a device that can output TrueType fonts (presumably by downloading). Also, the logical font must either specify a face name or use the OUT_TT_ONLY_PRECIS or CLIP_EMBEDDED flags (in its lfOutputPrecision and lfClipPrecision attributes, respectively) to be considered a candidate for an exact match. Obviously, if no face name is specified, an exact match cannot be found. The two flags indicate, however, that only TrueType fonts should be considered for a match so that some of the standard mapping process can be avoided. If the shortcut method cannot be used, the standard penalty-based mapper is used to choose the font.
Like the full font mapper, the shortcut inspects all the possible physical fonts for a match, but instead of tracking penalties, it throws out of consideration any candidate font that does not exactly match the above attributes. So if the logical font is based directly on an existing physical font, the matching is very simple, which is the entire goal of the shortcut.
If no exact match is found, the font mapping defaults to the penalty-based system. Ties (that is, multiple physical fonts providing an exact match) are resolved based on the filter setting of the lfOutputPrecision attribute. If no special filter is specified, the default behavior is that device fonts beat out everything else, and raster fonts beat out TrueType fonts. The default behavior can be altered to have the TrueType font win a tie by using the TTIfCollisions entry in the [TrueType] section of WIN.INI.
The possibility for close matches is especially true for loosely defined fonts, those fonts that use a lot of default attribute settings. For example, an application is making a very bad assumption if it assumes that a logical font created by specifying a height of 12 and setting all other attributes to 0 will map to the system font. While operating under this assumption might work under Windows version 3.0, under Windows version 3.1 at least six fonts can match that request exactly even if only the core TrueType fonts are loaded. The one that is chosen by the font mapper is suddenly not so obvious and depends on such intangibles as the ordering of the fonts during initialization.
It is up to the application to be specific enough in its definition of the logical font to avoid mapping confusion. The first thing to consider is that TrueType fonts are fully scalable, so an apparently off-size height can be matched-there is no penalty for height (or for width or aspect ratio).
Because most TrueType fonts are designed with a normal, italic, bold, and bold italic version, a request for one of these variations maps directly to a nonsimulated variant of the standard font. Many fonts are also available in nontraditional weights such as light, demibold, and black, so the exact lfWeight attribute that is specified could be meaningful. An application needs to be careful in choosing the lfFaceName attribute to deal with the potential explosion of face names. The EnumFontFamilies function is designed to help an application sort through the face names and their family relationships. In the eyes of the font mapper, the lfFaceName attribute specified by the application can be either the full face name (for example, Arial® Italic) or only the family name (in this example, Arial). Assuming that all of the attributes match (in this example, the lfItalic attribute needs to be set), the two names are considered equivalent.
TrueType doesn't really introduce anything new into the font-mapping picture, but it does make the choice of physical fonts large enough to require that an application carefully define its logical fonts.
Face name substitutions are used only for raster and TrueType fonts and not for device fonts. Also, when a face name is matched through substitution, it is not considered an exact match-a penalty is assessed for substitute face names, and an exact match always takes precedence.
The substitutions come from two places: one list is predefined in GDI, and a second list is defined by the user in WIN.INI under the [FontSubstitutes] section. The user-defined list can override GDI's predefined list to customize the Windows environment to the user's font needs. GDI's list consists of approximately 20 substitutions that map Tms Rmn to MS Serif, Helv to MS Sans Serif, and various PostScript® names to the corresponding TrueType fonts that ship with Windows and in the Microsoft TrueType Font Pack for Windows.
The second type of filtering is new for Windows version 3.1 and allows an application to choose what type of physical font should be chosen in the case of a face name conflict. These filters only affect the shortcut mapping described above; if no shortcut match is found, the font mapper continues with its standard matching scheme and ignores these filters. The application defines the filter in the lfOutputPrecision attribute of the logical font. Unlike the aspect-ratio filter, this filter is specific to a given logical font. The three possible filter settings are OUT_TT_PRECIS for TrueType fonts, OUT_DEVICE_PRECIS for device fonts, and OUT_RASTER_PRECIS for raster fonts. For example, if the shortcut mechanism finds two fonts-one TrueType and one raster-that provide an exact match for the logical font, and the logical font is defined with OUT_TT_PRECIS, the TrueType font is chosen.
Another shortcut filter, OUT_TT_ONLY_PRECIS, specifies that only TrueType fonts should be considered for the exact matching. None of the other types of physical fonts are considered. This filter is useful for an application that wants to guarantee that the realized font is a TrueType font.
There are times when using don't-care values gets dangerous. Using DEFAULT_CHARSET for specifying the font's lfCharSet attribute can lead to the font mapper choosing a non-ANSI font that may not contain needed characters and may not even be composed of alphanumeric glyphs. Internally, the DEFAULT_CHARSET is an actual charset definition, so all candidate fonts get an equally large penalty for not matching the charset. It is always a good idea to use a real charset when defining a logical font.
The font mapper treats a logical font with an lfHeight attribute of 0 as a font that is 12 points high. The actual pixel height depends on the resolution of the device being used. With the advent of TrueType technology in Windows version 3.1, this zero height becomes even less meaningful. The moral: Always specify a height.
By specifying no face name (the lfFaceName attribute) for the logical font, an application indicates to the font mapper that the exact face name of the physical font is not critical. An application that does not specify a face name is only asking for trouble. Because the face name is the only unique identifier of a font, ignoring it leaves the application open to more ambiguity in realizing a physical font. The more fonts that are available on the system, the less control the application has over the mapping process. An application can overcome some of this ambiguity by defining the generalized look of the font using the lfPitchAndFamily field, but as more and more fonts become available in the Windows system, a font's unique face name becomes critical in its identification. The moral: Always specify a face name.
The font mapper interprets an lfWeight attribute of FW_DONTCARE as though it were really FW_NORMAL, and any corresponding penalty is tabulated.
It is generally considered good to specify a don't-care lfWidth attribute by setting it to 0. While for most fonts the character widths cannot be changed and are not actually affected, scalable fonts (TrueType and many device fonts) are altered in shape by a nonzero width. This effect is usually not desirable. Because height is more important than width in the matching process, a nonzero width usually does not affect the matching, but it could. The font mapper compares this value to the average width value of the candidate font (accessible through the tmAvgWidth field of the TEXTMETRIC structure), a value that for nonscalable, variable-pitch fonts is an approximation at best. For scalable fonts, the lfWidth field is used to define an x-scaling factor for the font (x-scale = lfWidth/tmAvgWidth), where an lfWidth of 0 means a scaling factor of 1.0.
The height and width of a logical font are defined in logical units. When the font is selected into a DC, these values are converted to device units before the font mapping takes place. As a result, the realized font may be larger or smaller, depending on the DC's current mapping mode. Also, if an application changes the mapping mode of a DC, the currently selected font is re-realized based on the new coordinate system. This is entirely consistent with GDI's handling of logical and physical coordinates and is something to keep in mind when specifying the height of a font. The one exception to this process is new to Windows version 3.1: If the logical font is one of the stock objects (available through the GetStockObject function-copies don't count), the height and width are always treated as MM_TEXT values, regardless of the DC's current mapping mode.
When GDI scales a raster font, it does so by simply stretching the font's original bitmap definition horizontally and vertically, as appropriate. Because the scaling is always integral, none of the really nasty side effects of bitmap stretching occur, but a stretched font still looks very clunky, especially so at larger scale factors.
GDI can trivially simulate underlines and strikethroughs using horizontal lines, so these attributes are not a real concern. While TrueType fonts have special metrics for the placement of underlines and strikethroughs, GDI approximates these values for other fonts with the underline on the baseline and the strikethrough one-third of the ascent above the baseline.
Under Windows version 3.1, if an application selects a stock font into a DC, the requested font's logical height and width are not translated into logical units. The effect is that a stock font remains the same size regardless of the DC's mapping mode. A copy of a logical object does not qualify for this special feature; only the actual stock object does. Because objects recorded in metafiles are simply copies of objects, a stock font recorded in a metafile is treated as an ordinary font when the metafile is played back.
Table 1. Penalty Weights in the Font Mapper
Penalty description | Penalty weight | Comments |
CharSet | 65000 | Requested charset does not match the candidate's. |
OutputPrecision | 19000 | Requested OUT_STROKE_PRECIS,
but the device can't do it or the candidate is not a vector font.
Or OUT_STROKE_PRECIS not requested, and the candidate is a vector font that requires GDI support. |
FixedPitch | 15000 | Requested a fixed pitch font, but the candidate is a variable pitch font. |
FaceName | 10000 | Requested a face name, but the candidate's face name does not match. |
Family | 9000 | Requested a family, but the candidate's family is different. |
FamilyUnknown | 8000 | Requested a family, but the candidate has no family. |
HeightBigger | 600 | The candidate is a nonvector font and is bigger than the requested height. |
FaceNameSubst | 500 | New for Windows
version 3.1.
Requested face name is matched with a substitute face name. |
PitchVariable | 350 | Requested a variable pitch font, but the candidate is not a variable pitch font. |
HeightSmaller | 150 | The candidate
is a raster font and is smaller than the requested height.
Penalty * height difference |
HeightBiggerDifference | 150 | The candidate
is a raster font and is larger than the requested height.
Penalty * height difference |
FamilyUnlikely | 50 | New for Windows
version 3.1.
Requested a roman/modern/swiss family, but the candidate is decorative/script. Or requested decorative/script, and the candidate is roman/modern/swiss. |
Width | 50 | Requested a nonzero
width, but the candidate's width doesn't match.
Penalty * width difference |
SizeSynth | 50 | The candidate is a raster font that needs scaling by GDI. |
Aspect | 30 | The candidate's
aspect ratio is different from that of the device.
Penalty * ((100 * devY/devX) - (100 * candidateY / candidateX)) |
IntSizeSynth | 20 | The candidate
is a raster font that needs scaling.
Penalty * (height multiplier + width multiplier) |
UnevenSizeSynth | 4 | The candidate
is a raster font that is scaled unequally in width and height.
Penalty * (100 * bigger multiplier / smaller multiplier) |
Italic | 4 | Requested font and candidate font do not agree on italic status, and the desired result cannot be simulated. |
NotTrueType | 4 | New for Windows
version 3.1.
Requested OUT_TT_PRECIS, but the candidate is not a TrueType font. |
Weight | 3 | The candidate's
weight does not match the requested weight.
Penalty * (weight difference/10) |
Underline | 3 | Requested font has no underline, but the candidate is underlined. |
StrikeOut | 3 | Requested font has no strike-out, but the candidate is struck out. |
VectorHeightSmaller | 2 | Candidate is a
vector font that is smaller than the requested height.
Penalty * height difference |
DeviceFavor | 2 | Extra penalty for all nondevice fonts. |
ItalicSim | 1 | New for Windows
version 3.1.
Requested italic font but the candidate is not italic, although italics can be simulated. |
DefaultPitchFixed | 1 | Requested DEFAULT_PITCH, but the candidate is fixed pitch. |
SmallPenalty | 1 | New for Windows
version 3.1.
Requested a rotated font, and the candidate needs bold or italic simulation and is a raster or vector font. |
VectorHeightBigger | 1 | Candidate is a
vector font that is bigger than the requested height.
Penalty * height difference |
© 1997 Microsoft Corporation. All rights reserved. Terms of use