1/* 2 * tkUnixFont.c -- 3 * 4 * Contains the Unix implementation of the platform-independant 5 * font package interface. 6 * 7 * Copyright (c) 1996-1997 Sun Microsystems, Inc. 8 * 9 * See the file "license.terms" for information on usage and redistribution 10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 * RCS: @(#) $Id: tkUnixFont.c,v 1.18.2.6 2006/10/05 21:28:17 hobbs Exp $ 13 */ 14 15#include "tkUnixInt.h" 16#include "tkFont.h" 17#include <netinet/in.h> /* for htons() prototype */ 18#include <arpa/inet.h> /* inet_ntoa() */ 19 20/* 21 * The preferred font encodings. 22 */ 23 24static CONST char *encodingList[] = { 25 "iso8859-1", "jis0208", "jis0212", NULL 26}; 27 28/* 29 * The following structure represents a font family. It is assumed that 30 * all screen fonts constructed from the same "font family" share certain 31 * properties; all screen fonts with the same "font family" point to a 32 * shared instance of this structure. The most important shared property 33 * is the character existence metrics, used to determine if a screen font 34 * can display a given Unicode character. 35 * 36 * Under Unix, there are three attributes that uniquely identify a "font 37 * family": the foundry, face name, and charset. 38 */ 39 40#define FONTMAP_SHIFT 10 41 42#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT)) 43#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT) 44 45typedef struct FontFamily { 46 struct FontFamily *nextPtr; /* Next in list of all known font families. */ 47 int refCount; /* How many SubFonts are referring to this 48 * FontFamily. When the refCount drops to 49 * zero, this FontFamily may be freed. */ 50 /* 51 * Key. 52 */ 53 54 Tk_Uid foundry; /* Foundry key for this FontFamily. */ 55 Tk_Uid faceName; /* Face name key for this FontFamily. */ 56 Tcl_Encoding encoding; /* Encoding key for this FontFamily. */ 57 58 /* 59 * Derived properties. 60 */ 61 62 int isTwoByteFont; /* 1 if this is a double-byte font, 0 63 * otherwise. */ 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 alloced. 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} FontFamily; 77 78/* 79 * The following structure encapsulates an individual screen font. A font 80 * object is made up of however many SubFonts are necessary to display a 81 * stream of multilingual characters. 82 */ 83 84typedef struct SubFont { 85 char **fontMap; /* Pointer to font map from the FontFamily, 86 * cached here to save a dereference. */ 87 XFontStruct *fontStructPtr; /* The specific screen font that will be 88 * used when displaying/measuring chars 89 * belonging to the FontFamily. */ 90 FontFamily *familyPtr; /* The FontFamily for this SubFont. */ 91} SubFont; 92 93/* 94 * The following structure represents Unix's implementation of a font 95 * object. 96 */ 97 98#define SUBFONT_SPACE 3 99#define BASE_CHARS 256 100 101typedef struct UnixFont { 102 TkFont font; /* Stuff used by generic font package. Must 103 * be first in structure. */ 104 SubFont staticSubFonts[SUBFONT_SPACE]; 105 /* Builtin space for a limited number of 106 * SubFonts. */ 107 int numSubFonts; /* Length of following array. */ 108 SubFont *subFontArray; /* Array of SubFonts that have been loaded 109 * in order to draw/measure all the characters 110 * encountered by this font so far. All fonts 111 * start off with one SubFont initialized by 112 * AllocFont() from the original set of font 113 * attributes. Usually points to 114 * staticSubFonts, but may point to malloced 115 * space if there are lots of SubFonts. */ 116 SubFont controlSubFont; /* Font to use to display control-character 117 * expansions. */ 118 119 Display *display; /* Display that owns font. */ 120 int pixelSize; /* Original pixel size used when font was 121 * constructed. */ 122 TkXLFDAttributes xa; /* Additional attributes that specify the 123 * preferred foundry and encoding to use when 124 * constructing additional SubFonts. */ 125 int widths[BASE_CHARS]; /* Widths of first 256 chars in the base 126 * font, for handling common case. */ 127 int underlinePos; /* Offset from baseline to origin of 128 * underline bar (used when drawing underlined 129 * font) (pixels). */ 130 int barHeight; /* Height of underline or overstrike bar 131 * (used when drawing underlined or strikeout 132 * font) (pixels). */ 133} UnixFont; 134 135/* 136 * The following structure and definition is used to keep track of the 137 * alternative names for various encodings. Asking for an encoding that 138 * matches one of the alias patterns will result in actually getting the 139 * encoding by its real name. 140 */ 141 142typedef struct EncodingAlias { 143 char *realName; /* The real name of the encoding to load if 144 * the provided name matched the pattern. */ 145 char *aliasPattern; /* Pattern for encoding name, of the form 146 * that is acceptable to Tcl_StringMatch. */ 147} EncodingAlias; 148 149/* 150 * Just some utility structures used for passing around values in helper 151 * procedures. 152 */ 153 154typedef struct FontAttributes { 155 TkFontAttributes fa; 156 TkXLFDAttributes xa; 157} FontAttributes; 158 159 160typedef struct ThreadSpecificData { 161 FontFamily *fontFamilyList; /* The list of font families that are 162 * currently loaded. As screen fonts 163 * are loaded, this list grows to hold 164 * information about what characters 165 * exist in each font family. */ 166 FontFamily controlFamily; /* FontFamily used to handle control 167 * character expansions. The encoding 168 * of this FontFamily converts UTF-8 to 169 * backslashed escape sequences. */ 170} ThreadSpecificData; 171static Tcl_ThreadDataKey dataKey; 172 173/* 174 * The set of builtin encoding alises to convert the XLFD names for the 175 * encodings into the names expected by the Tcl encoding package. 176 */ 177 178static EncodingAlias encodingAliases[] = { 179 {"gb2312-raw", "gb2312*"}, 180 {"big5", "big5*"}, 181 {"cns11643-1", "cns11643*-1"}, 182 {"cns11643-1", "cns11643*.1-0"}, 183 {"cns11643-2", "cns11643*-2"}, 184 {"cns11643-2", "cns11643*.2-0"}, 185 {"jis0201", "jisx0201*"}, 186 {"jis0201", "jisx0202*"}, 187 {"jis0208", "jisc6226*"}, 188 {"jis0208", "jisx0208*"}, 189 {"jis0212", "jisx0212*"}, 190 {"tis620", "tis620*"}, 191 {"ksc5601", "ksc5601*"}, 192 {"dingbats", "*dingbats"}, 193#ifdef WORDS_BIGENDIAN 194 {"unicode", "iso10646-1"}, 195#else 196 /* 197 * ucs-2be is needed if native order isn't BE. 198 */ 199 {"ucs-2be", "iso10646-1"}, 200#endif 201 {NULL, NULL} 202}; 203 204/* 205 * Procedures used only in this file. 206 */ 207 208static void FontPkgCleanup _ANSI_ARGS_((ClientData clientData)); 209static FontFamily * AllocFontFamily _ANSI_ARGS_((Display *display, 210 XFontStruct *fontStructPtr, int base)); 211static SubFont * CanUseFallback _ANSI_ARGS_((UnixFont *fontPtr, 212 CONST char *fallbackName, int ch, 213 SubFont **fixSubFontPtrPtr)); 214static SubFont * CanUseFallbackWithAliases _ANSI_ARGS_(( 215 UnixFont *fontPtr, char *fallbackName, 216 int ch, Tcl_DString *nameTriedPtr, 217 SubFont **fixSubFontPtrPtr)); 218static int ControlUtfProc _ANSI_ARGS_((ClientData clientData, 219 CONST char *src, int srcLen, int flags, 220 Tcl_EncodingState *statePtr, char *dst, 221 int dstLen, int *srcReadPtr, int *dstWrotePtr, 222 int *dstCharsPtr)); 223static XFontStruct * CreateClosestFont _ANSI_ARGS_((Tk_Window tkwin, 224 CONST TkFontAttributes *faPtr, 225 CONST TkXLFDAttributes *xaPtr)); 226static SubFont * FindSubFontForChar _ANSI_ARGS_((UnixFont *fontPtr, 227 int ch, SubFont **fixSubFontPtrPtr)); 228static void FontMapInsert _ANSI_ARGS_((SubFont *subFontPtr, 229 int ch)); 230static void FontMapLoadPage _ANSI_ARGS_((SubFont *subFontPtr, 231 int row)); 232static int FontMapLookup _ANSI_ARGS_((SubFont *subFontPtr, 233 int ch)); 234static void FreeFontFamily _ANSI_ARGS_((FontFamily *afPtr)); 235static CONST char * GetEncodingAlias _ANSI_ARGS_((CONST char *name)); 236static int GetFontAttributes _ANSI_ARGS_((Display *display, 237 XFontStruct *fontStructPtr, FontAttributes *faPtr)); 238static XFontStruct * GetScreenFont _ANSI_ARGS_((Display *display, 239 FontAttributes *wantPtr, char **nameList, 240 int bestIdx[], unsigned int bestScore[])); 241static XFontStruct * GetSystemFont _ANSI_ARGS_((Display *display)); 242static int IdentifySymbolEncodings _ANSI_ARGS_(( 243 FontAttributes *faPtr)); 244static void InitFont _ANSI_ARGS_((Tk_Window tkwin, 245 XFontStruct *fontStructPtr, UnixFont *fontPtr)); 246static void InitSubFont _ANSI_ARGS_((Display *display, 247 XFontStruct *fontStructPtr, int base, 248 SubFont *subFontPtr)); 249static char ** ListFonts _ANSI_ARGS_((Display *display, 250 CONST char *faceName, int *numNamesPtr)); 251static char ** ListFontOrAlias _ANSI_ARGS_((Display *display, 252 CONST char *faceName, int *numNamesPtr)); 253static unsigned int RankAttributes _ANSI_ARGS_((FontAttributes *wantPtr, 254 FontAttributes *gotPtr)); 255static void ReleaseFont _ANSI_ARGS_((UnixFont *fontPtr)); 256static void ReleaseSubFont _ANSI_ARGS_((Display *display, 257 SubFont *subFontPtr)); 258static int SeenName _ANSI_ARGS_((CONST char *name, 259 Tcl_DString *dsPtr)); 260#ifndef WORDS_BIGENDIAN 261static int Ucs2beToUtfProc _ANSI_ARGS_((ClientData clientData, 262 CONST char *src, int srcLen, int flags, 263 Tcl_EncodingState *statePtr, char *dst, int dstLen, 264 int *srcReadPtr, int *dstWrotePtr, 265 int *dstCharsPtr)); 266static int UtfToUcs2beProc _ANSI_ARGS_((ClientData clientData, 267 CONST char *src, int srcLen, int flags, 268 Tcl_EncodingState *statePtr, char *dst, int dstLen, 269 int *srcReadPtr, int *dstWrotePtr, 270 int *dstCharsPtr)); 271#endif 272 273 274/* 275 *------------------------------------------------------------------------- 276 * 277 * FontPkgCleanup -- 278 * 279 * This procedure is called when an application is created. It 280 * initializes all the structures that are used by the 281 * platform-dependent code on a per application basis. 282 * 283 * Results: 284 * None. 285 * 286 * Side effects: 287 * Releases thread-specific resources used by font pkg. 288 * 289 *------------------------------------------------------------------------- 290 */ 291 292static void 293FontPkgCleanup(ClientData clientData) 294{ 295 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 296 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 297 298 if (tsdPtr->controlFamily.encoding != NULL) { 299 FontFamily *familyPtr = &tsdPtr->controlFamily; 300 int i; 301 302 Tcl_FreeEncoding(familyPtr->encoding); 303 for (i = 0; i < FONTMAP_PAGES; i++) { 304 if (familyPtr->fontMap[i] != NULL) { 305 ckfree(familyPtr->fontMap[i]); 306 } 307 } 308 tsdPtr->controlFamily.encoding = NULL; 309 } 310} 311 312/* 313 *------------------------------------------------------------------------- 314 * 315 * TkpFontPkgInit -- 316 * 317 * This procedure is called when an application is created. It 318 * initializes all the structures that are used by the 319 * platform-dependent code on a per application basis. 320 * 321 * Results: 322 * None. 323 * 324 * Side effects: 325 * None. 326 * 327 *------------------------------------------------------------------------- 328 */ 329 330void 331TkpFontPkgInit(mainPtr) 332 TkMainInfo *mainPtr; /* The application being created. */ 333{ 334 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 335 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 336 Tcl_EncodingType type; 337 SubFont dummy; 338 int i; 339 340 if (tsdPtr->controlFamily.encoding == NULL) { 341 type.encodingName = "X11ControlChars"; 342 type.toUtfProc = ControlUtfProc; 343 type.fromUtfProc = ControlUtfProc; 344 type.freeProc = NULL; 345 type.clientData = NULL; 346 type.nullSize = 0; 347 348 tsdPtr->controlFamily.refCount = 2; 349 tsdPtr->controlFamily.encoding = Tcl_CreateEncoding(&type); 350 tsdPtr->controlFamily.isTwoByteFont = 0; 351 352 dummy.familyPtr = &tsdPtr->controlFamily; 353 dummy.fontMap = tsdPtr->controlFamily.fontMap; 354 for (i = 0x00; i < 0x20; i++) { 355 FontMapInsert(&dummy, i); 356 FontMapInsert(&dummy, i + 0x80); 357 } 358 359#ifndef WORDS_BIGENDIAN 360 /* 361 * UCS-2BE is unicode (UCS-2) in big-endian format. Define this 362 * if native order isn't BE. It is used in iso10646 fonts. 363 */ 364 365 type.encodingName = "ucs-2be"; 366 type.toUtfProc = Ucs2beToUtfProc; 367 type.fromUtfProc = UtfToUcs2beProc; 368 type.freeProc = NULL; 369 type.clientData = NULL; 370 type.nullSize = 2; 371 Tcl_CreateEncoding(&type); 372#endif 373 Tcl_CreateThreadExitHandler(FontPkgCleanup, NULL); 374 } 375} 376 377/* 378 *------------------------------------------------------------------------- 379 * 380 * ControlUtfProc -- 381 * 382 * Convert from UTF-8 into the ASCII expansion of a control 383 * character. 384 * 385 * Results: 386 * Returns TCL_OK if conversion was successful. 387 * 388 * Side effects: 389 * None. 390 * 391 *------------------------------------------------------------------------- 392 */ 393 394static int 395ControlUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, 396 srcReadPtr, dstWrotePtr, dstCharsPtr) 397 ClientData clientData; /* Not used. */ 398 CONST char *src; /* Source string in UTF-8. */ 399 int srcLen; /* Source string length in bytes. */ 400 int flags; /* Conversion control flags. */ 401 Tcl_EncodingState *statePtr;/* Place for conversion routine to store 402 * state information used during a piecewise 403 * conversion. Contents of statePtr are 404 * initialized and/or reset by conversion 405 * routine under control of flags argument. */ 406 char *dst; /* Output buffer in which converted string 407 * is stored. */ 408 int dstLen; /* The maximum length of output buffer in 409 * bytes. */ 410 int *srcReadPtr; /* Filled with the number of bytes from the 411 * source string that were converted. This 412 * may be less than the original source length 413 * if there was a problem converting some 414 * source characters. */ 415 int *dstWrotePtr; /* Filled with the number of bytes that were 416 * stored in the output buffer as a result of 417 * the conversion. */ 418 int *dstCharsPtr; /* Filled with the number of characters that 419 * correspond to the bytes stored in the 420 * output buffer. */ 421{ 422 CONST char *srcStart, *srcEnd; 423 char *dstStart, *dstEnd; 424 Tcl_UniChar ch; 425 int result; 426 static char hexChars[] = "0123456789abcdef"; 427 static char mapChars[] = { 428 0, 0, 0, 0, 0, 0, 0, 429 'a', 'b', 't', 'n', 'v', 'f', 'r' 430 }; 431 432 result = TCL_OK; 433 434 srcStart = src; 435 srcEnd = src + srcLen; 436 437 dstStart = dst; 438 dstEnd = dst + dstLen - 6; 439 440 for ( ; src < srcEnd; ) { 441 if (dst > dstEnd) { 442 result = TCL_CONVERT_NOSPACE; 443 break; 444 } 445 src += Tcl_UtfToUniChar(src, &ch); 446 dst[0] = '\\'; 447 if ((ch < sizeof(mapChars)) && (mapChars[ch] != 0)) { 448 dst[1] = mapChars[ch]; 449 dst += 2; 450 } else if (ch < 256) { 451 dst[1] = 'x'; 452 dst[2] = hexChars[(ch >> 4) & 0xf]; 453 dst[3] = hexChars[ch & 0xf]; 454 dst += 4; 455 } else { 456 dst[1] = 'u'; 457 dst[2] = hexChars[(ch >> 12) & 0xf]; 458 dst[3] = hexChars[(ch >> 8) & 0xf]; 459 dst[4] = hexChars[(ch >> 4) & 0xf]; 460 dst[5] = hexChars[ch & 0xf]; 461 dst += 6; 462 } 463 } 464 *srcReadPtr = src - srcStart; 465 *dstWrotePtr = dst - dstStart; 466 *dstCharsPtr = dst - dstStart; 467 return result; 468} 469 470#ifndef WORDS_BIGENDIAN 471/* 472 *------------------------------------------------------------------------- 473 * 474 * Ucs2beToUtfProc -- 475 * 476 * Convert from UCS-2BE (big-endian 16-bit Unicode) to UTF-8. 477 * This is only defined on LE machines. 478 * 479 * Results: 480 * Returns TCL_OK if conversion was successful. 481 * 482 * Side effects: 483 * None. 484 * 485 *------------------------------------------------------------------------- 486 */ 487 488static int 489Ucs2beToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, 490 srcReadPtr, dstWrotePtr, dstCharsPtr) 491 ClientData clientData; /* Not used. */ 492 CONST char *src; /* Source string in Unicode. */ 493 int srcLen; /* Source string length in bytes. */ 494 int flags; /* Conversion control flags. */ 495 Tcl_EncodingState *statePtr;/* Place for conversion routine to store 496 * state information used during a piecewise 497 * conversion. Contents of statePtr are 498 * initialized and/or reset by conversion 499 * routine under control of flags argument. */ 500 char *dst; /* Output buffer in which converted string 501 * is stored. */ 502 int dstLen; /* The maximum length of output buffer in 503 * bytes. */ 504 int *srcReadPtr; /* Filled with the number of bytes from the 505 * source string that were converted. This 506 * may be less than the original source length 507 * if there was a problem converting some 508 * source characters. */ 509 int *dstWrotePtr; /* Filled with the number of bytes that were 510 * stored in the output buffer as a result of 511 * the conversion. */ 512 int *dstCharsPtr; /* Filled with the number of characters that 513 * correspond to the bytes stored in the 514 * output buffer. */ 515{ 516 CONST char *srcStart, *srcEnd; 517 char *dstEnd, *dstStart; 518 int result, numChars; 519 520 result = TCL_OK; 521 522 /* check alignment with ucs-2 (2 == sizeof(UCS-2)) */ 523 if ((srcLen % 2) != 0) { 524 result = TCL_CONVERT_MULTIBYTE; 525 srcLen--; 526 } 527 528 srcStart = src; 529 srcEnd = src + srcLen; 530 531 dstStart = dst; 532 dstEnd = dst + dstLen - TCL_UTF_MAX; 533 534 for (numChars = 0; src < srcEnd; numChars++) { 535 if (dst > dstEnd) { 536 result = TCL_CONVERT_NOSPACE; 537 break; 538 } 539 /* 540 * Need to swap byte-order on little-endian machines (x86) for 541 * UCS-2BE. We know this is an LE->BE swap. 542 */ 543 dst += Tcl_UniCharToUtf(htons(*((short *)src)), dst); 544 src += 2 /* sizeof(UCS-2) */; 545 } 546 547 *srcReadPtr = src - srcStart; 548 *dstWrotePtr = dst - dstStart; 549 *dstCharsPtr = numChars; 550 return result; 551} 552 553/* 554 *------------------------------------------------------------------------- 555 * 556 * UtfToUcs2beProc -- 557 * 558 * Convert from UTF-8 to UCS-2BE (fixed 2-byte encoding). 559 * 560 * Results: 561 * Returns TCL_OK if conversion was successful. 562 * 563 * Side effects: 564 * None. 565 * 566 *------------------------------------------------------------------------- 567 */ 568 569static int 570UtfToUcs2beProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, 571 srcReadPtr, dstWrotePtr, dstCharsPtr) 572 ClientData clientData; /* TableEncodingData that specifies encoding. */ 573 CONST char *src; /* Source string in UTF-8. */ 574 int srcLen; /* Source string length in bytes. */ 575 int flags; /* Conversion control flags. */ 576 Tcl_EncodingState *statePtr;/* Place for conversion routine to store 577 * state information used during a piecewise 578 * conversion. Contents of statePtr are 579 * initialized and/or reset by conversion 580 * routine under control of flags argument. */ 581 char *dst; /* Output buffer in which converted string 582 * is stored. */ 583 int dstLen; /* The maximum length of output buffer in 584 * bytes. */ 585 int *srcReadPtr; /* Filled with the number of bytes from the 586 * source string that were converted. This 587 * may be less than the original source length 588 * if there was a problem converting some 589 * source characters. */ 590 int *dstWrotePtr; /* Filled with the number of bytes that were 591 * stored in the output buffer as a result of 592 * the conversion. */ 593 int *dstCharsPtr; /* Filled with the number of characters that 594 * correspond to the bytes stored in the 595 * output buffer. */ 596{ 597 CONST char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd; 598 int result, numChars; 599 Tcl_UniChar ch; 600 601 srcStart = src; 602 srcEnd = src + srcLen; 603 srcClose = srcEnd; 604 if ((flags & TCL_ENCODING_END) == 0) { 605 srcClose -= TCL_UTF_MAX; 606 } 607 608 dstStart = dst; 609 dstEnd = dst + dstLen - 2 /* sizeof(UCS-2) */; 610 611 result = TCL_OK; 612 for (numChars = 0; src < srcEnd; numChars++) { 613 if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { 614 /* 615 * If there is more string to follow, this will ensure that the 616 * last UTF-8 character in the source buffer hasn't been cut off. 617 */ 618 619 result = TCL_CONVERT_MULTIBYTE; 620 break; 621 } 622 if (dst > dstEnd) { 623 result = TCL_CONVERT_NOSPACE; 624 break; 625 } 626 src += Tcl_UtfToUniChar(src, &ch); 627 /* 628 * Ensure big-endianness (store big bits first). 629 * XXX: This hard-codes the assumed size of Tcl_UniChar as 2. 630 * Make sure to work in char* for Tcl_UtfToUniChar alignment. 631 * [Bug 1122671] 632 */ 633 *dst++ = (ch >> 8); 634 *dst++ = (ch & 0xFF); 635 } 636 *srcReadPtr = src - srcStart; 637 *dstWrotePtr = dst - dstStart; 638 *dstCharsPtr = numChars; 639 return result; 640} 641#endif /* WORDS_BIGENDIAN */ 642 643/* 644 *--------------------------------------------------------------------------- 645 * 646 * TkpGetNativeFont -- 647 * 648 * Map a platform-specific native font name to a TkFont. 649 * 650 * Results: 651 * The return value is a pointer to a TkFont that represents the 652 * native font. If a native font by the given name could not be 653 * found, the return value is NULL. 654 * 655 * Every call to this procedure returns a new TkFont structure, 656 * even if the name has already been seen before. The caller should 657 * call TkpDeleteFont() when the font is no longer needed. 658 * 659 * The caller is responsible for initializing the memory associated 660 * with the generic TkFont when this function returns and releasing 661 * the contents of the generic TkFont before calling TkpDeleteFont(). 662 * 663 * Side effects: 664 * Memory allocated. 665 * 666 *--------------------------------------------------------------------------- 667 */ 668 669TkFont * 670TkpGetNativeFont(tkwin, name) 671 Tk_Window tkwin; /* For display where font will be used. */ 672 CONST char *name; /* Platform-specific font name. */ 673{ 674 UnixFont *fontPtr; 675 XFontStruct *fontStructPtr; 676 FontAttributes fa; 677 CONST char *p; 678 int hasSpace, dashes, hasWild; 679 680 /* 681 * The behavior of X when given a name that isn't an XLFD is unspecified. 682 * For example, Exceed 6 returns a valid font for any random string. This 683 * is awkward since system names have higher priority than the other Tk 684 * font syntaxes. So, we need to perform a quick sanity check on the 685 * name and fail if it looks suspicious. We fail if the name: 686 * - contains a space immediately before a dash 687 * - contains a space, but no '*' characters and fewer than 14 dashes 688 */ 689 690 hasSpace = dashes = hasWild = 0; 691 for (p = name; *p != '\0'; p++) { 692 if (*p == ' ') { 693 if (p[1] == '-') { 694 return NULL; 695 } 696 hasSpace = 1; 697 } else if (*p == '-') { 698 dashes++; 699 } else if (*p == '*') { 700 hasWild = 1; 701 } 702 } 703 if ((dashes < 14) && !hasWild && hasSpace) { 704 return NULL; 705 } 706 707 fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name); 708 if (fontStructPtr == NULL) { 709 /* 710 * Handle all names that look like XLFDs here. Otherwise, when 711 * TkpGetFontFromAttributes is called from generic code, any 712 * foundry or encoding information specified in the XLFD will have 713 * been parsed out and lost. But make sure we don't have an 714 * "-option value" string since TkFontParseXLFD would return a 715 * false success when attempting to parse it. 716 */ 717 718 if (name[0] == '-') { 719 if (name[1] != '*') { 720 char *dash; 721 722 dash = strchr(name + 1, '-'); 723 if ((dash == NULL) || (isspace(UCHAR(dash[-1])))) { 724 return NULL; 725 } 726 } 727 } else if (name[0] != '*') { 728 return NULL; 729 } 730 if (TkFontParseXLFD(name, &fa.fa, &fa.xa) != TCL_OK) { 731 return NULL; 732 } 733 fontStructPtr = CreateClosestFont(tkwin, &fa.fa, &fa.xa); 734 } 735 fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont)); 736 InitFont(tkwin, fontStructPtr, fontPtr); 737 738 return (TkFont *) fontPtr; 739} 740 741/* 742 *--------------------------------------------------------------------------- 743 * 744 * TkpGetFontFromAttributes -- 745 * 746 * Given a desired set of attributes for a font, find a font with 747 * the closest matching attributes. 748 * 749 * Results: 750 * The return value is a pointer to a TkFont that represents the 751 * font with the desired attributes. If a font with the desired 752 * attributes could not be constructed, some other font will be 753 * substituted automatically. 754 * 755 * Every call to this procedure returns a new TkFont structure, 756 * even if the specified attributes have already been seen before. 757 * The caller should call TkpDeleteFont() to free the platform- 758 * specific data when the font is no longer needed. 759 * 760 * The caller is responsible for initializing the memory associated 761 * with the generic TkFont when this function returns and releasing 762 * the contents of the generic TkFont before calling TkpDeleteFont(). 763 * 764 * Side effects: 765 * Memory allocated. 766 * 767 *--------------------------------------------------------------------------- 768 */ 769TkFont * 770TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr) 771 TkFont *tkFontPtr; /* If non-NULL, store the information in 772 * this existing TkFont structure, rather than 773 * allocating a new structure to hold the 774 * font; the existing contents of the font 775 * will be released. If NULL, a new TkFont 776 * structure is allocated. */ 777 Tk_Window tkwin; /* For display where font will be used. */ 778 CONST TkFontAttributes *faPtr; 779 /* Set of attributes to match. */ 780{ 781 UnixFont *fontPtr; 782 TkXLFDAttributes xa; 783 XFontStruct *fontStructPtr; 784 785 TkInitXLFDAttributes(&xa); 786 fontStructPtr = CreateClosestFont(tkwin, faPtr, &xa); 787 788 fontPtr = (UnixFont *) tkFontPtr; 789 if (fontPtr == NULL) { 790 fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont)); 791 } else { 792 ReleaseFont(fontPtr); 793 } 794 InitFont(tkwin, fontStructPtr, fontPtr); 795 796 fontPtr->font.fa.underline = faPtr->underline; 797 fontPtr->font.fa.overstrike = faPtr->overstrike; 798 799 return (TkFont *) fontPtr; 800} 801 802/* 803 *--------------------------------------------------------------------------- 804 * 805 * TkpDeleteFont -- 806 * 807 * Called to release a font allocated by TkpGetNativeFont() or 808 * TkpGetFontFromAttributes(). The caller should have already 809 * released the fields of the TkFont that are used exclusively by 810 * the generic TkFont code. 811 * 812 * Results: 813 * None. 814 * 815 * Side effects: 816 * TkFont is deallocated. 817 * 818 *--------------------------------------------------------------------------- 819 */ 820 821void 822TkpDeleteFont(tkFontPtr) 823 TkFont *tkFontPtr; /* Token of font to be deleted. */ 824{ 825 UnixFont *fontPtr; 826 827 fontPtr = (UnixFont *) tkFontPtr; 828 ReleaseFont(fontPtr); 829} 830 831/* 832 *--------------------------------------------------------------------------- 833 * 834 * TkpGetFontFamilies -- 835 * 836 * Return information about the font families that are available 837 * on the display of the given window. 838 * 839 * Results: 840 * Modifies interp's result object to hold a list of all the available 841 * font families. 842 * 843 * Side effects: 844 * None. 845 * 846 *--------------------------------------------------------------------------- 847 */ 848 849void 850TkpGetFontFamilies(interp, tkwin) 851 Tcl_Interp *interp; /* Interp to hold result. */ 852 Tk_Window tkwin; /* For display to query. */ 853{ 854 int i, new, numNames; 855 char *family; 856 Tcl_HashTable familyTable; 857 Tcl_HashEntry *hPtr; 858 Tcl_HashSearch search; 859 char **nameList; 860 Tcl_Obj *resultPtr, *strPtr; 861 862 resultPtr = Tcl_GetObjResult(interp); 863 864 Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS); 865 nameList = ListFonts(Tk_Display(tkwin), "*", &numNames); 866 for (i = 0; i < numNames; i++) { 867 char *familyEnd; 868 869 family = strchr(nameList[i] + 1, '-'); 870 if (family == NULL) { 871 /* 872 * Apparently, sometimes ListFonts() can return a font name with 873 * zero or one '-' character in it. This is probably indicative of 874 * a server misconfiguration, but crashing because of it is a very 875 * bad idea anyway. [Bug 1475865] 876 */ 877 878 continue; 879 } 880 family++; /* Advance to char after '-'. */ 881 familyEnd = strchr(family, '-'); 882 if (familyEnd == NULL) { 883 continue; /* See comment above. */ 884 } 885 *familyEnd = '\0'; 886 family = strchr(nameList[i] + 1, '-') + 1; 887 Tcl_CreateHashEntry(&familyTable, family, &new); 888 } 889 XFreeFontNames(nameList); 890 891 hPtr = Tcl_FirstHashEntry(&familyTable, &search); 892 while (hPtr != NULL) { 893 strPtr = Tcl_NewStringObj(Tcl_GetHashKey(&familyTable, hPtr), -1); 894 Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); 895 hPtr = Tcl_NextHashEntry(&search); 896 } 897 898 Tcl_DeleteHashTable(&familyTable); 899} 900 901/* 902 *------------------------------------------------------------------------- 903 * 904 * TkpGetSubFonts -- 905 * 906 * A function used by the testing package for querying the actual 907 * screen fonts that make up a font object. 908 * 909 * Results: 910 * Modifies interp's result object to hold a list containing the 911 * names of the screen fonts that make up the given font object. 912 * 913 * Side effects: 914 * None. 915 * 916 *------------------------------------------------------------------------- 917 */ 918 919void 920TkpGetSubFonts(interp, tkfont) 921 Tcl_Interp *interp; 922 Tk_Font tkfont; 923{ 924 int i; 925 Tcl_Obj *objv[3]; 926 Tcl_Obj *resultPtr, *listPtr; 927 UnixFont *fontPtr; 928 FontFamily *familyPtr; 929 930 resultPtr = Tcl_GetObjResult(interp); 931 fontPtr = (UnixFont *) tkfont; 932 for (i = 0; i < fontPtr->numSubFonts; i++) { 933 familyPtr = fontPtr->subFontArray[i].familyPtr; 934 objv[0] = Tcl_NewStringObj(familyPtr->faceName, -1); 935 objv[1] = Tcl_NewStringObj(familyPtr->foundry, -1); 936 objv[2] = Tcl_NewStringObj(Tcl_GetEncodingName(familyPtr->encoding), -1); 937 listPtr = Tcl_NewListObj(3, objv); 938 Tcl_ListObjAppendElement(NULL, resultPtr, listPtr); 939 } 940} 941 942/* 943 *--------------------------------------------------------------------------- 944 * 945 * Tk_MeasureChars -- 946 * 947 * Determine the number of characters from the string that will fit 948 * in the given horizontal span. The measurement is done under the 949 * assumption that Tk_DrawChars() will be used to actually display 950 * the characters. 951 * 952 * Results: 953 * The return value is the number of bytes from source that 954 * fit into the span that extends from 0 to maxLength. *lengthPtr is 955 * filled with the x-coordinate of the right edge of the last 956 * character that did fit. 957 * 958 * Side effects: 959 * None. 960 * 961 *--------------------------------------------------------------------------- 962 */ 963 964int 965Tk_MeasureChars(tkfont, source, numBytes, maxLength, flags, lengthPtr) 966 Tk_Font tkfont; /* Font in which characters will be drawn. */ 967 CONST char *source; /* UTF-8 string to be displayed. Need not be 968 * '\0' terminated. */ 969 int numBytes; /* Maximum number of bytes to consider 970 * from source string. */ 971 int maxLength; /* If >= 0, maxLength specifies the longest 972 * permissible line length in pixels; don't 973 * consider any character that would cross 974 * this x-position. If < 0, then line length 975 * is unbounded and the flags argument is 976 * ignored. */ 977 int flags; /* Various flag bits OR-ed together: 978 * TK_PARTIAL_OK means include the last char 979 * which only partially fit on this line. 980 * TK_WHOLE_WORDS means stop on a word 981 * boundary, if possible. 982 * TK_AT_LEAST_ONE means return at least one 983 * character even if no characters fit. */ 984 int *lengthPtr; /* Filled with x-location just after the 985 * terminating character. */ 986{ 987 UnixFont *fontPtr; 988 SubFont *lastSubFontPtr; 989 int curX, curByte; 990 991 /* 992 * Unix does not use kerning or fractional character widths when 993 * displaying text on the screen. So that means we can safely measure 994 * individual characters or spans of characters and add up the widths 995 * w/o any "off-by-one-pixel" errors. 996 */ 997 998 fontPtr = (UnixFont *) tkfont; 999 1000 lastSubFontPtr = &fontPtr->subFontArray[0]; 1001 1002 if (numBytes == 0) { 1003 curX = 0; 1004 curByte = 0; 1005 } else if (maxLength < 0) { 1006 CONST char *p, *end, *next; 1007 Tcl_UniChar ch; 1008 SubFont *thisSubFontPtr; 1009 FontFamily *familyPtr; 1010 Tcl_DString runString; 1011 1012 /* 1013 * A three step process: 1014 * 1. Find a contiguous range of characters that can all be 1015 * represented by a single screen font. 1016 * 2. Convert those chars to the encoding of that font. 1017 * 3. Measure converted chars. 1018 */ 1019 1020 curX = 0; 1021 end = source + numBytes; 1022 for (p = source; p < end; ) { 1023 next = p + Tcl_UtfToUniChar(p, &ch); 1024 thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr); 1025 if (thisSubFontPtr != lastSubFontPtr) { 1026 familyPtr = lastSubFontPtr->familyPtr; 1027 Tcl_UtfToExternalDString(familyPtr->encoding, source, 1028 p - source, &runString); 1029 if (familyPtr->isTwoByteFont) { 1030 curX += XTextWidth16(lastSubFontPtr->fontStructPtr, 1031 (XChar2b *) Tcl_DStringValue(&runString), 1032 Tcl_DStringLength(&runString) / 2); 1033 } else { 1034 curX += XTextWidth(lastSubFontPtr->fontStructPtr, 1035 Tcl_DStringValue(&runString), 1036 Tcl_DStringLength(&runString)); 1037 } 1038 Tcl_DStringFree(&runString); 1039 lastSubFontPtr = thisSubFontPtr; 1040 source = p; 1041 } 1042 p = next; 1043 } 1044 familyPtr = lastSubFontPtr->familyPtr; 1045 Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source, 1046 &runString); 1047 if (familyPtr->isTwoByteFont) { 1048 curX += XTextWidth16(lastSubFontPtr->fontStructPtr, 1049 (XChar2b *) Tcl_DStringValue(&runString), 1050 Tcl_DStringLength(&runString) >> 1); 1051 } else { 1052 curX += XTextWidth(lastSubFontPtr->fontStructPtr, 1053 Tcl_DStringValue(&runString), 1054 Tcl_DStringLength(&runString)); 1055 } 1056 Tcl_DStringFree(&runString); 1057 curByte = numBytes; 1058 } else { 1059 CONST char *p, *end, *next, *term; 1060 int newX, termX, sawNonSpace, dstWrote; 1061 Tcl_UniChar ch; 1062 FontFamily *familyPtr; 1063 char buf[16]; 1064 1065 /* 1066 * How many chars will fit in the space allotted? 1067 * This first version may be inefficient because it measures 1068 * every character individually. 1069 */ 1070 1071 next = source + Tcl_UtfToUniChar(source, &ch); 1072 newX = curX = termX = 0; 1073 1074 term = source; 1075 end = source + numBytes; 1076 1077 sawNonSpace = (ch > 255) || !isspace(ch); 1078 familyPtr = lastSubFontPtr->familyPtr; 1079 for (p = source; ; ) { 1080 if ((ch < BASE_CHARS) && (fontPtr->widths[ch] != 0)) { 1081 newX += fontPtr->widths[ch]; 1082 } else { 1083 lastSubFontPtr = FindSubFontForChar(fontPtr, ch, NULL); 1084 familyPtr = lastSubFontPtr->familyPtr; 1085 Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p, 1086 0, NULL, buf, sizeof(buf), NULL, &dstWrote, NULL); 1087 if (familyPtr->isTwoByteFont) { 1088 newX += XTextWidth16(lastSubFontPtr->fontStructPtr, 1089 (XChar2b *) buf, dstWrote >> 1); 1090 } else { 1091 newX += XTextWidth(lastSubFontPtr->fontStructPtr, buf, 1092 dstWrote); 1093 } 1094 } 1095 if (newX > maxLength) { 1096 break; 1097 } 1098 curX = newX; 1099 p = next; 1100 if (p >= end) { 1101 term = end; 1102 termX = curX; 1103 break; 1104 } 1105 1106 next += Tcl_UtfToUniChar(next, &ch); 1107 if ((ch < 256) && isspace(ch)) { 1108 if (sawNonSpace) { 1109 term = p; 1110 termX = curX; 1111 sawNonSpace = 0; 1112 } 1113 } else { 1114 sawNonSpace = 1; 1115 } 1116 } 1117 1118 /* 1119 * P points to the first character that doesn't fit in the desired 1120 * span. Use the flags to figure out what to return. 1121 */ 1122 1123 if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) { 1124 /* 1125 * Include the first character that didn't quite fit in the desired 1126 * span. The width returned will include the width of that extra 1127 * character. 1128 */ 1129 1130 curX = newX; 1131 p += Tcl_UtfToUniChar(p, &ch); 1132 } 1133 if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) { 1134 term = p; 1135 termX = curX; 1136 if (term == source) { 1137 term += Tcl_UtfToUniChar(term, &ch); 1138 termX = newX; 1139 } 1140 } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) { 1141 term = p; 1142 termX = curX; 1143 } 1144 1145 curX = termX; 1146 curByte = term - source; 1147 } 1148 1149 *lengthPtr = curX; 1150 return curByte; 1151} 1152 1153/* 1154 *--------------------------------------------------------------------------- 1155 * 1156 * Tk_DrawChars -- 1157 * 1158 * Draw a string of characters on the screen. Tk_DrawChars() 1159 * expands control characters that occur in the string to 1160 * \xNN sequences. 1161 * 1162 * Results: 1163 * None. 1164 * 1165 * Side effects: 1166 * Information gets drawn on the screen. 1167 * 1168 *--------------------------------------------------------------------------- 1169 */ 1170 1171void 1172Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y) 1173 Display *display; /* Display on which to draw. */ 1174 Drawable drawable; /* Window or pixmap in which to draw. */ 1175 GC gc; /* Graphics context for drawing characters. */ 1176 Tk_Font tkfont; /* Font in which characters will be drawn; 1177 * must be the same as font used in GC. */ 1178 CONST char *source; /* UTF-8 string to be displayed. Need not be 1179 * '\0' terminated. All Tk meta-characters 1180 * (tabs, control characters, and newlines) 1181 * should be stripped out of the string that 1182 * is passed to this function. If they are 1183 * not stripped out, they will be displayed as 1184 * regular printing characters. */ 1185 int numBytes; /* Number of bytes in string. */ 1186 int x, y; /* Coordinates at which to place origin of 1187 * string when drawing. */ 1188{ 1189 UnixFont *fontPtr; 1190 SubFont *thisSubFontPtr, *lastSubFontPtr; 1191 Tcl_DString runString; 1192 CONST char *p, *end, *next; 1193 int xStart, needWidth, window_width, do_width; 1194 Tcl_UniChar ch; 1195 FontFamily *familyPtr; 1196#ifdef TK_DRAW_CHAR_XWINDOW_CHECK 1197 int rx, ry; 1198 unsigned int width, height, border_width, depth; 1199 Drawable root; 1200#endif 1201 1202 fontPtr = (UnixFont *) tkfont; 1203 lastSubFontPtr = &fontPtr->subFontArray[0]; 1204 1205 xStart = x; 1206 1207#ifdef TK_DRAW_CHAR_XWINDOW_CHECK 1208 /* 1209 * Get the window width so we can abort drawing outside of the window 1210 */ 1211 if (XGetGeometry(display, drawable, &root, &rx, &ry, &width, &height, 1212 &border_width, &depth) == False) { 1213 window_width = INT_MAX; 1214 } else { 1215 window_width = width; 1216 } 1217#else 1218 /* 1219 * This is used by default until we find a solution that doesn't 1220 * round-trip to the X server (need to get Tk cached window width). 1221 */ 1222 window_width = 32768; 1223#endif 1224 1225 end = source + numBytes; 1226 needWidth = fontPtr->font.fa.underline + fontPtr->font.fa.overstrike; 1227 for (p = source; p <= end; ) { 1228 if (p < end) { 1229 next = p + Tcl_UtfToUniChar(p, &ch); 1230 thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr); 1231 } else { 1232 next = p + 1; 1233 thisSubFontPtr = lastSubFontPtr; 1234 } 1235 if ((thisSubFontPtr != lastSubFontPtr) 1236 || (p == end) || (p-source > 200)) { 1237 if (p > source) { 1238 do_width = (needWidth || (p != end)) ? 1 : 0; 1239 familyPtr = lastSubFontPtr->familyPtr; 1240 1241 Tcl_UtfToExternalDString(familyPtr->encoding, source, 1242 p - source, &runString); 1243 if (familyPtr->isTwoByteFont) { 1244 XDrawString16(display, drawable, gc, x, y, 1245 (XChar2b *) Tcl_DStringValue(&runString), 1246 Tcl_DStringLength(&runString) / 2); 1247 if (do_width) { 1248 x += XTextWidth16(lastSubFontPtr->fontStructPtr, 1249 (XChar2b *) Tcl_DStringValue(&runString), 1250 Tcl_DStringLength(&runString) / 2); 1251 } 1252 } else { 1253 XDrawString(display, drawable, gc, x, y, 1254 Tcl_DStringValue(&runString), 1255 Tcl_DStringLength(&runString)); 1256 if (do_width) { 1257 x += XTextWidth(lastSubFontPtr->fontStructPtr, 1258 Tcl_DStringValue(&runString), 1259 Tcl_DStringLength(&runString)); 1260 } 1261 } 1262 Tcl_DStringFree(&runString); 1263 } 1264 lastSubFontPtr = thisSubFontPtr; 1265 source = p; 1266 XSetFont(display, gc, lastSubFontPtr->fontStructPtr->fid); 1267 if (x > window_width) { 1268 break; 1269 } 1270 } 1271 p = next; 1272 } 1273 1274 if (lastSubFontPtr != &fontPtr->subFontArray[0]) { 1275 XSetFont(display, gc, fontPtr->subFontArray[0].fontStructPtr->fid); 1276 } 1277 1278 if (fontPtr->font.fa.underline != 0) { 1279 XFillRectangle(display, drawable, gc, xStart, 1280 y + fontPtr->underlinePos, 1281 (unsigned) (x - xStart), (unsigned) fontPtr->barHeight); 1282 } 1283 if (fontPtr->font.fa.overstrike != 0) { 1284 y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10; 1285 XFillRectangle(display, drawable, gc, xStart, y, 1286 (unsigned) (x - xStart), (unsigned) fontPtr->barHeight); 1287 } 1288} 1289 1290 1291 1292 1293/* 1294 *------------------------------------------------------------------------- 1295 * 1296 * CreateClosestFont -- 1297 * 1298 * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). 1299 * Given a set of font attributes, construct a close XFontStruct. 1300 * If requested face name is not available, automatically 1301 * substitutes an alias for requested face name. If encoding is 1302 * not specified (or the requested one is not available), 1303 * automatically chooses another encoding from the list of 1304 * preferred encodings. If the foundry is not specified (or 1305 * is not available) automatically prefers "adobe" foundry. 1306 * For all other attributes, if the requested value was not 1307 * available, the appropriate "close" value will be used. 1308 * 1309 * Results: 1310 * Return value is the XFontStruct that best matched the 1311 * requested attributes. The return value is never NULL; some 1312 * font will always be returned. 1313 * 1314 * Side effects: 1315 * None. 1316 * 1317 *------------------------------------------------------------------------- 1318 */ 1319 1320static XFontStruct * 1321CreateClosestFont(tkwin, faPtr, xaPtr) 1322 Tk_Window tkwin; /* For display where font will be used. */ 1323 CONST TkFontAttributes *faPtr; 1324 /* Set of generic attributes to match. */ 1325 CONST TkXLFDAttributes *xaPtr; 1326 /* Set of X-specific attributes to match. */ 1327{ 1328 FontAttributes want; 1329 char **nameList; 1330 int numNames, nameIdx; 1331 Display *display; 1332 XFontStruct *fontStructPtr; 1333 int bestIdx[2]; 1334 unsigned int bestScore[2]; 1335 1336 want.fa = *faPtr; 1337 want.xa = *xaPtr; 1338 1339 if (want.xa.foundry == NULL) { 1340 want.xa.foundry = Tk_GetUid("adobe"); 1341 } 1342 if (want.fa.family == NULL) { 1343 want.fa.family = Tk_GetUid("fixed"); 1344 } 1345 want.fa.size = -TkFontGetPixels(tkwin, faPtr->size); 1346 if (want.xa.charset == NULL || *want.xa.charset == '\0') { 1347 want.xa.charset = Tk_GetUid("iso8859-1"); /* locale. */ 1348 } 1349 1350 display = Tk_Display(tkwin); 1351 1352 /* 1353 * Algorithm to get the closest font to the name requested. 1354 * 1355 * try fontname 1356 * try all aliases for fontname 1357 * foreach fallback for fontname 1358 * try the fallback 1359 * try all aliases for the fallback 1360 */ 1361 1362 nameList = ListFontOrAlias(display, want.fa.family, &numNames); 1363 if (numNames == 0) { 1364 char ***fontFallbacks; 1365 int i, j; 1366 char *fallback; 1367 1368 fontFallbacks = TkFontGetFallbacks(); 1369 for (i = 0; fontFallbacks[i] != NULL; i++) { 1370 for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { 1371 if (strcasecmp(want.fa.family, fallback) == 0) { 1372 break; 1373 } 1374 } 1375 if (fallback != NULL) { 1376 for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { 1377 nameList = ListFontOrAlias(display, fallback, &numNames); 1378 if (numNames != 0) { 1379 goto found; 1380 } 1381 } 1382 } 1383 } 1384 nameList = ListFonts(display, "fixed", &numNames); 1385 if (numNames == 0) { 1386 nameList = ListFonts(display, "*", &numNames); 1387 } 1388 if (numNames == 0) { 1389 return GetSystemFont(display); 1390 } 1391 } 1392 found: 1393 bestIdx[0] = -1; 1394 bestIdx[1] = -1; 1395 bestScore[0] = (unsigned int) -1; 1396 bestScore[1] = (unsigned int) -1; 1397 for (nameIdx = 0; nameIdx < numNames; nameIdx++) { 1398 FontAttributes got; 1399 int scalable; 1400 unsigned int score; 1401 1402 if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) { 1403 continue; 1404 } 1405 IdentifySymbolEncodings(&got); 1406 scalable = (got.fa.size == 0); 1407 score = RankAttributes(&want, &got); 1408 if (score < bestScore[scalable]) { 1409 bestIdx[scalable] = nameIdx; 1410 bestScore[scalable] = score; 1411 } 1412 if (score == 0) { 1413 break; 1414 } 1415 } 1416 1417 fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx, bestScore); 1418 XFreeFontNames(nameList); 1419 1420 if (fontStructPtr == NULL) { 1421 return GetSystemFont(display); 1422 } 1423 return fontStructPtr; 1424} 1425 1426/* 1427 *--------------------------------------------------------------------------- 1428 * 1429 * InitFont -- 1430 * 1431 * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). 1432 * Initializes the memory for a new UnixFont that wraps the 1433 * platform-specific data. 1434 * 1435 * The caller is responsible for initializing the fields of the 1436 * TkFont that are used exclusively by the generic TkFont code, and 1437 * for releasing those fields before calling TkpDeleteFont(). 1438 * 1439 * Results: 1440 * Fills the WinFont structure. 1441 * 1442 * Side effects: 1443 * Memory allocated. 1444 * 1445 *--------------------------------------------------------------------------- 1446 */ 1447 1448static void 1449InitFont(tkwin, fontStructPtr, fontPtr) 1450 Tk_Window tkwin; /* For screen where font will be used. */ 1451 XFontStruct *fontStructPtr; /* X information about font. */ 1452 UnixFont *fontPtr; /* Filled with information constructed from 1453 * the above arguments. */ 1454{ 1455 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1456 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1457 unsigned long value; 1458 int minHi, maxHi, minLo, maxLo, fixed, width, limit, i, n; 1459 FontAttributes fa; 1460 TkFontAttributes *faPtr; 1461 TkFontMetrics *fmPtr; 1462 SubFont *controlPtr, *subFontPtr; 1463 char *pageMap; 1464 Display *display; 1465 1466 /* 1467 * Get all font attributes and metrics. 1468 */ 1469 1470 display = Tk_Display(tkwin); 1471 GetFontAttributes(display, fontStructPtr, &fa); 1472 1473 minHi = fontStructPtr->min_byte1; 1474 maxHi = fontStructPtr->max_byte1; 1475 minLo = fontStructPtr->min_char_or_byte2; 1476 maxLo = fontStructPtr->max_char_or_byte2; 1477 1478 fixed = 1; 1479 if (fontStructPtr->per_char != NULL) { 1480 width = 0; 1481 limit = (maxHi - minHi + 1) * (maxLo - minLo + 1); 1482 for (i = 0; i < limit; i++) { 1483 n = fontStructPtr->per_char[i].width; 1484 if (n != 0) { 1485 if (width == 0) { 1486 width = n; 1487 } else if (width != n) { 1488 fixed = 0; 1489 break; 1490 } 1491 } 1492 } 1493 } 1494 1495 fontPtr->font.fid = fontStructPtr->fid; 1496 1497 faPtr = &fontPtr->font.fa; 1498 faPtr->family = fa.fa.family; 1499 faPtr->size = TkFontGetPoints(tkwin, fa.fa.size); 1500 faPtr->weight = fa.fa.weight; 1501 faPtr->slant = fa.fa.slant; 1502 faPtr->underline = 0; 1503 faPtr->overstrike = 0; 1504 1505 fmPtr = &fontPtr->font.fm; 1506 fmPtr->ascent = fontStructPtr->ascent; 1507 fmPtr->descent = fontStructPtr->descent; 1508 fmPtr->maxWidth = fontStructPtr->max_bounds.width; 1509 fmPtr->fixed = fixed; 1510 1511 fontPtr->display = display; 1512 fontPtr->pixelSize = TkFontGetPixels(tkwin, fa.fa.size); 1513 fontPtr->xa = fa.xa; 1514 1515 fontPtr->numSubFonts = 1; 1516 fontPtr->subFontArray = fontPtr->staticSubFonts; 1517 InitSubFont(display, fontStructPtr, 1, &fontPtr->subFontArray[0]); 1518 1519 fontPtr->controlSubFont = fontPtr->subFontArray[0]; 1520 subFontPtr = FindSubFontForChar(fontPtr, '0', NULL); 1521 controlPtr = &fontPtr->controlSubFont; 1522 controlPtr->fontStructPtr = subFontPtr->fontStructPtr; 1523 controlPtr->familyPtr = &tsdPtr->controlFamily; 1524 controlPtr->fontMap = tsdPtr->controlFamily.fontMap; 1525 1526 pageMap = fontPtr->subFontArray[0].fontMap[0]; 1527 for (i = 0; i < 256; i++) { 1528 if ((minHi > 0) || (i < minLo) || (i > maxLo) || 1529 (((pageMap[i >> 3] >> (i & 7)) & 1) == 0)) { 1530 n = 0; 1531 } else if (fontStructPtr->per_char == NULL) { 1532 n = fontStructPtr->max_bounds.width; 1533 } else { 1534 n = fontStructPtr->per_char[i - minLo].width; 1535 } 1536 fontPtr->widths[i] = n; 1537 } 1538 1539 1540 if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) { 1541 fontPtr->underlinePos = value; 1542 } else { 1543 /* 1544 * If the XA_UNDERLINE_POSITION property does not exist, the X 1545 * manual recommends using the following value: 1546 */ 1547 1548 fontPtr->underlinePos = fontStructPtr->descent / 2; 1549 } 1550 fontPtr->barHeight = 0; 1551 if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) { 1552 fontPtr->barHeight = value; 1553 } 1554 if (fontPtr->barHeight == 0) { 1555 /* 1556 * If the XA_UNDERLINE_THICKNESS property does not exist, the X 1557 * manual recommends using the width of the stem on a capital 1558 * letter. I don't know of a way to get the stem width of a letter, 1559 * so guess and use 1/3 the width of a capital I. 1560 */ 1561 1562 fontPtr->barHeight = fontPtr->widths['I'] / 3; 1563 if (fontPtr->barHeight == 0) { 1564 fontPtr->barHeight = 1; 1565 } 1566 } 1567 if (fontPtr->underlinePos + fontPtr->barHeight > fontStructPtr->descent) { 1568 /* 1569 * If this set of cobbled together values would cause the bottom of 1570 * the underline bar to stick below the descent of the font, jack 1571 * the underline up a bit higher. 1572 */ 1573 1574 fontPtr->barHeight = fontStructPtr->descent - fontPtr->underlinePos; 1575 if (fontPtr->barHeight == 0) { 1576 fontPtr->underlinePos--; 1577 fontPtr->barHeight = 1; 1578 } 1579 } 1580} 1581 1582/* 1583 *------------------------------------------------------------------------- 1584 * 1585 * ReleaseFont -- 1586 * 1587 * Called to release the unix-specific contents of a TkFont. 1588 * The caller is responsible for freeing the memory used by the 1589 * font itself. 1590 * 1591 * Results: 1592 * None. 1593 * 1594 * Side effects: 1595 * Memory is freed. 1596 * 1597 *--------------------------------------------------------------------------- 1598 */ 1599 1600static void 1601ReleaseFont(fontPtr) 1602 UnixFont *fontPtr; /* The font to delete. */ 1603{ 1604 int i; 1605 1606 for (i = 0; i < fontPtr->numSubFonts; i++) { 1607 ReleaseSubFont(fontPtr->display, &fontPtr->subFontArray[i]); 1608 } 1609 if (fontPtr->subFontArray != fontPtr->staticSubFonts) { 1610 ckfree((char *) fontPtr->subFontArray); 1611 } 1612} 1613 1614/* 1615 *------------------------------------------------------------------------- 1616 * 1617 * InitSubFont -- 1618 * 1619 * Wrap a screen font and load the FontFamily that represents 1620 * it. Used to prepare a SubFont so that characters can be mapped 1621 * from UTF-8 to the charset of the font. 1622 * 1623 * Results: 1624 * The subFontPtr is filled with information about the font. 1625 * 1626 * Side effects: 1627 * None. 1628 * 1629 *------------------------------------------------------------------------- 1630 */ 1631 1632static void 1633InitSubFont(display, fontStructPtr, base, subFontPtr) 1634 Display *display; /* Display in which font will be used. */ 1635 XFontStruct *fontStructPtr; /* The screen font. */ 1636 int base; /* Non-zero if this SubFont is being used 1637 * as the base font for a font object. */ 1638 SubFont *subFontPtr; /* Filled with SubFont constructed from 1639 * above attributes. */ 1640{ 1641 subFontPtr->fontStructPtr = fontStructPtr; 1642 subFontPtr->familyPtr = AllocFontFamily(display, fontStructPtr, base); 1643 subFontPtr->fontMap = subFontPtr->familyPtr->fontMap; 1644} 1645 1646/* 1647 *------------------------------------------------------------------------- 1648 * 1649 * ReleaseSubFont -- 1650 * 1651 * Called to release the contents of a SubFont. The caller is 1652 * responsible for freeing the memory used by the SubFont itself. 1653 * 1654 * Results: 1655 * None. 1656 * 1657 * Side effects: 1658 * Memory and resources are freed. 1659 * 1660 *--------------------------------------------------------------------------- 1661 */ 1662 1663static void 1664ReleaseSubFont(display, subFontPtr) 1665 Display *display; /* Display which owns screen font. */ 1666 SubFont *subFontPtr; /* The SubFont to delete. */ 1667{ 1668 XFreeFont(display, subFontPtr->fontStructPtr); 1669 FreeFontFamily(subFontPtr->familyPtr); 1670} 1671 1672/* 1673 *------------------------------------------------------------------------- 1674 * 1675 * AllocFontFamily -- 1676 * 1677 * Find the FontFamily structure associated with the given font 1678 * name. The information should be stored by the caller in a 1679 * SubFont and used when determining if that SubFont supports a 1680 * character. 1681 * 1682 * Cannot use the string name used to construct the font as the 1683 * key, because the capitalization may not be canonical. Therefore 1684 * use the face name actually retrieved from the font metrics as 1685 * the key. 1686 * 1687 * Results: 1688 * A pointer to a FontFamily. The reference count in the FontFamily 1689 * is automatically incremented. When the SubFont is released, the 1690 * reference count is decremented. When no SubFont is using this 1691 * FontFamily, it may be deleted. 1692 * 1693 * Side effects: 1694 * A new FontFamily structure will be allocated if this font family 1695 * has not been seen. TrueType character existence metrics are 1696 * loaded into the FontFamily structure. 1697 * 1698 *------------------------------------------------------------------------- 1699 */ 1700 1701static FontFamily * 1702AllocFontFamily(display, fontStructPtr, base) 1703 Display *display; /* Display in which font will be used. */ 1704 XFontStruct *fontStructPtr; /* Screen font whose FontFamily is to be 1705 * returned. */ 1706 int base; /* Non-zero if this font family is to be 1707 * used in the base font of a font object. */ 1708{ 1709 FontFamily *familyPtr; 1710 FontAttributes fa; 1711 Tcl_Encoding encoding; 1712 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1713 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1714 1715 GetFontAttributes(display, fontStructPtr, &fa); 1716 encoding = Tcl_GetEncoding(NULL, GetEncodingAlias(fa.xa.charset)); 1717 1718 familyPtr = tsdPtr->fontFamilyList; 1719 for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) { 1720 if ((familyPtr->faceName == fa.fa.family) 1721 && (familyPtr->foundry == fa.xa.foundry) 1722 && (familyPtr->encoding == encoding)) { 1723 Tcl_FreeEncoding(encoding); 1724 familyPtr->refCount++; 1725 return familyPtr; 1726 } 1727 } 1728 1729 familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily)); 1730 memset(familyPtr, 0, sizeof(FontFamily)); 1731 familyPtr->nextPtr = tsdPtr->fontFamilyList; 1732 tsdPtr->fontFamilyList = familyPtr; 1733 1734 /* 1735 * Set key for this FontFamily. 1736 */ 1737 1738 familyPtr->foundry = fa.xa.foundry; 1739 familyPtr->faceName = fa.fa.family; 1740 familyPtr->encoding = encoding; 1741 1742 /* 1743 * An initial refCount of 2 means that FontFamily information will 1744 * persist even when the SubFont that loaded the FontFamily is released. 1745 * Change it to 1 to cause FontFamilies to be unloaded when not in use. 1746 */ 1747 1748 familyPtr->refCount = 2; 1749 1750 /* 1751 * One byte/character fonts have both min_byte1 and max_byte1 0, 1752 * and max_char_or_byte2 <= 255. 1753 * Anything else specifies a two byte/character font. 1754 */ 1755 1756 familyPtr->isTwoByteFont = !( 1757 (fontStructPtr->min_byte1 == 0) && 1758 (fontStructPtr->max_byte1 == 0) && 1759 (fontStructPtr->max_char_or_byte2 < 256)); 1760 return familyPtr; 1761} 1762 1763/* 1764 *------------------------------------------------------------------------- 1765 * 1766 * FreeFontFamily -- 1767 * 1768 * Called to free an FontFamily when the SubFont is finished using 1769 * it. Frees the contents of the FontFamily and the memory used by 1770 * the FontFamily itself. 1771 * 1772 * Results: 1773 * None. 1774 * 1775 * Side effects: 1776 * None. 1777 * 1778 *------------------------------------------------------------------------- 1779 */ 1780 1781static void 1782FreeFontFamily(familyPtr) 1783 FontFamily *familyPtr; /* The FontFamily to delete. */ 1784{ 1785 FontFamily **familyPtrPtr; 1786 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1787 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1788 int i; 1789 1790 if (familyPtr == NULL) { 1791 return; 1792 } 1793 familyPtr->refCount--; 1794 if (familyPtr->refCount > 0) { 1795 return; 1796 } 1797 Tcl_FreeEncoding(familyPtr->encoding); 1798 for (i = 0; i < FONTMAP_PAGES; i++) { 1799 if (familyPtr->fontMap[i] != NULL) { 1800 ckfree(familyPtr->fontMap[i]); 1801 } 1802 } 1803 1804 /* 1805 * Delete from list. 1806 */ 1807 1808 for (familyPtrPtr = &tsdPtr->fontFamilyList; ; ) { 1809 if (*familyPtrPtr == familyPtr) { 1810 *familyPtrPtr = familyPtr->nextPtr; 1811 break; 1812 } 1813 familyPtrPtr = &(*familyPtrPtr)->nextPtr; 1814 } 1815 1816 ckfree((char *) familyPtr); 1817} 1818 1819/* 1820 *------------------------------------------------------------------------- 1821 * 1822 * FindSubFontForChar -- 1823 * 1824 * Determine which screen font is necessary to use to 1825 * display the given character. If the font object does not have 1826 * a screen font that can display the character, another screen font 1827 * may be loaded into the font object, following a set of preferred 1828 * fallback rules. 1829 * 1830 * Results: 1831 * The return value is the SubFont to use to display the given 1832 * character. 1833 * 1834 * Side effects: 1835 * The contents of fontPtr are modified to cache the results 1836 * of the lookup and remember any SubFonts that were dynamically 1837 * loaded. The table of SubFonts might be extended, and if a non-NULL 1838 * reference to a subfont pointer is available, it is updated if it 1839 * previously pointed into the old subfont table. 1840 * 1841 *------------------------------------------------------------------------- 1842 */ 1843 1844static SubFont * 1845FindSubFontForChar(fontPtr, ch, fixSubFontPtrPtr) 1846 UnixFont *fontPtr; /* The font object with which the character 1847 * will be displayed. */ 1848 int ch; /* The Unicode character to be displayed. */ 1849 SubFont **fixSubFontPtrPtr; /* Subfont reference to fix up if we 1850 * reallocate our subfont table. */ 1851{ 1852 int i, j, k, numNames; 1853 Tk_Uid faceName; 1854 char *fallback; 1855 char **aliases, **nameList, **anyFallbacks; 1856 char ***fontFallbacks; 1857 SubFont *subFontPtr; 1858 Tcl_DString ds; 1859 1860 if (FontMapLookup(&fontPtr->subFontArray[0], ch)) { 1861 return &fontPtr->subFontArray[0]; 1862 } 1863 1864 for (i = 1; i < fontPtr->numSubFonts; i++) { 1865 if (FontMapLookup(&fontPtr->subFontArray[i], ch)) { 1866 return &fontPtr->subFontArray[i]; 1867 } 1868 } 1869 1870 if (FontMapLookup(&fontPtr->controlSubFont, ch)) { 1871 return &fontPtr->controlSubFont; 1872 } 1873 1874 /* 1875 * Keep track of all face names that we check, so we don't check some 1876 * name multiple times if it can be reached by multiple paths. 1877 */ 1878 1879 Tcl_DStringInit(&ds); 1880 1881 /* 1882 * Are there any other fonts with the same face name as the base 1883 * font that could display this character, e.g., if the base font 1884 * is adobe:fixed:iso8859-1, we could might be able to use 1885 * misc:fixed:iso8859-8 or sony:fixed:jisx0208.1983-0 1886 */ 1887 1888 faceName = fontPtr->font.fa.family; 1889 if (SeenName(faceName, &ds) == 0) { 1890 subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr); 1891 if (subFontPtr != NULL) { 1892 goto end; 1893 } 1894 } 1895 1896 aliases = TkFontGetAliasList(faceName); 1897 1898 subFontPtr = NULL; 1899 fontFallbacks = TkFontGetFallbacks(); 1900 for (i = 0; fontFallbacks[i] != NULL; i++) { 1901 for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { 1902 if (strcasecmp(fallback, faceName) == 0) { 1903 /* 1904 * If the base font has a fallback... 1905 */ 1906 1907 goto tryfallbacks; 1908 } else if (aliases != NULL) { 1909 /* 1910 * Or if an alias for the base font has a fallback... 1911 */ 1912 1913 for (k = 0; aliases[k] != NULL; k++) { 1914 if (strcasecmp(fallback, aliases[k]) == 0) { 1915 goto tryfallbacks; 1916 } 1917 } 1918 } 1919 } 1920 continue; 1921 1922 tryfallbacks: 1923 1924 /* 1925 * ...then see if we can use one of the fallbacks, or an 1926 * alias for one of the fallbacks. 1927 */ 1928 1929 for (j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) { 1930 subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds, 1931 fixSubFontPtrPtr); 1932 if (subFontPtr != NULL) { 1933 goto end; 1934 } 1935 } 1936 } 1937 1938 /* 1939 * See if we can use something from the global fallback list. 1940 */ 1941 1942 anyFallbacks = TkFontGetGlobalClass(); 1943 for (i = 0; (fallback = anyFallbacks[i]) != NULL; i++) { 1944 subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds, 1945 fixSubFontPtrPtr); 1946 if (subFontPtr != NULL) { 1947 goto end; 1948 } 1949 } 1950 1951 /* 1952 * Try all face names available in the whole system until we 1953 * find one that can be used. 1954 */ 1955 1956 nameList = ListFonts(fontPtr->display, "*", &numNames); 1957 for (i = 0; i < numNames; i++) { 1958 fallback = strchr(nameList[i] + 1, '-') + 1; 1959 strchr(fallback, '-')[0] = '\0'; 1960 if (SeenName(fallback, &ds) == 0) { 1961 subFontPtr = CanUseFallback(fontPtr, fallback, ch, 1962 fixSubFontPtrPtr); 1963 if (subFontPtr != NULL) { 1964 XFreeFontNames(nameList); 1965 goto end; 1966 } 1967 } 1968 } 1969 XFreeFontNames(nameList); 1970 1971 end: 1972 Tcl_DStringFree(&ds); 1973 1974 if (subFontPtr == NULL) { 1975 /* 1976 * No font can display this character, so it will be displayed as a 1977 * control character expansion. 1978 */ 1979 1980 subFontPtr = &fontPtr->controlSubFont; 1981 FontMapInsert(subFontPtr, ch); 1982 } 1983 return subFontPtr; 1984} 1985 1986/* 1987 *------------------------------------------------------------------------- 1988 * 1989 * FontMapLookup -- 1990 * 1991 * See if the screen font can display the given character. 1992 * 1993 * Results: 1994 * The return value is 0 if the screen font cannot display the 1995 * character, non-zero otherwise. 1996 * 1997 * Side effects: 1998 * New pages are added to the font mapping cache whenever the 1999 * character belongs to a page that hasn't been seen before. 2000 * When a page is loaded, information about all the characters on 2001 * that page is stored, not just for the single character in 2002 * question. 2003 * 2004 *------------------------------------------------------------------------- 2005 */ 2006 2007static int 2008FontMapLookup(subFontPtr, ch) 2009 SubFont *subFontPtr; /* Contains font mapping cache to be queried 2010 * and possibly updated. */ 2011 int ch; /* Character to be tested. */ 2012{ 2013 int row, bitOffset; 2014 2015 row = ch >> FONTMAP_SHIFT; 2016 if (subFontPtr->fontMap[row] == NULL) { 2017 FontMapLoadPage(subFontPtr, row); 2018 } 2019 bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); 2020 return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1; 2021} 2022 2023/* 2024 *------------------------------------------------------------------------- 2025 * 2026 * FontMapInsert -- 2027 * 2028 * Tell the font mapping cache that the given screen font should be 2029 * used to display the specified character. This is called when no 2030 * font on the system can be be found that can display that 2031 * character; we lie to the font and tell it that it can display 2032 * the character, otherwise we would end up re-searching the entire 2033 * fallback hierarchy every time that character was seen. 2034 * 2035 * Results: 2036 * None. 2037 * 2038 * Side effects: 2039 * New pages are added to the font mapping cache whenever the 2040 * character belongs to a page that hasn't been seen before. 2041 * When a page is loaded, information about all the characters on 2042 * that page is stored, not just for the single character in 2043 * question. 2044 * 2045 *------------------------------------------------------------------------- 2046 */ 2047 2048static void 2049FontMapInsert(subFontPtr, ch) 2050 SubFont *subFontPtr; /* Contains font mapping cache to be 2051 * updated. */ 2052 int ch; /* Character to be added to cache. */ 2053{ 2054 int row, bitOffset; 2055 2056 row = ch >> FONTMAP_SHIFT; 2057 if (subFontPtr->fontMap[row] == NULL) { 2058 FontMapLoadPage(subFontPtr, row); 2059 } 2060 bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); 2061 subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); 2062} 2063 2064/* 2065 *------------------------------------------------------------------------- 2066 * 2067 * FontMapLoadPage -- 2068 * 2069 * Load information about all the characters on a given page. 2070 * This information consists of one bit per character that indicates 2071 * whether the associated screen font can (1) or cannot (0) display 2072 * the characters on the page. 2073 * 2074 * Results: 2075 * None. 2076 * 2077 * Side effects: 2078 * Mempry allocated. 2079 * 2080 *------------------------------------------------------------------------- 2081 */ 2082static void 2083FontMapLoadPage(subFontPtr, row) 2084 SubFont *subFontPtr; /* Contains font mapping cache to be 2085 * updated. */ 2086 int row; /* Index of the page to be loaded into 2087 * the cache. */ 2088{ 2089 char buf[16], src[TCL_UTF_MAX]; 2090 int minHi, maxHi, minLo, maxLo, scale, checkLo; 2091 int i, end, bitOffset, isTwoByteFont, n; 2092 Tcl_Encoding encoding; 2093 XFontStruct *fontStructPtr; 2094 XCharStruct *widths; 2095 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 2096 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 2097 2098 subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8); 2099 memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8); 2100 2101 if (subFontPtr->familyPtr == &tsdPtr->controlFamily) { 2102 return; 2103 } 2104 2105 fontStructPtr = subFontPtr->fontStructPtr; 2106 encoding = subFontPtr->familyPtr->encoding; 2107 isTwoByteFont = subFontPtr->familyPtr->isTwoByteFont; 2108 2109 widths = fontStructPtr->per_char; 2110 minHi = fontStructPtr->min_byte1; 2111 maxHi = fontStructPtr->max_byte1; 2112 minLo = fontStructPtr->min_char_or_byte2; 2113 maxLo = fontStructPtr->max_char_or_byte2; 2114 scale = maxLo - minLo + 1; 2115 checkLo = minLo; 2116 2117 if (! isTwoByteFont) { 2118 if (minLo < 32) { 2119 checkLo = 32; 2120 } 2121 } 2122 2123 end = (row + 1) << FONTMAP_SHIFT; 2124 for (i = row << FONTMAP_SHIFT; i < end; i++) { 2125 int hi, lo; 2126 2127 if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i, src), 2128 TCL_ENCODING_STOPONERROR, NULL, buf, sizeof(buf), NULL, 2129 NULL, NULL) != TCL_OK) { 2130 continue; 2131 } 2132 if (isTwoByteFont) { 2133 hi = ((unsigned char *) buf)[0]; 2134 lo = ((unsigned char *) buf)[1]; 2135 } else { 2136 hi = 0; 2137 lo = ((unsigned char *) buf)[0]; 2138 } 2139 if ((hi < minHi) || (hi > maxHi) || (lo < checkLo) || (lo > maxLo)) { 2140 continue; 2141 } 2142 n = (hi - minHi) * scale + lo - minLo; 2143 if ((widths == NULL) || ((widths[n].width + widths[n].rbearing) != 0)) { 2144 bitOffset = i & (FONTMAP_BITSPERPAGE - 1); 2145 subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); 2146 } 2147 } 2148} 2149 2150/* 2151 *--------------------------------------------------------------------------- 2152 * 2153 * CanUseFallbackWithAliases -- 2154 * 2155 * Helper function for FindSubFontForChar. Determine if the 2156 * specified face name (or an alias of the specified face name) 2157 * can be used to construct a screen font that can display the 2158 * given character. 2159 * 2160 * Results: 2161 * See CanUseFallback(). 2162 * 2163 * Side effects: 2164 * If the name and/or one of its aliases was rejected, the 2165 * rejected string is recorded in nameTriedPtr so that it won't 2166 * be tried again. The table of SubFonts might be extended, and if 2167 * a non-NULL reference to a subfont pointer is available, it is 2168 * updated if it previously pointed into the old subfont table. 2169 * 2170 *--------------------------------------------------------------------------- 2171 */ 2172 2173static SubFont * 2174CanUseFallbackWithAliases(fontPtr, faceName, ch, nameTriedPtr, 2175 fixSubFontPtrPtr) 2176 UnixFont *fontPtr; /* The font object that will own the new 2177 * screen font. */ 2178 char *faceName; /* Desired face name for new screen font. */ 2179 int ch; /* The Unicode character that the new 2180 * screen font must be able to display. */ 2181 Tcl_DString *nameTriedPtr; /* Records face names that have already 2182 * been tried. It is possible for the same 2183 * face name to be queried multiple times when 2184 * trying to find a suitable screen font. */ 2185 SubFont **fixSubFontPtrPtr; /* Subfont reference to fix up if we 2186 * reallocate our subfont table. */ 2187{ 2188 SubFont *subFontPtr; 2189 char **aliases; 2190 int i; 2191 2192 if (SeenName(faceName, nameTriedPtr) == 0) { 2193 subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr); 2194 if (subFontPtr != NULL) { 2195 return subFontPtr; 2196 } 2197 } 2198 aliases = TkFontGetAliasList(faceName); 2199 if (aliases != NULL) { 2200 for (i = 0; aliases[i] != NULL; i++) { 2201 if (SeenName(aliases[i], nameTriedPtr) == 0) { 2202 subFontPtr = CanUseFallback(fontPtr, aliases[i], ch, 2203 fixSubFontPtrPtr); 2204 if (subFontPtr != NULL) { 2205 return subFontPtr; 2206 } 2207 } 2208 } 2209 } 2210 return NULL; 2211} 2212 2213/* 2214 *--------------------------------------------------------------------------- 2215 * 2216 * SeenName -- 2217 * 2218 * Used to determine we have already tried and rejected the given 2219 * face name when looking for a screen font that can support some 2220 * Unicode character. 2221 * 2222 * Results: 2223 * The return value is 0 if this face name has not already been seen, 2224 * non-zero otherwise. 2225 * 2226 * Side effects: 2227 * None. 2228 * 2229 *--------------------------------------------------------------------------- 2230 */ 2231 2232static int 2233SeenName(name, dsPtr) 2234 CONST char *name; /* The name to check. */ 2235 Tcl_DString *dsPtr; /* Contains names that have already been 2236 * seen. */ 2237{ 2238 CONST char *seen, *end; 2239 2240 seen = Tcl_DStringValue(dsPtr); 2241 end = seen + Tcl_DStringLength(dsPtr); 2242 while (seen < end) { 2243 if (strcasecmp(seen, name) == 0) { 2244 return 1; 2245 } 2246 seen += strlen(seen) + 1; 2247 } 2248 Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1)); 2249 return 0; 2250} 2251 2252/* 2253 *------------------------------------------------------------------------- 2254 * 2255 * CanUseFallback -- 2256 * 2257 * If the specified screen font has not already been loaded 2258 * into the font object, determine if the specified screen 2259 * font can display the given character. 2260 * 2261 * Results: 2262 * The return value is a pointer to a newly allocated SubFont, 2263 * owned by the font object. This SubFont can be used to display 2264 * the given character. The SubFont represents the screen font 2265 * with the base set of font attributes from the font object, but 2266 * using the specified face name. NULL is returned if the font 2267 * object already holds a reference to the specified font or if 2268 * the specified font doesn't exist or cannot display the given 2269 * character. 2270 * 2271 * Side effects: 2272 * The font object's subFontArray is updated to contain a reference 2273 * to the newly allocated SubFont. The table of SubFonts might be 2274 * extended, and if a non-NULL reference to a subfont pointer is 2275 * available, it is updated if it previously pointed into the old 2276 * subfont table. 2277 * 2278 *------------------------------------------------------------------------- 2279 */ 2280 2281static SubFont * 2282CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr) 2283 UnixFont *fontPtr; /* The font object that will own the new 2284 * screen font. */ 2285 CONST char *faceName; /* Desired face name for new screen font. */ 2286 int ch; /* The Unicode character that the new 2287 * screen font must be able to display. */ 2288 SubFont **fixSubFontPtrPtr; /* Subfont reference to fix up if we 2289 * reallocate our subfont table. */ 2290{ 2291 int i, nameIdx, numNames, srcLen; 2292 Tk_Uid hateFoundry; 2293 int bestIdx[2]; 2294 CONST char *charset, *hateCharset; 2295 unsigned int bestScore[2]; 2296 char **nameList, **nameListOrig; 2297 FontAttributes want, got; 2298 char src[TCL_UTF_MAX]; 2299 Display *display; 2300 SubFont subFont; 2301 XFontStruct *fontStructPtr; 2302 Tcl_DString dsEncodings; 2303 int numEncodings; 2304 Tcl_Encoding *encodingCachePtr; 2305 2306 /* 2307 * Assume: the face name is times. 2308 * Assume: adobe:times:iso8859-1 has already been used. 2309 * 2310 * Are there any versions of times that can display this 2311 * character (e.g., perhaps linotype:times:iso8859-2)? 2312 * a. Get list of all times fonts. 2313 * b1. Cross out all names whose encodings we've already used. 2314 * b2. Cross out all names whose foundry & encoding we've already seen. 2315 * c. Cross out all names whose encoding cannot handle the character. 2316 * d. Rank each name and pick the best match. 2317 * e. If that font cannot actually display the character, cross 2318 * out all names with the same foundry and encoding and go 2319 * back to (c). 2320 */ 2321 2322 display = fontPtr->display; 2323 nameList = ListFonts(display, faceName, &numNames); 2324 if (numNames == 0) { 2325 return NULL; 2326 } 2327 nameListOrig = nameList; 2328 2329 srcLen = Tcl_UniCharToUtf(ch, src); 2330 2331 want.fa = fontPtr->font.fa; 2332 want.xa = fontPtr->xa; 2333 2334 want.fa.family = Tk_GetUid(faceName); 2335 want.fa.size = -fontPtr->pixelSize; 2336 2337 hateFoundry = NULL; 2338 hateCharset = NULL; 2339 numEncodings = 0; 2340 Tcl_DStringInit(&dsEncodings); 2341 2342 charset = NULL; /* lint, since numNames must be > 0 to get here. */ 2343 2344 retry: 2345 bestIdx[0] = -1; 2346 bestIdx[1] = -1; 2347 bestScore[0] = (unsigned int) -1; 2348 bestScore[1] = (unsigned int) -1; 2349 for (nameIdx = 0; nameIdx < numNames; nameIdx++) { 2350 Tcl_Encoding encoding; 2351 char dst[16]; 2352 int scalable, srcRead, dstWrote; 2353 unsigned int score; 2354 2355 if (nameList[nameIdx] == NULL) { 2356 continue; 2357 } 2358 if (TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) { 2359 goto crossout; 2360 } 2361 IdentifySymbolEncodings(&got); 2362 charset = GetEncodingAlias(got.xa.charset); 2363 if (hateFoundry != NULL) { 2364 /* 2365 * E. If the font we picked cannot actually display the 2366 * character, cross out all names with the same foundry and 2367 * encoding. 2368 */ 2369 2370 if ((hateFoundry == got.xa.foundry) 2371 && (strcmp(hateCharset, charset) == 0)) { 2372 goto crossout; 2373 } 2374 } else { 2375 /* 2376 * B. Cross out all names whose encodings we've already used. 2377 */ 2378 2379 for (i = 0; i < fontPtr->numSubFonts; i++) { 2380 encoding = fontPtr->subFontArray[i].familyPtr->encoding; 2381 if (strcmp(charset, Tcl_GetEncodingName(encoding)) == 0) { 2382 goto crossout; 2383 } 2384 } 2385 } 2386 2387 /* 2388 * C. Cross out all names whose encoding cannot handle the character. 2389 */ 2390 2391 encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings); 2392 for (i = numEncodings; --i >= 0; encodingCachePtr++) { 2393 encoding = *encodingCachePtr; 2394 if (strcmp(Tcl_GetEncodingName(encoding), charset) == 0) { 2395 break; 2396 } 2397 } 2398 if (i < 0) { 2399 encoding = Tcl_GetEncoding(NULL, charset); 2400 if (encoding == NULL) { 2401 goto crossout; 2402 } 2403 2404 Tcl_DStringAppend(&dsEncodings, (char *) &encoding, 2405 sizeof(encoding)); 2406 numEncodings++; 2407 } 2408 Tcl_UtfToExternal(NULL, encoding, src, srcLen, 2409 TCL_ENCODING_STOPONERROR, NULL, dst, sizeof(dst), &srcRead, 2410 &dstWrote, NULL); 2411 if (dstWrote == 0) { 2412 goto crossout; 2413 } 2414 2415 /* 2416 * D. Rank each name and pick the best match. 2417 */ 2418 2419 scalable = (got.fa.size == 0); 2420 score = RankAttributes(&want, &got); 2421 if (score < bestScore[scalable]) { 2422 bestIdx[scalable] = nameIdx; 2423 bestScore[scalable] = score; 2424 } 2425 if (score == 0) { 2426 break; 2427 } 2428 continue; 2429 2430 crossout: 2431 if (nameList == nameListOrig) { 2432 /* 2433 * Not allowed to change pointers to memory that X gives you, 2434 * so make a copy. 2435 */ 2436 2437 nameList = (char **) ckalloc(numNames * sizeof(char *)); 2438 memcpy(nameList, nameListOrig, numNames * sizeof(char *)); 2439 } 2440 nameList[nameIdx] = NULL; 2441 } 2442 2443 fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx, bestScore); 2444 2445 encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings); 2446 for (i = numEncodings; --i >= 0; encodingCachePtr++) { 2447 Tcl_FreeEncoding(*encodingCachePtr); 2448 } 2449 Tcl_DStringFree(&dsEncodings); 2450 numEncodings = 0; 2451 2452 if (fontStructPtr == NULL) { 2453 if (nameList != nameListOrig) { 2454 ckfree((char *) nameList); 2455 } 2456 XFreeFontNames(nameListOrig); 2457 return NULL; 2458 } 2459 2460 InitSubFont(display, fontStructPtr, 0, &subFont); 2461 if (FontMapLookup(&subFont, ch) == 0) { 2462 /* 2463 * E. If the font we picked cannot actually display the character, 2464 * cross out all names with the same foundry and encoding and pick 2465 * another font. 2466 */ 2467 2468 hateFoundry = got.xa.foundry; 2469 hateCharset = charset; 2470 ReleaseSubFont(display, &subFont); 2471 goto retry; 2472 } 2473 if (nameList != nameListOrig) { 2474 ckfree((char *) nameList); 2475 } 2476 XFreeFontNames(nameListOrig); 2477 2478 if (fontPtr->numSubFonts >= SUBFONT_SPACE) { 2479 SubFont *newPtr; 2480 2481 newPtr = (SubFont *) ckalloc(sizeof(SubFont) * (fontPtr->numSubFonts + 1)); 2482 memcpy((char *) newPtr, fontPtr->subFontArray, 2483 fontPtr->numSubFonts * sizeof(SubFont)); 2484 if (fixSubFontPtrPtr != NULL) { 2485 register SubFont *fixSubFontPtr = *fixSubFontPtrPtr; 2486 2487 if (fixSubFontPtr != &fontPtr->controlSubFont) { 2488 *fixSubFontPtrPtr = 2489 newPtr + (fixSubFontPtr - fontPtr->subFontArray); 2490 } 2491 } 2492 if (fontPtr->subFontArray != fontPtr->staticSubFonts) { 2493 ckfree((char *) fontPtr->subFontArray); 2494 } 2495 fontPtr->subFontArray = newPtr; 2496 } 2497 fontPtr->subFontArray[fontPtr->numSubFonts] = subFont; 2498 fontPtr->numSubFonts++; 2499 return &fontPtr->subFontArray[fontPtr->numSubFonts - 1]; 2500} 2501 2502/* 2503 *--------------------------------------------------------------------------- 2504 * 2505 * RankAttributes -- 2506 * 2507 * Determine how close the attributes of the font in question match 2508 * the attributes that we want. 2509 * 2510 * Results: 2511 * The return value is the score; lower numbers are better. 2512 * *scalablePtr is set to 0 if the font was not scalable, 1 otherwise. 2513 * 2514 * Side effects: 2515 * None. 2516 * 2517 *--------------------------------------------------------------------------- 2518 */ 2519 2520static unsigned int 2521RankAttributes(wantPtr, gotPtr) 2522 FontAttributes *wantPtr; /* The desired attributes. */ 2523 FontAttributes *gotPtr; /* The attributes we have to live with. */ 2524{ 2525 unsigned int penalty; 2526 2527 penalty = 0; 2528 if (gotPtr->xa.foundry != wantPtr->xa.foundry) { 2529 penalty += 4500; 2530 } 2531 if (gotPtr->fa.family != wantPtr->fa.family) { 2532 penalty += 9000; 2533 } 2534 if (gotPtr->fa.weight != wantPtr->fa.weight) { 2535 penalty += 90; 2536 } 2537 if (gotPtr->fa.slant != wantPtr->fa.slant) { 2538 penalty += 60; 2539 } 2540 if (gotPtr->xa.slant != wantPtr->xa.slant) { 2541 penalty += 10; 2542 } 2543 if (gotPtr->xa.setwidth != wantPtr->xa.setwidth) { 2544 penalty += 1000; 2545 } 2546 2547 if (gotPtr->fa.size == 0) { 2548 /* 2549 * A scalable font is almost always acceptable, but the 2550 * corresponding bitmapped font would be better. 2551 */ 2552 2553 penalty += 10; 2554 } else { 2555 int diff; 2556 2557 /* 2558 * It's worse to be too large than to be too small. 2559 */ 2560 2561 diff = (-gotPtr->fa.size - -wantPtr->fa.size); 2562 if (diff > 0) { 2563 penalty += 600; 2564 } else if (diff < 0) { 2565 penalty += 150; 2566 diff = -diff; 2567 } 2568 penalty += 150 * diff; 2569 } 2570 if (gotPtr->xa.charset != wantPtr->xa.charset) { 2571 int i; 2572 CONST char *gotAlias, *wantAlias; 2573 2574 penalty += 65000; 2575 gotAlias = GetEncodingAlias(gotPtr->xa.charset); 2576 wantAlias = GetEncodingAlias(wantPtr->xa.charset); 2577 if (strcmp(gotAlias, wantAlias) != 0) { 2578 penalty += 30000; 2579 for (i = 0; encodingList[i] != NULL; i++) { 2580 if (strcmp(gotAlias, encodingList[i]) == 0) { 2581 penalty -= 30000; 2582 break; 2583 } 2584 penalty += 20000; 2585 } 2586 } 2587 } 2588 return penalty; 2589} 2590 2591/* 2592 *--------------------------------------------------------------------------- 2593 * 2594 * GetScreenFont -- 2595 * 2596 * Given the names for the best scalable and best bitmapped font, 2597 * actually construct an XFontStruct based on the best XLFD. 2598 * This is where all the alias and fallback substitution bottoms 2599 * out. 2600 * 2601 * Results: 2602 * The screen font that best corresponds to the set of attributes. 2603 * 2604 * Side effects: 2605 * None. 2606 * 2607 *--------------------------------------------------------------------------- 2608 */ 2609 2610static XFontStruct * 2611GetScreenFont(display, wantPtr, nameList, bestIdx, bestScore) 2612 Display *display; /* Display for new XFontStruct. */ 2613 FontAttributes *wantPtr; /* Contains desired actual pixel-size if the 2614 * best font was scalable. */ 2615 char **nameList; /* Array of XLFDs. */ 2616 int bestIdx[2]; /* Indices into above array for XLFD of 2617 * best bitmapped and best scalable font. */ 2618 unsigned int bestScore[2]; /* Scores of best bitmapped and best 2619 * scalable font. XLFD corresponding to 2620 * lowest score will be constructed. */ 2621{ 2622 XFontStruct *fontStructPtr; 2623 2624 if ((bestIdx[0] < 0) && (bestIdx[1] < 0)) { 2625 return NULL; 2626 } 2627 2628 /* 2629 * Now we know which is the closest matching scalable font and the 2630 * closest matching bitmapped font. If the scalable font was a 2631 * better match, try getting the scalable font; however, if the 2632 * scalable font was not actually available in the desired 2633 * pointsize, fall back to the closest bitmapped font. 2634 */ 2635 2636 fontStructPtr = NULL; 2637 if (bestScore[1] < bestScore[0]) { 2638 char *str, *rest; 2639 char buf[256]; 2640 int i; 2641 2642 /* 2643 * Fill in the desired pixel size for this font. 2644 */ 2645 2646 tryscale: 2647 str = nameList[bestIdx[1]]; 2648 for (i = 0; i < XLFD_PIXEL_SIZE; i++) { 2649 str = strchr(str + 1, '-'); 2650 } 2651 rest = str; 2652 for (i = XLFD_PIXEL_SIZE; i < XLFD_CHARSET; i++) { 2653 rest = strchr(rest + 1, '-'); 2654 } 2655 *str = '\0'; 2656 sprintf(buf, "%.200s-%d-*-*-*-*-*%s", nameList[bestIdx[1]], 2657 -wantPtr->fa.size, rest); 2658 *str = '-'; 2659 fontStructPtr = XLoadQueryFont(display, buf); 2660 bestScore[1] = INT_MAX; 2661 } 2662 if (fontStructPtr == NULL) { 2663 fontStructPtr = XLoadQueryFont(display, nameList[bestIdx[0]]); 2664 if (fontStructPtr == NULL) { 2665 /* 2666 * This shouldn't happen because the font name is one of the 2667 * names that X gave us to use, but it does anyhow. 2668 */ 2669 2670 if (bestScore[1] < INT_MAX) { 2671 goto tryscale; 2672 } 2673 return GetSystemFont(display); 2674 } 2675 } 2676 return fontStructPtr; 2677} 2678 2679/* 2680 *--------------------------------------------------------------------------- 2681 * 2682 * GetSystemFont -- 2683 * 2684 * Absolute fallback mechanism, called when we need a font and no 2685 * other font can be found and/or instantiated. 2686 * 2687 * Results: 2688 * A pointer to a font. Never NULL. 2689 * 2690 * Side effects: 2691 * If there are NO fonts installed on the system, this call will 2692 * panic, but how did you get X running in that case? 2693 * 2694 *--------------------------------------------------------------------------- 2695 */ 2696 2697static XFontStruct * 2698GetSystemFont(display) 2699 Display *display; /* Display for new XFontStruct. */ 2700{ 2701 XFontStruct *fontStructPtr; 2702 2703 fontStructPtr = XLoadQueryFont(display, "fixed"); 2704 if (fontStructPtr == NULL) { 2705 fontStructPtr = XLoadQueryFont(display, "*"); 2706 if (fontStructPtr == NULL) { 2707 panic("TkpGetFontFromAttributes: cannot get any font"); 2708 } 2709 } 2710 return fontStructPtr; 2711} 2712 2713/* 2714 *--------------------------------------------------------------------------- 2715 * 2716 * GetFontAttributes -- 2717 * 2718 * Given a screen font, determine its actual attributes, which are 2719 * not necessarily the attributes that were used to construct it. 2720 * 2721 * Results: 2722 * *faPtr is filled with the screen font's attributes. 2723 * 2724 * Side effects: 2725 * None. 2726 * 2727 *--------------------------------------------------------------------------- 2728 */ 2729 2730static int 2731GetFontAttributes(display, fontStructPtr, faPtr) 2732 Display *display; /* Display that owns the screen font. */ 2733 XFontStruct *fontStructPtr; /* Screen font to query. */ 2734 FontAttributes *faPtr; /* For storing attributes of screen font. */ 2735{ 2736 unsigned long value; 2737 char *name; 2738 2739 if ((XGetFontProperty(fontStructPtr, XA_FONT, &value) != False) && 2740 (value != 0)) { 2741 name = XGetAtomName(display, (Atom) value); 2742 if (TkFontParseXLFD(name, &faPtr->fa, &faPtr->xa) != TCL_OK) { 2743 faPtr->fa.family = Tk_GetUid(name); 2744 faPtr->xa.foundry = Tk_GetUid(""); 2745 faPtr->xa.charset = Tk_GetUid(""); 2746 } 2747 XFree(name); 2748 } else { 2749 TkInitFontAttributes(&faPtr->fa); 2750 TkInitXLFDAttributes(&faPtr->xa); 2751 } 2752 /* 2753 * Do last ditch check for family. It seems that some X servers can 2754 * fail on the X font calls above, slipping through earlier checks. 2755 * X-Win32 5.4 is one of these. 2756 */ 2757 if (faPtr->fa.family == NULL) { 2758 faPtr->fa.family = Tk_GetUid(""); 2759 faPtr->xa.foundry = Tk_GetUid(""); 2760 faPtr->xa.charset = Tk_GetUid(""); 2761 } 2762 return IdentifySymbolEncodings(faPtr); 2763} 2764 2765/* 2766 *--------------------------------------------------------------------------- 2767 * 2768 * ListFonts -- 2769 * 2770 * Utility function to return the array of all XLFDs on the system 2771 * with the specified face name. 2772 * 2773 * Results: 2774 * The return value is an array of XLFDs, which should be freed with 2775 * XFreeFontNames(), or NULL if no XLFDs matched the requested name. 2776 * 2777 * Side effects: 2778 * None. 2779 * 2780 *--------------------------------------------------------------------------- 2781 */ 2782 2783static char ** 2784ListFonts(display, faceName, numNamesPtr) 2785 Display *display; /* Display to query. */ 2786 CONST char *faceName; /* Desired face name, or "*" for all. */ 2787 int *numNamesPtr; /* Filled with length of returned array, or 2788 * 0 if no names were found. */ 2789{ 2790 char buf[256]; 2791 2792 sprintf(buf, "-*-%.80s-*-*-*-*-*-*-*-*-*-*-*-*", faceName); 2793 return XListFonts(display, buf, 10000, numNamesPtr); 2794} 2795 2796static char ** 2797ListFontOrAlias(display, faceName, numNamesPtr) 2798 Display *display; /* Display to query. */ 2799 CONST char *faceName; /* Desired face name, or "*" for all. */ 2800 int *numNamesPtr; /* Filled with length of returned array, or 2801 * 0 if no names were found. */ 2802{ 2803 char **nameList, **aliases; 2804 int i; 2805 2806 nameList = ListFonts(display, faceName, numNamesPtr); 2807 if (nameList != NULL) { 2808 return nameList; 2809 } 2810 aliases = TkFontGetAliasList(faceName); 2811 if (aliases != NULL) { 2812 for (i = 0; aliases[i] != NULL; i++) { 2813 nameList = ListFonts(display, aliases[i], numNamesPtr); 2814 if (nameList != NULL) { 2815 return nameList; 2816 } 2817 } 2818 } 2819 *numNamesPtr = 0; 2820 return NULL; 2821} 2822 2823/* 2824 *--------------------------------------------------------------------------- 2825 * 2826 * IdentifySymbolEncodings -- 2827 * 2828 * If the font attributes refer to a symbol font, update the 2829 * charset field of the font attributes so that it reflects the 2830 * encoding of that symbol font. In general, the raw value for 2831 * the charset field parsed from an XLFD is meaningless for symbol 2832 * fonts. 2833 * 2834 * Symbol fonts are all fonts whose name appears in the symbolClass. 2835 * 2836 * Results: 2837 * The return value is non-zero if the font attributes specify a 2838 * symbol font, or 0 otherwise. If a non-zero value is returned 2839 * the charset field of the font attributes will be changed to 2840 * the string that represents the actual encoding for the symbol font. 2841 * 2842 * Side effects: 2843 * None. 2844 * 2845 *--------------------------------------------------------------------------- 2846 */ 2847 2848static int 2849IdentifySymbolEncodings(faPtr) 2850 FontAttributes *faPtr; 2851{ 2852 int i, j; 2853 char **aliases, **symbolClass; 2854 2855 symbolClass = TkFontGetSymbolClass(); 2856 for (i = 0; symbolClass[i] != NULL; i++) { 2857 if (strcasecmp(faPtr->fa.family, symbolClass[i]) == 0) { 2858 faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(symbolClass[i])); 2859 return 1; 2860 } 2861 aliases = TkFontGetAliasList(symbolClass[i]); 2862 for (j = 0; (aliases != NULL) && (aliases[j] != NULL); j++) { 2863 if (strcasecmp(faPtr->fa.family, aliases[j]) == 0) { 2864 faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(aliases[j])); 2865 return 1; 2866 } 2867 } 2868 } 2869 return 0; 2870} 2871 2872/* 2873 *--------------------------------------------------------------------------- 2874 * 2875 * GetEncodingAlias -- 2876 * 2877 * Map the name of an encoding to another name that should be used 2878 * when actually loading the encoding. For instance, the encodings 2879 * "jisc6226.1978", "jisx0208.1983", "jisx0208.1990", and 2880 * "jisx0208.1996" are well-known names for the same encoding and 2881 * are represented by one encoding table: "jis0208". 2882 * 2883 * Results: 2884 * As above. If the name has no alias, the original name is returned. 2885 * 2886 * Side effects: 2887 * None. 2888 * 2889 *--------------------------------------------------------------------------- 2890 */ 2891 2892static CONST char * 2893GetEncodingAlias(name) 2894 CONST char *name; /* The name to look up. */ 2895{ 2896 EncodingAlias *aliasPtr; 2897 2898 for (aliasPtr = encodingAliases; aliasPtr->aliasPattern != NULL; ) { 2899 if (Tcl_StringMatch((char *) name, aliasPtr->aliasPattern)) { 2900 return aliasPtr->realName; 2901 } 2902 aliasPtr++; 2903 } 2904 return name; 2905} 2906