In Windows, a font is a collection of characters that have a common design. The terminology that Windows uses to describe fonts is not necessarily the same as that used by a typographer, but we will follow the Windows terminology.
The typeface of a font refers to the specific design of the characters in the font. For instance. Times New Roman and Arial are two different typefaces. One of the main design features of a typeface is the presence or absence of serifs, which are small lines that are designed to help the eyes make a smooth transition from one character to the next. thus making reading less stressful. Figure 25-1 shows the difference between a serif and a sans serif font.
Figure 25-1. Serifs and non serifs
The term style refers to the weight and slant of a font. Weights range from thin to black in the following order: thin, extralight, light, normal, medium, semibold, bold, extrabold, heavy, and black.
The slant of a font is characterized as roman, oblique, or italic. A roman style font has no slant; an oblique style font has a slant that is created simply by sheering the characters in a roman font; an italic style font is one that is designed to be slanted.
Page 427
To quote the documentation:
In Windows, the size of a font is an imprecise value. It can generally be determined by measuring the distance from the bottom of a lowercase ''g" to the top of an adjacent uppercase "M," A font's size is specified in units called points. A point is .013837 of an inch. Following the point system devised by Pierre Simon Fournier, it is common practice to approximate a point as 1/72 inch.
Font Families
In Windows, fonts are grouped by family, which is a set of fonts having a common stroke width (width of thick and thin lines making up the characters) and serif characteristics. There are five families in Windows, each identified by a symbolic constant:
Decorative (FF_DECORATIVE) Novelty fonts
Modern (FF_MODERN) Monospace fonts
Roman (FF_ROMAN) Proportional fonts with serifs, such as Times New Roman
Script (FF_SCRIPT) Fonts designed to look like handwriting
Swiss (FF_SWISS) Proportional fonts without serifs, such as Arial
Dontcare (FF_DONTCARE) A generic family name, used when information about a font does not exist or does not matter
Font Technologies
In Windows, there are four technologies for rendering fonts on the display or printer: raster (or bitmap), vector (or stroke), TrueType, or OpenType. The difference between these technologies centers on how the glyphs are stored in the font file. (A glyph is the data or commands that define a character.)
The characters of a raster font are stored as bitmaps. As a result, scaling a raster font generally gives very poor results. The characters of a vector font are stored as line segments. However, vector fonts tend to be drawn more slowly than TrueType and OpenType fonts and appear very thin, since the lines that make up the characters are one-pixel wide.
TrueType and OpenType characters are stored as line segments and curves, along with hints that are used to adjust the rendering of the characters based on point
Page 428
size. Hence, these fonts can be scaled up or down without losing their intended appearance. (OpenType fonts allow PostScript character definitions as well as TrueType character definitions.)
The glyphs for a font are stored in a font-resource file (or just font file). For raster and vector fonts, this data is divided into two parts: a header describing the font's metrics, and the glyph data. These files have extension FON. Each TrueType and OpenType font has two associated files a short header file with extension FOT and the font data with extension TTF.
Character Sets
We discussed the ASCII, ANSI, and Unicode character sets earlier in the book. Most Windows fonts use character sets that belong to one of the following groups:
Windows (ANSI)
Unicode
OEM (original equipment manufacturer)
Symbol
Vendor-specific
The OEM character set is usually used for console applications (in a text-based window). Symbol character sets contain special symbolic characters in the upper half (characters 128 255), such as those used in mathematics and the sciences.
Logical and Physical Fonts
In order for a particular font to be used in an API function, that font must exist on the user's machine. This presents a potential problem, since we have no way to predict which fonts are installed on a given computer. To deal with this issue, Windows uses the notions of logical and physical fonts.
Physical fonts can be divided into two types: GDI fonts, which are stored in files on the computer's hard disk, and device fonts, which are internal to (or resident in) a given device.
An application requests a font by creating a font object using the CreateFont or CreateFontIndirect function. The font attributes that are required by these functions define a logical font. When the logical font is selected into a device context using SelectObject. Windows replaces this logical font by a physical font on the user's system that forms the "closest" match to the logical font.
To do this, Windows applies a font-mapping algorithm. The process is call font realization. TrueType fonts are simply rendered on the device. Simply put, for non-TrueType fonts, Windows chooses the closest device font by assigning a relative
Page 429
importance to various font characteristics, the most important of which are (in decreasing order of importance): typeface name, character set, variable versus fixed pitch, family, height, width, weight, slant, underline, and strikeout.
Font Structures
There are more than two dozen structures associated with fonts, but two of them stand out. The LOGFONT structure describes a logical font:
Public Const LF_FACESIZE = 32
Type LOGFONT lfHeight As Long lfWidth As Long lfEscapement As Long lfOrientation As Long lfWeight As Long lfItalic As Byte lfUnderline As Byte lfStrikeOut As Byte lfCharSet As Byte lfOutPrecision As Byte lfClipPrecision As Byte lfQuality As Byte lfPitchAndFamily As Byte lfFaceName (1 To LF_FACESIZE) As Byte End Type
and the TEXTMETRIC structure describes a physical font:
Type TEXTMETRIC tmHeight As Long tmAscent As Long tmDescent As Long tmInternalLeading As Long tmExternalLeading As Long tmAveCharWidth As Long tmMaxCharWidth As Long tmWeight As Long tmOverhang As Long tmDigitizedAspectX As Long tmDigitizedAspectY As Long tmFirstChar As Byte tmLastChar As Byte tmDefaultChar As Byte tmBreakChar As Byte tmItalic As Byte tmUnderlined As Byte tmStruckOut As Byte tmPitchAndFamily As Byte tmCharSet As Byte End Type
Page 430
The CreateFont function is used to create a logical font object. Its parameters mimic the members of a LOGFONT structure.
Declare Function CreateFont Lib "gdi32" Alias "CreateFontA" ( _ ByVal nHeight As Long, _ ByVal nWidth As Long, _ ByVal nEscapement As Long, _ ByVal nOrientation As Long, _ ByVal fnWeight As Long, _ ByVal fdwItalic As long, _ ByVal fdwUnderline As Long, _ ByVal fdwStrikeOut As Long, _ ByVal fdwCharSet As Long, _ ByVal fdwOutputPrecision As Long, _ ByVal fdwClipPrecision As Long, _ ByVal fdwQuality As Long, _ ByVal fdwPitchAndFamily As Long, _ ByVal lpszFace As String _ ) As Long
The CreateFontIndirect function does essentially the same thing:
Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" ( _ lpLogFont As LOGFONT _ ) As Long
We will not go into the details of what all of these structure members mean. (Many of them are fairly evident.)
Getting the Current Logical/Physical Font
The GetTextMetrics API function returns a TextMetric structure for the currently realized physical font of a device context. The syntax is:
BOOL GetTextMetrics( HDC hdc, // handle of device context LPTEXTMETRIC 1ptm // address of text metrics structure );
or, in VB:
Declare Function GetTextMetrics Lib "gdi32" Alias "GetTextMetricsA" ( _ ByVal hdc As Long, _ lpMetrics As TEXTMETRIC _ ) As Long
To get the logical font that was selected into a device context, we need to proceed a bit more circuitously. The SelectObject function:
HGDIOBJ SelectObject( HDC hdc, // handle of device context HGDIOBJ hgdiobj // handle of object );
Page 431
returns a handle to the previous object of the specified type that was selected into the device context. Accordingly, we can temporarily select a new font into the device context, just to get the return value of SelectObject. We then immediately restore the original logical font:
Const SYSTEM_FONT = 13 Dim hCurrentFont As Long Dim lf As LOGFONT
' Get handle to current font hCurrentFont = SelectObject(Me.hdc, GetStockObject(SYSTEM_FONT)) ' Get current font info GetObject API hCurrentFont, LenB(lf), lf ' Restore font SelectObject Me.hdc, hCurrentFont
Debug.Print StrConv(lf.lfFaceName, vbUnicode)
Enumerating Fonts
The EnumFontFamiliesEx function can be used to enumerate the fonts on a system:
int EnumFontFamiliesEx( HDC hdc, // handle to device context LPLOGFONT lpLogfont, // pointer to logical font information FONTENUMPROC lpEnumFontFamExProc, // pointer to callback function LPARAM lParam, // application-supplied data DWORD dwFlags // reserved; must be zero );
This enumeration function uses a callback function, as does EnumWindows, for instance. Thus, we need a function to call EnumFontFamiliesEx:
This will produce the list of fonts shown in Figure 25-2.
Figure 25-2. Viewing fonts
Finally, to see a sample of the selected font in a picture box (see Figure 25-2), we have the following code, which uses CreateFont to create the selected font object, and SelectObject to select that font into the picture box:
Private Sub List1_Click()
' Create font and select it into Text1
Page 433
Dim hFont As Long Dim v As Variant
If List1.ListIndex = -1 Then Exit Sub
pic.Refresh
' Get the face name v = Split(List1.List(List1.ListIndex), "_", -1