1/*
2 * tkWinFont.c --
3 *
4 *	Contains the Windows implementation of the platform-independant
5 *	font package interface.
6 *
7 * Copyright (c) 1994 Software Research Associates, Inc.
8 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
9 * Copyright (c) 1998-1999 by Scriptics Corporation.
10 *
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 *
14 * RCS: @(#) $Id: tkWinFont.c,v 1.17.2.3 2004/08/09 23:48:11 mdejong Exp $
15 */
16
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
36typedef 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
96typedef 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
113typedef 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
146typedef struct CanUse {
147    HDC hdc;
148    WinFont *fontPtr;
149    Tcl_DString *nameTriedPtr;
150    int ch;
151    SubFont *subFontPtr;
152    SubFont **subFontPtrPtr;
153} CanUse;
154
155/*
156 * The following structure is used to map between the Tcl strings that
157 * represent the system fonts and the numbers used by Windows.
158 */
159
160static TkStateMap systemMap[] = {
161    {ANSI_FIXED_FONT,	    "ansifixed"},
162    {ANSI_VAR_FONT,	    "ansi"},
163    {DEVICE_DEFAULT_FONT,   "device"},
164    {OEM_FIXED_FONT,	    "oemfixed"},
165    {SYSTEM_FIXED_FONT,	    "systemfixed"},
166    {SYSTEM_FONT,	    "system"},
167    {-1,		    NULL}
168};
169
170typedef struct ThreadSpecificData {
171    FontFamily *fontFamilyList; /* The list of font families that are
172				 * currently loaded.  As screen fonts
173				 * are loaded, this list grows to hold
174				 * information about what characters
175				 * exist in each font family.  */
176    Tcl_HashTable uidTable;
177} ThreadSpecificData;
178static Tcl_ThreadDataKey dataKey;
179
180/*
181 * Information cached about the system at startup time.
182 */
183
184static Tcl_Encoding systemEncoding;
185
186/*
187 * Procedures used only in this file.
188 */
189
190static FontFamily *	AllocFontFamily(HDC hdc, HFONT hFont, int base);
191static SubFont *	CanUseFallback(HDC hdc, WinFont *fontPtr,
192			    char *fallbackName,	int ch,
193			    SubFont **subFontPtrPtr);
194static SubFont *	CanUseFallbackWithAliases(HDC hdc, WinFont *fontPtr,
195			    char *faceName, int ch, Tcl_DString *nameTriedPtr,
196			    SubFont **subFontPtrPtr);
197static int		FamilyExists(HDC hdc, CONST char *faceName);
198static char *		FamilyOrAliasExists(HDC hdc, CONST char *faceName);
199static SubFont *	FindSubFontForChar(WinFont *fontPtr, int ch,
200			    SubFont **subFontPtrPtr);
201static void		FontMapInsert(SubFont *subFontPtr, int ch);
202static void		FontMapLoadPage(SubFont *subFontPtr, int row);
203static int		FontMapLookup(SubFont *subFontPtr, int ch);
204static void		FreeFontFamily(FontFamily *familyPtr);
205static HFONT		GetScreenFont(CONST TkFontAttributes *faPtr,
206			    CONST char *faceName, int pixelSize);
207static void		InitFont(Tk_Window tkwin, HFONT hFont,
208			    int overstrike, WinFont *tkFontPtr);
209static void		InitSubFont(HDC hdc, HFONT hFont, int base,
210			    SubFont *subFontPtr);
211static int		LoadFontRanges(HDC hdc, HFONT hFont,
212			    USHORT **startCount, USHORT **endCount,
213			    int *symbolPtr);
214static void		MultiFontTextOut(HDC hdc, WinFont *fontPtr,
215			    CONST char *source, int numBytes, int x, int y);
216static void		ReleaseFont(WinFont *fontPtr);
217static void		ReleaseSubFont(SubFont *subFontPtr);
218static int		SeenName(CONST char *name, Tcl_DString *dsPtr);
219static void		SwapLong(PULONG p);
220static void		SwapShort(USHORT *p);
221static int CALLBACK	WinFontCanUseProc(ENUMLOGFONT *lfPtr,
222			    NEWTEXTMETRIC *tmPtr, int fontType,
223			    LPARAM lParam);
224static int CALLBACK	WinFontExistProc(ENUMLOGFONT *lfPtr,
225			    NEWTEXTMETRIC *tmPtr, int fontType,
226			    LPARAM lParam);
227static int CALLBACK	WinFontFamilyEnumProc(ENUMLOGFONT *lfPtr,
228			    NEWTEXTMETRIC *tmPtr, int fontType,
229			    LPARAM lParam);
230
231/*
232 *-------------------------------------------------------------------------
233 *
234 * TkpFontPkgInit --
235 *
236 *	This procedure is called when an application is created.  It
237 *	initializes all the structures that are used by the
238 *	platform-dependent code on a per application basis.
239 *
240 * Results:
241 *	None.
242 *
243 * Side effects:
244 *
245 *	None.
246 *
247 *-------------------------------------------------------------------------
248 */
249
250void
251TkpFontPkgInit(
252    TkMainInfo *mainPtr)	/* The application being created. */
253{
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 = TkWinGetUnicodeEncoding();
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
291TkFont *
292TkpGetNativeFont(
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
340TkFont *
341TkpGetFontFromAttributes(
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    Tk_Uid 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
436void
437TkpDeleteFont(
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
464void
465TkpGetFontFamilies(
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
502static int CALLBACK
503WinFontFamilyEnumProc(
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
542void
543TkpGetSubFonts(
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
583int
584Tk_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 fits 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 (or at least the first partial
603				 * word in case TK_WHOLE_WORDS is also set)
604				 * even if no characters (words) fit. */
605    int *lengthPtr)		/* Filled with x-location just after the
606				 * terminating character. */
607{
608    HDC hdc;
609    HFONT oldFont;
610    WinFont *fontPtr;
611    int curX;
612    Tcl_UniChar ch;
613    SIZE size;
614    int moretomeasure;
615    FontFamily *familyPtr;
616    Tcl_DString runString;
617    SubFont *thisSubFontPtr;
618    SubFont *lastSubFontPtr;
619    CONST char *p, *end, *next, *start;
620
621
622    if (numBytes == 0) {
623        *lengthPtr = 0;
624        return 0;
625    }
626
627    fontPtr = (WinFont *) tkfont;
628
629    hdc = GetDC(fontPtr->hwnd);
630    lastSubFontPtr = &fontPtr->subFontArray[0];
631    oldFont = SelectObject(hdc, lastSubFontPtr->hFont);
632
633    /*
634     * A three step process:
635     * 1. Find a contiguous range of characters that can all be
636     *    represented by a single screen font.
637     * 2. Convert those chars to the encoding of that font.
638     * 3. Measure converted chars.
639     */
640
641    moretomeasure = 0;
642    curX = 0;
643    start = source;
644    end = start + numBytes;
645    for (p = start; p < end; ) {
646        next = p + Tcl_UtfToUniChar(p, &ch);
647        thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
648        if (thisSubFontPtr != lastSubFontPtr) {
649            familyPtr = lastSubFontPtr->familyPtr;
650            Tcl_UtfToExternalDString(familyPtr->encoding, start,
651                    (int) (p - start), &runString);
652            size.cx = 0;
653            (*familyPtr->getTextExtentPoint32Proc)(hdc,
654                    Tcl_DStringValue(&runString),
655                    Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
656                    &size);
657            Tcl_DStringFree(&runString);
658            if (maxLength >= 0 && (curX+size.cx) > maxLength) {
659                moretomeasure = 1;
660                break;
661            }
662            curX += size.cx;
663            lastSubFontPtr = thisSubFontPtr;
664            start = p;
665
666            SelectObject(hdc, lastSubFontPtr->hFont);
667        }
668        p = next;
669    }
670
671    if (!moretomeasure) {
672        /*
673         * We get here if the previous loop was just finished
674         * normally, without a break.  Just measure the last run and
675         * that's it.
676         */
677
678	familyPtr = lastSubFontPtr->familyPtr;
679        Tcl_UtfToExternalDString(familyPtr->encoding, start,
680                (int) (p - start), &runString);
681        size.cx = 0;
682	(*familyPtr->getTextExtentPoint32Proc)(hdc,
683		Tcl_DStringValue(&runString),
684		Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
685		&size);
686        Tcl_DStringFree(&runString);
687        if (maxLength >= 0 && (curX+size.cx) > maxLength) {
688            moretomeasure = 1;
689        } else {
690	    curX += size.cx;
691            p = end;
692        }
693    }
694
695    if (moretomeasure) {
696	/*
697         * We get here if the measurement of the last run was over the
698         * maxLength limit.  We need to restart this run and do it
699         * char by char, but always in context with the previous text
700         * to account for kerning (especially italics).
701	 */
702
703        char buf[16];
704        int dstWrote;
705        int lastSize = 0;
706
707	familyPtr = lastSubFontPtr->familyPtr;
708        Tcl_DStringInit(&runString);
709        for (p = start; p < end; ) {
710            next = p + Tcl_UtfToUniChar(p, &ch);
711            Tcl_UtfToExternal(NULL, familyPtr->encoding, p,
712                    (int) (next - p), 0, NULL, buf, sizeof(buf), NULL,
713                    &dstWrote, NULL);
714            Tcl_DStringAppend(&runString,buf,dstWrote);
715            size.cx = 0;
716            (*familyPtr->getTextExtentPoint32Proc)(hdc,
717                    Tcl_DStringValue(&runString),
718                    Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
719                    &size);
720            if ((curX+size.cx) > maxLength) {
721		break;
722	    }
723            lastSize = size.cx;
724	    p = next;
725	}
726        Tcl_DStringFree(&runString);
727
728        /*
729         * "p" points to the first character that doesn't fit in the
730         * desired span.  Look at the flags to figure out whether to
731         * include this next character.
732         */
733
734        if ((p < end)
735                && (((flags & TK_PARTIAL_OK) && (curX != maxLength))
736                        || ((p == source) && (flags & TK_AT_LEAST_ONE)
737                                && (curX == 0)))) {
738
739            /*
740             * Include the first character that didn't quite fit in
741             * the desired span.  The width returned will include the
742             * width of that extra character.
743             */
744
745            p = next;
746            curX += size.cx;
747	} else {
748	    curX += lastSize;
749	}
750    }
751
752    SelectObject(hdc, oldFont);
753    ReleaseDC(fontPtr->hwnd, hdc);
754
755    if ((flags & TK_WHOLE_WORDS) && (p < end)) {
756
757        /*
758         * Scan the string for the last word break and than repeat the
759         * whole procedure without the maxLength limit or any flags.
760         */
761
762        CONST char *lastWordBreak = NULL;
763        Tcl_UniChar ch2;
764
765        end = p;
766        p = source;
767        ch = ' ';
768        while (p < end) {
769            next = p + Tcl_UtfToUniChar(p, &ch2);
770            if ((ch != ' ') && (ch2 == ' ')) {
771                lastWordBreak = p;
772            }
773            p = next;
774            ch = ch2;
775        }
776
777        if (lastWordBreak != NULL) {
778            return Tk_MeasureChars(
779                tkfont, source, lastWordBreak-source, -1, 0, lengthPtr);
780        } else {
781            if (flags & TK_AT_LEAST_ONE) {
782                p = end;
783            } else {
784                p = source;
785                curX = 0;
786            }
787        }
788    }
789
790    *lengthPtr = curX;
791    return p - source;
792}
793
794/*
795 *---------------------------------------------------------------------------
796 *
797 * Tk_DrawChars --
798 *
799 *	Draw a string of characters on the screen.
800 *
801 * Results:
802 *	None.
803 *
804 * Side effects:
805 *	Information gets drawn on the screen.
806 *
807 *---------------------------------------------------------------------------
808 */
809
810void
811Tk_DrawChars(
812    Display *display,		/* Display on which to draw. */
813    Drawable drawable,		/* Window or pixmap in which to draw. */
814    GC gc,			/* Graphics context for drawing characters. */
815    Tk_Font tkfont,		/* Font in which characters will be drawn;
816				 * must be the same as font used in GC. */
817    CONST char *source,		/* UTF-8 string to be displayed.  Need not be
818				 * '\0' terminated.  All Tk meta-characters
819				 * (tabs, control characters, and newlines)
820				 * should be stripped out of the string that
821				 * is passed to this function.  If they are
822				 * not stripped out, they will be displayed as
823				 * regular printing characters. */
824    int numBytes,		/* Number of bytes in string. */
825    int x, int y)		/* Coordinates at which to place origin of
826				 * string when drawing. */
827{
828    HDC dc;
829    WinFont *fontPtr;
830    TkWinDCState state;
831
832    fontPtr = (WinFont *) gc->font;
833    display->request++;
834
835    if (drawable == None) {
836	return;
837    }
838
839    dc = TkWinGetDrawableDC(display, drawable, &state);
840
841    SetROP2(dc, tkpWinRopModes[gc->function]);
842
843    if ((gc->clip_mask != None) &&
844            ((TkpClipMask*)gc->clip_mask)->type == TKP_CLIP_REGION) {
845        SelectClipRgn(dc, (HRGN)((TkpClipMask*)gc->clip_mask)->value.region);
846    }
847
848    if ((gc->fill_style == FillStippled
849	    || gc->fill_style == FillOpaqueStippled)
850	    && gc->stipple != None) {
851	TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
852	HBRUSH oldBrush, stipple;
853	HBITMAP oldBitmap, bitmap;
854	HDC dcMem;
855	TEXTMETRIC tm;
856	SIZE size;
857
858	if (twdPtr->type != TWD_BITMAP) {
859	    Tcl_Panic("unexpected drawable type in stipple");
860	}
861
862	/*
863	 * Select stipple pattern into destination dc.
864	 */
865
866	dcMem = CreateCompatibleDC(dc);
867
868	stipple = CreatePatternBrush(twdPtr->bitmap.handle);
869	SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
870	oldBrush = SelectObject(dc, stipple);
871
872	SetTextAlign(dcMem, TA_LEFT | TA_BASELINE);
873	SetTextColor(dcMem, gc->foreground);
874	SetBkMode(dcMem, TRANSPARENT);
875	SetBkColor(dcMem, RGB(0, 0, 0));
876
877	/*
878	 * Compute the bounding box and create a compatible bitmap.
879	 */
880
881	GetTextExtentPoint(dcMem, source, numBytes, &size);
882	GetTextMetrics(dcMem, &tm);
883	size.cx -= tm.tmOverhang;
884	bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy);
885	oldBitmap = SelectObject(dcMem, bitmap);
886
887	/*
888	 * The following code is tricky because fonts are rendered in multiple
889	 * colors.  First we draw onto a black background and copy the white
890	 * bits.  Then we draw onto a white background and copy the black bits.
891	 * Both the foreground and background bits of the font are ANDed with
892	 * the stipple pattern as they are copied.
893	 */
894
895	PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS);
896	MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);
897	BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
898		0, 0, 0xEA02E9);
899	PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS);
900	MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);
901	BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
902		0, 0, 0x8A0E06);
903
904	/*
905	 * Destroy the temporary bitmap and restore the device context.
906	 */
907
908	SelectObject(dcMem, oldBitmap);
909	DeleteObject(bitmap);
910	DeleteDC(dcMem);
911	SelectObject(dc, oldBrush);
912	DeleteObject(stipple);
913    } else if (gc->function == GXcopy) {
914	SetTextAlign(dc, TA_LEFT | TA_BASELINE);
915	SetTextColor(dc, gc->foreground);
916	SetBkMode(dc, TRANSPARENT);
917	MultiFontTextOut(dc, fontPtr, source, numBytes, x, y);
918    } else {
919	HBITMAP oldBitmap, bitmap;
920	HDC dcMem;
921	TEXTMETRIC tm;
922	SIZE size;
923
924	dcMem = CreateCompatibleDC(dc);
925
926	SetTextAlign(dcMem, TA_LEFT | TA_BASELINE);
927	SetTextColor(dcMem, gc->foreground);
928	SetBkMode(dcMem, TRANSPARENT);
929	SetBkColor(dcMem, RGB(0, 0, 0));
930
931	/*
932	 * Compute the bounding box and create a compatible bitmap.
933	 */
934
935	GetTextExtentPoint(dcMem, source, numBytes, &size);
936	GetTextMetrics(dcMem, &tm);
937	size.cx -= tm.tmOverhang;
938	bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy);
939	oldBitmap = SelectObject(dcMem, bitmap);
940
941	MultiFontTextOut(dcMem, fontPtr, source, numBytes, 0, tm.tmAscent);
942	BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem,
943		0, 0, tkpWinBltModes[gc->function]);
944
945	/*
946	 * Destroy the temporary bitmap and restore the device context.
947	 */
948
949	SelectObject(dcMem, oldBitmap);
950	DeleteObject(bitmap);
951	DeleteDC(dcMem);
952    }
953    TkWinReleaseDrawableDC(drawable, dc, &state);
954}
955
956/*
957 *-------------------------------------------------------------------------
958 *
959 * MultiFontTextOut --
960 *
961 *	Helper function for Tk_DrawChars.  Draws characters, using the
962 *	various screen fonts in fontPtr to draw multilingual characters.
963 *	Note: No bidirectional support.
964 *
965 * Results:
966 *	None.
967 *
968 * Side effects:
969 *	Information gets drawn on the screen.
970 *	Contents of fontPtr may be modified if more subfonts were loaded
971 *	in order to draw all the multilingual characters in the given
972 *	string.
973 *
974 *-------------------------------------------------------------------------
975 */
976
977static void
978MultiFontTextOut(
979    HDC hdc,			/* HDC to draw into. */
980    WinFont *fontPtr,		/* Contains set of fonts to use when drawing
981				 * following string. */
982    CONST char *source,		/* Potentially multilingual UTF-8 string. */
983    int numBytes,		/* Length of string in bytes. */
984    int x, int y)		/* Coordinates at which to place origin *
985				 * of string when drawing. */
986{
987    Tcl_UniChar ch;
988    SIZE size;
989    HFONT oldFont;
990    FontFamily *familyPtr;
991    Tcl_DString runString;
992    CONST char *p, *end, *next;
993    SubFont *lastSubFontPtr, *thisSubFontPtr;
994    TEXTMETRIC tm;
995
996    lastSubFontPtr = &fontPtr->subFontArray[0];
997    oldFont = SelectObject(hdc, lastSubFontPtr->hFont);
998    GetTextMetrics(hdc, &tm);
999
1000    end = source + numBytes;
1001    for (p = source; p < end; ) {
1002        next = p + Tcl_UtfToUniChar(p, &ch);
1003        thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
1004        if (thisSubFontPtr != lastSubFontPtr) {
1005            if (p > source) {
1006		familyPtr = lastSubFontPtr->familyPtr;
1007 		Tcl_UtfToExternalDString(familyPtr->encoding, source,
1008			(int) (p - source), &runString);
1009		(*familyPtr->textOutProc)(hdc, x-(tm.tmOverhang/2), y,
1010			Tcl_DStringValue(&runString),
1011			Tcl_DStringLength(&runString) >> familyPtr->isWideFont);
1012		(*familyPtr->getTextExtentPoint32Proc)(hdc,
1013			Tcl_DStringValue(&runString),
1014			Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
1015			&size);
1016		x += size.cx;
1017		Tcl_DStringFree(&runString);
1018	    }
1019            lastSubFontPtr = thisSubFontPtr;
1020            source = p;
1021	    SelectObject(hdc, lastSubFontPtr->hFont);
1022            GetTextMetrics(hdc, &tm);
1023	}
1024	p = next;
1025    }
1026    if (p > source) {
1027	familyPtr = lastSubFontPtr->familyPtr;
1028 	Tcl_UtfToExternalDString(familyPtr->encoding, source,
1029		(int) (p - source), &runString);
1030	(*familyPtr->textOutProc)(hdc, x-(tm.tmOverhang/2), y,
1031                Tcl_DStringValue(&runString),
1032		Tcl_DStringLength(&runString) >> familyPtr->isWideFont);
1033	Tcl_DStringFree(&runString);
1034    }
1035    SelectObject(hdc, oldFont);
1036}
1037
1038/*
1039 *---------------------------------------------------------------------------
1040 *
1041 * InitFont --
1042 *
1043 *	Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
1044 *	Initializes the memory for a new WinFont that wraps the
1045 *	platform-specific data.
1046 *
1047 *	The caller is responsible for initializing the fields of the
1048 *	WinFont that are used exclusively by the generic TkFont code, and
1049 *	for releasing those fields before calling TkpDeleteFont().
1050 *
1051 * Results:
1052 *	Fills the WinFont structure.
1053 *
1054 * Side effects:
1055 *	Memory allocated.
1056 *
1057 *---------------------------------------------------------------------------
1058 */
1059
1060static void
1061InitFont(
1062    Tk_Window tkwin,		/* Main window of interp in which font will
1063				 * be used, for getting HDC. */
1064    HFONT hFont,		/* Windows token for font. */
1065    int overstrike,		/* The overstrike attribute of logfont used
1066				 * to allocate this font.  For some reason,
1067				 * the TEXTMETRICs may contain incorrect info
1068				 * in the tmStruckOut field. */
1069    WinFont *fontPtr)		/* Filled with information constructed from
1070				 * the above arguments. */
1071{
1072    HDC hdc;
1073    HWND hwnd;
1074    HFONT oldFont;
1075    TEXTMETRIC tm;
1076    Window window;
1077    TkFontMetrics *fmPtr;
1078    Tcl_Encoding encoding;
1079    Tcl_DString faceString;
1080    TkFontAttributes *faPtr;
1081    char buf[LF_FACESIZE * sizeof(WCHAR)];
1082
1083    window  = Tk_WindowId(tkwin);
1084    hwnd    = (window == None) ? NULL : TkWinGetHWND(window);
1085    hdc	    = GetDC(hwnd);
1086    oldFont = SelectObject(hdc, hFont);
1087
1088    GetTextMetrics(hdc, &tm);
1089
1090    /*
1091     * On any version NT, there may fonts with international names.
1092     * Use the NT-only Unicode version of GetTextFace to get the font's
1093     * name.  If we used the ANSI version on a non-internationalized
1094     * version of NT, we would get a font name with '?' replacing all
1095     * the international characters.
1096     *
1097     * On a non-internationalized verson of 95, fonts with international
1098     * names are not allowed, so the ANSI version of GetTextFace will work.
1099     * On an internationalized version of 95, there may be fonts with
1100     * international names; the ANSI version will work, fetching the
1101     * name in the international system code page.  Can't use the Unicode
1102     * version of GetTextFace because it only exists under NT.
1103     */
1104
1105    if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1106	GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf);
1107    } else {
1108	GetTextFaceA(hdc, LF_FACESIZE, (char *) buf);
1109    }
1110    Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString);
1111
1112    fontPtr->font.fid	= (Font) fontPtr;
1113
1114    faPtr		= &fontPtr->font.fa;
1115    faPtr->family	= Tk_GetUid(Tcl_DStringValue(&faceString));
1116    faPtr->size		= TkFontGetPoints(tkwin, -(tm.tmHeight - tm.tmInternalLeading));
1117    faPtr->weight	= (tm.tmWeight > FW_MEDIUM) ? TK_FW_BOLD : TK_FW_NORMAL;
1118    faPtr->slant	= (tm.tmItalic != 0) ? TK_FS_ITALIC : TK_FS_ROMAN;
1119    faPtr->underline	= (tm.tmUnderlined != 0) ? 1 : 0;
1120    faPtr->overstrike	= overstrike;
1121
1122    fmPtr		= &fontPtr->font.fm;
1123    fmPtr->ascent	= tm.tmAscent;
1124    fmPtr->descent	= tm.tmDescent;
1125    fmPtr->maxWidth	= tm.tmMaxCharWidth;
1126    fmPtr->fixed	= !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
1127
1128    fontPtr->hwnd	= hwnd;
1129    fontPtr->pixelSize	= tm.tmHeight - tm.tmInternalLeading;
1130
1131    fontPtr->numSubFonts 	= 1;
1132    fontPtr->subFontArray	= fontPtr->staticSubFonts;
1133    InitSubFont(hdc, hFont, 1, &fontPtr->subFontArray[0]);
1134
1135    encoding = fontPtr->subFontArray[0].familyPtr->encoding;
1136    if (encoding == TkWinGetUnicodeEncoding()) {
1137	GetCharWidthW(hdc, 0, BASE_CHARS - 1, fontPtr->widths);
1138    } else {
1139	GetCharWidthA(hdc, 0, BASE_CHARS - 1, fontPtr->widths);
1140    }
1141    Tcl_DStringFree(&faceString);
1142
1143    SelectObject(hdc, oldFont);
1144    ReleaseDC(hwnd, hdc);
1145}
1146
1147/*
1148 *-------------------------------------------------------------------------
1149 *
1150 * ReleaseFont --
1151 *
1152 *	Called to release the windows-specific contents of a TkFont.
1153 *	The caller is responsible for freeing the memory used by the
1154 *	font itself.
1155 *
1156 * Results:
1157 *	None.
1158 *
1159 * Side effects:
1160 *	Memory is freed.
1161 *
1162 *---------------------------------------------------------------------------
1163 */
1164
1165static void
1166ReleaseFont(
1167    WinFont *fontPtr)		/* The font to delete. */
1168{
1169    int i;
1170
1171    for (i = 0; i < fontPtr->numSubFonts; i++) {
1172	ReleaseSubFont(&fontPtr->subFontArray[i]);
1173    }
1174    if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
1175	ckfree((char *) fontPtr->subFontArray);
1176    }
1177}
1178
1179/*
1180 *-------------------------------------------------------------------------
1181 *
1182 * InitSubFont --
1183 *
1184 *	Wrap a screen font and load the FontFamily that represents
1185 *	it.  Used to prepare a SubFont so that characters can be mapped
1186 *	from UTF-8 to the charset of the font.
1187 *
1188 * Results:
1189 *	The subFontPtr is filled with information about the font.
1190 *
1191 * Side effects:
1192 *	None.
1193 *
1194 *-------------------------------------------------------------------------
1195 */
1196
1197static void
1198InitSubFont(
1199    HDC hdc,			/* HDC in which font can be selected. */
1200    HFONT hFont,		/* The screen font. */
1201    int base,			/* Non-zero if this SubFont is being used
1202				 * as the base font for a font object. */
1203    SubFont *subFontPtr)	/* Filled with SubFont constructed from
1204    				 * above attributes. */
1205{
1206    subFontPtr->hFont	    = hFont;
1207    subFontPtr->familyPtr   = AllocFontFamily(hdc, hFont, base);
1208    subFontPtr->fontMap	    = subFontPtr->familyPtr->fontMap;
1209}
1210
1211/*
1212 *-------------------------------------------------------------------------
1213 *
1214 * ReleaseSubFont --
1215 *
1216 *	Called to release the contents of a SubFont.  The caller is
1217 *	responsible for freeing the memory used by the SubFont itself.
1218 *
1219 * Results:
1220 *	None.
1221 *
1222 * Side effects:
1223 *	Memory and resources are freed.
1224 *
1225 *---------------------------------------------------------------------------
1226 */
1227
1228static void
1229ReleaseSubFont(
1230    SubFont *subFontPtr)	/* The SubFont to delete. */
1231{
1232    DeleteObject(subFontPtr->hFont);
1233    FreeFontFamily(subFontPtr->familyPtr);
1234}
1235
1236/*
1237 *-------------------------------------------------------------------------
1238 *
1239 * AllocFontFamily --
1240 *
1241 *	Find the FontFamily structure associated with the given font
1242 *	name.  The information should be stored by the caller in a
1243 *	SubFont and used when determining if that SubFont supports a
1244 *	character.
1245 *
1246 *	Cannot use the string name used to construct the font as the
1247 *	key, because the capitalization may not be canonical.  Therefore
1248 *	use the face name actually retrieved from the font metrics as
1249 *	the key.
1250 *
1251 * Results:
1252 *	A pointer to a FontFamily.  The reference count in the FontFamily
1253 *	is automatically incremented.  When the SubFont is released, the
1254 *	reference count is decremented.  When no SubFont is using this
1255 *	FontFamily, it may be deleted.
1256 *
1257 * Side effects:
1258 *	A new FontFamily structure will be allocated if this font family
1259 *	has not been seen.  TrueType character existence metrics are
1260 *	loaded into the FontFamily structure.
1261 *
1262 *-------------------------------------------------------------------------
1263 */
1264
1265static FontFamily *
1266AllocFontFamily(
1267    HDC hdc,			/* HDC in which font can be selected. */
1268    HFONT hFont,		/* Screen font whose FontFamily is to be
1269				 * returned. */
1270    int base)			/* Non-zero if this font family is to be
1271				 * used in the base font of a font object. */
1272{
1273    Tk_Uid faceName;
1274    FontFamily *familyPtr;
1275    Tcl_DString faceString;
1276    Tcl_Encoding encoding;
1277    char buf[LF_FACESIZE * sizeof(WCHAR)];
1278    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1279            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1280
1281    hFont = SelectObject(hdc, hFont);
1282    if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1283	GetTextFaceW(hdc, LF_FACESIZE, (WCHAR *) buf);
1284    } else {
1285	GetTextFaceA(hdc, LF_FACESIZE, (char *) buf);
1286    }
1287    Tcl_ExternalToUtfDString(systemEncoding, buf, -1, &faceString);
1288    faceName = Tk_GetUid(Tcl_DStringValue(&faceString));
1289    Tcl_DStringFree(&faceString);
1290    hFont = SelectObject(hdc, hFont);
1291
1292    familyPtr = tsdPtr->fontFamilyList;
1293    for ( ; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {
1294	if (familyPtr->faceName == faceName) {
1295	    familyPtr->refCount++;
1296	    return familyPtr;
1297	}
1298    }
1299
1300    familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily));
1301    memset(familyPtr, 0, sizeof(FontFamily));
1302    familyPtr->nextPtr = tsdPtr->fontFamilyList;
1303    tsdPtr->fontFamilyList = familyPtr;
1304
1305    /*
1306     * Set key for this FontFamily.
1307     */
1308
1309    familyPtr->faceName = faceName;
1310
1311    /*
1312     * An initial refCount of 2 means that FontFamily information will
1313     * persist even when the SubFont that loaded the FontFamily is released.
1314     * Change it to 1 to cause FontFamilies to be unloaded when not in use.
1315     */
1316
1317    familyPtr->refCount = 2;
1318
1319    familyPtr->segCount = LoadFontRanges(hdc, hFont, &familyPtr->startCount,
1320	    &familyPtr->endCount, &familyPtr->isSymbolFont);
1321
1322    encoding = NULL;
1323    if (familyPtr->isSymbolFont != 0) {
1324	/*
1325	 * Symbol fonts are handled specially.  For instance, Unicode 0393
1326	 * (GREEK CAPITAL GAMMA) must be mapped to Symbol character 0047
1327	 * (GREEK CAPITAL GAMMA), because the Symbol font doesn't have a
1328	 * GREEK CAPITAL GAMMA at location 0393.  If Tk interpreted the
1329	 * Symbol font using the Unicode encoding, it would decide that
1330	 * the Symbol font has no GREEK CAPITAL GAMMA, because the Symbol
1331	 * encoding (of course) reports that character 0393 doesn't exist.
1332	 *
1333	 * With non-symbol Windows fonts, such as Times New Roman, if the
1334	 * font has a GREEK CAPITAL GAMMA, it will be found in the correct
1335	 * Unicode location (0393); the GREEK CAPITAL GAMMA will not be off
1336	 * hiding at some other location.
1337	 */
1338
1339	encoding = Tcl_GetEncoding(NULL, faceName);
1340    }
1341
1342    if (encoding == NULL) {
1343	encoding = Tcl_GetEncoding(NULL, "unicode");
1344	familyPtr->textOutProc =
1345	    (BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutW;
1346	familyPtr->getTextExtentPoint32Proc =
1347	    (BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32W;
1348	familyPtr->isWideFont = 1;
1349    } else {
1350	familyPtr->textOutProc =
1351	    (BOOL (WINAPI *)(HDC, int, int, TCHAR *, int)) TextOutA;
1352	familyPtr->getTextExtentPoint32Proc =
1353	    (BOOL (WINAPI *)(HDC, TCHAR *, int, LPSIZE)) GetTextExtentPoint32A;
1354	familyPtr->isWideFont = 0;
1355    }
1356
1357    familyPtr->encoding = encoding;
1358
1359    return familyPtr;
1360}
1361
1362/*
1363 *-------------------------------------------------------------------------
1364 *
1365 * FreeFontFamily --
1366 *
1367 *	Called to free a FontFamily when the SubFont is finished using it.
1368 *	Frees the contents of the FontFamily and the memory used by the
1369 *	FontFamily itself.
1370 *
1371 * Results:
1372 *	None.
1373 *
1374 * Side effects:
1375 *	None.
1376 *
1377 *-------------------------------------------------------------------------
1378 */
1379
1380static void
1381FreeFontFamily(
1382    FontFamily *familyPtr)	/* The FontFamily to delete. */
1383{
1384    int i;
1385    FontFamily **familyPtrPtr;
1386    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1387            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1388
1389    if (familyPtr == NULL) {
1390        return;
1391    }
1392    familyPtr->refCount--;
1393    if (familyPtr->refCount > 0) {
1394    	return;
1395    }
1396    for (i = 0; i < FONTMAP_PAGES; i++) {
1397        if (familyPtr->fontMap[i] != NULL) {
1398            ckfree(familyPtr->fontMap[i]);
1399        }
1400    }
1401    if (familyPtr->startCount != NULL) {
1402	ckfree((char *) familyPtr->startCount);
1403    }
1404    if (familyPtr->endCount != NULL) {
1405	ckfree((char *) familyPtr->endCount);
1406    }
1407    if (familyPtr->encoding != TkWinGetUnicodeEncoding()) {
1408	Tcl_FreeEncoding(familyPtr->encoding);
1409    }
1410
1411    /*
1412     * Delete from list.
1413     */
1414
1415    for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) {
1416        if (*familyPtrPtr == familyPtr) {
1417  	    *familyPtrPtr = familyPtr->nextPtr;
1418	    break;
1419	}
1420	familyPtrPtr = &(*familyPtrPtr)->nextPtr;
1421    }
1422
1423    ckfree((char *) familyPtr);
1424}
1425
1426/*
1427 *-------------------------------------------------------------------------
1428 *
1429 * FindSubFontForChar --
1430 *
1431 *	Determine which screen font is necessary to use to display the
1432 *	given character.  If the font object does not have a screen font
1433 *	that can display the character, another screen font may be loaded
1434 *	into the font object, following a set of preferred fallback rules.
1435 *
1436 * Results:
1437 *	The return value is the SubFont to use to display the given
1438 *	character.
1439 *
1440 * Side effects:
1441 *	The contents of fontPtr are modified to cache the results
1442 *	of the lookup and remember any SubFonts that were dynamically
1443 *	loaded.
1444 *
1445 *-------------------------------------------------------------------------
1446 */
1447
1448static SubFont *
1449FindSubFontForChar(
1450    WinFont *fontPtr,		/* The font object with which the character
1451				 * will be displayed. */
1452    int ch,			/* The Unicode character to be displayed. */
1453    SubFont **subFontPtrPtr)	/* Pointer to var to be fixed up if we
1454				 * reallocate the subfont table. */
1455{
1456    HDC hdc;
1457    int i, j, k;
1458    CanUse canUse;
1459    char **aliases, **anyFallbacks;
1460    char ***fontFallbacks;
1461    char *fallbackName;
1462    SubFont *subFontPtr;
1463    Tcl_DString ds;
1464
1465    if (ch < BASE_CHARS) {
1466	return &fontPtr->subFontArray[0];
1467    }
1468
1469    for (i = 0; i < fontPtr->numSubFonts; i++) {
1470	if (FontMapLookup(&fontPtr->subFontArray[i], ch)) {
1471	    return &fontPtr->subFontArray[i];
1472	}
1473    }
1474
1475    /*
1476     * Keep track of all face names that we check, so we don't check some
1477     * name multiple times if it can be reached by multiple paths.
1478     */
1479
1480    Tcl_DStringInit(&ds);
1481    hdc = GetDC(fontPtr->hwnd);
1482
1483    aliases = TkFontGetAliasList(fontPtr->font.fa.family);
1484
1485    fontFallbacks = TkFontGetFallbacks();
1486    for (i = 0; fontFallbacks[i] != NULL; i++) {
1487	for (j = 0; fontFallbacks[i][j] != NULL; j++) {
1488	    fallbackName = fontFallbacks[i][j];
1489	    if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 0) {
1490		/*
1491		 * If the base font has a fallback...
1492		 */
1493
1494		goto tryfallbacks;
1495	    } else if (aliases != NULL) {
1496		/*
1497		 * Or if an alias for the base font has a fallback...
1498		 */
1499
1500		for (k = 0; aliases[k] != NULL; k++) {
1501		    if (strcasecmp(aliases[k], fallbackName) == 0) {
1502		        goto tryfallbacks;
1503		    }
1504		}
1505	    }
1506	}
1507	continue;
1508
1509	/*
1510	 * ...then see if we can use one of the fallbacks, or an
1511	 * alias for one of the fallbacks.
1512	 */
1513
1514	tryfallbacks:
1515	for (j = 0; fontFallbacks[i][j] != NULL; j++) {
1516	    fallbackName = fontFallbacks[i][j];
1517	    subFontPtr = CanUseFallbackWithAliases(hdc, fontPtr, fallbackName,
1518		    ch, &ds, subFontPtrPtr);
1519	    if (subFontPtr != NULL) {
1520		goto end;
1521	    }
1522	}
1523    }
1524
1525    /*
1526     * See if we can use something from the global fallback list.
1527     */
1528
1529    anyFallbacks = TkFontGetGlobalClass();
1530    for (i = 0; anyFallbacks[i] != NULL; i++) {
1531	fallbackName = anyFallbacks[i];
1532	subFontPtr = CanUseFallbackWithAliases(hdc, fontPtr, fallbackName,
1533		ch, &ds, subFontPtrPtr);
1534	if (subFontPtr != NULL) {
1535	    goto end;
1536	}
1537    }
1538
1539    /*
1540     * Try all face names available in the whole system until we
1541     * find one that can be used.
1542     */
1543
1544    canUse.hdc = hdc;
1545    canUse.fontPtr = fontPtr;
1546    canUse.nameTriedPtr = &ds;
1547    canUse.ch = ch;
1548    canUse.subFontPtr = NULL;
1549    canUse.subFontPtrPtr = subFontPtrPtr;
1550    if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1551	EnumFontFamiliesW(hdc, NULL, (FONTENUMPROCW) WinFontCanUseProc,
1552		(LPARAM) &canUse);
1553    } else {
1554	EnumFontFamiliesA(hdc, NULL, (FONTENUMPROCA) WinFontCanUseProc,
1555		(LPARAM) &canUse);
1556    }
1557    subFontPtr = canUse.subFontPtr;
1558
1559    end:
1560    Tcl_DStringFree(&ds);
1561
1562    if (subFontPtr == NULL) {
1563        /*
1564         * No font can display this character.  We will use the base font
1565         * and have it display the "unknown" character.
1566         */
1567
1568	subFontPtr = &fontPtr->subFontArray[0];
1569        FontMapInsert(subFontPtr, ch);
1570    }
1571    ReleaseDC(fontPtr->hwnd, hdc);
1572    return subFontPtr;
1573}
1574
1575static int CALLBACK
1576WinFontCanUseProc(
1577    ENUMLOGFONT *lfPtr,		/* Logical-font data. */
1578    NEWTEXTMETRIC *tmPtr,	/* Physical-font data (not used). */
1579    int fontType,		/* Type of font (not used). */
1580    LPARAM lParam)		/* Result object to hold result. */
1581{
1582    int ch;
1583    HDC hdc;
1584    WinFont *fontPtr;
1585    CanUse *canUsePtr;
1586    char *fallbackName;
1587    SubFont *subFontPtr;
1588    Tcl_DString faceString;
1589    Tcl_DString *nameTriedPtr;
1590
1591    canUsePtr	    = (CanUse *) lParam;
1592    ch		    = canUsePtr->ch;
1593    hdc		    = canUsePtr->hdc;
1594    fontPtr	    = canUsePtr->fontPtr;
1595    nameTriedPtr    = canUsePtr->nameTriedPtr;
1596
1597    fallbackName = lfPtr->elfLogFont.lfFaceName;
1598    Tcl_ExternalToUtfDString(systemEncoding, fallbackName, -1, &faceString);
1599    fallbackName = Tcl_DStringValue(&faceString);
1600
1601    if (SeenName(fallbackName, nameTriedPtr) == 0) {
1602	subFontPtr = CanUseFallback(hdc, fontPtr, fallbackName, ch,
1603		canUsePtr->subFontPtrPtr);
1604	if (subFontPtr != NULL) {
1605	    canUsePtr->subFontPtr = subFontPtr;
1606	    Tcl_DStringFree(&faceString);
1607	    return 0;
1608	}
1609    }
1610    Tcl_DStringFree(&faceString);
1611    return 1;
1612}
1613
1614/*
1615 *-------------------------------------------------------------------------
1616 *
1617 * FontMapLookup --
1618 *
1619 *	See if the screen font can display the given character.
1620 *
1621 * Results:
1622 *	The return value is 0 if the screen font cannot display the
1623 *	character, non-zero otherwise.
1624 *
1625 * Side effects:
1626 *	New pages are added to the font mapping cache whenever the
1627 *	character belongs to a page that hasn't been seen before.
1628 *	When a page is loaded, information about all the characters on
1629 *	that page is stored, not just for the single character in
1630 *	question.
1631 *
1632 *-------------------------------------------------------------------------
1633 */
1634
1635static int
1636FontMapLookup(
1637    SubFont *subFontPtr,	/* Contains font mapping cache to be queried
1638				 * and possibly updated. */
1639    int ch)			/* Character to be tested. */
1640{
1641    int row, bitOffset;
1642
1643    row = ch >> FONTMAP_SHIFT;
1644    if (subFontPtr->fontMap[row] == NULL) {
1645	FontMapLoadPage(subFontPtr, row);
1646    }
1647    bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
1648    return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;
1649}
1650
1651/*
1652 *-------------------------------------------------------------------------
1653 *
1654 * FontMapInsert --
1655 *
1656 *	Tell the font mapping cache that the given screen font should be
1657 *	used to display the specified character.  This is called when no
1658 *	font on the system can be be found that can display that
1659 *	character; we lie to the font and tell it that it can display
1660 *	the character, otherwise we would end up re-searching the entire
1661 *	fallback hierarchy every time that character was seen.
1662 *
1663 * Results:
1664 *	None.
1665 *
1666 * Side effects:
1667 *	New pages are added to the font mapping cache whenever the
1668 *	character belongs to a page that hasn't been seen before.
1669 *	When a page is loaded, information about all the characters on
1670 *	that page is stored, not just for the single character in
1671 *	question.
1672 *
1673 *-------------------------------------------------------------------------
1674 */
1675
1676static void
1677FontMapInsert(
1678    SubFont *subFontPtr,	/* Contains font mapping cache to be
1679				 * updated. */
1680    int ch)			/* Character to be added to cache. */
1681{
1682    int row, bitOffset;
1683
1684    row = ch >> FONTMAP_SHIFT;
1685    if (subFontPtr->fontMap[row] == NULL) {
1686	FontMapLoadPage(subFontPtr, row);
1687    }
1688    bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
1689    subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
1690}
1691
1692/*
1693 *-------------------------------------------------------------------------
1694 *
1695 * FontMapLoadPage --
1696 *
1697 *	Load information about all the characters on a given page.
1698 *	This information consists of one bit per character that indicates
1699 *	whether the associated HFONT can (1) or cannot (0) display the
1700 *	characters on the page.
1701 *
1702 * Results:
1703 *	None.
1704 *
1705 * Side effects:
1706 *	Mempry allocated.
1707 *
1708 *-------------------------------------------------------------------------
1709 */
1710static void
1711FontMapLoadPage(
1712    SubFont *subFontPtr,	/* Contains font mapping cache to be
1713				 * updated. */
1714    int row)			/* Index of the page to be loaded into
1715				 * the cache. */
1716{
1717    FontFamily *familyPtr;
1718    Tcl_Encoding encoding;
1719    char src[TCL_UTF_MAX], buf[16];
1720    USHORT *startCount, *endCount;
1721    int i, j, bitOffset, end, segCount;
1722
1723    subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8);
1724    memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
1725
1726    familyPtr = subFontPtr->familyPtr;
1727    encoding = familyPtr->encoding;
1728
1729    if (familyPtr->encoding == TkWinGetUnicodeEncoding()) {
1730	/*
1731	 * Font is Unicode.  Few fonts are going to have all characters, so
1732	 * examine the TrueType character existence metrics to determine
1733	 * what characters actually exist in this font.
1734	 */
1735
1736	segCount    = familyPtr->segCount;
1737	startCount  = familyPtr->startCount;
1738	endCount    = familyPtr->endCount;
1739
1740	j = 0;
1741	end = (row + 1) << FONTMAP_SHIFT;
1742	for (i = row << FONTMAP_SHIFT; i < end; i++) {
1743	    for ( ; j < segCount; j++) {
1744		if (endCount[j] >= i) {
1745		    if (startCount[j] <= i) {
1746			bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
1747			subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
1748		    }
1749		    break;
1750		}
1751	    }
1752	}
1753    } else if (familyPtr->isSymbolFont) {
1754	/*
1755	 * Assume that a symbol font with a known encoding has all the
1756	 * characters that its encoding claims it supports.
1757	 *
1758	 * The test for "encoding == unicodeEncoding"
1759	 * must occur before this case, to catch all symbol fonts (such
1760	 * as {Comic Sans MS} or Wingdings) for which we don't have
1761	 * encoding information; those symbol fonts are treated as if
1762	 * they were in the Unicode encoding and their symbolic
1763	 * character existence metrics are treated as if they were Unicode
1764	 * character existence metrics.  This way, although we don't know
1765	 * the proper Unicode -> symbol font mapping, we can install the
1766	 * symbol font as the base font and access its glyphs.
1767	 */
1768
1769        end = (row + 1) << FONTMAP_SHIFT;
1770	for (i = row << FONTMAP_SHIFT; i < end; i++) {
1771	    if (Tcl_UtfToExternal(NULL, encoding, src,
1772		    Tcl_UniCharToUtf(i, src), TCL_ENCODING_STOPONERROR, NULL,
1773		    buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK) {
1774		continue;
1775	    }
1776	    bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
1777	    subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
1778	}
1779    }
1780}
1781
1782/*
1783 *---------------------------------------------------------------------------
1784 *
1785 * CanUseFallbackWithAliases --
1786 *
1787 *	Helper function for FindSubFontForChar.  Determine if the
1788 *	specified face name (or an alias of the specified face name)
1789 *	can be used to construct a screen font that can display the
1790 *	given character.
1791 *
1792 * Results:
1793 *	See CanUseFallback().
1794 *
1795 * Side effects:
1796 *	If the name and/or one of its aliases was rejected, the
1797 *	rejected string is recorded in nameTriedPtr so that it won't
1798 *	be tried again.
1799 *
1800 *---------------------------------------------------------------------------
1801 */
1802
1803static SubFont *
1804CanUseFallbackWithAliases(
1805    HDC hdc,			/* HDC in which font can be selected. */
1806    WinFont *fontPtr,		/* The font object that will own the new
1807				 * screen font. */
1808    char *faceName,		/* Desired face name for new screen font. */
1809    int ch,			/* The Unicode character that the new
1810				 * screen font must be able to display. */
1811    Tcl_DString *nameTriedPtr,	/* Records face names that have already
1812				 * been tried.  It is possible for the same
1813				 * face name to be queried multiple times when
1814				 * trying to find a suitable screen font. */
1815    SubFont **subFontPtrPtr)	/* Variable to fixup if we reallocate the
1816				 * array of subfonts. */
1817{
1818    int i;
1819    char **aliases;
1820    SubFont *subFontPtr;
1821
1822    if (SeenName(faceName, nameTriedPtr) == 0) {
1823	subFontPtr = CanUseFallback(hdc, fontPtr, faceName, ch, subFontPtrPtr);
1824	if (subFontPtr != NULL) {
1825	    return subFontPtr;
1826	}
1827    }
1828    aliases = TkFontGetAliasList(faceName);
1829    if (aliases != NULL) {
1830	for (i = 0; aliases[i] != NULL; i++) {
1831	    if (SeenName(aliases[i], nameTriedPtr) == 0) {
1832		subFontPtr = CanUseFallback(hdc, fontPtr, aliases[i], ch,
1833			subFontPtrPtr);
1834		if (subFontPtr != NULL) {
1835		    return subFontPtr;
1836		}
1837	    }
1838	}
1839    }
1840    return NULL;
1841}
1842
1843/*
1844 *---------------------------------------------------------------------------
1845 *
1846 * SeenName --
1847 *
1848 *	Used to determine we have already tried and rejected the given
1849 *	face name when looking for a screen font that can support some
1850 *	Unicode character.
1851 *
1852 * Results:
1853 *	The return value is 0 if this face name has not already been seen,
1854 *	non-zero otherwise.
1855 *
1856 * Side effects:
1857 *	None.
1858 *
1859 *---------------------------------------------------------------------------
1860 */
1861
1862static int
1863SeenName(
1864    CONST char *name,		/* The name to check. */
1865    Tcl_DString *dsPtr)		/* Contains names that have already been
1866				 * seen. */
1867{
1868    CONST char *seen, *end;
1869
1870    seen = Tcl_DStringValue(dsPtr);
1871    end = seen + Tcl_DStringLength(dsPtr);
1872    while (seen < end) {
1873	if (strcasecmp(seen, name) == 0) {
1874	    return 1;
1875	}
1876	seen += strlen(seen) + 1;
1877    }
1878    Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1));
1879    return 0;
1880}
1881
1882/*
1883 *-------------------------------------------------------------------------
1884 *
1885 * CanUseFallback --
1886 *
1887 *	If the specified screen font has not already been loaded into
1888 *	the font object, determine if it can display the given character.
1889 *
1890 * Results:
1891 *	The return value is a pointer to a newly allocated SubFont, owned
1892 *	by the font object.  This SubFont can be used to display the given
1893 *	character.  The SubFont represents the screen font with the base set
1894 *	of font attributes from the font object, but using the specified
1895 *	font name.  NULL is returned if the font object already holds
1896 *	a reference to the specified physical font or if the specified
1897 *	physical font cannot display the given character.
1898 *
1899 * Side effects:
1900 *	The font object's subFontArray is updated to contain a reference
1901 *	to the newly allocated SubFont.
1902 *
1903 *-------------------------------------------------------------------------
1904 */
1905
1906static SubFont *
1907CanUseFallback(
1908    HDC hdc,			/* HDC in which font can be selected. */
1909    WinFont *fontPtr,		/* The font object that will own the new
1910				 * screen font. */
1911    char *faceName,		/* Desired face name for new screen font. */
1912    int ch,			/* The Unicode character that the new
1913				 * screen font must be able to display. */
1914    SubFont **subFontPtrPtr)	/* Variable to fix-up if we realloc the array
1915				 * of subfonts. */
1916{
1917    int i;
1918    HFONT hFont;
1919    SubFont subFont;
1920
1921    if (FamilyExists(hdc, faceName) == 0) {
1922	return NULL;
1923    }
1924
1925    /*
1926     * Skip all fonts we've already used.
1927     */
1928
1929    for (i = 0; i < fontPtr->numSubFonts; i++) {
1930	if (faceName == fontPtr->subFontArray[i].familyPtr->faceName) {
1931	    return NULL;
1932	}
1933    }
1934
1935    /*
1936     * Load this font and see if it has the desired character.
1937     */
1938
1939    hFont = GetScreenFont(&fontPtr->font.fa, faceName, fontPtr->pixelSize);
1940    InitSubFont(hdc, hFont, 0, &subFont);
1941    if (((ch < 256) && (subFont.familyPtr->isSymbolFont))
1942	    || (FontMapLookup(&subFont, ch) == 0)) {
1943	/*
1944	 * Don't use a symbol font as a fallback font for characters below
1945	 * 256.
1946	 */
1947
1948	ReleaseSubFont(&subFont);
1949	return NULL;
1950    }
1951
1952    if (fontPtr->numSubFonts >= SUBFONT_SPACE) {
1953	SubFont *newPtr;
1954
1955    	newPtr = (SubFont *) ckalloc(sizeof(SubFont)
1956		* (fontPtr->numSubFonts + 1));
1957	memcpy((char *) newPtr, fontPtr->subFontArray,
1958		fontPtr->numSubFonts * sizeof(SubFont));
1959	if (fontPtr->subFontArray != fontPtr->staticSubFonts) {
1960	    ckfree((char *) fontPtr->subFontArray);
1961	}
1962	/*
1963	 * Fix up the variable pointed to by subFontPtrPtr so it still
1964	 * points into the live array.  [Bug 618872]
1965	 */
1966	*subFontPtrPtr = newPtr + (*subFontPtrPtr - fontPtr->subFontArray);
1967	fontPtr->subFontArray = newPtr;
1968    }
1969    fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
1970    fontPtr->numSubFonts++;
1971    return &fontPtr->subFontArray[fontPtr->numSubFonts - 1];
1972}
1973
1974/*
1975 *---------------------------------------------------------------------------
1976 *
1977 * GetScreenFont --
1978 *
1979 *	Given the name and other attributes, construct an HFONT.
1980 *	This is where all the alias and fallback substitution bottoms
1981 *	out.
1982 *
1983 * Results:
1984 *	The screen font that corresponds to the attributes.
1985 *
1986 * Side effects:
1987 *	None.
1988 *
1989 *---------------------------------------------------------------------------
1990 */
1991
1992static HFONT
1993GetScreenFont(
1994    CONST TkFontAttributes *faPtr,
1995				/* Desired font attributes for new HFONT. */
1996    CONST char *faceName,	/* Overrides font family specified in font
1997				 * attributes. */
1998    int pixelSize)		/* Overrides size specified in font
1999				 * attributes. */
2000{
2001    Tcl_DString ds;
2002    HFONT hFont;
2003    LOGFONTW lf;
2004
2005    memset(&lf, 0, sizeof(lf));
2006    lf.lfHeight		= -pixelSize;
2007    lf.lfWidth		= 0;
2008    lf.lfEscapement	= 0;
2009    lf.lfOrientation	= 0;
2010    lf.lfWeight		= (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD;
2011    lf.lfItalic		= faPtr->slant;
2012    lf.lfUnderline	= faPtr->underline;
2013    lf.lfStrikeOut	= faPtr->overstrike;
2014    lf.lfCharSet	= DEFAULT_CHARSET;
2015    lf.lfOutPrecision	= OUT_TT_PRECIS;
2016    lf.lfClipPrecision	= CLIP_DEFAULT_PRECIS;
2017    lf.lfQuality	= DEFAULT_QUALITY;
2018    lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
2019
2020    Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &ds);
2021
2022    if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
2023	Tcl_UniChar *src, *dst;
2024
2025	/*
2026	 * We can only store up to LF_FACESIZE wide characters
2027	 */
2028	if (Tcl_DStringLength(&ds) >= (LF_FACESIZE * sizeof(WCHAR))) {
2029	    Tcl_DStringSetLength(&ds, LF_FACESIZE);
2030	}
2031	src = (Tcl_UniChar *) Tcl_DStringValue(&ds);
2032	dst = (Tcl_UniChar *) lf.lfFaceName;
2033	while (*src != '\0') {
2034	    *dst++ = *src++;
2035	}
2036	*dst = '\0';
2037	hFont = CreateFontIndirectW(&lf);
2038    } else {
2039	/*
2040	 * We can only store up to LF_FACESIZE characters
2041	 */
2042	if (Tcl_DStringLength(&ds) >= LF_FACESIZE) {
2043	    Tcl_DStringSetLength(&ds, LF_FACESIZE);
2044	}
2045	strcpy((char *) lf.lfFaceName, Tcl_DStringValue(&ds));
2046	hFont = CreateFontIndirectA((LOGFONTA *) &lf);
2047    }
2048    Tcl_DStringFree(&ds);
2049    return hFont;
2050}
2051
2052/*
2053 *-------------------------------------------------------------------------
2054 *
2055 * FamilyExists, FamilyOrAliasExists, WinFontExistsProc --
2056 *
2057 *	Determines if any physical screen font exists on the system with
2058 *	the given family name.  If the family exists, then it should be
2059 *	possible to construct some physical screen font with that family
2060 *	name.
2061 *
2062 * Results:
2063 *	The return value is 0 if the specified font family does not exist,
2064 *	non-zero otherwise.
2065 *
2066 * Side effects:
2067 *	None.
2068 *
2069 *-------------------------------------------------------------------------
2070 */
2071
2072static int
2073FamilyExists(
2074    HDC hdc,			/* HDC in which font family will be used. */
2075    CONST char *faceName)	/* Font family to query. */
2076{
2077    int result;
2078    Tcl_DString faceString;
2079
2080    /*
2081     * Just immediately rule out the following fonts, because they look so
2082     * ugly on windows.  The caller's fallback mechanism will cause the
2083     * corresponding appropriate TrueType fonts to be selected.
2084     */
2085
2086    if (strcasecmp(faceName, "Courier") == 0) {
2087	return 0;
2088    }
2089    if (strcasecmp(faceName, "Times") == 0) {
2090	return 0;
2091    }
2092    if (strcasecmp(faceName, "Helvetica") == 0) {
2093	return 0;
2094    }
2095
2096    Tcl_UtfToExternalDString(systemEncoding, faceName, -1, &faceString);
2097
2098    /*
2099     * If the family exists, WinFontExistProc() will be called and
2100     * EnumFontFamilies() will return whatever WinFontExistProc() returns.
2101     * If the family doesn't exist, EnumFontFamilies() will just return a
2102     * non-zero value.
2103     */
2104
2105    if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
2106	result = EnumFontFamiliesW(hdc, (WCHAR *) Tcl_DStringValue(&faceString),
2107		(FONTENUMPROCW) WinFontExistProc, 0);
2108    } else {
2109	result = EnumFontFamiliesA(hdc, (char *) Tcl_DStringValue(&faceString),
2110		(FONTENUMPROCA) WinFontExistProc, 0);
2111    }
2112    Tcl_DStringFree(&faceString);
2113    return (result == 0);
2114}
2115
2116static char *
2117FamilyOrAliasExists(
2118    HDC hdc,
2119    CONST char *faceName)
2120{
2121    char **aliases;
2122    int i;
2123
2124    if (FamilyExists(hdc, faceName) != 0) {
2125	return (char *) faceName;
2126    }
2127    aliases = TkFontGetAliasList(faceName);
2128    if (aliases != NULL) {
2129	for (i = 0; aliases[i] != NULL; i++) {
2130	    if (FamilyExists(hdc, aliases[i]) != 0) {
2131		return aliases[i];
2132	    }
2133	}
2134    }
2135    return NULL;
2136}
2137
2138static int CALLBACK
2139WinFontExistProc(
2140    ENUMLOGFONT *lfPtr,		/* Logical-font data. */
2141    NEWTEXTMETRIC *tmPtr,	/* Physical-font data (not used). */
2142    int fontType,		/* Type of font (not used). */
2143    LPARAM lParam)		/* EnumFontData to hold result. */
2144{
2145    return 0;
2146}
2147
2148/*
2149 * The following data structures are used when querying a TrueType font file
2150 * to determine which characters the font supports.
2151 */
2152
2153#pragma pack(1)			/* Structures are byte aligned in file. */
2154
2155#define CMAPHEX  0x636d6170	/* Key for character map resource. */
2156
2157typedef struct CMAPTABLE {
2158    USHORT version;		/* Table version number (0). */
2159    USHORT numTables;		/* Number of encoding tables following. */
2160} CMAPTABLE;
2161
2162typedef struct ENCODINGTABLE {
2163    USHORT platform;		/* Platform for which data is targeted.
2164				 * 3 means data is for Windows. */
2165    USHORT encoding;		/* How characters in font are encoded.
2166				 * 1 means that the following subtable is
2167				 * keyed based on Unicode. */
2168    ULONG offset;		/* Byte offset from beginning of CMAPTABLE
2169				 * to the subtable for this encoding. */
2170} ENCODINGTABLE;
2171
2172typedef struct ANYTABLE {
2173    USHORT format;		/* Format number. */
2174    USHORT length;		/* The actual length in bytes of this
2175				 * subtable. */
2176    USHORT version;		/* Version number (starts at 0). */
2177} ANYTABLE;
2178
2179typedef struct BYTETABLE {
2180    USHORT format;		/* Format number is set to 0. */
2181    USHORT length;		/* The actual length in bytes of this
2182				 * subtable. */
2183    USHORT version;		/* Version number (starts at 0). */
2184    BYTE glyphIdArray[256];	/* Array that maps up to 256 single-byte char
2185				 * codes to glyph indices. */
2186} BYTETABLE;
2187
2188typedef struct SUBHEADER {
2189    USHORT firstCode;		/* First valid low byte for subHeader. */
2190    USHORT entryCount;		/* Number valid low bytes for subHeader. */
2191    SHORT idDelta;		/* Constant adder to get base glyph index. */
2192    USHORT idRangeOffset;	/* Byte offset from here to appropriate
2193				 * glyphIndexArray. */
2194} SUBHEADER;
2195
2196typedef struct HIBYTETABLE {
2197    USHORT format;  		/* Format number is set to 2. */
2198    USHORT length;		/* The actual length in bytes of this
2199				 * subtable. */
2200    USHORT version;		/* Version number (starts at 0). */
2201    USHORT subHeaderKeys[256];	/* Maps high bytes to subHeaders: value is
2202				 * subHeader index * 8. */
2203#if 0
2204    SUBHEADER subHeaders[];	/* Variable-length array of SUBHEADERs. */
2205    USHORT glyphIndexArray[];	/* Variable-length array containing subarrays
2206				 * used for mapping the low byte of 2-byte
2207				 * characters. */
2208#endif
2209} HIBYTETABLE;
2210
2211typedef struct SEGMENTTABLE {
2212    USHORT format;		/* Format number is set to 4. */
2213    USHORT length;		/* The actual length in bytes of this
2214				 * subtable. */
2215    USHORT version;		/* Version number (starts at 0). */
2216    USHORT segCountX2;		/* 2 x segCount. */
2217    USHORT searchRange;		/* 2 x (2**floor(log2(segCount))). */
2218    USHORT entrySelector;	/* log2(searchRange/2). */
2219    USHORT rangeShift;		/* 2 x segCount - searchRange. */
2220#if 0
2221    USHORT endCount[segCount]	/* End characterCode for each segment. */
2222    USHORT reservedPad;		/* Set to 0. */
2223    USHORT startCount[segCount];/* Start character code for each segment. */
2224    USHORT idDelta[segCount];	/* Delta for all character in segment. */
2225    USHORT idRangeOffset[segCount]; /* Offsets into glyphIdArray or 0. */
2226    USHORT glyphIdArray[]	/* Glyph index array. */
2227#endif
2228} SEGMENTTABLE;
2229
2230typedef struct TRIMMEDTABLE {
2231    USHORT format;		/* Format number is set to 6. */
2232    USHORT length;		/* The actual length in bytes of this
2233				 * subtable. */
2234    USHORT version;		/* Version number (starts at 0). */
2235    USHORT firstCode;		/* First character code of subrange. */
2236    USHORT entryCount;		/* Number of character codes in subrange. */
2237#if 0
2238    USHORT glyphIdArray[];	/* Array of glyph index values for
2239				        character codes in the range. */
2240#endif
2241} TRIMMEDTABLE;
2242
2243typedef union SUBTABLE {
2244    ANYTABLE any;
2245    BYTETABLE byte;
2246    HIBYTETABLE hiByte;
2247    SEGMENTTABLE segment;
2248    TRIMMEDTABLE trimmed;
2249} SUBTABLE;
2250
2251#pragma pack()
2252
2253/*
2254 *-------------------------------------------------------------------------
2255 *
2256 * LoadFontRanges --
2257 *
2258 *	Given an HFONT, get the information about the characters that
2259 *	this font can display.
2260 *
2261 * Results:
2262 *	If the font has no Unicode character information, the return value
2263 *	is 0 and *startCountPtr and *endCountPtr are filled with NULL.
2264 *	Otherwise, *startCountPtr and *endCountPtr are set to pointers to
2265 *	arrays of TrueType character existence information and the return
2266 *	value is the length of the arrays (the two arrays are always the
2267 *	same length as each other).
2268 *
2269 * Side effects:
2270 *	None.
2271 *
2272 *-------------------------------------------------------------------------
2273 */
2274
2275static int
2276LoadFontRanges(
2277    HDC hdc,			/* HDC into which font can be selected. */
2278    HFONT hFont,		/* HFONT to query. */
2279    USHORT **startCountPtr,	/* Filled with malloced pointer to
2280				 * character range information. */
2281    USHORT **endCountPtr,	/* Filled with malloced pointer to
2282				 * character range information. */
2283    int *symbolPtr)
2284 {
2285    int n, i, swapped, offset, cbData, segCount;
2286    DWORD cmapKey;
2287    USHORT *startCount, *endCount;
2288    CMAPTABLE cmapTable;
2289    ENCODINGTABLE encTable;
2290    SUBTABLE subTable;
2291    char *s;
2292
2293    segCount = 0;
2294    startCount = NULL;
2295    endCount = NULL;
2296    *symbolPtr = 0;
2297
2298    hFont = SelectObject(hdc, hFont);
2299
2300    i = 0;
2301    s = (char *) &i;
2302    *s = '\1';
2303    swapped = 0;
2304
2305    if (i == 1) {
2306	swapped = 1;
2307    }
2308
2309    cmapKey = CMAPHEX;
2310    if (swapped) {
2311	SwapLong(&cmapKey);
2312    }
2313
2314    n = GetFontData(hdc, cmapKey, 0, &cmapTable, sizeof(cmapTable));
2315    if (n != GDI_ERROR) {
2316	if (swapped) {
2317	    SwapShort(&cmapTable.numTables);
2318	}
2319	for (i = 0; i < cmapTable.numTables; i++) {
2320	    offset = sizeof(cmapTable) + i * sizeof(encTable);
2321	    GetFontData(hdc, cmapKey, offset, &encTable, sizeof(encTable));
2322	    if (swapped) {
2323		SwapShort(&encTable.platform);
2324		SwapShort(&encTable.encoding);
2325		SwapLong(&encTable.offset);
2326	    }
2327	    if (encTable.platform != 3) {
2328		/*
2329		 * Not Microsoft encoding.
2330		 */
2331
2332		continue;
2333	    }
2334	    if (encTable.encoding == 0) {
2335		*symbolPtr = 1;
2336	    } else if (encTable.encoding != 1) {
2337		continue;
2338	    }
2339
2340	    GetFontData(hdc, cmapKey, encTable.offset, &subTable,
2341		    sizeof(subTable));
2342	    if (swapped) {
2343		SwapShort(&subTable.any.format);
2344	    }
2345	    if (subTable.any.format == 4) {
2346		if (swapped) {
2347		    SwapShort(&subTable.segment.segCountX2);
2348		}
2349		segCount = subTable.segment.segCountX2 / 2;
2350		cbData = segCount * sizeof(USHORT);
2351
2352		startCount = (USHORT *) ckalloc(cbData);
2353		endCount = (USHORT *) ckalloc(cbData);
2354
2355		offset = encTable.offset + sizeof(subTable.segment);
2356		GetFontData(hdc, cmapKey, offset, endCount, cbData);
2357		offset += cbData + sizeof(USHORT);
2358		GetFontData(hdc, cmapKey, offset, startCount, cbData);
2359		if (swapped) {
2360		    for (i = 0; i < segCount; i++) {
2361			SwapShort(&endCount[i]);
2362			SwapShort(&startCount[i]);
2363		    }
2364		}
2365		if (*symbolPtr != 0) {
2366		    /*
2367		     * Empirically determined:  When a symbol font is
2368		     * loaded, the character existence metrics obtained
2369		     * from the system are mildly wrong.  If the real range
2370		     * of the symbol font is from 0020 to 00FE, then the
2371		     * metrics are reported as F020 to F0FE.  When we load
2372		     * a symbol font, we must fix the character existence
2373		     * metrics.
2374		     *
2375		     * Symbol fonts should only use the symbol encoding
2376		     * for 8-bit characters [note Bug: 2406]
2377		     */
2378
2379		    for (i = 0; i < segCount; i++) {
2380			if (((startCount[i] & 0xff00) == 0xf000)
2381				&& ((endCount[i] & 0xff00) == 0xf000)) {
2382			    startCount[i] &= 0xff;
2383			    endCount[i] &= 0xff;
2384			}
2385		    }
2386		}
2387	    }
2388	}
2389    } else if (GetTextCharset(hdc) == ANSI_CHARSET) {
2390	/*
2391	 * Bitmap font.  We should also support ranges for the other
2392	 * *_CHARSET values.
2393	 */
2394	segCount = 1;
2395	cbData = segCount * sizeof(USHORT);
2396	startCount = (USHORT *) ckalloc(cbData);
2397	endCount = (USHORT *) ckalloc(cbData);
2398	startCount[0] = 0x0000;
2399	endCount[0] = 0x00ff;
2400    }
2401    SelectObject(hdc, hFont);
2402
2403    *startCountPtr = startCount;
2404    *endCountPtr = endCount;
2405    return segCount;
2406}
2407
2408/*
2409 *-------------------------------------------------------------------------
2410 *
2411 * SwapShort, SwapLong --
2412 *
2413 *	Helper functions to convert the data loaded from TrueType font
2414 *	files to Intel byte ordering.
2415 *
2416 * Results:
2417 *	Bytes of input value are swapped and stored back in argument.
2418 *
2419 * Side effects:
2420 *	None.
2421 *
2422 *-------------------------------------------------------------------------
2423 */
2424
2425static void
2426SwapShort(PUSHORT p)
2427{
2428    *p = (SHORT)(HIBYTE(*p) + (LOBYTE(*p) << 8));
2429}
2430
2431static void
2432SwapLong(PULONG p)
2433{
2434    ULONG temp;
2435
2436    temp = (LONG) ((BYTE) *p);
2437    temp <<= 8;
2438    *p >>=8;
2439
2440    temp += (LONG) ((BYTE) *p);
2441    temp <<= 8;
2442    *p >>=8;
2443
2444    temp += (LONG) ((BYTE) *p);
2445    temp <<= 8;
2446    *p >>=8;
2447
2448    temp += (LONG) ((BYTE) *p);
2449    *p = temp;
2450}
2451