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