/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinfont.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinfont.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

sf_code/esrgpcpj/shared/tk_base/tkwinfont.c revision 25 by dashley, Sat Oct 8 06:43:03 2016 UTC projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinfont.c revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkwinfont.c,v 1.1.1.1 2001/06/13 05:13:30 dtashley Exp $ */  
   
 /*  
  * tkWinFont.c --  
  *  
  *      Contains the Windows implementation of the platform-independant  
  *      font package interface.  
  *  
  * Copyright (c) 1994 Software Research Associates, Inc.  
  * Copyright (c) 1995-1997 Sun Microsystems, Inc.  
  * Copyright (c) 1998-1999 by Scriptics Corporation.  
  *  
  * See the file "license.terms" for information on usage and redistribution  
  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.  
  *  
  * RCS: @(#) $Id: tkwinfont.c,v 1.1.1.1 2001/06/13 05:13:30 dtashley Exp $  
  */  
   
 #include "tkWinInt.h"  
 #include "tkFont.h"  
   
 /*  
  * The following structure represents a font family.  It is assumed that  
  * all screen fonts constructed from the same "font family" share certain  
  * properties; all screen fonts with the same "font family" point to a  
  * shared instance of this structure.  The most important shared property  
  * is the character existence metrics, used to determine if a screen font  
  * can display a given Unicode character.  
  *  
  * Under Windows, a "font family" is uniquely identified by its face name.  
  */  
   
 #define FONTMAP_SHIFT       10  
   
 #define FONTMAP_PAGES           (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT))  
 #define FONTMAP_BITSPERPAGE     (1 << FONTMAP_SHIFT)  
   
 typedef struct FontFamily {  
     struct FontFamily *nextPtr; /* Next in list of all known font families. */  
     int refCount;               /* How many SubFonts are referring to this  
                                  * FontFamily.  When the refCount drops to  
                                  * zero, this FontFamily may be freed. */  
     /*  
      * Key.  
      */  
       
     Tk_Uid faceName;            /* Face name key for this FontFamily. */  
   
     /*  
      * Derived properties.  
      */  
       
     Tcl_Encoding encoding;      /* Encoding for this font family. */  
     int isSymbolFont;           /* Non-zero if this is a symbol font. */  
     int isWideFont;             /* 1 if this is a double-byte font, 0  
                                  * otherwise. */  
     BOOL (WINAPI *textOutProc)(HDC, int, int, TCHAR *, int);  
                                 /* The procedure to use to draw text after  
                                  * it has been converted from UTF-8 to the  
                                  * encoding of this font. */  
     BOOL (WINAPI *getTextExtentPoint32Proc)(HDC, TCHAR *, int, LPSIZE);  
                                 /* The procedure to use to measure text after  
                                  * it has been converted from UTF-8 to the  
                                  * encoding of this font. */  
   
     char *fontMap[FONTMAP_PAGES];  
                                 /* Two-level sparse table used to determine  
                                  * quickly if the specified character exists.  
                                  * As characters are encountered, more pages  
                                  * in this table are dynamically added.  The  
                                  * contents of each page is a bitmask  
                                  * consisting of FONTMAP_BITSPERPAGE bits,  
                                  * representing whether this font can be used  
                                  * to display the given character at the  
                                  * corresponding bit position.  The high bits  
                                  * of the character are used to pick which  
                                  * page of the table is used. */  
   
     /*  
      * Cached Truetype font info.  
      */  
       
     int segCount;               /* The length of the following arrays. */  
     USHORT *startCount;         /* Truetype information about the font, */  
     USHORT *endCount;           /* indicating which characters this font  
                                  * can display (malloced).  The format of  
                                  * this information is (relatively) compact,  
                                  * but would take longer to search than  
                                  * indexing into the fontMap[][] table. */  
 } FontFamily;  
   
 /*  
  * The following structure encapsulates an individual screen font.  A font  
  * object is made up of however many SubFonts are necessary to display a  
  * stream of multilingual characters.  
  */  
   
 typedef struct SubFont {  
     char **fontMap;             /* Pointer to font map from the FontFamily,  
                                  * cached here to save a dereference. */  
     HFONT hFont;                /* The specific screen font that will be  
                                  * used when displaying/measuring chars  
                                  * belonging to the FontFamily. */  
     FontFamily *familyPtr;      /* The FontFamily for this SubFont. */  
 } SubFont;  
   
 /*  
  * The following structure represents Windows' implementation of a font  
  * object.  
  */  
   
 #define SUBFONT_SPACE           3  
 #define BASE_CHARS              128  
   
 typedef struct WinFont {  
     TkFont font;                /* Stuff used by generic font package.  Must  
                                  * be first in structure. */  
     SubFont staticSubFonts[SUBFONT_SPACE];  
                                 /* Builtin space for a limited number of  
                                  * SubFonts. */  
     int numSubFonts;            /* Length of following array. */  
     SubFont *subFontArray;      /* Array of SubFonts that have been loaded  
                                  * in order to draw/measure all the characters  
                                  * encountered by this font so far.  All fonts  
                                  * start off with one SubFont initialized by  
                                  * AllocFont() from the original set of font  
                                  * attributes.  Usually points to  
                                  * staticSubFonts, but may point to malloced  
                                  * space if there are lots of SubFonts. */  
   
     HWND hwnd;                  /* Toplevel window of application that owns  
                                  * this font, used for getting HDC for  
                                  * offscreen measurements. */  
     int pixelSize;              /* Original pixel size used when font was  
                                  * constructed. */  
     int widths[BASE_CHARS];     /* Widths of first 128 chars in the base  
                                  * font, for handling common case.  The base  
                                  * font is always used to draw characters  
                                  * between 0x0000 and 0x007f. */  
 } WinFont;  
   
 /*  
  * The following structure is passed as the LPARAM when calling the font  
  * enumeration procedure to determine if a font can support the given  
  * character.  
  */  
   
 typedef struct CanUse {  
     HDC hdc;  
     WinFont *fontPtr;  
     Tcl_DString *nameTriedPtr;  
     int ch;  
     SubFont *subFontPtr;  
 } CanUse;  
   
 /*  
  * The following structure is used to map between the Tcl strings that  
  * represent the system fonts and the numbers used by Windows.  
  */  
   
 static TkStateMap systemMap[] = {  
     {ANSI_FIXED_FONT,       "ansifixed"},  
     {ANSI_VAR_FONT,         "ansi"},  
     {DEVICE_DEFAULT_FONT,   "device"},  
     {OEM_FIXED_FONT,        "oemfixed"},  
     {SYSTEM_FIXED_FONT,     "systemfixed"},  
     {SYSTEM_FONT,           "system"},  
     {-1,                    NULL}  
 };  
   
 typedef struct ThreadSpecificData {  
     FontFamily *fontFamilyList; /* The list of font families that are  
                                  * currently loaded.  As screen fonts  
                                  * are loaded, this list grows to hold  
                                  * information about what characters  
                                  * exist in each font family.  */  
     Tcl_HashTable uidTable;  
 } ThreadSpecificData;  
 static Tcl_ThreadDataKey dataKey;  
   
 /*  
  * Information cached about the system at startup time.  
  */  
   
 static Tcl_Encoding unicodeEncoding;  
 static Tcl_Encoding systemEncoding;  
   
 /*  
  * Procedures used only in this file.  
  */  
   
 static FontFamily *     AllocFontFamily(HDC hdc, HFONT hFont, int base);  
 static SubFont *        CanUseFallback(HDC hdc, WinFont *fontPtr,  
                             char *fallbackName, int ch);  
 static SubFont *        CanUseFallbackWithAliases(HDC hdc, WinFont *fontPtr,  
                             char *faceName, int ch, Tcl_DString *nameTriedPtr);  
 static int              FamilyExists(HDC hdc, CONST char *faceName);  
 static char *           FamilyOrAliasExists(HDC hdc, CONST char *faceName);  
 static SubFont *        FindSubFontForChar(WinFont *fontPtr, int ch);  
 static void             FontMapInsert(SubFont *subFontPtr, int ch);  
 static void             FontMapLoadPage(SubFont *subFontPtr, int row);  
 static int              FontMapLookup(SubFont *subFontPtr, int ch);  
 static void             FreeFontFamily(FontFamily *familyPtr);  
 static HFONT            GetScreenFont(CONST TkFontAttributes *faPtr,  
                             CONST char *faceName, int pixelSize);  
 static void             InitFont(Tk_Window tkwin, HFONT hFont,  
                             int overstrike, WinFont *tkFontPtr);  
 static void             InitSubFont(HDC hdc, HFONT hFont, int base,  
                             SubFont *subFontPtr);  
 static int              LoadFontRanges(HDC hdc, HFONT hFont,  
                             USHORT **startCount, USHORT **endCount,  
                             int *symbolPtr);  
 static void             MultiFontTextOut(HDC hdc, WinFont *fontPtr,  
                             CONST char *source, int numBytes, int x, int y);  
 static void             ReleaseFont(WinFont *fontPtr);  
 static void             ReleaseSubFont(SubFont *subFontPtr);  
 static int              SeenName(CONST char *name, Tcl_DString *dsPtr);  
 static void             SwapLong(PULONG p);  
 static void             SwapShort(USHORT *p);  
 static int CALLBACK     WinFontCanUseProc(ENUMLOGFONT *lfPtr,  
                             NEWTEXTMETRIC *tmPtr, int fontType,  
                             LPARAM lParam);  
 static int CALLBACK     WinFontExistProc(ENUMLOGFONT *lfPtr,  
                             NEWTEXTMETRIC *tmPtr, int fontType,  
                             LPARAM lParam);  
 static int CALLBACK     WinFontFamilyEnumProc(ENUMLOGFONT *lfPtr,  
                             NEWTEXTMETRIC *tmPtr, int fontType,  
                             LPARAM lParam);  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * TkpFontPkgInit --  
  *  
  *      This procedure is called when an application is created.  It  
  *      initializes all the structures that are used by the  
  *      platform-dependent code on a per application basis.  
  *  
  * Results:  
  *      None.    
  *  
  * Side effects:  
  *        
  *      None.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 void  
 TkpFontPkgInit(  
     TkMainInfo *mainPtr)        /* The application being created. */  
 {  
     unicodeEncoding = Tcl_GetEncoding(NULL, "unicode");  
     if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {  
         /*  
          * If running NT, then we will be calling some Unicode functions  
          * explictly.  So, even if the Tcl system encoding isn't Unicode,  
          * make sure we convert to/from the Unicode char set.  
          */  
   
         systemEncoding = unicodeEncoding;  
     }  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * TkpGetNativeFont --  
  *  
  *      Map a platform-specific native font name to a TkFont.  
  *  
  * Results:  
  *      The return value is a pointer to a TkFont that represents the  
  *      native font.  If a native font by the given name could not be  
  *      found, the return value is NULL.    
  *  
  *      Every call to this procedure returns a new TkFont structure,  
  *      even if the name has already been seen before.  The caller should  
  *      call TkpDeleteFont() when the font is no longer needed.  
  *  
  *      The caller is responsible for initializing the memory associated  
  *      with the generic TkFont when this function returns and releasing  
  *      the contents of the generic TkFont before calling TkpDeleteFont().  
  *  
  * Side effects:  
  *      Memory allocated.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 TkFont *  
 TkpGetNativeFont(  
     Tk_Window tkwin,            /* For display where font will be used. */  
     CONST char *name)           /* Platform-specific font name. */  
 {  
     int object;  
     WinFont *fontPtr;  
   
     object = TkFindStateNum(NULL, NULL, systemMap, name);  
     if (object < 0) {  
         return NULL;  
     }  
   
     tkwin = (Tk_Window) ((TkWindow *) tkwin)->mainPtr->winPtr;  
     fontPtr = (WinFont *) ckalloc(sizeof(WinFont));  
     InitFont(tkwin, GetStockObject(object), 0, fontPtr);  
   
     return (TkFont *) fontPtr;  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * TkpGetFontFromAttributes --  
  *  
  *      Given a desired set of attributes for a font, find a font with  
  *      the closest matching attributes.  
  *  
  * Results:  
  *      The return value is a pointer to a TkFont that represents the  
  *      font with the desired attributes.  If a font with the desired  
  *      attributes could not be constructed, some other font will be  
  *      substituted automatically.  NULL is never returned.  
  *  
  *      Every call to this procedure returns a new TkFont structure,  
  *      even if the specified attributes have already been seen before.  
  *      The caller should call TkpDeleteFont() to free the platform-  
  *      specific data when the font is no longer needed.    
  *  
  *      The caller is responsible for initializing the memory associated  
  *      with the generic TkFont when this function returns and releasing  
  *      the contents of the generic TkFont before calling TkpDeleteFont().  
  *  
  * Side effects:  
  *      Memory allocated.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 TkFont *  
 TkpGetFontFromAttributes(  
     TkFont *tkFontPtr,          /* If non-NULL, store the information in  
                                  * this existing TkFont structure, rather than  
                                  * allocating a new structure to hold the  
                                  * font; the existing contents of the font  
                                  * will be released.  If NULL, a new TkFont  
                                  * structure is allocated. */  
     Tk_Window tkwin,            /* For display where font will be used. */  
     CONST TkFontAttributes *faPtr)  
                                 /* Set of attributes to match. */  
 {  
     int i, j;  
     HDC hdc;  
     HWND hwnd;  
     HFONT hFont;  
     Window window;  
     WinFont *fontPtr;  
     char ***fontFallbacks;  
     char *faceName, *fallback, *actualName;  
   
     tkwin   = (Tk_Window) ((TkWindow *) tkwin)->mainPtr->winPtr;  
     window  = Tk_WindowId(tkwin);  
     hwnd    = (window == None) ? NULL : TkWinGetHWND(window);  
     hdc     = GetDC(hwnd);  
   
     /*  
      * Algorithm to get the closest font name to the one requested.  
      *  
      * try fontname  
      * try all aliases for fontname  
      * foreach fallback for fontname  
      *      try the fallback  
      *      try all aliases for the fallback  
      */  
   
     faceName = faPtr->family;  
     if (faceName != NULL) {  
         actualName = FamilyOrAliasExists(hdc, faceName);  
         if (actualName != NULL) {  
             faceName = actualName;  
             goto found;  
         }  
         fontFallbacks = TkFontGetFallbacks();  
         for (i = 0; fontFallbacks[i] != NULL; i++) {  
             for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {  
                 if (strcasecmp(faceName, fallback) == 0) {  
                     break;  
                 }  
             }  
             if (fallback != NULL) {  
                 for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {  
                     actualName = FamilyOrAliasExists(hdc, fallback);  
                     if (actualName != NULL) {  
                         faceName = actualName;  
                         goto found;  
                     }  
                 }  
             }  
         }  
     }  
   
     found:  
     ReleaseDC(hwnd, hdc);  
   
     hFont = GetScreenFont(faPtr, faceName, TkFontGetPixels(tkwin, faPtr->size));  
     if (tkFontPtr == NULL) {  
         fontPtr = (WinFont *) ckalloc(sizeof(WinFont));  
     } else {  
         fontPtr = (WinFont *) tkFontPtr;  
         ReleaseFont(fontPtr);  
     }  
     InitFont(tkwin, hFont, faPtr->overstrike, fontPtr);  
   
     return (TkFont *) fontPtr;  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * TkpDeleteFont --  
  *  
  *      Called to release a font allocated by TkpGetNativeFont() or  
  *      TkpGetFontFromAttributes().  The caller should have already  
  *      released the fields of the TkFont that are used exclusively by  
  *      the generic TkFont code.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      TkFont is deallocated.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 void  
 TkpDeleteFont(  
     TkFont *tkFontPtr)          /* Token of font to be deleted. */  
 {  
     WinFont *fontPtr;  
   
     fontPtr = (WinFont *) tkFontPtr;  
     ReleaseFont(fontPtr);  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * TkpGetFontFamilies, WinFontFamilyEnumProc --  
  *  
  *      Return information about the font families that are available  
  *      on the display of the given window.  
  *  
  * Results:  
  *      Modifies interp's result object to hold a list of all the available  
  *      font families.  
  *  
  * Side effects:  
  *      None.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 void  
 TkpGetFontFamilies(  
     Tcl_Interp *interp,         /* Interp to hold result. */  
     Tk_Window tkwin)            /* For display to query. */  
 {      
     HDC hdc;  
     HWND hwnd;  
     Window window;  
   
     window  = Tk_WindowId(tkwin);  
     hwnd    = (window == None) ? NULL : TkWinGetHWND(window);  
     hdc     = GetDC(hwnd);  
   
     /*  
      * On any version NT, there may fonts with international names.    
      * Use the NT-only Unicode version of EnumFontFamilies to get the  
      * font names.  If we used the ANSI version on a non-internationalized  
      * version of NT, we would get font names with '?' replacing all  
      * the international characters.  
      *  
      * On a non-internationalized verson of 95, fonts with international  
      * names are not allowed, so the ANSI version of EnumFontFamilies will  
      * work.  On an internationalized version of 95, there may be fonts with  
      * international names; the ANSI version will work, fetching the  
      * name in the system code page.  Can't use the Unicode version of  
      * EnumFontFamilies because it only exists under NT.  
      */  
   
     if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {  
         EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontFamilyEnumProc,  
                 (LPARAM) interp);  
     } else {  
         EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontFamilyEnumProc,  
                 (LPARAM) interp);  
     }        
     ReleaseDC(hwnd, hdc);  
 }  
   
 static int CALLBACK  
 WinFontFamilyEnumProc(  
     ENUMLOGFONT *lfPtr,         /* Logical-font data. */  
     NEWTEXTMETRIC *tmPtr,       /* Physical-font data (not used). */  
     int fontType,               /* Type of font (not used). */  
     LPARAM lParam)              /* Result object to hold result. */  
 {  
     char *faceName;  
     Tcl_DString faceString;  
     Tcl_Obj *strPtr;  
     Tcl_Interp *interp;  
   
     interp = (Tcl_Interp *) lParam;  
     faceName = lfPtr->elfLogFont.lfFaceName;  
     Tcl_ExternalToUtfDString(systemEncoding, faceName, -1, &faceString);  
     strPtr = Tcl_NewStringObj(Tcl_DStringValue(&faceString),  
             Tcl_DStringLength(&faceString));  
     Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr);  
     Tcl_DStringFree(&faceString);  
     return 1;  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * TkpGetSubFonts --  
  *  
  *      A function used by the testing package for querying the actual  
  *      screen fonts that make up a font object.  
  *  
  * Results:  
  *      Modifies interp's result object to hold a list containing the  
  *      names of the screen fonts that make up the given font object.  
  *  
  * Side effects:  
  *      None.  
  *  
  *-------------------------------------------------------------------------  
  */  
           
 void  
 TkpGetSubFonts(  
     Tcl_Interp *interp,         /* Interp to hold result. */  
     Tk_Font tkfont)             /* Font object to query. */  
 {  
     int i;  
     WinFont *fontPtr;  
     FontFamily *familyPtr;  
     Tcl_Obj *resultPtr, *strPtr;  
   
     resultPtr = Tcl_GetObjResult(interp);      
     fontPtr = (WinFont *) tkfont;  
     for (i = 0; i < fontPtr->numSubFonts; i++) {  
         familyPtr = fontPtr->subFontArray[i].familyPtr;  
         strPtr = Tcl_NewStringObj(familyPtr->faceName, -1);  
         Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);  
     }  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  *  Tk_MeasureChars --  
  *  
  *      Determine the number of bytes from the string that will fit  
  *      in the given horizontal span.  The measurement is done under the  
  *      assumption that Tk_DrawChars() will be used to actually display  
  *      the characters.  
  *  
  * Results:  
  *      The return value is the number of bytes from source that  
  *      fit into the span that extends from 0 to maxLength.  *lengthPtr is  
  *      filled with the x-coordinate of the right edge of the last  
  *      character that did fit.  
  *  
  * Side effects:  
  *      None.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 int  
 Tk_MeasureChars(  
     Tk_Font tkfont,             /* Font in which characters will be drawn. */  
     CONST char *source,         /* UTF-8 string to be displayed.  Need not be  
                                  * '\0' terminated. */  
     int numBytes,               /* Maximum number of bytes to consider  
                                  * from source string. */  
     int maxLength,              /* If >= 0, maxLength specifies the longest  
                                  * permissible line length in pixels; don't  
                                  * consider any character that would cross  
                                  * this x-position.  If < 0, then line length  
                                  * is unbounded and the flags argument is  
                                  * ignored. */  
     int flags,                  /* Various flag bits OR-ed together:  
                                  * TK_PARTIAL_OK means include the last char  
                                  * which only partially fit on this line.  
                                  * TK_WHOLE_WORDS means stop on a word  
                                  * boundary, if possible.  
                                  * TK_AT_LEAST_ONE means return at least one  
                                  * character even if no characters fit. */  
     int *lengthPtr)             /* Filled with x-location just after the  
                                  * terminating character. */  
 {  
     HDC hdc;  
     HFONT oldFont;  
     WinFont *fontPtr;  
     int curX, curByte;  
     SubFont *lastSubFontPtr;  
   
     /*  
      * According to Microsoft tech support, Windows does not use kerning  
      * or fractional character widths when displaying text on the screen.  
      * So that means we can safely measure individual characters or spans  
      * of characters and add up the widths w/o any "off-by-one-pixel"  
      * errors.    
      */  
   
     fontPtr = (WinFont *) tkfont;  
   
     hdc = GetDC(fontPtr->hwnd);  
     lastSubFontPtr = &fontPtr->subFontArray[0];  
     oldFont = SelectObject(hdc, lastSubFontPtr->hFont);  
   
     if (numBytes == 0) {  
         curX = 0;  
         curByte = 0;  
     } else if (maxLength < 0) {                            
         Tcl_UniChar ch;  
         SIZE size;  
         FontFamily *familyPtr;  
         Tcl_DString runString;  
         SubFont *thisSubFontPtr;  
         CONST char *p, *end, *next;  
   
         /*  
          * A three step process:  
          * 1. Find a contiguous range of characters that can all be  
          *    represented by a single screen font.  
          * 2. Convert those chars to the encoding of that font.  
          * 3. Measure converted chars.  
          */  
   
         curX = 0;  
         end = source + numBytes;  
         for (p = source; p < end; ) {  
             next = p + Tcl_UtfToUniChar(p, &ch);  
             thisSubFontPtr = FindSubFontForChar(fontPtr, ch);  
             if (thisSubFontPtr != lastSubFontPtr) {  
                 familyPtr = lastSubFontPtr->familyPtr;  
                 Tcl_UtfToExternalDString(familyPtr->encoding, source,  
                         p - source, &runString);  
                 (*familyPtr->getTextExtentPoint32Proc)(hdc,  
                         Tcl_DStringValue(&runString),  
                         Tcl_DStringLength(&runString) >> familyPtr->isWideFont,  
                         &size);  
                 curX += size.cx;  
                 Tcl_DStringFree(&runString);  
                 lastSubFontPtr = thisSubFontPtr;  
                 source = p;  
   
                 SelectObject(hdc, lastSubFontPtr->hFont);  
             }  
             p = next;  
         }  
         familyPtr = lastSubFontPtr->familyPtr;  
         Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,  
                 &runString);  
         (*familyPtr->getTextExtentPoint32Proc)(hdc,  
                 Tcl_DStringValue(&runString),  
                 Tcl_DStringLength(&runString) >> familyPtr->isWideFont,  
                 &size);  
         curX += size.cx;  
         Tcl_DStringFree(&runString);  
         curByte = numBytes;  
     } else {  
         Tcl_UniChar ch;  
         SIZE size;  
         char buf[16];  
         FontFamily *familyPtr;  
         SubFont *thisSubFontPtr;  
         CONST char *term, *end, *p, *next;  
         int newX, termX, sawNonSpace, dstWrote;  
   
         /*  
          * How many chars will fit in the space allotted?  
          * This first version may be inefficient because it measures  
          * every character individually.  There is a function call that  
          * can measure multiple characters at once and return the  
          * offset of each of them, but it only works on NT, even though  
          * the documentation claims it works for 95.  
          * TODO: verify that GetTextExtentExPoint is still broken in '95, and  
          * possibly use it for NT anyway since it should be much faster and  
          * more accurate.  
          */  
   
         next = source + Tcl_UtfToUniChar(source, &ch);  
         newX = curX = termX = 0;  
           
         term = source;  
         end = source + numBytes;  
   
         sawNonSpace = (ch > 255) || !isspace(ch);  
         for (p = source; ; ) {  
             if (ch < BASE_CHARS) {  
                 newX += fontPtr->widths[ch];  
             } else {  
                 thisSubFontPtr = FindSubFontForChar(fontPtr, ch);  
                 if (thisSubFontPtr != lastSubFontPtr) {  
                     SelectObject(hdc, thisSubFontPtr->hFont);  
                     lastSubFontPtr = thisSubFontPtr;  
                 }  
                 familyPtr = lastSubFontPtr->familyPtr;  
                 Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p,  
                         0, NULL, buf, sizeof(buf), NULL, &dstWrote, NULL);  
                 (*familyPtr->getTextExtentPoint32Proc)(hdc, buf,  
                         dstWrote >> familyPtr->isWideFont, &size);  
                 newX += size.cx;  
             }  
             if (newX > maxLength) {  
                 break;  
             }  
             curX = newX;  
             p = next;  
             if (p >= end) {  
                 term = end;  
                 termX = curX;  
                 break;  
             }  
   
             next += Tcl_UtfToUniChar(next, &ch);  
             if ((ch < 256) && isspace(ch)) {  
                 if (sawNonSpace) {  
                     term = p;  
                     termX = curX;  
                     sawNonSpace = 0;  
                 }  
             } else {  
                 sawNonSpace = 1;  
             }  
         }  
   
         /*  
          * P points to the first character that doesn't fit in the desired  
          * span.  Use the flags to figure out what to return.  
          */  
   
         if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) {  
             /*  
              * Include the first character that didn't quite fit in the desired  
              * span.  The width returned will include the width of that extra  
              * character.  
              */  
   
             curX = newX;  
             p += Tcl_UtfToUniChar(p, &ch);  
         }  
         if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) {  
             term = p;  
             termX = curX;  
             if (term == source) {  
                 term += Tcl_UtfToUniChar(term, &ch);  
                 termX = newX;  
             }  
         } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) {  
             term = p;  
             termX = curX;  
         }  
   
         curX = termX;  
         curByte = term - source;          
     }  
   
     SelectObject(hdc, oldFont);  
     ReleaseDC(fontPtr->hwnd, hdc);  
   
     *lengthPtr = curX;  
     return curByte;  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * Tk_DrawChars --  
  *  
  *      Draw a string of characters on the screen.    
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Information gets drawn on the screen.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 void  
 Tk_DrawChars(  
     Display *display,           /* Display on which to draw. */  
     Drawable drawable,          /* Window or pixmap in which to draw. */  
     GC gc,                      /* Graphics context for drawing characters. */  
     Tk_Font tkfont,             /* Font in which characters will be drawn;  
                                  * must be the same as font used in GC. */  
     CONST char *source,         /* UTF-8 string to be displayed.  Need not be  
                                  * '\0' terminated.  All Tk meta-characters  
                                  * (tabs, control characters, and newlines)  
                                  * should be stripped out of the string that  
                                  * is passed to this function.  If they are  
                                  * not stripped out, they will be displayed as  
                                  * regular printing characters. */  
     int numBytes,               /* Number of bytes in string. */  
     int x, int y)               /* Coordinates at which to place origin of  
                                  * string when drawing. */  
 {  
     HDC dc;  
     WinFont *fontPtr;  
     TkWinDCState state;  
   
     fontPtr = (WinFont *) gc->font;  
     display->request++;  
   
     if (drawable == None) {  
         return;  
     }  
   
     dc = TkWinGetDrawableDC(display, drawable, &state);  
   
     SetROP2(dc, tkpWinRopModes[gc->function]);  
   
     if ((gc->fill_style == FillStippled  
             || gc->fill_style == FillOpaqueStippled)  
             && gc->stipple != None) {  
         TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;  
         HBRUSH oldBrush, stipple;  
         HBITMAP oldBitmap, bitmap;  
         HDC dcMem;  
         TEXTMETRIC tm;  
         SIZE size;  
   
         if (twdPtr->type != TWD_BITMAP) {  
             panic("unexpected drawable type in stipple");  
         }  
   
         /*  
          * Select stipple pattern into destination dc.  
          */  
           
         dcMem = CreateCompatibleDC(dc);  
   
         stipple = CreatePatternBrush(twdPtr->bitmap.handle);  
         SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);  
         oldBrush = SelectObject(dc, stipple);  
   
         SetTextAlign(dcMem, TA_LEFT | TA_BASELINE);  
         SetTextColor(dcMem, gc->foreground);  
         SetBkMode(dcMem, TRANSPARENT);  
         SetBkColor(dcMem, RGB(0, 0, 0));  
   
         /*  
          * Compute the bounding box and create a compatible bitmap.  
          */  
   
         GetTextExtentPoint(dcMem, source, numBytes, &size);  
         GetTextMetrics(dcMem, &tm);  
         size.cx -= tm.tmOverhang;  
         bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy);  
         oldBitmap = SelectObject(dcMem, bitmap);  
   
         /*  
          * The following code is tricky because fonts are rendered in multiple  
          * colors.  First we draw onto a black background and copy the white  
          * bits.  Then we draw onto a white background and copy the black bits.  
          * Both the foreground and background bits of the font are ANDed with  
          * the stipple pattern as they are copied.  
          */  
   
         PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS);  
         MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);  
         BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,  
                 0, 0, 0xEA02E9);  
         PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS);  
         MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);  
         BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,  
                 0, 0, 0x8A0E06);  
   
         /*  
          * Destroy the temporary bitmap and restore the device context.  
          */  
   
         SelectObject(dcMem, oldBitmap);  
         DeleteObject(bitmap);  
         DeleteDC(dcMem);  
         SelectObject(dc, oldBrush);  
         DeleteObject(stipple);  
     } else {  
         SetTextAlign(dc, TA_LEFT | TA_BASELINE);  
         SetTextColor(dc, gc->foreground);  
         SetBkMode(dc, TRANSPARENT);  
         MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);  
     }  
     TkWinReleaseDrawableDC(drawable, dc, &state);  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * MultiFontTextOut --  
  *  
  *      Helper function for Tk_DrawChars.  Draws characters, using the  
  *      various screen fonts in fontPtr to draw multilingual characters.  
  *      Note: No bidirectional support.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Information gets drawn on the screen.    
  *      Contents of fontPtr may be modified if more subfonts were loaded  
  *      in order to draw all the multilingual characters in the given  
  *      string.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static void  
 MultiFontTextOut(  
     HDC hdc,                    /* HDC to draw into. */  
     WinFont *fontPtr,           /* Contains set of fonts to use when drawing  
                                  * following string. */  
     CONST char *source,         /* Potentially multilingual UTF-8 string. */  
     int numBytes,               /* Length of string in bytes. */  
     int x, int y)               /* Coordinates at which to place origin *  
                                  * of string when drawing. */  
 {  
     Tcl_UniChar ch;  
     SIZE size;  
     HFONT oldFont;  
     FontFamily *familyPtr;  
     Tcl_DString runString;  
     CONST char *p, *end, *next;  
     SubFont *lastSubFontPtr, *thisSubFontPtr;  
   
     lastSubFontPtr = &fontPtr->subFontArray[0];  
     oldFont = SelectObject(hdc, lastSubFontPtr->hFont);  
   
     end = source + numBytes;  
     for (p = source; p < end; ) {  
         next = p + Tcl_UtfToUniChar(p, &ch);  
         thisSubFontPtr = FindSubFontForChar(fontPtr, ch);  
         if (thisSubFontPtr != lastSubFontPtr) {  
             if (p > source) {  
                 familyPtr = lastSubFontPtr->familyPtr;  
                 Tcl_UtfToExternalDString(familyPtr->encoding, source,  
                         p - source, &runString);  
                 (*familyPtr->textOutProc)(hdc, x, y,  
                         Tcl_DStringValue(&runString),  
                         Tcl_DStringLength(&runString) >> familyPtr->isWideFont);  
                 (*familyPtr->getTextExtentPoint32Proc)(hdc,  
                         Tcl_DStringValue(&runString),  
                         Tcl_DStringLength(&runString) >> familyPtr->isWideFont,  
                         &size);  
                 x += size.cx;  
                 Tcl_DStringFree(&runString);  
             }  
             lastSubFontPtr = thisSubFontPtr;  
             source = p;  
             SelectObject(hdc, lastSubFontPtr->hFont);  
         }  
         p = next;  
     }  
     if (p > source) {  
         familyPtr = lastSubFontPtr->familyPtr;  
         Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,  
                 &runString);  
         (*familyPtr->textOutProc)(hdc, x, y, Tcl_DStringValue(&runString),  
                 Tcl_DStringLength(&runString) >> familyPtr->isWideFont);  
         Tcl_DStringFree(&runString);  
     }  
     SelectObject(hdc, oldFont);  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * InitFont --  
  *  
  *      Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().  
  *      Initializes the memory for a new WinFont that wraps the  
  *      platform-specific data.  
  *  
  *      The caller is responsible for initializing the fields of the  
  *      WinFont that are used exclusively by the generic TkFont code, and  
  *      for releasing those fields before calling TkpDeleteFont().  
  *  
  * Results:  
  *      Fills the WinFont structure.  
  *  
  * Side effects:  
  *      Memory allocated.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 static void  
 InitFont(  
     Tk_Window tkwin,            /* Main window of interp in which font will  
                                  * be used, for getting HDC. */  
     HFONT hFont,                /* Windows token for font. */  
     int overstrike,             /* The overstrike attribute of logfont used  
                                  * to allocate this font.  For some reason,  
                                  * the TEXTMETRICs may contain incorrect info  
                                  * in the tmStruckOut field. */  
     WinFont *fontPtr)           /* Filled with information constructed from  
                                  * the above arguments. */  
 {  
     HDC hdc;  
     HWND hwnd;  
     HFONT oldFont;  
     TEXTMETRIC tm;  
     Window window;  
     TkFontMetrics *fmPtr;  
     Tcl_Encoding encoding;  
     Tcl_DString faceString;  
     TkFontAttributes *faPtr;  
     char buf[LF_FACESIZE * sizeof(WCHAR)];  
   
     window  = Tk_WindowId(tkwin);  
     hwnd    = (window == None) ? NULL : TkWinGetHWND(window);  
     hdc     = GetDC(hwnd);  
     oldFont = SelectObject(hdc, hFont);  
   
     GetTextMetrics(hdc, &tm);  
   
     /*  
      * On any version NT, there may fonts with international names.    
      * Use the NT-only Unicode version of GetTextFace to get the font's  
      * name.  If we used the ANSI version on a non-internationalized  
      * version of NT, we would get a font name with '?' replacing all  
      * the international characters.  
      *  
      * On a non-internationalized verson of 95, fonts with international  
      * names are not allowed, so the ANSI version of GetTextFace will work.  
      * On an internationalized version of 95, there may be fonts with  
      * international names; the ANSI version will work, fetching the  
      * name in the international system code page.  Can't use the Unicode  
      * version of GetTextFace because it only exists under NT.  
      */  
   
     if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {  
         GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf);  
     } else {  
         GetTextFaceA(hdc, LF_FACESIZE, (char *) buf);  
     }  
     Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString);  
   
     fontPtr->font.fid   = (Font) fontPtr;  
   
     faPtr               = &fontPtr->font.fa;  
     faPtr->family       = Tk_GetUid(Tcl_DStringValue(&faceString));  
     faPtr->size         = TkFontGetPoints(tkwin, -(tm.tmHeight - tm.tmInternalLeading));  
     faPtr->weight       = (tm.tmWeight > FW_MEDIUM) ? TK_FW_BOLD : TK_FW_NORMAL;  
     faPtr->slant        = (tm.tmItalic != 0) ? TK_FS_ITALIC : TK_FS_ROMAN;  
     faPtr->underline    = (tm.tmUnderlined != 0) ? 1 : 0;  
     faPtr->overstrike   = overstrike;  
       
     fmPtr               = &fontPtr->font.fm;  
     fmPtr->ascent       = tm.tmAscent;  
     fmPtr->descent      = tm.tmDescent;  
     fmPtr->maxWidth     = tm.tmMaxCharWidth;  
     fmPtr->fixed        = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);  
   
     fontPtr->hwnd       = hwnd;  
     fontPtr->pixelSize  = tm.tmHeight - tm.tmInternalLeading;  
   
     fontPtr->numSubFonts        = 1;  
     fontPtr->subFontArray       = fontPtr->staticSubFonts;  
     InitSubFont(hdc, hFont, 1, &fontPtr->subFontArray[0]);  
   
     encoding = fontPtr->subFontArray[0].familyPtr->encoding;  
     if (encoding == unicodeEncoding) {  
         GetCharWidthW(hdc, 0, BASE_CHARS - 1, fontPtr->widths);  
     } else {  
         GetCharWidthA(hdc, 0, BASE_CHARS - 1, fontPtr->widths);  
     }  
     Tcl_DStringFree(&faceString);  
   
     SelectObject(hdc, oldFont);  
     ReleaseDC(hwnd, hdc);  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * ReleaseFont --  
  *  
  *      Called to release the windows-specific contents of a TkFont.  
  *      The caller is responsible for freeing the memory used by the  
  *      font itself.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Memory is freed.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 static void  
 ReleaseFont(  
     WinFont *fontPtr)           /* The font to delete. */  
 {  
     int i;  
   
     for (i = 0; i < fontPtr->numSubFonts; i++) {  
         ReleaseSubFont(&fontPtr->subFontArray[i]);  
     }  
     if (fontPtr->subFontArray != fontPtr->staticSubFonts) {  
         ckfree((char *) fontPtr->subFontArray);  
     }  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * InitSubFont --  
  *  
  *      Wrap a screen font and load the FontFamily that represents  
  *      it.  Used to prepare a SubFont so that characters can be mapped  
  *      from UTF-8 to the charset of the font.  
  *  
  * Results:  
  *      The subFontPtr is filled with information about the font.  
  *  
  * Side effects:  
  *      None.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static void  
 InitSubFont(  
     HDC hdc,                    /* HDC in which font can be selected. */  
     HFONT hFont,                /* The screen font. */  
     int base,                   /* Non-zero if this SubFont is being used  
                                  * as the base font for a font object. */  
     SubFont *subFontPtr)        /* Filled with SubFont constructed from  
                                  * above attributes. */  
 {  
     subFontPtr->hFont       = hFont;  
     subFontPtr->familyPtr   = AllocFontFamily(hdc, hFont, base);  
     subFontPtr->fontMap     = subFontPtr->familyPtr->fontMap;  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * ReleaseSubFont --  
  *  
  *      Called to release the contents of a SubFont.  The caller is  
  *      responsible for freeing the memory used by the SubFont itself.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Memory and resources are freed.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 static void  
 ReleaseSubFont(  
     SubFont *subFontPtr)        /* The SubFont to delete. */  
 {  
     DeleteObject(subFontPtr->hFont);  
     FreeFontFamily(subFontPtr->familyPtr);  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * AllocFontFamily --  
  *  
  *      Find the FontFamily structure associated with the given font  
  *      name.  The information should be stored by the caller in a  
  *      SubFont and used when determining if that SubFont supports a  
  *      character.  
  *  
  *      Cannot use the string name used to construct the font as the  
  *      key, because the capitalization may not be canonical.  Therefore  
  *      use the face name actually retrieved from the font metrics as  
  *      the key.  
  *  
  * Results:  
  *      A pointer to a FontFamily.  The reference count in the FontFamily  
  *      is automatically incremented.  When the SubFont is released, the  
  *      reference count is decremented.  When no SubFont is using this  
  *      FontFamily, it may be deleted.  
  *  
  * Side effects:  
  *      A new FontFamily structure will be allocated if this font family  
  *      has not been seen.  TrueType character existence metrics are  
  *      loaded into the FontFamily structure.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static FontFamily *  
 AllocFontFamily(  
     HDC hdc,                    /* HDC in which font can be selected. */  
     HFONT hFont,                /* Screen font whose FontFamily is to be  
                                  * returned. */  
     int base)                   /* Non-zero if this font family is to be  
                                  * used in the base font of a font object. */  
 {  
     Tk_Uid faceName;  
     FontFamily *familyPtr;  
     Tcl_DString faceString;  
     Tcl_Encoding encoding;  
     char buf[LF_FACESIZE * sizeof(WCHAR)];  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     hFont = SelectObject(hdc, hFont);  
     if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {  
         GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf);  
     } else {  
         GetTextFaceA(hdc, LF_FACESIZE, (char *) buf);  
     }  
     Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString);  
     faceName = Tk_GetUid(Tcl_DStringValue(&faceString));  
     Tcl_DStringFree(&faceString);  
     hFont = SelectObject(hdc, hFont);  
   
     familyPtr = tsdPtr->fontFamilyList;  
     for ( ; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {  
         if (familyPtr->faceName == faceName) {  
             familyPtr->refCount++;  
             return familyPtr;  
         }  
     }  
   
     familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily));  
     memset(familyPtr, 0, sizeof(FontFamily));  
     familyPtr->nextPtr = tsdPtr->fontFamilyList;  
     tsdPtr->fontFamilyList = familyPtr;  
   
     /*  
      * Set key for this FontFamily.  
      */  
   
     familyPtr->faceName = faceName;  
   
     /*  
      * An initial refCount of 2 means that FontFamily information will  
      * persist even when the SubFont that loaded the FontFamily is released.  
      * Change it to 1 to cause FontFamilies to be unloaded when not in use.  
      */  
   
     familyPtr->refCount = 2;  
   
     familyPtr->segCount = LoadFontRanges(hdc, hFont, &familyPtr->startCount,  
             &familyPtr->endCount, &familyPtr->isSymbolFont);  
   
     encoding = NULL;  
     if (familyPtr->isSymbolFont != 0) {  
         /*  
          * Symbol fonts are handled specially.  For instance, Unicode 0393  
          * (GREEK CAPITAL GAMMA) must be mapped to Symbol character 0047  
          * (GREEK CAPITAL GAMMA), because the Symbol font doesn't have a  
          * GREEK CAPITAL GAMMA at location 0393.  If Tk interpreted the  
          * Symbol font using the Unicode encoding, it would decide that  
          * the Symbol font has no GREEK CAPITAL GAMMA, because the Symbol  
          * encoding (of course) reports that character 0393 doesn't exist.    
          *  
          * With non-symbol Windows fonts, such as Times New Roman, if the  
          * font has a GREEK CAPITAL GAMMA, it will be found in the correct  
          * Unicode location (0393); the GREEK CAPITAL GAMMA will not be off  
          * hiding at some other location.  
          */  
   
         encoding = Tcl_GetEncoding(NULL, faceName);  
     }  
   
     if (encoding == NULL) {  
         encoding = Tcl_GetEncoding(NULL, "unicode");  
         familyPtr->textOutProc =  
             (BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutW;  
         familyPtr->getTextExtentPoint32Proc =  
             (BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32W;  
         familyPtr->isWideFont = 1;  
     } else {  
         familyPtr->textOutProc =  
             (BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutA;  
         familyPtr->getTextExtentPoint32Proc =  
             (BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32A;  
         familyPtr->isWideFont = 0;  
     }  
   
     familyPtr->encoding = encoding;  
   
     return familyPtr;  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * FreeFontFamily --  
  *  
  *      Called to free a FontFamily when the SubFont is finished using it.  
  *      Frees the contents of the FontFamily and the memory used by the  
  *      FontFamily itself.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      None.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static void  
 FreeFontFamily(  
     FontFamily *familyPtr)      /* The FontFamily to delete. */  
 {  
     int i;  
     FontFamily **familyPtrPtr;  
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)  
             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));  
   
     if (familyPtr == NULL) {  
         return;  
     }  
     familyPtr->refCount--;  
     if (familyPtr->refCount > 0) {  
         return;  
     }  
     for (i = 0; i < FONTMAP_PAGES; i++) {  
         if (familyPtr->fontMap[i] != NULL) {  
             ckfree(familyPtr->fontMap[i]);  
         }  
     }  
     if (familyPtr->startCount != NULL) {  
         ckfree((char *) familyPtr->startCount);  
     }  
     if (familyPtr->endCount != NULL) {  
         ckfree((char *) familyPtr->endCount);  
     }  
     if (familyPtr->encoding != unicodeEncoding) {  
         Tcl_FreeEncoding(familyPtr->encoding);  
     }  
       
     /*  
      * Delete from list.  
      */  
           
     for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) {  
         if (*familyPtrPtr == familyPtr) {  
             *familyPtrPtr = familyPtr->nextPtr;  
             break;  
         }  
         familyPtrPtr = &(*familyPtrPtr)->nextPtr;  
     }  
       
     ckfree((char *) familyPtr);  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * FindSubFontForChar --  
  *  
  *      Determine which screen font is necessary to use to display the  
  *      given character.  If the font object does not have a screen font  
  *      that can display the character, another screen font may be loaded  
  *      into the font object, following a set of preferred fallback rules.  
  *  
  * Results:  
  *      The return value is the SubFont to use to display the given  
  *      character.  
  *  
  * Side effects:  
  *      The contents of fontPtr are modified to cache the results  
  *      of the lookup and remember any SubFonts that were dynamically  
  *      loaded.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static SubFont *  
 FindSubFontForChar(  
     WinFont *fontPtr,           /* The font object with which the character  
                                  * will be displayed. */  
     int ch)                     /* The Unicode character to be displayed. */  
 {  
     HDC hdc;  
     int i, j, k;  
     CanUse canUse;  
     char **aliases, **anyFallbacks;  
     char ***fontFallbacks;  
     char *fallbackName;  
     SubFont *subFontPtr;  
     Tcl_DString ds;  
       
     if (ch < BASE_CHARS) {  
         return &fontPtr->subFontArray[0];  
     }  
   
     for (i = 0; i < fontPtr->numSubFonts; i++) {  
         if (FontMapLookup(&fontPtr->subFontArray[i], ch)) {  
             return &fontPtr->subFontArray[i];  
         }  
     }  
   
     /*  
      * Keep track of all face names that we check, so we don't check some  
      * name multiple times if it can be reached by multiple paths.  
      */  
       
     Tcl_DStringInit(&ds);  
     hdc = GetDC(fontPtr->hwnd);  
           
     aliases = TkFontGetAliasList(fontPtr->font.fa.family);  
   
     fontFallbacks = TkFontGetFallbacks();  
     for (i = 0; fontFallbacks[i] != NULL; i++) {  
         for (j = 0; fontFallbacks[i][j] != NULL; j++) {  
             fallbackName = fontFallbacks[i][j];  
             if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 0) {  
                 /*  
                  * If the base font has a fallback...  
                  */  
   
                 goto tryfallbacks;  
             } else if (aliases != NULL) {  
                 /*  
                  * Or if an alias for the base font has a fallback...  
                  */  
   
                 for (k = 0; aliases[k] != NULL; k++) {  
                     if (strcasecmp(aliases[k], fallbackName) == 0) {  
                         goto tryfallbacks;  
                     }  
                 }  
             }  
         }  
         continue;  
   
         /*  
          * ...then see if we can use one of the fallbacks, or an  
          * alias for one of the fallbacks.  
          */  
   
         tryfallbacks:  
         for (j = 0; fontFallbacks[i][j] != NULL; j++) {  
             fallbackName = fontFallbacks[i][j];  
             subFontPtr = CanUseFallbackWithAliases(hdc, fontPtr, fallbackName,  
                     ch, &ds);  
             if (subFontPtr != NULL) {  
                 goto end;  
             }  
         }  
     }  
   
     /*  
      * See if we can use something from the global fallback list.  
      */  
   
     anyFallbacks = TkFontGetGlobalClass();  
     for (i = 0; anyFallbacks[i] != NULL; i++) {  
         fallbackName = anyFallbacks[i];  
         subFontPtr = CanUseFallbackWithAliases(hdc, fontPtr, fallbackName,  
                 ch, &ds);  
         if (subFontPtr != NULL) {  
             goto end;  
         }  
     }  
   
     /*  
      * Try all face names available in the whole system until we  
      * find one that can be used.  
      */  
   
     canUse.hdc = hdc;  
     canUse.fontPtr = fontPtr;  
     canUse.nameTriedPtr = &ds;  
     canUse.ch = ch;  
     canUse.subFontPtr = NULL;  
     if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {  
         EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontCanUseProc,  
                 (LPARAM) &canUse);  
     } else {  
         EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontCanUseProc,  
                 (LPARAM) &canUse);  
     }  
     subFontPtr = canUse.subFontPtr;  
   
     end:  
     Tcl_DStringFree(&ds);  
       
     if (subFontPtr == NULL) {  
         /*  
          * No font can display this character.  We will use the base font  
          * and have it display the "unknown" character.  
          */  
   
         subFontPtr = &fontPtr->subFontArray[0];  
         FontMapInsert(subFontPtr, ch);  
     }  
     ReleaseDC(fontPtr->hwnd, hdc);  
     return subFontPtr;  
 }  
   
 static int CALLBACK  
 WinFontCanUseProc(  
     ENUMLOGFONT *lfPtr,         /* Logical-font data. */  
     NEWTEXTMETRIC *tmPtr,       /* Physical-font data (not used). */  
     int fontType,               /* Type of font (not used). */  
     LPARAM lParam)              /* Result object to hold result. */  
 {  
     int ch;  
     HDC hdc;  
     WinFont *fontPtr;  
     CanUse *canUsePtr;  
     char *fallbackName;  
     SubFont *subFontPtr;  
     Tcl_DString faceString;  
     Tcl_DString *nameTriedPtr;  
   
     canUsePtr       = (CanUse *) lParam;  
     ch              = canUsePtr->ch;  
     hdc             = canUsePtr->hdc;  
     fontPtr         = canUsePtr->fontPtr;  
     nameTriedPtr    = canUsePtr->nameTriedPtr;  
   
     fallbackName = lfPtr->elfLogFont.lfFaceName;  
     Tcl_ExternalToUtfDString(systemEncoding, fallbackName, -1, &faceString);  
     fallbackName = Tcl_DStringValue(&faceString);  
   
     if (SeenName(fallbackName, nameTriedPtr) == 0) {  
         subFontPtr = CanUseFallback(hdc, fontPtr, fallbackName, ch);  
         if (subFontPtr != NULL) {  
             canUsePtr->subFontPtr = subFontPtr;  
             Tcl_DStringFree(&faceString);  
             return 0;  
         }  
     }  
     Tcl_DStringFree(&faceString);  
     return 1;  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * FontMapLookup --  
  *  
  *      See if the screen font can display the given character.  
  *  
  * Results:  
  *      The return value is 0 if the screen font cannot display the  
  *      character, non-zero otherwise.  
  *  
  * Side effects:  
  *      New pages are added to the font mapping cache whenever the  
  *      character belongs to a page that hasn't been seen before.  
  *      When a page is loaded, information about all the characters on  
  *      that page is stored, not just for the single character in  
  *      question.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static int  
 FontMapLookup(  
     SubFont *subFontPtr,        /* Contains font mapping cache to be queried  
                                  * and possibly updated. */  
     int ch)                     /* Character to be tested. */  
 {  
     int row, bitOffset;  
   
     row = ch >> FONTMAP_SHIFT;  
     if (subFontPtr->fontMap[row] == NULL) {  
         FontMapLoadPage(subFontPtr, row);  
     }  
     bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);  
     return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * FontMapInsert --  
  *  
  *      Tell the font mapping cache that the given screen font should be  
  *      used to display the specified character.  This is called when no  
  *      font on the system can be be found that can display that  
  *      character; we lie to the font and tell it that it can display  
  *      the character, otherwise we would end up re-searching the entire  
  *      fallback hierarchy every time that character was seen.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      New pages are added to the font mapping cache whenever the  
  *      character belongs to a page that hasn't been seen before.  
  *      When a page is loaded, information about all the characters on  
  *      that page is stored, not just for the single character in  
  *      question.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static void  
 FontMapInsert(  
     SubFont *subFontPtr,        /* Contains font mapping cache to be  
                                  * updated. */  
     int ch)                     /* Character to be added to cache. */  
 {  
     int row, bitOffset;  
   
     row = ch >> FONTMAP_SHIFT;  
     if (subFontPtr->fontMap[row] == NULL) {  
         FontMapLoadPage(subFontPtr, row);  
     }  
     bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);  
     subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * FontMapLoadPage --  
  *  
  *      Load information about all the characters on a given page.  
  *      This information consists of one bit per character that indicates  
  *      whether the associated HFONT can (1) or cannot (0) display the  
  *      characters on the page.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Mempry allocated.  
  *  
  *-------------------------------------------------------------------------  
  */  
 static void  
 FontMapLoadPage(  
     SubFont *subFontPtr,        /* Contains font mapping cache to be  
                                  * updated. */  
     int row)                    /* Index of the page to be loaded into  
                                  * the cache. */  
 {  
     FontFamily *familyPtr;  
     Tcl_Encoding encoding;  
     char src[TCL_UTF_MAX], buf[16];  
     USHORT *startCount, *endCount;  
     int i, j, bitOffset, end, segCount;  
   
     subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8);  
     memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);  
   
     familyPtr = subFontPtr->familyPtr;  
     encoding = familyPtr->encoding;  
   
     if (familyPtr->encoding == unicodeEncoding) {  
         /*  
          * Font is Unicode.  Few fonts are going to have all characters, so  
          * examine the TrueType character existence metrics to determine  
          * what characters actually exist in this font.  
          */  
   
         segCount    = familyPtr->segCount;  
         startCount  = familyPtr->startCount;  
         endCount    = familyPtr->endCount;  
   
         j = 0;  
         end = (row + 1) << FONTMAP_SHIFT;  
         for (i = row << FONTMAP_SHIFT; i < end; i++) {  
             for ( ; j < segCount; j++) {  
                 if (endCount[j] >= i) {  
                     if (startCount[j] <= i) {  
                         bitOffset = i & (FONTMAP_BITSPERPAGE - 1);  
                         subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);  
                     }  
                     break;  
                 }  
             }  
         }  
     } else if (familyPtr->isSymbolFont) {  
         /*  
          * Assume that a symbol font with a known encoding has all the  
          * characters that its encoding claims it supports.    
          *        
          * The test for "encoding == unicodeEncoding"  
          * must occur before this case, to catch all symbol fonts (such  
          * as {Comic Sans MS} or Wingdings) for which we don't have  
          * encoding information; those symbol fonts are treated as if  
          * they were in the Unicode encoding and their symbolic  
          * character existence metrics are treated as if they were Unicode  
          * character existence metrics.  This way, although we don't know  
          * the proper Unicode -> symbol font mapping, we can install the  
          * symbol font as the base font and access its glyphs.  
          */  
   
         end = (row + 1) << FONTMAP_SHIFT;  
         for (i = row << FONTMAP_SHIFT; i < end; i++) {  
             if (Tcl_UtfToExternal(NULL, encoding, src,  
                     Tcl_UniCharToUtf(i, src), TCL_ENCODING_STOPONERROR, NULL,  
                     buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK) {  
                 continue;  
             }  
             bitOffset = i & (FONTMAP_BITSPERPAGE - 1);  
             subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);  
         }  
     }  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * CanUseFallbackWithAliases --  
  *  
  *      Helper function for FindSubFontForChar.  Determine if the  
  *      specified face name (or an alias of the specified face name)  
  *      can be used to construct a screen font that can display the  
  *      given character.  
  *  
  * Results:  
  *      See CanUseFallback().  
  *  
  * Side effects:  
  *      If the name and/or one of its aliases was rejected, the  
  *      rejected string is recorded in nameTriedPtr so that it won't  
  *      be tried again.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 static SubFont *  
 CanUseFallbackWithAliases(  
     HDC hdc,                    /* HDC in which font can be selected. */  
     WinFont *fontPtr,           /* The font object that will own the new  
                                  * screen font. */  
     char *faceName,             /* Desired face name for new screen font. */  
     int ch,                     /* The Unicode character that the new  
                                  * screen font must be able to display. */  
     Tcl_DString *nameTriedPtr)  /* Records face names that have already  
                                  * been tried.  It is possible for the same  
                                  * face name to be queried multiple times when  
                                  * trying to find a suitable screen font. */  
 {  
     int i;  
     char **aliases;  
     SubFont *subFontPtr;  
       
     if (SeenName(faceName, nameTriedPtr) == 0) {  
         subFontPtr = CanUseFallback(hdc, fontPtr, faceName, ch);  
         if (subFontPtr != NULL) {  
             return subFontPtr;  
         }  
     }  
     aliases = TkFontGetAliasList(faceName);  
     if (aliases != NULL) {  
         for (i = 0; aliases[i] != NULL; i++) {  
             if (SeenName(aliases[i], nameTriedPtr) == 0) {  
                 subFontPtr = CanUseFallback(hdc, fontPtr, aliases[i], ch);  
                 if (subFontPtr != NULL) {  
                     return subFontPtr;  
                 }  
             }  
         }  
     }  
     return NULL;  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * SeenName --  
  *  
  *      Used to determine we have already tried and rejected the given  
  *      face name when looking for a screen font that can support some  
  *      Unicode character.  
  *  
  * Results:  
  *      The return value is 0 if this face name has not already been seen,  
  *      non-zero otherwise.  
  *  
  * Side effects:  
  *      None.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 static int  
 SeenName(  
     CONST char *name,           /* The name to check. */  
     Tcl_DString *dsPtr)         /* Contains names that have already been  
                                  * seen. */  
 {  
     CONST char *seen, *end;  
   
     seen = Tcl_DStringValue(dsPtr);  
     end = seen + Tcl_DStringLength(dsPtr);  
     while (seen < end) {  
         if (strcasecmp(seen, name) == 0) {  
             return 1;  
         }  
         seen += strlen(seen) + 1;  
     }  
     Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1));  
     return 0;  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * CanUseFallback --  
  *  
  *      If the specified screen font has not already been loaded into  
  *      the font object, determine if it can display the given character.  
  *  
  * Results:  
  *      The return value is a pointer to a newly allocated SubFont, owned  
  *      by the font object.  This SubFont can be used to display the given  
  *      character.  The SubFont represents the screen font with the base set  
  *      of font attributes from the font object, but using the specified  
  *      font name.  NULL is returned if the font object already holds  
  *      a reference to the specified physical font or if the specified  
  *      physical font cannot display the given character.  
  *  
  * Side effects:                                        
  *      The font object's subFontArray is updated to contain a reference  
  *      to the newly allocated SubFont.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static SubFont *  
 CanUseFallback(  
     HDC hdc,                    /* HDC in which font can be selected. */  
     WinFont *fontPtr,           /* The font object that will own the new  
                                  * screen font. */  
     char *faceName,             /* Desired face name for new screen font. */  
     int ch)                     /* The Unicode character that the new  
                                  * screen font must be able to display. */  
 {  
     int i;  
     HFONT hFont;  
     SubFont subFont;  
   
     if (FamilyExists(hdc, faceName) == 0) {  
         return NULL;  
     }  
   
     /*  
      * Skip all fonts we've already used.  
      */  
       
     for (i = 0; i < fontPtr->numSubFonts; i++) {  
         if (faceName == fontPtr->subFontArray[i].familyPtr->faceName) {  
             return NULL;  
         }  
     }  
   
     /*  
      * Load this font and see if it has the desired character.  
      */  
   
     hFont = GetScreenFont(&fontPtr->font.fa, faceName, fontPtr->pixelSize);  
     InitSubFont(hdc, hFont, 0, &subFont);  
     if (((ch < 256) && (subFont.familyPtr->isSymbolFont))  
             || (FontMapLookup(&subFont, ch) == 0)) {  
         /*  
          * Don't use a symbol font as a fallback font for characters below  
          * 256.  
          */  
   
         ReleaseSubFont(&subFont);  
         return NULL;  
     }  
   
     if (fontPtr->numSubFonts >= SUBFONT_SPACE) {  
         SubFont *newPtr;  
           
         newPtr = (SubFont *) ckalloc(sizeof(SubFont)  
                 * (fontPtr->numSubFonts + 1));  
         memcpy((char *) newPtr, fontPtr->subFontArray,  
                 fontPtr->numSubFonts * sizeof(SubFont));  
         if (fontPtr->subFontArray != fontPtr->staticSubFonts) {  
             ckfree((char *) fontPtr->subFontArray);  
         }  
         fontPtr->subFontArray = newPtr;  
     }  
     fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;  
     fontPtr->numSubFonts++;  
     return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];  
 }  
   
 /*  
  *---------------------------------------------------------------------------  
  *  
  * GetScreenFont --  
  *  
  *      Given the name and other attributes, construct an HFONT.  
  *      This is where all the alias and fallback substitution bottoms  
  *      out.  
  *  
  * Results:  
  *      The screen font that corresponds to the attributes.  
  *  
  * Side effects:  
  *      None.  
  *  
  *---------------------------------------------------------------------------  
  */  
   
 static HFONT  
 GetScreenFont(  
     CONST TkFontAttributes *faPtr,  
                                 /* Desired font attributes for new HFONT. */  
     CONST char *faceName,       /* Overrides font family specified in font  
                                  * attributes. */  
     int pixelSize)              /* Overrides size specified in font  
                                  * attributes. */  
 {  
     Tcl_DString ds;  
     HFONT hFont;  
     LOGFONTW lf;  
   
     lf.lfHeight         = -pixelSize;  
     lf.lfWidth          = 0;  
     lf.lfEscapement     = 0;  
     lf.lfOrientation    = 0;  
     lf.lfWeight         = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD;  
     lf.lfItalic         = faPtr->slant;  
     lf.lfUnderline      = faPtr->underline;  
     lf.lfStrikeOut      = faPtr->overstrike;  
     lf.lfCharSet        = DEFAULT_CHARSET;  
     lf.lfOutPrecision   = OUT_TT_PRECIS;  
     lf.lfClipPrecision  = CLIP_DEFAULT_PRECIS;  
     lf.lfQuality        = DEFAULT_QUALITY;  
     lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;  
   
     Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &ds);  
   
     if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {  
         Tcl_UniChar *src, *dst;  
   
         /*  
          * We can only store up to LF_FACESIZE wide characters  
          */  
         if (Tcl_DStringLength(&ds) >= (LF_FACESIZE * sizeof(WCHAR))) {  
             Tcl_DStringSetLength(&ds, LF_FACESIZE);  
         }  
         src = (Tcl_UniChar *) Tcl_DStringValue(&ds);  
         dst = (Tcl_UniChar *) lf.lfFaceName;  
         while (*src != '\0') {  
             *dst++ = *src++;  
         }  
         *dst = '\0';  
         hFont = CreateFontIndirectW(&lf);  
     } else {  
         /*  
          * We can only store up to LF_FACESIZE characters  
          */  
         if (Tcl_DStringLength(&ds) >= LF_FACESIZE) {  
             Tcl_DStringSetLength(&ds, LF_FACESIZE);  
         }  
         strcpy((char *) lf.lfFaceName, Tcl_DStringValue(&ds));  
         hFont = CreateFontIndirectA((LOGFONTA *) &lf);  
     }  
     Tcl_DStringFree(&ds);  
     return hFont;  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * FamilyExists, FamilyOrAliasExists, WinFontExistsProc --  
  *  
  *      Determines if any physical screen font exists on the system with  
  *      the given family name.  If the family exists, then it should be  
  *      possible to construct some physical screen font with that family  
  *      name.  
  *  
  * Results:  
  *      The return value is 0 if the specified font family does not exist,  
  *      non-zero otherwise.  
  *  
  * Side effects:  
  *      None.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static int  
 FamilyExists(  
     HDC hdc,                    /* HDC in which font family will be used. */  
     CONST char *faceName)       /* Font family to query. */  
 {  
     int result;  
     Tcl_DString faceString;  
   
     /*  
      * Just immediately rule out the following fonts, because they look so  
      * ugly on windows.  The caller's fallback mechanism will cause the  
      * corresponding appropriate TrueType fonts to be selected.  
      */  
   
     if (strcasecmp(faceName, "Courier") == 0) {  
         return 0;  
     }  
     if (strcasecmp(faceName, "Times") == 0) {  
         return 0;  
     }  
     if (strcasecmp(faceName, "Helvetica") == 0) {  
         return 0;  
     }  
       
     Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &faceString);  
   
     /*  
      * If the family exists, WinFontExistProc() will be called and  
      * EnumFontFamilies() will return whatever WinFontExistProc() returns.    
      * If the family doesn't exist, EnumFontFamilies() will just return a  
      * non-zero value.  
      */  
   
     if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {  
         result = EnumFontFamiliesW(hdc, (WCHAR *) Tcl_DStringValue(&faceString),  
                 (FONTENUMPROCW) WinFontExistProc, 0);  
     } else {  
         result = EnumFontFamiliesA(hdc, (char *) Tcl_DStringValue(&faceString),  
                 (FONTENUMPROCA) WinFontExistProc, 0);  
     }  
     Tcl_DStringFree(&faceString);  
     return (result == 0);  
 }  
   
 static char *  
 FamilyOrAliasExists(  
     HDC hdc,  
     CONST char *faceName)  
 {  
     char **aliases;  
     int i;  
   
     if (FamilyExists(hdc, faceName) != 0) {  
         return (char *) faceName;  
     }  
     aliases = TkFontGetAliasList(faceName);  
     if (aliases != NULL) {  
         for (i = 0; aliases[i] != NULL; i++) {  
             if (FamilyExists(hdc, aliases[i]) != 0) {  
                 return aliases[i];  
             }  
         }  
     }  
     return NULL;  
 }  
   
 static int CALLBACK  
 WinFontExistProc(  
     ENUMLOGFONT *lfPtr,         /* Logical-font data. */  
     NEWTEXTMETRIC *tmPtr,       /* Physical-font data (not used). */  
     int fontType,               /* Type of font (not used). */  
     LPARAM lParam)              /* EnumFontData to hold result. */  
 {  
     return 0;  
 }  
   
 /*  
  * The following data structures are used when querying a TrueType font file  
  * to determine which characters the font supports.  
  */  
   
 #pragma pack(1)                 /* Structures are byte aligned in file. */  
   
 #define CMAPHEX  0x636d6170     /* Key for character map resource. */  
   
 typedef struct CMAPTABLE {  
     USHORT version;             /* Table version number (0). */  
     USHORT numTables;           /* Number of encoding tables following. */  
 } CMAPTABLE;  
   
 typedef struct ENCODINGTABLE {  
     USHORT platform;            /* Platform for which data is targeted.    
                                  * 3 means data is for Windows. */  
     USHORT encoding;            /* How characters in font are encoded.    
                                  * 1 means that the following subtable is  
                                  * keyed based on Unicode. */  
     ULONG offset;               /* Byte offset from beginning of CMAPTABLE  
                                  * to the subtable for this encoding. */  
 } ENCODINGTABLE;  
   
 typedef struct ANYTABLE {  
     USHORT format;              /* Format number. */  
     USHORT length;              /* The actual length in bytes of this  
                                  * subtable. */  
     USHORT version;             /* Version number (starts at 0). */  
 } ANYTABLE;  
   
 typedef struct BYTETABLE {  
     USHORT format;              /* Format number is set to 0. */  
     USHORT length;              /* The actual length in bytes of this  
                                  * subtable. */  
     USHORT version;             /* Version number (starts at 0). */  
     BYTE glyphIdArray[256];     /* Array that maps up to 256 single-byte char  
                                  * codes to glyph indices. */  
 } BYTETABLE;  
   
 typedef struct SUBHEADER {  
     USHORT firstCode;           /* First valid low byte for subHeader. */  
     USHORT entryCount;          /* Number valid low bytes for subHeader. */  
     SHORT idDelta;              /* Constant adder to get base glyph index. */  
     USHORT idRangeOffset;       /* Byte offset from here to appropriate  
                                  * glyphIndexArray. */  
 } SUBHEADER;  
   
 typedef struct HIBYTETABLE {  
     USHORT format;              /* Format number is set to 2. */  
     USHORT length;              /* The actual length in bytes of this  
                                  * subtable. */  
     USHORT version;             /* Version number (starts at 0). */  
     USHORT subHeaderKeys[256];  /* Maps high bytes to subHeaders: value is  
                                  * subHeader index * 8. */  
 #if 0  
     SUBHEADER subHeaders[];     /* Variable-length array of SUBHEADERs. */  
     USHORT glyphIndexArray[];   /* Variable-length array containing subarrays  
                                  * used for mapping the low byte of 2-byte  
                                  * characters. */  
 #endif  
 } HIBYTETABLE;  
   
 typedef struct SEGMENTTABLE {  
     USHORT format;              /* Format number is set to 4. */  
     USHORT length;              /* The actual length in bytes of this  
                                  * subtable. */  
     USHORT version;             /* Version number (starts at 0). */  
     USHORT segCountX2;          /* 2 x segCount. */  
     USHORT searchRange;         /* 2 x (2**floor(log2(segCount))). */  
     USHORT entrySelector;       /* log2(searchRange/2). */  
     USHORT rangeShift;          /* 2 x segCount - searchRange. */  
 #if 0  
     USHORT endCount[segCount]   /* End characterCode for each segment. */  
     USHORT reservedPad;         /* Set to 0. */  
     USHORT startCount[segCount];/* Start character code for each segment. */  
     USHORT idDelta[segCount];   /* Delta for all character in segment. */  
     USHORT idRangeOffset[segCount]; /* Offsets into glyphIdArray or 0. */  
     USHORT glyphIdArray[]       /* Glyph index array. */  
 #endif  
 } SEGMENTTABLE;  
   
 typedef struct TRIMMEDTABLE {  
     USHORT format;              /* Format number is set to 6. */  
     USHORT length;              /* The actual length in bytes of this  
                                  * subtable. */  
     USHORT version;             /* Version number (starts at 0). */  
     USHORT firstCode;           /* First character code of subrange. */  
     USHORT entryCount;          /* Number of character codes in subrange. */  
 #if 0  
     USHORT glyphIdArray[];      /* Array of glyph index values for  
                                         character codes in the range. */  
 #endif  
 } TRIMMEDTABLE;  
   
 typedef union SUBTABLE {  
     ANYTABLE any;  
     BYTETABLE byte;  
     HIBYTETABLE hiByte;  
     SEGMENTTABLE segment;  
     TRIMMEDTABLE trimmed;  
 } SUBTABLE;  
   
 #pragma pack()  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * LoadFontRanges --  
  *  
  *      Given an HFONT, get the information about the characters that  
  *      this font can display.  
  *  
  * Results:  
  *      If the font has no Unicode character information, the return value  
  *      is 0 and *startCountPtr and *endCountPtr are filled with NULL.    
  *      Otherwise, *startCountPtr and *endCountPtr are set to pointers to  
  *      arrays of TrueType character existence information and the return  
  *      value is the length of the arrays (the two arrays are always the  
  *      same length as each other).  
  *  
  * Side effects:  
  *      None.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static int  
 LoadFontRanges(  
     HDC hdc,                    /* HDC into which font can be selected. */  
     HFONT hFont,                /* HFONT to query. */  
     USHORT **startCountPtr,     /* Filled with malloced pointer to  
                                  * character range information. */  
     USHORT **endCountPtr,       /* Filled with malloced pointer to  
                                  * character range information. */  
     int *symbolPtr)  
  {  
     int n, i, swapped, offset, cbData, segCount;  
     DWORD cmapKey;  
     USHORT *startCount, *endCount;  
     CMAPTABLE cmapTable;  
     ENCODINGTABLE encTable;  
     SUBTABLE subTable;  
     char *s;  
   
     segCount = 0;  
     startCount = NULL;  
     endCount = NULL;  
     *symbolPtr = 0;  
   
     hFont = SelectObject(hdc, hFont);  
   
     i = 0;  
     s = (char *) &i;  
     *s = '\1';  
     swapped = 0;  
   
     if (i == 1) {  
         swapped = 1;  
     }  
   
     cmapKey = CMAPHEX;  
     if (swapped) {  
         SwapLong(&cmapKey);  
     }  
   
     n = GetFontData(hdc, cmapKey, 0, &cmapTable, sizeof(cmapTable));  
     if (n != GDI_ERROR) {  
         if (swapped) {  
             SwapShort(&cmapTable.numTables);  
         }  
         for (i = 0; i < cmapTable.numTables; i++) {  
             offset = sizeof(cmapTable) + i * sizeof(encTable);  
             GetFontData(hdc, cmapKey, offset, &encTable, sizeof(encTable));  
             if (swapped) {  
                 SwapShort(&encTable.platform);  
                 SwapShort(&encTable.encoding);  
                 SwapLong(&encTable.offset);  
             }  
             if (encTable.platform != 3) {  
                 /*  
                  * Not Microsoft encoding.  
                  */  
   
                 continue;  
             }  
             if (encTable.encoding == 0) {  
                 *symbolPtr = 1;  
             } else if (encTable.encoding != 1) {  
                 continue;  
             }  
   
             GetFontData(hdc, cmapKey, encTable.offset, &subTable,  
                     sizeof(subTable));  
             if (swapped) {  
                 SwapShort(&subTable.any.format);  
             }  
             if (subTable.any.format == 4) {  
                 if (swapped) {  
                     SwapShort(&subTable.segment.segCountX2);  
                 }  
                 segCount = subTable.segment.segCountX2 / 2;  
                 cbData = segCount * sizeof(USHORT);  
   
                 startCount = (USHORT *) ckalloc(cbData);  
                 endCount = (USHORT *) ckalloc(cbData);  
   
                 offset = encTable.offset + sizeof(subTable.segment);  
                 GetFontData(hdc, cmapKey, offset, endCount, cbData);  
                 offset += cbData + sizeof(USHORT);  
                 GetFontData(hdc, cmapKey, offset, startCount, cbData);  
                 if (swapped) {  
                     for (i = 0; i < segCount; i++) {  
                         SwapShort(&endCount[i]);  
                         SwapShort(&startCount[i]);  
                     }  
                 }  
                 if (*symbolPtr != 0) {  
                     /*  
                      * Empirically determined:  When a symbol font is  
                      * loaded, the character existence metrics obtained  
                      * from the system are mildly wrong.  If the real range  
                      * of the symbol font is from 0020 to 00FE, then the  
                      * metrics are reported as F020 to F0FE.  When we load  
                      * a symbol font, we must fix the character existence  
                      * metrics.  
                      *  
                      * Symbol fonts should only use the symbol encoding  
                      * for 8-bit characters [note Bug: 2406]  
                      */  
   
                     for (i = 0; i < segCount; i++) {  
                         if (((startCount[i] & 0xff00) == 0xf000)  
                                 && ((endCount[i] & 0xff00) == 0xf000)) {  
                             startCount[i] &= 0xff;  
                             endCount[i] &= 0xff;  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     SelectObject(hdc, hFont);  
   
     *startCountPtr = startCount;  
     *endCountPtr = endCount;  
     return segCount;  
 }  
   
 /*  
  *-------------------------------------------------------------------------  
  *  
  * SwapShort, SwapLong --  
  *  
  *      Helper functions to convert the data loaded from TrueType font  
  *      files to Intel byte ordering.  
  *  
  * Results:  
  *      Bytes of input value are swapped and stored back in argument.  
  *  
  * Side effects:  
  *      None.  
  *  
  *-------------------------------------------------------------------------  
  */  
   
 static void  
 SwapShort(PUSHORT p)  
 {  
     *p = (SHORT)(HIBYTE(*p) + (LOBYTE(*p) << 8));  
 }  
   
 static void  
 SwapLong(PULONG p)  
 {                                              
     ULONG temp;  
   
     temp = (LONG) ((BYTE) *p);  
     temp <<= 8;  
     *p >>=8;  
   
     temp += (LONG) ((BYTE) *p);  
     temp <<= 8;  
     *p >>=8;  
   
     temp += (LONG) ((BYTE) *p);  
     temp <<= 8;  
     *p >>=8;  
   
     temp += (LONG) ((BYTE) *p);  
     *p = temp;  
 }  
   
   
 /* $History: tkWinFont.c $  
  *  
  * *****************  Version 1  *****************  
  * User: Dtashley     Date: 1/02/01    Time: 3:15a  
  * Created in $/IjuScripter, IjuConsole/Source/Tk Base  
  * Initial check-in.  
  */  
   
 /* End of TKWINFONT.C */  
1    /* $Header$ */
2    
3    /*
4     * tkWinFont.c --
5     *
6     *      Contains the Windows implementation of the platform-independant
7     *      font package interface.
8     *
9     * Copyright (c) 1994 Software Research Associates, Inc.
10     * Copyright (c) 1995-1997 Sun Microsystems, Inc.
11     * Copyright (c) 1998-1999 by Scriptics Corporation.
12     *
13     * See the file "license.terms" for information on usage and redistribution
14     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15     *
16     * RCS: @(#) $Id: tkwinfont.c,v 1.1.1.1 2001/06/13 05:13:30 dtashley Exp $
17     */
18    
19    #include "tkWinInt.h"
20    #include "tkFont.h"
21    
22    /*
23     * The following structure represents a font family.  It is assumed that
24     * all screen fonts constructed from the same "font family" share certain
25     * properties; all screen fonts with the same "font family" point to a
26     * shared instance of this structure.  The most important shared property
27     * is the character existence metrics, used to determine if a screen font
28     * can display a given Unicode character.
29     *
30     * Under Windows, a "font family" is uniquely identified by its face name.
31     */
32    
33    #define FONTMAP_SHIFT       10
34    
35    #define FONTMAP_PAGES           (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT))
36    #define FONTMAP_BITSPERPAGE     (1 << FONTMAP_SHIFT)
37    
38    typedef struct FontFamily {
39        struct FontFamily *nextPtr; /* Next in list of all known font families. */
40        int refCount;               /* How many SubFonts are referring to this
41                                     * FontFamily.  When the refCount drops to
42                                     * zero, this FontFamily may be freed. */
43        /*
44         * Key.
45         */
46        
47        Tk_Uid faceName;            /* Face name key for this FontFamily. */
48    
49        /*
50         * Derived properties.
51         */
52        
53        Tcl_Encoding encoding;      /* Encoding for this font family. */
54        int isSymbolFont;           /* Non-zero if this is a symbol font. */
55        int isWideFont;             /* 1 if this is a double-byte font, 0
56                                     * otherwise. */
57        BOOL (WINAPI *textOutProc)(HDC, int, int, TCHAR *, int);
58                                    /* The procedure to use to draw text after
59                                     * it has been converted from UTF-8 to the
60                                     * encoding of this font. */
61        BOOL (WINAPI *getTextExtentPoint32Proc)(HDC, TCHAR *, int, LPSIZE);
62                                    /* The procedure to use to measure text after
63                                     * it has been converted from UTF-8 to the
64                                     * encoding of this font. */
65    
66        char *fontMap[FONTMAP_PAGES];
67                                    /* Two-level sparse table used to determine
68                                     * quickly if the specified character exists.
69                                     * As characters are encountered, more pages
70                                     * in this table are dynamically added.  The
71                                     * contents of each page is a bitmask
72                                     * consisting of FONTMAP_BITSPERPAGE bits,
73                                     * representing whether this font can be used
74                                     * to display the given character at the
75                                     * corresponding bit position.  The high bits
76                                     * of the character are used to pick which
77                                     * page of the table is used. */
78    
79        /*
80         * Cached Truetype font info.
81         */
82        
83        int segCount;               /* The length of the following arrays. */
84        USHORT *startCount;         /* Truetype information about the font, */
85        USHORT *endCount;           /* indicating which characters this font
86                                     * can display (malloced).  The format of
87                                     * this information is (relatively) compact,
88                                     * but would take longer to search than
89                                     * indexing into the fontMap[][] table. */
90    } FontFamily;
91    
92    /*
93     * The following structure encapsulates an individual screen font.  A font
94     * object is made up of however many SubFonts are necessary to display a
95     * stream of multilingual characters.
96     */
97    
98    typedef struct SubFont {
99        char **fontMap;             /* Pointer to font map from the FontFamily,
100                                     * cached here to save a dereference. */
101        HFONT hFont;                /* The specific screen font that will be
102                                     * used when displaying/measuring chars
103                                     * belonging to the FontFamily. */
104        FontFamily *familyPtr;      /* The FontFamily for this SubFont. */
105    } SubFont;
106    
107    /*
108     * The following structure represents Windows' implementation of a font
109     * object.
110     */
111    
112    #define SUBFONT_SPACE           3
113    #define BASE_CHARS              128
114    
115    typedef struct WinFont {
116        TkFont font;                /* Stuff used by generic font package.  Must
117                                     * be first in structure. */
118        SubFont staticSubFonts[SUBFONT_SPACE];
119                                    /* Builtin space for a limited number of
120                                     * SubFonts. */
121        int numSubFonts;            /* Length of following array. */
122        SubFont *subFontArray;      /* Array of SubFonts that have been loaded
123                                     * in order to draw/measure all the characters
124                                     * encountered by this font so far.  All fonts
125                                     * start off with one SubFont initialized by
126                                     * AllocFont() from the original set of font
127                                     * attributes.  Usually points to
128                                     * staticSubFonts, but may point to malloced
129                                     * space if there are lots of SubFonts. */
130    
131        HWND hwnd;                  /* Toplevel window of application that owns
132                                     * this font, used for getting HDC for
133                                     * offscreen measurements. */
134        int pixelSize;              /* Original pixel size used when font was
135                                     * constructed. */
136        int widths[BASE_CHARS];     /* Widths of first 128 chars in the base
137                                     * font, for handling common case.  The base
138                                     * font is always used to draw characters
139                                     * between 0x0000 and 0x007f. */
140    } WinFont;
141    
142    /*
143     * The following structure is passed as the LPARAM when calling the font
144     * enumeration procedure to determine if a font can support the given
145     * character.
146     */
147    
148    typedef struct CanUse {
149        HDC hdc;
150        WinFont *fontPtr;
151        Tcl_DString *nameTriedPtr;
152        int ch;
153        SubFont *subFontPtr;
154    } CanUse;
155    
156    /*
157     * The following structure is used to map between the Tcl strings that
158     * represent the system fonts and the numbers used by Windows.
159     */
160    
161    static TkStateMap systemMap[] = {
162        {ANSI_FIXED_FONT,       "ansifixed"},
163        {ANSI_VAR_FONT,         "ansi"},
164        {DEVICE_DEFAULT_FONT,   "device"},
165        {OEM_FIXED_FONT,        "oemfixed"},
166        {SYSTEM_FIXED_FONT,     "systemfixed"},
167        {SYSTEM_FONT,           "system"},
168        {-1,                    NULL}
169    };
170    
171    typedef struct ThreadSpecificData {
172        FontFamily *fontFamilyList; /* The list of font families that are
173                                     * currently loaded.  As screen fonts
174                                     * are loaded, this list grows to hold
175                                     * information about what characters
176                                     * exist in each font family.  */
177        Tcl_HashTable uidTable;
178    } ThreadSpecificData;
179    static Tcl_ThreadDataKey dataKey;
180    
181    /*
182     * Information cached about the system at startup time.
183     */
184    
185    static Tcl_Encoding unicodeEncoding;
186    static Tcl_Encoding systemEncoding;
187    
188    /*
189     * Procedures used only in this file.
190     */
191    
192    static FontFamily *     AllocFontFamily(HDC hdc, HFONT hFont, int base);
193    static SubFont *        CanUseFallback(HDC hdc, WinFont *fontPtr,
194                                char *fallbackName, int ch);
195    static SubFont *        CanUseFallbackWithAliases(HDC hdc, WinFont *fontPtr,
196                                char *faceName, int ch, Tcl_DString *nameTriedPtr);
197    static int              FamilyExists(HDC hdc, CONST char *faceName);
198    static char *           FamilyOrAliasExists(HDC hdc, CONST char *faceName);
199    static SubFont *        FindSubFontForChar(WinFont *fontPtr, int ch);
200    static void             FontMapInsert(SubFont *subFontPtr, int ch);
201    static void             FontMapLoadPage(SubFont *subFontPtr, int row);
202    static int              FontMapLookup(SubFont *subFontPtr, int ch);
203    static void             FreeFontFamily(FontFamily *familyPtr);
204    static HFONT            GetScreenFont(CONST TkFontAttributes *faPtr,
205                                CONST char *faceName, int pixelSize);
206    static void             InitFont(Tk_Window tkwin, HFONT hFont,
207                                int overstrike, WinFont *tkFontPtr);
208    static void             InitSubFont(HDC hdc, HFONT hFont, int base,
209                                SubFont *subFontPtr);
210    static int              LoadFontRanges(HDC hdc, HFONT hFont,
211                                USHORT **startCount, USHORT **endCount,
212                                int *symbolPtr);
213    static void             MultiFontTextOut(HDC hdc, WinFont *fontPtr,
214                                CONST char *source, int numBytes, int x, int y);
215    static void             ReleaseFont(WinFont *fontPtr);
216    static void             ReleaseSubFont(SubFont *subFontPtr);
217    static int              SeenName(CONST char *name, Tcl_DString *dsPtr);
218    static void             SwapLong(PULONG p);
219    static void             SwapShort(USHORT *p);
220    static int CALLBACK     WinFontCanUseProc(ENUMLOGFONT *lfPtr,
221                                NEWTEXTMETRIC *tmPtr, int fontType,
222                                LPARAM lParam);
223    static int CALLBACK     WinFontExistProc(ENUMLOGFONT *lfPtr,
224                                NEWTEXTMETRIC *tmPtr, int fontType,
225                                LPARAM lParam);
226    static int CALLBACK     WinFontFamilyEnumProc(ENUMLOGFONT *lfPtr,
227                                NEWTEXTMETRIC *tmPtr, int fontType,
228                                LPARAM lParam);
229    
230    /*
231     *-------------------------------------------------------------------------
232     *
233     * TkpFontPkgInit --
234     *
235     *      This procedure is called when an application is created.  It
236     *      initializes all the structures that are used by the
237     *      platform-dependent code on a per application basis.
238     *
239     * Results:
240     *      None.  
241     *
242     * Side effects:
243     *      
244     *      None.
245     *
246     *-------------------------------------------------------------------------
247     */
248    
249    void
250    TkpFontPkgInit(
251        TkMainInfo *mainPtr)        /* The application being created. */
252    {
253        unicodeEncoding = Tcl_GetEncoding(NULL, "unicode");
254        if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
255            /*
256             * If running NT, then we will be calling some Unicode functions
257             * explictly.  So, even if the Tcl system encoding isn't Unicode,
258             * make sure we convert to/from the Unicode char set.
259             */
260    
261            systemEncoding = unicodeEncoding;
262        }
263    }
264    
265    /*
266     *---------------------------------------------------------------------------
267     *
268     * TkpGetNativeFont --
269     *
270     *      Map a platform-specific native font name to a TkFont.
271     *
272     * Results:
273     *      The return value is a pointer to a TkFont that represents the
274     *      native font.  If a native font by the given name could not be
275     *      found, the return value is NULL.  
276     *
277     *      Every call to this procedure returns a new TkFont structure,
278     *      even if the name has already been seen before.  The caller should
279     *      call TkpDeleteFont() when the font is no longer needed.
280     *
281     *      The caller is responsible for initializing the memory associated
282     *      with the generic TkFont when this function returns and releasing
283     *      the contents of the generic TkFont before calling TkpDeleteFont().
284     *
285     * Side effects:
286     *      Memory allocated.
287     *
288     *---------------------------------------------------------------------------
289     */
290    
291    TkFont *
292    TkpGetNativeFont(
293        Tk_Window tkwin,            /* For display where font will be used. */
294        CONST char *name)           /* Platform-specific font name. */
295    {
296        int object;
297        WinFont *fontPtr;
298    
299        object = TkFindStateNum(NULL, NULL, systemMap, name);
300        if (object < 0) {
301            return NULL;
302        }
303    
304        tkwin = (Tk_Window) ((TkWindow *) tkwin)->mainPtr->winPtr;
305        fontPtr = (WinFont *) ckalloc(sizeof(WinFont));
306        InitFont(tkwin, GetStockObject(object), 0, fontPtr);
307    
308        return (TkFont *) fontPtr;
309    }
310    
311    /*
312     *---------------------------------------------------------------------------
313     *
314     * TkpGetFontFromAttributes --
315     *
316     *      Given a desired set of attributes for a font, find a font with
317     *      the closest matching attributes.
318     *
319     * Results:
320     *      The return value is a pointer to a TkFont that represents the
321     *      font with the desired attributes.  If a font with the desired
322     *      attributes could not be constructed, some other font will be
323     *      substituted automatically.  NULL is never returned.
324     *
325     *      Every call to this procedure returns a new TkFont structure,
326     *      even if the specified attributes have already been seen before.
327     *      The caller should call TkpDeleteFont() to free the platform-
328     *      specific data when the font is no longer needed.  
329     *
330     *      The caller is responsible for initializing the memory associated
331     *      with the generic TkFont when this function returns and releasing
332     *      the contents of the generic TkFont before calling TkpDeleteFont().
333     *
334     * Side effects:
335     *      Memory allocated.
336     *
337     *---------------------------------------------------------------------------
338     */
339    
340    TkFont *
341    TkpGetFontFromAttributes(
342        TkFont *tkFontPtr,          /* If non-NULL, store the information in
343                                     * this existing TkFont structure, rather than
344                                     * allocating a new structure to hold the
345                                     * font; the existing contents of the font
346                                     * will be released.  If NULL, a new TkFont
347                                     * structure is allocated. */
348        Tk_Window tkwin,            /* For display where font will be used. */
349        CONST TkFontAttributes *faPtr)
350                                    /* Set of attributes to match. */
351    {
352        int i, j;
353        HDC hdc;
354        HWND hwnd;
355        HFONT hFont;
356        Window window;
357        WinFont *fontPtr;
358        char ***fontFallbacks;
359        char *faceName, *fallback, *actualName;
360    
361        tkwin   = (Tk_Window) ((TkWindow *) tkwin)->mainPtr->winPtr;
362        window  = Tk_WindowId(tkwin);
363        hwnd    = (window == None) ? NULL : TkWinGetHWND(window);
364        hdc     = GetDC(hwnd);
365    
366        /*
367         * Algorithm to get the closest font name to the one requested.
368         *
369         * try fontname
370         * try all aliases for fontname
371         * foreach fallback for fontname
372         *      try the fallback
373         *      try all aliases for the fallback
374         */
375    
376        faceName = faPtr->family;
377        if (faceName != NULL) {
378            actualName = FamilyOrAliasExists(hdc, faceName);
379            if (actualName != NULL) {
380                faceName = actualName;
381                goto found;
382            }
383            fontFallbacks = TkFontGetFallbacks();
384            for (i = 0; fontFallbacks[i] != NULL; i++) {
385                for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
386                    if (strcasecmp(faceName, fallback) == 0) {
387                        break;
388                    }
389                }
390                if (fallback != NULL) {
391                    for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
392                        actualName = FamilyOrAliasExists(hdc, fallback);
393                        if (actualName != NULL) {
394                            faceName = actualName;
395                            goto found;
396                        }
397                    }
398                }
399            }
400        }
401    
402        found:
403        ReleaseDC(hwnd, hdc);
404    
405        hFont = GetScreenFont(faPtr, faceName, TkFontGetPixels(tkwin, faPtr->size));
406        if (tkFontPtr == NULL) {
407            fontPtr = (WinFont *) ckalloc(sizeof(WinFont));
408        } else {
409            fontPtr = (WinFont *) tkFontPtr;
410            ReleaseFont(fontPtr);
411        }
412        InitFont(tkwin, hFont, faPtr->overstrike, fontPtr);
413    
414        return (TkFont *) fontPtr;
415    }
416    
417    /*
418     *---------------------------------------------------------------------------
419     *
420     * TkpDeleteFont --
421     *
422     *      Called to release a font allocated by TkpGetNativeFont() or
423     *      TkpGetFontFromAttributes().  The caller should have already
424     *      released the fields of the TkFont that are used exclusively by
425     *      the generic TkFont code.
426     *
427     * Results:
428     *      None.
429     *
430     * Side effects:
431     *      TkFont is deallocated.
432     *
433     *---------------------------------------------------------------------------
434     */
435    
436    void
437    TkpDeleteFont(
438        TkFont *tkFontPtr)          /* Token of font to be deleted. */
439    {
440        WinFont *fontPtr;
441    
442        fontPtr = (WinFont *) tkFontPtr;
443        ReleaseFont(fontPtr);
444    }
445    
446    /*
447     *---------------------------------------------------------------------------
448     *
449     * TkpGetFontFamilies, WinFontFamilyEnumProc --
450     *
451     *      Return information about the font families that are available
452     *      on the display of the given window.
453     *
454     * Results:
455     *      Modifies interp's result object to hold a list of all the available
456     *      font families.
457     *
458     * Side effects:
459     *      None.
460     *
461     *---------------------------------------------------------------------------
462     */
463    
464    void
465    TkpGetFontFamilies(
466        Tcl_Interp *interp,         /* Interp to hold result. */
467        Tk_Window tkwin)            /* For display to query. */
468    {    
469        HDC hdc;
470        HWND hwnd;
471        Window window;
472    
473        window  = Tk_WindowId(tkwin);
474        hwnd    = (window == None) ? NULL : TkWinGetHWND(window);
475        hdc     = GetDC(hwnd);
476    
477        /*
478         * On any version NT, there may fonts with international names.  
479         * Use the NT-only Unicode version of EnumFontFamilies to get the
480         * font names.  If we used the ANSI version on a non-internationalized
481         * version of NT, we would get font names with '?' replacing all
482         * the international characters.
483         *
484         * On a non-internationalized verson of 95, fonts with international
485         * names are not allowed, so the ANSI version of EnumFontFamilies will
486         * work.  On an internationalized version of 95, there may be fonts with
487         * international names; the ANSI version will work, fetching the
488         * name in the system code page.  Can't use the Unicode version of
489         * EnumFontFamilies because it only exists under NT.
490         */
491    
492        if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
493            EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontFamilyEnumProc,
494                    (LPARAM) interp);
495        } else {
496            EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontFamilyEnumProc,
497                    (LPARAM) interp);
498        }      
499        ReleaseDC(hwnd, hdc);
500    }
501    
502    static int CALLBACK
503    WinFontFamilyEnumProc(
504        ENUMLOGFONT *lfPtr,         /* Logical-font data. */
505        NEWTEXTMETRIC *tmPtr,       /* Physical-font data (not used). */
506        int fontType,               /* Type of font (not used). */
507        LPARAM lParam)              /* Result object to hold result. */
508    {
509        char *faceName;
510        Tcl_DString faceString;
511        Tcl_Obj *strPtr;
512        Tcl_Interp *interp;
513    
514        interp = (Tcl_Interp *) lParam;
515        faceName = lfPtr->elfLogFont.lfFaceName;
516        Tcl_ExternalToUtfDString(systemEncoding, faceName, -1, &faceString);
517        strPtr = Tcl_NewStringObj(Tcl_DStringValue(&faceString),
518                Tcl_DStringLength(&faceString));
519        Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr);
520        Tcl_DStringFree(&faceString);
521        return 1;
522    }
523    
524    /*
525     *-------------------------------------------------------------------------
526     *
527     * TkpGetSubFonts --
528     *
529     *      A function used by the testing package for querying the actual
530     *      screen fonts that make up a font object.
531     *
532     * Results:
533     *      Modifies interp's result object to hold a list containing the
534     *      names of the screen fonts that make up the given font object.
535     *
536     * Side effects:
537     *      None.
538     *
539     *-------------------------------------------------------------------------
540     */
541            
542    void
543    TkpGetSubFonts(
544        Tcl_Interp *interp,         /* Interp to hold result. */
545        Tk_Font tkfont)             /* Font object to query. */
546    {
547        int i;
548        WinFont *fontPtr;
549        FontFamily *familyPtr;
550        Tcl_Obj *resultPtr, *strPtr;
551    
552        resultPtr = Tcl_GetObjResult(interp);    
553        fontPtr = (WinFont *) tkfont;
554        for (i = 0; i < fontPtr->numSubFonts; i++) {
555            familyPtr = fontPtr->subFontArray[i].familyPtr;
556            strPtr = Tcl_NewStringObj(familyPtr->faceName, -1);
557            Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
558        }
559    }
560    
561    /*
562     *---------------------------------------------------------------------------
563     *
564     *  Tk_MeasureChars --
565     *
566     *      Determine the number of bytes from the string that will fit
567     *      in the given horizontal span.  The measurement is done under the
568     *      assumption that Tk_DrawChars() will be used to actually display
569     *      the characters.
570     *
571     * Results:
572     *      The return value is the number of bytes from source that
573     *      fit into the span that extends from 0 to maxLength.  *lengthPtr is
574     *      filled with the x-coordinate of the right edge of the last
575     *      character that did fit.
576     *
577     * Side effects:
578     *      None.
579     *
580     *---------------------------------------------------------------------------
581     */
582    
583    int
584    Tk_MeasureChars(
585        Tk_Font tkfont,             /* Font in which characters will be drawn. */
586        CONST char *source,         /* UTF-8 string to be displayed.  Need not be
587                                     * '\0' terminated. */
588        int numBytes,               /* Maximum number of bytes to consider
589                                     * from source string. */
590        int maxLength,              /* If >= 0, maxLength specifies the longest
591                                     * permissible line length in pixels; don't
592                                     * consider any character that would cross
593                                     * this x-position.  If < 0, then line length
594                                     * is unbounded and the flags argument is
595                                     * ignored. */
596        int flags,                  /* Various flag bits OR-ed together:
597                                     * TK_PARTIAL_OK means include the last char
598                                     * which only partially fit on this line.
599                                     * TK_WHOLE_WORDS means stop on a word
600                                     * boundary, if possible.
601                                     * TK_AT_LEAST_ONE means return at least one
602                                     * character even if no characters fit. */
603        int *lengthPtr)             /* Filled with x-location just after the
604                                     * terminating character. */
605    {
606        HDC hdc;
607        HFONT oldFont;
608        WinFont *fontPtr;
609        int curX, curByte;
610        SubFont *lastSubFontPtr;
611    
612        /*
613         * According to Microsoft tech support, Windows does not use kerning
614         * or fractional character widths when displaying text on the screen.
615         * So that means we can safely measure individual characters or spans
616         * of characters and add up the widths w/o any "off-by-one-pixel"
617         * errors.  
618         */
619    
620        fontPtr = (WinFont *) tkfont;
621    
622        hdc = GetDC(fontPtr->hwnd);
623        lastSubFontPtr = &fontPtr->subFontArray[0];
624        oldFont = SelectObject(hdc, lastSubFontPtr->hFont);
625    
626        if (numBytes == 0) {
627            curX = 0;
628            curByte = 0;
629        } else if (maxLength < 0) {                          
630            Tcl_UniChar ch;
631            SIZE size;
632            FontFamily *familyPtr;
633            Tcl_DString runString;
634            SubFont *thisSubFontPtr;
635            CONST char *p, *end, *next;
636    
637            /*
638             * A three step process:
639             * 1. Find a contiguous range of characters that can all be
640             *    represented by a single screen font.
641             * 2. Convert those chars to the encoding of that font.
642             * 3. Measure converted chars.
643             */
644    
645            curX = 0;
646            end = source + numBytes;
647            for (p = source; p < end; ) {
648                next = p + Tcl_UtfToUniChar(p, &ch);
649                thisSubFontPtr = FindSubFontForChar(fontPtr, ch);
650                if (thisSubFontPtr != lastSubFontPtr) {
651                    familyPtr = lastSubFontPtr->familyPtr;
652                    Tcl_UtfToExternalDString(familyPtr->encoding, source,
653                            p - source, &runString);
654                    (*familyPtr->getTextExtentPoint32Proc)(hdc,
655                            Tcl_DStringValue(&runString),
656                            Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
657                            &size);
658                    curX += size.cx;
659                    Tcl_DStringFree(&runString);
660                    lastSubFontPtr = thisSubFontPtr;
661                    source = p;
662    
663                    SelectObject(hdc, lastSubFontPtr->hFont);
664                }
665                p = next;
666            }
667            familyPtr = lastSubFontPtr->familyPtr;
668            Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,
669                    &runString);
670            (*familyPtr->getTextExtentPoint32Proc)(hdc,
671                    Tcl_DStringValue(&runString),
672                    Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
673                    &size);
674            curX += size.cx;
675            Tcl_DStringFree(&runString);
676            curByte = numBytes;
677        } else {
678            Tcl_UniChar ch;
679            SIZE size;
680            char buf[16];
681            FontFamily *familyPtr;
682            SubFont *thisSubFontPtr;
683            CONST char *term, *end, *p, *next;
684            int newX, termX, sawNonSpace, dstWrote;
685    
686            /*
687             * How many chars will fit in the space allotted?
688             * This first version may be inefficient because it measures
689             * every character individually.  There is a function call that
690             * can measure multiple characters at once and return the
691             * offset of each of them, but it only works on NT, even though
692             * the documentation claims it works for 95.
693             * TODO: verify that GetTextExtentExPoint is still broken in '95, and
694             * possibly use it for NT anyway since it should be much faster and
695             * more accurate.
696             */
697    
698            next = source + Tcl_UtfToUniChar(source, &ch);
699            newX = curX = termX = 0;
700            
701            term = source;
702            end = source + numBytes;
703    
704            sawNonSpace = (ch > 255) || !isspace(ch);
705            for (p = source; ; ) {
706                if (ch < BASE_CHARS) {
707                    newX += fontPtr->widths[ch];
708                } else {
709                    thisSubFontPtr = FindSubFontForChar(fontPtr, ch);
710                    if (thisSubFontPtr != lastSubFontPtr) {
711                        SelectObject(hdc, thisSubFontPtr->hFont);
712                        lastSubFontPtr = thisSubFontPtr;
713                    }
714                    familyPtr = lastSubFontPtr->familyPtr;
715                    Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p,
716                            0, NULL, buf, sizeof(buf), NULL, &dstWrote, NULL);
717                    (*familyPtr->getTextExtentPoint32Proc)(hdc, buf,
718                            dstWrote >> familyPtr->isWideFont, &size);
719                    newX += size.cx;
720                }
721                if (newX > maxLength) {
722                    break;
723                }
724                curX = newX;
725                p = next;
726                if (p >= end) {
727                    term = end;
728                    termX = curX;
729                    break;
730                }
731    
732                next += Tcl_UtfToUniChar(next, &ch);
733                if ((ch < 256) && isspace(ch)) {
734                    if (sawNonSpace) {
735                        term = p;
736                        termX = curX;
737                        sawNonSpace = 0;
738                    }
739                } else {
740                    sawNonSpace = 1;
741                }
742            }
743    
744            /*
745             * P points to the first character that doesn't fit in the desired
746             * span.  Use the flags to figure out what to return.
747             */
748    
749            if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) {
750                /*
751                 * Include the first character that didn't quite fit in the desired
752                 * span.  The width returned will include the width of that extra
753                 * character.
754                 */
755    
756                curX = newX;
757                p += Tcl_UtfToUniChar(p, &ch);
758            }
759            if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) {
760                term = p;
761                termX = curX;
762                if (term == source) {
763                    term += Tcl_UtfToUniChar(term, &ch);
764                    termX = newX;
765                }
766            } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) {
767                term = p;
768                termX = curX;
769            }
770    
771            curX = termX;
772            curByte = term - source;        
773        }
774    
775        SelectObject(hdc, oldFont);
776        ReleaseDC(fontPtr->hwnd, hdc);
777    
778        *lengthPtr = curX;
779        return curByte;
780    }
781    
782    /*
783     *---------------------------------------------------------------------------
784     *
785     * Tk_DrawChars --
786     *
787     *      Draw a string of characters on the screen.  
788     *
789     * Results:
790     *      None.
791     *
792     * Side effects:
793     *      Information gets drawn on the screen.
794     *
795     *---------------------------------------------------------------------------
796     */
797    
798    void
799    Tk_DrawChars(
800        Display *display,           /* Display on which to draw. */
801        Drawable drawable,          /* Window or pixmap in which to draw. */
802        GC gc,                      /* Graphics context for drawing characters. */
803        Tk_Font tkfont,             /* Font in which characters will be drawn;
804                                     * must be the same as font used in GC. */
805        CONST char *source,         /* UTF-8 string to be displayed.  Need not be
806                                     * '\0' terminated.  All Tk meta-characters
807                                     * (tabs, control characters, and newlines)
808                                     * should be stripped out of the string that
809                                     * is passed to this function.  If they are
810                                     * not stripped out, they will be displayed as
811                                     * regular printing characters. */
812        int numBytes,               /* Number of bytes in string. */
813        int x, int y)               /* Coordinates at which to place origin of
814                                     * string when drawing. */
815    {
816        HDC dc;
817        WinFont *fontPtr;
818        TkWinDCState state;
819    
820        fontPtr = (WinFont *) gc->font;
821        display->request++;
822    
823        if (drawable == None) {
824            return;
825        }
826    
827        dc = TkWinGetDrawableDC(display, drawable, &state);
828    
829        SetROP2(dc, tkpWinRopModes[gc->function]);
830    
831        if ((gc->fill_style == FillStippled
832                || gc->fill_style == FillOpaqueStippled)
833                && gc->stipple != None) {
834            TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
835            HBRUSH oldBrush, stipple;
836            HBITMAP oldBitmap, bitmap;
837            HDC dcMem;
838            TEXTMETRIC tm;
839            SIZE size;
840    
841            if (twdPtr->type != TWD_BITMAP) {
842                panic("unexpected drawable type in stipple");
843            }
844    
845            /*
846             * Select stipple pattern into destination dc.
847             */
848            
849            dcMem = CreateCompatibleDC(dc);
850    
851            stipple = CreatePatternBrush(twdPtr->bitmap.handle);
852            SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
853            oldBrush = SelectObject(dc, stipple);
854    
855            SetTextAlign(dcMem, TA_LEFT | TA_BASELINE);
856            SetTextColor(dcMem, gc->foreground);
857            SetBkMode(dcMem, TRANSPARENT);
858            SetBkColor(dcMem, RGB(0, 0, 0));
859    
860            /*
861             * Compute the bounding box and create a compatible bitmap.
862             */
863    
864            GetTextExtentPoint(dcMem, source, numBytes, &size);
865            GetTextMetrics(dcMem, &tm);
866            size.cx -= tm.tmOverhang;
867            bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy);
868            oldBitmap = SelectObject(dcMem, bitmap);
869    
870            /*
871             * The following code is tricky because fonts are rendered in multiple
872             * colors.  First we draw onto a black background and copy the white
873             * bits.  Then we draw onto a white background and copy the black bits.
874             * Both the foreground and background bits of the font are ANDed with
875             * the stipple pattern as they are copied.
876             */
877    
878            PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS);
879            MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);
880            BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
881                    0, 0, 0xEA02E9);
882            PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS);
883            MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);
884            BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
885                    0, 0, 0x8A0E06);
886    
887            /*
888             * Destroy the temporary bitmap and restore the device context.
889             */
890    
891            SelectObject(dcMem, oldBitmap);
892            DeleteObject(bitmap);
893            DeleteDC(dcMem);
894            SelectObject(dc, oldBrush);
895            DeleteObject(stipple);
896        } else {
897            SetTextAlign(dc, TA_LEFT | TA_BASELINE);
898            SetTextColor(dc, gc->foreground);
899            SetBkMode(dc, TRANSPARENT);
900            MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);
901        }
902        TkWinReleaseDrawableDC(drawable, dc, &state);
903    }
904    
905    /*
906     *-------------------------------------------------------------------------
907     *
908     * MultiFontTextOut --
909     *
910     *      Helper function for Tk_DrawChars.  Draws characters, using the
911     *      various screen fonts in fontPtr to draw multilingual characters.
912     *      Note: No bidirectional support.
913     *
914     * Results:
915     *      None.
916     *
917     * Side effects:
918     *      Information gets drawn on the screen.  
919     *      Contents of fontPtr may be modified if more subfonts were loaded
920     *      in order to draw all the multilingual characters in the given
921     *      string.
922     *
923     *-------------------------------------------------------------------------
924     */
925    
926    static void
927    MultiFontTextOut(
928        HDC hdc,                    /* HDC to draw into. */
929        WinFont *fontPtr,           /* Contains set of fonts to use when drawing
930                                     * following string. */
931        CONST char *source,         /* Potentially multilingual UTF-8 string. */
932        int numBytes,               /* Length of string in bytes. */
933        int x, int y)               /* Coordinates at which to place origin *
934                                     * of string when drawing. */
935    {
936        Tcl_UniChar ch;
937        SIZE size;
938        HFONT oldFont;
939        FontFamily *familyPtr;
940        Tcl_DString runString;
941        CONST char *p, *end, *next;
942        SubFont *lastSubFontPtr, *thisSubFontPtr;
943    
944        lastSubFontPtr = &fontPtr->subFontArray[0];
945        oldFont = SelectObject(hdc, lastSubFontPtr->hFont);
946    
947        end = source + numBytes;
948        for (p = source; p < end; ) {
949            next = p + Tcl_UtfToUniChar(p, &ch);
950            thisSubFontPtr = FindSubFontForChar(fontPtr, ch);
951            if (thisSubFontPtr != lastSubFontPtr) {
952                if (p > source) {
953                    familyPtr = lastSubFontPtr->familyPtr;
954                    Tcl_UtfToExternalDString(familyPtr->encoding, source,
955                            p - source, &runString);
956                    (*familyPtr->textOutProc)(hdc, x, y,
957                            Tcl_DStringValue(&runString),
958                            Tcl_DStringLength(&runString) >> familyPtr->isWideFont);
959                    (*familyPtr->getTextExtentPoint32Proc)(hdc,
960                            Tcl_DStringValue(&runString),
961                            Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
962                            &size);
963                    x += size.cx;
964                    Tcl_DStringFree(&runString);
965                }
966                lastSubFontPtr = thisSubFontPtr;
967                source = p;
968                SelectObject(hdc, lastSubFontPtr->hFont);
969            }
970            p = next;
971        }
972        if (p > source) {
973            familyPtr = lastSubFontPtr->familyPtr;
974            Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,
975                    &runString);
976            (*familyPtr->textOutProc)(hdc, x, y, Tcl_DStringValue(&runString),
977                    Tcl_DStringLength(&runString) >> familyPtr->isWideFont);
978            Tcl_DStringFree(&runString);
979        }
980        SelectObject(hdc, oldFont);
981    }
982    
983    /*
984     *---------------------------------------------------------------------------
985     *
986     * InitFont --
987     *
988     *      Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
989     *      Initializes the memory for a new WinFont that wraps the
990     *      platform-specific data.
991     *
992     *      The caller is responsible for initializing the fields of the
993     *      WinFont that are used exclusively by the generic TkFont code, and
994     *      for releasing those fields before calling TkpDeleteFont().
995     *
996     * Results:
997     *      Fills the WinFont structure.
998     *
999     * Side effects:
1000     *      Memory allocated.
1001     *
1002     *---------------------------------------------------------------------------
1003     */
1004    
1005    static void
1006    InitFont(
1007        Tk_Window tkwin,            /* Main window of interp in which font will
1008                                     * be used, for getting HDC. */
1009        HFONT hFont,                /* Windows token for font. */
1010        int overstrike,             /* The overstrike attribute of logfont used
1011                                     * to allocate this font.  For some reason,
1012                                     * the TEXTMETRICs may contain incorrect info
1013                                     * in the tmStruckOut field. */
1014        WinFont *fontPtr)           /* Filled with information constructed from
1015                                     * the above arguments. */
1016    {
1017        HDC hdc;
1018        HWND hwnd;
1019        HFONT oldFont;
1020        TEXTMETRIC tm;
1021        Window window;
1022        TkFontMetrics *fmPtr;
1023        Tcl_Encoding encoding;
1024        Tcl_DString faceString;
1025        TkFontAttributes *faPtr;
1026        char buf[LF_FACESIZE * sizeof(WCHAR)];
1027    
1028        window  = Tk_WindowId(tkwin);
1029        hwnd    = (window == None) ? NULL : TkWinGetHWND(window);
1030        hdc     = GetDC(hwnd);
1031        oldFont = SelectObject(hdc, hFont);
1032    
1033        GetTextMetrics(hdc, &tm);
1034    
1035        /*
1036         * On any version NT, there may fonts with international names.  
1037         * Use the NT-only Unicode version of GetTextFace to get the font's
1038         * name.  If we used the ANSI version on a non-internationalized
1039         * version of NT, we would get a font name with '?' replacing all
1040         * the international characters.
1041         *
1042         * On a non-internationalized verson of 95, fonts with international
1043         * names are not allowed, so the ANSI version of GetTextFace will work.
1044         * On an internationalized version of 95, there may be fonts with
1045         * international names; the ANSI version will work, fetching the
1046         * name in the international system code page.  Can't use the Unicode
1047         * version of GetTextFace because it only exists under NT.
1048         */
1049    
1050        if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1051            GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf);
1052        } else {
1053            GetTextFaceA(hdc, LF_FACESIZE, (char *) buf);
1054        }
1055        Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString);
1056    
1057        fontPtr->font.fid   = (Font) fontPtr;
1058    
1059        faPtr               = &fontPtr->font.fa;
1060        faPtr->family       = Tk_GetUid(Tcl_DStringValue(&faceString));
1061        faPtr->size         = TkFontGetPoints(tkwin, -(tm.tmHeight - tm.tmInternalLeading));
1062        faPtr->weight       = (tm.tmWeight > FW_MEDIUM) ? TK_FW_BOLD : TK_FW_NORMAL;
1063        faPtr->slant        = (tm.tmItalic != 0) ? TK_FS_ITALIC : TK_FS_ROMAN;
1064        faPtr->underline    = (tm.tmUnderlined != 0) ? 1 : 0;
1065        faPtr->overstrike   = overstrike;
1066        
1067        fmPtr               = &fontPtr->font.fm;
1068        fmPtr->ascent       = tm.tmAscent;
1069        fmPtr->descent      = tm.tmDescent;
1070        fmPtr->maxWidth     = tm.tmMaxCharWidth;
1071        fmPtr->fixed        = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
1072    
1073        fontPtr->hwnd       = hwnd;
1074        fontPtr->pixelSize  = tm.tmHeight - tm.tmInternalLeading;
1075    
1076        fontPtr->numSubFonts        = 1;
1077        fontPtr->subFontArray       = fontPtr->staticSubFonts;
1078        InitSubFont(hdc, hFont, 1, &fontPtr->subFontArray[0]);
1079    
1080        encoding = fontPtr->subFontArray[0].familyPtr->encoding;
1081        if (encoding == unicodeEncoding) {
1082            GetCharWidthW(hdc, 0, BASE_CHARS - 1, fontPtr->widths);
1083        } else {
1084            GetCharWidthA(hdc, 0, BASE_CHARS - 1, fontPtr->widths);
1085        }
1086        Tcl_DStringFree(&faceString);
1087    
1088        SelectObject(hdc, oldFont);
1089        ReleaseDC(hwnd, hdc);
1090    }
1091    
1092    /*
1093     *-------------------------------------------------------------------------
1094     *
1095     * ReleaseFont --
1096     *
1097     *      Called to release the windows-specific contents of a TkFont.
1098     *      The caller is responsible for freeing the memory used by the
1099     *      font itself.
1100     *
1101     * Results:
1102     *      None.
1103     *
1104     * Side effects:
1105     *      Memory is freed.
1106     *
1107     *---------------------------------------------------------------------------
1108     */
1109    
1110    static void
1111    ReleaseFont(
1112        WinFont *fontPtr)           /* The font to delete. */
1113    {
1114        int i;
1115    
1116        for (i = 0; i < fontPtr->numSubFonts; i++) {
1117            ReleaseSubFont(&fontPtr->subFontArray[i]);
1118        }
1119        if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
1120            ckfree((char *) fontPtr->subFontArray);
1121        }
1122    }
1123    
1124    /*
1125     *-------------------------------------------------------------------------
1126     *
1127     * InitSubFont --
1128     *
1129     *      Wrap a screen font and load the FontFamily that represents
1130     *      it.  Used to prepare a SubFont so that characters can be mapped
1131     *      from UTF-8 to the charset of the font.
1132     *
1133     * Results:
1134     *      The subFontPtr is filled with information about the font.
1135     *
1136     * Side effects:
1137     *      None.
1138     *
1139     *-------------------------------------------------------------------------
1140     */
1141    
1142    static void
1143    InitSubFont(
1144        HDC hdc,                    /* HDC in which font can be selected. */
1145        HFONT hFont,                /* The screen font. */
1146        int base,                   /* Non-zero if this SubFont is being used
1147                                     * as the base font for a font object. */
1148        SubFont *subFontPtr)        /* Filled with SubFont constructed from
1149                                     * above attributes. */
1150    {
1151        subFontPtr->hFont       = hFont;
1152        subFontPtr->familyPtr   = AllocFontFamily(hdc, hFont, base);
1153        subFontPtr->fontMap     = subFontPtr->familyPtr->fontMap;
1154    }
1155    
1156    /*
1157     *-------------------------------------------------------------------------
1158     *
1159     * ReleaseSubFont --
1160     *
1161     *      Called to release the contents of a SubFont.  The caller is
1162     *      responsible for freeing the memory used by the SubFont itself.
1163     *
1164     * Results:
1165     *      None.
1166     *
1167     * Side effects:
1168     *      Memory and resources are freed.
1169     *
1170     *---------------------------------------------------------------------------
1171     */
1172    
1173    static void
1174    ReleaseSubFont(
1175        SubFont *subFontPtr)        /* The SubFont to delete. */
1176    {
1177        DeleteObject(subFontPtr->hFont);
1178        FreeFontFamily(subFontPtr->familyPtr);
1179    }
1180    
1181    /*
1182     *-------------------------------------------------------------------------
1183     *
1184     * AllocFontFamily --
1185     *
1186     *      Find the FontFamily structure associated with the given font
1187     *      name.  The information should be stored by the caller in a
1188     *      SubFont and used when determining if that SubFont supports a
1189     *      character.
1190     *
1191     *      Cannot use the string name used to construct the font as the
1192     *      key, because the capitalization may not be canonical.  Therefore
1193     *      use the face name actually retrieved from the font metrics as
1194     *      the key.
1195     *
1196     * Results:
1197     *      A pointer to a FontFamily.  The reference count in the FontFamily
1198     *      is automatically incremented.  When the SubFont is released, the
1199     *      reference count is decremented.  When no SubFont is using this
1200     *      FontFamily, it may be deleted.
1201     *
1202     * Side effects:
1203     *      A new FontFamily structure will be allocated if this font family
1204     *      has not been seen.  TrueType character existence metrics are
1205     *      loaded into the FontFamily structure.
1206     *
1207     *-------------------------------------------------------------------------
1208     */
1209    
1210    static FontFamily *
1211    AllocFontFamily(
1212        HDC hdc,                    /* HDC in which font can be selected. */
1213        HFONT hFont,                /* Screen font whose FontFamily is to be
1214                                     * returned. */
1215        int base)                   /* Non-zero if this font family is to be
1216                                     * used in the base font of a font object. */
1217    {
1218        Tk_Uid faceName;
1219        FontFamily *familyPtr;
1220        Tcl_DString faceString;
1221        Tcl_Encoding encoding;
1222        char buf[LF_FACESIZE * sizeof(WCHAR)];
1223        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1224                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1225    
1226        hFont = SelectObject(hdc, hFont);
1227        if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1228            GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf);
1229        } else {
1230            GetTextFaceA(hdc, LF_FACESIZE, (char *) buf);
1231        }
1232        Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString);
1233        faceName = Tk_GetUid(Tcl_DStringValue(&faceString));
1234        Tcl_DStringFree(&faceString);
1235        hFont = SelectObject(hdc, hFont);
1236    
1237        familyPtr = tsdPtr->fontFamilyList;
1238        for ( ; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {
1239            if (familyPtr->faceName == faceName) {
1240                familyPtr->refCount++;
1241                return familyPtr;
1242            }
1243        }
1244    
1245        familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily));
1246        memset(familyPtr, 0, sizeof(FontFamily));
1247        familyPtr->nextPtr = tsdPtr->fontFamilyList;
1248        tsdPtr->fontFamilyList = familyPtr;
1249    
1250        /*
1251         * Set key for this FontFamily.
1252         */
1253    
1254        familyPtr->faceName = faceName;
1255    
1256        /*
1257         * An initial refCount of 2 means that FontFamily information will
1258         * persist even when the SubFont that loaded the FontFamily is released.
1259         * Change it to 1 to cause FontFamilies to be unloaded when not in use.
1260         */
1261    
1262        familyPtr->refCount = 2;
1263    
1264        familyPtr->segCount = LoadFontRanges(hdc, hFont, &familyPtr->startCount,
1265                &familyPtr->endCount, &familyPtr->isSymbolFont);
1266    
1267        encoding = NULL;
1268        if (familyPtr->isSymbolFont != 0) {
1269            /*
1270             * Symbol fonts are handled specially.  For instance, Unicode 0393
1271             * (GREEK CAPITAL GAMMA) must be mapped to Symbol character 0047
1272             * (GREEK CAPITAL GAMMA), because the Symbol font doesn't have a
1273             * GREEK CAPITAL GAMMA at location 0393.  If Tk interpreted the
1274             * Symbol font using the Unicode encoding, it would decide that
1275             * the Symbol font has no GREEK CAPITAL GAMMA, because the Symbol
1276             * encoding (of course) reports that character 0393 doesn't exist.  
1277             *
1278             * With non-symbol Windows fonts, such as Times New Roman, if the
1279             * font has a GREEK CAPITAL GAMMA, it will be found in the correct
1280             * Unicode location (0393); the GREEK CAPITAL GAMMA will not be off
1281             * hiding at some other location.
1282             */
1283    
1284            encoding = Tcl_GetEncoding(NULL, faceName);
1285        }
1286    
1287        if (encoding == NULL) {
1288            encoding = Tcl_GetEncoding(NULL, "unicode");
1289            familyPtr->textOutProc =
1290                (BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutW;
1291            familyPtr->getTextExtentPoint32Proc =
1292                (BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32W;
1293            familyPtr->isWideFont = 1;
1294        } else {
1295            familyPtr->textOutProc =
1296                (BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutA;
1297            familyPtr->getTextExtentPoint32Proc =
1298                (BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32A;
1299            familyPtr->isWideFont = 0;
1300        }
1301    
1302        familyPtr->encoding = encoding;
1303    
1304        return familyPtr;
1305    }
1306    
1307    /*
1308     *-------------------------------------------------------------------------
1309     *
1310     * FreeFontFamily --
1311     *
1312     *      Called to free a FontFamily when the SubFont is finished using it.
1313     *      Frees the contents of the FontFamily and the memory used by the
1314     *      FontFamily itself.
1315     *
1316     * Results:
1317     *      None.
1318     *
1319     * Side effects:
1320     *      None.
1321     *
1322     *-------------------------------------------------------------------------
1323     */
1324    
1325    static void
1326    FreeFontFamily(
1327        FontFamily *familyPtr)      /* The FontFamily to delete. */
1328    {
1329        int i;
1330        FontFamily **familyPtrPtr;
1331        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1332                Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1333    
1334        if (familyPtr == NULL) {
1335            return;
1336        }
1337        familyPtr->refCount--;
1338        if (familyPtr->refCount > 0) {
1339            return;
1340        }
1341        for (i = 0; i < FONTMAP_PAGES; i++) {
1342            if (familyPtr->fontMap[i] != NULL) {
1343                ckfree(familyPtr->fontMap[i]);
1344            }
1345        }
1346        if (familyPtr->startCount != NULL) {
1347            ckfree((char *) familyPtr->startCount);
1348        }
1349        if (familyPtr->endCount != NULL) {
1350            ckfree((char *) familyPtr->endCount);
1351        }
1352        if (familyPtr->encoding != unicodeEncoding) {
1353            Tcl_FreeEncoding(familyPtr->encoding);
1354        }
1355        
1356        /*
1357         * Delete from list.
1358         */
1359            
1360        for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) {
1361            if (*familyPtrPtr == familyPtr) {
1362                *familyPtrPtr = familyPtr->nextPtr;
1363                break;
1364            }
1365            familyPtrPtr = &(*familyPtrPtr)->nextPtr;
1366        }
1367        
1368        ckfree((char *) familyPtr);
1369    }
1370    
1371    /*
1372     *-------------------------------------------------------------------------
1373     *
1374     * FindSubFontForChar --
1375     *
1376     *      Determine which screen font is necessary to use to display the
1377     *      given character.  If the font object does not have a screen font
1378     *      that can display the character, another screen font may be loaded
1379     *      into the font object, following a set of preferred fallback rules.
1380     *
1381     * Results:
1382     *      The return value is the SubFont to use to display the given
1383     *      character.
1384     *
1385     * Side effects:
1386     *      The contents of fontPtr are modified to cache the results
1387     *      of the lookup and remember any SubFonts that were dynamically
1388     *      loaded.
1389     *
1390     *-------------------------------------------------------------------------
1391     */
1392    
1393    static SubFont *
1394    FindSubFontForChar(
1395        WinFont *fontPtr,           /* The font object with which the character
1396                                     * will be displayed. */
1397        int ch)                     /* The Unicode character to be displayed. */
1398    {
1399        HDC hdc;
1400        int i, j, k;
1401        CanUse canUse;
1402        char **aliases, **anyFallbacks;
1403        char ***fontFallbacks;
1404        char *fallbackName;
1405        SubFont *subFontPtr;
1406        Tcl_DString ds;
1407        
1408        if (ch < BASE_CHARS) {
1409            return &fontPtr->subFontArray[0];
1410        }
1411    
1412        for (i = 0; i < fontPtr->numSubFonts; i++) {
1413            if (FontMapLookup(&fontPtr->subFontArray[i], ch)) {
1414                return &fontPtr->subFontArray[i];
1415            }
1416        }
1417    
1418        /*
1419         * Keep track of all face names that we check, so we don't check some
1420         * name multiple times if it can be reached by multiple paths.
1421         */
1422        
1423        Tcl_DStringInit(&ds);
1424        hdc = GetDC(fontPtr->hwnd);
1425            
1426        aliases = TkFontGetAliasList(fontPtr->font.fa.family);
1427    
1428        fontFallbacks = TkFontGetFallbacks();
1429        for (i = 0; fontFallbacks[i] != NULL; i++) {
1430            for (j = 0; fontFallbacks[i][j] != NULL; j++) {
1431                fallbackName = fontFallbacks[i][j];
1432                if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 0) {
1433                    /*
1434                     * If the base font has a fallback...
1435                     */
1436    
1437                    goto tryfallbacks;
1438                } else if (aliases != NULL) {
1439                    /*
1440                     * Or if an alias for the base font has a fallback...
1441                     */
1442    
1443                    for (k = 0; aliases[k] != NULL; k++) {
1444                        if (strcasecmp(aliases[k], fallbackName) == 0) {
1445                            goto tryfallbacks;
1446                        }
1447                    }
1448                }
1449            }
1450            continue;
1451    
1452            /*
1453             * ...then see if we can use one of the fallbacks, or an
1454             * alias for one of the fallbacks.
1455             */
1456    
1457            tryfallbacks:
1458            for (j = 0; fontFallbacks[i][j] != NULL; j++) {
1459                fallbackName = fontFallbacks[i][j];
1460                subFontPtr = CanUseFallbackWithAliases(hdc, fontPtr, fallbackName,
1461                        ch, &ds);
1462                if (subFontPtr != NULL) {
1463                    goto end;
1464                }
1465            }
1466        }
1467    
1468        /*
1469         * See if we can use something from the global fallback list.
1470         */
1471    
1472        anyFallbacks = TkFontGetGlobalClass();
1473        for (i = 0; anyFallbacks[i] != NULL; i++) {
1474            fallbackName = anyFallbacks[i];
1475            subFontPtr = CanUseFallbackWithAliases(hdc, fontPtr, fallbackName,
1476                    ch, &ds);
1477            if (subFontPtr != NULL) {
1478                goto end;
1479            }
1480        }
1481    
1482        /*
1483         * Try all face names available in the whole system until we
1484         * find one that can be used.
1485         */
1486    
1487        canUse.hdc = hdc;
1488        canUse.fontPtr = fontPtr;
1489        canUse.nameTriedPtr = &ds;
1490        canUse.ch = ch;
1491        canUse.subFontPtr = NULL;
1492        if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1493            EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontCanUseProc,
1494                    (LPARAM) &canUse);
1495        } else {
1496            EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontCanUseProc,
1497                    (LPARAM) &canUse);
1498        }
1499        subFontPtr = canUse.subFontPtr;
1500    
1501        end:
1502        Tcl_DStringFree(&ds);
1503        
1504        if (subFontPtr == NULL) {
1505            /*
1506             * No font can display this character.  We will use the base font
1507             * and have it display the "unknown" character.
1508             */
1509    
1510            subFontPtr = &fontPtr->subFontArray[0];
1511            FontMapInsert(subFontPtr, ch);
1512        }
1513        ReleaseDC(fontPtr->hwnd, hdc);
1514        return subFontPtr;
1515    }
1516    
1517    static int CALLBACK
1518    WinFontCanUseProc(
1519        ENUMLOGFONT *lfPtr,         /* Logical-font data. */
1520        NEWTEXTMETRIC *tmPtr,       /* Physical-font data (not used). */
1521        int fontType,               /* Type of font (not used). */
1522        LPARAM lParam)              /* Result object to hold result. */
1523    {
1524        int ch;
1525        HDC hdc;
1526        WinFont *fontPtr;
1527        CanUse *canUsePtr;
1528        char *fallbackName;
1529        SubFont *subFontPtr;
1530        Tcl_DString faceString;
1531        Tcl_DString *nameTriedPtr;
1532    
1533        canUsePtr       = (CanUse *) lParam;
1534        ch              = canUsePtr->ch;
1535        hdc             = canUsePtr->hdc;
1536        fontPtr         = canUsePtr->fontPtr;
1537        nameTriedPtr    = canUsePtr->nameTriedPtr;
1538    
1539        fallbackName = lfPtr->elfLogFont.lfFaceName;
1540        Tcl_ExternalToUtfDString(systemEncoding, fallbackName, -1, &faceString);
1541        fallbackName = Tcl_DStringValue(&faceString);
1542    
1543        if (SeenName(fallbackName, nameTriedPtr) == 0) {
1544            subFontPtr = CanUseFallback(hdc, fontPtr, fallbackName, ch);
1545            if (subFontPtr != NULL) {
1546                canUsePtr->subFontPtr = subFontPtr;
1547                Tcl_DStringFree(&faceString);
1548                return 0;
1549            }
1550        }
1551        Tcl_DStringFree(&faceString);
1552        return 1;
1553    }
1554    
1555    /*
1556     *-------------------------------------------------------------------------
1557     *
1558     * FontMapLookup --
1559     *
1560     *      See if the screen font can display the given character.
1561     *
1562     * Results:
1563     *      The return value is 0 if the screen font cannot display the
1564     *      character, non-zero otherwise.
1565     *
1566     * Side effects:
1567     *      New pages are added to the font mapping cache whenever the
1568     *      character belongs to a page that hasn't been seen before.
1569     *      When a page is loaded, information about all the characters on
1570     *      that page is stored, not just for the single character in
1571     *      question.
1572     *
1573     *-------------------------------------------------------------------------
1574     */
1575    
1576    static int
1577    FontMapLookup(
1578        SubFont *subFontPtr,        /* Contains font mapping cache to be queried
1579                                     * and possibly updated. */
1580        int ch)                     /* Character to be tested. */
1581    {
1582        int row, bitOffset;
1583    
1584        row = ch >> FONTMAP_SHIFT;
1585        if (subFontPtr->fontMap[row] == NULL) {
1586            FontMapLoadPage(subFontPtr, row);
1587        }
1588        bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
1589        return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;
1590    }
1591    
1592    /*
1593     *-------------------------------------------------------------------------
1594     *
1595     * FontMapInsert --
1596     *
1597     *      Tell the font mapping cache that the given screen font should be
1598     *      used to display the specified character.  This is called when no
1599     *      font on the system can be be found that can display that
1600     *      character; we lie to the font and tell it that it can display
1601     *      the character, otherwise we would end up re-searching the entire
1602     *      fallback hierarchy every time that character was seen.
1603     *
1604     * Results:
1605     *      None.
1606     *
1607     * Side effects:
1608     *      New pages are added to the font mapping cache whenever the
1609     *      character belongs to a page that hasn't been seen before.
1610     *      When a page is loaded, information about all the characters on
1611     *      that page is stored, not just for the single character in
1612     *      question.
1613     *
1614     *-------------------------------------------------------------------------
1615     */
1616    
1617    static void
1618    FontMapInsert(
1619        SubFont *subFontPtr,        /* Contains font mapping cache to be
1620                                     * updated. */
1621        int ch)                     /* Character to be added to cache. */
1622    {
1623        int row, bitOffset;
1624    
1625        row = ch >> FONTMAP_SHIFT;
1626        if (subFontPtr->fontMap[row] == NULL) {
1627            FontMapLoadPage(subFontPtr, row);
1628        }
1629        bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
1630        subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
1631    }
1632    
1633    /*
1634     *-------------------------------------------------------------------------
1635     *
1636     * FontMapLoadPage --
1637     *
1638     *      Load information about all the characters on a given page.
1639     *      This information consists of one bit per character that indicates
1640     *      whether the associated HFONT can (1) or cannot (0) display the
1641     *      characters on the page.
1642     *
1643     * Results:
1644     *      None.
1645     *
1646     * Side effects:
1647     *      Mempry allocated.
1648     *
1649     *-------------------------------------------------------------------------
1650     */
1651    static void
1652    FontMapLoadPage(
1653        SubFont *subFontPtr,        /* Contains font mapping cache to be
1654                                     * updated. */
1655        int row)                    /* Index of the page to be loaded into
1656                                     * the cache. */
1657    {
1658        FontFamily *familyPtr;
1659        Tcl_Encoding encoding;
1660        char src[TCL_UTF_MAX], buf[16];
1661        USHORT *startCount, *endCount;
1662        int i, j, bitOffset, end, segCount;
1663    
1664        subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8);
1665        memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
1666    
1667        familyPtr = subFontPtr->familyPtr;
1668        encoding = familyPtr->encoding;
1669    
1670        if (familyPtr->encoding == unicodeEncoding) {
1671            /*
1672             * Font is Unicode.  Few fonts are going to have all characters, so
1673             * examine the TrueType character existence metrics to determine
1674             * what characters actually exist in this font.
1675             */
1676    
1677            segCount    = familyPtr->segCount;
1678            startCount  = familyPtr->startCount;
1679            endCount    = familyPtr->endCount;
1680    
1681            j = 0;
1682            end = (row + 1) << FONTMAP_SHIFT;
1683            for (i = row << FONTMAP_SHIFT; i < end; i++) {
1684                for ( ; j < segCount; j++) {
1685                    if (endCount[j] >= i) {
1686                        if (startCount[j] <= i) {
1687                            bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
1688                            subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
1689                        }
1690                        break;
1691                    }
1692                }
1693            }
1694        } else if (familyPtr->isSymbolFont) {
1695            /*
1696             * Assume that a symbol font with a known encoding has all the
1697             * characters that its encoding claims it supports.  
1698             *      
1699             * The test for "encoding == unicodeEncoding"
1700             * must occur before this case, to catch all symbol fonts (such
1701             * as {Comic Sans MS} or Wingdings) for which we don't have
1702             * encoding information; those symbol fonts are treated as if
1703             * they were in the Unicode encoding and their symbolic
1704             * character existence metrics are treated as if they were Unicode
1705             * character existence metrics.  This way, although we don't know
1706             * the proper Unicode -> symbol font mapping, we can install the
1707             * symbol font as the base font and access its glyphs.
1708             */
1709    
1710            end = (row + 1) << FONTMAP_SHIFT;
1711            for (i = row << FONTMAP_SHIFT; i < end; i++) {
1712                if (Tcl_UtfToExternal(NULL, encoding, src,
1713                        Tcl_UniCharToUtf(i, src), TCL_ENCODING_STOPONERROR, NULL,
1714                        buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK) {
1715                    continue;
1716                }
1717                bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
1718                subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
1719            }
1720        }
1721    }
1722    
1723    /*
1724     *---------------------------------------------------------------------------
1725     *
1726     * CanUseFallbackWithAliases --
1727     *
1728     *      Helper function for FindSubFontForChar.  Determine if the
1729     *      specified face name (or an alias of the specified face name)
1730     *      can be used to construct a screen font that can display the
1731     *      given character.
1732     *
1733     * Results:
1734     *      See CanUseFallback().
1735     *
1736     * Side effects:
1737     *      If the name and/or one of its aliases was rejected, the
1738     *      rejected string is recorded in nameTriedPtr so that it won't
1739     *      be tried again.
1740     *
1741     *---------------------------------------------------------------------------
1742     */
1743    
1744    static SubFont *
1745    CanUseFallbackWithAliases(
1746        HDC hdc,                    /* HDC in which font can be selected. */
1747        WinFont *fontPtr,           /* The font object that will own the new
1748                                     * screen font. */
1749        char *faceName,             /* Desired face name for new screen font. */
1750        int ch,                     /* The Unicode character that the new
1751                                     * screen font must be able to display. */
1752        Tcl_DString *nameTriedPtr)  /* Records face names that have already
1753                                     * been tried.  It is possible for the same
1754                                     * face name to be queried multiple times when
1755                                     * trying to find a suitable screen font. */
1756    {
1757        int i;
1758        char **aliases;
1759        SubFont *subFontPtr;
1760        
1761        if (SeenName(faceName, nameTriedPtr) == 0) {
1762            subFontPtr = CanUseFallback(hdc, fontPtr, faceName, ch);
1763            if (subFontPtr != NULL) {
1764                return subFontPtr;
1765            }
1766        }
1767        aliases = TkFontGetAliasList(faceName);
1768        if (aliases != NULL) {
1769            for (i = 0; aliases[i] != NULL; i++) {
1770                if (SeenName(aliases[i], nameTriedPtr) == 0) {
1771                    subFontPtr = CanUseFallback(hdc, fontPtr, aliases[i], ch);
1772                    if (subFontPtr != NULL) {
1773                        return subFontPtr;
1774                    }
1775                }
1776            }
1777        }
1778        return NULL;
1779    }
1780    
1781    /*
1782     *---------------------------------------------------------------------------
1783     *
1784     * SeenName --
1785     *
1786     *      Used to determine we have already tried and rejected the given
1787     *      face name when looking for a screen font that can support some
1788     *      Unicode character.
1789     *
1790     * Results:
1791     *      The return value is 0 if this face name has not already been seen,
1792     *      non-zero otherwise.
1793     *
1794     * Side effects:
1795     *      None.
1796     *
1797     *---------------------------------------------------------------------------
1798     */
1799    
1800    static int
1801    SeenName(
1802        CONST char *name,           /* The name to check. */
1803        Tcl_DString *dsPtr)         /* Contains names that have already been
1804                                     * seen. */
1805    {
1806        CONST char *seen, *end;
1807    
1808        seen = Tcl_DStringValue(dsPtr);
1809        end = seen + Tcl_DStringLength(dsPtr);
1810        while (seen < end) {
1811            if (strcasecmp(seen, name) == 0) {
1812                return 1;
1813            }
1814            seen += strlen(seen) + 1;
1815        }
1816        Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1));
1817        return 0;
1818    }
1819    
1820    /*
1821     *-------------------------------------------------------------------------
1822     *
1823     * CanUseFallback --
1824     *
1825     *      If the specified screen font has not already been loaded into
1826     *      the font object, determine if it can display the given character.
1827     *
1828     * Results:
1829     *      The return value is a pointer to a newly allocated SubFont, owned
1830     *      by the font object.  This SubFont can be used to display the given
1831     *      character.  The SubFont represents the screen font with the base set
1832     *      of font attributes from the font object, but using the specified
1833     *      font name.  NULL is returned if the font object already holds
1834     *      a reference to the specified physical font or if the specified
1835     *      physical font cannot display the given character.
1836     *
1837     * Side effects:                                      
1838     *      The font object's subFontArray is updated to contain a reference
1839     *      to the newly allocated SubFont.
1840     *
1841     *-------------------------------------------------------------------------
1842     */
1843    
1844    static SubFont *
1845    CanUseFallback(
1846        HDC hdc,                    /* HDC in which font can be selected. */
1847        WinFont *fontPtr,           /* The font object that will own the new
1848                                     * screen font. */
1849        char *faceName,             /* Desired face name for new screen font. */
1850        int ch)                     /* The Unicode character that the new
1851                                     * screen font must be able to display. */
1852    {
1853        int i;
1854        HFONT hFont;
1855        SubFont subFont;
1856    
1857        if (FamilyExists(hdc, faceName) == 0) {
1858            return NULL;
1859        }
1860    
1861        /*
1862         * Skip all fonts we've already used.
1863         */
1864        
1865        for (i = 0; i < fontPtr->numSubFonts; i++) {
1866            if (faceName == fontPtr->subFontArray[i].familyPtr->faceName) {
1867                return NULL;
1868            }
1869        }
1870    
1871        /*
1872         * Load this font and see if it has the desired character.
1873         */
1874    
1875        hFont = GetScreenFont(&fontPtr->font.fa, faceName, fontPtr->pixelSize);
1876        InitSubFont(hdc, hFont, 0, &subFont);
1877        if (((ch < 256) && (subFont.familyPtr->isSymbolFont))
1878                || (FontMapLookup(&subFont, ch) == 0)) {
1879            /*
1880             * Don't use a symbol font as a fallback font for characters below
1881             * 256.
1882             */
1883    
1884            ReleaseSubFont(&subFont);
1885            return NULL;
1886        }
1887    
1888        if (fontPtr->numSubFonts >= SUBFONT_SPACE) {
1889            SubFont *newPtr;
1890            
1891            newPtr = (SubFont *) ckalloc(sizeof(SubFont)
1892                    * (fontPtr->numSubFonts + 1));
1893            memcpy((char *) newPtr, fontPtr->subFontArray,
1894                    fontPtr->numSubFonts * sizeof(SubFont));
1895            if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
1896                ckfree((char *) fontPtr->subFontArray);
1897            }
1898            fontPtr->subFontArray = newPtr;
1899        }
1900        fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
1901        fontPtr->numSubFonts++;
1902        return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];
1903    }
1904    
1905    /*
1906     *---------------------------------------------------------------------------
1907     *
1908     * GetScreenFont --
1909     *
1910     *      Given the name and other attributes, construct an HFONT.
1911     *      This is where all the alias and fallback substitution bottoms
1912     *      out.
1913     *
1914     * Results:
1915     *      The screen font that corresponds to the attributes.
1916     *
1917     * Side effects:
1918     *      None.
1919     *
1920     *---------------------------------------------------------------------------
1921     */
1922    
1923    static HFONT
1924    GetScreenFont(
1925        CONST TkFontAttributes *faPtr,
1926                                    /* Desired font attributes for new HFONT. */
1927        CONST char *faceName,       /* Overrides font family specified in font
1928                                     * attributes. */
1929        int pixelSize)              /* Overrides size specified in font
1930                                     * attributes. */
1931    {
1932        Tcl_DString ds;
1933        HFONT hFont;
1934        LOGFONTW lf;
1935    
1936        lf.lfHeight         = -pixelSize;
1937        lf.lfWidth          = 0;
1938        lf.lfEscapement     = 0;
1939        lf.lfOrientation    = 0;
1940        lf.lfWeight         = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD;
1941        lf.lfItalic         = faPtr->slant;
1942        lf.lfUnderline      = faPtr->underline;
1943        lf.lfStrikeOut      = faPtr->overstrike;
1944        lf.lfCharSet        = DEFAULT_CHARSET;
1945        lf.lfOutPrecision   = OUT_TT_PRECIS;
1946        lf.lfClipPrecision  = CLIP_DEFAULT_PRECIS;
1947        lf.lfQuality        = DEFAULT_QUALITY;
1948        lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
1949    
1950        Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &ds);
1951    
1952        if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1953            Tcl_UniChar *src, *dst;
1954    
1955            /*
1956             * We can only store up to LF_FACESIZE wide characters
1957             */
1958            if (Tcl_DStringLength(&ds) >= (LF_FACESIZE * sizeof(WCHAR))) {
1959                Tcl_DStringSetLength(&ds, LF_FACESIZE);
1960            }
1961            src = (Tcl_UniChar *) Tcl_DStringValue(&ds);
1962            dst = (Tcl_UniChar *) lf.lfFaceName;
1963            while (*src != '\0') {
1964                *dst++ = *src++;
1965            }
1966            *dst = '\0';
1967            hFont = CreateFontIndirectW(&lf);
1968        } else {
1969            /*
1970             * We can only store up to LF_FACESIZE characters
1971             */
1972            if (Tcl_DStringLength(&ds) >= LF_FACESIZE) {
1973                Tcl_DStringSetLength(&ds, LF_FACESIZE);