Old-fashioned character-mode applications could display only the boring system font on the screen. Windows provides multiple device-independent fonts in variable sizes. The effective use of these Windows fonts can significantly energize an application with minimum programming effort. TrueType fonts, first introduced with Windows version 3.1, are even more effective and are easier to program than the previous device-dependent fonts. You'll see several example programs that use various fonts later in this chapter.

Fonts Are GDI Objects

Fonts are an integral part of the Windows GDI. This means that fonts behave the same way other GDI objects do. They can be scaled and clipped, and they can be selected into a device context as a pen or a brush can be selected. All GDI rules about deselection and deletion apply to fonts.

Choosing a Font

Choosing a Windows font used to be like going to a fruit stand and asking for "a piece of reddish-yellow fruit, with a stone inside, that weighs about 4 ounces." You might have gotten a peach or a plum or even a nectarine, and you could be sure that it wouldn't have weighed exactly 4 ounces. Once you took possession of the fruit, you could weigh it and check the fruit type. Now, with TrueType, you can specify the fruit type, but you still can't specify the exact weight.

Today you can choose between two font types—device-independent TrueType fonts and device-dependent fonts such as the Windows display System font and the LaserJet LinePrinter font—or you can specify a font category and size and let Windows select the font for you. If you let Windows select the font, it will choose a TrueType font if possible. The MFC library provides a font selection dialog box tied to the currently selected printer, so there's little need for printer font guesswork. You let the user select the exact font and size for the printer, and then you approximate the display the best you can.

Printing with Fonts

For text-intensive applications, you'll probably want to specify printer font sizes in points (1 point = 1/72 inch). Why? Most, if not all, built-in printer fonts are defined in terms of points. The LaserJet LinePrinter font, for example, comes in one size, 8.5 point. You can specify TrueType fonts in any point size. If you work in points, you need a mapping mode that easily accommodates points. That's what MM_TWIPS is for. An 8.5-point font is 8.5 × 20, or 170, twips, and that's the character height you'll want to specify.

Displaying Fonts

If you're not worried about the display matching the printed output, you have a lot of flexibility. You can choose any of the scalable Windows TrueType fonts, or you can choose the fixed-size system fonts (stock objects). With the TrueType fonts, it doesn't much matter what mapping mode you use; simply choose a font height and go for it. No need to worry about points.

Matching printer fonts to make printed output match the screen presents some problems, but TrueType makes it easier than it used to be. Even if you're printing with TrueType fonts, however, you'll never quite get the display to match the printer output. Why? Characters are ultimately displayed in pixels (or dots), and the width of a string of characters is equal to the sum of the pixel widths of its characters, possibly adjusted for kerning. The pixel width of the characters depends on the font, the mapping mode, and the resolution of the output device. Only if both the printer and the display were set to MM_TEXT mode (1 pixel or dot = 1 logical unit) would you get an exact correspondence. If you're using the CDC::GetTextExtent function to calculate line breaks, the screen breakpoint will occasionally be different from the printer breakpoint.

In the MFC Print Preview mode, which we'll examine closely in Chapter 19, line breaks occur exactly as they do on the printer, but the print quality in the preview window suffers in the process.

If you're matching a printer-specific font on the screen, TrueType again makes the job easier. Windows substitutes the closest matching TrueType font. For the 8.5-point LinePrinter font, Windows comes pretty close with its Courier New font.

Logical Inches and Physical Inches on the Display

The CDC member function GetDeviceCaps returns various display measurements that are important to your graphics programming. The six described below provide information about the display size. The values listed are for a typical display card configured for a resolution of 640-by-480 pixels with Microsoft Windows NT 4.0.

HORZSIZEPhysical width in millimeters320
VERTSIZEPhysical height in millimeters240
HORZRESWidth in pixels640
VERTRESHeight in raster lines480
LOGPIXELSXHorizontal dots per logical inch96
LOGPIXELSYVertical dots per logical inch96

The indexes HORZSIZE and VERTSIZE represent the physical dimensions of your display. (These indexes might not be true since Windows doesn't know what size display you have connected to your video adapter.) You can also calculate a display size by multiplying HORZRES and VERTRES by LOGPIXELSX and LOGPIXELSY, respectively. The size calculated this way is known as the logical size of the display. Using the values above and the fact that there are 25.4 millimeters per inch, we can quickly calculate the two display sizes for a 640-by-480 pixel display under Windows NT 4.0. The physical display size is 12.60-by-9.45 inches, and the logical size is 6.67-by-5.00 inches. So the physical size and the logical size need not be the same.

For Windows NT 4.0, it turns out that HORZSIZE and VERTSIZE are independent of the display resolution, and LOGPIXELSX and LOGPIXELSY are always 96. So the logical size changes for different display resolutions, but the physical size does not. For Windows 95, the logical size and the physical size are equal, so both change with the display resolution. (At a resolution of 640-by-480 pixels with Windows 95, HORZSIZE is 169 and VERTSIZE is 127.)

Whenever you use a fixed mapping mode such as MM_HIMETRIC or MM_TWIPS, the display driver uses the physical display size to do the mapping.

So, for Windows NT, text is smaller on a small monitor; but that's not what you want. Instead, you want your font sizes to correspond to the logical display size, not the physical size.

You can invent a special mapping mode, called logical twips, for which one logical unit is equal to 1/1440 logical inch. This mapping mode is independent of the operating system and display resolution and is used by programs such as Microsoft Word. Here is the code that sets the mapping mode to logical twips:

pDC->SetWindowExt(1440, 1440);

From the Windows Control Panel, you can adjust both the display font size and the display resolution. If you change the display font size from the default 100 percent to 200 percent, HORZSIZE becomes 160, VERTSIZE becomes 120, and the dots-per-inch value becomes 192. In that case, the logical size is divided by 2, and all text drawn with the logical twips mapping mode is doubled in size.

Computing Character Height

Five font height measurement parameters are available through the CDC function GetTextMetrics, but only three are significant. Figure 5-1 shows the important font measurements. The tmHeight parameter represents the full height of the font, including descenders (for the characters g, j, p, q, and y) and any diacritics that appear over capital letters. The tmExternalLeading parameter is the distance between the top of the diacritic and the bottom of the descender from the line above. The sum of tmHeight and tmExternalLeading is the total character height. The value of tmExternalLeading can be 0.

Click to view at full size.

Figure 5-1. Font height measurements.

You would think that tmHeight would represent the font size in points. Wrong! Another GetTextMetrics parameter, tmInternalLeading, comes into play. The point size corresponds to the difference between tmHeight and tmInternalLeading. With the MM_TWIPS mapping mode in effect, a selected 12-point font might have a tmHeight value of 295 logical units and a tmInter-nalLeading value of 55. The font's net height of 240 corresponds to the point size of 12.