OSDN Git Service

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