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