Annotation of micropolis/src/tk/tkfont.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.