|VC++ 6.0 ebook chapter index|
Much of the remainder of this chapter addresses working with different fonts. Before you get involved with specific code, however, you'll benefit from having a firm grasp of the basics of fonts as they are implemented in Windows.
The Types of Fonts
Windows supports two broad categories of fonts, called "GDI fonts" and "device fonts." The GDI fonts are stored in files on your hard disk. Device fonts are native to an output device. For example, it is common for printers to have a collection of built-in device fonts.
GDI fonts come in three flavors: raster fonts, stroke fonts, and TrueType fonts.
A raster font is sometimes also called a bitmap font, because each character is stored as a bitmap pixel pattern. Each raster font is designed for a specific aspect ratio and character size. Windows can create larger character sizes from GDI raster fonts by simply duplicating rows or columns of pixels. However, this can be done in integral multiples only and within certain limits. For this reason, GDI raster fonts are termed "nonscaleable" fonts. They cannot be expanded or compressed to an arbitrary size. The primary advantages of raster fonts are performance (because they are very fast to display) and readability (because they have been hand-designed to be as legible as possible).
Fonts are identified by typeface names. The raster fonts have typeface names of
|System||(used for SYSTEM_FONT)|
|FixedSys||(used for SYSTEM_FIXED_FONT)|
|Terminal||(used for OEM_FIXED_FONT)|
|MS Sans Serif||(used for DEFAULT_GUI_FONT)|
Each raster font comes in just a few (no more than six) different sizes. The Courier font is a fixed-pitch font similar in appearance to the font used by a typewriter. The word "serif" refers to small turns that often finish the strokes of letters in a font such as the one used for this book. A "sans serif" font doesn't have serifs. In early versions of Windows, the MS (Microsoft) Serif and MS Sans Serif fonts were called Tms Rmn (meaning that it was a font similar to Times Roman) and Helv (similar to Helvetica). The Small Fonts are especially designed for displaying text in small sizes.
Prior to Windows 3.1, the only other GDI fonts supplied with Windows were the stroke fonts. The stroke fonts are defined as a series of line segments in a "connect-the-dots" format. Stroke fonts are continuously scaleable, which means that the same font can be used for graphics output devices of any resolution and the fonts can be increased or decreased to any size. However, performance is poor, legibility suffers greatly at small sizes, and at large sizes the characters look decidedly weak because their strokes are single lines. Stroke fonts are now sometimes called plotter fonts because they are particularly suitable for plotters but not for anything else. The stroke fonts have typeface names of Modern, Roman, and Script.
For both GDI raster fonts and GDI stroke fonts, Windows can "synthesize" boldface, italics, underlining, and strikethroughs without storing separate fonts for each attribute. For italics, for instance, Windows simply shifts the upper part of the character to the right.
Then there is TrueType, to which I'll devote much of the remainder of this chapter.
The individual characters of TrueType fonts are defined by filled outlines of straight lines and curves. Windows can scale these fonts by altering the coordinates that define the outlines.
When your program begins to use a TrueType font of a particular size, Windows "rasterizes" the font. This means that Windows scales the coordinates connecting the lines and curves of each character using "hints" that are included in the TrueType font file. These hints compensate for rounding errors that would otherwise cause a resultant character to be unsightly. (For example, in some fonts the two legs of a capital H should be the same width. A blind scaling of the font could result in one leg being a pixel wider than the other. The hints prevent this from happening.) The resultant outline of each character is then used to create a bitmap of the character. These bitmaps are cached in memory for future use.
Originally, Windows was equipped with 13 TrueType fonts, which have the following typeface names:
Courier New Bold
Courier New Italic
Courier New Bold Italic
Times New Roman
Times New Roman Bold
Times New Roman Italic
Times New Roman Bold Italic
Arial Bold Italic
In more recent versions of Windows, this list has been expanded. In particular, I'll be making use of the Lucida Sans Unicode font that includes some additional alphabets used around the world.
The three main font families are similar to the main raster fonts. Courier New is a fixed-pitch font designed to look like the output from that antique piece of hardware known as a typewriter. Times New Roman is a clone of the Times font originally designed for the Times of London and used in much printed material. It is considered to be highly readable. Arial is a clone of Helvetica, a sans serif font. The Symbol font contains a collection of handy symbols.
Attributes or Styles?
You'll notice in the list of TrueType fonts shown above that bold and italic styles of Courier, Times New Roman, and Arial seem to be separate fonts with their own typeface names. This naming is very much in accordance with traditional typography. However, computer users have come to think of bold and italic as particular "attributes" that are applied to existing fonts. Windows itself took the attribute approach early on when defining how the raster fonts were named, enumerated, and selected. With TrueType fonts, however, more traditional naming is preferred.
This conflict is not quite ever resolved in Windows. In short, as you'll see, you can select fonts by either naming them fully or by specifying attributes. The process of font enumeration, in which an application requests a list of fonts from the system, is—as you might expect—complicated somewhat by this dual approach.
The Point Size
In traditional typography, you specify a font by its typeface name and its size. The type size is expressed in units called points. A point is very close to 1/72 inch—so close in fact that in computer typography it is often defined as exactly 1/72 inch. The text of this book is printed in 10-point type. The point size is usually described as the height of the characters from the top of the ascenders (without diacritics) to the bottom of the descenders, encompassing, for example, the full height of the letters "bq." That's a convenient way to think of the type size, but it's usually not metrically accurate.
The point size of a font is actually a typographical design concept rather than a metrical concept. The size of the characters in a particular font might be greater than or less than what the point size implies. In traditional typography, you use a point size to specify the size of a font; in computer typography, there are other methods to determine the actual size of the characters.
Leading and Spacing
As you'll recall from as long ago as Chapter 4, you can obtain information about the font currently selected in the device context by calling GetTextMetrics, as we've also done frequently since then. Figure 4-3 illustrates the vertical sizes of a font from the FONTMETRIC structure.
Another field of the TEXTMETRIC structure is named tmExternalLeading. The word leading (pronounced "ledding") is derived from the lead that typesetters insert between blocks of metal type to add white space between lines of text. The tmInternalLeading value corresponds to the space usually reserved for diacritics; tmExternalLeading suggests an additional space to leave between successive lines of characters. Programmers can use or ignore the external leading value.
When we refer to a font as being 8-point or 12-point, we're talking about the height of the font less internal leading. The diacritics on certain capital letters are considered to occupy the space that normally separates lines of type. The tmHeight value of the TEXTMETRIC structure thus actually refers to line spacing rather than the font point size. The point size can be derived from tmHeight minus tmInternalLeading.
The Logical Inch Problem
As I discussed in Chapter 5 (in the section entitled "The Size of the Device"), Windows 98 defines the system font as being a 10-point font with 12-point line spacing. Depending on whether you choose Small Fonts or Large Fonts from the Display Properties dialog, this font could have a tmHeight value of 16 pixels or 20 pixels and a tmHeight minus tmInternalLeading value of 13 pixels or 16 pixels. Thus, the choice of the font implies a resolution of the device in dots per inch, namely 96 dpi when Small Fonts are selected and 120 dpi for Large Fonts.
You can obtain this implied resolution of the device by calling GetDeviceCaps with the LOGPIXELSX or LOGPIXELSY arguments. Thus, the metrical distance occupied by 96 or 120 pixels on the screen can be said to be a "logical inch." If you start measuring your screen with a ruler and counting pixels, you'll probably find that a logical inch is larger than an actual inch. Why is this?
On paper, 8-point type with about 14 characters horizontally per inch is perfectly readable. If you were programming a word processing or page-composition application, you would want to be able to show legible 8-point type on the display. But if you used the actual dimensions of the video display, there would probably not be enough pixels to show the character legibly. Even if the display had sufficient resolution, you might still have problems reading actual 8-point type on a screen. When people read print on paper, the distance between the eyes and the text is generally about a foot, but a video display is commonly viewed from a distance of two feet.
The logical inch in effect provides a magnification of the screen, allowing the display of legible fonts in a size as small as 8 points. Also, having 96 dots per logical inch makes the 640-pixel minimum display size equal to about 6.5 inches. This is precisely the width of text that prints on 8.5-inch-wide paper when you use the standard margins of an inch on each side. Thus, the logical inch also takes advantage of the width of the screen to allow text to be displayed as large as possible.
As you may also recall from Chapter 5, Windows NT does it a little differently. In Windows NT, the LOGPIXELSX (pixels per inch) value you obtain from GetDeviceCaps is not equal to the HORZRES value (in pixels) divided by the HORZSIZE value (in millimeters), multiplied by 25.4. Similarly, LOGPIXELSY, VERTRES, and VERTSIZE are not consistent. Windows uses the HORZRES, HORZSIZE, VERTRES, and VERTSIZE values when calculating window and offset extents for the various mapping modes; however, a program that displays text would be better off to use an assumed display resolution based on LOGPIXELSX and LOGPIXELSY. This is more consistent with Windows 98.
So, under Windows NT a program should probably not use the mapping modes provided by Windows when also displaying text in specific point sizes. The program should instead define its own mapping mode based on the logical-pixels-per-inch dimensions consistent with Windows 98. One such useful mapping mode for text I call the "Logical Twips" mapping mode. Here's how you set it:
SetMapMode (hdc, MM_ANISOTROPIC) ; SetWindowExtEx (hdc, 1440, 1440, NULL) ; SetViewportExt (hdc, GetDeviceCaps (hdc, LOGPIXELSX), GetDeviceCaps (hdc, LOGPIXELSY), NULL) ;
With this mapping mode set, you can specify font dimensions in 20 times the point size—for example, 240 for 12 points. Notice that unlike the MM_TWIPS mapping mode, the values of y increase going down the screen. This is easier when displaying successive lines of text.
Keep in mind that the discrepancy between logical inches and real inches occurs only for the display. On printer devices, there is total consistency with GDI and rulers.