HOWTO: Determine When Font Creation Was Successful

ID: Q230342


The information in this article applies to:


SUMMARY

Windows operating systems use a "best match" approach to font creation and use in applications. It may be useful to determine if a realized font used in a Windows Device Context matches the logical description used when the font was created. This can be determined by comparing the physical, or realized, font attributes to the ideal, or logical, attributes.


MORE INFORMATION

Windows applications use different fonts by first creating a font with one of the CreateFont() functions and then selecting this font into a Device Context (DC) with the SelectObject() function. The CreateFont() functions do not actually create a font; rather, they create a description of the desired font per the members of the LOGFONT structure. The process of finding a font in the system that matches this description is called font mapping. Font mapping occurs as a result of selecting and using the logical description of the font with the SelectObject() function. The whole process of creating and selecting a logical font description for use is commonly referred to as font creation.

The process of font mapping searches the list of installed fonts to find the font that best matches the logical description. The process of font mapping is discussed and described by the Technical Article titled, "Windows Font Mapping" as noted in the REFERENCES section of this article.

Because font mapping is a best match technique, it technically cannot fail. However, the physical font that is selected (or realized) as a result of the mapping process may not exactly match the logical description provided by the application. This problem can occur when the logical description describes a font that does not exist in the system. In this scenario, the font mapper chooses a font that most closely matches the logical description.

This problem is best described as a failure of the font mapper to find a font that exactly matches the logical description. Conversely, successful font creation (font mapping) can be defined as a case when at least some of the logical attributes of a font match.

To determine the "success" of font creation, compare the attributes of the realized font [the physical font in the DC resulting from the SelectObject() function call] to the attributes of the logical font (the description of the font created by the application).

The attributes of the logical description of the font created and selected into a DC by the application can be retrieved by calling the GetCurrentObject() and GetObject() functions. The result of these function calls is a LOGFONT structure identical to the one passed as a parameter to one of the CreateFont() functions.

The actual attributes of the realized font in the DC corresponding to the selected logical font are retrieved with the GetTextFace() and GetTextMetrics() functions. These functions return the physical attributes of the realized font that is in the Device Context.

A software developer should be careful when formulating comparisons between the realized font's attributes and the logical font description because there no one-to-one correspondence between attributes may exist. However, any particular attribute of the logical font description does have an analogous or at least inferred attribute in the realized font's metrics.

The following sample code implements a function that determines the "success" of font creation. The FontMappingSuccess() function determines success by pulling the realized font's attributes and the logical font description from the DC and making a comparison. The comparison is performed in the CompareFonts() function.

The CompareFonts() function implements the comparisons to determine if the logical font meets certain criteria to be considered a match, and thus whether a successful mapping occurred. The suite of tests used in this function represents the software developer's subjective definition of success.

As implemented, the CompareFonts() function returns TRUE based upon the generally accepted definition of matching fonts. That is, that the character set, pitch, typeface name, italic, and required font technology criteria match. Note that additional restrictive comparisons are possible, such as checking weights, character size, and so.

Sample Code


BOOL CompareFonts(
    const TEXTMETRIC *ptm, 
    const TCHAR *pFaceName, 
    const LOGFONT lf
    )
// 
//  Comparisons made in roughly the same order that the font mapper 
//  weights any given font. 
// 
//  See Technical Article: "Windows Font Mapping" by Ron Gery
// 
{
    BOOL bTTRequired;
    BOOL bTTRealized;
    
    // Compare character sets if they were specified;
    // if character sets don't compare, then fonts are not 
    // even similar.
    if (lf.lfCharSet != DEFAULT_CHARSET)
    {
        if (lf.lfCharSet != ptm->tmCharSet) return FALSE;
    }
    
    // Compare pitch if the pitch bits are set.
    // Note counter-intuitive nature of TextMetric.tmPitchAndFamily, 
    // see Platform SDK docs.
    if (lf.lfPitchAndFamily & 0x03)
    {
        BOOL bFixedPitchRequired = (lf.lfPitchAndFamily & FIXED_PITCH) > 0;
        BOOL bFixedPitchRealized = !((ptm->tmPitchAndFamily & TMPF_FIXED_PITCH) > 0);

        if ( bFixedPitchRequired != bFixedPitchRealized )
            return FALSE;
    }

    // Compare TT flags.
    // Was TrueType only requested?
    bTTRequired = (lf.lfOutPrecision & OUT_TT_ONLY_PRECIS) > 0;

    if (bTTRequired)
    {
        // Is the realized font TT?
        bTTRealized = (ptm->tmPitchAndFamily & TMPF_TRUETYPE) > 0;

        // Do they match?
        if ( bTTRequired != bTTRealized )
            return FALSE;
    }

    // Compare only if a facename was supplied.
    if ( lstrlen( lf.lfFaceName ) > 0 )
    {
        // NOTE: a stricter comparison would be case-sensitive.
        if ( lstrcmpi( pFaceName, lf.lfFaceName ) != 0 ) 
            return FALSE;
    }

    if ((BOOL)(lf.lfItalic) != (BOOL)(ptm->tmItalic)) return FALSE;

    // This is sufficient to determine most "successful" font mappings.
    // Even more restrictive comparisons can compare:
    //      Type Families via lf.lfPitchAndFamily
    //      Font technology: Device, Raster, TrueType, and so on
    //      Height: Realized size equals or "close" to LOGFONT request
    //      Width
    //      Weight
    //      Underline
    //      Strikeout


    return TRUE;

} /* End of function CompareFonts. */ 

BOOL FontMappingSuccess(const HDC hdc)
{
    BOOL                bMatched = FALSE;
    TEXTMETRIC          tm;
    LOGFONT             lf;
    TCHAR   szFaceName[LF_FACESIZE];

    GetObject( GetCurrentObject( hdc, OBJ_FONT ), 
        sizeof(lf), 
        (LPVOID) &lf );

    // Get the info for the currently realized font.
    GetTextMetrics( hdc, &tm );
    GetTextFace( hdc, sizeof(szFaceName), szFaceName );

    // Compare realized to logical font description to 
    // determine mapping success.
    bMatched = CompareFonts( &tm, szFaceName, lf );

    return bMatched;

} /* End of function FontMappingSuccess. */ 
 


The font mapping process used by Windows may not be desirable to some applications. Those applications that that want more direct control over the font creation process should use the EnumFontFamilies() group of functions to enumerate the list of installed fonts. The application can then judge the most appropriate font using its own criteria.

As part of the enumeration, the application receives a completed LOGFONT structure for each font. Once a font has been selected, the complete LOGFONT structure should be used in the font creation process. Because the LOGFONT structure completely describes a font that is available, the font creation process will be successful. That is, the font mapping process will realize to the font for which the completed LOGFONT structure was enumerated.


REFERENCES

For additional information about Font Mapping in Windows Operating Systems, please see the following article on MSDN:

"Windows Font Mapping" - a Technical Article by Ron Gery

Additional query words:


Keywords          : kbFont kbGDI kbSDKWin32 kbTTFonts kbGrpGDI 
Version           : winnt:
Platform          : winnt 
Issue type        : kbhowto 

Last Reviewed: May 21, 1999