tkWinFont.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:72k
源码类别:

通讯编程

开发平台:

Visual C++

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