THE PRINTER AND FONTS

Chapter 14 culminated in a program called JUSTIFY that uses GDI-based raster fonts to display formatted text. Programs that work with formatted text on the screen usually also need to print this text. In fact, word-processing and desktop publishing programs generally use the display solely to provide a preview of the printed output.

This is a difficult task: What you show on the display can only approximate what the printer will print. Even if the printer uses only GDI-based fonts (those fonts stored in .FON font resource files), it generally has a different resolution than the screen, meaning that the printed characters will be a slightly different size than on the display. And if the printer uses device-based fonts (fonts that are internal to the printer), the problem becomes even more complex. For example, in the case of a printer that offers a 15-point Zapf Chancery font, you'll be approximating that font on the display with a 14-point font of another typeface. Even if the user wants to print text in 14-point Times Roman, the various character widths of the printer's device-based font can differ from those of the display's GDI-based font. In short, if you're writing a program that must display formatted text destined for a printer, you can count on some work ahead. Here are some guidelines to get you started.

You'll want to let the user choose from a list of typeface names and sizes that are supported by the currently selected printer. That is, you need to enumerate the printer fonts (as we did in the FONTLIST program in Chapter 14), which requires using EnumFonts with a call-back function. This call-back function receives a pointer to a logical font (LOGFONT) structure and a text metrics (TEXTMETRICS) structure describing each font. The call-back function also receives a short integer that indicates whether the font is a GDI-based or a device-based font. Another bit indicates whether the font is a raster font, in which case it is scalable (within limits) by integer multiples, or a vector font, in which case it is continuously scalable.

For device-based vector fonts, the call-back function will receive only one typeface size. You can check the value returned from GetDeviceCaps using the TEXTCAPS parameter to determine how the device can scale these vector fonts. If they can be scaled by any multiple, you might want to allow the user to specify a point size.

When you display formatted text on the screen, you want to space the text based on how it will be eventually printed. You can use GetDeviceCaps and the GETPHYSPAGESIZE Escape call to determine the size of the paper and the size of the printable area. For instance, if the paper is 8-1/2 inches wide and the user selects left and right margins of 1 inch, then you want to display text on the screen using a width of 6-1/2 inches. The ”logical twips“ mapping mode discussed in Chapter 14 is appropriate for this display. There's a catch, however. If the user selects a 15-point font that the printer supports, you'll have to approximate that font on the display with a 14-point font—but you can't use this 14-point display font to determine the amount of 15-point text that can fit in one printed line. You must determine this instead based on the printer font. Likewise, you must use the printer font to determine how many lines fit on a page.

To format the display text, you'll need both a handle to the screen device context (to display the text on the screen) and a handle to a printer information context. You don't need a printer device context handle until you actually want to print. Follow these steps:

1.Put together a logical font structure with the typeface name, the type size, and the attributes selected by the user, and select that logical font into the printer information context.

2.Call GetTextMetrics for the printer information context to determine the real size and characteristics of the selected printer font. Call GetTextFace to obtain the typeface name.

3.Use the information obtained in Step 2 to create another logical font structure based on the size and characteristics of the printer font, and select this logical font into the screen device context. The font now selected into the screen device context closely approximates the font selected into the printer information context.

4.When you write the text to the display, follow the general procedure used in the Justify function of the JUSTIFY program. However, go through the GetTextExtent and SetTextJustification logic using the printer information context, but stop short of TextOut. This approach allows you to determine the amount of text that fits on each line and the number of lines that fit on a page.

5.When you have established each line of text as appropriate for the printer, you can call GetTextExtent and (possibly) SetTextJustification using the screen display context. You then call TextOut to display the line.

To print the text, you'll probably use code structured like that in the POPPADP.C file combined with the logic in the Justify function of JUSTIFY.C. You obtain a printer device context and go through the GetTextExtent and SetTextJustification logic again, this time using TextOut to print each line.