|
|
1.1 ! root 1: /* ! 2: * tkFont.c -- ! 3: * ! 4: * This file maintains a database of looked-up fonts for the Tk ! 5: * toolkit, in order to avoid round-trips to the server to map ! 6: * font names to XFontStructs. ! 7: * ! 8: * Copyright 1990 Regents of the University of California ! 9: * Permission to use, copy, modify, and distribute this ! 10: * software and its documentation for any purpose and without ! 11: * fee is hereby granted, provided that the above copyright ! 12: * notice appear in all copies. The University of California ! 13: * makes no representations about the suitability of this ! 14: * software for any purpose. It is provided "as is" without ! 15: * express or implied warranty. ! 16: */ ! 17: ! 18: #ifndef lint ! 19: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkFont.c,v 1.21 92/06/15 14:00:19 ouster Exp $ SPRITE (Berkeley)"; ! 20: #endif ! 21: ! 22: #include "tkconfig.h" ! 23: #include "tkint.h" ! 24: ! 25: /* ! 26: * This module caches extra information about fonts in addition to ! 27: * what X already provides. The extra information is used by the ! 28: * TkMeasureChars procedure, and consists of two parts: a type and ! 29: * a width. The type is one of the following: ! 30: * ! 31: * NORMAL: Standard character. ! 32: * TAB: Tab character: output enough space to ! 33: * get to next tab stop. ! 34: * NEWLINE: Newline character: don't output anything more ! 35: * on this line (character has infinite width). ! 36: * REPLACE: This character doesn't print: instead of ! 37: * displaying character, display a replacement ! 38: * sequence of the form "\xdd" where dd is the ! 39: * hex equivalent of the character. ! 40: * SKIP: Don't display anything for this character. This ! 41: * is only used where the font doesn't contain ! 42: * all the characters needed to generate ! 43: * replacement sequences. ! 44: * The width gives the total width of the displayed character or ! 45: * sequence: for replacement sequences, it gives the width of the ! 46: * sequence. ! 47: */ ! 48: ! 49: #define NORMAL 1 ! 50: #define TAB 2 ! 51: #define NEWLINE 3 ! 52: #define REPLACE 4 ! 53: #define SKIP 5 ! 54: ! 55: /* ! 56: * One of the following data structures exists for each font that is ! 57: * currently active. The structure is indexed with two hash tables, ! 58: * one based on font name and one based on XFontStruct address. ! 59: */ ! 60: ! 61: typedef struct { ! 62: XFontStruct *fontStructPtr; /* X information about font. */ ! 63: Display *display; /* Display to which font belongs. */ ! 64: int refCount; /* Number of active uses of this font. */ ! 65: char *types; /* Malloc'ed array giving types of all ! 66: * chars in the font (may be NULL). */ ! 67: unsigned char *widths; /* Malloc'ed array giving widths of all ! 68: * chars in the font (may be NULL). */ ! 69: int tabWidth; /* Width of tabs in this font. */ ! 70: Tcl_HashEntry *nameHashPtr; /* Entry in name-based hash table (needed ! 71: * when deleting this structure). */ ! 72: } TkFont; ! 73: ! 74: /* ! 75: * Hash table for name -> TkFont mapping, and key structure used to ! 76: * index into that table: ! 77: */ ! 78: ! 79: static Tcl_HashTable nameTable; ! 80: typedef struct { ! 81: Tk_Uid name; /* Name of font. */ ! 82: Display *display; /* Display for which font is valid. */ ! 83: } NameKey; ! 84: ! 85: /* ! 86: * Hash table for font struct -> TkFont mapping. This table is ! 87: * indexed by the XFontStruct address. ! 88: */ ! 89: ! 90: static Tcl_HashTable fontTable; ! 91: ! 92: static int initialized = 0; /* 0 means static structures haven't been ! 93: * initialized yet. */ ! 94: ! 95: /* ! 96: * To speed up TkMeasureChars, the variables below keep the last ! 97: * mapping from (XFontStruct *) to (TkFont *). ! 98: */ ! 99: ! 100: static TkFont *lastFontPtr = NULL; ! 101: static XFontStruct *lastFontStructPtr = NULL; ! 102: ! 103: /* ! 104: * Characters used when displaying control sequences as their ! 105: * hex equivalents. ! 106: */ ! 107: ! 108: static char hexChars[] = "0123456789abcdefx\\"; ! 109: ! 110: /* ! 111: * Forward declarations for procedures defined in this file: ! 112: */ ! 113: ! 114: static void FontInit _ANSI_ARGS_((void)); ! 115: static void SetFontMetrics _ANSI_ARGS_((TkFont *fontPtr)); ! 116: ! 117: /* ! 118: *---------------------------------------------------------------------- ! 119: * ! 120: * Tk_GetFontStruct -- ! 121: * ! 122: * Given a string name for a font, map the name to an XFontStruct ! 123: * describing the font. ! 124: * ! 125: * Results: ! 126: * The return value is normally a pointer to the font description ! 127: * for the desired font. If an error occurs in mapping the string ! 128: * to a font, then an error message will be left in interp->result ! 129: * and NULL will be returned. ! 130: * ! 131: * Side effects: ! 132: * The font is added to an internal database with a reference count. ! 133: * For each call to this procedure, there should eventually be a call ! 134: * to Tk_FreeFontStruct, so that the database is cleaned up when fonts ! 135: * aren't in use anymore. ! 136: * ! 137: *---------------------------------------------------------------------- ! 138: */ ! 139: ! 140: XFontStruct * ! 141: Tk_GetFontStruct(interp, tkwin, name) ! 142: Tcl_Interp *interp; /* Place to leave error message if ! 143: * font can't be found. */ ! 144: Tk_Window tkwin; /* Window in which font will be used. */ ! 145: Tk_Uid name; /* Name of font (in form suitable for ! 146: * passing to XLoadQueryFont). */ ! 147: { ! 148: NameKey nameKey; ! 149: Tcl_HashEntry *nameHashPtr, *fontHashPtr; ! 150: int new; ! 151: register TkFont *fontPtr; ! 152: XFontStruct *fontStructPtr; ! 153: ! 154: if (!initialized) { ! 155: FontInit(); ! 156: } ! 157: ! 158: /* ! 159: * First, check to see if there's already a mapping for this font ! 160: * name. ! 161: */ ! 162: ! 163: nameKey.name = name; ! 164: nameKey.display = Tk_Display(tkwin); ! 165: nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new); ! 166: if (!new) { ! 167: fontPtr = (TkFont *) Tcl_GetHashValue(nameHashPtr); ! 168: fontPtr->refCount++; ! 169: return fontPtr->fontStructPtr; ! 170: } ! 171: ! 172: /* ! 173: * The name isn't currently known. Map from the name to a font, and ! 174: * add a new structure to the database. ! 175: */ ! 176: ! 177: fontStructPtr = XLoadQueryFont(nameKey.display, name); ! 178: if (fontStructPtr == NULL) { ! 179: Tcl_DeleteHashEntry(nameHashPtr); ! 180: Tcl_AppendResult(interp, "font \"", name, "\" doesn't exist", ! 181: (char *) NULL); ! 182: return NULL; ! 183: } ! 184: fontPtr = (TkFont *) ckalloc(sizeof(TkFont)); ! 185: fontPtr->display = nameKey.display; ! 186: fontPtr->fontStructPtr = fontStructPtr; ! 187: fontPtr->refCount = 1; ! 188: fontPtr->types = NULL; ! 189: fontPtr->widths = NULL; ! 190: fontPtr->nameHashPtr = nameHashPtr; ! 191: fontHashPtr = Tcl_CreateHashEntry(&fontTable, (char *) fontStructPtr, &new); ! 192: if (!new) { ! 193: panic("XFontStruct already registered in Tk_GetFontStruct"); ! 194: } ! 195: Tcl_SetHashValue(nameHashPtr, fontPtr); ! 196: Tcl_SetHashValue(fontHashPtr, fontPtr); ! 197: return fontPtr->fontStructPtr; ! 198: } ! 199: ! 200: /* ! 201: *-------------------------------------------------------------- ! 202: * ! 203: * Tk_NameOfFontStruct -- ! 204: * ! 205: * Given a font, return a textual string identifying it. ! 206: * ! 207: * Results: ! 208: * If font was created by Tk_GetFontStruct, then the return ! 209: * value is the "string" that was used to create it. ! 210: * Otherwise the return value is a string giving the X ! 211: * identifier for the font. The storage for the returned ! 212: * string is only guaranteed to persist up until the next ! 213: * call to this procedure. ! 214: * ! 215: * Side effects: ! 216: * None. ! 217: * ! 218: *-------------------------------------------------------------- ! 219: */ ! 220: ! 221: char * ! 222: Tk_NameOfFontStruct(fontStructPtr) ! 223: XFontStruct *fontStructPtr; /* Font whose name is desired. */ ! 224: { ! 225: Tcl_HashEntry *fontHashPtr; ! 226: TkFont *fontPtr; ! 227: static char string[20]; ! 228: ! 229: if (!initialized) { ! 230: printid: ! 231: sprintf(string, "font id 0x%x", fontStructPtr->fid); ! 232: return string; ! 233: } ! 234: fontHashPtr = Tcl_FindHashEntry(&fontTable, (char *) fontStructPtr); ! 235: if (fontHashPtr == NULL) { ! 236: goto printid; ! 237: } ! 238: fontPtr = (TkFont *) Tcl_GetHashValue(fontHashPtr); ! 239: return ((NameKey *) fontPtr->nameHashPtr->key.words)->name; ! 240: } ! 241: ! 242: /* ! 243: *---------------------------------------------------------------------- ! 244: * ! 245: * Tk_FreeFontStruct -- ! 246: * ! 247: * This procedure is called to release a font allocated by ! 248: * Tk_GetFontStruct. ! 249: * ! 250: * Results: ! 251: * None. ! 252: * ! 253: * Side effects: ! 254: * The reference count associated with font is decremented, and ! 255: * the font is officially deallocated if no-one is using it ! 256: * anymore. ! 257: * ! 258: *---------------------------------------------------------------------- ! 259: */ ! 260: ! 261: void ! 262: Tk_FreeFontStruct(fontStructPtr) ! 263: XFontStruct *fontStructPtr; /* Font to be released. */ ! 264: { ! 265: Tcl_HashEntry *fontHashPtr; ! 266: register TkFont *fontPtr; ! 267: ! 268: if (!initialized) { ! 269: panic("Tk_FreeFontStruct called before Tk_GetFontStruct"); ! 270: } ! 271: ! 272: fontHashPtr = Tcl_FindHashEntry(&fontTable, (char *) fontStructPtr); ! 273: if (fontHashPtr == NULL) { ! 274: panic("Tk_FreeFontStruct received unknown font argument"); ! 275: } ! 276: fontPtr = (TkFont *) Tcl_GetHashValue(fontHashPtr); ! 277: fontPtr->refCount--; ! 278: if (fontPtr->refCount == 0) { ! 279: XFreeFont(fontPtr->display, fontPtr->fontStructPtr); ! 280: Tcl_DeleteHashEntry(fontPtr->nameHashPtr); ! 281: Tcl_DeleteHashEntry(fontHashPtr); ! 282: if (fontPtr->types != NULL) { ! 283: ckfree(fontPtr->types); ! 284: } ! 285: if (fontPtr->widths != NULL) { ! 286: ckfree((char *) fontPtr->widths); ! 287: } ! 288: ckfree((char *) fontPtr); ! 289: lastFontStructPtr = NULL; ! 290: } ! 291: } ! 292: ! 293: /* ! 294: *---------------------------------------------------------------------- ! 295: * ! 296: * FontInit -- ! 297: * ! 298: * Initialize the structure used for font management. ! 299: * ! 300: * Results: ! 301: * None. ! 302: * ! 303: * Side effects: ! 304: * Read the code. ! 305: * ! 306: *---------------------------------------------------------------------- ! 307: */ ! 308: ! 309: static void ! 310: FontInit() ! 311: { ! 312: initialized = 1; ! 313: Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); ! 314: Tcl_InitHashTable(&fontTable, TCL_ONE_WORD_KEYS); ! 315: } ! 316: ! 317: /* ! 318: *-------------------------------------------------------------- ! 319: * ! 320: * SetFontMetrics -- ! 321: * ! 322: * This procedure is called to fill in the "widths" and "types" ! 323: * arrays for a font. ! 324: * ! 325: * Results: ! 326: * None. ! 327: * ! 328: * Side effects: ! 329: * FontPtr gets modified to hold font metric information. ! 330: * ! 331: *-------------------------------------------------------------- ! 332: */ ! 333: ! 334: static void ! 335: SetFontMetrics(fontPtr) ! 336: register TkFont *fontPtr; /* Font structure in which to ! 337: * set metrics. */ ! 338: { ! 339: int i, replaceOK, baseWidth; ! 340: register XFontStruct *fontStructPtr = fontPtr->fontStructPtr; ! 341: char *p; ! 342: ! 343: /* ! 344: * Pass 1: initialize the arrays. ! 345: */ ! 346: ! 347: fontPtr->types = (char *) ckalloc(256); ! 348: fontPtr->widths = (unsigned char *) ckalloc(256); ! 349: for (i = 0; i < 256; i++) { ! 350: fontPtr->types[i] = REPLACE; ! 351: } ! 352: ! 353: /* ! 354: * Pass 2: for all characters that exist in the font and are ! 355: * not control characters, fill in the type and width ! 356: * information. ! 357: */ ! 358: ! 359: for (i = ' '; i < 256; i++) { ! 360: if ((i == 0177) || (i < fontStructPtr->min_char_or_byte2) ! 361: || (i > fontStructPtr->max_char_or_byte2)) { ! 362: continue; ! 363: } ! 364: fontPtr->types[i] = NORMAL; ! 365: if (fontStructPtr->per_char == NULL) { ! 366: fontPtr->widths[i] = fontStructPtr->min_bounds.width; ! 367: } else { ! 368: fontPtr->widths[i] = fontStructPtr->per_char[i ! 369: - fontStructPtr->min_char_or_byte2].width; ! 370: } ! 371: } ! 372: ! 373: /* ! 374: * Pass 3: fill in information for characters that have to ! 375: * be replaced with "\xhh" strings. If the font doesn't ! 376: * have the characters needed for this, then just use the ! 377: * font's default character. ! 378: */ ! 379: ! 380: replaceOK = 1; ! 381: baseWidth = fontPtr->widths['\\'] + fontPtr->widths['x']; ! 382: for (p = hexChars; *p != 0; p++) { ! 383: if (fontPtr->types[*p] != NORMAL) { ! 384: replaceOK = 0; ! 385: break; ! 386: } ! 387: } ! 388: for (i = 0; i < 256; i++) { ! 389: if (fontPtr->types[i] != REPLACE) { ! 390: continue; ! 391: } ! 392: if (replaceOK) { ! 393: fontPtr->widths[i] = baseWidth ! 394: + fontPtr->widths[hexChars[i & 0xf]] ! 395: + fontPtr->widths[hexChars[(i>>4) & 0xf]]; ! 396: } else { ! 397: fontPtr->types[i] = SKIP; ! 398: fontPtr->widths[i] = 0; ! 399: } ! 400: } ! 401: ! 402: /* ! 403: * Lastly, fill in special information for newline and tab. ! 404: */ ! 405: ! 406: fontPtr->types['\n'] = NEWLINE; ! 407: fontPtr->widths['\n'] = 0; ! 408: fontPtr->types['\t'] = TAB; ! 409: fontPtr->widths['\t'] = 0; ! 410: if (fontPtr->types['0'] == NORMAL) { ! 411: fontPtr->tabWidth = 8*fontPtr->widths['0']; ! 412: } else { ! 413: fontPtr->tabWidth = 8*fontStructPtr->max_bounds.width; ! 414: } ! 415: ! 416: /* ! 417: * Make sure the tab width isn't zero (some fonts may not have enough ! 418: * information to set a reasonable tab width). ! 419: */ ! 420: ! 421: if (fontPtr->tabWidth == 0) { ! 422: fontPtr->tabWidth = 1; ! 423: } ! 424: } ! 425: ! 426: /* ! 427: *-------------------------------------------------------------- ! 428: * ! 429: * TkMeasureChars -- ! 430: * ! 431: * Measure the number of characters from a string that ! 432: * will fit in a given horizontal span. The measurement ! 433: * is done under the assumption that TkDisplayChars will ! 434: * be used to actually display the characters. ! 435: * ! 436: * Results: ! 437: * The return value is the number of characters from source ! 438: * that fit in the span given by startX and maxX. *nextXPtr ! 439: * is filled in with the x-coordinate at which the first ! 440: * character that didn't fit would be drawn, if it were to ! 441: * be drawn. ! 442: * ! 443: * Side effects: ! 444: * None. ! 445: * ! 446: *-------------------------------------------------------------- ! 447: */ ! 448: ! 449: int ! 450: TkMeasureChars(fontStructPtr, source, maxChars, startX, maxX, flags, nextXPtr) ! 451: XFontStruct *fontStructPtr; /* Font in which to draw characters. */ ! 452: char *source; /* Characters to be displayed. Need not ! 453: * be NULL-terminated. */ ! 454: int maxChars; /* Maximum # of characters to consider from ! 455: * source. */ ! 456: int startX; /* X-position at which first character will ! 457: * be drawn. */ ! 458: int maxX; /* Don't consider any character that would ! 459: * cross this x-position. */ ! 460: int flags; /* Various flag bits OR-ed together. ! 461: * TK_WHOLE_WORDS means stop on a word boundary ! 462: * (just before a space character) if ! 463: * possible. TK_AT_LEAST_ONE means always ! 464: * return a value of at least one, even ! 465: * if the character doesn't fit. ! 466: * TK_PARTIAL_OK means it's OK to display only ! 467: * a part of the last character in the line. ! 468: * TK_NEWLINES_NOT_SPECIAL means that newlines ! 469: * are treated just like other control chars: ! 470: * they don't terminate the line,*/ ! 471: int *nextXPtr; /* Return x-position of terminating ! 472: * character here. */ ! 473: { ! 474: register TkFont *fontPtr; ! 475: register char *p; /* Current character. */ ! 476: register int c; ! 477: char *term; /* Pointer to most recent character that ! 478: * may legally be a terminating character. */ ! 479: int termX; /* X-position just after term. */ ! 480: int curX; /* X-position corresponding to p. */ ! 481: int newX; /* X-position corresponding to p+1. */ ! 482: int type; ! 483: ! 484: /* ! 485: * Find the TkFont structure for this font, and make sure its ! 486: * font metrics exist. ! 487: */ ! 488: ! 489: if (lastFontStructPtr == fontStructPtr) { ! 490: fontPtr = lastFontPtr; ! 491: } else { ! 492: Tcl_HashEntry *fontHashPtr; ! 493: ! 494: if (!initialized) { ! 495: badArg: ! 496: panic("TkMeasureChars received unknown font argument"); ! 497: } ! 498: ! 499: fontHashPtr = Tcl_FindHashEntry(&fontTable, (char *) fontStructPtr); ! 500: if (fontHashPtr == NULL) { ! 501: goto badArg; ! 502: } ! 503: fontPtr = (TkFont *) Tcl_GetHashValue(fontHashPtr); ! 504: lastFontStructPtr = fontPtr->fontStructPtr; ! 505: lastFontPtr = fontPtr; ! 506: } ! 507: if (fontPtr->types == NULL) { ! 508: SetFontMetrics(fontPtr); ! 509: } ! 510: ! 511: /* ! 512: * Scan the input string one character at a time, until a character ! 513: * is found that crosses maxX. ! 514: */ ! 515: ! 516: newX = curX = startX; ! 517: termX = 0; /* Not needed, but eliminates compiler warning. */ ! 518: term = source; ! 519: for (p = source, c = *p & 0xff; maxChars > 0; p++, maxChars--) { ! 520: type = fontPtr->types[c]; ! 521: if (type == NORMAL) { ! 522: newX += fontPtr->widths[c]; ! 523: } else if (type == TAB) { ! 524: newX += fontPtr->tabWidth; ! 525: newX -= newX % fontPtr->tabWidth; ! 526: } else if (type == REPLACE) { ! 527: replaceType: ! 528: newX += fontPtr->widths['\\'] + fontPtr->widths['x'] ! 529: + fontPtr->widths[hexChars[(c >> 4) & 0xf]] ! 530: + fontPtr->widths[hexChars[c & 0xf]]; ! 531: } else if (type == NEWLINE) { ! 532: if (flags & TK_NEWLINES_NOT_SPECIAL) { ! 533: goto replaceType; ! 534: } ! 535: break; ! 536: } else if (type != SKIP) { ! 537: panic("Unknown type %d in TkMeasureChars", type); ! 538: } ! 539: if (newX > maxX) { ! 540: break; ! 541: } ! 542: c = p[1] & 0xff; ! 543: if (isspace(c) || (c == 0)) { ! 544: term = p+1; ! 545: termX = newX; ! 546: } ! 547: curX = newX; ! 548: } ! 549: ! 550: /* ! 551: * P points to the first character that doesn't fit in the desired ! 552: * span. Use the flags to figure out what to return. ! 553: */ ! 554: ! 555: if ((flags & TK_PARTIAL_OK) && (curX < maxX)) { ! 556: curX = newX; ! 557: p++; ! 558: } ! 559: if ((flags & TK_AT_LEAST_ONE) && (term == source) && (maxChars > 0) ! 560: & !isspace(*term)) { ! 561: term = p; ! 562: termX = curX; ! 563: if (term == source) { ! 564: term++; ! 565: termX = newX; ! 566: } ! 567: } else if ((maxChars == 0) || !(flags & TK_WHOLE_WORDS)) { ! 568: term = p; ! 569: termX = curX; ! 570: } ! 571: *nextXPtr = termX; ! 572: return term-source; ! 573: } ! 574: ! 575: /* ! 576: *-------------------------------------------------------------- ! 577: * ! 578: * TkDisplayChars -- ! 579: * ! 580: * Draw a string of characters on the screen, converting ! 581: * tabs to the right number of spaces and control characters ! 582: * to sequences of the form "\xhh" where hh are two hex ! 583: * digits. ! 584: * ! 585: * Results: ! 586: * None. ! 587: * ! 588: * Side effects: ! 589: * Information gets drawn on the screen. ! 590: * ! 591: *-------------------------------------------------------------- ! 592: */ ! 593: ! 594: void ! 595: TkDisplayChars(display, drawable, gc, fontStructPtr, string, numChars, ! 596: x, y, flags) ! 597: Display *display; /* Display on which to draw. */ ! 598: Drawable drawable; /* Window or pixmap in which to draw. */ ! 599: GC gc; /* Graphics context for actually drawing ! 600: * characters. */ ! 601: XFontStruct *fontStructPtr; /* Font used in GC; must have been allocated ! 602: * by Tk_GetFontStruct. Used to compute sizes ! 603: * of tabs, etc. */ ! 604: char *string; /* Characters to be displayed. */ ! 605: int numChars; /* Number of characters to display from ! 606: * string. */ ! 607: int x, y; /* Coordinates at which to draw string. */ ! 608: int flags; /* Flags to control display. Only ! 609: * TK_NEWLINES_NOT_SPECIAL is supported right ! 610: * now. See TkMeasureChars for information ! 611: * about it. */ ! 612: { ! 613: register TkFont *fontPtr; ! 614: register char *p; /* Current character being scanned. */ ! 615: register int c; ! 616: int type; ! 617: char *start; /* First character waiting to be displayed. */ ! 618: int startX; /* X-coordinate corresponding to start. */ ! 619: int curX; /* X-coordinate corresponding to p. */ ! 620: char replace[10]; ! 621: ! 622: /* ! 623: * Find the TkFont structure for this font, and make sure its ! 624: * font metrics exist. ! 625: */ ! 626: ! 627: if (lastFontStructPtr == fontStructPtr) { ! 628: fontPtr = lastFontPtr; ! 629: } else { ! 630: Tcl_HashEntry *fontHashPtr; ! 631: ! 632: if (!initialized) { ! 633: badArg: ! 634: panic("TkDisplayChars received unknown font argument"); ! 635: } ! 636: ! 637: fontHashPtr = Tcl_FindHashEntry(&fontTable, (char *) fontStructPtr); ! 638: if (fontHashPtr == NULL) { ! 639: goto badArg; ! 640: } ! 641: fontPtr = (TkFont *) Tcl_GetHashValue(fontHashPtr); ! 642: lastFontStructPtr = fontPtr->fontStructPtr; ! 643: lastFontPtr = fontPtr; ! 644: } ! 645: if (fontPtr->types == NULL) { ! 646: SetFontMetrics(fontPtr); ! 647: } ! 648: ! 649: /* ! 650: * Scan the string one character at a time. Display control ! 651: * characters immediately, but delay displaying normal characters ! 652: * in order to pass many characters to the server all together. ! 653: */ ! 654: ! 655: startX = curX = x; ! 656: start = string; ! 657: for (p = string; numChars > 0; numChars--, p++) { ! 658: c = *p & 0xff; ! 659: type = fontPtr->types[c]; ! 660: if (type == NORMAL) { ! 661: curX += fontPtr->widths[c]; ! 662: continue; ! 663: } ! 664: if (p != start) { ! 665: XDrawString(display, drawable, gc, startX, y, start, p - start); ! 666: startX = curX; ! 667: } ! 668: if (type == TAB) { ! 669: curX += fontPtr->tabWidth; ! 670: curX -= curX % fontPtr->tabWidth; ! 671: } else if (type == REPLACE) { ! 672: doReplace: ! 673: replace[0] = '\\'; ! 674: replace[1] = 'x'; ! 675: replace[2] = hexChars[(c >> 4) & 0xf]; ! 676: replace[3] = hexChars[c & 0xf]; ! 677: XDrawString(display, drawable, gc, startX, y, replace, 4); ! 678: curX += fontPtr->widths[replace[0]] ! 679: + fontPtr->widths[replace[1]] ! 680: + fontPtr->widths[replace[2]] ! 681: + fontPtr->widths[replace[3]]; ! 682: } else if (type == NEWLINE) { ! 683: if (flags & TK_NEWLINES_NOT_SPECIAL) { ! 684: goto doReplace; ! 685: } ! 686: y += fontStructPtr->ascent + fontStructPtr->descent; ! 687: curX = x; ! 688: } else if (type != SKIP) { ! 689: panic("Unknown type %d in TkDisplayChars", type); ! 690: } ! 691: startX = curX; ! 692: start = p+1; ! 693: } ! 694: ! 695: /* ! 696: * At the very end, there may be one last batch of normal characters ! 697: * to display. ! 698: */ ! 699: ! 700: if (p != start) { ! 701: XDrawString(display, drawable, gc, startX, y, start, p - start); ! 702: } ! 703: } ! 704: ! 705: /* ! 706: *---------------------------------------------------------------------- ! 707: * ! 708: * TkUnderlineChars -- ! 709: * ! 710: * This procedure draws an underline for a given range of characters ! 711: * in a given string, using appropriate information for the string's ! 712: * font. It doesn't draw the characters (which are assumed to have ! 713: * been displayed previously); it just draws the underline. ! 714: * ! 715: * Results: ! 716: * None. ! 717: * ! 718: * Side effects: ! 719: * Information gets displayed in "drawable". ! 720: * ! 721: *---------------------------------------------------------------------- ! 722: */ ! 723: ! 724: void ! 725: TkUnderlineChars(display, drawable, gc, fontStructPtr, string, x, y, ! 726: flags, firstChar, lastChar) ! 727: Display *display; /* Display on which to draw. */ ! 728: Drawable drawable; /* Window or pixmap in which to draw. */ ! 729: GC gc; /* Graphics context for actually drawing ! 730: * underline. */ ! 731: XFontStruct *fontStructPtr; /* Font used in GC; must have been allocated ! 732: * by Tk_GetFontStruct. Used to character ! 733: * dimensions, etc. */ ! 734: char *string; /* String containing characters to be ! 735: * underlined. */ ! 736: int x, y; /* Coordinates at which first character of ! 737: * string is drawn. */ ! 738: int flags; /* Flags that were passed to TkDisplayChars. */ ! 739: int firstChar; /* Index of first character to underline. */ ! 740: int lastChar; /* Index of last character to underline. */ ! 741: { ! 742: int xUnder, yUnder, width, height; ! 743: unsigned long value; ! 744: ! 745: /* ! 746: * First compute the vertical span of the underline, using font ! 747: * properties if they exist. ! 748: */ ! 749: ! 750: if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) { ! 751: yUnder = y + value; ! 752: } else { ! 753: yUnder = y + fontStructPtr->max_bounds.descent/2; ! 754: } ! 755: if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) { ! 756: height = value; ! 757: } else { ! 758: height = 2; ! 759: } ! 760: ! 761: /* ! 762: * Now compute the horizontal span of the underline. ! 763: */ ! 764: ! 765: TkMeasureChars(fontStructPtr, string, firstChar, x, (int) 1000000, flags, ! 766: &xUnder); ! 767: TkMeasureChars(fontStructPtr, string+firstChar, lastChar+1-firstChar, ! 768: xUnder, (int) 1000000, flags, &width); ! 769: width -= xUnder; ! 770: ! 771: XFillRectangle(display, drawable, gc, xUnder, yUnder, ! 772: (unsigned int) width, (unsigned int) height); ! 773: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.