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