tkFont.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:102k
- /*
- * 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-1998 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkFont.c,v 1.21.2.2 2007/05/31 13:39:26 das Exp $
- */
- #include "tkPort.h"
- #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 string font names, values are
- * TkFont pointers. */
- 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
- * strings, values are NamedFont pointers. */
- TkMainInfo *mainPtr; /* Application that owns this structure. */
- int updatePending; /* Non-zero when a World Changed event has
- * already been queued to handle a change to
- * a named font. */
- } TkFontInfo;
- /*
- * 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 numBytes; /* The number of bytes in this chunk. */
- 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}
- };
- /*
- * The following structure and defines specify the valid builtin options
- * when configuring a set of font attributes.
- */
- static CONST 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
- /*
- * Hardcoded font aliases. These are used to describe (mostly) identical
- * fonts whose names differ from platform to platform. If the
- * user-supplied font name matches any of the names in one of the alias
- * lists, the other names in the alias list are also automatically tried.
- */
- static char *timesAliases[] = {
- "Times", /* Unix. */
- "Times New Roman", /* Windows. */
- "New York", /* Mac. */
- NULL
- };
- static char *helveticaAliases[] = {
- "Helvetica", /* Unix. */
- "Arial", /* Windows. */
- "Geneva", /* Mac. */
- NULL
- };
- static char *courierAliases[] = {
- "Courier", /* Unix and Mac. */
- "Courier New", /* Windows. */
- NULL
- };
- static char *minchoAliases[] = {
- "mincho", /* Unix. */
- "357274255357274263 346230216346234235",
- /* Windows (MS mincho). */
- "346234254346230216346234235342210222357274255",
- /* Mac (honmincho-M). */
- NULL
- };
- static char *gothicAliases[] = {
- "gothic", /* Unix. */
- "357274255357274263 343202264343202267343203203343202257",
- /* Windows (MS goshikku). */
- "344270270343202264343202267343203203343202257342210222357274255",
- /* Mac (goshikku-M). */
- NULL
- };
- static char *dingbatsAliases[] = {
- "dingbats", "zapfdingbats", "itc zapfdingbats",
- /* Unix. */
- /* Windows. */
- "zapf dingbats", /* Mac. */
- NULL
- };
- static char **fontAliases[] = {
- timesAliases,
- helveticaAliases,
- courierAliases,
- minchoAliases,
- gothicAliases,
- dingbatsAliases,
- NULL
- };
- /*
- * Hardcoded font classes. If the character cannot be found in the base
- * font, the classes are examined in order to see if some other similar
- * font should be examined also.
- */
- static char *systemClass[] = {
- "fixed", /* Unix. */
- /* Windows. */
- "chicago", "osaka", "sistemny", /* Mac. */
- NULL
- };
- static char *serifClass[] = {
- "times", "palatino", "mincho", /* All platforms. */
- "song ti", /* Unix. */
- "ms serif", "simplified arabic", /* Windows. */
- "latinski", /* Mac. */
- NULL
- };
- static char *sansClass[] = {
- "helvetica", "gothic", /* All platforms. */
- /* Unix. */
- "ms sans serif", "traditional arabic",
- /* Windows. */
- "bastion", /* Mac. */
- NULL
- };
- static char *monoClass[] = {
- "courier", "gothic", /* All platforms. */
- "fangsong ti", /* Unix. */
- "simplified arabic fixed", /* Windows. */
- "monaco", "pryamoy", /* Mac. */
- NULL
- };
- static char *symbolClass[] = {
- "symbol", "dingbats", "wingdings", NULL
- };
- static char **fontFallbacks[] = {
- systemClass,
- serifClass,
- sansClass,
- monoClass,
- symbolClass,
- NULL
- };
- /*
- * Global fallbacks. If the character could not be found in the preferred
- * fallback list, this list is examined. If the character still cannot be
- * found, all font families in the system are examined.
- */
- static char *globalFontClass[] = {
- "symbol", /* All platforms. */
- /* Unix. */
- "lucida sans unicode", /* Windows. */
- "bitstream cyberbit", /* Windows popular CJK font */
- "chicago", /* Mac. */
- NULL
- };
- #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 CreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp,
- Tk_Window tkwin, CONST char *name,
- TkFontAttributes *faPtr));
- static void DupFontObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
- Tcl_Obj *dupObjPtr));
- static int FieldSpecified _ANSI_ARGS_((CONST char *field));
- static void FreeFontObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
- static int 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 int SetFontFromAny _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_Obj *objPtr));
- static void TheWorldHasChanged _ANSI_ARGS_((
- ClientData clientData));
- static void UpdateDependentFonts _ANSI_ARGS_((TkFontInfo *fiPtr,
- Tk_Window tkwin, Tcl_HashEntry *namedHashPtr));
- /*
- * The following structure defines the implementation of the "font" Tcl
- * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of
- * each font object points to the TkFont structure for the font, or
- * NULL.
- */
- Tcl_ObjType tkFontObjType = {
- "font", /* name */
- FreeFontObjProc, /* freeIntRepProc */
- DupFontObjProc, /* dupIntRepProc */
- NULL, /* updateStringProc */
- SetFontFromAny /* setFromAnyProc */
- };
- /*
- *---------------------------------------------------------------------------
- *
- * 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:
- * Stores a token in the mainPtr to hold information needed by this
- * package on a per application basis.
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
- void
- TkFontPkgInit(mainPtr)
- TkMainInfo *mainPtr; /* The application being created. */
- {
- TkFontInfo *fiPtr;
- fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo));
- Tcl_InitHashTable(&fiPtr->fontCache, TCL_STRING_KEYS);
- Tcl_InitHashTable(&fiPtr->namedTable, TCL_STRING_KEYS);
- fiPtr->mainPtr = mainPtr;
- fiPtr->updatePending = 0;
- mainPtr->fontInfoPtr = fiPtr;
- TkpFontPkgInit(mainPtr);
- }
- /*
- *---------------------------------------------------------------------------
- *
- * 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, *searchPtr;
- Tcl_HashSearch search;
- int fontsLeft;
- fiPtr = mainPtr->fontInfoPtr;
- fontsLeft = 0;
- for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
- searchPtr != NULL;
- searchPtr = Tcl_NextHashEntry(&search)) {
- fontsLeft++;
- #ifdef DEBUG_FONTS
- fprintf(stderr, "Font %s still in cache.n",
- Tcl_GetHashKey(&fiPtr->fontCache, searchPtr));
- #endif
- }
- #ifdef PURIFY
- if (fontsLeft) {
- panic("TkFontPkgFree: all fonts should have been freed already");
- }
- #endif
- 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 CONST 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, result;
- 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_AllocFontFromObj(interp, tkwin, objv[2]);
- if (tkfont == NULL) {
- return TCL_ERROR;
- }
- objc -= skip;
- objv += skip;
- faPtr = GetFontAttributes(tkfont);
- objPtr = NULL;
- if (objc > 3) {
- objPtr = objv[3];
- }
- result = GetAttributeInfoObj(interp, faPtr, objPtr);
- Tk_FreeFont(tkfont);
- return result;
- }
- 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 = Tcl_GetString(objv[2]);
- namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
- nfPtr = NULL; /* lint. */
- if (namedHashPtr != NULL) {
- nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
- }
- if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) {
- Tcl_AppendResult(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);
- UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);
- return result;
- }
- return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr);
- }
- case FONT_CREATE: {
- int skip, i;
- char *name;
- char buf[16 + TCL_INTEGER_SPACE];
- TkFontAttributes fa;
- Tcl_HashEntry *namedHashPtr;
- skip = 3;
- if (objc < 3) {
- name = NULL;
- } else {
- name = Tcl_GetString(objv[2]);
- 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, 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 (CreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) {
- return TCL_ERROR;
- }
- Tcl_AppendResult(interp, name, NULL);
- 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 = Tcl_GetString(objv[i]);
- namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
- if (namedHashPtr == NULL) {
- Tcl_AppendResult(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;
- Tcl_Obj *resultPtr;
-
- skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &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_AllocFontFromObj(interp, tkwin, objv[2]);
- if (tkfont == NULL) {
- return TCL_ERROR;
- }
- string = Tcl_GetStringFromObj(objv[3 + skip], &length);
- resultPtr = Tcl_GetObjResult(interp);
- Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length));
- Tk_FreeFont(tkfont);
- break;
- }
- case FONT_METRICS: {
- Tk_Font tkfont;
- int skip, index, i;
- CONST TkFontMetrics *fmPtr;
- static CONST char *switches[] = {
- "-ascent", "-descent", "-linespace", "-fixed", NULL
- };
- 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_AllocFontFromObj(interp, tkwin, objv[2]);
- if (tkfont == NULL) {
- return TCL_ERROR;
- }
- objc -= skip;
- objv += skip;
- fmPtr = GetFontMetrics(tkfont);
- if (objc == 3) {
- char buf[64 + TCL_INTEGER_SPACE * 4];
- sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d",
- fmPtr->ascent, fmPtr->descent,
- fmPtr->ascent + fmPtr->descent,
- fmPtr->fixed);
- Tcl_AppendResult(interp, buf, NULL);
- } else {
- if (Tcl_GetIndexFromObj(interp, objv[3], 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;
- NamedFont *nfPtr;
- Tcl_HashSearch search;
- Tcl_HashEntry *namedHashPtr;
- Tcl_Obj *strPtr, *resultPtr;
-
- if (objc != 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "names");
- return TCL_ERROR;
- }
- resultPtr = Tcl_GetObjResult(interp);
- 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, resultPtr, strPtr);
- }
- namedHashPtr = Tcl_NextHashEntry(&search);
- }
- break;
- }
- }
- return TCL_OK;
- }
- /*
- *---------------------------------------------------------------------------
- *
- * UpdateDependentFonts, 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
- UpdateDependentFonts(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) {
- for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
- fontPtr != NULL; fontPtr = fontPtr->nextPtr) {
- 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. */
- {
- Tk_ClassWorldChangedProc *proc;
- proc = Tk_GetClassProc(winPtr->classProcsPtr, worldChangedProc);
- if (proc != NULL) {
- (*proc)(winPtr->instanceData);
- }
- /*
- * Notify all the descendants of this window that the world has changed.
- *
- * This could be done recursively or iteratively. The recursive version
- * is easier to implement and understand, and typically, windows with a
- * -font option will be leaf nodes in the widget heirarchy (buttons,
- * labels, etc.), so the recursion depth will be shallow.
- *
- * However, the additional overhead of the recursive calls may become
- * a performance problem if typical usage alters such that -font'ed widgets
- * appear high in the heirarchy, causing deep recursion. This could happen
- * with text widgets, or more likely with the (not yet existant) labeled
- * frame widget. With these widgets it is possible, even likely, that a
- * -font'ed widget (text or labeled frame) will not be a leaf node, but
- * will instead have many descendants. If this is ever found to cause
- * a performance problem, it may be worth investigating an iterative
- * version of the code below.
- */
- for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) {
- RecomputeWidgets(winPtr);
- }
- }
- /*
- *---------------------------------------------------------------------------
- *
- * CreateNamedFont --
- *
- * 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 the interp's 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.
- *
- *---------------------------------------------------------------------------
- */
- static int
- CreateNamedFont(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;
- namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new);
-
- if (new == 0) {
- nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
- if (nfPtr->deletePending == 0) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "named 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;
- UpdateDependentFonts(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 the interp's result.
- *
- * 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() or Tk_FreeFontFromObj() so that the
- * database is cleaned up when fonts aren't in use anymore.
- *
- *---------------------------------------------------------------------------
- */
- Tk_Font
- Tk_GetFont(interp, tkwin, string)
- Tcl_Interp *interp; /* Interp for database and error return, or
- * NULL for no error messages. */
- 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. */
- {
- Tk_Font tkfont;
- Tcl_Obj *strPtr;
- strPtr = Tcl_NewStringObj((char *) string, -1);
- Tcl_IncrRefCount(strPtr);
- tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr);
- Tcl_DecrRefCount(strPtr);
- return tkfont;
- }
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_AllocFontFromObj --
- *
- * 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 (if non-NULL).
- *
- * 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() or Tk_FreeFontFromObj() so that the
- * database is cleaned up when fonts aren't in use anymore.
- *
- *---------------------------------------------------------------------------
- */
- Tk_Font
- Tk_AllocFontFromObj(interp, tkwin, objPtr)
- Tcl_Interp *interp; /* Interp for database and error return. */
- Tk_Window tkwin; /* For screen on which font will be used. */
- Tcl_Obj *objPtr; /* Object describing font, as: named font,
- * native format, or parseable string. */
- {
- TkFontInfo *fiPtr;
- Tcl_HashEntry *cacheHashPtr, *namedHashPtr;
- TkFont *fontPtr, *firstFontPtr, *oldFontPtr;
- int new, descent;
- NamedFont *nfPtr;
- fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
- if (objPtr->typePtr != &tkFontObjType) {
- SetFontFromAny(interp, objPtr);
- }
- oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
- if (oldFontPtr != NULL) {
- if (oldFontPtr->resourceRefCount == 0) {
- /*
- * This is a stale reference: it refers to a TkFont that's
- * no longer in use. Clear the reference.
- */
- FreeFontObjProc(objPtr);
- oldFontPtr = NULL;
- } else if (Tk_Screen(tkwin) == oldFontPtr->screen) {
- oldFontPtr->resourceRefCount++;
- return (Tk_Font) oldFontPtr;
- }
- }
- /*
- * Next, search the list of fonts that have the name we want, to see
- * if one of them is for the right screen.
- */
- new = 0;
- if (oldFontPtr != NULL) {
- cacheHashPtr = oldFontPtr->cacheHashPtr;
- FreeFontObjProc(objPtr);
- } else {
- cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache,
- Tcl_GetString(objPtr), &new);
- }
- firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
- for (fontPtr = firstFontPtr; (fontPtr != NULL);
- fontPtr = fontPtr->nextPtr) {
- if (Tk_Screen(tkwin) == fontPtr->screen) {
- fontPtr->resourceRefCount++;
- fontPtr->objRefCount++;
- objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
- return (Tk_Font) fontPtr;
- }
- }
- /*
- * The desired font isn't in the table. Make a new one.
- */
- namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable,
- Tcl_GetString(objPtr));
- 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, Tcl_GetString(objPtr));
- if (fontPtr == NULL) {
- TkFontAttributes fa;
- Tcl_Obj *dupObjPtr = Tcl_DuplicateObj(objPtr);
- if (ParseFontNameObj(interp, tkwin, dupObjPtr, &fa) != TCL_OK) {
- if (new) {
- Tcl_DeleteHashEntry(cacheHashPtr);
- }
- Tcl_DecrRefCount(dupObjPtr);
- return NULL;
- }
- Tcl_DecrRefCount(dupObjPtr);
- /*
- * String contained the attributes inline.
- */
- fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa);
- }
- }
- fontPtr->resourceRefCount = 1;
- fontPtr->objRefCount = 1;
- fontPtr->cacheHashPtr = cacheHashPtr;
- fontPtr->namedHashPtr = namedHashPtr;
- fontPtr->screen = Tk_Screen(tkwin);
- fontPtr->nextPtr = firstFontPtr;
- Tcl_SetHashValue(cacheHashPtr, fontPtr);
- Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, -1, 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 = TkFontGetPixels(tkwin, fontPtr->fa.size) / 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;
- }
- }
-
- objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
- return (Tk_Font) fontPtr;
- }
- /*
- *----------------------------------------------------------------------
- *
- * Tk_GetFontFromObj --
- *
- * Find the font that corresponds to a given object. The font must
- * have already been created by Tk_GetFont or Tk_AllocFontFromObj.
- *
- * Results:
- * The return value is a token for the font that matches objPtr
- * and is suitable for use in tkwin.
- *
- * Side effects:
- * If the object is not already a font ref, the conversion will free
- * any old internal representation.
- *
- *----------------------------------------------------------------------
- */
- Tk_Font
- Tk_GetFontFromObj(tkwin, objPtr)
- Tk_Window tkwin; /* The window that the font will be used in. */
- Tcl_Obj *objPtr; /* The object from which to get the font. */
- {
- TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
- TkFont *fontPtr;
- Tcl_HashEntry *hashPtr;
-
- if (objPtr->typePtr != &tkFontObjType) {
- SetFontFromAny((Tcl_Interp *) NULL, objPtr);
- }
- fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
- if (fontPtr != NULL) {
- if (fontPtr->resourceRefCount == 0) {
- /*
- * This is a stale reference: it refers to a TkFont that's
- * no longer in use. Clear the reference.
- */
- FreeFontObjProc(objPtr);
- fontPtr = NULL;
- } else if (Tk_Screen(tkwin) == fontPtr->screen) {
- return (Tk_Font) fontPtr;
- }
- }
- /*
- * Next, search the list of fonts that have the name we want, to see
- * if one of them is for the right screen.
- */
- if (fontPtr != NULL) {
- hashPtr = fontPtr->cacheHashPtr;
- FreeFontObjProc(objPtr);
- } else {
- hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr));
- }
- if (hashPtr != NULL) {
- for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL;
- fontPtr = fontPtr->nextPtr) {
- if (Tk_Screen(tkwin) == fontPtr->screen) {
- fontPtr->objRefCount++;
- objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
- return (Tk_Font) fontPtr;
- }
- }
- }
- panic("Tk_GetFontFromObj called with non-existent font!");
- return NULL;
- }
- /*
- *----------------------------------------------------------------------
- *
- * SetFontFromAny --
- *
- * Convert the internal representation of a Tcl object to the
- * font internal form.
- *
- * Results:
- * Always returns TCL_OK.
- *
- * Side effects:
- * The object is left with its typePtr pointing to tkFontObjType.
- * The TkFont pointer is NULL.
- *
- *----------------------------------------------------------------------
- */
- static int
- SetFontFromAny(interp, objPtr)
- Tcl_Interp *interp; /* Used for error reporting if not NULL. */
- Tcl_Obj *objPtr; /* The object to convert. */
- {
- Tcl_ObjType *typePtr;
- /*
- * Free the old internalRep before setting the new one.
- */
- Tcl_GetString(objPtr);
- typePtr = objPtr->typePtr;
- if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
- (*typePtr->freeIntRepProc)(objPtr);
- }
- objPtr->typePtr = &tkFontObjType;
- objPtr->internalRep.twoPtrValue.ptr1 = NULL;
- return TCL_OK;
- }
- /*
- *---------------------------------------------------------------------------
- *
- * 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.
- *
- *---------------------------------------------------------------------------
- */
- CONST char *
- Tk_NameOfFont(tkfont)
- Tk_Font tkfont; /* Font whose name is desired. */
- {
- TkFont *fontPtr;
- fontPtr = (TkFont *) tkfont;
- return fontPtr->cacheHashPtr->key.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, *prevPtr;
- NamedFont *nfPtr;
- if (tkfont == NULL) {
- return;
- }
- fontPtr = (TkFont *) tkfont;
- fontPtr->resourceRefCount--;
- if (fontPtr->resourceRefCount > 0) {
- return;
- }
- if (fontPtr->namedHashPtr != NULL) {
- /*
- * This font derived from a named font. Reduce the reference
- * count on the named font and free it if no-one else is
- * using it.
- */
- nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr);
- nfPtr->refCount--;
- if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) {
- Tcl_DeleteHashEntry(fontPtr->namedHashPtr);
- ckfree((char *) nfPtr);
- }
- }
- prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr);
- if (prevPtr == fontPtr) {
- if (fontPtr->nextPtr == NULL) {
- Tcl_DeleteHashEntry(fontPtr->cacheHashPtr);
- } else {
- Tcl_SetHashValue(fontPtr->cacheHashPtr, fontPtr->nextPtr);
- }
- } else {
- while (prevPtr->nextPtr != fontPtr) {
- prevPtr = prevPtr->nextPtr;
- }
- prevPtr->nextPtr = fontPtr->nextPtr;
- }
- TkpDeleteFont(fontPtr);
- if (fontPtr->objRefCount == 0) {
- ckfree((char *) fontPtr);
- }
- }
- /*
- *---------------------------------------------------------------------------
- *
- * Tk_FreeFontFromObj --
- *
- * Called to release a font inside a Tcl_Obj *. Decrements the refCount
- * of the font and removes it from the hash tables if necessary.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The reference count associated with font is decremented, and
- * only deallocated when no one is using it.
- *
- *---------------------------------------------------------------------------
- */
- void
- Tk_FreeFontFromObj(tkwin, objPtr)
- Tk_Window tkwin; /* The window this font lives in. Needed
- * for the screen value. */
- Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */
- {
- Tk_FreeFont(Tk_GetFontFromObj(tkwin, objPtr));
- }
- /*
- *---------------------------------------------------------------------------
- *
- * FreeFontObjProc --
- *
- * This proc is called to release an object reference to a font.
- * Called when the object's internal rep is released or when
- * the cached fontPtr needs to be changed.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The object reference count is decremented. When both it
- * and the hash ref count go to zero, the font's resources
- * are released.
- *
- *---------------------------------------------------------------------------
- */
- static void
- FreeFontObjProc(objPtr)
- Tcl_Obj *objPtr; /* The object we are releasing. */
- {
- TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
- if (fontPtr != NULL) {
- fontPtr->objRefCount--;
- if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) {
- ckfree((char *) fontPtr);
- objPtr->internalRep.twoPtrValue.ptr1 = NULL;
- }
- }
- }
- /*
- *---------------------------------------------------------------------------
- *
- * DupFontObjProc --
- *
- * When a cached font object is duplicated, this is called to
- * update the internal reps.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The font's objRefCount is incremented and the internal rep
- * of the copy is set to point to it.
- *
- *---------------------------------------------------------------------------
- */
- static void
- DupFontObjProc(srcObjPtr, dupObjPtr)
- Tcl_Obj *srcObjPtr; /* The object we are copying from. */
- Tcl_Obj *dupObjPtr; /* The object we are copying to. */
- {
- TkFont *fontPtr = (TkFont *) srcObjPtr->internalRep.twoPtrValue.ptr1;
-
- dupObjPtr->typePtr = srcObjPtr->typePtr;
- dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
- if (fontPtr != NULL) {
- fontPtr->objRefCount++;
- }
- }
- /*
- *---------------------------------------------------------------------------
- *
- * 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;
- Tk_Uid 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 {
- Tcl_UniChar ch;
- /*
- * 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 != ' '; ) {
- while (isspace(UCHAR(*src))) { /* INTL: ISO space */
- src++;
- upper = 1;
- }
- src += Tcl_UtfToUniChar(src, &ch);
- if (upper) {
- ch = Tcl_UniCharToUpper(ch);
- upper = 0;
- } else {
- ch = Tcl_UniCharToLower(ch);
- }
- dest += Tcl_UniCharToUtf(ch, dest);
- }
- *dest = ' ';
- 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.size;
- }
- /*
- *---------------------------------------------------------------------------
- *
- * 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, numBytes)
- Tk_Font tkfont; /* Font in which text will be measured. */
- CONST char *string; /* String whose width will be computed. */
- int numBytes; /* Number of bytes to consider from
- * string, or < 0 for strlen(). */
- {
- int width;
- if (numBytes < 0) {
- numBytes = strlen(string);
- }
- Tk_MeasureChars(tkfont, string, numBytes, -1, 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, firstByte,
- lastByte)
- 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 firstByte; /* Index of first byte of first character. */
- int lastByte; /* Index of first byte after the last
- * character. */
- {
- TkFont *fontPtr;
- int startX, endX;
- fontPtr = (TkFont *) tkfont;
-
- Tk_MeasureChars(tkfont, string, firstByte, -1, 0, &startX);
- Tk_MeasureChars(tkfont, string, lastByte, -1, 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, bytesThisChunk, maxChunks;
- int baseline, height, curX, newX, maxWidth;
- TextLayout *layoutPtr;
- LayoutChunk *chunkPtr;
- CONST TkFontMetrics *fmPtr;
- Tcl_DString lineBuffer;
- int *lineLengths;
- int curLine, layoutHeight;
- Tcl_DStringInit(&lineBuffer);
-
- fontPtr = (TkFont *) tkfont;
- if ((fontPtr == NULL) || (string == NULL)) {
- if (widthPtr != NULL) {
- *widthPtr = 0;
- }
- if (heightPtr != NULL) {
- *heightPtr = 0;
- }
- return NULL;
- }
- fmPtr = &fontPtr->fm;
- height = fmPtr->ascent + fmPtr->descent;
- if (numChars < 0) {
- numChars = Tcl_NumUtfChars(string, -1);
- }
- if (wrapLength == 0) {
- wrapLength = -1;
- }
- 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 = Tcl_UtfAtIndex(string, numChars);
- special = string;
- flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES;
- flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE;
- for (start = string; start < end; ) {
- if (start >= special) {
- /*
- * Find the next special character in the string.
- *
- * INTL: Note that it is safe to increment by byte, because we are
- * looking for 7-bit characters that will appear unchanged in
- * UTF-8. At some point we may need to support the full Unicode
- * whitespace set.
- */
- 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) {
- bytesThisChunk = Tk_MeasureChars(tkfont, start, special - start,
- wrapLength - curX, flags, &newX);
- newX += curX;
- flags &= ~TK_AT_LEAST_ONE;
- if (bytesThisChunk > 0) {
- chunkPtr = NewChunk(&layoutPtr, &maxChunks, start,
- bytesThisChunk, curX, newX, baseline);
-
- start += bytesThisChunk;
- curX = newX;
- }
- }
- if ((start == special) && (special < end)) {
- /*
- * Handle the special character.
- *
- * INTL: Special will be pointing at a 7-bit character so we
- * can safely treat it as a single byte.
- */
- 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, curX,
- 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))) { /* INTL: ISO space */
- if (!(flags & TK_IGNORE_NEWLINES)) {
- if ((*start == 'n') || (*start == 'r')) {
- break;
- }
- }
- if (!(flags & TK_IGNORE_TABS)) {
- if (*start == 't') {
- break;
- }
- }
- start++;
- }
- if (chunkPtr != NULL) {
- CONST char *end;
- /*
- * Append all the extra spaces on this line to the end of the
- * last text chunk. This is a little tricky because we are
- * switching back and forth between characters and bytes.
- */
- end = chunkPtr->start + chunkPtr->numBytes;
- bytesThisChunk = start - end;
- if (bytesThisChunk > 0) {
- bytesThisChunk = Tk_MeasureChars(tkfont, end, bytesThisChunk,
- -1, 0, &chunkPtr->totalWidth);
- chunkPtr->numBytes += bytesThisChunk;
- chunkPtr->numChars += Tcl_NumUtfChars(end, bytesThisChunk);
- 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.
- */
- Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
- curX = 0;
- baseline += height;
- }
- /*
- * If last line ends with a newline, then we need to make a 0 width
- * chunk on the next line. Otherwise "Hello" and "Hellon" are the
- * same height.
- */
- if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) {
- if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == 'n') {
- chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX,
- curX, baseline);
- chunkPtr->numDisplayChars = -1;
- Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
- baseline += height;
- }
- }
- 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].numBytes = 0;
- 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;
- } else {
- /*
- * Using maximum line length, shift all the chunks so that the lines
- * are all justified correctly.
- */
-
- curLine = 0;
- chunkPtr = layoutPtr->chunks;
- y = chunkPtr->y;
- lineLengths = (int *) Tcl_DStringValue(&lineBuffer);
- 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++;
- }
- }
- if (widthPtr != NULL) {
- *widthPtr = layoutPtr->width;
- }
- if (heightPtr != NULL) {
- *heightPtr = layoutHeight;
- }
- Tcl_DStringFree(&lineBuffer);
- 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;
- CONST char *firstByte;
- CONST char *lastByte;
- 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;
- firstByte = chunkPtr->start;
- } else {
- firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar);
- Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start,
- firstByte - chunkPtr->start, -1, 0, &drawX);
- }
- if (lastChar < numDisplayChars) {
- numDisplayChars = lastChar;
- }
- lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars);
- Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,
- firstByte, lastByte - firstByte,
- 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, numChars;
- 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;
- numChars = 0;
- 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 numChars;
- }
- 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 numChars;
- }
- n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start,
- chunkPtr->numBytes, x - chunkPtr->x,
- 0, &dummy);
- return numChars + Tcl_NumUtfChars(chunkPtr->start, n);
- }
- numChars += chunkPtr->numChars;
- 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 = numChars;
- if (i < layoutPtr->numChunks) {
- pos--;
- }
- return pos;
- }
- numChars += chunkPtr->numChars;
- 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;
- CONST char *end;
- 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) {
- end = Tcl_UtfAtIndex(chunkPtr->start, index);
- if (xPtr != NULL) {
- Tk_MeasureChars(tkfont, chunkPtr->start,
- end - chunkPtr->start, -1, 0, &x);
- x += chunkPtr->x;
- }
- if (widthPtr != NULL) {
- Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end,
- -1, 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:
- * The interp's 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+30];
- LayoutChunk *chunkPtr;
- int i, j, used, c, baseline;
- Tcl_UniChar ch;
- CONST char *p, *last_p,*glyphname;
- TextLayout *layoutPtr;
- char uindex[5]="