|
|
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.