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

Annotation of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwinfont.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25