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