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