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

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinfont.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25