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