1/* 2 * tkMacOSXFont.c -- 3 * 4 * Contains the Macintosh implementation of the platform-independant 5 * font package interface. 6 * 7 * Copyright (c) 1990-1994 The Regents of the University of California. 8 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 9 * Copyright 2001, Apple Computer, Inc. 10 * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net> 11 * 12 * See the file "license.terms" for information on usage and redistribution 13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 14 * 15 * RCS: @(#) $Id: tkMacOSXFont.c,v 1.3.2.11 2007/11/09 06:26:55 das Exp $ 16 */ 17 18#include "tkMacOSXPrivate.h" 19#include "tkMacOSXFont.h" 20 21#include "tclInt.h" /* for Tcl_CreateNamespace() */ 22 23/* 24 * Dealing with pascal strings. 25 */ 26 27#ifndef StrLength 28#define StrLength(s) (*((unsigned char *) (s))) 29#endif 30#ifndef StrBody 31#define StrBody(s) ((char *) (s) + 1) 32#endif 33#define pstrcmp(s1, s2) RelString((s1), (s2), 1, 1) 34#define pstrcasecmp(s1, s2) RelString((s1), (s2), 0, 1) 35 36/* 37 * The preferred font encodings. 38 */ 39 40static const char *encodingList[] = { 41 "macRoman", "macJapan", NULL 42}; 43 44/* 45 * The following structures are used to map the script/language codes of a 46 * font to the name that should be passed to Tcl_GetTextEncoding() to obtain 47 * the encoding for that font. The set of numeric constants is fixed and 48 * defined by Apple. 49 */ 50 51static TkStateMap scriptMap[] = { 52 {smRoman, "macRoman"}, 53 {smJapanese, "macJapan"}, 54 {smTradChinese, "macChinese"}, 55 {smKorean, "macKorean"}, 56 {smArabic, "macArabic"}, 57 {smHebrew, "macHebrew"}, 58 {smGreek, "macGreek"}, 59 {smCyrillic, "macCyrillic"}, 60 {smRSymbol, "macRSymbol"}, 61 {smDevanagari, "macDevanagari"}, 62 {smGurmukhi, "macGurmukhi"}, 63 {smGujarati, "macGujarati"}, 64 {smOriya, "macOriya"}, 65 {smBengali, "macBengali"}, 66 {smTamil, "macTamil"}, 67 {smTelugu, "macTelugu"}, 68 {smKannada, "macKannada"}, 69 {smMalayalam, "macMalayalam"}, 70 {smSinhalese, "macSinhalese"}, 71 {smBurmese, "macBurmese"}, 72 {smKhmer, "macKhmer"}, 73 {smThai, "macThailand"}, 74 {smLaotian, "macLaos"}, 75 {smGeorgian, "macGeorgia"}, 76 {smArmenian, "macArmenia"}, 77 {smSimpChinese, "macSimpChinese"}, 78 {smTibetan, "macTIbet"}, 79 {smMongolian, "macMongolia"}, 80 {smGeez, "macEthiopia"}, 81 {smEastEurRoman, "macCentEuro"}, 82 {smVietnamese, "macVietnam"}, 83 {smExtArabic, "macSindhi"}, 84 {0, NULL} 85}; 86 87static TkStateMap romanMap[] = { 88 {langCroatian, "macCroatian"}, 89 {langSlovenian, "macCroatian"}, 90 {langIcelandic, "macIceland"}, 91 {langRomanian, "macRomania"}, 92 {langTurkish, "macTurkish"}, 93 {langGreek, "macGreek"}, 94 {0, NULL} 95}; 96 97static TkStateMap cyrillicMap[] = { 98 {langUkrainian, "macUkraine"}, 99 {langBulgarian, "macBulgaria"}, 100 {0, NULL} 101}; 102 103/* 104 * The following structure represents a font family. It is assumed that 105 * all screen fonts constructed from the same "font family" share certain 106 * properties; all screen fonts with the same "font family" point to a 107 * shared instance of this structure. The most important shared property 108 * is the character existence metrics, used to determine if a screen font 109 * can display a given Unicode character. 110 * 111 * Under Macintosh, a "font family" is uniquely identified by its face number. 112 */ 113 114 115#define FONTMAP_SHIFT 10 116 117#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar) * 8 - FONTMAP_SHIFT)) 118#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT) 119 120typedef struct FontFamily { 121 struct FontFamily *nextPtr; /* Next in list of all known font families. */ 122 int refCount; /* How many SubFonts are referring to this 123 * FontFamily. When the refCount drops to 124 * zero, this FontFamily may be freed. */ 125 /* 126 * Key. 127 */ 128 129 FMFontFamily faceNum; /* Unique face number key for this FontFamily. */ 130 131 /* 132 * Derived properties. 133 */ 134 135 Tcl_Encoding encoding; /* Encoding for this font family. */ 136 int isSymbolFont; /* Non-zero if this is a symbol family. */ 137 int isMultiByteFont; /* Non-zero if this is a multi-byte family. */ 138 char typeTable[256]; /* Table that identfies all lead bytes for a 139 * multi-byte family, used when measuring chars. 140 * If a byte is a lead byte, the value at the 141 * corresponding position in the typeTable is 1, 142 * otherwise 0. If this is a single-byte font, 143 * all entries are 0. */ 144 char *fontMap[FONTMAP_PAGES]; 145 /* Two-level sparse table used to determine 146 * quickly if the specified character exists. 147 * As characters are encountered, more pages 148 * in this table are dynamically added. The 149 * contents of each page is a bitmask 150 * consisting of FONTMAP_BITSPERPAGE bits, 151 * representing whether this font can be used 152 * to display the given character at the 153 * corresponding bit position. The high bits 154 * of the character are used to pick which 155 * page of the table is used. */ 156} FontFamily; 157 158/* 159 * The following structure encapsulates an individual screen font. A font 160 * object is made up of however many SubFonts are necessary to display a 161 * stream of multilingual characters. 162 */ 163 164typedef struct SubFont { 165 char **fontMap; /* Pointer to font map from the FontFamily, 166 * cached here to save a dereference. */ 167 FontFamily *familyPtr; /* The FontFamily for this SubFont. */ 168} SubFont; 169 170/* 171 * The following structure represents Macintosh's implementation of a font 172 * object. 173 */ 174 175#define SUBFONT_SPACE 3 176 177typedef struct MacFont { 178 TkFont font; /* Stuff used by generic font package. Must 179 * be first in structure. */ 180 SubFont staticSubFonts[SUBFONT_SPACE]; 181 /* Builtin space for a limited number of 182 * SubFonts. */ 183 int numSubFonts; /* Length of following array. */ 184 SubFont *subFontArray; /* Array of SubFonts that have been loaded 185 * in order to draw/measure all the characters 186 * encountered by this font so far. All fonts 187 * start off with one SubFont initialized by 188 * AllocFont() from the original set of font 189 * attributes. Usually points to 190 * staticSubFonts, but may point to malloced 191 * space if there are lots of SubFonts. */ 192 193 short size; /* Font size in pixels, constructed from 194 * font attributes. */ 195 short style; /* Style bits, constructed from font 196 * attributes. */ 197} MacFont; 198 199/* 200 * The following structure is used to map between the UTF-8 name for a font and 201 * the name that the Macintosh uses to refer to the font, in order to determine 202 * if a font exists. The Macintosh names for fonts are stored in the encoding 203 * of the font itself. 204 */ 205 206typedef struct FontNameMap { 207 Tk_Uid utfName; /* The name of the font in UTF-8. */ 208 StringPtr nativeName; /* The name of the font in the font's encoding. */ 209 FMFontFamily faceNum; /* Unique face number for this font. */ 210} FontNameMap; 211 212/* 213 * The list of font families that are currently loaded. As screen fonts 214 * are loaded, this list grows to hold information about what characters 215 * exist in each font family. 216 */ 217 218static FontFamily *fontFamilyList = NULL; 219 220/* 221 * Information cached about the system at startup time. 222 */ 223 224static FontNameMap *gFontNameMap = NULL; 225static GWorldPtr gWorld = NULL; 226 227/* 228 * The names for our "native" fonts. 229 */ 230 231#define SYSTEMFONT_NAME "system" 232#define APPLFONT_NAME "application" 233#define MENUITEMFONT_NAME "menu" 234 235/* 236 * Procedures used only in this file. 237 */ 238 239static FontFamily * AllocFontFamily(const MacFont *fontPtr, int family); 240static SubFont * CanUseFallback(MacFont *fontPtr, const char *fallbackName, int ch, SubFont **fixSubFontPtrPtr); 241static SubFont * CanUseFallbackWithAliases(MacFont *fontPtr, const char *faceName, int ch, Tcl_DString *nameTriedPtr, SubFont **fixSubFontPtrPtr); 242static SubFont * FindSubFontForChar(MacFont *fontPtr, int ch, SubFont **fixSubFontPtrPtr); 243static void FontMapInsert(SubFont *subFontPtr, int ch); 244static void FontMapLoadPage(SubFont *subFontPtr, int row); 245static int FontMapLookup(SubFont *subFontPtr, int ch); 246static void FreeFontFamily(FontFamily *familyPtr); 247static void InitFont(Tk_Window tkwin, int family, unsigned char *familyName, int size, int style, MacFont *fontPtr); 248static void InitSubFont(const MacFont *fontPtr, int family, SubFont *subFontPtr); 249static void MultiFontDrawText(MacFont *fontPtr, const char *source, int numBytes, int x, int y); 250static void ReleaseFont(MacFont *fontPtr); 251static void ReleaseSubFont(SubFont *subFontPtr); 252static int SeenName(const char *name, Tcl_DString *dsPtr); 253 254static const char * BreakLine(FontFamily *familyPtr, int flags, const char *source, int numBytes, int *widthPtr); 255static int GetFamilyNum(const char *faceName, short *familyPtr); 256static int GetFamilyOrAliasNum(const char *faceName, short *familyPtr); 257static Tcl_Encoding GetFontEncoding(int faceNum, int allowSymbol, int *isSymbolPtr); 258static Tk_Uid GetUtfFaceName(StringPtr faceNameStr); 259static OSStatus GetThemeFontAndFamily(const ThemeFontID themeFontId, 260 FMFontFamily *fontFamily, unsigned char *fontName, SInt16 *fontSize, 261 Style *fontStyle); 262 263 264/* 265 *------------------------------------------------------------------------- 266 * 267 * TkpFontPkgInit -- 268 * 269 * This procedure is called when an application is created. It 270 * initializes all the structures that are used by the 271 * platform-dependant code on a per application basis. 272 * 273 * Results: 274 * None. 275 * 276 * Side effects: 277 * See comments below. 278 * 279 *------------------------------------------------------------------------- 280 */ 281 282void 283TkpFontPkgInit( 284 TkMainInfo *mainPtr) /* The application being created. */ 285{ 286 FMFontFamilyIterator fontFamilyIterator; 287 FMFontFamily fontFamily; 288 FontNameMap *tmpFontNameMap, *newFontNameMap, *mapPtr; 289 int i, j, numFonts, fontMapOffset, isSymbol; 290 Str255 nativeName; 291 Tcl_DString ds; 292 Tcl_Encoding encoding; 293 Tcl_Encoding *encodings; 294 295 if (gWorld == NULL) { 296 Rect rect = {0, 0, 1, 1}; 297 298 SetFractEnable(0); 299 /* 300 * Used for saving and restoring state while drawing and measuring. 301 */ 302 if (ChkErr(NewGWorld, &gWorld, 32, &rect, NULL, NULL, 0 303#ifdef __LITTLE_ENDIAN__ 304 | kNativeEndianPixMap 305#endif 306 ) != noErr) { 307 Tcl_Panic("TkpFontPkgInit: NewGWorld failed"); 308 } 309 /* 310 * The name of each font is stored in the encoding of that font. 311 * How would we translate a name from UTF-8 into the native encoding 312 * of the font unless we knew the encoding of that font? We can't. 313 * So, precompute the UTF-8 and native names of all fonts on the 314 * system. The when the user asks for font by its UTF-8 name, we 315 * lookup the name in that table and really ask for the font by its 316 * native name. Any unknown UTF-8 names will be mapped to the system 317 * font. 318 */ 319 FMCreateFontFamilyIterator(NULL, NULL, kFMDefaultOptions, &fontFamilyIterator); 320 numFonts = 0; 321 while (FMGetNextFontFamily(&fontFamilyIterator, &fontFamily) != kFMIterationCompleted) { 322 numFonts++; 323 } 324 tmpFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * numFonts); 325 encodings = (Tcl_Encoding *) ckalloc(sizeof(Tcl_Encoding) * numFonts); 326 mapPtr = tmpFontNameMap; 327 FMResetFontFamilyIterator(NULL, NULL, kFMDefaultOptions, &fontFamilyIterator); 328 i = 0; 329 while (FMGetNextFontFamily(&fontFamilyIterator, &fontFamily) != kFMIterationCompleted) { 330 mapPtr->faceNum = fontFamily; 331 encodings[i] = GetFontEncoding(mapPtr->faceNum, 0, &isSymbol); 332 FMGetFontFamilyName(fontFamily, nativeName ); 333 Tcl_ExternalToUtfDString(encodings[i], StrBody(nativeName), StrLength(nativeName), &ds); 334 mapPtr->utfName = Tk_GetUid(Tcl_DStringValue(&ds)); 335 mapPtr->nativeName = (StringPtr) ckalloc(StrLength(nativeName) + 1); 336 memcpy(mapPtr->nativeName, nativeName, StrLength(nativeName) + 1); 337 Tcl_DStringFree(&ds); 338 mapPtr++; 339 i++; 340 } 341 FMDisposeFontFamilyIterator(&fontFamilyIterator); 342 343 /* 344 * Reorder FontNameMap so fonts with the preferred encodings are at 345 * the front of the list. The relative order of fonts that all have 346 * the same encoding is preserved. Fonts with unknown encodings get 347 * stuck at the end. 348 */ 349 newFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * (numFonts + 1)); 350 fontMapOffset = 0; 351 for (i = 0; encodingList[i] != NULL; i++) { 352 encoding = Tcl_GetEncoding(NULL, encodingList[i]); 353 if (encoding == NULL) { 354 continue; 355 } 356 for (j = 0; j < numFonts; j++) { 357 if (encodings[j] == encoding) { 358 newFontNameMap[fontMapOffset] = tmpFontNameMap[j]; 359 fontMapOffset++; 360 Tcl_FreeEncoding(encodings[j]); 361 tmpFontNameMap[j].utfName = NULL; 362 } 363 } 364 Tcl_FreeEncoding(encoding); 365 } 366 for (i = 0; i < numFonts; i++) { 367 if (tmpFontNameMap[i].utfName != NULL) { 368 newFontNameMap[fontMapOffset] = tmpFontNameMap[i]; 369 fontMapOffset++; 370 Tcl_FreeEncoding(encodings[i]); 371 } 372 } 373 if (fontMapOffset != numFonts) { 374 Tcl_Panic("TkpFontPkgInit: unexpected number of fonts"); 375 } 376 377 mapPtr = &newFontNameMap[numFonts]; 378 mapPtr->utfName = NULL; 379 mapPtr->nativeName = NULL; 380 mapPtr->faceNum = 0; 381 382 ckfree((char *) tmpFontNameMap); 383 ckfree((char *) encodings); 384 385 gFontNameMap = newFontNameMap; 386 } 387} 388 389/* 390 *--------------------------------------------------------------------------- 391 * 392 * GetThemeFontAndFamily -- 393 * 394 * Wrapper around the GetThemeFont and FMGetFontFamilyFromName APIs. 395 * 396 *--------------------------------------------------------------------------- 397 */ 398 399OSStatus 400GetThemeFontAndFamily( 401 const ThemeFontID themeFontId, 402 FMFontFamily* fontFamily, 403 unsigned char *fontName, 404 SInt16 *fontSize, 405 Style *fontStyle) 406{ 407 OSStatus err = ChkErr(GetThemeFont, themeFontId, smSystemScript, fontName, 408 fontSize, fontStyle); 409 410 if (err == noErr) { 411 *fontFamily = FMGetFontFamilyFromName(fontName); 412 if (*fontFamily == kInvalidFontFamily) { 413 err = kFMInvalidFontFamilyErr; 414 TkMacOSXDbgMsg("FMGetFontFamilyFromName failed."); 415 } 416 } 417 418 return err; 419} 420 421/* 422 *--------------------------------------------------------------------------- 423 * 424 * TkpGetNativeFont -- 425 * 426 * Map a platform-specific native font name to a TkFont. 427 * 428 * Results: 429 * The return value is a pointer to a TkFont that represents the 430 * native font. If a native font by the given name could not be 431 * found, the return value is NULL. 432 * 433 * Every call to this procedure returns a new TkFont structure, even 434 * if the name has already been seen before. The caller should call 435 * TkpDeleteFont() when the font is no longer needed. 436 * 437 * The caller is responsible for initializing the memory associated 438 * with the generic TkFont when this function returns and releasing 439 * the contents of the generics TkFont before calling TkpDeleteFont(). 440 * 441 * Side effects: 442 * None. 443 * 444 *--------------------------------------------------------------------------- 445 */ 446 447TkFont * 448TkpGetNativeFont( 449 Tk_Window tkwin, /* For display where font will be used. */ 450 CONST char *name) /* Platform-specific font name. */ 451{ 452 ThemeFontID themeFontId; 453 FMFontFamily fontFamily; 454 Str255 fontName; 455 SInt16 fontSize; 456 Style fontStyle; 457 MacFont * fontPtr; 458 459 if (strcmp(name, SYSTEMFONT_NAME) == 0) { 460 themeFontId = kThemeSystemFont; 461 } else if (strcmp(name, APPLFONT_NAME) == 0) { 462 themeFontId = kThemeApplicationFont; 463 } else if (strcmp(name, MENUITEMFONT_NAME) == 0) { 464 themeFontId = kThemeMenuItemFont; 465 } else { 466 return NULL; 467 } 468 if (GetThemeFontAndFamily(themeFontId, &fontFamily, fontName, &fontSize, 469 &fontStyle) != noErr) { 470 return NULL; 471 } 472 473 fontPtr = (MacFont *) ckalloc(sizeof(MacFont)); 474 InitFont(tkwin, fontFamily, fontName, fontSize, fontStyle, fontPtr); 475 476 return (TkFont *) fontPtr; 477} 478 479/* 480 *--------------------------------------------------------------------------- 481 * 482 * TkpGetFontFromAttributes -- 483 * 484 * Given a desired set of attributes for a font, find a font with the 485 * closest matching attributes. 486 * 487 * Results: 488 * The return value is a pointer to a TkFont that represents the font 489 * with the desired attributes. If a font with the desired attributes 490 * could not be constructed, some other font will be substituted 491 * automatically. 492 * 493 * Every call to this procedure returns a new TkFont structure, even 494 * if the specified attributes have already been seen before. The 495 * caller should call TkpDeleteFont() to free the platform- specific 496 * data when the font is no longer needed. 497 * 498 * The caller is responsible for initializing the memory associated 499 * with the generic TkFont when this function returns and releasing 500 * the contents of the generic TkFont before calling TkpDeleteFont(). 501 * 502 * Side effects: 503 * None. 504 * 505 *--------------------------------------------------------------------------- 506 */ 507 508TkFont * 509TkpGetFontFromAttributes( 510 TkFont *tkFontPtr, /* If non-NULL, store the information in this 511 * existing TkFont structure, rather than 512 * allocating a new structure to hold the 513 * font; the existing contents of the font 514 * will be released. If NULL, a new TkFont 515 * structure is allocated. */ 516 Tk_Window tkwin, /* For display where font will be used. */ 517 CONST TkFontAttributes *faPtr) 518 /* Set of attributes to match. */ 519{ 520 short faceNum, style; 521 int i, j; 522 const char *faceName, *fallback; 523 char ***fallbacks; 524 MacFont *fontPtr; 525 526 /* 527 * Algorithm to get the closest font to the one requested. 528 * 529 * try fontname 530 * try all aliases for fontname 531 * foreach fallback for fontname 532 * try the fallback 533 * try all aliases for the fallback 534 */ 535 536 faceNum = 0; 537 faceName = faPtr->family; 538 if (faceName != NULL) { 539 if (GetFamilyOrAliasNum(faceName, &faceNum) != 0) { 540 goto found; 541 } 542 fallbacks = TkFontGetFallbacks(); 543 for (i = 0; fallbacks[i] != NULL; i++) { 544 for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) { 545 if (strcasecmp(faceName, fallback) == 0) { 546 for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) { 547 if (GetFamilyOrAliasNum(fallback, &faceNum)) { 548 goto found; 549 } 550 } 551 } 552 break; 553 } 554 } 555 } 556 557found: 558 style = 0; 559 if (faPtr->weight != TK_FW_NORMAL) { 560 style |= bold; 561 } 562 if (faPtr->slant != TK_FS_ROMAN) { 563 style |= italic; 564 } 565 if (faPtr->underline) { 566 style |= underline; 567 } 568 if (tkFontPtr == NULL) { 569 fontPtr = (MacFont *) ckalloc(sizeof(MacFont)); 570 } else { 571 fontPtr = (MacFont *) tkFontPtr; 572 ReleaseFont(fontPtr); 573 } 574 InitFont(tkwin, faceNum, NULL, faPtr->size, style, fontPtr); 575 576 return (TkFont *) fontPtr; 577} 578 579/* 580 *--------------------------------------------------------------------------- 581 * 582 * TkpDeleteFont -- 583 * 584 * Called to release a font allocated by TkpGetNativeFont() or 585 * TkpGetFontFromAttributes(). The caller should have already 586 * released the fields of the TkFont that are used exclusively by the 587 * generic TkFont code. 588 * 589 * Results: 590 * TkFont is deallocated. 591 * 592 * Side effects: 593 * None. 594 * 595 *--------------------------------------------------------------------------- 596 */ 597 598void 599TkpDeleteFont( 600 TkFont *tkFontPtr) /* Token of font to be deleted. */ 601{ 602 ReleaseFont((MacFont *) tkFontPtr); 603} 604 605/* 606 *--------------------------------------------------------------------------- 607 * 608 * TkpGetFontFamilies -- 609 * 610 * Return information about the font families that are available on 611 * the display of the given window. 612 * 613 * Results: 614 * Modifies interp's result object to hold a list of all the available 615 * font families. 616 * 617 * Side effects: 618 * None. 619 * 620 *--------------------------------------------------------------------------- 621 */ 622 623void 624TkpGetFontFamilies( 625 Tcl_Interp *interp, /* Interp to hold result. */ 626 Tk_Window tkwin) /* For display to query. */ 627{ 628 FontNameMap *mapPtr; 629 Tcl_Obj *resultPtr, *strPtr; 630 631 resultPtr = Tcl_GetObjResult(interp); 632 for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) { 633 strPtr = Tcl_NewStringObj(mapPtr->utfName, -1); 634 Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); 635 } 636} 637 638/* 639 *------------------------------------------------------------------------- 640 * 641 * TkpGetSubFonts -- 642 * 643 * A function used by the testing package for querying the actual 644 * screen fonts that make up a font object. 645 * 646 * Results: 647 * Modifies interp's result object to hold a list containing the names 648 * of the screen fonts that make up the given font object. 649 * 650 * Side effects: 651 * None. 652 * 653 *------------------------------------------------------------------------- 654 */ 655 656void 657TkpGetSubFonts( 658 Tcl_Interp *interp, /* Interp to hold result. */ 659 Tk_Font tkfont) /* Font object to query. */ 660{ 661 int i; 662 Tcl_Obj *resultPtr, *strPtr; 663 MacFont *fontPtr; 664 FontFamily *familyPtr; 665 Str255 nativeName; 666 667 resultPtr = Tcl_GetObjResult(interp); 668 fontPtr = (MacFont *) tkfont; 669 for (i = 0; i < fontPtr->numSubFonts; i++) { 670 familyPtr = fontPtr->subFontArray[i].familyPtr; 671 GetFontName(familyPtr->faceNum, nativeName); 672 strPtr = Tcl_NewStringObj(GetUtfFaceName(nativeName), -1); 673 Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); 674 } 675} 676 677/* 678 *--------------------------------------------------------------------------- 679 * 680 * Tk_MeasureChars -- 681 * 682 * Determine the number of characters from the string that will fit 683 * in the given horizontal span. The measurement is done under the 684 * assumption that Tk_DrawChars() will be used to actually display 685 * the characters. 686 * 687 * Results: 688 * The return value is the number of bytes from source that 689 * fit into the span that extends from 0 to maxLength. *lengthPtr is 690 * filled with the x-coordinate of the right edge of the last 691 * character that did fit. 692 * 693 * Side effects: 694 * None. 695 * 696 *--------------------------------------------------------------------------- 697 */ 698 699int 700Tk_MeasureChars( 701 Tk_Font tkfont, /* Font in which characters will be drawn. */ 702 CONST char *source, /* UTF-8 string to be displayed. Need not be 703 * '\0' terminated. */ 704 int numBytes, /* Maximum number of bytes to consider 705 * from source string. */ 706 int maxLength, /* If >= 0, maxLength specifies the longest 707 * permissible line length; don't consider any 708 * character that would cross this 709 * x-position. If < 0, then line length is 710 * unbounded and the flags argument is 711 * ignored. */ 712 int flags, /* Various flag bits OR-ed together: 713 * TK_PARTIAL_OK means include the last char 714 * which only partially fit on this line. 715 * TK_WHOLE_WORDS means stop on a word 716 * boundary, if possible. 717 * TK_AT_LEAST_ONE means return at least one 718 * character even if no characters fit. */ 719 int *lengthPtr) /* Filled with x-location just after the 720 * terminating character. */ 721{ 722 MacFont *fontPtr; 723 SubFont *thisSubFontPtr, *lastSubFontPtr; 724 CGrafPtr savePort; 725 Boolean portChanged; 726 int curX, curByte; 727 728 /* 729 * According to "Inside Macintosh: Text", the Macintosh may 730 * automatically substitute 731 * ligatures or context-sensitive presentation forms when 732 * measuring/displaying text within a font run. We cannot safely 733 * measure individual characters and add up the widths w/o errors. 734 * However, if we convert a range of text from UTF-8 to, say, 735 * Shift-JIS, and get the offset into the Shift-JIS string as to 736 * where a word or line break would occur, then can we map that 737 * number back to UTF-8? 738 */ 739 740 fontPtr = (MacFont *) tkfont; 741 742 portChanged = QDSwapPort(gWorld, &savePort); 743 744 TextSize(fontPtr->size); 745 TextFace(fontPtr->style); 746 747 lastSubFontPtr = &fontPtr->subFontArray[0]; 748 749 if (numBytes == 0) { 750 curX = 0; 751 curByte = 0; 752 } else if (maxLength < 0) { 753 const char *p, *end, *next; 754 Tcl_UniChar ch; 755 FontFamily *familyPtr; 756 Tcl_DString runString; 757 758 /* 759 * A three step process: 760 * 1. Find a contiguous range of characters that can all be 761 * represented by a single screen font. 762 * 2. Convert those chars to the encoding of that font. 763 * 3. Measure converted chars. 764 */ 765 766 curX = 0; 767 end = source + numBytes; 768 for (p = source; p < end; ) { 769 next = p + Tcl_UtfToUniChar(p, &ch); 770 thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr); 771 if (thisSubFontPtr != lastSubFontPtr) { 772 familyPtr = lastSubFontPtr->familyPtr; 773 TextFont(familyPtr->faceNum); 774 Tcl_UtfToExternalDString(familyPtr->encoding, source, 775 p - source, &runString); 776 curX += TextWidth(Tcl_DStringValue(&runString), 0, 777 Tcl_DStringLength(&runString)); 778 Tcl_DStringFree(&runString); 779 lastSubFontPtr = thisSubFontPtr; 780 source = p; 781 } 782 p = next; 783 } 784 familyPtr = lastSubFontPtr->familyPtr; 785 TextFont(familyPtr->faceNum); 786 Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source, 787 &runString); 788 curX += TextWidth(Tcl_DStringValue(&runString), 0, 789 Tcl_DStringLength(&runString)); 790 Tcl_DStringFree(&runString); 791 curByte = numBytes; 792 } else { 793 const char *p, *end, *next, *sourceOrig; 794 int widthLeft; 795 Tcl_UniChar ch; 796 const char *rest = NULL; 797 798 /* 799 * How many chars will fit in the space allotted? 800 */ 801 802 if (maxLength > 32767) { 803 maxLength = 32767; 804 } 805 806 widthLeft = maxLength; 807 sourceOrig = source; 808 end = source + numBytes; 809 for (p = source; p < end; p = next) { 810 next = p + Tcl_UtfToUniChar(p, &ch); 811 thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr); 812 if (thisSubFontPtr != lastSubFontPtr) { 813 if (p > source) { 814 rest = BreakLine(lastSubFontPtr->familyPtr, flags, source, 815 p - source, &widthLeft); 816 flags &= ~TK_AT_LEAST_ONE; 817 if (rest != NULL) { 818 p = source; 819 break; 820 } 821 } 822 lastSubFontPtr = thisSubFontPtr; 823 source = p; 824 } 825 } 826 827 if (p > source) { 828 rest = BreakLine(lastSubFontPtr->familyPtr, flags, source, p - source, 829 &widthLeft); 830 } 831 832 if (rest == NULL) { 833 curByte = numBytes; 834 } else { 835 curByte = rest - sourceOrig; 836 } 837 curX = maxLength - widthLeft; 838 } 839 840 if (portChanged) { 841 QDSwapPort(savePort, NULL); 842 } 843 844 *lengthPtr = curX; 845 return curByte; 846} 847 848/* 849 *--------------------------------------------------------------------------- 850 * 851 * BreakLine -- 852 * 853 * Determine where the given line of text should be broken so that it 854 * fits in the specified range. Before calling this function, the 855 * font values and graphics port must be set. 856 * 857 * Results: 858 * The return value is NULL if the specified range is larger that the 859 * space the text needs, and *widthLeftPtr is filled with how much 860 * space is left in the range after measuring the whole text buffer. 861 * Otherwise, the return value is a pointer into the text buffer that 862 * indicates where the line should be broken (up to, but not including 863 * that character), and *widthLeftPtr is filled with how much space is 864 * left in the range after measuring up to that character. 865 * 866 * Side effects: 867 * None. 868 * 869 *--------------------------------------------------------------------------- 870 */ 871 872static const char * 873BreakLine( 874 FontFamily *familyPtr, /* FontFamily that describes the font values 875 * that are already selected into the graphics 876 * port. */ 877 int flags, /* Various flag bits OR-ed together: 878 * TK_PARTIAL_OK means include the last char 879 * which only partially fit on this line. 880 * TK_WHOLE_WORDS means stop on a word 881 * boundary, if possible. 882 * TK_AT_LEAST_ONE means return at least one 883 * character even if no characters fit. */ 884 const char *source, /* UTF-8 string to be displayed. Need not be 885 * '\0' terminated. */ 886 int numBytes, /* Maximum number of bytes to consider 887 * from source string. */ 888 int *widthLeftPtr) /* On input, specifies size of range into 889 * which characters from source buffer should 890 * be fit. On output, filled with how much 891 * space is left after fitting as many 892 * characters as possible into the range. 893 * Result may be negative if TK_AT_LEAST_ONE 894 * was specified in the flags argument. */ 895{ 896 Fixed pixelWidth, widthLeft; 897 StyledLineBreakCode breakCode; 898 Tcl_DString runString; 899 long textOffset; 900 Boolean leadingEdge; 901 Point point; 902 int charOffset, thisCharWasDoubleByte; 903 char *p, *end, *typeTable; 904 905 TextFont(familyPtr->faceNum); 906 Tcl_UtfToExternalDString(familyPtr->encoding, source, numBytes, 907 &runString); 908 pixelWidth = IntToFixed(*widthLeftPtr) + 1; 909 if (flags & TK_WHOLE_WORDS) { 910 textOffset = (flags & TK_AT_LEAST_ONE); 911 widthLeft = pixelWidth; 912 breakCode = StyledLineBreak(Tcl_DStringValue(&runString), 913 Tcl_DStringLength(&runString), 0, Tcl_DStringLength(&runString), 914 0, &widthLeft, &textOffset); 915 if (breakCode != smBreakOverflow) { 916 /* 917 * StyledLineBreak includes all the space characters at the end of 918 * line that we want to suppress. 919 */ 920 921 textOffset = VisibleLength(Tcl_DStringValue(&runString), textOffset); 922 goto getoffset; 923 } 924 } else { 925 point.v = 1; 926 point.h = 1; 927 textOffset = PixelToChar(Tcl_DStringValue(&runString), 928 Tcl_DStringLength(&runString), 0, pixelWidth, &leadingEdge, 929 &widthLeft, smOnlyStyleRun, point, point); 930 if (FixedToInt(widthLeft) < 0) { 931 goto getoffset; 932 } 933 } 934 *widthLeftPtr = FixedToInt(widthLeft); 935 Tcl_DStringFree(&runString); 936 return NULL; 937 938 /* 939 * The conversion routine that converts UTF-8 to the target encoding 940 * must map one UTF-8 character to exactly one encoding-specific 941 * character, so that the following algorithm works: 942 * 943 * 1. Get byte offset of where line should be broken. 944 * 2. Get char offset corresponding to that byte offset. 945 * 3. Map that char offset to byte offset in UTF-8 string. 946 */ 947 948 getoffset: 949 thisCharWasDoubleByte = 0; 950 if (familyPtr->isMultiByteFont == 0) { 951 charOffset = textOffset; 952 } else { 953 charOffset = 0; 954 typeTable = familyPtr->typeTable; 955 956 p = Tcl_DStringValue(&runString); 957 end = p + textOffset; 958 thisCharWasDoubleByte = typeTable[*((unsigned char *) p)]; 959 for ( ; p < end; p++) { 960 thisCharWasDoubleByte = typeTable[*((unsigned char *) p)]; 961 p += thisCharWasDoubleByte; 962 charOffset++; 963 } 964 } 965 966 if ((flags & TK_WHOLE_WORDS) == 0) { 967 if ((flags & TK_PARTIAL_OK) && (leadingEdge != 0)) { 968 textOffset += thisCharWasDoubleByte; 969 textOffset++; 970 charOffset++; 971 } else if (((flags & TK_PARTIAL_OK) == 0) && (leadingEdge == 0)) { 972 textOffset -= thisCharWasDoubleByte; 973 textOffset--; 974 charOffset--; 975 } 976 } 977 if ((textOffset == 0) && (Tcl_DStringLength(&runString) > 0) 978 && (flags & TK_AT_LEAST_ONE)) { 979 p = Tcl_DStringValue(&runString); 980 textOffset += familyPtr->typeTable[*((unsigned char *) p)]; 981 textOffset++; 982 charOffset++; 983 } 984 *widthLeftPtr = FixedToInt(pixelWidth) 985 - TextWidth(Tcl_DStringValue(&runString), 0, textOffset); 986 Tcl_DStringFree(&runString); 987 return Tcl_UtfAtIndex(source, charOffset); 988} 989 990/* 991 *--------------------------------------------------------------------------- 992 * 993 * Tk_DrawChars -- 994 * 995 * Draw a string of characters on the screen. 996 * 997 * Results: 998 * None. 999 * 1000 * Side effects: 1001 * Information gets drawn on the screen. 1002 * 1003 *--------------------------------------------------------------------------- 1004 */ 1005 1006void 1007Tk_DrawChars( 1008 Display *display, /* Display on which to draw. */ 1009 Drawable drawable, /* Window or pixmap in which to draw. */ 1010 GC gc, /* Graphics context for drawing characters. */ 1011 Tk_Font tkfont, /* Font in which characters will be drawn; must 1012 * be the same as font used in GC. */ 1013 CONST char *source, /* UTF-8 string to be displayed. Need not be 1014 * '\0' terminated. All Tk meta-characters 1015 * (tabs, control characters, and newlines) 1016 * should be stripped out of the string that 1017 * is passed to this function. If they are not 1018 * stripped out, they will be displayed as 1019 * regular printing characters. */ 1020 int numBytes, /* Number of bytes in string. */ 1021 int x, int y) /* Coordinates at which to place origin of the 1022 * string when drawing. */ 1023{ 1024 MacDrawable *macWin = (MacDrawable *) drawable; 1025 MacFont *fontPtr = (MacFont *) tkfont; 1026 TkMacOSXDrawingContext drawingContext; 1027 1028 if (!TkMacOSXSetupDrawingContext(drawable, gc, 0, &drawingContext)) { 1029 return; 1030 } 1031#if 0 1032 /* 1033 * Stippled QD text drawing only kind of works and is ugly, so disable it 1034 * for now: 1035 */ 1036 if ((gc->fill_style == FillStippled 1037 || gc->fill_style == FillOpaqueStippled) 1038 && gc->stipple != None) { 1039 TkMacOSXDrawingContext pixmapDrawingContext; 1040 BitMapPtr stippleMap; 1041 Pixmap pixmap; 1042 Pattern white; 1043 Rect bounds = drawingContext.portBounds; 1044 1045 OffsetRect(&bounds, macWin->xOff + x, 0); 1046 stippleMap = TkMacOSXMakeStippleMap(drawable, gc->stipple); 1047 pixmap = Tk_GetPixmap(display, drawable, 1048 stippleMap->bounds.right, stippleMap->bounds.bottom, 0); 1049 if (!TkMacOSXSetupDrawingContext(pixmap, gc, 0, 1050 &pixmapDrawingContext)) { 1051 return; 1052 } 1053 GetQDGlobalsWhite(&white); 1054 FillRect(&stippleMap->bounds, &white); 1055 MultiFontDrawText(fontPtr, source, numBytes, 0, macWin->yOff + y); 1056 TkMacOSXRestoreDrawingContext(&pixmapDrawingContext); 1057 CopyDeepMask(GetPortBitMapForCopyBits(TkMacOSXGetDrawablePort(pixmap)), 1058 stippleMap, GetPortBitMapForCopyBits( 1059 TkMacOSXGetDrawablePort(drawable)), &stippleMap->bounds, 1060 &stippleMap->bounds, &bounds, srcOr, NULL); 1061 1062 /* TODO: this doesn't work quite right - it does a blend. You can't 1063 * draw white text when you have a stipple. 1064 */ 1065 1066 Tk_FreePixmap(display, pixmap); 1067 ckfree(stippleMap->baseAddr); 1068 ckfree((char *)stippleMap); 1069 } else 1070#endif 1071 { 1072 MultiFontDrawText(fontPtr, source, numBytes, macWin->xOff + x, 1073 macWin->yOff + y); 1074 } 1075 TkMacOSXRestoreDrawingContext(&drawingContext); 1076} 1077 1078/* 1079 *------------------------------------------------------------------------- 1080 * 1081 * MultiFontDrawText -- 1082 * 1083 * Helper function for Tk_DrawChars. Draws characters, using the 1084 * various screen fonts in fontPtr to draw multilingual characters. 1085 * Note: No bidirectional support. 1086 * 1087 * Results: 1088 * None. 1089 * 1090 * Side effects: 1091 * Information gets drawn on the screen. 1092 * Contents of fontPtr may be modified if more subfonts were loaded 1093 * in order to draw all the multilingual characters in the given 1094 * string. 1095 * 1096 *------------------------------------------------------------------------- 1097 */ 1098 1099static void 1100MultiFontDrawText( 1101 MacFont *fontPtr, /* Contains set of fonts to use when drawing 1102 * following string. */ 1103 const char *source, /* Potentially multilingual UTF-8 string. */ 1104 int numBytes, /* Length of string in bytes. */ 1105 int x, int y) /* Coordinates at which to place origin * 1106 * of string when drawing. */ 1107{ 1108 SubFont *thisSubFontPtr, *lastSubFontPtr; 1109 FontFamily *familyPtr; 1110 Tcl_DString runString; 1111 const char *p, *end, *next; 1112 Tcl_UniChar ch; 1113 1114 TextSize(fontPtr->size); 1115 TextFace(fontPtr->style); 1116 1117 lastSubFontPtr = &fontPtr->subFontArray[0]; 1118 1119 end = source + numBytes; 1120 for (p = source; p < end; ) { 1121 next = p + Tcl_UtfToUniChar(p, &ch); 1122 thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr); 1123 if (thisSubFontPtr != lastSubFontPtr) { 1124 if (p > source) { 1125 familyPtr = lastSubFontPtr->familyPtr; 1126 TextFont(familyPtr->faceNum); 1127 Tcl_UtfToExternalDString(familyPtr->encoding, source, 1128 p - source, &runString); 1129 MoveTo((short) x, (short) y); 1130 DrawText(Tcl_DStringValue(&runString), 0, 1131 Tcl_DStringLength(&runString)); 1132 x += TextWidth(Tcl_DStringValue(&runString), 0, 1133 Tcl_DStringLength(&runString)); 1134 Tcl_DStringFree(&runString); 1135 source = p; 1136 } 1137 lastSubFontPtr = thisSubFontPtr; 1138 } 1139 p = next; 1140 } 1141 if (p > source) { 1142 familyPtr = lastSubFontPtr->familyPtr; 1143 TextFont(familyPtr->faceNum); 1144 Tcl_UtfToExternalDString(familyPtr->encoding, source, 1145 p - source, &runString); 1146 MoveTo((short) x, (short) y); 1147 DrawText(Tcl_DStringValue(&runString), 0, 1148 Tcl_DStringLength(&runString)); 1149 Tcl_DStringFree(&runString); 1150 } 1151} 1152 1153/* 1154 *--------------------------------------------------------------------------- 1155 * 1156 * TkMacOSXIsCharacterMissing -- 1157 * 1158 * Given a tkFont and a character determines whether the character has 1159 * a glyph defined in the font or not. Note that this is potentially 1160 * not compatible with Mac OS 8 as it looks at the font handle 1161 * structure directly. Looks into the character array of the font 1162 * handle to determine whether the glyph is defined or not. 1163 * 1164 * Results: 1165 * Returns a 1 if the character is missing, a 0 if it is not. 1166 * 1167 * Side effects: 1168 * None. 1169 * 1170 *--------------------------------------------------------------------------- 1171 */ 1172 1173int 1174TkMacOSXIsCharacterMissing( 1175 Tk_Font tkfont, /* The font we are looking in. */ 1176 unsigned int searchChar) /* The character we are looking for. */ 1177{ 1178 /* 1179 * For some reason, FMSwapFont always returns a NULL font handle under OS X 1180 * Until we figure this one out, return 0; 1181 */ 1182 1183 return 0; 1184} 1185 1186/* 1187 *--------------------------------------------------------------------------- 1188 * 1189 * InitFont -- 1190 * 1191 * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). 1192 * Initializes the memory for a MacFont that wraps the platform-specific 1193 * data. 1194 * 1195 * The caller is responsible for initializing the fields of the 1196 * TkFont that are used exclusively by the generic TkFont code, and 1197 * for releasing those fields before calling TkpDeleteFont(). 1198 * 1199 * Results: 1200 * Fills the MacFont structure. 1201 * 1202 * Side effects: 1203 * Memory allocated. 1204 * 1205 *--------------------------------------------------------------------------- 1206 */ 1207 1208static void 1209InitFont( 1210 Tk_Window tkwin, /* For display where font will be used. */ 1211 int faceNum, /* Macintosh font number. */ 1212 unsigned char *familyName, /* The font family name or NULL. */ 1213 int size, /* Point size for Macintosh font. */ 1214 int style, /* Macintosh style bits. */ 1215 MacFont *fontPtr) /* Filled with information constructed from 1216 * the above arguments. */ 1217{ 1218 Str255 nativeName; 1219 FontInfo fi; 1220 TkFontAttributes *faPtr; 1221 TkFontMetrics *fmPtr; 1222 CGrafPtr savePort; 1223 Boolean portChanged; 1224 short pixels; 1225 1226 if (size == 0) { 1227 size = -GetDefFontSize(); 1228 } 1229 pixels = (short) TkFontGetPixels(tkwin, size); 1230 1231 portChanged = QDSwapPort(gWorld, &savePort); 1232 TextFont(faceNum); 1233 TextSize(pixels); 1234 TextFace(style); 1235 1236 GetFontInfo(&fi); 1237 if (!familyName) { 1238 GetFontName(faceNum, nativeName); 1239 familyName = nativeName; 1240 } 1241 fontPtr->font.fid = (Font) fontPtr; 1242 1243 faPtr = &fontPtr->font.fa; 1244 faPtr->family = GetUtfFaceName(familyName); 1245 faPtr->size = TkFontGetPoints(tkwin, size); 1246 faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL; 1247 faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN; 1248 faPtr->underline = ((style & underline) != 0); 1249 faPtr->overstrike = 0; 1250 1251 fmPtr = &fontPtr->font.fm; 1252 fmPtr->ascent = fi.ascent; 1253 fmPtr->descent = fi.descent; 1254 fmPtr->maxWidth = fi.widMax; 1255 fmPtr->fixed = (CharWidth('i') == CharWidth('w')); 1256 1257 fontPtr->size = pixels; 1258 fontPtr->style = (short) style; 1259 1260 fontPtr->numSubFonts = 1; 1261 fontPtr->subFontArray = fontPtr->staticSubFonts; 1262 InitSubFont(fontPtr, faceNum, &fontPtr->subFontArray[0]); 1263 1264 if (portChanged) { 1265 QDSwapPort(savePort, NULL); 1266 } 1267} 1268 1269/* 1270 *------------------------------------------------------------------------- 1271 * 1272 * ReleaseFont -- 1273 * 1274 * Called to release the Macintosh-specific contents of a TkFont. 1275 * The caller is responsible for freeing the memory used by the 1276 * font itself. 1277 * 1278 * Results: 1279 * None. 1280 * 1281 * Side effects: 1282 * Memory is freed. 1283 * 1284 *--------------------------------------------------------------------------- 1285 */ 1286 1287static void 1288ReleaseFont( 1289 MacFont *fontPtr) /* The font to delete. */ 1290{ 1291 int i; 1292 1293 for (i = 0; i < fontPtr->numSubFonts; i++) { 1294 ReleaseSubFont(&fontPtr->subFontArray[i]); 1295 } 1296 if (fontPtr->subFontArray != fontPtr->staticSubFonts) { 1297 ckfree((char *) fontPtr->subFontArray); 1298 } 1299} 1300 1301/* 1302 *------------------------------------------------------------------------- 1303 * 1304 * InitSubFont -- 1305 * 1306 * Wrap a screen font and load the FontFamily that represents 1307 * it. Used to prepare a SubFont so that characters can be mapped 1308 * from UTF-8 to the charset of the font. 1309 * 1310 * Results: 1311 * The subFontPtr is filled with information about the font. 1312 * 1313 * Side effects: 1314 * None. 1315 * 1316 *------------------------------------------------------------------------- 1317 */ 1318 1319static void 1320InitSubFont( 1321 const MacFont *fontPtr, /* Font object in which the SubFont will be 1322 * used. */ 1323 int faceNum, /* The font number. */ 1324 SubFont *subFontPtr) /* Filled with SubFont constructed from 1325 * above attributes. */ 1326{ 1327 subFontPtr->familyPtr = AllocFontFamily(fontPtr, faceNum); 1328 subFontPtr->fontMap = subFontPtr->familyPtr->fontMap; 1329} 1330 1331/* 1332 *------------------------------------------------------------------------- 1333 * 1334 * ReleaseSubFont -- 1335 * 1336 * Called to release the contents of a SubFont. The caller is 1337 * responsible for freeing the memory used by the SubFont itself. 1338 * 1339 * Results: 1340 * None. 1341 * 1342 * Side effects: 1343 * Memory and resources are freed. 1344 * 1345 *--------------------------------------------------------------------------- 1346 */ 1347 1348static void 1349ReleaseSubFont( 1350 SubFont *subFontPtr) /* The SubFont to delete. */ 1351{ 1352 FreeFontFamily(subFontPtr->familyPtr); 1353} 1354 1355/* 1356 *------------------------------------------------------------------------- 1357 * 1358 * AllocFontFamily -- 1359 * 1360 * Find the FontFamily structure associated with the given font 1361 * family. The information should be stored by the caller in a 1362 * SubFont and used when determining if that SubFont supports a 1363 * character. 1364 * 1365 * Results: 1366 * A pointer to a FontFamily. The reference count in the FontFamily 1367 * is automatically incremented. When the SubFont is released, the 1368 * reference count is decremented. When no SubFont is using this 1369 * FontFamily, it may be deleted. 1370 * 1371 * Side effects: 1372 * A new FontFamily structure will be allocated if this font family 1373 * has not been seen. 1374 * 1375 *------------------------------------------------------------------------- 1376 */ 1377 1378static FontFamily * 1379AllocFontFamily( 1380 const MacFont *fontPtr, /* Font object in which the FontFamily will 1381 * be used. */ 1382 int faceNum) /* The font number. */ 1383{ 1384 FontFamily *familyPtr; 1385 int i; 1386 1387 familyPtr = fontFamilyList; 1388 for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) { 1389 if (familyPtr->faceNum == faceNum) { 1390 familyPtr->refCount++; 1391 return familyPtr; 1392 } 1393 } 1394 1395 familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily)); 1396 memset(familyPtr, 0, sizeof(FontFamily)); 1397 familyPtr->nextPtr = fontFamilyList; 1398 fontFamilyList = familyPtr; 1399 1400 /* 1401 * Set key for this FontFamily. 1402 */ 1403 1404 familyPtr->faceNum = faceNum; 1405 1406 /* 1407 * An initial refCount of 2 means that FontFamily information will 1408 * persist even when the SubFont that loaded the FontFamily is released. 1409 * Change it to 1 to cause FontFamilies to be unloaded when not in use. 1410 */ 1411 1412 familyPtr->refCount = 2; 1413 familyPtr->encoding = GetFontEncoding(faceNum, 1, &familyPtr->isSymbolFont); 1414 familyPtr->isMultiByteFont = 0; 1415 FillParseTable(familyPtr->typeTable, FontToScript(faceNum)); 1416 for (i = 0; i < 256; i++) { 1417 if (familyPtr->typeTable[i] != 0) { 1418 familyPtr->isMultiByteFont = 1; 1419 break; 1420 } 1421 } 1422 return familyPtr; 1423} 1424 1425/* 1426 *------------------------------------------------------------------------- 1427 * 1428 * FreeFontFamily -- 1429 * 1430 * Called to free a FontFamily when the SubFont is finished using it. 1431 * Frees the contents of the FontFamily and the memory used by the 1432 * FontFamily itself. 1433 * 1434 * Results: 1435 * None. 1436 * 1437 * Side effects: 1438 * None. 1439 * 1440 *------------------------------------------------------------------------- 1441 */ 1442 1443static void 1444FreeFontFamily( 1445 FontFamily *familyPtr) /* The FontFamily to delete. */ 1446{ 1447 FontFamily **familyPtrPtr; 1448 int i; 1449 1450 if (familyPtr == NULL) { 1451 return; 1452 } 1453 familyPtr->refCount--; 1454 if (familyPtr->refCount > 0) { 1455 return; 1456 } 1457 Tcl_FreeEncoding(familyPtr->encoding); 1458 for (i = 0; i < FONTMAP_PAGES; i++) { 1459 if (familyPtr->fontMap[i] != NULL) { 1460 ckfree((char *) familyPtr->fontMap[i]); 1461 } 1462 } 1463 1464 /* 1465 * Delete from list. 1466 */ 1467 1468 for (familyPtrPtr = &fontFamilyList; ; ) { 1469 if (*familyPtrPtr == familyPtr) { 1470 *familyPtrPtr = familyPtr->nextPtr; 1471 break; 1472 } 1473 familyPtrPtr = &(*familyPtrPtr)->nextPtr; 1474 } 1475 1476 ckfree((char *) familyPtr); 1477} 1478 1479/* 1480 *------------------------------------------------------------------------- 1481 * 1482 * FindSubFontForChar -- 1483 * 1484 * Determine which physical screen font is necessary to use to 1485 * display the given character. If the font object does not have 1486 * a screen font that can display the character, another screen font 1487 * may be loaded into the font object, following a set of preferred 1488 * fallback rules. 1489 * 1490 * Results: 1491 * The return value is the SubFont to use to display the given 1492 * character. 1493 * 1494 * Side effects: 1495 * The contents of fontPtr are modified to cache the results 1496 * of the lookup and remember any SubFonts that were dynamically 1497 * loaded. The table of SubFonts might be extended, and if a non-NULL 1498 * reference to a subfont pointer is available, it is updated if it 1499 * previously pointed into the old subfont table. 1500 * 1501 *------------------------------------------------------------------------- 1502 */ 1503 1504static SubFont * 1505FindSubFontForChar( 1506 MacFont *fontPtr, /* The font object with which the character 1507 * will be displayed. */ 1508 int ch, /* The Unicode character to be displayed. */ 1509 SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we 1510 * reallocate our subfont table. */ 1511{ 1512 int i, j, k; 1513 const char *fallbackName; 1514 char **aliases; 1515 SubFont *subFontPtr; 1516 FontNameMap *mapPtr; 1517 Tcl_DString faceNames; 1518 char ***fontFallbacks; 1519 char **anyFallbacks; 1520 1521 if (FontMapLookup(&fontPtr->subFontArray[0], ch)) { 1522 return &fontPtr->subFontArray[0]; 1523 } 1524 1525 for (i = 1; i < fontPtr->numSubFonts; i++) { 1526 if (FontMapLookup(&fontPtr->subFontArray[i], ch)) { 1527 return &fontPtr->subFontArray[i]; 1528 } 1529 } 1530 1531 /* 1532 * Keep track of all face names that we check, so we don't check some 1533 * name multiple times if it can be reached by multiple paths. 1534 */ 1535 1536 Tcl_DStringInit(&faceNames); 1537 1538 aliases = TkFontGetAliasList(fontPtr->font.fa.family); 1539 1540 subFontPtr = NULL; 1541 fontFallbacks = TkFontGetFallbacks(); 1542 for (i = 0; fontFallbacks[i] != NULL; i++) { 1543 for (j = 0; fontFallbacks[i][j] != NULL; j++) { 1544 fallbackName = fontFallbacks[i][j]; 1545 if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 0) { 1546 /* 1547 * If the base font has a fallback... 1548 */ 1549 1550 goto tryfallbacks; 1551 } else if (aliases != NULL) { 1552 /* 1553 * Or if an alias for the base font has a fallback... 1554 */ 1555 1556 for (k = 0; aliases[k] != NULL; k++) { 1557 if (strcasecmp(aliases[k], fallbackName) == 0) { 1558 goto tryfallbacks; 1559 } 1560 } 1561 } 1562 } 1563 continue; 1564 1565 /* 1566 * ...then see if we can use one of the fallbacks, or an 1567 * alias for one of the fallbacks. 1568 */ 1569 1570 tryfallbacks: 1571 for (j = 0; fontFallbacks[i][j] != NULL; j++) { 1572 fallbackName = fontFallbacks[i][j]; 1573 subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName, 1574 ch, &faceNames, fixSubFontPtrPtr); 1575 if (subFontPtr != NULL) { 1576 goto end; 1577 } 1578 } 1579 } 1580 1581 /* 1582 * See if we can use something from the global fallback list. 1583 */ 1584 1585 anyFallbacks = TkFontGetGlobalClass(); 1586 for (i = 0; anyFallbacks[i] != NULL; i++) { 1587 fallbackName = anyFallbacks[i]; 1588 subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName, ch, 1589 &faceNames, fixSubFontPtrPtr); 1590 if (subFontPtr != NULL) { 1591 goto end; 1592 } 1593 } 1594 1595 /* 1596 * Try all face names available in the whole system until we 1597 * find one that can be used. 1598 */ 1599 1600 for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) { 1601 fallbackName = mapPtr->utfName; 1602 if (SeenName(fallbackName, &faceNames) == 0) { 1603 subFontPtr = CanUseFallback(fontPtr, fallbackName, ch, 1604 fixSubFontPtrPtr); 1605 if (subFontPtr != NULL) { 1606 goto end; 1607 } 1608 } 1609 } 1610 1611 end: 1612 Tcl_DStringFree(&faceNames); 1613 1614 if (subFontPtr == NULL) { 1615 /* 1616 * No font can display this character. We will use the base font 1617 * and have it display the "unknown" character. 1618 */ 1619 1620 subFontPtr = &fontPtr->subFontArray[0]; 1621 FontMapInsert(subFontPtr, ch); 1622 } 1623 return subFontPtr; 1624} 1625 1626/* 1627 *------------------------------------------------------------------------- 1628 * 1629 * FontMapLookup -- 1630 * 1631 * See if the screen font can display the given character. 1632 * 1633 * Results: 1634 * The return value is 0 if the screen font cannot display the 1635 * character, non-zero otherwise. 1636 * 1637 * Side effects: 1638 * New pages are added to the font mapping cache whenever the 1639 * character belongs to a page that hasn't been seen before. 1640 * When a page is loaded, information about all the characters on 1641 * that page is stored, not just for the single character in 1642 * question. 1643 * 1644 *------------------------------------------------------------------------- 1645 */ 1646 1647static int 1648FontMapLookup( 1649 SubFont *subFontPtr, /* Contains font mapping cache to be queried 1650 * and possibly updated. */ 1651 int ch) /* Character to be tested. */ 1652{ 1653 int row, bitOffset; 1654 1655 row = ch >> FONTMAP_SHIFT; 1656 if (subFontPtr->fontMap[row] == NULL) { 1657 FontMapLoadPage(subFontPtr, row); 1658 } 1659 bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); 1660 return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1; 1661} 1662 1663/* 1664 *------------------------------------------------------------------------- 1665 * 1666 * FontMapInsert -- 1667 * 1668 * Tell the font mapping cache that the given screen font should be 1669 * used to display the specified character. This is called when no 1670 * font on the system can be be found that can display that 1671 * character; we lie to the font and tell it that it can display 1672 * the character, otherwise we would end up re-searching the entire 1673 * fallback hierarchy every time that character was seen. 1674 * 1675 * Results: 1676 * None. 1677 * 1678 * Side effects: 1679 * New pages are added to the font mapping cache whenever the 1680 * character belongs to a page that hasn't been seen before. 1681 * When a page is loaded, information about all the characters on 1682 * that page is stored, not just for the single character in 1683 * question. 1684 * 1685 *------------------------------------------------------------------------- 1686 */ 1687 1688static void 1689FontMapInsert( 1690 SubFont *subFontPtr, /* Contains font mapping cache to be 1691 * updated. */ 1692 int ch) /* Character to be added to cache. */ 1693{ 1694 int row, bitOffset; 1695 1696 row = ch >> FONTMAP_SHIFT; 1697 if (subFontPtr->fontMap[row] == NULL) { 1698 FontMapLoadPage(subFontPtr, row); 1699 } 1700 bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); 1701 subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); 1702} 1703 1704/* 1705 *------------------------------------------------------------------------- 1706 * 1707 * FontMapLoadPage -- 1708 * 1709 * Load information about all the characters on a given page. 1710 * This information consists of one bit per character that indicates 1711 * whether the associated HFONT can (1) or cannot (0) display the 1712 * characters on the page. 1713 * 1714 * Results: 1715 * None. 1716 * 1717 * Side effects: 1718 * Mempry allocated. 1719 * 1720 *------------------------------------------------------------------------- 1721 */ 1722static void 1723FontMapLoadPage( 1724 SubFont *subFontPtr, /* Contains font mapping cache to be 1725 * updated. */ 1726 int row) /* Index of the page to be loaded into 1727 * the cache. */ 1728{ 1729 FMInput fm; 1730 FMOutPtr fmOut; 1731 int i, end, bitOffset, isMultiByteFont; 1732 char src[TCL_UTF_MAX]; 1733 unsigned char buf[16]; 1734 int srcRead, dstWrote; 1735 Tcl_Encoding encoding; 1736 Handle fHandle = NULL; 1737 1738 subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8); 1739 memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8); 1740 1741 encoding = subFontPtr->familyPtr->encoding; 1742 1743 fm.family = subFontPtr->familyPtr->faceNum; 1744 fm.size = 12; 1745 fm.face = 0; 1746 fm.needBits = 0; 1747 fm.device = 0; 1748 fm.numer.h = 1; 1749 fm.numer.v = 1; 1750 fm.denom.h = 1; 1751 fm.denom.v = 1; 1752 1753/* 1754 * For some reason, FMSwapFont alywas returns a structure where the returned font handle 1755 * is NULL. Until we figure this one out, assume all characters are allowed 1756 */ 1757 1758 fmOut = FMSwapFont(&fm); 1759 fHandle = fmOut->fontHandle; 1760 isMultiByteFont = subFontPtr->familyPtr->isMultiByteFont; 1761 1762 /* 1763 * Found an outline font which has very complex font record. 1764 * Let's just assume *ALL* the characters are allowed. 1765 */ 1766 1767 end = (row + 1) << FONTMAP_SHIFT; 1768 for (i = row << FONTMAP_SHIFT; i < end; i++) { 1769 if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i, 1770 src), 1771 TCL_ENCODING_STOPONERROR, NULL, (char *) buf, 1772 sizeof(buf), 1773 &srcRead, &dstWrote, NULL) == TCL_OK) { 1774 bitOffset = i & (FONTMAP_BITSPERPAGE - 1); 1775 subFontPtr->fontMap[row][bitOffset >> 3] |= 1 1776 << (bitOffset & 7); 1777 } 1778 } 1779} 1780 1781/* 1782 *--------------------------------------------------------------------------- 1783 * 1784 * CanUseFallbackWithAliases -- 1785 * 1786 * Helper function for FindSubFontForChar. Determine if the 1787 * specified face name (or an alias of the specified face name) 1788 * can be used to construct a screen font that can display the 1789 * given character. 1790 * 1791 * Results: 1792 * See CanUseFallback(). 1793 * 1794 * Side effects: 1795 * If the name and/or one of its aliases was rejected, the 1796 * rejected string is recorded in nameTriedPtr so that it won't 1797 * be tried again. The table of SubFonts might be extended, and if 1798 * a non-NULL reference to a subfont pointer is available, it is 1799 * updated if it previously pointed into the old subfont table. 1800 * 1801 *--------------------------------------------------------------------------- 1802 */ 1803 1804static SubFont * 1805CanUseFallbackWithAliases( 1806 MacFont *fontPtr, /* The font object that will own the new 1807 * screen font. */ 1808 const char *faceName, /* Desired face name for new screen font. */ 1809 int ch, /* The Unicode character that the new 1810 * screen font must be able to display. */ 1811 Tcl_DString *nameTriedPtr, /* Records face names that have already 1812 * been tried. It is possible for the same 1813 * face name to be queried multiple times when 1814 * trying to find a suitable screen font. */ 1815 SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we 1816 * reallocate our subfont table. */ 1817{ 1818 SubFont *subFontPtr; 1819 char **aliases; 1820 int i; 1821 1822 if (SeenName(faceName, nameTriedPtr) == 0) { 1823 subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr); 1824 if (subFontPtr != NULL) { 1825 return subFontPtr; 1826 } 1827 } 1828 aliases = TkFontGetAliasList(faceName); 1829 if (aliases != NULL) { 1830 for (i = 0; aliases[i] != NULL; i++) { 1831 if (SeenName(aliases[i], nameTriedPtr) == 0) { 1832 subFontPtr = CanUseFallback(fontPtr, aliases[i], ch, 1833 fixSubFontPtrPtr); 1834 if (subFontPtr != NULL) { 1835 return subFontPtr; 1836 } 1837 } 1838 } 1839 } 1840 return NULL; 1841} 1842 1843/* 1844 *--------------------------------------------------------------------------- 1845 * 1846 * SeenName -- 1847 * 1848 * Used to determine we have already tried and rejected the given 1849 * face name when looking for a screen font that can support some 1850 * Unicode character. 1851 * 1852 * Results: 1853 * The return value is 0 if this face name has not already been seen, 1854 * non-zero otherwise. 1855 * 1856 * Side effects: 1857 * None. 1858 * 1859 *--------------------------------------------------------------------------- 1860 */ 1861 1862static int 1863SeenName( 1864 const char *name, /* The name to check. */ 1865 Tcl_DString *dsPtr) /* Contains names that have already been 1866 * seen. */ 1867{ 1868 const char *seen, *end; 1869 1870 seen = Tcl_DStringValue(dsPtr); 1871 end = seen + Tcl_DStringLength(dsPtr); 1872 while (seen < end) { 1873 if (strcasecmp(seen, name) == 0) { 1874 return 1; 1875 } 1876 seen += strlen(seen) + 1; 1877 } 1878 Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1)); 1879 return 0; 1880} 1881 1882/* 1883 *------------------------------------------------------------------------- 1884 * 1885 * CanUseFallback -- 1886 * 1887 * If the specified physical screen font has not already been loaded 1888 * into the font object, determine if the specified physical screen 1889 * font can display the given character. 1890 * 1891 * Results: 1892 * The return value is a pointer to a newly allocated SubFont, owned 1893 * by the font object. This SubFont can be used to display the given 1894 * character. The SubFont represents the screen font with the base set 1895 * of font attributes from the font object, but using the specified 1896 * font name. NULL is returned if the font object already holds 1897 * a reference to the specified physical font or if the specified 1898 * physical font cannot display the given character. 1899 * 1900 * Side effects: 1901 * The font object's subFontArray is updated to contain a reference 1902 * to the newly allocated SubFont. The table of SubFonts might be 1903 * extended, and if a non-NULL reference to a subfont pointer is 1904 * available, it is updated if it previously pointed into the old 1905 * subfont table. 1906 * 1907 *------------------------------------------------------------------------- 1908 */ 1909 1910static SubFont * 1911CanUseFallback( 1912 MacFont *fontPtr, /* The font object that will own the new 1913 * screen font. */ 1914 const char *faceName, /* Desired face name for new screen font. */ 1915 int ch, /* The Unicode character that the new 1916 * screen font must be able to display. */ 1917 SubFont **fixSubFontPtrPtr) /* Subfont reference to fix up if we 1918 * reallocate our subfont table. */ 1919{ 1920 int i; 1921 SubFont subFont; 1922 short faceNum; 1923 1924 if (GetFamilyNum(faceName, &faceNum) == 0) { 1925 return NULL; 1926 } 1927 1928 /* 1929 * Skip all fonts we've already used. 1930 */ 1931 1932 for (i = 0; i < fontPtr->numSubFonts; i++) { 1933 if (faceNum == fontPtr->subFontArray[i].familyPtr->faceNum) { 1934 return NULL; 1935 } 1936 } 1937 1938 /* 1939 * Load this font and see if it has the desired character. 1940 */ 1941 1942 InitSubFont(fontPtr, faceNum, &subFont); 1943 if (((ch < 256) && (subFont.familyPtr->isSymbolFont)) 1944 || (FontMapLookup(&subFont, ch) == 0)) { 1945 ReleaseSubFont(&subFont); 1946 return NULL; 1947 } 1948 1949 if (fontPtr->numSubFonts >= SUBFONT_SPACE) { 1950 SubFont *newPtr = (SubFont *) ckalloc(sizeof(SubFont) 1951 * (fontPtr->numSubFonts + 1)); 1952 memcpy((char *) newPtr, fontPtr->subFontArray, 1953 fontPtr->numSubFonts * sizeof(SubFont)); 1954 if (fixSubFontPtrPtr != NULL) { 1955 /* 1956 * Fix up the variable pointed to by fixSubFontPtrPtr so it 1957 * still points into the live array. [Bug 618872] 1958 */ 1959 1960 *fixSubFontPtrPtr = 1961 newPtr + (*fixSubFontPtrPtr - fontPtr->subFontArray); 1962 } 1963 if (fontPtr->subFontArray != fontPtr->staticSubFonts) { 1964 ckfree((char *) fontPtr->subFontArray); 1965 } 1966 fontPtr->subFontArray = newPtr; 1967 } 1968 fontPtr->subFontArray[fontPtr->numSubFonts] = subFont; 1969 fontPtr->numSubFonts++; 1970 return &fontPtr->subFontArray[fontPtr->numSubFonts - 1]; 1971} 1972 1973/* 1974 *------------------------------------------------------------------------- 1975 * 1976 * GetFamilyNum -- 1977 * 1978 * Determines if any physical screen font exists on the system with 1979 * the given family name. If the family exists, then it should be 1980 * possible to construct some physical screen font with that family 1981 * name. 1982 * 1983 * Results: 1984 * The return value is 0 if the specified font family does not exist, 1985 * non-zero otherwise. *faceNumPtr is filled with the unique face 1986 * number that identifies the screen font, or 0 if the font family 1987 * did not exist. 1988 * 1989 * Side effects: 1990 * None. 1991 * 1992 *------------------------------------------------------------------------- 1993 */ 1994 1995static int 1996GetFamilyNum( 1997 const char *faceName, /* UTF-8 name of font family to query. */ 1998 short *faceNumPtr) /* Filled with font number for above family. */ 1999{ 2000 FontNameMap *mapPtr; 2001 2002 if (faceName != NULL) { 2003 for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) { 2004 if (strcasecmp(faceName, mapPtr->utfName) == 0) { 2005 *faceNumPtr = mapPtr->faceNum; 2006 return 1; 2007 } 2008 } 2009 } 2010 *faceNumPtr = 0; 2011 return 0; 2012} 2013 2014static int 2015GetFamilyOrAliasNum( 2016 const char *faceName, /* UTF-8 name of font family to query. */ 2017 short *faceNumPtr) /* Filled with font number for above family. */ 2018{ 2019 char **aliases; 2020 int i; 2021 2022 if (GetFamilyNum(faceName, faceNumPtr) != 0) { 2023 return 1; 2024 } 2025 aliases = TkFontGetAliasList(faceName); 2026 if (aliases != NULL) { 2027 for (i = 0; aliases[i] != NULL; i++) { 2028 if (GetFamilyNum(aliases[i], faceNumPtr) != 0) { 2029 return 1; 2030 } 2031 } 2032 } 2033 return 0; 2034} 2035 2036/* 2037 *------------------------------------------------------------------------- 2038 * 2039 * GetUtfFaceName -- 2040 * 2041 * Given the native name for a Macintosh font (in which the name of 2042 * the font is in the encoding of the font itself), return the UTF-8 2043 * name that corresponds to that font. The specified font name must 2044 * refer to a font that actually exists on the machine. 2045 * 2046 * This function is used to obtain the UTF-8 name when querying the 2047 * properties of a Macintosh font object. 2048 * 2049 * Results: 2050 * The return value is a pointer to the UTF-8 of the specified font. 2051 * 2052 * Side effects: 2053 * None. 2054 * 2055 *------------------------------------------------------------------------ 2056 */ 2057 2058static Tk_Uid 2059GetUtfFaceName( 2060 StringPtr nativeName) /* Pascal name for font in native encoding. */ 2061{ 2062 FontNameMap *mapPtr; 2063 2064 for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) { 2065 if (pstrcmp(nativeName, mapPtr->nativeName) == 0) { 2066 return mapPtr->utfName; 2067 } 2068 } 2069 Tcl_Panic("GetUtfFaceName: unexpected nativeName"); 2070 return NULL; 2071} 2072 2073/* 2074 *------------------------------------------------------------------------ 2075 * 2076 * GetFontEncoding -- 2077 * 2078 * Return a string that can be passed to Tcl_GetTextEncoding() and 2079 * used to convert bytes from UTF-8 into the encoding of the 2080 * specified font. 2081 * 2082 * The desired encoding to use to convert the name of a symbolic 2083 * font into UTF-8 is macRoman, while the desired encoding to use 2084 * to convert bytes in a symbolic font to UTF-8 is the corresponding 2085 * symbolic encoding. Due to this dual interpretatation of symbolic 2086 * fonts, the caller can specify what type of encoding to return 2087 * should the specified font be symbolic. 2088 * 2089 * Results: 2090 * The return value is a string that specifies the font's encoding. 2091 * If the font's encoding could not be identified, NULL is returned. 2092 * 2093 * Side effects: 2094 * None. 2095 * 2096 *------------------------------------------------------------------------ 2097 */ 2098 2099static Tcl_Encoding 2100GetFontEncoding( 2101 int faceNum, /* Macintosh font number. */ 2102 int allowSymbol, /* If non-zero, then the encoding string 2103 * for symbol fonts will be the corresponding 2104 * symbol encoding. Otherwise, the encoding 2105 * string for symbol fonts will be 2106 * "macRoman". */ 2107 int *isSymbolPtr) /* Filled with non-zero if this font is a 2108 * symbol font, 0 otherwise. */ 2109{ 2110 Str255 faceName; 2111 int script, lang; 2112 char *name; 2113 2114 if (allowSymbol != 0) { 2115 GetFontName(faceNum, faceName); 2116 if (pstrcasecmp(faceName, "\psymbol") == 0) { 2117 *isSymbolPtr = 1; 2118 return Tcl_GetEncoding(NULL, "symbol"); 2119 } 2120 if (pstrcasecmp(faceName, "\pzapf dingbats") == 0) { 2121 *isSymbolPtr = 1; 2122 return Tcl_GetEncoding(NULL, "macDingbats"); 2123 } 2124 } 2125 *isSymbolPtr = 0; 2126 script = FontToScript(faceNum); 2127 lang = GetScriptVariable(script, smScriptLang); 2128 name = NULL; 2129 if (script == smRoman) { 2130 name = TkFindStateString(romanMap, lang); 2131 } else if (script == smCyrillic) { 2132 name = TkFindStateString(cyrillicMap, lang); 2133 } 2134 if (name == NULL) { 2135 name = TkFindStateString(scriptMap, script); 2136 } 2137 return Tcl_GetEncoding(NULL, name); 2138} 2139 2140/* 2141 *---------------------------------------------------------------------- 2142 * 2143 * TkMacOSXInitControlFontStyle -- 2144 * 2145 * This procedure sets up the appropriate ControlFontStyleRec 2146 * for a Mac control. 2147 * 2148 * Results: 2149 * None. 2150 * 2151 * Side effects: 2152 * None. 2153 * 2154 *---------------------------------------------------------------------- 2155 */ 2156 2157void 2158TkMacOSXInitControlFontStyle( 2159 Tk_Font tkfont, 2160 ControlFontStylePtr fsPtr) 2161{ 2162 MacFont *fontPtr = (MacFont *) tkfont; 2163 FontFamily *lastFamilyPtr = fontPtr->subFontArray[0].familyPtr; 2164 2165 fsPtr->flags = kControlUseFontMask | kControlUseSizeMask | 2166 kControlUseFaceMask | kControlUseJustMask; 2167 fsPtr->font = lastFamilyPtr->faceNum; 2168 fsPtr->size = fontPtr->size; 2169 fsPtr->style = fontPtr->style; 2170 fsPtr->just = teCenter; 2171} 2172 2173/* 2174 *---------------------------------------------------------------------- 2175 * 2176 * TkMacOSXUseAntialiasedText -- 2177 * 2178 * Enables or disables application-wide use of quickdraw 2179 * antialiased text (where available). 2180 * Sets up a linked tcl global boolean variable with write trace 2181 * to allow disabling of antialiased text from tcl. 2182 * 2183 * Results: 2184 * TCL_OK if facility was sucessfully enabled/disabled. 2185 * TCL_ERROR if an error occurred or if facility is not available. 2186 * 2187 * Side effects: 2188 * None. 2189 * 2190 *---------------------------------------------------------------------- 2191 */ 2192 2193static int TkMacOSXAntialiasedTextEnabled = FALSE; 2194 2195static char * 2196TkMacOSXAntialiasedTextVariableProc( 2197 ClientData clientData, 2198 Tcl_Interp *interp, 2199 const char *name1, 2200 const char *name2, 2201 int flags) 2202{ 2203 TkMacOSXUseAntialiasedText(interp, TkMacOSXAntialiasedTextEnabled); 2204 return (char *) NULL; 2205} 2206 2207int 2208TkMacOSXUseAntialiasedText( 2209 Tcl_Interp *interp, 2210 int enable) 2211{ 2212 static Boolean initialized = FALSE; 2213 static UInt32 (*swaptextflags)(UInt32) = NULL; 2214 2215 if(!initialized) { 2216 swaptextflags = TkMacOSXGetNamedSymbol("QD", "_QDSwapTextFlags"); 2217 if (!swaptextflags) { 2218 swaptextflags = TkMacOSXGetNamedSymbol("QD", "_SwapQDTextFlags"); 2219 } 2220 initialized = TRUE; 2221 2222 TkMacOSXAntialiasedTextEnabled = (swaptextflags ? enable : FALSE); 2223 if (Tcl_CreateNamespace(interp, "::tk::mac", NULL, NULL) == NULL) { 2224 Tcl_ResetResult(interp); 2225 } 2226 if (Tcl_TraceVar(interp, "::tk::mac::antialiasedtext", 2227 TCL_GLOBAL_ONLY | TCL_TRACE_WRITES, 2228 TkMacOSXAntialiasedTextVariableProc, NULL) != TCL_OK) { 2229 Tcl_ResetResult(interp); 2230 } 2231 if (Tcl_LinkVar(interp, "::tk::mac::antialiasedtext", 2232 (char *) &TkMacOSXAntialiasedTextEnabled, 2233 TCL_LINK_BOOLEAN) != TCL_OK) { 2234 Tcl_ResetResult(interp); 2235 } 2236 } 2237 if (swaptextflags) { 2238 swaptextflags(enable ? kQDUseCGTextRendering | kQDUseCGTextMetrics 2239 : kQDUseTrueTypeScalerGlyphs); 2240 TkMacOSXAntialiasedTextEnabled = enable; 2241 return TCL_OK; 2242 } else { 2243 TkMacOSXAntialiasedTextEnabled = FALSE; 2244 return TCL_ERROR; 2245 } 2246} 2247