home *** CD-ROM | disk | FTP | other *** search
- /*
- * tkFont.c --
- *
- * This file maintains a database of fonts for the Tk toolkit.
- * It also provides several utility procedures for measuring and
- * displaying text.
- *
- * Copyright (c) 1990-1994 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * SCCS: @(#) tkFont.c 1.72 97/07/22 15:33:45
- */
-
- #include "tkInt.h"
- #include "tkFont.h"
-
- /*
- * The following structure is used to keep track of all the fonts that
- * exist in the current application. It must be stored in the
- * TkMainInfo for the application.
- */
-
- typedef struct TkFontInfo {
- Tcl_HashTable fontCache; /* Map a string to an existing Tk_Font.
- * Keys are CachedFontKey structs, values are
- * TkFont structs. */
- Tcl_HashTable namedTable; /* Map a name to a set of attributes for a
- * font, used when constructing a Tk_Font from
- * a named font description. Keys are
- * Tk_Uids, values are NamedFont structs. */
- TkMainInfo *mainPtr; /* Application that owns this structure. */
- int updatePending;
- } TkFontInfo;
-
- /*
- * The following structure is used as a key in the fontCache.
- */
-
- typedef struct CachedFontKey {
- Display *display; /* Display for which font was constructed. */
- Tk_Uid string; /* String that describes font. */
- } CachedFontKey;
-
- /*
- * The following data structure is used to keep track of the font attributes
- * for each named font that has been defined. The named font is only deleted
- * when the last reference to it goes away.
- */
-
- typedef struct NamedFont {
- int refCount; /* Number of users of named font. */
- int deletePending; /* Non-zero if font should be deleted when
- * last reference goes away. */
- TkFontAttributes fa; /* Desired attributes for named font. */
- } NamedFont;
-
- /*
- * The following two structures are used to keep track of string
- * measurement information when using the text layout facilities.
- *
- * A LayoutChunk represents a contiguous range of text that can be measured
- * and displayed by low-level text calls. In general, chunks will be
- * delimited by newlines and tabs. Low-level, platform-specific things
- * like kerning and non-integer character widths may occur between the
- * characters in a single chunk, but not between characters in different
- * chunks.
- *
- * A TextLayout is a collection of LayoutChunks. It can be displayed with
- * respect to any origin. It is the implementation of the Tk_TextLayout
- * opaque token.
- */
-
- typedef struct LayoutChunk {
- CONST char *start; /* Pointer to simple string to be displayed.
- * This is a pointer into the TkTextLayout's
- * string. */
- int numChars; /* The number of characters in this chunk. */
- int numDisplayChars; /* The number of characters to display when
- * this chunk is displayed. Can be less than
- * numChars if extra space characters were
- * absorbed by the end of the chunk. This
- * will be < 0 if this is a chunk that is
- * holding a tab or newline. */
- int x, y; /* The origin of the first character in this
- * chunk with respect to the upper-left hand
- * corner of the TextLayout. */
- int totalWidth; /* Width in pixels of this chunk. Used
- * when hit testing the invisible spaces at
- * the end of a chunk. */
- int displayWidth; /* Width in pixels of the displayable
- * characters in this chunk. Can be less than
- * width if extra space characters were
- * absorbed by the end of the chunk. */
- } LayoutChunk;
-
- typedef struct TextLayout {
- Tk_Font tkfont; /* The font used when laying out the text. */
- CONST char *string; /* The string that was layed out. */
- int width; /* The maximum width of all lines in the
- * text layout. */
- int numChunks; /* Number of chunks actually used in
- * following array. */
- LayoutChunk chunks[1]; /* Array of chunks. The actual size will
- * be maxChunks. THIS FIELD MUST BE THE LAST
- * IN THE STRUCTURE. */
- } TextLayout;
-
- /*
- * The following structures are used as two-way maps between the values for
- * the fields in the TkFontAttributes structure and the strings used in
- * Tcl, when parsing both option-value format and style-list format font
- * name strings.
- */
-
- static TkStateMap weightMap[] = {
- {TK_FW_NORMAL, "normal"},
- {TK_FW_BOLD, "bold"},
- {TK_FW_UNKNOWN, NULL}
- };
-
- static TkStateMap slantMap[] = {
- {TK_FS_ROMAN, "roman"},
- {TK_FS_ITALIC, "italic"},
- {TK_FS_UNKNOWN, NULL}
- };
-
- static TkStateMap underlineMap[] = {
- {1, "underline"},
- {0, NULL}
- };
-
- static TkStateMap overstrikeMap[] = {
- {1, "overstrike"},
- {0, NULL}
- };
-
- /*
- * The following structures are used when parsing XLFD's into a set of
- * TkFontAttributes.
- */
-
- static TkStateMap xlfdWeightMap[] = {
- {TK_FW_NORMAL, "normal"},
- {TK_FW_NORMAL, "medium"},
- {TK_FW_NORMAL, "book"},
- {TK_FW_NORMAL, "light"},
- {TK_FW_BOLD, "bold"},
- {TK_FW_BOLD, "demi"},
- {TK_FW_BOLD, "demibold"},
- {TK_FW_NORMAL, NULL} /* Assume anything else is "normal". */
- };
-
- static TkStateMap xlfdSlantMap[] = {
- {TK_FS_ROMAN, "r"},
- {TK_FS_ITALIC, "i"},
- {TK_FS_OBLIQUE, "o"},
- {TK_FS_ROMAN, NULL} /* Assume anything else is "roman". */
- };
-
- static TkStateMap xlfdSetwidthMap[] = {
- {TK_SW_NORMAL, "normal"},
- {TK_SW_CONDENSE, "narrow"},
- {TK_SW_CONDENSE, "semicondensed"},
- {TK_SW_CONDENSE, "condensed"},
- {TK_SW_UNKNOWN, NULL}
- };
-
- static TkStateMap xlfdCharsetMap[] = {
- {TK_CS_NORMAL, "iso8859"},
- {TK_CS_SYMBOL, "adobe"},
- {TK_CS_SYMBOL, "sun"},
- {TK_CS_OTHER, NULL}
- };
-
- /*
- * The following structure and defines specify the valid builtin options
- * when configuring a set of font attributes.
- */
-
- static char *fontOpt[] = {
- "-family",
- "-size",
- "-weight",
- "-slant",
- "-underline",
- "-overstrike",
- NULL
- };
-
- #define FONT_FAMILY 0
- #define FONT_SIZE 1
- #define FONT_WEIGHT 2
- #define FONT_SLANT 3
- #define FONT_UNDERLINE 4
- #define FONT_OVERSTRIKE 5
- #define FONT_NUMFIELDS 6 /* Length of fontOpt array. */
-
- #define GetFontAttributes(tkfont) \
- ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa)
-
- #define GetFontMetrics(tkfont) \
- ((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm)
-
-
- static int ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp,
- Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[],
- TkFontAttributes *faPtr));
- static int FieldSpecified _ANSI_ARGS_((CONST char *field));
- static void GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp,
- CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr));
- static LayoutChunk * NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr,
- int *maxPtr, CONST char *start, int numChars,
- int curX, int newX, int y));
- static int ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp,
- Tk_Window tkwin, Tcl_Obj *objPtr,
- TkFontAttributes *faPtr));
- static void RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr));
- static void TheWorldHasChanged _ANSI_ARGS_((
- ClientData clientData));
- static void UpdateDependantFonts _ANSI_ARGS_((TkFontInfo *fiPtr,
- Tk_Window tkwin, Tcl_HashEntry *namedHashPtr));
-
-
-
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkFontPkgInit --
- *
- * This procedure is called when an application is created. It
- * initializes all the structures that are used by the font
- * package on a per application basis.
- *
- * Results:
- * Returns a token that must be stored in the TkMainInfo for this
- * application.
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
- void
- TkFontPkgInit(mainPtr)
- TkMainInfo *mainPtr; /* The application being created. */
- {
- TkFontInfo *fiPtr;
-
- fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo));
- Tcl_InitHashTable(&fiPtr->fontCache, sizeof(CachedFontKey) / sizeof(int));
- Tcl_InitHashTable(&fiPtr->namedTable, TCL_ONE_WORD_KEYS);
- fiPtr->mainPtr = mainPtr;
- fiPtr->updatePending = 0;
- mainPtr->fontInfoPtr = fiPtr;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkFontPkgFree --
- *
- * This procedure is called when an application is deleted. It
- * deletes all the structures that were used by the font package
- * for this application.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory freed.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- TkFontPkgFree(mainPtr)
- TkMainInfo *mainPtr; /* The application being deleted. */
- {
- TkFontInfo *fiPtr;
- Tcl_HashEntry *hPtr;
- Tcl_HashSearch search;
-
- fiPtr = mainPtr->fontInfoPtr;
-
- if (fiPtr->fontCache.numEntries != 0) {
- panic("TkFontPkgFree: all fonts should have been freed already");
- }
- Tcl_DeleteHashTable(&fiPtr->fontCache);
-
- hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
- while (hPtr != NULL) {
- ckfree((char *) Tcl_GetHashValue(hPtr));
- hPtr = Tcl_NextHashEntry(&search);
- }
- Tcl_DeleteHashTable(&fiPtr->namedTable);
- if (fiPtr->updatePending != 0) {
- Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr);
- }
- ckfree((char *) fiPtr);
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_FontObjCmd --
- *
- * This procedure is implemented to process the "font" Tcl command.
- * See the user documentation for details on what it does.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * See the user documentation.
- *
- *----------------------------------------------------------------------
- */
-
- int
- Tk_FontObjCmd(clientData, interp, objc, objv)
- ClientData clientData; /* Main window associated with interpreter. */
- Tcl_Interp *interp; /* Current interpreter. */
- int objc; /* Number of arguments. */
- Tcl_Obj *CONST objv[]; /* Argument objects. */
- {
- int index;
- Tk_Window tkwin;
- TkFontInfo *fiPtr;
- static char *optionStrings[] = {
- "actual", "configure", "create", "delete",
- "families", "measure", "metrics", "names",
- NULL
- };
- enum options {
- FONT_ACTUAL, FONT_CONFIGURE, FONT_CREATE, FONT_DELETE,
- FONT_FAMILIES, FONT_MEASURE, FONT_METRICS, FONT_NAMES
- };
-
- tkwin = (Tk_Window) clientData;
- fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
-
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
- return TCL_ERROR;
- }
- if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
- &index) != TCL_OK) {
- return TCL_ERROR;
- }
-
- switch ((enum options) index) {
- case FONT_ACTUAL: {
- int skip;
- Tk_Font tkfont;
- Tcl_Obj *objPtr;
- CONST TkFontAttributes *faPtr;
-
- skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
- if (skip < 0) {
- return TCL_ERROR;
- }
- if ((objc < 3) || (objc - skip > 4)) {
- Tcl_WrongNumArgs(interp, 2, objv,
- "font ?-displayof window? ?option?");
- return TCL_ERROR;
- }
- tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]);
- if (tkfont == NULL) {
- return TCL_ERROR;
- }
- faPtr = GetFontAttributes(tkfont);
- objPtr = NULL;
- if (objc > 3) {
- objPtr = objv[3 + skip];
- }
- GetAttributeInfoObj(interp, faPtr, objPtr);
- Tk_FreeFont(tkfont);
- break;
- }
- case FONT_CONFIGURE: {
- int result;
- char *string;
- Tcl_Obj *objPtr;
- NamedFont *nfPtr;
- Tcl_HashEntry *namedHashPtr;
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?");
- return TCL_ERROR;
- }
- string = Tk_GetUid(Tcl_GetStringFromObj(objv[2], NULL));
- namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
- nfPtr = NULL; /* lint. */
- if (namedHashPtr != NULL) {
- nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
- }
- if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) {
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string,
- "\" doesn't exist", NULL);
- return TCL_ERROR;
- }
- if (objc == 3) {
- objPtr = NULL;
- } else if (objc == 4) {
- objPtr = objv[3];
- } else {
- result = ConfigAttributesObj(interp, tkwin, objc - 3,
- objv + 3, &nfPtr->fa);
- UpdateDependantFonts(fiPtr, tkwin, namedHashPtr);
- return result;
- }
- GetAttributeInfoObj(interp, &nfPtr->fa, objPtr);
- break;
- }
- case FONT_CREATE: {
- int skip, i;
- char *name;
- char buf[32];
- TkFontAttributes fa;
- Tcl_HashEntry *namedHashPtr;
-
- skip = 3;
- if (objc < 3) {
- name = NULL;
- } else {
- name = Tcl_GetStringFromObj(objv[2], NULL);
- if (name[0] == '-') {
- name = NULL;
- }
- }
- if (name == NULL) {
- /*
- * No font name specified. Generate one of the form "fontX".
- */
-
- for (i = 1; ; i++) {
- sprintf(buf, "font%d", i);
- namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable,
- Tk_GetUid(buf));
- if (namedHashPtr == NULL) {
- break;
- }
- }
- name = buf;
- skip = 2;
- }
- TkInitFontAttributes(&fa);
- if (ConfigAttributesObj(interp, tkwin, objc - skip, objv + skip,
- &fa) != TCL_OK) {
- return TCL_ERROR;
- }
- if (TkCreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) {
- return TCL_ERROR;
- }
- Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1);
- break;
- }
- case FONT_DELETE: {
- int i;
- char *string;
- NamedFont *nfPtr;
- Tcl_HashEntry *namedHashPtr;
-
- /*
- * Delete the named font. If there are still widgets using this
- * font, then it isn't deleted right away.
- */
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?");
- return TCL_ERROR;
- }
- for (i = 2; i < objc; i++) {
- string = Tk_GetUid(Tcl_GetStringFromObj(objv[i], NULL));
- namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
- if (namedHashPtr == NULL) {
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string,
- "\" doesn't exist", (char *) NULL);
- return TCL_ERROR;
- }
- nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
- if (nfPtr->refCount != 0) {
- nfPtr->deletePending = 1;
- } else {
- Tcl_DeleteHashEntry(namedHashPtr);
- ckfree((char *) nfPtr);
- }
- }
- break;
- }
- case FONT_FAMILIES: {
- int skip;
-
- skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
- if (skip < 0) {
- return TCL_ERROR;
- }
- if (objc - skip != 2) {
- Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?");
- return TCL_ERROR;
- }
- TkpGetFontFamilies(interp, tkwin);
- break;
- }
- case FONT_MEASURE: {
- char *string;
- Tk_Font tkfont;
- int length, skip;
-
- skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
- if (skip < 0) {
- return TCL_ERROR;
- }
- if (objc - skip != 4) {
- Tcl_WrongNumArgs(interp, 2, objv,
- "font ?-displayof window? text");
- return TCL_ERROR;
- }
- tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]);
- if (tkfont == NULL) {
- return TCL_ERROR;
- }
- string = Tcl_GetStringFromObj(objv[3 + skip], &length);
- Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_TextWidth(tkfont, string, length));
- Tk_FreeFont(tkfont);
- break;
- }
- case FONT_METRICS: {
- char buf[64];
- Tk_Font tkfont;
- int skip, index, i;
- CONST TkFontMetrics *fmPtr;
- static char *switches[] = {
- "-ascent", "-descent", "-linespace", "-fixed", NULL
- };
-
- skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
- if (skip < 0) {
- return TCL_ERROR;
- }
- if ((objc < 3) || ((objc - skip) > 4)) {
- Tcl_WrongNumArgs(interp, 2, objv,
- "font ?-displayof window? ?option?");
- return TCL_ERROR;
- }
- tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]);
- if (tkfont == NULL) {
- return TCL_ERROR;
- }
- fmPtr = GetFontMetrics(tkfont);
- if (objc == 3) {
- sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d",
- fmPtr->ascent, fmPtr->descent,
- fmPtr->ascent + fmPtr->descent,
- fmPtr->fixed);
- Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1);
- } else {
- if (Tcl_GetIndexFromObj(interp, objv[3 + skip], switches,
- "metric", 0, &index) != TCL_OK) {
- Tk_FreeFont(tkfont);
- return TCL_ERROR;
- }
- i = 0; /* Needed only to prevent compiler
- * warning. */
- switch (index) {
- case 0: i = fmPtr->ascent; break;
- case 1: i = fmPtr->descent; break;
- case 2: i = fmPtr->ascent + fmPtr->descent; break;
- case 3: i = fmPtr->fixed; break;
- }
- Tcl_SetIntObj(Tcl_GetObjResult(interp), i);
- }
- Tk_FreeFont(tkfont);
- break;
- }
- case FONT_NAMES: {
- char *string;
- Tcl_Obj *strPtr;
- NamedFont *nfPtr;
- Tcl_HashSearch search;
- Tcl_HashEntry *namedHashPtr;
-
- if (objc != 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "names");
- return TCL_ERROR;
- }
- namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
- while (namedHashPtr != NULL) {
- nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
- if (nfPtr->deletePending == 0) {
- string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr);
- strPtr = Tcl_NewStringObj(string, -1);
- Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr);
- }
- namedHashPtr = Tcl_NextHashEntry(&search);
- }
- break;
- }
- }
- return TCL_OK;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * UpdateDependantFonts, TheWorldHasChanged, RecomputeWidgets --
- *
- * Called when the attributes of a named font changes. Updates all
- * the instantiated fonts that depend on that named font and then
- * uses the brute force approach and prepares every widget to
- * recompute its geometry.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Things get queued for redisplay.
- *
- *---------------------------------------------------------------------------
- */
-
- static void
- UpdateDependantFonts(fiPtr, tkwin, namedHashPtr)
- TkFontInfo *fiPtr; /* Info about application's fonts. */
- Tk_Window tkwin; /* A window in the application. */
- Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */
- {
- Tcl_HashEntry *cacheHashPtr;
- Tcl_HashSearch search;
- TkFont *fontPtr;
- NamedFont *nfPtr;
-
- nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
- if (nfPtr->refCount == 0) {
- /*
- * Well nobody's using this named font, so don't have to tell
- * any widgets to recompute themselves.
- */
-
- return;
- }
-
-
- cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
- while (cacheHashPtr != NULL) {
- fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
- if (fontPtr->namedHashPtr == namedHashPtr) {
- TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa);
- if (fiPtr->updatePending == 0) {
- fiPtr->updatePending = 1;
- Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr);
- }
- }
- cacheHashPtr = Tcl_NextHashEntry(&search);
- }
- }
-
- static void
- TheWorldHasChanged(clientData)
- ClientData clientData; /* Info about application's fonts. */
- {
- TkFontInfo *fiPtr;
-
- fiPtr = (TkFontInfo *) clientData;
- fiPtr->updatePending = 0;
-
- RecomputeWidgets(fiPtr->mainPtr->winPtr);
- }
-
- static void
- RecomputeWidgets(winPtr)
- TkWindow *winPtr; /* Window to which command is sent. */
- {
- if ((winPtr->classProcsPtr != NULL)
- && (winPtr->classProcsPtr->geometryProc != NULL)) {
- (*winPtr->classProcsPtr->geometryProc)(winPtr->instanceData);
- }
- for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) {
- RecomputeWidgets(winPtr);
- }
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkCreateNamedFont --
- *
- * Create the specified named font with the given attributes in the
- * named font table associated with the interp.
- *
- * Results:
- * Returns TCL_OK if the font was successfully created, or TCL_ERROR
- * if the named font already existed. If TCL_ERROR is returned, an
- * error message is left in interp->result.
- *
- * Side effects:
- * Assume there used to exist a named font by the specified name, and
- * that the named font had been deleted, but there were still some
- * widgets using the named font at the time it was deleted. If a
- * new named font is created with the same name, all those widgets
- * that were using the old named font will be redisplayed using
- * the new named font's attributes.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- TkCreateNamedFont(interp, tkwin, name, faPtr)
- Tcl_Interp *interp; /* Interp for error return. */
- Tk_Window tkwin; /* A window associated with interp. */
- CONST char *name; /* Name for the new named font. */
- TkFontAttributes *faPtr; /* Attributes for the new named font. */
- {
- TkFontInfo *fiPtr;
- Tcl_HashEntry *namedHashPtr;
- int new;
- NamedFont *nfPtr;
-
- fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
-
- name = Tk_GetUid(name);
- namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new);
-
- if (new == 0) {
- nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
- if (nfPtr->deletePending == 0) {
- interp->result[0] = '\0';
- Tcl_AppendResult(interp, "font \"", name,
- "\" already exists", (char *) NULL);
- return TCL_ERROR;
- }
-
- /*
- * Recreating a named font with the same name as a previous
- * named font. Some widgets were still using that named
- * font, so they need to get redisplayed.
- */
-
- nfPtr->fa = *faPtr;
- nfPtr->deletePending = 0;
- UpdateDependantFonts(fiPtr, tkwin, namedHashPtr);
- return TCL_OK;
- }
-
- nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont));
- nfPtr->deletePending = 0;
- Tcl_SetHashValue(namedHashPtr, nfPtr);
- nfPtr->fa = *faPtr;
- nfPtr->refCount = 0;
- nfPtr->deletePending = 0;
- return TCL_OK;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_GetFont --
- *
- * Given a string description of a font, map the description to a
- * corresponding Tk_Font that represents the font.
- *
- * Results:
- * The return value is token for the font, or NULL if an error
- * prevented the font from being created. If NULL is returned, an
- * error message will be left in interp->result.
- *
- * Side effects:
- * Calls Tk_GetFontFromObj(), which modifies interp's result object,
- * then copies the string from the result object into interp->result.
- * This procedure will go away when Tk_ConfigureWidget() is
- * made into an object command.
- *
- *---------------------------------------------------------------------------
- */
-
- Tk_Font
- Tk_GetFont(interp, tkwin, string)
- Tcl_Interp *interp; /* Interp for database and error return. */
- Tk_Window tkwin; /* For display on which font will be used. */
- CONST char *string; /* String describing font, as: named font,
- * native format, or parseable string. */
- {
- Tcl_Obj *strPtr;
- Tk_Font tkfont;
-
- strPtr = Tcl_NewStringObj((char *) string, -1);
-
- tkfont = Tk_GetFontFromObj(interp, tkwin, strPtr);
- if (tkfont == NULL) {
- Tcl_SetResult(interp,
- Tcl_GetStringFromObj(Tcl_GetObjResult(interp), NULL),
- TCL_VOLATILE);
- }
-
- Tcl_DecrRefCount(strPtr); /* done with object */
- return tkfont;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_GetFontFromObj --
- *
- * Given a string description of a font, map the description to a
- * corresponding Tk_Font that represents the font.
- *
- * Results:
- * The return value is token for the font, or NULL if an error
- * prevented the font from being created. If NULL is returned, an
- * error message will be left in interp's result object.
- *
- * Side effects:
- * The font is added to an internal database with a reference
- * count. For each call to this procedure, there should eventually
- * be a call to Tk_FreeFont() so that the database is cleaned up when
- * fonts aren't in use anymore.
- *
- *---------------------------------------------------------------------------
- */
-
- Tk_Font
- Tk_GetFontFromObj(interp, tkwin, objPtr)
- Tcl_Interp *interp; /* Interp for database and error return. */
- Tk_Window tkwin; /* For display on which font will be used. */
- Tcl_Obj *objPtr; /* Object describing font, as: named font,
- * native format, or parseable string. */
- {
- TkFontInfo *fiPtr;
- CachedFontKey key;
- Tcl_HashEntry *cacheHashPtr, *namedHashPtr;
- TkFont *fontPtr;
- int new, descent;
- NamedFont *nfPtr;
- char *string;
-
- fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
- string = Tcl_GetStringFromObj(objPtr, NULL);
-
- key.display = Tk_Display(tkwin);
- key.string = Tk_GetUid(string);
- cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, (char *) &key, &new);
-
- if (new == 0) {
- /*
- * We have already constructed a font with this description for
- * this display. Bump the reference count of the cached font.
- */
-
- fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
- fontPtr->refCount++;
- return (Tk_Font) fontPtr;
- }
-
- namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, key.string);
- if (namedHashPtr != NULL) {
- /*
- * Construct a font based on a named font.
- */
-
- nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
- nfPtr->refCount++;
-
- fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa);
- } else {
- /*
- * Native font?
- */
-
- fontPtr = TkpGetNativeFont(tkwin, string);
- if (fontPtr == NULL) {
- TkFontAttributes fa;
-
- TkInitFontAttributes(&fa);
- if (ParseFontNameObj(interp, tkwin, objPtr, &fa) != TCL_OK) {
- Tcl_DeleteHashEntry(cacheHashPtr);
- return NULL;
- }
-
- /*
- * String contained the attributes inline.
- */
-
- fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa);
- }
- }
- Tcl_SetHashValue(cacheHashPtr, fontPtr);
-
- fontPtr->refCount = 1;
- fontPtr->cacheHashPtr = cacheHashPtr;
- fontPtr->namedHashPtr = namedHashPtr;
-
- Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, 0, 0, &fontPtr->tabWidth);
- if (fontPtr->tabWidth == 0) {
- fontPtr->tabWidth = fontPtr->fm.maxWidth;
- }
- fontPtr->tabWidth *= 8;
-
- /*
- * Make sure the tab width isn't zero (some fonts may not have enough
- * information to set a reasonable tab width).
- */
-
- if (fontPtr->tabWidth == 0) {
- fontPtr->tabWidth = 1;
- }
-
- /*
- * Get information used for drawing underlines in generic code on a
- * non-underlined font.
- */
-
- descent = fontPtr->fm.descent;
- fontPtr->underlinePos = descent / 2;
- fontPtr->underlineHeight = fontPtr->fa.pointsize / 10;
- if (fontPtr->underlineHeight == 0) {
- fontPtr->underlineHeight = 1;
- }
- if (fontPtr->underlinePos + fontPtr->underlineHeight > descent) {
- /*
- * If this set of values would cause the bottom of the underline
- * bar to stick below the descent of the font, jack the underline
- * up a bit higher.
- */
-
- fontPtr->underlineHeight = descent - fontPtr->underlinePos;
- if (fontPtr->underlineHeight == 0) {
- fontPtr->underlinePos--;
- fontPtr->underlineHeight = 1;
- }
- }
-
- return (Tk_Font) fontPtr;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_NameOfFont --
- *
- * Given a font, return a textual string identifying it.
- *
- * Results:
- * The return value is the description that was passed to
- * Tk_GetFont() to create the font. The storage for the returned
- * string is only guaranteed to persist until the font is deleted.
- * The caller should not modify this string.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- char *
- Tk_NameOfFont(tkfont)
- Tk_Font tkfont; /* Font whose name is desired. */
- {
- TkFont *fontPtr;
- Tcl_HashEntry *hPtr;
- CachedFontKey *keyPtr;
-
- fontPtr = (TkFont *) tkfont;
- hPtr = fontPtr->cacheHashPtr;
-
- keyPtr = (CachedFontKey *) Tcl_GetHashKey(hPtr->tablePtr, hPtr);
- return (char *) keyPtr->string;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_FreeFont --
- *
- * Called to release a font allocated by Tk_GetFont().
- *
- * Results:
- * None.
- *
- * Side effects:
- * The reference count associated with font is decremented, and
- * only deallocated when no one is using it.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- Tk_FreeFont(tkfont)
- Tk_Font tkfont; /* Font to be released. */
- {
- TkFont *fontPtr;
- NamedFont *nfPtr;
-
- if (tkfont == NULL) {
- return;
- }
- fontPtr = (TkFont *) tkfont;
- fontPtr->refCount--;
- if (fontPtr->refCount == 0) {
- if (fontPtr->namedHashPtr != NULL) {
- /*
- * The font is being deleted. Determine if the associated named
- * font definition should and/or can be deleted too.
- */
-
- nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr);
- nfPtr->refCount--;
- if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) {
- Tcl_DeleteHashEntry(fontPtr->namedHashPtr);
- ckfree((char *) nfPtr);
- }
- }
- Tcl_DeleteHashEntry(fontPtr->cacheHashPtr);
- TkpDeleteFont(fontPtr);
- }
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_FontId --
- *
- * Given a font, return an opaque handle that should be selected
- * into the XGCValues structure in order to get the constructed
- * gc to use this font. This procedure would go away if the
- * XGCValues structure were replaced with a TkGCValues structure.
- *
- * Results:
- * As above.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- Font
- Tk_FontId(tkfont)
- Tk_Font tkfont; /* Font that is going to be selected into GC. */
- {
- TkFont *fontPtr;
-
- fontPtr = (TkFont *) tkfont;
- return fontPtr->fid;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_GetFontMetrics --
- *
- * Returns overall ascent and descent metrics for the given font.
- * These values can be used to space multiple lines of text and
- * to align the baselines of text in different fonts.
- *
- * Results:
- * If *heightPtr is non-NULL, it is filled with the overall height
- * of the font, which is the sum of the ascent and descent.
- * If *ascentPtr or *descentPtr is non-NULL, they are filled with
- * the ascent and/or descent information for the font.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
- void
- Tk_GetFontMetrics(tkfont, fmPtr)
- Tk_Font tkfont; /* Font in which metrics are calculated. */
- Tk_FontMetrics *fmPtr; /* Pointer to structure in which font
- * metrics for tkfont will be stored. */
- {
- TkFont *fontPtr;
-
- fontPtr = (TkFont *) tkfont;
- fmPtr->ascent = fontPtr->fm.ascent;
- fmPtr->descent = fontPtr->fm.descent;
- fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_PostscriptFontName --
- *
- * Given a Tk_Font, return the name of the corresponding Postscript
- * font.
- *
- * Results:
- * The return value is the pointsize of the given Tk_Font.
- * The name of the Postscript font is appended to dsPtr.
- *
- * Side effects:
- * If the font does not exist on the printer, the print job will
- * fail at print time. Given a "reasonable" Postscript printer,
- * the following Tk_Font font families should print correctly:
- *
- * Avant Garde, Arial, Bookman, Courier, Courier New, Geneva,
- * Helvetica, Monaco, New Century Schoolbook, New York,
- * Palatino, Symbol, Times, Times New Roman, Zapf Chancery,
- * and Zapf Dingbats.
- *
- * Any other Tk_Font font families may not print correctly
- * because the computed Postscript font name may be incorrect.
- *
- *---------------------------------------------------------------------------
- */
-
-
- int
- Tk_PostscriptFontName(tkfont, dsPtr)
- Tk_Font tkfont; /* Font in which text will be printed. */
- Tcl_DString *dsPtr; /* Pointer to an initialized Tcl_DString to
- * which the name of the Postscript font that
- * corresponds to tkfont will be appended. */
- {
- TkFont *fontPtr;
- char *family, *weightString, *slantString;
- char *src, *dest;
- int upper, len;
-
- len = Tcl_DStringLength(dsPtr);
- fontPtr = (TkFont *) tkfont;
-
- /*
- * Convert the case-insensitive Tk_Font family name to the
- * case-sensitive Postscript family name. Take out any spaces and
- * capitalize the first letter of each word.
- */
-
- family = fontPtr->fa.family;
- if (strncasecmp(family, "itc ", 4) == 0) {
- family = family + 4;
- }
- if ((strcasecmp(family, "Arial") == 0)
- || (strcasecmp(family, "Geneva") == 0)) {
- family = "Helvetica";
- } else if ((strcasecmp(family, "Times New Roman") == 0)
- || (strcasecmp(family, "New York") == 0)) {
- family = "Times";
- } else if ((strcasecmp(family, "Courier New") == 0)
- || (strcasecmp(family, "Monaco") == 0)) {
- family = "Courier";
- } else if (strcasecmp(family, "AvantGarde") == 0) {
- family = "AvantGarde";
- } else if (strcasecmp(family, "ZapfChancery") == 0) {
- family = "ZapfChancery";
- } else if (strcasecmp(family, "ZapfDingbats") == 0) {
- family = "ZapfDingbats";
- } else {
- /*
- * Inline, capitalize the first letter of each word, lowercase the
- * rest of the letters in each word, and then take out the spaces
- * between the words. This may make the DString shorter, which is
- * safe to do.
- */
-
- Tcl_DStringAppend(dsPtr, family, -1);
-
- src = dest = Tcl_DStringValue(dsPtr) + len;
- upper = 1;
- for (; *src != '\0'; src++, dest++) {
- while (isspace(UCHAR(*src))) {
- src++;
- upper = 1;
- }
- *dest = *src;
- if ((upper != 0) && (islower(UCHAR(*src)))) {
- *dest = toupper(UCHAR(*src));
- }
- upper = 0;
- }
- *dest = '\0';
- Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr));
- family = Tcl_DStringValue(dsPtr) + len;
- }
- if (family != Tcl_DStringValue(dsPtr) + len) {
- Tcl_DStringAppend(dsPtr, family, -1);
- family = Tcl_DStringValue(dsPtr) + len;
- }
-
- if (strcasecmp(family, "NewCenturySchoolbook") == 0) {
- Tcl_DStringSetLength(dsPtr, len);
- Tcl_DStringAppend(dsPtr, "NewCenturySchlbk", -1);
- family = Tcl_DStringValue(dsPtr) + len;
- }
-
- /*
- * Get the string to use for the weight.
- */
-
- weightString = NULL;
- if (fontPtr->fa.weight == TK_FW_NORMAL) {
- if (strcmp(family, "Bookman") == 0) {
- weightString = "Light";
- } else if (strcmp(family, "AvantGarde") == 0) {
- weightString = "Book";
- } else if (strcmp(family, "ZapfChancery") == 0) {
- weightString = "Medium";
- }
- } else {
- if ((strcmp(family, "Bookman") == 0)
- || (strcmp(family, "AvantGarde") == 0)) {
- weightString = "Demi";
- } else {
- weightString = "Bold";
- }
- }
-
- /*
- * Get the string to use for the slant.
- */
-
- slantString = NULL;
- if (fontPtr->fa.slant == TK_FS_ROMAN) {
- ;
- } else {
- if ((strcmp(family, "Helvetica") == 0)
- || (strcmp(family, "Courier") == 0)
- || (strcmp(family, "AvantGarde") == 0)) {
- slantString = "Oblique";
- } else {
- slantString = "Italic";
- }
- }
-
- /*
- * The string "Roman" needs to be added to some fonts that are not bold
- * and not italic.
- */
-
- if ((slantString == NULL) && (weightString == NULL)) {
- if ((strcmp(family, "Times") == 0)
- || (strcmp(family, "NewCenturySchlbk") == 0)
- || (strcmp(family, "Palatino") == 0)) {
- Tcl_DStringAppend(dsPtr, "-Roman", -1);
- }
- } else {
- Tcl_DStringAppend(dsPtr, "-", -1);
- if (weightString != NULL) {
- Tcl_DStringAppend(dsPtr, weightString, -1);
- }
- if (slantString != NULL) {
- Tcl_DStringAppend(dsPtr, slantString, -1);
- }
- }
-
- return fontPtr->fa.pointsize;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_TextWidth --
- *
- * A wrapper function for the more complicated interface of
- * Tk_MeasureChars. Computes how much space the given
- * simple string needs.
- *
- * Results:
- * The return value is the width (in pixels) of the given string.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- Tk_TextWidth(tkfont, string, numChars)
- Tk_Font tkfont; /* Font in which text will be measured. */
- CONST char *string; /* String whose width will be computed. */
- int numChars; /* Number of characters to consider from
- * string, or < 0 for strlen(). */
- {
- int width;
-
- if (numChars < 0) {
- numChars = strlen(string);
- }
- Tk_MeasureChars(tkfont, string, numChars, 0, 0, &width);
- return width;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_UnderlineChars --
- *
- * This procedure draws an underline for a given range of characters
- * in a given string. It doesn't draw the characters (which are
- * assumed to have been displayed previously); it just draws the
- * underline. This procedure would mainly be used to quickly
- * underline a few characters without having to construct an
- * underlined font. To produce properly underlined text, the
- * appropriate underlined font should be constructed and used.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Information gets displayed in "drawable".
- *
- *----------------------------------------------------------------------
- */
-
- void
- Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstChar,
- lastChar)
- Display *display; /* Display on which to draw. */
- Drawable drawable; /* Window or pixmap in which to draw. */
- GC gc; /* Graphics context for actually drawing
- * line. */
- Tk_Font tkfont; /* Font used in GC; must have been allocated
- * by Tk_GetFont(). Used for character
- * dimensions, etc. */
- CONST char *string; /* String containing characters to be
- * underlined or overstruck. */
- int x, y; /* Coordinates at which first character of
- * string is drawn. */
- int firstChar; /* Index of first character. */
- int lastChar; /* Index of one after the last character. */
- {
- TkFont *fontPtr;
- int startX, endX;
-
- fontPtr = (TkFont *) tkfont;
-
- Tk_MeasureChars(tkfont, string, firstChar, 0, 0, &startX);
- Tk_MeasureChars(tkfont, string, lastChar, 0, 0, &endX);
-
- XFillRectangle(display, drawable, gc, x + startX,
- y + fontPtr->underlinePos, (unsigned int) (endX - startX),
- (unsigned int) fontPtr->underlineHeight);
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_ComputeTextLayout --
- *
- * Computes the amount of screen space needed to display a
- * multi-line, justified string of text. Records all the
- * measurements that were done to determine to size and
- * positioning of the individual lines of text; this information
- * can be used by the Tk_DrawTextLayout() procedure to
- * display the text quickly (without remeasuring it).
- *
- * This procedure is useful for simple widgets that want to
- * display single-font, multi-line text and want Tk to handle the
- * details.
- *
- * Results:
- * The return value is a Tk_TextLayout token that holds the
- * measurement information for the given string. The token is
- * only valid for the given string. If the string is freed,
- * the token is no longer valid and must also be freed. To free
- * the token, call Tk_FreeTextLayout().
- *
- * The dimensions of the screen area needed to display the text
- * are stored in *widthPtr and *heightPtr.
- *
- * Side effects:
- * Memory is allocated to hold the measurement information.
- *
- *---------------------------------------------------------------------------
- */
-
- Tk_TextLayout
- Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags,
- widthPtr, heightPtr)
- Tk_Font tkfont; /* Font that will be used to display text. */
- CONST char *string; /* String whose dimensions are to be
- * computed. */
- int numChars; /* Number of characters to consider from
- * string, or < 0 for strlen(). */
- int wrapLength; /* Longest permissible line length, in
- * pixels. <= 0 means no automatic wrapping:
- * just let lines get as long as needed. */
- Tk_Justify justify; /* How to justify lines. */
- int flags; /* Flag bits OR-ed together.
- * TK_IGNORE_TABS means that tab characters
- * should not be expanded. TK_IGNORE_NEWLINES
- * means that newline characters should not
- * cause a line break. */
- int *widthPtr; /* Filled with width of string. */
- int *heightPtr; /* Filled with height of string. */
- {
- TkFont *fontPtr;
- CONST char *start, *end, *special;
- int n, y, charsThisChunk, maxChunks;
- int baseline, height, curX, newX, maxWidth;
- TextLayout *layoutPtr;
- LayoutChunk *chunkPtr;
- CONST TkFontMetrics *fmPtr;
- #define MAX_LINES 50
- int staticLineLengths[MAX_LINES];
- int *lineLengths;
- int maxLines, curLine, layoutHeight;
-
- lineLengths = staticLineLengths;
- maxLines = MAX_LINES;
-
- fontPtr = (TkFont *) tkfont;
- fmPtr = &fontPtr->fm;
-
- height = fmPtr->ascent + fmPtr->descent;
-
- if (numChars < 0) {
- numChars = strlen(string);
- }
-
- maxChunks = 1;
-
- layoutPtr = (TextLayout *) ckalloc(sizeof(TextLayout)
- + (maxChunks - 1) * sizeof(LayoutChunk));
- layoutPtr->tkfont = tkfont;
- layoutPtr->string = string;
- layoutPtr->numChunks = 0;
-
- baseline = fmPtr->ascent;
- maxWidth = 0;
-
- /*
- * Divide the string up into simple strings and measure each string.
- */
-
- curX = 0;
-
- end = string + numChars;
- special = string;
-
- flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES;
- flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE;
- curLine = 0;
- for (start = string; start < end; ) {
- if (start >= special) {
- /*
- * Find the next special character in the string.
- */
-
- for (special = start; special < end; special++) {
- if (!(flags & TK_IGNORE_NEWLINES)) {
- if ((*special == '\n') || (*special == '\r')) {
- break;
- }
- }
- if (!(flags & TK_IGNORE_TABS)) {
- if (*special == '\t') {
- break;
- }
- }
- }
- }
-
- /*
- * Special points at the next special character (or the end of the
- * string). Process characters between start and special.
- */
-
- chunkPtr = NULL;
- if (start < special) {
- charsThisChunk = Tk_MeasureChars(tkfont, start, special - start,
- wrapLength - curX, flags, &newX);
- newX += curX;
- flags &= ~TK_AT_LEAST_ONE;
- if (charsThisChunk > 0) {
- chunkPtr = NewChunk(&layoutPtr, &maxChunks, start,
- charsThisChunk, curX, newX, baseline);
-
- start += charsThisChunk;
- curX = newX;
- }
- }
-
- if ((start == special) && (special < end)) {
- /*
- * Handle the special character.
- */
-
- chunkPtr = NULL;
- if (*special == '\t') {
- newX = curX + fontPtr->tabWidth;
- newX -= newX % fontPtr->tabWidth;
- NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX,
- baseline)->numDisplayChars = -1;
- start++;
- if ((start < end) &&
- ((wrapLength <= 0) || (newX <= wrapLength))) {
- /*
- * More chars can still fit on this line.
- */
-
- curX = newX;
- flags &= ~TK_AT_LEAST_ONE;
- continue;
- }
- } else {
- NewChunk(&layoutPtr, &maxChunks, start, 1, curX, 1000000000,
- baseline)->numDisplayChars = -1;
- start++;
- goto wrapLine;
- }
- }
-
- /*
- * No more characters are going to go on this line, either because
- * no more characters can fit or there are no more characters left.
- * Consume all extra spaces at end of line.
- */
-
- while ((start < end) && isspace(UCHAR(*start))) {
- if (!(flags & TK_IGNORE_NEWLINES)) {
- if ((*start == '\n') || (*start == '\r')) {
- break;
- }
- }
- if (!(flags & TK_IGNORE_TABS)) {
- if (*start == '\t') {
- break;
- }
- }
- start++;
- }
- if (chunkPtr != NULL) {
- /*
- * Append all the extra spaces on this line to the end of the
- * last text chunk.
- */
- charsThisChunk = start - (chunkPtr->start + chunkPtr->numChars);
- if (charsThisChunk > 0) {
- chunkPtr->numChars += Tk_MeasureChars(tkfont,
- chunkPtr->start + chunkPtr->numChars, charsThisChunk,
- 0, 0, &chunkPtr->totalWidth);
- chunkPtr->totalWidth += curX;
- }
- }
-
- wrapLine:
- flags |= TK_AT_LEAST_ONE;
-
- /*
- * Save current line length, then move current position to start of
- * next line.
- */
-
- if (curX > maxWidth) {
- maxWidth = curX;
- }
-
- /*
- * Remember width of this line, so that all chunks on this line
- * can be centered or right justified, if necessary.
- */
-
- if (curLine >= maxLines) {
- int *newLengths;
-
- newLengths = (int *) ckalloc(2 * maxLines * sizeof(int));
- memcpy((void *) newLengths, lineLengths, maxLines * sizeof(int));
- if (lineLengths != staticLineLengths) {
- ckfree((char *) lineLengths);
- }
- lineLengths = newLengths;
- maxLines *= 2;
- }
- lineLengths[curLine] = curX;
- curLine++;
-
- curX = 0;
- baseline += height;
- }
-
- /*
- * Using maximum line length, shift all the chunks so that the lines are
- * all justified correctly.
- */
-
- curLine = 0;
- chunkPtr = layoutPtr->chunks;
- y = chunkPtr->y;
- for (n = 0; n < layoutPtr->numChunks; n++) {
- int extra;
-
- if (chunkPtr->y != y) {
- curLine++;
- y = chunkPtr->y;
- }
- extra = maxWidth - lineLengths[curLine];
- if (justify == TK_JUSTIFY_CENTER) {
- chunkPtr->x += extra / 2;
- } else if (justify == TK_JUSTIFY_RIGHT) {
- chunkPtr->x += extra;
- }
- chunkPtr++;
- }
-
- layoutPtr->width = maxWidth;
- layoutHeight = baseline - fmPtr->ascent;
- if (layoutPtr->numChunks == 0) {
- layoutHeight = height;
-
- /*
- * This fake chunk is used by the other procedures so that they can
- * pretend that there is a chunk with no chars in it, which makes
- * the coding simpler.
- */
-
- layoutPtr->numChunks = 1;
- layoutPtr->chunks[0].start = string;
- layoutPtr->chunks[0].numChars = 0;
- layoutPtr->chunks[0].numDisplayChars = -1;
- layoutPtr->chunks[0].x = 0;
- layoutPtr->chunks[0].y = fmPtr->ascent;
- layoutPtr->chunks[0].totalWidth = 0;
- layoutPtr->chunks[0].displayWidth = 0;
- }
-
- if (widthPtr != NULL) {
- *widthPtr = layoutPtr->width;
- }
- if (heightPtr != NULL) {
- *heightPtr = layoutHeight;
- }
- if (lineLengths != staticLineLengths) {
- ckfree((char *) lineLengths);
- }
-
- return (Tk_TextLayout) layoutPtr;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_FreeTextLayout --
- *
- * This procedure is called to release the storage associated with
- * a Tk_TextLayout when it is no longer needed.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory is freed.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- Tk_FreeTextLayout(textLayout)
- Tk_TextLayout textLayout; /* The text layout to be released. */
- {
- TextLayout *layoutPtr;
-
- layoutPtr = (TextLayout *) textLayout;
- if (layoutPtr != NULL) {
- ckfree((char *) layoutPtr);
- }
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_DrawTextLayout --
- *
- * Use the information in the Tk_TextLayout token to display a
- * multi-line, justified string of text.
- *
- * This procedure is useful for simple widgets that need to
- * display single-font, multi-line text and want Tk to handle
- * the details.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Text drawn on the screen.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar)
- Display *display; /* Display on which to draw. */
- Drawable drawable; /* Window or pixmap in which to draw. */
- GC gc; /* Graphics context to use for drawing text. */
- Tk_TextLayout layout; /* Layout information, from a previous call
- * to Tk_ComputeTextLayout(). */
- int x, y; /* Upper-left hand corner of rectangle in
- * which to draw (pixels). */
- int firstChar; /* The index of the first character to draw
- * from the given text item. 0 specfies the
- * beginning. */
- int lastChar; /* The index just after the last character
- * to draw from the given text item. A number
- * < 0 means to draw all characters. */
- {
- TextLayout *layoutPtr;
- int i, numDisplayChars, drawX;
- LayoutChunk *chunkPtr;
-
- layoutPtr = (TextLayout *) layout;
- if (layoutPtr == NULL) {
- return;
- }
-
- if (lastChar < 0) {
- lastChar = 100000000;
- }
- chunkPtr = layoutPtr->chunks;
- for (i = 0; i < layoutPtr->numChunks; i++) {
- numDisplayChars = chunkPtr->numDisplayChars;
- if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {
- if (firstChar <= 0) {
- drawX = 0;
- firstChar = 0;
- } else {
- Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, firstChar,
- 0, 0, &drawX);
- }
- if (lastChar < numDisplayChars) {
- numDisplayChars = lastChar;
- }
- Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,
- chunkPtr->start + firstChar, numDisplayChars - firstChar,
- x + chunkPtr->x + drawX, y + chunkPtr->y);
- }
- firstChar -= chunkPtr->numChars;
- lastChar -= chunkPtr->numChars;
- if (lastChar <= 0) {
- break;
- }
- chunkPtr++;
- }
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_UnderlineTextLayout --
- *
- * Use the information in the Tk_TextLayout token to display an
- * underline below an individual character. This procedure does
- * not draw the text, just the underline.
- *
- * This procedure is useful for simple widgets that need to
- * display single-font, multi-line text with an individual
- * character underlined and want Tk to handle the details.
- * To display larger amounts of underlined text, construct
- * and use an underlined font.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Underline drawn on the screen.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline)
- Display *display; /* Display on which to draw. */
- Drawable drawable; /* Window or pixmap in which to draw. */
- GC gc; /* Graphics context to use for drawing text. */
- Tk_TextLayout layout; /* Layout information, from a previous call
- * to Tk_ComputeTextLayout(). */
- int x, y; /* Upper-left hand corner of rectangle in
- * which to draw (pixels). */
- int underline; /* Index of the single character to
- * underline, or -1 for no underline. */
- {
- TextLayout *layoutPtr;
- TkFont *fontPtr;
- int xx, yy, width, height;
-
- if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0)
- && (width != 0)) {
- layoutPtr = (TextLayout *) layout;
- fontPtr = (TkFont *) layoutPtr->tkfont;
-
- XFillRectangle(display, drawable, gc, x + xx,
- y + yy + fontPtr->fm.ascent + fontPtr->underlinePos,
- (unsigned int) width, (unsigned int) fontPtr->underlineHeight);
- }
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_PointToChar --
- *
- * Use the information in the Tk_TextLayout token to determine the
- * character closest to the given point. The point must be
- * specified with respect to the upper-left hand corner of the
- * text layout, which is considered to be located at (0, 0).
- *
- * Any point whose y-value is less that 0 will be considered closest
- * to the first character in the text layout; any point whose y-value
- * is greater than the height of the text layout will be considered
- * closest to the last character in the text layout.
- *
- * Any point whose x-value is less than 0 will be considered closest
- * to the first character on that line; any point whose x-value is
- * greater than the width of the text layout will be considered
- * closest to the last character on that line.
- *
- * Results:
- * The return value is the index of the character that was
- * closest to the point. Given a text layout with no characters,
- * the value 0 will always be returned, referring to a hypothetical
- * zero-width placeholder character.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- Tk_PointToChar(layout, x, y)
- Tk_TextLayout layout; /* Layout information, from a previous call
- * to Tk_ComputeTextLayout(). */
- int x, y; /* Coordinates of point to check, with
- * respect to the upper-left corner of the
- * text layout. */
- {
- TextLayout *layoutPtr;
- LayoutChunk *chunkPtr, *lastPtr;
- TkFont *fontPtr;
- int i, n, dummy, baseline, pos;
-
- if (y < 0) {
- /*
- * Point lies above any line in this layout. Return the index of
- * the first char.
- */
-
- return 0;
- }
-
- /*
- * Find which line contains the point.
- */
-
- layoutPtr = (TextLayout *) layout;
- fontPtr = (TkFont *) layoutPtr->tkfont;
- lastPtr = chunkPtr = layoutPtr->chunks;
- for (i = 0; i < layoutPtr->numChunks; i++) {
- baseline = chunkPtr->y;
- if (y < baseline + fontPtr->fm.descent) {
- if (x < chunkPtr->x) {
- /*
- * Point is to the left of all chunks on this line. Return
- * the index of the first character on this line.
- */
-
- return chunkPtr->start - layoutPtr->string;
- }
- if (x >= layoutPtr->width) {
- /*
- * If point lies off right side of the text layout, return
- * the last char in the last chunk on this line. Without
- * this, it might return the index of the first char that
- * was located outside of the text layout.
- */
-
- x = INT_MAX;
- }
-
- /*
- * Examine all chunks on this line to see which one contains
- * the specified point.
- */
-
- lastPtr = chunkPtr;
- while ((i < layoutPtr->numChunks) && (chunkPtr->y == baseline)) {
- if (x < chunkPtr->x + chunkPtr->totalWidth) {
- /*
- * Point falls on one of the characters in this chunk.
- */
-
- if (chunkPtr->numDisplayChars < 0) {
- /*
- * This is a special chunk that encapsulates a single
- * tab or newline char.
- */
-
- return chunkPtr->start - layoutPtr->string;
- }
- n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start,
- chunkPtr->numChars, x + 1 - chunkPtr->x,
- TK_PARTIAL_OK, &dummy);
- return (chunkPtr->start + n - 1) - layoutPtr->string;
- }
- lastPtr = chunkPtr;
- chunkPtr++;
- i++;
- }
-
- /*
- * Point is to the right of all chars in all the chunks on this
- * line. Return the index just past the last char in the last
- * chunk on this line.
- */
-
- pos = (lastPtr->start + lastPtr->numChars) - layoutPtr->string;
- if (i < layoutPtr->numChunks) {
- pos--;
- }
- return pos;
- }
- lastPtr = chunkPtr;
- chunkPtr++;
- }
-
- /*
- * Point lies below any line in this text layout. Return the index
- * just past the last char.
- */
-
- return (lastPtr->start + lastPtr->numChars) - layoutPtr->string;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_CharBbox --
- *
- * Use the information in the Tk_TextLayout token to return the
- * bounding box for the character specified by index.
- *
- * The width of the bounding box is the advance width of the
- * character, and does not include and left- or right-bearing.
- * Any character that extends partially outside of the
- * text layout is considered to be truncated at the edge. Any
- * character which is located completely outside of the text
- * layout is considered to be zero-width and pegged against
- * the edge.
- *
- * The height of the bounding box is the line height for this font,
- * extending from the top of the ascent to the bottom of the
- * descent. Information about the actual height of the individual
- * letter is not available.
- *
- * A text layout that contains no characters is considered to
- * contain a single zero-width placeholder character.
- *
- * Results:
- * The return value is 0 if the index did not specify a character
- * in the text layout, or non-zero otherwise. In that case,
- * *bbox is filled with the bounding box of the character.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr)
- Tk_TextLayout layout; /* Layout information, from a previous call to
- * Tk_ComputeTextLayout(). */
- int index; /* The index of the character whose bbox is
- * desired. */
- int *xPtr, *yPtr; /* Filled with the upper-left hand corner, in
- * pixels, of the bounding box for the character
- * specified by index, if non-NULL. */
- int *widthPtr, *heightPtr;
- /* Filled with the width and height of the
- * bounding box for the character specified by
- * index, if non-NULL. */
- {
- TextLayout *layoutPtr;
- LayoutChunk *chunkPtr;
- int i, x, w;
- Tk_Font tkfont;
- TkFont *fontPtr;
-
- if (index < 0) {
- return 0;
- }
-
- layoutPtr = (TextLayout *) layout;
- chunkPtr = layoutPtr->chunks;
- tkfont = layoutPtr->tkfont;
- fontPtr = (TkFont *) tkfont;
-
- for (i = 0; i < layoutPtr->numChunks; i++) {
- if (chunkPtr->numDisplayChars < 0) {
- if (index == 0) {
- x = chunkPtr->x;
- w = chunkPtr->totalWidth;
- goto check;
- }
- } else if (index < chunkPtr->numChars) {
- if (xPtr != NULL) {
- Tk_MeasureChars(tkfont, chunkPtr->start, index, 0, 0, &x);
- x += chunkPtr->x;
- }
- if (widthPtr != NULL) {
- Tk_MeasureChars(tkfont, chunkPtr->start + index, 1, 0, 0, &w);
- }
- goto check;
- }
- index -= chunkPtr->numChars;
- chunkPtr++;
- }
- if (index == 0) {
- /*
- * Special case to get location just past last char in layout.
- */
-
- chunkPtr--;
- x = chunkPtr->x + chunkPtr->totalWidth;
- w = 0;
- } else {
- return 0;
- }
-
- /*
- * Ensure that the bbox lies within the text layout. This forces all
- * chars that extend off the right edge of the text layout to have
- * truncated widths, and all chars that are completely off the right
- * edge of the text layout to peg to the edge and have 0 width.
- */
- check:
- if (yPtr != NULL) {
- *yPtr = chunkPtr->y - fontPtr->fm.ascent;
- }
- if (heightPtr != NULL) {
- *heightPtr = fontPtr->fm.ascent + fontPtr->fm.descent;
- }
-
- if (x > layoutPtr->width) {
- x = layoutPtr->width;
- }
- if (xPtr != NULL) {
- *xPtr = x;
- }
- if (widthPtr != NULL) {
- if (x + w > layoutPtr->width) {
- w = layoutPtr->width - x;
- }
- *widthPtr = w;
- }
-
- return 1;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_DistanceToTextLayout --
- *
- * Computes the distance in pixels from the given point to the
- * given text layout. Non-displaying space characters that occur
- * at the end of individual lines in the text layout are ignored
- * for hit detection purposes.
- *
- * Results:
- * The return value is 0 if the point (x, y) is inside the text
- * layout. If the point isn't inside the text layout then the
- * return value is the distance in pixels from the point to the
- * text item.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- Tk_DistanceToTextLayout(layout, x, y)
- Tk_TextLayout layout; /* Layout information, from a previous call
- * to Tk_ComputeTextLayout(). */
- int x, y; /* Coordinates of point to check, with
- * respect to the upper-left corner of the
- * text layout (in pixels). */
- {
- int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;
- LayoutChunk *chunkPtr;
- TextLayout *layoutPtr;
- TkFont *fontPtr;
-
- layoutPtr = (TextLayout *) layout;
- fontPtr = (TkFont *) layoutPtr->tkfont;
- ascent = fontPtr->fm.ascent;
- descent = fontPtr->fm.descent;
-
- minDist = 0;
- chunkPtr = layoutPtr->chunks;
- for (i = 0; i < layoutPtr->numChunks; i++) {
- if (chunkPtr->start[0] == '\n') {
- /*
- * Newline characters are not counted when computing distance
- * (but tab characters would still be considered).
- */
-
- chunkPtr++;
- continue;
- }
-
- x1 = chunkPtr->x;
- y1 = chunkPtr->y - ascent;
- x2 = chunkPtr->x + chunkPtr->displayWidth;
- y2 = chunkPtr->y + descent;
-
- if (x < x1) {
- xDiff = x1 - x;
- } else if (x >= x2) {
- xDiff = x - x2 + 1;
- } else {
- xDiff = 0;
- }
-
- if (y < y1) {
- yDiff = y1 - y;
- } else if (y >= y2) {
- yDiff = y - y2 + 1;
- } else {
- yDiff = 0;
- }
- if ((xDiff == 0) && (yDiff == 0)) {
- return 0;
- }
- dist = (int) hypot((double) xDiff, (double) yDiff);
- if ((dist < minDist) || (minDist == 0)) {
- minDist = dist;
- }
- chunkPtr++;
- }
- return minDist;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_IntersectTextLayout --
- *
- * Determines whether a text layout lies entirely inside,
- * entirely outside, or overlaps a given rectangle. Non-displaying
- * space characters that occur at the end of individual lines in
- * the text layout are ignored for intersection calculations.
- *
- * Results:
- * The return value is -1 if the text layout is entirely outside of
- * the rectangle, 0 if it overlaps, and 1 if it is entirely inside
- * of the rectangle.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- Tk_IntersectTextLayout(layout, x, y, width, height)
- Tk_TextLayout layout; /* Layout information, from a previous call
- * to Tk_ComputeTextLayout(). */
- int x, y; /* Upper-left hand corner, in pixels, of
- * rectangular area to compare with text
- * layout. Coordinates are with respect to
- * the upper-left hand corner of the text
- * layout itself. */
- int width, height; /* The width and height of the above
- * rectangular area, in pixels. */
- {
- int result, i, x1, y1, x2, y2;
- TextLayout *layoutPtr;
- LayoutChunk *chunkPtr;
- TkFont *fontPtr;
- int left, top, right, bottom;
-
- /*
- * Scan the chunks one at a time, seeing whether each is entirely in,
- * entirely out, or overlapping the rectangle. If an overlap is
- * detected, return immediately; otherwise wait until all chunks have
- * been processed and see if they were all inside or all outside.
- */
-
- layoutPtr = (TextLayout *) layout;
- chunkPtr = layoutPtr->chunks;
- fontPtr = (TkFont *) layoutPtr->tkfont;
-
- left = x;
- top = y;
- right = x + width;
- bottom = y + height;
-
- result = 0;
- for (i = 0; i < layoutPtr->numChunks; i++) {
- if (chunkPtr->start[0] == '\n') {
- /*
- * Newline characters are not counted when computing area
- * intersection (but tab characters would still be considered).
- */
-
- chunkPtr++;
- continue;
- }
-
- x1 = chunkPtr->x;
- y1 = chunkPtr->y - fontPtr->fm.ascent;
- x2 = chunkPtr->x + chunkPtr->displayWidth;
- y2 = chunkPtr->y + fontPtr->fm.descent;
-
- if ((right < x1) || (left >= x2)
- || (bottom < y1) || (top >= y2)) {
- if (result == 1) {
- return 0;
- }
- result = -1;
- } else if ((x1 < left) || (x2 >= right)
- || (y1 < top) || (y2 >= bottom)) {
- return 0;
- } else if (result == -1) {
- return 0;
- } else {
- result = 1;
- }
- chunkPtr++;
- }
- return result;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_TextLayoutToPostscript --
- *
- * Outputs the contents of a text layout in Postscript format.
- * The set of lines in the text layout will be rendered by the user
- * supplied Postscript function. The function should be of the form:
- *
- * justify x y string function --
- *
- * Justify is -1, 0, or 1, depending on whether the following string
- * should be left, center, or right justified, x and y is the
- * location for the origin of the string, string is the sequence
- * of characters to be printed, and function is the name of the
- * caller-provided function; the function should leave nothing
- * on the stack.
- *
- * The meaning of the origin of the string (x and y) depends on
- * the justification. For left justification, x is where the
- * left edge of the string should appear. For center justification,
- * x is where the center of the string should appear. And for right
- * justification, x is where the right edge of the string should
- * appear. This behavior is necessary because, for example, right
- * justified text on the screen is justified with screen metrics.
- * The same string needs to be justified with printer metrics on
- * the printer to appear in the correct place with respect to other
- * similarly justified strings. In all circumstances, y is the
- * location of the baseline for the string.
- *
- * Results:
- * Interp->result is modified to hold the Postscript code that
- * will render the text layout.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- Tk_TextLayoutToPostscript(interp, layout)
- Tcl_Interp *interp; /* Filled with Postscript code. */
- Tk_TextLayout layout; /* The layout to be rendered. */
- {
- #define MAXUSE 128
- char buf[MAXUSE+10];
- LayoutChunk *chunkPtr;
- int i, j, used, c, baseline;
- TextLayout *layoutPtr;
-
- layoutPtr = (TextLayout *) layout;
- chunkPtr = layoutPtr->chunks;
- baseline = chunkPtr->y;
- used = 0;
- buf[used++] = '(';
- for (i = 0; i < layoutPtr->numChunks; i++) {
- if (baseline != chunkPtr->y) {
- buf[used++] = ')';
- buf[used++] = '\n';
- buf[used++] = '(';
- baseline = chunkPtr->y;
- }
- if (chunkPtr->numDisplayChars <= 0) {
- if (chunkPtr->start[0] == '\t') {
- buf[used++] = '\\';
- buf[used++] = 't';
- }
- } else {
- for (j = 0; j < chunkPtr->numDisplayChars; j++) {
- c = UCHAR(chunkPtr->start[j]);
- if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20)
- || (c >= UCHAR(0x7f))) {
- /*
- * Tricky point: the "03" is necessary in the sprintf
- * below, so that a full three digits of octal are
- * always generated. Without the "03", a number
- * following this sequence could be interpreted by
- * Postscript as part of this sequence.
- */
-
- sprintf(buf + used, "\\%03o", c);
- used += 4;
- } else {
- buf[used++] = c;
- }
- if (used >= MAXUSE) {
- buf[used] = '\0';
- Tcl_AppendResult(interp, buf, (char *) NULL);
- used = 0;
- }
- }
- }
- if (used >= MAXUSE) {
- /*
- * If there are a whole bunch of returns or tabs in a row,
- * then buf[] could get filled up.
- */
-
- buf[used] = '\0';
- Tcl_AppendResult(interp, buf, (char *) NULL);
- used = 0;
- }
- chunkPtr++;
- }
- buf[used++] = ')';
- buf[used++] = '\n';
- buf[used] = '\0';
- Tcl_AppendResult(interp, buf, (char *) NULL);
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkInitFontAttributes --
- *
- * Initialize the font attributes structure to contain sensible
- * values. This must be called before using any other font
- * attributes functions.
- *
- * Results:
- * None.
- *
- * Side effects.
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- void
- TkInitFontAttributes(faPtr)
- TkFontAttributes *faPtr; /* The attributes structure to initialize. */
- {
- faPtr->family = NULL;
- faPtr->pointsize = 0;
- faPtr->weight = TK_FW_NORMAL;
- faPtr->slant = TK_FS_ROMAN;
- faPtr->underline = 0;
- faPtr->overstrike = 0;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * ConfigAttributesObj --
- *
- * Process command line options to fill in fields of a properly
- * initialized font attributes structure.
- *
- * Results:
- * A standard Tcl return value. If TCL_ERROR is returned, an
- * error message will be left in interp's result object.
- *
- * Side effects:
- * The fields of the font attributes structure get filled in with
- * information from argc/argv. If an error occurs while parsing,
- * the font attributes structure will contain all modifications
- * specified in the command line options up to the point of the
- * error.
- *
- *---------------------------------------------------------------------------
- */
-
- static int
- ConfigAttributesObj(interp, tkwin, objc, objv, faPtr)
- Tcl_Interp *interp; /* Interp for error return. */
- Tk_Window tkwin; /* For display on which font will be used. */
- int objc; /* Number of elements in argv. */
- Tcl_Obj *CONST objv[]; /* Command line options. */
- TkFontAttributes *faPtr; /* Font attributes structure whose fields
- * are to be modified. Structure must already
- * be properly initialized. */
- {
- int i, n, index;
- Tcl_Obj *value;
- char *option, *string;
-
- if (objc & 1) {
- string = Tcl_GetStringFromObj(objv[objc - 1], NULL);
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "missing value for \"",
- string, "\" option", (char *) NULL);
- return TCL_ERROR;
- }
-
- for (i = 0; i < objc; i += 2) {
- option = Tcl_GetStringFromObj(objv[i], NULL);
- value = objv[i + 1];
-
- if (Tcl_GetIndexFromObj(interp, objv[i], fontOpt, "option", 1,
- &index) != TCL_OK) {
- return TCL_ERROR;
- }
- switch (index) {
- case FONT_FAMILY:
- string = Tcl_GetStringFromObj(value, NULL);
- faPtr->family = Tk_GetUid(string);
- break;
-
- case FONT_SIZE:
- if (Tcl_GetIntFromObj(interp, value, &n) != TCL_OK) {
- return TCL_ERROR;
- }
- faPtr->pointsize = n;
- break;
-
- case FONT_WEIGHT:
- string = Tcl_GetStringFromObj(value, NULL);
- n = TkFindStateNum(interp, option, weightMap, string);
- if (n == TK_FW_UNKNOWN) {
- return TCL_ERROR;
- }
- faPtr->weight = n;
- break;
-
- case FONT_SLANT:
- string = Tcl_GetStringFromObj(value, NULL);
- n = TkFindStateNum(interp, option, slantMap, string);
- if (n == TK_FS_UNKNOWN) {
- return TCL_ERROR;
- }
- faPtr->slant = n;
- break;
-
- case FONT_UNDERLINE:
- if (Tcl_GetBooleanFromObj(interp, value, &n) != TCL_OK) {
- return TCL_ERROR;
- }
- faPtr->underline = n;
- break;
-
- case FONT_OVERSTRIKE:
- if (Tcl_GetBooleanFromObj(interp, value, &n) != TCL_OK) {
- return TCL_ERROR;
- }
- faPtr->overstrike = n;
- break;
- }
- }
- return TCL_OK;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * GetAttributeInfoObj --
- *
- * Return information about the font attributes as a Tcl list.
- *
- * Results:
- * Interp's result object is modified to hold a description of either
- * the current value of a single option, or a list of all options
- * and their current values for the given font attributes.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- static void
- GetAttributeInfoObj(interp, faPtr, objPtr)
- Tcl_Interp *interp; /* Interp to hold result. */
- CONST TkFontAttributes *faPtr; /* The font attributes to inspect. */
- Tcl_Obj *objPtr; /* If non-NULL, indicates the single
- * option whose value is to be
- * returned. Otherwise
- * information is returned for
- * all options. */
- {
- int i, index, start, end, num;
- char *str;
- Tcl_Obj *newPtr;
-
- start = 0;
- end = FONT_NUMFIELDS;
- if (objPtr != NULL) {
- if (Tcl_GetIndexFromObj(NULL, objPtr, fontOpt, "option", 1,
- &index) != TCL_OK) {
- return;
- }
- start = index;
- end = index + 1;
- }
-
- for (i = start; i < end; i++) {
- str = NULL;
- num = 0; /* Needed only to prevent compiler
- * warning. */
- switch (i) {
- case FONT_FAMILY:
- str = faPtr->family;
- if (str == NULL) {
- str = "";
- }
- break;
-
- case FONT_SIZE:
- num = faPtr->pointsize;
- break;
-
- case FONT_WEIGHT:
- str = TkFindStateString(weightMap, faPtr->weight);
- break;
-
- case FONT_SLANT:
- str = TkFindStateString(slantMap, faPtr->slant);
- break;
-
- case FONT_UNDERLINE:
- num = faPtr->underline;
- break;
-
- case FONT_OVERSTRIKE:
- num = faPtr->overstrike;
- break;
- }
- if (objPtr == NULL) {
- Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp),
- Tcl_NewStringObj(fontOpt[i], -1));
- if (str != NULL) {
- newPtr = Tcl_NewStringObj(str, -1);
- } else {
- newPtr = Tcl_NewIntObj(num);
- }
- Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp),
- newPtr);
- } else {
- if (str != NULL) {
- Tcl_SetStringObj(Tcl_GetObjResult(interp), str, -1);
- } else {
- Tcl_SetIntObj(Tcl_GetObjResult(interp), num);
- }
- }
- }
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * ParseFontNameObj --
- *
- * Converts a object into a set of font attributes that can be used
- * to construct a font.
- *
- * The string rep of the object can be one of the following forms:
- * XLFD (see X documentation)
- * "Family [size [style] [style ...]]"
- * "-option value [-option value ...]"
- *
- * Results:
- * The return value is TCL_ERROR if the object was syntactically
- * invalid. In that case an error message is left in interp's
- * result object. Otherwise, fills the font attribute buffer with
- * the values parsed from the string and returns TCL_OK;
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- static int
- ParseFontNameObj(interp, tkwin, objPtr, faPtr)
- Tcl_Interp *interp; /* Interp for error return. */
- Tk_Window tkwin; /* For display on which font is used. */
- Tcl_Obj *objPtr; /* Parseable font description object. */
- TkFontAttributes *faPtr; /* Font attributes structure whose fields
- * are to be modified. Structure must already
- * be properly initialized. */
- {
- char *dash;
- int objc, result, i, n;
- Tcl_Obj **objv;
- TkXLFDAttributes xa;
- char *string;
-
- string = Tcl_GetStringFromObj(objPtr, NULL);
- if (*string == '-') {
- /*
- * This may be an XLFD or an "-option value" string.
- *
- * If the string begins with "-*" or a "-foundry-family-*" pattern,
- * then consider it an XLFD.
- */
-
- if (string[1] == '*') {
- goto xlfd;
- }
- dash = strchr(string + 1, '-');
- if ((dash != NULL) && (!isspace(UCHAR(dash[-1])))) {
- goto xlfd;
- }
-
- if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
- return TCL_ERROR;
- }
-
- return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr);
- }
-
- if (*string == '*') {
- /*
- * This appears to be an XLFD.
- */
-
- xlfd:
- xa.fa = *faPtr;
- result = TkParseXLFD(string, &xa);
- if (result == TCL_OK) {
- *faPtr = xa.fa;
- return result;
- }
- }
-
- /*
- * Wasn't an XLFD or "-option value" string. Try it as a
- * "font size style" list.
- */
-
- if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
- return TCL_ERROR;
- }
- if (objc < 1) {
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "font \"", string,
- "\" doesn't exist", (char *) NULL);
- return TCL_ERROR;
- }
-
- faPtr->family = Tk_GetUid(Tcl_GetStringFromObj(objv[0], NULL));
- if (objc > 1) {
- if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) {
- return TCL_ERROR;
- }
- faPtr->pointsize = n;
- }
-
- i = 2;
- if (objc == 3) {
- if (Tcl_ListObjGetElements(interp, objv[2], &objc, &objv) != TCL_OK) {
- return TCL_ERROR;
- }
- i = 0;
- }
- for ( ; i < objc; i++) {
- string = Tcl_GetStringFromObj(objv[i], NULL);
- n = TkFindStateNum(NULL, NULL, weightMap, string);
- if (n != TK_FW_UNKNOWN) {
- faPtr->weight = n;
- continue;
- }
- n = TkFindStateNum(NULL, NULL, slantMap, string);
- if (n != TK_FS_UNKNOWN) {
- faPtr->slant = n;
- continue;
- }
- n = TkFindStateNum(NULL, NULL, underlineMap, string);
- if (n != 0) {
- faPtr->underline = n;
- continue;
- }
- n = TkFindStateNum(NULL, NULL, overstrikeMap, string);
- if (n != 0) {
- faPtr->overstrike = n;
- continue;
- }
-
- /*
- * Unknown style.
- */
-
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "unknown font style \"", string, "\"",
- (char *) NULL);
- return TCL_ERROR;
- }
- return TCL_OK;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * TkParseXLFD --
- *
- * Break up a fully specified XLFD into a set of font attributes.
- *
- * Results:
- * Return value is TCL_ERROR if string was not a fully specified XLFD.
- * Otherwise, fills font attribute buffer with the values parsed
- * from the XLFD and returns TCL_OK.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- int
- TkParseXLFD(string, xaPtr)
- CONST char *string; /* Parseable font description string. */
- TkXLFDAttributes *xaPtr; /* XLFD attributes structure whose fields
- * are to be modified. Structure must already
- * be properly initialized. */
- {
- char *src;
- CONST char *str;
- int i, j;
- char *field[XLFD_NUMFIELDS + 2];
- Tcl_DString ds;
-
- memset(field, '\0', sizeof(field));
-
- str = string;
- if (*str == '-') {
- str++;
- }
-
- Tcl_DStringInit(&ds);
- Tcl_DStringAppend(&ds, (char *) str, -1);
- src = Tcl_DStringValue(&ds);
-
- field[0] = src;
- for (i = 0; *src != '\0'; src++) {
- if (isupper(UCHAR(*src))) {
- *src = tolower(UCHAR(*src));
- }
- if (*src == '-') {
- i++;
- if (i > XLFD_NUMFIELDS) {
- break;
- }
- *src = '\0';
- field[i] = src + 1;
- }
- }
-
- /*
- * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common,
- * but it is (strictly) malformed, because the first * is eliding both
- * the Setwidth and the Addstyle fields. If the Addstyle field is a
- * number, then assume the above incorrect form was used and shift all
- * the rest of the fields up by one, so the number gets interpreted
- * as a pixelsize. This fix is so that we don't get a million reports
- * that "it works under X, but gives a syntax error under Windows".
- */
-
- if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {
- if (atoi(field[XLFD_ADD_STYLE]) != 0) {
- for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {
- field[j + 1] = field[j];
- }
- field[XLFD_ADD_STYLE] = NULL;
- i++;
- }
- }
-
- /*
- * Bail if we don't have enough of the fields (up to pointsize).
- */
-
- if (i < XLFD_FAMILY) {
- Tcl_DStringFree(&ds);
- return TCL_ERROR;
- }
-
- if (FieldSpecified(field[XLFD_FOUNDRY])) {
- xaPtr->foundry = Tk_GetUid(field[XLFD_FOUNDRY]);
- }
-
- if (FieldSpecified(field[XLFD_FAMILY])) {
- xaPtr->fa.family = Tk_GetUid(field[XLFD_FAMILY]);
- }
- if (FieldSpecified(field[XLFD_WEIGHT])) {
- xaPtr->fa.weight = TkFindStateNum(NULL, NULL, xlfdWeightMap,
- field[XLFD_WEIGHT]);
- }
- if (FieldSpecified(field[XLFD_SLANT])) {
- xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap,
- field[XLFD_SLANT]);
- if (xaPtr->slant == TK_FS_ROMAN) {
- xaPtr->fa.slant = TK_FS_ROMAN;
- } else {
- xaPtr->fa.slant = TK_FS_ITALIC;
- }
- }
- if (FieldSpecified(field[XLFD_SETWIDTH])) {
- xaPtr->setwidth = TkFindStateNum(NULL, NULL, xlfdSetwidthMap,
- field[XLFD_SETWIDTH]);
- }
-
- /* XLFD_ADD_STYLE ignored. */
-
- /*
- * Pointsize in tenths of a point, but treat it as tenths of a pixel.
- */
-
- if (FieldSpecified(field[XLFD_POINT_SIZE])) {
- if (field[XLFD_POINT_SIZE][0] == '[') {
- /*
- * Some X fonts have the point size specified as follows:
- *
- * [ N1 N2 N3 N4 ]
- *
- * where N1 is the point size (in points, not decipoints!), and
- * N2, N3, and N4 are some additional numbers that I don't know
- * the purpose of, so I ignore them.
- */
-
- xaPtr->fa.pointsize = atoi(field[XLFD_POINT_SIZE] + 1);
- } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE],
- &xaPtr->fa.pointsize) == TCL_OK) {
- xaPtr->fa.pointsize /= 10;
- } else {
- return TCL_ERROR;
- }
- }
-
- /*
- * Pixel height of font. If specified, overrides pointsize.
- */
-
- if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
- if (field[XLFD_PIXEL_SIZE][0] == '[') {
- /*
- * Some X fonts have the pixel size specified as follows:
- *
- * [ N1 N2 N3 N4 ]
- *
- * where N1 is the pixel size, and where N2, N3, and N4
- * are some additional numbers that I don't know
- * the purpose of, so I ignore them.
- */
-
- xaPtr->fa.pointsize = atoi(field[XLFD_PIXEL_SIZE] + 1);
- } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE],
- &xaPtr->fa.pointsize) != TCL_OK) {
- return TCL_ERROR;
- }
- }
-
- xaPtr->fa.pointsize = -xaPtr->fa.pointsize;
-
- /* XLFD_RESOLUTION_X ignored. */
-
- /* XLFD_RESOLUTION_Y ignored. */
-
- /* XLFD_SPACING ignored. */
-
- /* XLFD_AVERAGE_WIDTH ignored. */
-
- if (FieldSpecified(field[XLFD_REGISTRY])) {
- xaPtr->charset = TkFindStateNum(NULL, NULL, xlfdCharsetMap,
- field[XLFD_REGISTRY]);
- }
- if (FieldSpecified(field[XLFD_ENCODING])) {
- xaPtr->encoding = atoi(field[XLFD_ENCODING]);
- }
-
- Tcl_DStringFree(&ds);
- return TCL_OK;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * FieldSpecified --
- *
- * Helper function for TkParseXLFD(). Determines if a field in the
- * XLFD was set to a non-null, non-don't-care value.
- *
- * Results:
- * The return value is 0 if the field in the XLFD was not set and
- * should be ignored, non-zero otherwise.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
- static int
- FieldSpecified(field)
- CONST char *field; /* The field of the XLFD to check. Strictly
- * speaking, only when the string is "*" does it mean
- * don't-care. However, an unspecified or question
- * mark is also interpreted as don't-care. */
- {
- char ch;
-
- if (field == NULL) {
- return 0;
- }
- ch = field[0];
- return (ch != '*' && ch != '?');
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * NewChunk --
- *
- * Helper function for Tk_ComputeTextLayout(). Encapsulates a
- * measured set of characters in a chunk that can be quickly
- * drawn.
- *
- * Results:
- * A pointer to the new chunk in the text layout.
- *
- * Side effects:
- * The text layout is reallocated to hold more chunks as necessary.
- *
- * Currently, Tk_ComputeTextLayout() stores contiguous ranges of
- * "normal" characters in a chunk, along with individual tab
- * and newline chars in their own chunks. All characters in the
- * text layout are accounted for.
- *
- *---------------------------------------------------------------------------
- */
- static LayoutChunk *
- NewChunk(layoutPtrPtr, maxPtr, start, numChars, curX, newX, y)
- TextLayout **layoutPtrPtr;
- int *maxPtr;
- CONST char *start;
- int numChars;
- int curX;
- int newX;
- int y;
- {
- TextLayout *layoutPtr;
- LayoutChunk *chunkPtr;
- int maxChunks;
- size_t s;
-
- layoutPtr = *layoutPtrPtr;
- maxChunks = *maxPtr;
- if (layoutPtr->numChunks == maxChunks) {
- maxChunks *= 2;
- s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk));
- layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s);
-
- *layoutPtrPtr = layoutPtr;
- *maxPtr = maxChunks;
- }
- chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks];
- chunkPtr->start = start;
- chunkPtr->numChars = numChars;
- chunkPtr->numDisplayChars = numChars;
- chunkPtr->x = curX;
- chunkPtr->y = y;
- chunkPtr->totalWidth = newX - curX;
- chunkPtr->displayWidth = newX - curX;
- layoutPtr->numChunks++;
-
- return chunkPtr;
- }
-
-