Annotation of micropolis/src/tk/tkfont.c, revision 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.