1/* 2 * tkFont.c -- 3 * 4 * This file maintains a database of fonts for the Tk toolkit. 5 * It also provides several utility procedures for measuring and 6 * displaying text. 7 * 8 * Copyright (c) 1990-1994 The Regents of the University of California. 9 * Copyright (c) 1994-1998 Sun Microsystems, Inc. 10 * 11 * See the file "license.terms" for information on usage and redistribution 12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 * 14 * RCS: @(#) $Id: tkFont.c,v 1.21.2.2 2007/05/31 13:39:26 das Exp $ 15 */ 16 17#include "tkPort.h" 18#include "tkInt.h" 19#include "tkFont.h" 20 21/* 22 * The following structure is used to keep track of all the fonts that 23 * exist in the current application. It must be stored in the 24 * TkMainInfo for the application. 25 */ 26 27typedef struct TkFontInfo { 28 Tcl_HashTable fontCache; /* Map a string to an existing Tk_Font. 29 * Keys are string font names, values are 30 * TkFont pointers. */ 31 Tcl_HashTable namedTable; /* Map a name to a set of attributes for a 32 * font, used when constructing a Tk_Font from 33 * a named font description. Keys are 34 * strings, values are NamedFont pointers. */ 35 TkMainInfo *mainPtr; /* Application that owns this structure. */ 36 int updatePending; /* Non-zero when a World Changed event has 37 * already been queued to handle a change to 38 * a named font. */ 39} TkFontInfo; 40 41/* 42 * The following data structure is used to keep track of the font attributes 43 * for each named font that has been defined. The named font is only deleted 44 * when the last reference to it goes away. 45 */ 46 47typedef struct NamedFont { 48 int refCount; /* Number of users of named font. */ 49 int deletePending; /* Non-zero if font should be deleted when 50 * last reference goes away. */ 51 TkFontAttributes fa; /* Desired attributes for named font. */ 52} NamedFont; 53 54/* 55 * The following two structures are used to keep track of string 56 * measurement information when using the text layout facilities. 57 * 58 * A LayoutChunk represents a contiguous range of text that can be measured 59 * and displayed by low-level text calls. In general, chunks will be 60 * delimited by newlines and tabs. Low-level, platform-specific things 61 * like kerning and non-integer character widths may occur between the 62 * characters in a single chunk, but not between characters in different 63 * chunks. 64 * 65 * A TextLayout is a collection of LayoutChunks. It can be displayed with 66 * respect to any origin. It is the implementation of the Tk_TextLayout 67 * opaque token. 68 */ 69 70typedef struct LayoutChunk { 71 CONST char *start; /* Pointer to simple string to be displayed. 72 * This is a pointer into the TkTextLayout's 73 * string. */ 74 int numBytes; /* The number of bytes in this chunk. */ 75 int numChars; /* The number of characters in this chunk. */ 76 int numDisplayChars; /* The number of characters to display when 77 * this chunk is displayed. Can be less than 78 * numChars if extra space characters were 79 * absorbed by the end of the chunk. This 80 * will be < 0 if this is a chunk that is 81 * holding a tab or newline. */ 82 int x, y; /* The origin of the first character in this 83 * chunk with respect to the upper-left hand 84 * corner of the TextLayout. */ 85 int totalWidth; /* Width in pixels of this chunk. Used 86 * when hit testing the invisible spaces at 87 * the end of a chunk. */ 88 int displayWidth; /* Width in pixels of the displayable 89 * characters in this chunk. Can be less than 90 * width if extra space characters were 91 * absorbed by the end of the chunk. */ 92} LayoutChunk; 93 94typedef struct TextLayout { 95 Tk_Font tkfont; /* The font used when laying out the text. */ 96 CONST char *string; /* The string that was layed out. */ 97 int width; /* The maximum width of all lines in the 98 * text layout. */ 99 int numChunks; /* Number of chunks actually used in 100 * following array. */ 101 LayoutChunk chunks[1]; /* Array of chunks. The actual size will 102 * be maxChunks. THIS FIELD MUST BE THE LAST 103 * IN THE STRUCTURE. */ 104} TextLayout; 105 106/* 107 * The following structures are used as two-way maps between the values for 108 * the fields in the TkFontAttributes structure and the strings used in 109 * Tcl, when parsing both option-value format and style-list format font 110 * name strings. 111 */ 112 113static TkStateMap weightMap[] = { 114 {TK_FW_NORMAL, "normal"}, 115 {TK_FW_BOLD, "bold"}, 116 {TK_FW_UNKNOWN, NULL} 117}; 118 119static TkStateMap slantMap[] = { 120 {TK_FS_ROMAN, "roman"}, 121 {TK_FS_ITALIC, "italic"}, 122 {TK_FS_UNKNOWN, NULL} 123}; 124 125static TkStateMap underlineMap[] = { 126 {1, "underline"}, 127 {0, NULL} 128}; 129 130static TkStateMap overstrikeMap[] = { 131 {1, "overstrike"}, 132 {0, NULL} 133}; 134 135/* 136 * The following structures are used when parsing XLFD's into a set of 137 * TkFontAttributes. 138 */ 139 140static TkStateMap xlfdWeightMap[] = { 141 {TK_FW_NORMAL, "normal"}, 142 {TK_FW_NORMAL, "medium"}, 143 {TK_FW_NORMAL, "book"}, 144 {TK_FW_NORMAL, "light"}, 145 {TK_FW_BOLD, "bold"}, 146 {TK_FW_BOLD, "demi"}, 147 {TK_FW_BOLD, "demibold"}, 148 {TK_FW_NORMAL, NULL} /* Assume anything else is "normal". */ 149}; 150 151static TkStateMap xlfdSlantMap[] = { 152 {TK_FS_ROMAN, "r"}, 153 {TK_FS_ITALIC, "i"}, 154 {TK_FS_OBLIQUE, "o"}, 155 {TK_FS_ROMAN, NULL} /* Assume anything else is "roman". */ 156}; 157 158static TkStateMap xlfdSetwidthMap[] = { 159 {TK_SW_NORMAL, "normal"}, 160 {TK_SW_CONDENSE, "narrow"}, 161 {TK_SW_CONDENSE, "semicondensed"}, 162 {TK_SW_CONDENSE, "condensed"}, 163 {TK_SW_UNKNOWN, NULL} 164}; 165 166/* 167 * The following structure and defines specify the valid builtin options 168 * when configuring a set of font attributes. 169 */ 170 171static CONST char *fontOpt[] = { 172 "-family", 173 "-size", 174 "-weight", 175 "-slant", 176 "-underline", 177 "-overstrike", 178 NULL 179}; 180 181#define FONT_FAMILY 0 182#define FONT_SIZE 1 183#define FONT_WEIGHT 2 184#define FONT_SLANT 3 185#define FONT_UNDERLINE 4 186#define FONT_OVERSTRIKE 5 187#define FONT_NUMFIELDS 6 188 189/* 190 * Hardcoded font aliases. These are used to describe (mostly) identical 191 * fonts whose names differ from platform to platform. If the 192 * user-supplied font name matches any of the names in one of the alias 193 * lists, the other names in the alias list are also automatically tried. 194 */ 195 196static char *timesAliases[] = { 197 "Times", /* Unix. */ 198 "Times New Roman", /* Windows. */ 199 "New York", /* Mac. */ 200 NULL 201}; 202 203static char *helveticaAliases[] = { 204 "Helvetica", /* Unix. */ 205 "Arial", /* Windows. */ 206 "Geneva", /* Mac. */ 207 NULL 208}; 209 210static char *courierAliases[] = { 211 "Courier", /* Unix and Mac. */ 212 "Courier New", /* Windows. */ 213 NULL 214}; 215 216static char *minchoAliases[] = { 217 "mincho", /* Unix. */ 218 "\357\274\255\357\274\263 \346\230\216\346\234\235", 219 /* Windows (MS mincho). */ 220 "\346\234\254\346\230\216\346\234\235\342\210\222\357\274\255", 221 /* Mac (honmincho-M). */ 222 NULL 223}; 224 225static char *gothicAliases[] = { 226 "gothic", /* Unix. */ 227 "\357\274\255\357\274\263 \343\202\264\343\202\267\343\203\203\343\202\257", 228 /* Windows (MS goshikku). */ 229 "\344\270\270\343\202\264\343\202\267\343\203\203\343\202\257\342\210\222\357\274\255", 230 /* Mac (goshikku-M). */ 231 NULL 232}; 233 234static char *dingbatsAliases[] = { 235 "dingbats", "zapfdingbats", "itc zapfdingbats", 236 /* Unix. */ 237 /* Windows. */ 238 "zapf dingbats", /* Mac. */ 239 NULL 240}; 241 242static char **fontAliases[] = { 243 timesAliases, 244 helveticaAliases, 245 courierAliases, 246 minchoAliases, 247 gothicAliases, 248 dingbatsAliases, 249 NULL 250}; 251 252/* 253 * Hardcoded font classes. If the character cannot be found in the base 254 * font, the classes are examined in order to see if some other similar 255 * font should be examined also. 256 */ 257 258static char *systemClass[] = { 259 "fixed", /* Unix. */ 260 /* Windows. */ 261 "chicago", "osaka", "sistemny", /* Mac. */ 262 NULL 263}; 264 265static char *serifClass[] = { 266 "times", "palatino", "mincho", /* All platforms. */ 267 "song ti", /* Unix. */ 268 "ms serif", "simplified arabic", /* Windows. */ 269 "latinski", /* Mac. */ 270 NULL 271}; 272 273static char *sansClass[] = { 274 "helvetica", "gothic", /* All platforms. */ 275 /* Unix. */ 276 "ms sans serif", "traditional arabic", 277 /* Windows. */ 278 "bastion", /* Mac. */ 279 NULL 280}; 281 282static char *monoClass[] = { 283 "courier", "gothic", /* All platforms. */ 284 "fangsong ti", /* Unix. */ 285 "simplified arabic fixed", /* Windows. */ 286 "monaco", "pryamoy", /* Mac. */ 287 NULL 288}; 289 290static char *symbolClass[] = { 291 "symbol", "dingbats", "wingdings", NULL 292}; 293 294static char **fontFallbacks[] = { 295 systemClass, 296 serifClass, 297 sansClass, 298 monoClass, 299 symbolClass, 300 NULL 301}; 302 303/* 304 * Global fallbacks. If the character could not be found in the preferred 305 * fallback list, this list is examined. If the character still cannot be 306 * found, all font families in the system are examined. 307 */ 308 309static char *globalFontClass[] = { 310 "symbol", /* All platforms. */ 311 /* Unix. */ 312 "lucida sans unicode", /* Windows. */ 313 "bitstream cyberbit", /* Windows popular CJK font */ 314 "chicago", /* Mac. */ 315 NULL 316}; 317 318#define GetFontAttributes(tkfont) \ 319 ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa) 320 321#define GetFontMetrics(tkfont) \ 322 ((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm) 323 324 325static int ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp, 326 Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[], 327 TkFontAttributes *faPtr)); 328static int CreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp, 329 Tk_Window tkwin, CONST char *name, 330 TkFontAttributes *faPtr)); 331static void DupFontObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr, 332 Tcl_Obj *dupObjPtr)); 333static int FieldSpecified _ANSI_ARGS_((CONST char *field)); 334static void FreeFontObjProc _ANSI_ARGS_((Tcl_Obj *objPtr)); 335static int GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp, 336 CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr)); 337static LayoutChunk * NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr, 338 int *maxPtr, CONST char *start, int numChars, 339 int curX, int newX, int y)); 340static int ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp, 341 Tk_Window tkwin, Tcl_Obj *objPtr, 342 TkFontAttributes *faPtr)); 343static void RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr)); 344static int SetFontFromAny _ANSI_ARGS_((Tcl_Interp *interp, 345 Tcl_Obj *objPtr)); 346static void TheWorldHasChanged _ANSI_ARGS_(( 347 ClientData clientData)); 348static void UpdateDependentFonts _ANSI_ARGS_((TkFontInfo *fiPtr, 349 Tk_Window tkwin, Tcl_HashEntry *namedHashPtr)); 350 351/* 352 * The following structure defines the implementation of the "font" Tcl 353 * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of 354 * each font object points to the TkFont structure for the font, or 355 * NULL. 356 */ 357 358Tcl_ObjType tkFontObjType = { 359 "font", /* name */ 360 FreeFontObjProc, /* freeIntRepProc */ 361 DupFontObjProc, /* dupIntRepProc */ 362 NULL, /* updateStringProc */ 363 SetFontFromAny /* setFromAnyProc */ 364}; 365 366 367/* 368 *--------------------------------------------------------------------------- 369 * 370 * TkFontPkgInit -- 371 * 372 * This procedure is called when an application is created. It 373 * initializes all the structures that are used by the font 374 * package on a per application basis. 375 * 376 * Results: 377 * Stores a token in the mainPtr to hold information needed by this 378 * package on a per application basis. 379 * 380 * Side effects: 381 * Memory allocated. 382 * 383 *--------------------------------------------------------------------------- 384 */ 385void 386TkFontPkgInit(mainPtr) 387 TkMainInfo *mainPtr; /* The application being created. */ 388{ 389 TkFontInfo *fiPtr; 390 391 fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo)); 392 Tcl_InitHashTable(&fiPtr->fontCache, TCL_STRING_KEYS); 393 Tcl_InitHashTable(&fiPtr->namedTable, TCL_STRING_KEYS); 394 fiPtr->mainPtr = mainPtr; 395 fiPtr->updatePending = 0; 396 mainPtr->fontInfoPtr = fiPtr; 397 398 TkpFontPkgInit(mainPtr); 399} 400 401/* 402 *--------------------------------------------------------------------------- 403 * 404 * TkFontPkgFree -- 405 * 406 * This procedure is called when an application is deleted. It 407 * deletes all the structures that were used by the font package 408 * for this application. 409 * 410 * Results: 411 * None. 412 * 413 * Side effects: 414 * Memory freed. 415 * 416 *--------------------------------------------------------------------------- 417 */ 418 419void 420TkFontPkgFree(mainPtr) 421 TkMainInfo *mainPtr; /* The application being deleted. */ 422{ 423 TkFontInfo *fiPtr; 424 Tcl_HashEntry *hPtr, *searchPtr; 425 Tcl_HashSearch search; 426 int fontsLeft; 427 428 fiPtr = mainPtr->fontInfoPtr; 429 430 fontsLeft = 0; 431 for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); 432 searchPtr != NULL; 433 searchPtr = Tcl_NextHashEntry(&search)) { 434 fontsLeft++; 435#ifdef DEBUG_FONTS 436 fprintf(stderr, "Font %s still in cache.\n", 437 Tcl_GetHashKey(&fiPtr->fontCache, searchPtr)); 438#endif 439 } 440#ifdef PURIFY 441 if (fontsLeft) { 442 panic("TkFontPkgFree: all fonts should have been freed already"); 443 } 444#endif 445 Tcl_DeleteHashTable(&fiPtr->fontCache); 446 447 hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); 448 while (hPtr != NULL) { 449 ckfree((char *) Tcl_GetHashValue(hPtr)); 450 hPtr = Tcl_NextHashEntry(&search); 451 } 452 Tcl_DeleteHashTable(&fiPtr->namedTable); 453 if (fiPtr->updatePending != 0) { 454 Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr); 455 } 456 ckfree((char *) fiPtr); 457} 458 459/* 460 *--------------------------------------------------------------------------- 461 * 462 * Tk_FontObjCmd -- 463 * 464 * This procedure is implemented to process the "font" Tcl command. 465 * See the user documentation for details on what it does. 466 * 467 * Results: 468 * A standard Tcl result. 469 * 470 * Side effects: 471 * See the user documentation. 472 * 473 *---------------------------------------------------------------------- 474 */ 475 476int 477Tk_FontObjCmd(clientData, interp, objc, objv) 478 ClientData clientData; /* Main window associated with interpreter. */ 479 Tcl_Interp *interp; /* Current interpreter. */ 480 int objc; /* Number of arguments. */ 481 Tcl_Obj *CONST objv[]; /* Argument objects. */ 482{ 483 int index; 484 Tk_Window tkwin; 485 TkFontInfo *fiPtr; 486 static CONST char *optionStrings[] = { 487 "actual", "configure", "create", "delete", 488 "families", "measure", "metrics", "names", 489 NULL 490 }; 491 enum options { 492 FONT_ACTUAL, FONT_CONFIGURE, FONT_CREATE, FONT_DELETE, 493 FONT_FAMILIES, FONT_MEASURE, FONT_METRICS, FONT_NAMES 494 }; 495 496 tkwin = (Tk_Window) clientData; 497 fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; 498 499 if (objc < 2) { 500 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); 501 return TCL_ERROR; 502 } 503 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, 504 &index) != TCL_OK) { 505 return TCL_ERROR; 506 } 507 508 switch ((enum options) index) { 509 case FONT_ACTUAL: { 510 int skip, result; 511 Tk_Font tkfont; 512 Tcl_Obj *objPtr; 513 CONST TkFontAttributes *faPtr; 514 515 skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); 516 if (skip < 0) { 517 return TCL_ERROR; 518 } 519 if ((objc < 3) || (objc - skip > 4)) { 520 Tcl_WrongNumArgs(interp, 2, objv, 521 "font ?-displayof window? ?option?"); 522 return TCL_ERROR; 523 } 524 tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); 525 if (tkfont == NULL) { 526 return TCL_ERROR; 527 } 528 objc -= skip; 529 objv += skip; 530 faPtr = GetFontAttributes(tkfont); 531 objPtr = NULL; 532 if (objc > 3) { 533 objPtr = objv[3]; 534 } 535 result = GetAttributeInfoObj(interp, faPtr, objPtr); 536 Tk_FreeFont(tkfont); 537 return result; 538 } 539 case FONT_CONFIGURE: { 540 int result; 541 char *string; 542 Tcl_Obj *objPtr; 543 NamedFont *nfPtr; 544 Tcl_HashEntry *namedHashPtr; 545 546 if (objc < 3) { 547 Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?"); 548 return TCL_ERROR; 549 } 550 string = Tcl_GetString(objv[2]); 551 namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); 552 nfPtr = NULL; /* lint. */ 553 if (namedHashPtr != NULL) { 554 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); 555 } 556 if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) { 557 Tcl_AppendResult(interp, "named font \"", string, 558 "\" doesn't exist", NULL); 559 return TCL_ERROR; 560 } 561 if (objc == 3) { 562 objPtr = NULL; 563 } else if (objc == 4) { 564 objPtr = objv[3]; 565 } else { 566 result = ConfigAttributesObj(interp, tkwin, objc - 3, 567 objv + 3, &nfPtr->fa); 568 UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); 569 return result; 570 } 571 return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr); 572 } 573 case FONT_CREATE: { 574 int skip, i; 575 char *name; 576 char buf[16 + TCL_INTEGER_SPACE]; 577 TkFontAttributes fa; 578 Tcl_HashEntry *namedHashPtr; 579 580 skip = 3; 581 if (objc < 3) { 582 name = NULL; 583 } else { 584 name = Tcl_GetString(objv[2]); 585 if (name[0] == '-') { 586 name = NULL; 587 } 588 } 589 if (name == NULL) { 590 /* 591 * No font name specified. Generate one of the form "fontX". 592 */ 593 594 for (i = 1; ; i++) { 595 sprintf(buf, "font%d", i); 596 namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, buf); 597 if (namedHashPtr == NULL) { 598 break; 599 } 600 } 601 name = buf; 602 skip = 2; 603 } 604 TkInitFontAttributes(&fa); 605 if (ConfigAttributesObj(interp, tkwin, objc - skip, objv + skip, 606 &fa) != TCL_OK) { 607 return TCL_ERROR; 608 } 609 if (CreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) { 610 return TCL_ERROR; 611 } 612 Tcl_AppendResult(interp, name, NULL); 613 break; 614 } 615 case FONT_DELETE: { 616 int i; 617 char *string; 618 NamedFont *nfPtr; 619 Tcl_HashEntry *namedHashPtr; 620 621 /* 622 * Delete the named font. If there are still widgets using this 623 * font, then it isn't deleted right away. 624 */ 625 626 if (objc < 3) { 627 Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?"); 628 return TCL_ERROR; 629 } 630 for (i = 2; i < objc; i++) { 631 string = Tcl_GetString(objv[i]); 632 namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); 633 if (namedHashPtr == NULL) { 634 Tcl_AppendResult(interp, "named font \"", string, 635 "\" doesn't exist", (char *) NULL); 636 return TCL_ERROR; 637 } 638 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); 639 if (nfPtr->refCount != 0) { 640 nfPtr->deletePending = 1; 641 } else { 642 Tcl_DeleteHashEntry(namedHashPtr); 643 ckfree((char *) nfPtr); 644 } 645 } 646 break; 647 } 648 case FONT_FAMILIES: { 649 int skip; 650 651 skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); 652 if (skip < 0) { 653 return TCL_ERROR; 654 } 655 if (objc - skip != 2) { 656 Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?"); 657 return TCL_ERROR; 658 } 659 TkpGetFontFamilies(interp, tkwin); 660 break; 661 } 662 case FONT_MEASURE: { 663 char *string; 664 Tk_Font tkfont; 665 int length, skip; 666 Tcl_Obj *resultPtr; 667 668 skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); 669 if (skip < 0) { 670 return TCL_ERROR; 671 } 672 if (objc - skip != 4) { 673 Tcl_WrongNumArgs(interp, 2, objv, 674 "font ?-displayof window? text"); 675 return TCL_ERROR; 676 } 677 tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); 678 if (tkfont == NULL) { 679 return TCL_ERROR; 680 } 681 string = Tcl_GetStringFromObj(objv[3 + skip], &length); 682 resultPtr = Tcl_GetObjResult(interp); 683 Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length)); 684 Tk_FreeFont(tkfont); 685 break; 686 } 687 case FONT_METRICS: { 688 Tk_Font tkfont; 689 int skip, index, i; 690 CONST TkFontMetrics *fmPtr; 691 static CONST char *switches[] = { 692 "-ascent", "-descent", "-linespace", "-fixed", NULL 693 }; 694 695 skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); 696 if (skip < 0) { 697 return TCL_ERROR; 698 } 699 if ((objc < 3) || ((objc - skip) > 4)) { 700 Tcl_WrongNumArgs(interp, 2, objv, 701 "font ?-displayof window? ?option?"); 702 return TCL_ERROR; 703 } 704 tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); 705 if (tkfont == NULL) { 706 return TCL_ERROR; 707 } 708 objc -= skip; 709 objv += skip; 710 fmPtr = GetFontMetrics(tkfont); 711 if (objc == 3) { 712 char buf[64 + TCL_INTEGER_SPACE * 4]; 713 714 sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d", 715 fmPtr->ascent, fmPtr->descent, 716 fmPtr->ascent + fmPtr->descent, 717 fmPtr->fixed); 718 Tcl_AppendResult(interp, buf, NULL); 719 } else { 720 if (Tcl_GetIndexFromObj(interp, objv[3], switches, 721 "metric", 0, &index) != TCL_OK) { 722 Tk_FreeFont(tkfont); 723 return TCL_ERROR; 724 } 725 i = 0; /* Needed only to prevent compiler 726 * warning. */ 727 switch (index) { 728 case 0: i = fmPtr->ascent; break; 729 case 1: i = fmPtr->descent; break; 730 case 2: i = fmPtr->ascent + fmPtr->descent; break; 731 case 3: i = fmPtr->fixed; break; 732 } 733 Tcl_SetIntObj(Tcl_GetObjResult(interp), i); 734 } 735 Tk_FreeFont(tkfont); 736 break; 737 } 738 case FONT_NAMES: { 739 char *string; 740 NamedFont *nfPtr; 741 Tcl_HashSearch search; 742 Tcl_HashEntry *namedHashPtr; 743 Tcl_Obj *strPtr, *resultPtr; 744 745 if (objc != 2) { 746 Tcl_WrongNumArgs(interp, 1, objv, "names"); 747 return TCL_ERROR; 748 } 749 resultPtr = Tcl_GetObjResult(interp); 750 namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); 751 while (namedHashPtr != NULL) { 752 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); 753 if (nfPtr->deletePending == 0) { 754 string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr); 755 strPtr = Tcl_NewStringObj(string, -1); 756 Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); 757 } 758 namedHashPtr = Tcl_NextHashEntry(&search); 759 } 760 break; 761 } 762 } 763 return TCL_OK; 764} 765 766/* 767 *--------------------------------------------------------------------------- 768 * 769 * UpdateDependentFonts, TheWorldHasChanged, RecomputeWidgets -- 770 * 771 * Called when the attributes of a named font changes. Updates all 772 * the instantiated fonts that depend on that named font and then 773 * uses the brute force approach and prepares every widget to 774 * recompute its geometry. 775 * 776 * Results: 777 * None. 778 * 779 * Side effects: 780 * Things get queued for redisplay. 781 * 782 *--------------------------------------------------------------------------- 783 */ 784 785static void 786UpdateDependentFonts(fiPtr, tkwin, namedHashPtr) 787 TkFontInfo *fiPtr; /* Info about application's fonts. */ 788 Tk_Window tkwin; /* A window in the application. */ 789 Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */ 790{ 791 Tcl_HashEntry *cacheHashPtr; 792 Tcl_HashSearch search; 793 TkFont *fontPtr; 794 NamedFont *nfPtr; 795 796 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); 797 if (nfPtr->refCount == 0) { 798 /* 799 * Well nobody's using this named font, so don't have to tell 800 * any widgets to recompute themselves. 801 */ 802 803 return; 804 } 805 806 cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); 807 while (cacheHashPtr != NULL) { 808 for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); 809 fontPtr != NULL; fontPtr = fontPtr->nextPtr) { 810 if (fontPtr->namedHashPtr == namedHashPtr) { 811 TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa); 812 if (fiPtr->updatePending == 0) { 813 fiPtr->updatePending = 1; 814 Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr); 815 } 816 } 817 } 818 cacheHashPtr = Tcl_NextHashEntry(&search); 819 } 820} 821 822static void 823TheWorldHasChanged(clientData) 824 ClientData clientData; /* Info about application's fonts. */ 825{ 826 TkFontInfo *fiPtr; 827 828 fiPtr = (TkFontInfo *) clientData; 829 fiPtr->updatePending = 0; 830 831 RecomputeWidgets(fiPtr->mainPtr->winPtr); 832} 833 834static void 835RecomputeWidgets(winPtr) 836 TkWindow *winPtr; /* Window to which command is sent. */ 837{ 838 Tk_ClassWorldChangedProc *proc; 839 proc = Tk_GetClassProc(winPtr->classProcsPtr, worldChangedProc); 840 if (proc != NULL) { 841 (*proc)(winPtr->instanceData); 842 } 843 844 /* 845 * Notify all the descendants of this window that the world has changed. 846 * 847 * This could be done recursively or iteratively. The recursive version 848 * is easier to implement and understand, and typically, windows with a 849 * -font option will be leaf nodes in the widget heirarchy (buttons, 850 * labels, etc.), so the recursion depth will be shallow. 851 * 852 * However, the additional overhead of the recursive calls may become 853 * a performance problem if typical usage alters such that -font'ed widgets 854 * appear high in the heirarchy, causing deep recursion. This could happen 855 * with text widgets, or more likely with the (not yet existant) labeled 856 * frame widget. With these widgets it is possible, even likely, that a 857 * -font'ed widget (text or labeled frame) will not be a leaf node, but 858 * will instead have many descendants. If this is ever found to cause 859 * a performance problem, it may be worth investigating an iterative 860 * version of the code below. 861 */ 862 for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) { 863 RecomputeWidgets(winPtr); 864 } 865} 866 867/* 868 *--------------------------------------------------------------------------- 869 * 870 * CreateNamedFont -- 871 * 872 * Create the specified named font with the given attributes in the 873 * named font table associated with the interp. 874 * 875 * Results: 876 * Returns TCL_OK if the font was successfully created, or TCL_ERROR 877 * if the named font already existed. If TCL_ERROR is returned, an 878 * error message is left in the interp's result. 879 * 880 * Side effects: 881 * Assume there used to exist a named font by the specified name, and 882 * that the named font had been deleted, but there were still some 883 * widgets using the named font at the time it was deleted. If a 884 * new named font is created with the same name, all those widgets 885 * that were using the old named font will be redisplayed using 886 * the new named font's attributes. 887 * 888 *--------------------------------------------------------------------------- 889 */ 890 891static int 892CreateNamedFont(interp, tkwin, name, faPtr) 893 Tcl_Interp *interp; /* Interp for error return. */ 894 Tk_Window tkwin; /* A window associated with interp. */ 895 CONST char *name; /* Name for the new named font. */ 896 TkFontAttributes *faPtr; /* Attributes for the new named font. */ 897{ 898 TkFontInfo *fiPtr; 899 Tcl_HashEntry *namedHashPtr; 900 int new; 901 NamedFont *nfPtr; 902 903 fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; 904 905 namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new); 906 907 if (new == 0) { 908 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); 909 if (nfPtr->deletePending == 0) { 910 Tcl_ResetResult(interp); 911 Tcl_AppendResult(interp, "named font \"", name, 912 "\" already exists", (char *) NULL); 913 return TCL_ERROR; 914 } 915 916 /* 917 * Recreating a named font with the same name as a previous 918 * named font. Some widgets were still using that named 919 * font, so they need to get redisplayed. 920 */ 921 922 nfPtr->fa = *faPtr; 923 nfPtr->deletePending = 0; 924 UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); 925 return TCL_OK; 926 } 927 928 nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont)); 929 nfPtr->deletePending = 0; 930 Tcl_SetHashValue(namedHashPtr, nfPtr); 931 nfPtr->fa = *faPtr; 932 nfPtr->refCount = 0; 933 nfPtr->deletePending = 0; 934 return TCL_OK; 935} 936 937/* 938 *--------------------------------------------------------------------------- 939 * 940 * Tk_GetFont -- 941 * 942 * Given a string description of a font, map the description to a 943 * corresponding Tk_Font that represents the font. 944 * 945 * Results: 946 * The return value is token for the font, or NULL if an error 947 * prevented the font from being created. If NULL is returned, an 948 * error message will be left in the interp's result. 949 * 950 * Side effects: 951 * The font is added to an internal database with a reference 952 * count. For each call to this procedure, there should eventually 953 * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the 954 * database is cleaned up when fonts aren't in use anymore. 955 * 956 *--------------------------------------------------------------------------- 957 */ 958 959Tk_Font 960Tk_GetFont(interp, tkwin, string) 961 Tcl_Interp *interp; /* Interp for database and error return, or 962 * NULL for no error messages. */ 963 Tk_Window tkwin; /* For display on which font will be used. */ 964 CONST char *string; /* String describing font, as: named font, 965 * native format, or parseable string. */ 966{ 967 Tk_Font tkfont; 968 Tcl_Obj *strPtr; 969 970 strPtr = Tcl_NewStringObj((char *) string, -1); 971 Tcl_IncrRefCount(strPtr); 972 tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr); 973 Tcl_DecrRefCount(strPtr); 974 return tkfont; 975} 976 977/* 978 *--------------------------------------------------------------------------- 979 * 980 * Tk_AllocFontFromObj -- 981 * 982 * Given a string description of a font, map the description to a 983 * corresponding Tk_Font that represents the font. 984 * 985 * Results: 986 * The return value is token for the font, or NULL if an error 987 * prevented the font from being created. If NULL is returned, an 988 * error message will be left in interp's result object (if non-NULL). 989 * 990 * Side effects: 991 * The font is added to an internal database with a reference 992 * count. For each call to this procedure, there should eventually 993 * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the 994 * database is cleaned up when fonts aren't in use anymore. 995 * 996 *--------------------------------------------------------------------------- 997 */ 998 999Tk_Font 1000Tk_AllocFontFromObj(interp, tkwin, objPtr) 1001 Tcl_Interp *interp; /* Interp for database and error return. */ 1002 Tk_Window tkwin; /* For screen on which font will be used. */ 1003 Tcl_Obj *objPtr; /* Object describing font, as: named font, 1004 * native format, or parseable string. */ 1005{ 1006 TkFontInfo *fiPtr; 1007 Tcl_HashEntry *cacheHashPtr, *namedHashPtr; 1008 TkFont *fontPtr, *firstFontPtr, *oldFontPtr; 1009 int new, descent; 1010 NamedFont *nfPtr; 1011 1012 fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; 1013 if (objPtr->typePtr != &tkFontObjType) { 1014 SetFontFromAny(interp, objPtr); 1015 } 1016 1017 oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; 1018 1019 if (oldFontPtr != NULL) { 1020 if (oldFontPtr->resourceRefCount == 0) { 1021 /* 1022 * This is a stale reference: it refers to a TkFont that's 1023 * no longer in use. Clear the reference. 1024 */ 1025 1026 FreeFontObjProc(objPtr); 1027 oldFontPtr = NULL; 1028 } else if (Tk_Screen(tkwin) == oldFontPtr->screen) { 1029 oldFontPtr->resourceRefCount++; 1030 return (Tk_Font) oldFontPtr; 1031 } 1032 } 1033 1034 /* 1035 * Next, search the list of fonts that have the name we want, to see 1036 * if one of them is for the right screen. 1037 */ 1038 1039 new = 0; 1040 if (oldFontPtr != NULL) { 1041 cacheHashPtr = oldFontPtr->cacheHashPtr; 1042 FreeFontObjProc(objPtr); 1043 } else { 1044 cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, 1045 Tcl_GetString(objPtr), &new); 1046 } 1047 firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); 1048 for (fontPtr = firstFontPtr; (fontPtr != NULL); 1049 fontPtr = fontPtr->nextPtr) { 1050 if (Tk_Screen(tkwin) == fontPtr->screen) { 1051 fontPtr->resourceRefCount++; 1052 fontPtr->objRefCount++; 1053 objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; 1054 return (Tk_Font) fontPtr; 1055 } 1056 } 1057 1058 /* 1059 * The desired font isn't in the table. Make a new one. 1060 */ 1061 1062 namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, 1063 Tcl_GetString(objPtr)); 1064 if (namedHashPtr != NULL) { 1065 /* 1066 * Construct a font based on a named font. 1067 */ 1068 1069 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); 1070 nfPtr->refCount++; 1071 1072 fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa); 1073 } else { 1074 /* 1075 * Native font? 1076 */ 1077 1078 fontPtr = TkpGetNativeFont(tkwin, Tcl_GetString(objPtr)); 1079 if (fontPtr == NULL) { 1080 TkFontAttributes fa; 1081 Tcl_Obj *dupObjPtr = Tcl_DuplicateObj(objPtr); 1082 1083 if (ParseFontNameObj(interp, tkwin, dupObjPtr, &fa) != TCL_OK) { 1084 if (new) { 1085 Tcl_DeleteHashEntry(cacheHashPtr); 1086 } 1087 Tcl_DecrRefCount(dupObjPtr); 1088 return NULL; 1089 } 1090 Tcl_DecrRefCount(dupObjPtr); 1091 1092 /* 1093 * String contained the attributes inline. 1094 */ 1095 1096 fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa); 1097 } 1098 } 1099 1100 fontPtr->resourceRefCount = 1; 1101 fontPtr->objRefCount = 1; 1102 fontPtr->cacheHashPtr = cacheHashPtr; 1103 fontPtr->namedHashPtr = namedHashPtr; 1104 fontPtr->screen = Tk_Screen(tkwin); 1105 fontPtr->nextPtr = firstFontPtr; 1106 Tcl_SetHashValue(cacheHashPtr, fontPtr); 1107 1108 Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, -1, 0, &fontPtr->tabWidth); 1109 if (fontPtr->tabWidth == 0) { 1110 fontPtr->tabWidth = fontPtr->fm.maxWidth; 1111 } 1112 fontPtr->tabWidth *= 8; 1113 1114 /* 1115 * Make sure the tab width isn't zero (some fonts may not have enough 1116 * information to set a reasonable tab width). 1117 */ 1118 1119 if (fontPtr->tabWidth == 0) { 1120 fontPtr->tabWidth = 1; 1121 } 1122 1123 /* 1124 * Get information used for drawing underlines in generic code on a 1125 * non-underlined font. 1126 */ 1127 1128 descent = fontPtr->fm.descent; 1129 fontPtr->underlinePos = descent / 2; 1130 fontPtr->underlineHeight = TkFontGetPixels(tkwin, fontPtr->fa.size) / 10; 1131 if (fontPtr->underlineHeight == 0) { 1132 fontPtr->underlineHeight = 1; 1133 } 1134 if (fontPtr->underlinePos + fontPtr->underlineHeight > descent) { 1135 /* 1136 * If this set of values would cause the bottom of the underline 1137 * bar to stick below the descent of the font, jack the underline 1138 * up a bit higher. 1139 */ 1140 1141 fontPtr->underlineHeight = descent - fontPtr->underlinePos; 1142 if (fontPtr->underlineHeight == 0) { 1143 fontPtr->underlinePos--; 1144 fontPtr->underlineHeight = 1; 1145 } 1146 } 1147 1148 objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; 1149 return (Tk_Font) fontPtr; 1150} 1151 1152/* 1153 *---------------------------------------------------------------------- 1154 * 1155 * Tk_GetFontFromObj -- 1156 * 1157 * Find the font that corresponds to a given object. The font must 1158 * have already been created by Tk_GetFont or Tk_AllocFontFromObj. 1159 * 1160 * Results: 1161 * The return value is a token for the font that matches objPtr 1162 * and is suitable for use in tkwin. 1163 * 1164 * Side effects: 1165 * If the object is not already a font ref, the conversion will free 1166 * any old internal representation. 1167 * 1168 *---------------------------------------------------------------------- 1169 */ 1170 1171Tk_Font 1172Tk_GetFontFromObj(tkwin, objPtr) 1173 Tk_Window tkwin; /* The window that the font will be used in. */ 1174 Tcl_Obj *objPtr; /* The object from which to get the font. */ 1175{ 1176 TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; 1177 TkFont *fontPtr; 1178 Tcl_HashEntry *hashPtr; 1179 1180 if (objPtr->typePtr != &tkFontObjType) { 1181 SetFontFromAny((Tcl_Interp *) NULL, objPtr); 1182 } 1183 1184 fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; 1185 1186 if (fontPtr != NULL) { 1187 if (fontPtr->resourceRefCount == 0) { 1188 /* 1189 * This is a stale reference: it refers to a TkFont that's 1190 * no longer in use. Clear the reference. 1191 */ 1192 1193 FreeFontObjProc(objPtr); 1194 fontPtr = NULL; 1195 } else if (Tk_Screen(tkwin) == fontPtr->screen) { 1196 return (Tk_Font) fontPtr; 1197 } 1198 } 1199 1200 /* 1201 * Next, search the list of fonts that have the name we want, to see 1202 * if one of them is for the right screen. 1203 */ 1204 1205 if (fontPtr != NULL) { 1206 hashPtr = fontPtr->cacheHashPtr; 1207 FreeFontObjProc(objPtr); 1208 } else { 1209 hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr)); 1210 } 1211 if (hashPtr != NULL) { 1212 for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL; 1213 fontPtr = fontPtr->nextPtr) { 1214 if (Tk_Screen(tkwin) == fontPtr->screen) { 1215 fontPtr->objRefCount++; 1216 objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; 1217 return (Tk_Font) fontPtr; 1218 } 1219 } 1220 } 1221 1222 panic("Tk_GetFontFromObj called with non-existent font!"); 1223 return NULL; 1224} 1225 1226/* 1227 *---------------------------------------------------------------------- 1228 * 1229 * SetFontFromAny -- 1230 * 1231 * Convert the internal representation of a Tcl object to the 1232 * font internal form. 1233 * 1234 * Results: 1235 * Always returns TCL_OK. 1236 * 1237 * Side effects: 1238 * The object is left with its typePtr pointing to tkFontObjType. 1239 * The TkFont pointer is NULL. 1240 * 1241 *---------------------------------------------------------------------- 1242 */ 1243 1244static int 1245SetFontFromAny(interp, objPtr) 1246 Tcl_Interp *interp; /* Used for error reporting if not NULL. */ 1247 Tcl_Obj *objPtr; /* The object to convert. */ 1248{ 1249 Tcl_ObjType *typePtr; 1250 1251 /* 1252 * Free the old internalRep before setting the new one. 1253 */ 1254 1255 Tcl_GetString(objPtr); 1256 typePtr = objPtr->typePtr; 1257 if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { 1258 (*typePtr->freeIntRepProc)(objPtr); 1259 } 1260 objPtr->typePtr = &tkFontObjType; 1261 objPtr->internalRep.twoPtrValue.ptr1 = NULL; 1262 1263 return TCL_OK; 1264} 1265 1266/* 1267 *--------------------------------------------------------------------------- 1268 * 1269 * Tk_NameOfFont -- 1270 * 1271 * Given a font, return a textual string identifying it. 1272 * 1273 * Results: 1274 * The return value is the description that was passed to 1275 * Tk_GetFont() to create the font. The storage for the returned 1276 * string is only guaranteed to persist until the font is deleted. 1277 * The caller should not modify this string. 1278 * 1279 * Side effects: 1280 * None. 1281 * 1282 *--------------------------------------------------------------------------- 1283 */ 1284 1285CONST char * 1286Tk_NameOfFont(tkfont) 1287 Tk_Font tkfont; /* Font whose name is desired. */ 1288{ 1289 TkFont *fontPtr; 1290 1291 fontPtr = (TkFont *) tkfont; 1292 return fontPtr->cacheHashPtr->key.string; 1293} 1294 1295/* 1296 *--------------------------------------------------------------------------- 1297 * 1298 * Tk_FreeFont -- 1299 * 1300 * Called to release a font allocated by Tk_GetFont(). 1301 * 1302 * Results: 1303 * None. 1304 * 1305 * Side effects: 1306 * The reference count associated with font is decremented, and 1307 * only deallocated when no one is using it. 1308 * 1309 *--------------------------------------------------------------------------- 1310 */ 1311 1312void 1313Tk_FreeFont(tkfont) 1314 Tk_Font tkfont; /* Font to be released. */ 1315{ 1316 TkFont *fontPtr, *prevPtr; 1317 NamedFont *nfPtr; 1318 1319 if (tkfont == NULL) { 1320 return; 1321 } 1322 fontPtr = (TkFont *) tkfont; 1323 fontPtr->resourceRefCount--; 1324 if (fontPtr->resourceRefCount > 0) { 1325 return; 1326 } 1327 if (fontPtr->namedHashPtr != NULL) { 1328 /* 1329 * This font derived from a named font. Reduce the reference 1330 * count on the named font and free it if no-one else is 1331 * using it. 1332 */ 1333 1334 nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr); 1335 nfPtr->refCount--; 1336 if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) { 1337 Tcl_DeleteHashEntry(fontPtr->namedHashPtr); 1338 ckfree((char *) nfPtr); 1339 } 1340 } 1341 1342 prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr); 1343 if (prevPtr == fontPtr) { 1344 if (fontPtr->nextPtr == NULL) { 1345 Tcl_DeleteHashEntry(fontPtr->cacheHashPtr); 1346 } else { 1347 Tcl_SetHashValue(fontPtr->cacheHashPtr, fontPtr->nextPtr); 1348 } 1349 } else { 1350 while (prevPtr->nextPtr != fontPtr) { 1351 prevPtr = prevPtr->nextPtr; 1352 } 1353 prevPtr->nextPtr = fontPtr->nextPtr; 1354 } 1355 1356 TkpDeleteFont(fontPtr); 1357 if (fontPtr->objRefCount == 0) { 1358 ckfree((char *) fontPtr); 1359 } 1360} 1361 1362/* 1363 *--------------------------------------------------------------------------- 1364 * 1365 * Tk_FreeFontFromObj -- 1366 * 1367 * Called to release a font inside a Tcl_Obj *. Decrements the refCount 1368 * of the font and removes it from the hash tables if necessary. 1369 * 1370 * Results: 1371 * None. 1372 * 1373 * Side effects: 1374 * The reference count associated with font is decremented, and 1375 * only deallocated when no one is using it. 1376 * 1377 *--------------------------------------------------------------------------- 1378 */ 1379 1380void 1381Tk_FreeFontFromObj(tkwin, objPtr) 1382 Tk_Window tkwin; /* The window this font lives in. Needed 1383 * for the screen value. */ 1384 Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */ 1385{ 1386 Tk_FreeFont(Tk_GetFontFromObj(tkwin, objPtr)); 1387} 1388 1389/* 1390 *--------------------------------------------------------------------------- 1391 * 1392 * FreeFontObjProc -- 1393 * 1394 * This proc is called to release an object reference to a font. 1395 * Called when the object's internal rep is released or when 1396 * the cached fontPtr needs to be changed. 1397 * 1398 * Results: 1399 * None. 1400 * 1401 * Side effects: 1402 * The object reference count is decremented. When both it 1403 * and the hash ref count go to zero, the font's resources 1404 * are released. 1405 * 1406 *--------------------------------------------------------------------------- 1407 */ 1408 1409static void 1410FreeFontObjProc(objPtr) 1411 Tcl_Obj *objPtr; /* The object we are releasing. */ 1412{ 1413 TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; 1414 1415 if (fontPtr != NULL) { 1416 fontPtr->objRefCount--; 1417 if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) { 1418 ckfree((char *) fontPtr); 1419 objPtr->internalRep.twoPtrValue.ptr1 = NULL; 1420 } 1421 } 1422} 1423 1424/* 1425 *--------------------------------------------------------------------------- 1426 * 1427 * DupFontObjProc -- 1428 * 1429 * When a cached font object is duplicated, this is called to 1430 * update the internal reps. 1431 * 1432 * Results: 1433 * None. 1434 * 1435 * Side effects: 1436 * The font's objRefCount is incremented and the internal rep 1437 * of the copy is set to point to it. 1438 * 1439 *--------------------------------------------------------------------------- 1440 */ 1441 1442static void 1443DupFontObjProc(srcObjPtr, dupObjPtr) 1444 Tcl_Obj *srcObjPtr; /* The object we are copying from. */ 1445 Tcl_Obj *dupObjPtr; /* The object we are copying to. */ 1446{ 1447 TkFont *fontPtr = (TkFont *) srcObjPtr->internalRep.twoPtrValue.ptr1; 1448 1449 dupObjPtr->typePtr = srcObjPtr->typePtr; 1450 dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; 1451 1452 if (fontPtr != NULL) { 1453 fontPtr->objRefCount++; 1454 } 1455} 1456 1457/* 1458 *--------------------------------------------------------------------------- 1459 * 1460 * Tk_FontId -- 1461 * 1462 * Given a font, return an opaque handle that should be selected 1463 * into the XGCValues structure in order to get the constructed 1464 * gc to use this font. This procedure would go away if the 1465 * XGCValues structure were replaced with a TkGCValues structure. 1466 * 1467 * Results: 1468 * As above. 1469 * 1470 * Side effects: 1471 * None. 1472 * 1473 *--------------------------------------------------------------------------- 1474 */ 1475 1476Font 1477Tk_FontId(tkfont) 1478 Tk_Font tkfont; /* Font that is going to be selected into GC. */ 1479{ 1480 TkFont *fontPtr; 1481 1482 fontPtr = (TkFont *) tkfont; 1483 return fontPtr->fid; 1484} 1485 1486/* 1487 *--------------------------------------------------------------------------- 1488 * 1489 * Tk_GetFontMetrics -- 1490 * 1491 * Returns overall ascent and descent metrics for the given font. 1492 * These values can be used to space multiple lines of text and 1493 * to align the baselines of text in different fonts. 1494 * 1495 * Results: 1496 * If *heightPtr is non-NULL, it is filled with the overall height 1497 * of the font, which is the sum of the ascent and descent. 1498 * If *ascentPtr or *descentPtr is non-NULL, they are filled with 1499 * the ascent and/or descent information for the font. 1500 * 1501 * Side effects: 1502 * None. 1503 * 1504 *--------------------------------------------------------------------------- 1505 */ 1506void 1507Tk_GetFontMetrics(tkfont, fmPtr) 1508 Tk_Font tkfont; /* Font in which metrics are calculated. */ 1509 Tk_FontMetrics *fmPtr; /* Pointer to structure in which font 1510 * metrics for tkfont will be stored. */ 1511{ 1512 TkFont *fontPtr; 1513 1514 fontPtr = (TkFont *) tkfont; 1515 fmPtr->ascent = fontPtr->fm.ascent; 1516 fmPtr->descent = fontPtr->fm.descent; 1517 fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent; 1518} 1519 1520/* 1521 *--------------------------------------------------------------------------- 1522 * 1523 * Tk_PostscriptFontName -- 1524 * 1525 * Given a Tk_Font, return the name of the corresponding Postscript 1526 * font. 1527 * 1528 * Results: 1529 * The return value is the pointsize of the given Tk_Font. 1530 * The name of the Postscript font is appended to dsPtr. 1531 * 1532 * Side effects: 1533 * If the font does not exist on the printer, the print job will 1534 * fail at print time. Given a "reasonable" Postscript printer, 1535 * the following Tk_Font font families should print correctly: 1536 * 1537 * Avant Garde, Arial, Bookman, Courier, Courier New, Geneva, 1538 * Helvetica, Monaco, New Century Schoolbook, New York, 1539 * Palatino, Symbol, Times, Times New Roman, Zapf Chancery, 1540 * and Zapf Dingbats. 1541 * 1542 * Any other Tk_Font font families may not print correctly 1543 * because the computed Postscript font name may be incorrect. 1544 * 1545 *--------------------------------------------------------------------------- 1546 */ 1547 1548int 1549Tk_PostscriptFontName(tkfont, dsPtr) 1550 Tk_Font tkfont; /* Font in which text will be printed. */ 1551 Tcl_DString *dsPtr; /* Pointer to an initialized Tcl_DString to 1552 * which the name of the Postscript font that 1553 * corresponds to tkfont will be appended. */ 1554{ 1555 TkFont *fontPtr; 1556 Tk_Uid family, weightString, slantString; 1557 char *src, *dest; 1558 int upper, len; 1559 1560 len = Tcl_DStringLength(dsPtr); 1561 fontPtr = (TkFont *) tkfont; 1562 1563 /* 1564 * Convert the case-insensitive Tk_Font family name to the 1565 * case-sensitive Postscript family name. Take out any spaces and 1566 * capitalize the first letter of each word. 1567 */ 1568 1569 family = fontPtr->fa.family; 1570 if (strncasecmp(family, "itc ", 4) == 0) { 1571 family = family + 4; 1572 } 1573 if ((strcasecmp(family, "Arial") == 0) 1574 || (strcasecmp(family, "Geneva") == 0)) { 1575 family = "Helvetica"; 1576 } else if ((strcasecmp(family, "Times New Roman") == 0) 1577 || (strcasecmp(family, "New York") == 0)) { 1578 family = "Times"; 1579 } else if ((strcasecmp(family, "Courier New") == 0) 1580 || (strcasecmp(family, "Monaco") == 0)) { 1581 family = "Courier"; 1582 } else if (strcasecmp(family, "AvantGarde") == 0) { 1583 family = "AvantGarde"; 1584 } else if (strcasecmp(family, "ZapfChancery") == 0) { 1585 family = "ZapfChancery"; 1586 } else if (strcasecmp(family, "ZapfDingbats") == 0) { 1587 family = "ZapfDingbats"; 1588 } else { 1589 Tcl_UniChar ch; 1590 1591 /* 1592 * Inline, capitalize the first letter of each word, lowercase the 1593 * rest of the letters in each word, and then take out the spaces 1594 * between the words. This may make the DString shorter, which is 1595 * safe to do. 1596 */ 1597 1598 Tcl_DStringAppend(dsPtr, family, -1); 1599 1600 src = dest = Tcl_DStringValue(dsPtr) + len; 1601 upper = 1; 1602 for (; *src != '\0'; ) { 1603 while (isspace(UCHAR(*src))) { /* INTL: ISO space */ 1604 src++; 1605 upper = 1; 1606 } 1607 src += Tcl_UtfToUniChar(src, &ch); 1608 if (upper) { 1609 ch = Tcl_UniCharToUpper(ch); 1610 upper = 0; 1611 } else { 1612 ch = Tcl_UniCharToLower(ch); 1613 } 1614 dest += Tcl_UniCharToUtf(ch, dest); 1615 } 1616 *dest = '\0'; 1617 Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr)); 1618 family = Tcl_DStringValue(dsPtr) + len; 1619 } 1620 if (family != Tcl_DStringValue(dsPtr) + len) { 1621 Tcl_DStringAppend(dsPtr, family, -1); 1622 family = Tcl_DStringValue(dsPtr) + len; 1623 } 1624 1625 if (strcasecmp(family, "NewCenturySchoolbook") == 0) { 1626 Tcl_DStringSetLength(dsPtr, len); 1627 Tcl_DStringAppend(dsPtr, "NewCenturySchlbk", -1); 1628 family = Tcl_DStringValue(dsPtr) + len; 1629 } 1630 1631 /* 1632 * Get the string to use for the weight. 1633 */ 1634 1635 weightString = NULL; 1636 if (fontPtr->fa.weight == TK_FW_NORMAL) { 1637 if (strcmp(family, "Bookman") == 0) { 1638 weightString = "Light"; 1639 } else if (strcmp(family, "AvantGarde") == 0) { 1640 weightString = "Book"; 1641 } else if (strcmp(family, "ZapfChancery") == 0) { 1642 weightString = "Medium"; 1643 } 1644 } else { 1645 if ((strcmp(family, "Bookman") == 0) 1646 || (strcmp(family, "AvantGarde") == 0)) { 1647 weightString = "Demi"; 1648 } else { 1649 weightString = "Bold"; 1650 } 1651 } 1652 1653 /* 1654 * Get the string to use for the slant. 1655 */ 1656 1657 slantString = NULL; 1658 if (fontPtr->fa.slant == TK_FS_ROMAN) { 1659 ; 1660 } else { 1661 if ((strcmp(family, "Helvetica") == 0) 1662 || (strcmp(family, "Courier") == 0) 1663 || (strcmp(family, "AvantGarde") == 0)) { 1664 slantString = "Oblique"; 1665 } else { 1666 slantString = "Italic"; 1667 } 1668 } 1669 1670 /* 1671 * The string "Roman" needs to be added to some fonts that are not bold 1672 * and not italic. 1673 */ 1674 1675 if ((slantString == NULL) && (weightString == NULL)) { 1676 if ((strcmp(family, "Times") == 0) 1677 || (strcmp(family, "NewCenturySchlbk") == 0) 1678 || (strcmp(family, "Palatino") == 0)) { 1679 Tcl_DStringAppend(dsPtr, "-Roman", -1); 1680 } 1681 } else { 1682 Tcl_DStringAppend(dsPtr, "-", -1); 1683 if (weightString != NULL) { 1684 Tcl_DStringAppend(dsPtr, weightString, -1); 1685 } 1686 if (slantString != NULL) { 1687 Tcl_DStringAppend(dsPtr, slantString, -1); 1688 } 1689 } 1690 1691 return fontPtr->fa.size; 1692} 1693 1694/* 1695 *--------------------------------------------------------------------------- 1696 * 1697 * Tk_TextWidth -- 1698 * 1699 * A wrapper function for the more complicated interface of 1700 * Tk_MeasureChars. Computes how much space the given 1701 * simple string needs. 1702 * 1703 * Results: 1704 * The return value is the width (in pixels) of the given string. 1705 * 1706 * Side effects: 1707 * None. 1708 * 1709 *--------------------------------------------------------------------------- 1710 */ 1711 1712int 1713Tk_TextWidth(tkfont, string, numBytes) 1714 Tk_Font tkfont; /* Font in which text will be measured. */ 1715 CONST char *string; /* String whose width will be computed. */ 1716 int numBytes; /* Number of bytes to consider from 1717 * string, or < 0 for strlen(). */ 1718{ 1719 int width; 1720 1721 if (numBytes < 0) { 1722 numBytes = strlen(string); 1723 } 1724 Tk_MeasureChars(tkfont, string, numBytes, -1, 0, &width); 1725 return width; 1726} 1727 1728/* 1729 *--------------------------------------------------------------------------- 1730 * 1731 * Tk_UnderlineChars -- 1732 * 1733 * This procedure draws an underline for a given range of characters 1734 * in a given string. It doesn't draw the characters (which are 1735 * assumed to have been displayed previously); it just draws the 1736 * underline. This procedure would mainly be used to quickly 1737 * underline a few characters without having to construct an 1738 * underlined font. To produce properly underlined text, the 1739 * appropriate underlined font should be constructed and used. 1740 * 1741 * Results: 1742 * None. 1743 * 1744 * Side effects: 1745 * Information gets displayed in "drawable". 1746 * 1747 *---------------------------------------------------------------------- 1748 */ 1749 1750void 1751Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstByte, 1752 lastByte) 1753 Display *display; /* Display on which to draw. */ 1754 Drawable drawable; /* Window or pixmap in which to draw. */ 1755 GC gc; /* Graphics context for actually drawing 1756 * line. */ 1757 Tk_Font tkfont; /* Font used in GC; must have been allocated 1758 * by Tk_GetFont(). Used for character 1759 * dimensions, etc. */ 1760 CONST char *string; /* String containing characters to be 1761 * underlined or overstruck. */ 1762 int x, y; /* Coordinates at which first character of 1763 * string is drawn. */ 1764 int firstByte; /* Index of first byte of first character. */ 1765 int lastByte; /* Index of first byte after the last 1766 * character. */ 1767{ 1768 TkFont *fontPtr; 1769 int startX, endX; 1770 1771 fontPtr = (TkFont *) tkfont; 1772 1773 Tk_MeasureChars(tkfont, string, firstByte, -1, 0, &startX); 1774 Tk_MeasureChars(tkfont, string, lastByte, -1, 0, &endX); 1775 1776 XFillRectangle(display, drawable, gc, x + startX, 1777 y + fontPtr->underlinePos, (unsigned int) (endX - startX), 1778 (unsigned int) fontPtr->underlineHeight); 1779} 1780 1781/* 1782 *--------------------------------------------------------------------------- 1783 * 1784 * Tk_ComputeTextLayout -- 1785 * 1786 * Computes the amount of screen space needed to display a 1787 * multi-line, justified string of text. Records all the 1788 * measurements that were done to determine to size and 1789 * positioning of the individual lines of text; this information 1790 * can be used by the Tk_DrawTextLayout() procedure to 1791 * display the text quickly (without remeasuring it). 1792 * 1793 * This procedure is useful for simple widgets that want to 1794 * display single-font, multi-line text and want Tk to handle the 1795 * details. 1796 * 1797 * Results: 1798 * The return value is a Tk_TextLayout token that holds the 1799 * measurement information for the given string. The token is 1800 * only valid for the given string. If the string is freed, 1801 * the token is no longer valid and must also be freed. To free 1802 * the token, call Tk_FreeTextLayout(). 1803 * 1804 * The dimensions of the screen area needed to display the text 1805 * are stored in *widthPtr and *heightPtr. 1806 * 1807 * Side effects: 1808 * Memory is allocated to hold the measurement information. 1809 * 1810 *--------------------------------------------------------------------------- 1811 */ 1812 1813Tk_TextLayout 1814Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, 1815 widthPtr, heightPtr) 1816 Tk_Font tkfont; /* Font that will be used to display text. */ 1817 CONST char *string; /* String whose dimensions are to be 1818 * computed. */ 1819 int numChars; /* Number of characters to consider from 1820 * string, or < 0 for strlen(). */ 1821 int wrapLength; /* Longest permissible line length, in 1822 * pixels. <= 0 means no automatic wrapping: 1823 * just let lines get as long as needed. */ 1824 Tk_Justify justify; /* How to justify lines. */ 1825 int flags; /* Flag bits OR-ed together. 1826 * TK_IGNORE_TABS means that tab characters 1827 * should not be expanded. TK_IGNORE_NEWLINES 1828 * means that newline characters should not 1829 * cause a line break. */ 1830 int *widthPtr; /* Filled with width of string. */ 1831 int *heightPtr; /* Filled with height of string. */ 1832{ 1833 TkFont *fontPtr; 1834 CONST char *start, *end, *special; 1835 int n, y, bytesThisChunk, maxChunks; 1836 int baseline, height, curX, newX, maxWidth; 1837 TextLayout *layoutPtr; 1838 LayoutChunk *chunkPtr; 1839 CONST TkFontMetrics *fmPtr; 1840 Tcl_DString lineBuffer; 1841 int *lineLengths; 1842 int curLine, layoutHeight; 1843 1844 Tcl_DStringInit(&lineBuffer); 1845 1846 fontPtr = (TkFont *) tkfont; 1847 if ((fontPtr == NULL) || (string == NULL)) { 1848 if (widthPtr != NULL) { 1849 *widthPtr = 0; 1850 } 1851 if (heightPtr != NULL) { 1852 *heightPtr = 0; 1853 } 1854 return NULL; 1855 } 1856 1857 fmPtr = &fontPtr->fm; 1858 1859 height = fmPtr->ascent + fmPtr->descent; 1860 1861 if (numChars < 0) { 1862 numChars = Tcl_NumUtfChars(string, -1); 1863 } 1864 if (wrapLength == 0) { 1865 wrapLength = -1; 1866 } 1867 1868 maxChunks = 1; 1869 1870 layoutPtr = (TextLayout *) ckalloc(sizeof(TextLayout) 1871 + (maxChunks - 1) * sizeof(LayoutChunk)); 1872 layoutPtr->tkfont = tkfont; 1873 layoutPtr->string = string; 1874 layoutPtr->numChunks = 0; 1875 1876 baseline = fmPtr->ascent; 1877 maxWidth = 0; 1878 1879 /* 1880 * Divide the string up into simple strings and measure each string. 1881 */ 1882 1883 curX = 0; 1884 1885 end = Tcl_UtfAtIndex(string, numChars); 1886 special = string; 1887 1888 flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES; 1889 flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE; 1890 for (start = string; start < end; ) { 1891 if (start >= special) { 1892 /* 1893 * Find the next special character in the string. 1894 * 1895 * INTL: Note that it is safe to increment by byte, because we are 1896 * looking for 7-bit characters that will appear unchanged in 1897 * UTF-8. At some point we may need to support the full Unicode 1898 * whitespace set. 1899 */ 1900 1901 for (special = start; special < end; special++) { 1902 if (!(flags & TK_IGNORE_NEWLINES)) { 1903 if ((*special == '\n') || (*special == '\r')) { 1904 break; 1905 } 1906 } 1907 if (!(flags & TK_IGNORE_TABS)) { 1908 if (*special == '\t') { 1909 break; 1910 } 1911 } 1912 } 1913 } 1914 1915 /* 1916 * Special points at the next special character (or the end of the 1917 * string). Process characters between start and special. 1918 */ 1919 1920 chunkPtr = NULL; 1921 if (start < special) { 1922 bytesThisChunk = Tk_MeasureChars(tkfont, start, special - start, 1923 wrapLength - curX, flags, &newX); 1924 newX += curX; 1925 flags &= ~TK_AT_LEAST_ONE; 1926 if (bytesThisChunk > 0) { 1927 chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 1928 bytesThisChunk, curX, newX, baseline); 1929 1930 start += bytesThisChunk; 1931 curX = newX; 1932 } 1933 } 1934 1935 if ((start == special) && (special < end)) { 1936 /* 1937 * Handle the special character. 1938 * 1939 * INTL: Special will be pointing at a 7-bit character so we 1940 * can safely treat it as a single byte. 1941 */ 1942 1943 chunkPtr = NULL; 1944 if (*special == '\t') { 1945 newX = curX + fontPtr->tabWidth; 1946 newX -= newX % fontPtr->tabWidth; 1947 NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX, 1948 baseline)->numDisplayChars = -1; 1949 start++; 1950 if ((start < end) && 1951 ((wrapLength <= 0) || (newX <= wrapLength))) { 1952 /* 1953 * More chars can still fit on this line. 1954 */ 1955 1956 curX = newX; 1957 flags &= ~TK_AT_LEAST_ONE; 1958 continue; 1959 } 1960 } else { 1961 NewChunk(&layoutPtr, &maxChunks, start, 1, curX, curX, 1962 baseline)->numDisplayChars = -1; 1963 start++; 1964 goto wrapLine; 1965 } 1966 } 1967 1968 /* 1969 * No more characters are going to go on this line, either because 1970 * no more characters can fit or there are no more characters left. 1971 * Consume all extra spaces at end of line. 1972 */ 1973 1974 while ((start < end) && isspace(UCHAR(*start))) { /* INTL: ISO space */ 1975 if (!(flags & TK_IGNORE_NEWLINES)) { 1976 if ((*start == '\n') || (*start == '\r')) { 1977 break; 1978 } 1979 } 1980 if (!(flags & TK_IGNORE_TABS)) { 1981 if (*start == '\t') { 1982 break; 1983 } 1984 } 1985 start++; 1986 } 1987 if (chunkPtr != NULL) { 1988 CONST char *end; 1989 1990 /* 1991 * Append all the extra spaces on this line to the end of the 1992 * last text chunk. This is a little tricky because we are 1993 * switching back and forth between characters and bytes. 1994 */ 1995 1996 end = chunkPtr->start + chunkPtr->numBytes; 1997 bytesThisChunk = start - end; 1998 if (bytesThisChunk > 0) { 1999 bytesThisChunk = Tk_MeasureChars(tkfont, end, bytesThisChunk, 2000 -1, 0, &chunkPtr->totalWidth); 2001 chunkPtr->numBytes += bytesThisChunk; 2002 chunkPtr->numChars += Tcl_NumUtfChars(end, bytesThisChunk); 2003 chunkPtr->totalWidth += curX; 2004 } 2005 } 2006 2007 wrapLine: 2008 flags |= TK_AT_LEAST_ONE; 2009 2010 /* 2011 * Save current line length, then move current position to start of 2012 * next line. 2013 */ 2014 2015 if (curX > maxWidth) { 2016 maxWidth = curX; 2017 } 2018 2019 /* 2020 * Remember width of this line, so that all chunks on this line 2021 * can be centered or right justified, if necessary. 2022 */ 2023 2024 Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX)); 2025 2026 curX = 0; 2027 baseline += height; 2028 } 2029 2030 /* 2031 * If last line ends with a newline, then we need to make a 0 width 2032 * chunk on the next line. Otherwise "Hello" and "Hello\n" are the 2033 * same height. 2034 */ 2035 2036 if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) { 2037 if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') { 2038 chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX, 2039 curX, baseline); 2040 chunkPtr->numDisplayChars = -1; 2041 Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX)); 2042 baseline += height; 2043 } 2044 } 2045 2046 layoutPtr->width = maxWidth; 2047 layoutHeight = baseline - fmPtr->ascent; 2048 if (layoutPtr->numChunks == 0) { 2049 layoutHeight = height; 2050 2051 /* 2052 * This fake chunk is used by the other procedures so that they can 2053 * pretend that there is a chunk with no chars in it, which makes 2054 * the coding simpler. 2055 */ 2056 2057 layoutPtr->numChunks = 1; 2058 layoutPtr->chunks[0].start = string; 2059 layoutPtr->chunks[0].numBytes = 0; 2060 layoutPtr->chunks[0].numChars = 0; 2061 layoutPtr->chunks[0].numDisplayChars = -1; 2062 layoutPtr->chunks[0].x = 0; 2063 layoutPtr->chunks[0].y = fmPtr->ascent; 2064 layoutPtr->chunks[0].totalWidth = 0; 2065 layoutPtr->chunks[0].displayWidth = 0; 2066 } else { 2067 /* 2068 * Using maximum line length, shift all the chunks so that the lines 2069 * are all justified correctly. 2070 */ 2071 2072 curLine = 0; 2073 chunkPtr = layoutPtr->chunks; 2074 y = chunkPtr->y; 2075 lineLengths = (int *) Tcl_DStringValue(&lineBuffer); 2076 for (n = 0; n < layoutPtr->numChunks; n++) { 2077 int extra; 2078 2079 if (chunkPtr->y != y) { 2080 curLine++; 2081 y = chunkPtr->y; 2082 } 2083 extra = maxWidth - lineLengths[curLine]; 2084 if (justify == TK_JUSTIFY_CENTER) { 2085 chunkPtr->x += extra / 2; 2086 } else if (justify == TK_JUSTIFY_RIGHT) { 2087 chunkPtr->x += extra; 2088 } 2089 chunkPtr++; 2090 } 2091 } 2092 2093 if (widthPtr != NULL) { 2094 *widthPtr = layoutPtr->width; 2095 } 2096 if (heightPtr != NULL) { 2097 *heightPtr = layoutHeight; 2098 } 2099 Tcl_DStringFree(&lineBuffer); 2100 2101 return (Tk_TextLayout) layoutPtr; 2102} 2103 2104/* 2105 *--------------------------------------------------------------------------- 2106 * 2107 * Tk_FreeTextLayout -- 2108 * 2109 * This procedure is called to release the storage associated with 2110 * a Tk_TextLayout when it is no longer needed. 2111 * 2112 * Results: 2113 * None. 2114 * 2115 * Side effects: 2116 * Memory is freed. 2117 * 2118 *--------------------------------------------------------------------------- 2119 */ 2120 2121void 2122Tk_FreeTextLayout(textLayout) 2123 Tk_TextLayout textLayout; /* The text layout to be released. */ 2124{ 2125 TextLayout *layoutPtr; 2126 2127 layoutPtr = (TextLayout *) textLayout; 2128 if (layoutPtr != NULL) { 2129 ckfree((char *) layoutPtr); 2130 } 2131} 2132 2133/* 2134 *--------------------------------------------------------------------------- 2135 * 2136 * Tk_DrawTextLayout -- 2137 * 2138 * Use the information in the Tk_TextLayout token to display a 2139 * multi-line, justified string of text. 2140 * 2141 * This procedure is useful for simple widgets that need to 2142 * display single-font, multi-line text and want Tk to handle 2143 * the details. 2144 * 2145 * Results: 2146 * None. 2147 * 2148 * Side effects: 2149 * Text drawn on the screen. 2150 * 2151 *--------------------------------------------------------------------------- 2152 */ 2153 2154void 2155Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar) 2156 Display *display; /* Display on which to draw. */ 2157 Drawable drawable; /* Window or pixmap in which to draw. */ 2158 GC gc; /* Graphics context to use for drawing text. */ 2159 Tk_TextLayout layout; /* Layout information, from a previous call 2160 * to Tk_ComputeTextLayout(). */ 2161 int x, y; /* Upper-left hand corner of rectangle in 2162 * which to draw (pixels). */ 2163 int firstChar; /* The index of the first character to draw 2164 * from the given text item. 0 specfies the 2165 * beginning. */ 2166 int lastChar; /* The index just after the last character 2167 * to draw from the given text item. A number 2168 * < 0 means to draw all characters. */ 2169{ 2170 TextLayout *layoutPtr; 2171 int i, numDisplayChars, drawX; 2172 CONST char *firstByte; 2173 CONST char *lastByte; 2174 LayoutChunk *chunkPtr; 2175 2176 layoutPtr = (TextLayout *) layout; 2177 if (layoutPtr == NULL) { 2178 return; 2179 } 2180 2181 if (lastChar < 0) { 2182 lastChar = 100000000; 2183 } 2184 chunkPtr = layoutPtr->chunks; 2185 for (i = 0; i < layoutPtr->numChunks; i++) { 2186 numDisplayChars = chunkPtr->numDisplayChars; 2187 if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) { 2188 if (firstChar <= 0) { 2189 drawX = 0; 2190 firstChar = 0; 2191 firstByte = chunkPtr->start; 2192 } else { 2193 firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar); 2194 Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, 2195 firstByte - chunkPtr->start, -1, 0, &drawX); 2196 } 2197 if (lastChar < numDisplayChars) { 2198 numDisplayChars = lastChar; 2199 } 2200 lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars); 2201 Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, 2202 firstByte, lastByte - firstByte, 2203 x + chunkPtr->x + drawX, y + chunkPtr->y); 2204 } 2205 firstChar -= chunkPtr->numChars; 2206 lastChar -= chunkPtr->numChars; 2207 if (lastChar <= 0) { 2208 break; 2209 } 2210 chunkPtr++; 2211 } 2212} 2213 2214/* 2215 *--------------------------------------------------------------------------- 2216 * 2217 * Tk_UnderlineTextLayout -- 2218 * 2219 * Use the information in the Tk_TextLayout token to display an 2220 * underline below an individual character. This procedure does 2221 * not draw the text, just the underline. 2222 * 2223 * This procedure is useful for simple widgets that need to 2224 * display single-font, multi-line text with an individual 2225 * character underlined and want Tk to handle the details. 2226 * To display larger amounts of underlined text, construct 2227 * and use an underlined font. 2228 * 2229 * Results: 2230 * None. 2231 * 2232 * Side effects: 2233 * Underline drawn on the screen. 2234 * 2235 *--------------------------------------------------------------------------- 2236 */ 2237 2238void 2239Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline) 2240 Display *display; /* Display on which to draw. */ 2241 Drawable drawable; /* Window or pixmap in which to draw. */ 2242 GC gc; /* Graphics context to use for drawing text. */ 2243 Tk_TextLayout layout; /* Layout information, from a previous call 2244 * to Tk_ComputeTextLayout(). */ 2245 int x, y; /* Upper-left hand corner of rectangle in 2246 * which to draw (pixels). */ 2247 int underline; /* Index of the single character to 2248 * underline, or -1 for no underline. */ 2249{ 2250 TextLayout *layoutPtr; 2251 TkFont *fontPtr; 2252 int xx, yy, width, height; 2253 2254 if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0) 2255 && (width != 0)) { 2256 layoutPtr = (TextLayout *) layout; 2257 fontPtr = (TkFont *) layoutPtr->tkfont; 2258 2259 XFillRectangle(display, drawable, gc, x + xx, 2260 y + yy + fontPtr->fm.ascent + fontPtr->underlinePos, 2261 (unsigned int) width, (unsigned int) fontPtr->underlineHeight); 2262 } 2263} 2264 2265/* 2266 *--------------------------------------------------------------------------- 2267 * 2268 * Tk_PointToChar -- 2269 * 2270 * Use the information in the Tk_TextLayout token to determine the 2271 * character closest to the given point. The point must be 2272 * specified with respect to the upper-left hand corner of the 2273 * text layout, which is considered to be located at (0, 0). 2274 * 2275 * Any point whose y-value is less that 0 will be considered closest 2276 * to the first character in the text layout; any point whose y-value 2277 * is greater than the height of the text layout will be considered 2278 * closest to the last character in the text layout. 2279 * 2280 * Any point whose x-value is less than 0 will be considered closest 2281 * to the first character on that line; any point whose x-value is 2282 * greater than the width of the text layout will be considered 2283 * closest to the last character on that line. 2284 * 2285 * Results: 2286 * The return value is the index of the character that was 2287 * closest to the point. Given a text layout with no characters, 2288 * the value 0 will always be returned, referring to a hypothetical 2289 * zero-width placeholder character. 2290 * 2291 * Side effects: 2292 * None. 2293 * 2294 *--------------------------------------------------------------------------- 2295 */ 2296 2297int 2298Tk_PointToChar(layout, x, y) 2299 Tk_TextLayout layout; /* Layout information, from a previous call 2300 * to Tk_ComputeTextLayout(). */ 2301 int x, y; /* Coordinates of point to check, with 2302 * respect to the upper-left corner of the 2303 * text layout. */ 2304{ 2305 TextLayout *layoutPtr; 2306 LayoutChunk *chunkPtr, *lastPtr; 2307 TkFont *fontPtr; 2308 int i, n, dummy, baseline, pos, numChars; 2309 2310 if (y < 0) { 2311 /* 2312 * Point lies above any line in this layout. Return the index of 2313 * the first char. 2314 */ 2315 2316 return 0; 2317 } 2318 2319 /* 2320 * Find which line contains the point. 2321 */ 2322 2323 layoutPtr = (TextLayout *) layout; 2324 fontPtr = (TkFont *) layoutPtr->tkfont; 2325 lastPtr = chunkPtr = layoutPtr->chunks; 2326 numChars = 0; 2327 for (i = 0; i < layoutPtr->numChunks; i++) { 2328 baseline = chunkPtr->y; 2329 if (y < baseline + fontPtr->fm.descent) { 2330 if (x < chunkPtr->x) { 2331 /* 2332 * Point is to the left of all chunks on this line. Return 2333 * the index of the first character on this line. 2334 */ 2335 2336 return numChars; 2337 } 2338 if (x >= layoutPtr->width) { 2339 /* 2340 * If point lies off right side of the text layout, return 2341 * the last char in the last chunk on this line. Without 2342 * this, it might return the index of the first char that 2343 * was located outside of the text layout. 2344 */ 2345 2346 x = INT_MAX; 2347 } 2348 2349 /* 2350 * Examine all chunks on this line to see which one contains 2351 * the specified point. 2352 */ 2353 2354 lastPtr = chunkPtr; 2355 while ((i < layoutPtr->numChunks) && (chunkPtr->y == baseline)) { 2356 if (x < chunkPtr->x + chunkPtr->totalWidth) { 2357 /* 2358 * Point falls on one of the characters in this chunk. 2359 */ 2360 2361 if (chunkPtr->numDisplayChars < 0) { 2362 /* 2363 * This is a special chunk that encapsulates a single 2364 * tab or newline char. 2365 */ 2366 2367 return numChars; 2368 } 2369 n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start, 2370 chunkPtr->numBytes, x - chunkPtr->x, 2371 0, &dummy); 2372 return numChars + Tcl_NumUtfChars(chunkPtr->start, n); 2373 } 2374 numChars += chunkPtr->numChars; 2375 lastPtr = chunkPtr; 2376 chunkPtr++; 2377 i++; 2378 } 2379 2380 /* 2381 * Point is to the right of all chars in all the chunks on this 2382 * line. Return the index just past the last char in the last 2383 * chunk on this line. 2384 */ 2385 2386 pos = numChars; 2387 if (i < layoutPtr->numChunks) { 2388 pos--; 2389 } 2390 return pos; 2391 } 2392 numChars += chunkPtr->numChars; 2393 lastPtr = chunkPtr; 2394 chunkPtr++; 2395 } 2396 2397 /* 2398 * Point lies below any line in this text layout. Return the index 2399 * just past the last char. 2400 */ 2401 2402 return (lastPtr->start + lastPtr->numChars) - layoutPtr->string; 2403} 2404 2405/* 2406 *--------------------------------------------------------------------------- 2407 * 2408 * Tk_CharBbox -- 2409 * 2410 * Use the information in the Tk_TextLayout token to return the 2411 * bounding box for the character specified by index. 2412 * 2413 * The width of the bounding box is the advance width of the 2414 * character, and does not include and left- or right-bearing. 2415 * Any character that extends partially outside of the 2416 * text layout is considered to be truncated at the edge. Any 2417 * character which is located completely outside of the text 2418 * layout is considered to be zero-width and pegged against 2419 * the edge. 2420 * 2421 * The height of the bounding box is the line height for this font, 2422 * extending from the top of the ascent to the bottom of the 2423 * descent. Information about the actual height of the individual 2424 * letter is not available. 2425 * 2426 * A text layout that contains no characters is considered to 2427 * contain a single zero-width placeholder character. 2428 * 2429 * Results: 2430 * The return value is 0 if the index did not specify a character 2431 * in the text layout, or non-zero otherwise. In that case, 2432 * *bbox is filled with the bounding box of the character. 2433 * 2434 * Side effects: 2435 * None. 2436 * 2437 *--------------------------------------------------------------------------- 2438 */ 2439 2440int 2441Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr) 2442 Tk_TextLayout layout; /* Layout information, from a previous call to 2443 * Tk_ComputeTextLayout(). */ 2444 int index; /* The index of the character whose bbox is 2445 * desired. */ 2446 int *xPtr, *yPtr; /* Filled with the upper-left hand corner, in 2447 * pixels, of the bounding box for the character 2448 * specified by index, if non-NULL. */ 2449 int *widthPtr, *heightPtr; 2450 /* Filled with the width and height of the 2451 * bounding box for the character specified by 2452 * index, if non-NULL. */ 2453{ 2454 TextLayout *layoutPtr; 2455 LayoutChunk *chunkPtr; 2456 int i, x, w; 2457 Tk_Font tkfont; 2458 TkFont *fontPtr; 2459 CONST char *end; 2460 2461 if (index < 0) { 2462 return 0; 2463 } 2464 2465 layoutPtr = (TextLayout *) layout; 2466 chunkPtr = layoutPtr->chunks; 2467 tkfont = layoutPtr->tkfont; 2468 fontPtr = (TkFont *) tkfont; 2469 2470 for (i = 0; i < layoutPtr->numChunks; i++) { 2471 if (chunkPtr->numDisplayChars < 0) { 2472 if (index == 0) { 2473 x = chunkPtr->x; 2474 w = chunkPtr->totalWidth; 2475 goto check; 2476 } 2477 } else if (index < chunkPtr->numChars) { 2478 end = Tcl_UtfAtIndex(chunkPtr->start, index); 2479 if (xPtr != NULL) { 2480 Tk_MeasureChars(tkfont, chunkPtr->start, 2481 end - chunkPtr->start, -1, 0, &x); 2482 x += chunkPtr->x; 2483 } 2484 if (widthPtr != NULL) { 2485 Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end, 2486 -1, 0, &w); 2487 } 2488 goto check; 2489 } 2490 index -= chunkPtr->numChars; 2491 chunkPtr++; 2492 } 2493 if (index == 0) { 2494 /* 2495 * Special case to get location just past last char in layout. 2496 */ 2497 2498 chunkPtr--; 2499 x = chunkPtr->x + chunkPtr->totalWidth; 2500 w = 0; 2501 } else { 2502 return 0; 2503 } 2504 2505 /* 2506 * Ensure that the bbox lies within the text layout. This forces all 2507 * chars that extend off the right edge of the text layout to have 2508 * truncated widths, and all chars that are completely off the right 2509 * edge of the text layout to peg to the edge and have 0 width. 2510 */ 2511 check: 2512 if (yPtr != NULL) { 2513 *yPtr = chunkPtr->y - fontPtr->fm.ascent; 2514 } 2515 if (heightPtr != NULL) { 2516 *heightPtr = fontPtr->fm.ascent + fontPtr->fm.descent; 2517 } 2518 2519 if (x > layoutPtr->width) { 2520 x = layoutPtr->width; 2521 } 2522 if (xPtr != NULL) { 2523 *xPtr = x; 2524 } 2525 if (widthPtr != NULL) { 2526 if (x + w > layoutPtr->width) { 2527 w = layoutPtr->width - x; 2528 } 2529 *widthPtr = w; 2530 } 2531 2532 return 1; 2533} 2534 2535/* 2536 *--------------------------------------------------------------------------- 2537 * 2538 * Tk_DistanceToTextLayout -- 2539 * 2540 * Computes the distance in pixels from the given point to the 2541 * given text layout. Non-displaying space characters that occur 2542 * at the end of individual lines in the text layout are ignored 2543 * for hit detection purposes. 2544 * 2545 * Results: 2546 * The return value is 0 if the point (x, y) is inside the text 2547 * layout. If the point isn't inside the text layout then the 2548 * return value is the distance in pixels from the point to the 2549 * text item. 2550 * 2551 * Side effects: 2552 * None. 2553 * 2554 *--------------------------------------------------------------------------- 2555 */ 2556 2557int 2558Tk_DistanceToTextLayout(layout, x, y) 2559 Tk_TextLayout layout; /* Layout information, from a previous call 2560 * to Tk_ComputeTextLayout(). */ 2561 int x, y; /* Coordinates of point to check, with 2562 * respect to the upper-left corner of the 2563 * text layout (in pixels). */ 2564{ 2565 int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent; 2566 LayoutChunk *chunkPtr; 2567 TextLayout *layoutPtr; 2568 TkFont *fontPtr; 2569 2570 layoutPtr = (TextLayout *) layout; 2571 fontPtr = (TkFont *) layoutPtr->tkfont; 2572 ascent = fontPtr->fm.ascent; 2573 descent = fontPtr->fm.descent; 2574 2575 minDist = 0; 2576 chunkPtr = layoutPtr->chunks; 2577 for (i = 0; i < layoutPtr->numChunks; i++) { 2578 if (chunkPtr->start[0] == '\n') { 2579 /* 2580 * Newline characters are not counted when computing distance 2581 * (but tab characters would still be considered). 2582 */ 2583 2584 chunkPtr++; 2585 continue; 2586 } 2587 2588 x1 = chunkPtr->x; 2589 y1 = chunkPtr->y - ascent; 2590 x2 = chunkPtr->x + chunkPtr->displayWidth; 2591 y2 = chunkPtr->y + descent; 2592 2593 if (x < x1) { 2594 xDiff = x1 - x; 2595 } else if (x >= x2) { 2596 xDiff = x - x2 + 1; 2597 } else { 2598 xDiff = 0; 2599 } 2600 2601 if (y < y1) { 2602 yDiff = y1 - y; 2603 } else if (y >= y2) { 2604 yDiff = y - y2 + 1; 2605 } else { 2606 yDiff = 0; 2607 } 2608 if ((xDiff == 0) && (yDiff == 0)) { 2609 return 0; 2610 } 2611 dist = (int) hypot((double) xDiff, (double) yDiff); 2612 if ((dist < minDist) || (minDist == 0)) { 2613 minDist = dist; 2614 } 2615 chunkPtr++; 2616 } 2617 return minDist; 2618} 2619 2620/* 2621 *--------------------------------------------------------------------------- 2622 * 2623 * Tk_IntersectTextLayout -- 2624 * 2625 * Determines whether a text layout lies entirely inside, 2626 * entirely outside, or overlaps a given rectangle. Non-displaying 2627 * space characters that occur at the end of individual lines in 2628 * the text layout are ignored for intersection calculations. 2629 * 2630 * Results: 2631 * The return value is -1 if the text layout is entirely outside of 2632 * the rectangle, 0 if it overlaps, and 1 if it is entirely inside 2633 * of the rectangle. 2634 * 2635 * Side effects: 2636 * None. 2637 * 2638 *--------------------------------------------------------------------------- 2639 */ 2640 2641int 2642Tk_IntersectTextLayout(layout, x, y, width, height) 2643 Tk_TextLayout layout; /* Layout information, from a previous call 2644 * to Tk_ComputeTextLayout(). */ 2645 int x, y; /* Upper-left hand corner, in pixels, of 2646 * rectangular area to compare with text 2647 * layout. Coordinates are with respect to 2648 * the upper-left hand corner of the text 2649 * layout itself. */ 2650 int width, height; /* The width and height of the above 2651 * rectangular area, in pixels. */ 2652{ 2653 int result, i, x1, y1, x2, y2; 2654 TextLayout *layoutPtr; 2655 LayoutChunk *chunkPtr; 2656 TkFont *fontPtr; 2657 int left, top, right, bottom; 2658 2659 /* 2660 * Scan the chunks one at a time, seeing whether each is entirely in, 2661 * entirely out, or overlapping the rectangle. If an overlap is 2662 * detected, return immediately; otherwise wait until all chunks have 2663 * been processed and see if they were all inside or all outside. 2664 */ 2665 2666 layoutPtr = (TextLayout *) layout; 2667 chunkPtr = layoutPtr->chunks; 2668 fontPtr = (TkFont *) layoutPtr->tkfont; 2669 2670 left = x; 2671 top = y; 2672 right = x + width; 2673 bottom = y + height; 2674 2675 result = 0; 2676 for (i = 0; i < layoutPtr->numChunks; i++) { 2677 if (chunkPtr->start[0] == '\n') { 2678 /* 2679 * Newline characters are not counted when computing area 2680 * intersection (but tab characters would still be considered). 2681 */ 2682 2683 chunkPtr++; 2684 continue; 2685 } 2686 2687 x1 = chunkPtr->x; 2688 y1 = chunkPtr->y - fontPtr->fm.ascent; 2689 x2 = chunkPtr->x + chunkPtr->displayWidth; 2690 y2 = chunkPtr->y + fontPtr->fm.descent; 2691 2692 if ((right < x1) || (left >= x2) 2693 || (bottom < y1) || (top >= y2)) { 2694 if (result == 1) { 2695 return 0; 2696 } 2697 result = -1; 2698 } else if ((x1 < left) || (x2 >= right) 2699 || (y1 < top) || (y2 >= bottom)) { 2700 return 0; 2701 } else if (result == -1) { 2702 return 0; 2703 } else { 2704 result = 1; 2705 } 2706 chunkPtr++; 2707 } 2708 return result; 2709} 2710 2711/* 2712 *--------------------------------------------------------------------------- 2713 * 2714 * Tk_TextLayoutToPostscript -- 2715 * 2716 * Outputs the contents of a text layout in Postscript format. 2717 * The set of lines in the text layout will be rendered by the user 2718 * supplied Postscript function. The function should be of the form: 2719 * 2720 * justify x y string function -- 2721 * 2722 * Justify is -1, 0, or 1, depending on whether the following string 2723 * should be left, center, or right justified, x and y is the 2724 * location for the origin of the string, string is the sequence 2725 * of characters to be printed, and function is the name of the 2726 * caller-provided function; the function should leave nothing 2727 * on the stack. 2728 * 2729 * The meaning of the origin of the string (x and y) depends on 2730 * the justification. For left justification, x is where the 2731 * left edge of the string should appear. For center justification, 2732 * x is where the center of the string should appear. And for right 2733 * justification, x is where the right edge of the string should 2734 * appear. This behavior is necessary because, for example, right 2735 * justified text on the screen is justified with screen metrics. 2736 * The same string needs to be justified with printer metrics on 2737 * the printer to appear in the correct place with respect to other 2738 * similarly justified strings. In all circumstances, y is the 2739 * location of the baseline for the string. 2740 * 2741 * Results: 2742 * The interp's result is modified to hold the Postscript code that 2743 * will render the text layout. 2744 * 2745 * Side effects: 2746 * None. 2747 * 2748 *--------------------------------------------------------------------------- 2749 */ 2750 2751void 2752Tk_TextLayoutToPostscript(interp, layout) 2753 Tcl_Interp *interp; /* Filled with Postscript code. */ 2754 Tk_TextLayout layout; /* The layout to be rendered. */ 2755{ 2756#define MAXUSE 128 2757 char buf[MAXUSE+30]; 2758 LayoutChunk *chunkPtr; 2759 int i, j, used, c, baseline; 2760 Tcl_UniChar ch; 2761 CONST char *p, *last_p,*glyphname; 2762 TextLayout *layoutPtr; 2763 char uindex[5]="\0\0\0\0"; 2764 char one_char[5]; 2765 int charsize; 2766 int bytecount=0; 2767 2768 layoutPtr = (TextLayout *) layout; 2769 chunkPtr = layoutPtr->chunks; 2770 baseline = chunkPtr->y; 2771 used = 0; 2772 buf[used++] = '['; 2773 buf[used++] = '('; 2774 for (i = 0; i < layoutPtr->numChunks; i++) { 2775 if (baseline != chunkPtr->y) { 2776 buf[used++] = ')'; 2777 buf[used++] = ']'; 2778 buf[used++] = '\n'; 2779 buf[used++] = '['; 2780 buf[used++] = '('; 2781 baseline = chunkPtr->y; 2782 } 2783 if (chunkPtr->numDisplayChars <= 0) { 2784 if (chunkPtr->start[0] == '\t') { 2785 buf[used++] = '\\'; 2786 buf[used++] = 't'; 2787 } 2788 } else { 2789 p = chunkPtr->start; 2790 for (j = 0; j < chunkPtr->numDisplayChars; j++) { 2791 /* 2792 * INTL: For now we just treat the characters as binary 2793 * data and display the lower byte. Eventually this should 2794 * be revised to handle international postscript fonts. 2795 */ 2796 last_p=p; 2797 p +=(charsize= Tcl_UtfToUniChar(p,&ch)); 2798 Tcl_UtfToExternal(interp,NULL,last_p,charsize,0,NULL,one_char,4, 2799 NULL,&bytecount,NULL); 2800 if (bytecount == 1) { 2801 c = UCHAR(one_char[0]); 2802 /* c = UCHAR( ch & 0xFF) */; 2803 if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20) 2804 || (c >= UCHAR(0x7f))) { 2805 /* 2806 * Tricky point: the "03" is necessary in the sprintf 2807 * below, so that a full three digits of octal are 2808 * always generated. Without the "03", a number 2809 * following this sequence could be interpreted by 2810 * Postscript as part of this sequence. 2811 */ 2812 2813 sprintf(buf + used, "\\%03o", c); 2814 used += 4; 2815 } else { 2816 buf[used++] = c; 2817 } 2818 } else { 2819 /* This character doesn't belong to system character set. 2820 * So, we must use full glyph name */ 2821 sprintf(uindex,"%04X",ch); /* endianness? */ 2822 if ((glyphname = Tcl_GetVar2( interp , "::tk::psglyphs",uindex,0))) { 2823 if (used > 0 && buf [used-1] == '(') 2824 --used; 2825 else 2826 buf[used++] = ')'; 2827 buf[used++] = '/'; 2828 while( (*glyphname) && (used < (MAXUSE+27))) 2829 buf[used++] = *glyphname++ ; 2830 buf[used++] = '('; 2831 } 2832 2833 } 2834 if (used >= MAXUSE) { 2835 buf[used] = '\0'; 2836 Tcl_AppendResult(interp, buf, (char *) NULL); 2837 used = 0; 2838 } 2839 } 2840 } 2841 if (used >= MAXUSE) { 2842 /* 2843 * If there are a whole bunch of returns or tabs in a row, 2844 * then buf[] could get filled up. 2845 */ 2846 2847 buf[used] = '\0'; 2848 Tcl_AppendResult(interp, buf, (char *) NULL); 2849 used = 0; 2850 } 2851 chunkPtr++; 2852 } 2853 buf[used++] = ')'; 2854 buf[used++] = ']'; 2855 buf[used++] = '\n'; 2856 buf[used] = '\0'; 2857 Tcl_AppendResult(interp, buf, (char *) NULL); 2858} 2859 2860/* 2861 *--------------------------------------------------------------------------- 2862 * 2863 * ConfigAttributesObj -- 2864 * 2865 * Process command line options to fill in fields of a properly 2866 * initialized font attributes structure. 2867 * 2868 * Results: 2869 * A standard Tcl return value. If TCL_ERROR is returned, an 2870 * error message will be left in interp's result object (if non-NULL). 2871 * 2872 * Side effects: 2873 * The fields of the font attributes structure get filled in with 2874 * information from argc/argv. If an error occurs while parsing, 2875 * the font attributes structure will contain all modifications 2876 * specified in the command line options up to the point of the 2877 * error. 2878 * 2879 *--------------------------------------------------------------------------- 2880 */ 2881 2882static int 2883ConfigAttributesObj(interp, tkwin, objc, objv, faPtr) 2884 Tcl_Interp *interp; /* Interp for error return, or NULL. */ 2885 Tk_Window tkwin; /* For display on which font will be used. */ 2886 int objc; /* Number of elements in argv. */ 2887 Tcl_Obj *CONST objv[]; /* Command line options. */ 2888 TkFontAttributes *faPtr; /* Font attributes structure whose fields 2889 * are to be modified. Structure must already 2890 * be properly initialized. */ 2891{ 2892 int i, n, index; 2893 Tcl_Obj *optionPtr, *valuePtr; 2894 char *value; 2895 2896 for (i = 0; i < objc; i += 2) { 2897 optionPtr = objv[i]; 2898 valuePtr = objv[i + 1]; 2899 2900 if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1, 2901 &index) != TCL_OK) { 2902 return TCL_ERROR; 2903 } 2904 if ((i+2 >= objc) && (objc & 1)) { 2905 /* 2906 * This test occurs after Tcl_GetIndexFromObj() so that 2907 * "font create xyz -xyz" will return the error message 2908 * that "-xyz" is a bad option, rather than that the value 2909 * for "-xyz" is missing. 2910 */ 2911 2912 if (interp != NULL) { 2913 Tcl_AppendResult(interp, "value for \"", 2914 Tcl_GetString(optionPtr), "\" option missing", 2915 (char *) NULL); 2916 } 2917 return TCL_ERROR; 2918 } 2919 2920 switch (index) { 2921 case FONT_FAMILY: { 2922 value = Tcl_GetString(valuePtr); 2923 faPtr->family = Tk_GetUid(value); 2924 break; 2925 } 2926 case FONT_SIZE: { 2927 if (Tcl_GetIntFromObj(interp, valuePtr, &n) != TCL_OK) { 2928 return TCL_ERROR; 2929 } 2930 faPtr->size = n; 2931 break; 2932 } 2933 case FONT_WEIGHT: { 2934 n = TkFindStateNumObj(interp, optionPtr, weightMap, valuePtr); 2935 if (n == TK_FW_UNKNOWN) { 2936 return TCL_ERROR; 2937 } 2938 faPtr->weight = n; 2939 break; 2940 } 2941 case FONT_SLANT: { 2942 n = TkFindStateNumObj(interp, optionPtr, slantMap, valuePtr); 2943 if (n == TK_FS_UNKNOWN) { 2944 return TCL_ERROR; 2945 } 2946 faPtr->slant = n; 2947 break; 2948 } 2949 case FONT_UNDERLINE: { 2950 if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) { 2951 return TCL_ERROR; 2952 } 2953 faPtr->underline = n; 2954 break; 2955 } 2956 case FONT_OVERSTRIKE: { 2957 if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) { 2958 return TCL_ERROR; 2959 } 2960 faPtr->overstrike = n; 2961 break; 2962 } 2963 } 2964 } 2965 return TCL_OK; 2966} 2967 2968/* 2969 *--------------------------------------------------------------------------- 2970 * 2971 * GetAttributeInfoObj -- 2972 * 2973 * Return information about the font attributes as a Tcl list. 2974 * 2975 * Results: 2976 * The return value is TCL_OK if the objPtr was non-NULL and 2977 * specified a valid font attribute, TCL_ERROR otherwise. If TCL_OK 2978 * is returned, the interp's result object is modified to hold a 2979 * description of either the current value of a single option, or a 2980 * list of all options and their current values for the given font 2981 * attributes. If TCL_ERROR is returned, the interp's result is 2982 * set to an error message describing that the objPtr did not refer 2983 * to a valid option. 2984 * 2985 * Side effects: 2986 * None. 2987 * 2988 *--------------------------------------------------------------------------- 2989 */ 2990 2991static int 2992GetAttributeInfoObj(interp, faPtr, objPtr) 2993 Tcl_Interp *interp; /* Interp to hold result. */ 2994 CONST TkFontAttributes *faPtr; /* The font attributes to inspect. */ 2995 Tcl_Obj *objPtr; /* If non-NULL, indicates the single 2996 * option whose value is to be 2997 * returned. Otherwise information is 2998 * returned for all options. */ 2999{ 3000 int i, index, start, end; 3001 CONST char *str; 3002 Tcl_Obj *optionPtr, *valuePtr, *resultPtr; 3003 3004 resultPtr = Tcl_GetObjResult(interp); 3005 3006 start = 0; 3007 end = FONT_NUMFIELDS; 3008 if (objPtr != NULL) { 3009 if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", TCL_EXACT, 3010 &index) != TCL_OK) { 3011 return TCL_ERROR; 3012 } 3013 start = index; 3014 end = index + 1; 3015 } 3016 3017 valuePtr = NULL; 3018 for (i = start; i < end; i++) { 3019 switch (i) { 3020 case FONT_FAMILY: 3021 str = faPtr->family; 3022 valuePtr = Tcl_NewStringObj(str, ((str == NULL) ? 0 : -1)); 3023 break; 3024 3025 case FONT_SIZE: 3026 valuePtr = Tcl_NewIntObj(faPtr->size); 3027 break; 3028 3029 case FONT_WEIGHT: 3030 str = TkFindStateString(weightMap, faPtr->weight); 3031 valuePtr = Tcl_NewStringObj(str, -1); 3032 break; 3033 3034 case FONT_SLANT: 3035 str = TkFindStateString(slantMap, faPtr->slant); 3036 valuePtr = Tcl_NewStringObj(str, -1); 3037 break; 3038 3039 case FONT_UNDERLINE: 3040 valuePtr = Tcl_NewBooleanObj(faPtr->underline); 3041 break; 3042 3043 case FONT_OVERSTRIKE: 3044 valuePtr = Tcl_NewBooleanObj(faPtr->overstrike); 3045 break; 3046 } 3047 if (objPtr != NULL) { 3048 Tcl_SetObjResult(interp, valuePtr); 3049 return TCL_OK; 3050 } 3051 optionPtr = Tcl_NewStringObj(fontOpt[i], -1); 3052 Tcl_ListObjAppendElement(NULL, resultPtr, optionPtr); 3053 Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr); 3054 } 3055 return TCL_OK; 3056} 3057 3058/* 3059 *--------------------------------------------------------------------------- 3060 * 3061 * ParseFontNameObj -- 3062 * 3063 * Converts a object into a set of font attributes that can be used 3064 * to construct a font. 3065 * 3066 * The string rep of the object can be one of the following forms: 3067 * XLFD (see X documentation) 3068 * "family [size] [style1 [style2 ...]" 3069 * "-option value [-option value ...]" 3070 * 3071 * Results: 3072 * The return value is TCL_ERROR if the object was syntactically 3073 * invalid. In that case an error message is left in interp's 3074 * result object. Otherwise, fills the font attribute buffer with 3075 * the values parsed from the string and returns TCL_OK; 3076 * 3077 * Side effects: 3078 * None. 3079 * 3080 *--------------------------------------------------------------------------- 3081 */ 3082 3083static int 3084ParseFontNameObj(interp, tkwin, objPtr, faPtr) 3085 Tcl_Interp *interp; /* Interp for error return, or NULL if no 3086 * error messages are to be generated. */ 3087 Tk_Window tkwin; /* For display on which font is used. */ 3088 Tcl_Obj *objPtr; /* Parseable font description object. */ 3089 TkFontAttributes *faPtr; /* Filled with attributes parsed from font 3090 * name. Any attributes that were not 3091 * specified in font name are filled with 3092 * default values. */ 3093{ 3094 char *dash; 3095 int objc, result, i, n; 3096 Tcl_Obj **objv; 3097 char *string; 3098 3099 TkInitFontAttributes(faPtr); 3100 3101 string = Tcl_GetString(objPtr); 3102 if (*string == '-') { 3103 /* 3104 * This may be an XLFD or an "-option value" string. 3105 * 3106 * If the string begins with "-*" or a "-foundry-family-*" pattern, 3107 * then consider it an XLFD. 3108 */ 3109 3110 if (string[1] == '*') { 3111 goto xlfd; 3112 } 3113 dash = strchr(string + 1, '-'); 3114 if ((dash != NULL) 3115 && (!isspace(UCHAR(dash[-1])))) { /* INTL: ISO space */ 3116 goto xlfd; 3117 } 3118 3119 if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { 3120 return TCL_ERROR; 3121 } 3122 3123 return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr); 3124 } 3125 3126 if (*string == '*') { 3127 /* 3128 * This is appears to be an XLFD. Under Unix, all valid XLFDs were 3129 * already handled by TkpGetNativeFont. If we are here, either we 3130 * have something that initially looks like an XLFD but isn't or we 3131 * have encountered an XLFD on Windows or Mac. 3132 */ 3133 3134 xlfd: 3135 result = TkFontParseXLFD(string, faPtr, NULL); 3136 if (result == TCL_OK) { 3137 return TCL_OK; 3138 } 3139 } 3140 3141 /* 3142 * Wasn't an XLFD or "-option value" string. Try it as a 3143 * "font size style" list. 3144 */ 3145 3146 if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) 3147 || (objc < 1)) { 3148 if (interp != NULL) { 3149 Tcl_AppendResult(interp, "font \"", string, "\" doesn't exist", 3150 (char *) NULL); 3151 } 3152 return TCL_ERROR; 3153 } 3154 3155 faPtr->family = Tk_GetUid(Tcl_GetString(objv[0])); 3156 if (objc > 1) { 3157 if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) { 3158 return TCL_ERROR; 3159 } 3160 faPtr->size = n; 3161 } 3162 3163 i = 2; 3164 if (objc == 3) { 3165 if (Tcl_ListObjGetElements(interp, objv[2], &objc, &objv) != TCL_OK) { 3166 return TCL_ERROR; 3167 } 3168 i = 0; 3169 } 3170 for ( ; i < objc; i++) { 3171 n = TkFindStateNumObj(NULL, NULL, weightMap, objv[i]); 3172 if (n != TK_FW_UNKNOWN) { 3173 faPtr->weight = n; 3174 continue; 3175 } 3176 n = TkFindStateNumObj(NULL, NULL, slantMap, objv[i]); 3177 if (n != TK_FS_UNKNOWN) { 3178 faPtr->slant = n; 3179 continue; 3180 } 3181 n = TkFindStateNumObj(NULL, NULL, underlineMap, objv[i]); 3182 if (n != 0) { 3183 faPtr->underline = n; 3184 continue; 3185 } 3186 n = TkFindStateNumObj(NULL, NULL, overstrikeMap, objv[i]); 3187 if (n != 0) { 3188 faPtr->overstrike = n; 3189 continue; 3190 } 3191 3192 /* 3193 * Unknown style. 3194 */ 3195 3196 if (interp != NULL) { 3197 Tcl_AppendResult(interp, "unknown font style \"", 3198 Tcl_GetString(objv[i]), "\"", (char *) NULL); 3199 } 3200 return TCL_ERROR; 3201 } 3202 return TCL_OK; 3203} 3204 3205/* 3206 *--------------------------------------------------------------------------- 3207 * 3208 * NewChunk -- 3209 * 3210 * Helper function for Tk_ComputeTextLayout(). Encapsulates a 3211 * measured set of characters in a chunk that can be quickly 3212 * drawn. 3213 * 3214 * Results: 3215 * A pointer to the new chunk in the text layout. 3216 * 3217 * Side effects: 3218 * The text layout is reallocated to hold more chunks as necessary. 3219 * 3220 * Currently, Tk_ComputeTextLayout() stores contiguous ranges of 3221 * "normal" characters in a chunk, along with individual tab 3222 * and newline chars in their own chunks. All characters in the 3223 * text layout are accounted for. 3224 * 3225 *--------------------------------------------------------------------------- 3226 */ 3227static LayoutChunk * 3228NewChunk(layoutPtrPtr, maxPtr, start, numBytes, curX, newX, y) 3229 TextLayout **layoutPtrPtr; 3230 int *maxPtr; 3231 CONST char *start; 3232 int numBytes; 3233 int curX; 3234 int newX; 3235 int y; 3236{ 3237 TextLayout *layoutPtr; 3238 LayoutChunk *chunkPtr; 3239 int maxChunks, numChars; 3240 size_t s; 3241 3242 layoutPtr = *layoutPtrPtr; 3243 maxChunks = *maxPtr; 3244 if (layoutPtr->numChunks == maxChunks) { 3245 maxChunks *= 2; 3246 s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk)); 3247 layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s); 3248 3249 *layoutPtrPtr = layoutPtr; 3250 *maxPtr = maxChunks; 3251 } 3252 numChars = Tcl_NumUtfChars(start, numBytes); 3253 chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks]; 3254 chunkPtr->start = start; 3255 chunkPtr->numBytes = numBytes; 3256 chunkPtr->numChars = numChars; 3257 chunkPtr->numDisplayChars = numChars; 3258 chunkPtr->x = curX; 3259 chunkPtr->y = y; 3260 chunkPtr->totalWidth = newX - curX; 3261 chunkPtr->displayWidth = newX - curX; 3262 layoutPtr->numChunks++; 3263 3264 return chunkPtr; 3265} 3266 3267/* 3268 *--------------------------------------------------------------------------- 3269 * 3270 * TkFontParseXLFD -- 3271 * 3272 * Break up a fully specified XLFD into a set of font attributes. 3273 * 3274 * Results: 3275 * Return value is TCL_ERROR if string was not a fully specified XLFD. 3276 * Otherwise, fills font attribute buffer with the values parsed 3277 * from the XLFD and returns TCL_OK. 3278 * 3279 * Side effects: 3280 * None. 3281 * 3282 *--------------------------------------------------------------------------- 3283 */ 3284 3285int 3286TkFontParseXLFD(string, faPtr, xaPtr) 3287 CONST char *string; /* Parseable font description string. */ 3288 TkFontAttributes *faPtr; /* Filled with attributes parsed from font 3289 * name. Any attributes that were not 3290 * specified in font name are filled with 3291 * default values. */ 3292 TkXLFDAttributes *xaPtr; /* Filled with X-specific attributes parsed 3293 * from font name. Any attributes that were 3294 * not specified in font name are filled with 3295 * default values. May be NULL if such 3296 * information is not desired. */ 3297{ 3298 char *src; 3299 CONST char *str; 3300 int i, j; 3301 char *field[XLFD_NUMFIELDS + 2]; 3302 Tcl_DString ds; 3303 TkXLFDAttributes xa; 3304 3305 if (xaPtr == NULL) { 3306 xaPtr = &xa; 3307 } 3308 TkInitFontAttributes(faPtr); 3309 TkInitXLFDAttributes(xaPtr); 3310 3311 memset(field, '\0', sizeof(field)); 3312 3313 str = string; 3314 if (*str == '-') { 3315 str++; 3316 } 3317 3318 Tcl_DStringInit(&ds); 3319 Tcl_DStringAppend(&ds, (char *) str, -1); 3320 src = Tcl_DStringValue(&ds); 3321 3322 field[0] = src; 3323 for (i = 0; *src != '\0'; src++) { 3324 if (!(*src & 0x80) 3325 && Tcl_UniCharIsUpper(UCHAR(*src))) { 3326 *src = (char) Tcl_UniCharToLower(UCHAR(*src)); 3327 } 3328 if (*src == '-') { 3329 i++; 3330 if (i == XLFD_NUMFIELDS) { 3331 continue; 3332 } 3333 *src = '\0'; 3334 field[i] = src + 1; 3335 if (i > XLFD_NUMFIELDS) { 3336 break; 3337 } 3338 } 3339 } 3340 3341 /* 3342 * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common, 3343 * but it is (strictly) malformed, because the first * is eliding both 3344 * the Setwidth and the Addstyle fields. If the Addstyle field is a 3345 * number, then assume the above incorrect form was used and shift all 3346 * the rest of the fields right by one, so the number gets interpreted 3347 * as a pixelsize. This fix is so that we don't get a million reports 3348 * that "it works under X (as a native font name), but gives a syntax 3349 * error under Windows (as a parsed set of attributes)". 3350 */ 3351 3352 if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) { 3353 if (atoi(field[XLFD_ADD_STYLE]) != 0) { 3354 for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) { 3355 field[j + 1] = field[j]; 3356 } 3357 field[XLFD_ADD_STYLE] = NULL; 3358 i++; 3359 } 3360 } 3361 3362 /* 3363 * Bail if we don't have enough of the fields (up to pointsize). 3364 */ 3365 3366 if (i < XLFD_FAMILY) { 3367 Tcl_DStringFree(&ds); 3368 return TCL_ERROR; 3369 } 3370 3371 if (FieldSpecified(field[XLFD_FOUNDRY])) { 3372 xaPtr->foundry = Tk_GetUid(field[XLFD_FOUNDRY]); 3373 } 3374 3375 if (FieldSpecified(field[XLFD_FAMILY])) { 3376 faPtr->family = Tk_GetUid(field[XLFD_FAMILY]); 3377 } 3378 if (FieldSpecified(field[XLFD_WEIGHT])) { 3379 faPtr->weight = TkFindStateNum(NULL, NULL, xlfdWeightMap, 3380 field[XLFD_WEIGHT]); 3381 } 3382 if (FieldSpecified(field[XLFD_SLANT])) { 3383 xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap, 3384 field[XLFD_SLANT]); 3385 if (xaPtr->slant == TK_FS_ROMAN) { 3386 faPtr->slant = TK_FS_ROMAN; 3387 } else { 3388 faPtr->slant = TK_FS_ITALIC; 3389 } 3390 } 3391 if (FieldSpecified(field[XLFD_SETWIDTH])) { 3392 xaPtr->setwidth = TkFindStateNum(NULL, NULL, xlfdSetwidthMap, 3393 field[XLFD_SETWIDTH]); 3394 } 3395 3396 /* XLFD_ADD_STYLE ignored. */ 3397 3398 /* 3399 * Pointsize in tenths of a point, but treat it as tenths of a pixel 3400 * for historical compatibility. 3401 */ 3402 3403 faPtr->size = 12; 3404 3405 if (FieldSpecified(field[XLFD_POINT_SIZE])) { 3406 if (field[XLFD_POINT_SIZE][0] == '[') { 3407 /* 3408 * Some X fonts have the point size specified as follows: 3409 * 3410 * [ N1 N2 N3 N4 ] 3411 * 3412 * where N1 is the point size (in points, not decipoints!), and 3413 * N2, N3, and N4 are some additional numbers that I don't know 3414 * the purpose of, so I ignore them. 3415 */ 3416 3417 faPtr->size = atoi(field[XLFD_POINT_SIZE] + 1); 3418 } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE], 3419 &faPtr->size) == TCL_OK) { 3420 faPtr->size /= 10; 3421 } else { 3422 return TCL_ERROR; 3423 } 3424 } 3425 3426 /* 3427 * Pixel height of font. If specified, overrides pointsize. 3428 */ 3429 3430 if (FieldSpecified(field[XLFD_PIXEL_SIZE])) { 3431 if (field[XLFD_PIXEL_SIZE][0] == '[') { 3432 /* 3433 * Some X fonts have the pixel size specified as follows: 3434 * 3435 * [ N1 N2 N3 N4 ] 3436 * 3437 * where N1 is the pixel size, and where N2, N3, and N4 3438 * are some additional numbers that I don't know 3439 * the purpose of, so I ignore them. 3440 */ 3441 3442 faPtr->size = atoi(field[XLFD_PIXEL_SIZE] + 1); 3443 } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE], 3444 &faPtr->size) != TCL_OK) { 3445 return TCL_ERROR; 3446 } 3447 } 3448 3449 faPtr->size = -faPtr->size; 3450 3451 /* XLFD_RESOLUTION_X ignored. */ 3452 3453 /* XLFD_RESOLUTION_Y ignored. */ 3454 3455 /* XLFD_SPACING ignored. */ 3456 3457 /* XLFD_AVERAGE_WIDTH ignored. */ 3458 3459 if (FieldSpecified(field[XLFD_CHARSET])) { 3460 xaPtr->charset = Tk_GetUid(field[XLFD_CHARSET]); 3461 } else { 3462 xaPtr->charset = Tk_GetUid("iso8859-1"); 3463 } 3464 Tcl_DStringFree(&ds); 3465 return TCL_OK; 3466} 3467 3468/* 3469 *--------------------------------------------------------------------------- 3470 * 3471 * FieldSpecified -- 3472 * 3473 * Helper function for TkParseXLFD(). Determines if a field in the 3474 * XLFD was set to a non-null, non-don't-care value. 3475 * 3476 * Results: 3477 * The return value is 0 if the field in the XLFD was not set and 3478 * should be ignored, non-zero otherwise. 3479 * 3480 * Side effects: 3481 * None. 3482 * 3483 *--------------------------------------------------------------------------- 3484 */ 3485 3486static int 3487FieldSpecified(field) 3488 CONST char *field; /* The field of the XLFD to check. Strictly 3489 * speaking, only when the string is "*" does it mean 3490 * don't-care. However, an unspecified or question 3491 * mark is also interpreted as don't-care. */ 3492{ 3493 char ch; 3494 3495 if (field == NULL) { 3496 return 0; 3497 } 3498 ch = field[0]; 3499 return (ch != '*' && ch != '?'); 3500} 3501 3502/* 3503 *--------------------------------------------------------------------------- 3504 * 3505 * TkFontGetPixels -- 3506 * 3507 * Given a font size specification (as described in the TkFontAttributes 3508 * structure) return the number of pixels it represents. 3509 * 3510 * Results: 3511 * As above. 3512 * 3513 * Side effects: 3514 * None. 3515 * 3516 *--------------------------------------------------------------------------- 3517 */ 3518 3519int 3520TkFontGetPixels(tkwin, size) 3521 Tk_Window tkwin; /* For point->pixel conversion factor. */ 3522 int size; /* Font size. */ 3523{ 3524 double d; 3525 3526 if (size < 0) { 3527 return -size; 3528 } 3529 3530 d = size * 25.4 / 72.0; 3531 d *= WidthOfScreen(Tk_Screen(tkwin)); 3532 d /= WidthMMOfScreen(Tk_Screen(tkwin)); 3533 return (int) (d + 0.5); 3534} 3535 3536/* 3537 *--------------------------------------------------------------------------- 3538 * 3539 * TkFontGetPoints -- 3540 * 3541 * Given a font size specification (as described in the TkFontAttributes 3542 * structure) return the number of points it represents. 3543 * 3544 * Results: 3545 * As above. 3546 * 3547 * Side effects: 3548 * None. 3549 * 3550 *--------------------------------------------------------------------------- 3551 */ 3552 3553int 3554TkFontGetPoints(tkwin, size) 3555 Tk_Window tkwin; /* For pixel->point conversion factor. */ 3556 int size; /* Font size. */ 3557{ 3558 double d; 3559 3560 if (size >= 0) { 3561 return size; 3562 } 3563 3564 d = -size * 72.0 / 25.4; 3565 d *= WidthMMOfScreen(Tk_Screen(tkwin)); 3566 d /= WidthOfScreen(Tk_Screen(tkwin)); 3567 return (int) (d + 0.5); 3568} 3569 3570/* 3571 *------------------------------------------------------------------------- 3572 * 3573 * TkFontGetAliasList -- 3574 * 3575 * Given a font name, find the list of all aliases for that font 3576 * name. One of the names in this list will probably be the name 3577 * that this platform expects when asking for the font. 3578 * 3579 * Results: 3580 * As above. The return value is NULL if the font name has no 3581 * aliases. 3582 * 3583 * Side effects: 3584 * None. 3585 * 3586 *------------------------------------------------------------------------- 3587 */ 3588 3589char ** 3590TkFontGetAliasList(faceName) 3591 CONST char *faceName; /* Font name to test for aliases. */ 3592{ 3593 int i, j; 3594 3595 for (i = 0; fontAliases[i] != NULL; i++) { 3596 for (j = 0; fontAliases[i][j] != NULL; j++) { 3597 if (strcasecmp(faceName, fontAliases[i][j]) == 0) { 3598 return fontAliases[i]; 3599 } 3600 } 3601 } 3602 return NULL; 3603} 3604 3605/* 3606 *------------------------------------------------------------------------- 3607 * 3608 * TkFontGetFallbacks -- 3609 * 3610 * Get the list of font fallbacks that the platform-specific code 3611 * can use to try to find the closest matching font the name 3612 * requested. 3613 * 3614 * Results: 3615 * As above. 3616 * 3617 * Side effects: 3618 * None. 3619 * 3620 *------------------------------------------------------------------------- 3621 */ 3622 3623char *** 3624TkFontGetFallbacks() 3625{ 3626 return fontFallbacks; 3627} 3628 3629/* 3630 *------------------------------------------------------------------------- 3631 * 3632 * TkFontGetGlobalClass -- 3633 * 3634 * Get the list of fonts to try if the requested font name does not 3635 * exist and no fallbacks for that font name could be used either. 3636 * The names in this list are considered preferred over all the other 3637 * font names in the system when looking for a last-ditch fallback. 3638 * 3639 * Results: 3640 * As above. 3641 * 3642 * Side effects: 3643 * None. 3644 * 3645 *------------------------------------------------------------------------- 3646 */ 3647 3648char ** 3649TkFontGetGlobalClass() 3650{ 3651 return globalFontClass; 3652} 3653 3654/* 3655 *------------------------------------------------------------------------- 3656 * 3657 * TkFontGetSymbolClass -- 3658 * 3659 * Get the list of fonts that are symbolic; used if the operating 3660 * system cannot apriori identify symbolic fonts on its own. 3661 * 3662 * Results: 3663 * As above. 3664 * 3665 * Side effects: 3666 * None. 3667 * 3668 *------------------------------------------------------------------------- 3669 */ 3670 3671char ** 3672TkFontGetSymbolClass() 3673{ 3674 return symbolClass; 3675} 3676 3677/* 3678 *---------------------------------------------------------------------- 3679 * 3680 * TkDebugFont -- 3681 * 3682 * This procedure returns debugging information about a font. 3683 * 3684 * Results: 3685 * The return value is a list with one sublist for each TkFont 3686 * corresponding to "name". Each sublist has two elements that 3687 * contain the resourceRefCount and objRefCount fields from the 3688 * TkFont structure. 3689 * 3690 * Side effects: 3691 * None. 3692 * 3693 *---------------------------------------------------------------------- 3694 */ 3695 3696Tcl_Obj * 3697TkDebugFont(tkwin, name) 3698 Tk_Window tkwin; /* The window in which the font will be 3699 * used (not currently used). */ 3700 char *name; /* Name of the desired color. */ 3701{ 3702 TkFont *fontPtr; 3703 Tcl_HashEntry *hashPtr; 3704 Tcl_Obj *resultPtr, *objPtr; 3705 3706 resultPtr = Tcl_NewObj(); 3707 hashPtr = Tcl_FindHashEntry( 3708 &((TkWindow *) tkwin)->mainPtr->fontInfoPtr->fontCache, name); 3709 if (hashPtr != NULL) { 3710 fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); 3711 if (fontPtr == NULL) { 3712 panic("TkDebugFont found empty hash table entry"); 3713 } 3714 for ( ; (fontPtr != NULL); fontPtr = fontPtr->nextPtr) { 3715 objPtr = Tcl_NewObj(); 3716 Tcl_ListObjAppendElement(NULL, objPtr, 3717 Tcl_NewIntObj(fontPtr->resourceRefCount)); 3718 Tcl_ListObjAppendElement(NULL, objPtr, 3719 Tcl_NewIntObj(fontPtr->objRefCount)); 3720 Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); 3721 } 3722 } 3723 return resultPtr; 3724} 3725 3726/* 3727 *---------------------------------------------------------------------- 3728 * 3729 * TkFontGetFirstTextLayout -- 3730 * 3731 * This procedure returns the first chunk of a Tk_TextLayout, 3732 * i.e. until the first font change on the first line (or the 3733 * whole first line if there is no such font change). 3734 * 3735 * Results: 3736 * The return value is the byte length of the chunk, the chunk 3737 * itself is copied into dst and its Tk_Font into font. 3738 * 3739 * Side effects: 3740 * None. 3741 * 3742 *---------------------------------------------------------------------- 3743 */ 3744 3745int 3746TkFontGetFirstTextLayout( 3747 Tk_TextLayout layout, /* Layout information, from a previous call 3748 * to Tk_ComputeTextLayout(). */ 3749 Tk_Font * font, 3750 char * dst) 3751{ 3752 TextLayout *layoutPtr; 3753 LayoutChunk *chunkPtr; 3754 int numBytesInChunk; 3755 3756 layoutPtr = (TextLayout *)layout; 3757 if ((layoutPtr==NULL) 3758 || (layoutPtr->numChunks==0) 3759 || (layoutPtr->chunks->numDisplayChars <= 0)) { 3760 dst[0] = '\0'; 3761 return 0; 3762 } 3763 chunkPtr = layoutPtr->chunks; 3764 numBytesInChunk = chunkPtr->numBytes; 3765 strncpy(dst, chunkPtr->start, (size_t) numBytesInChunk); 3766 *font = layoutPtr->tkfont; 3767 return numBytesInChunk; 3768} 3769