diff options
Diffstat (limited to 'tk8.6/generic/tkFont.c')
-rw-r--r-- | tk8.6/generic/tkFont.c | 4271 |
1 files changed, 0 insertions, 4271 deletions
diff --git a/tk8.6/generic/tkFont.c b/tk8.6/generic/tkFont.c deleted file mode 100644 index 4183686..0000000 --- a/tk8.6/generic/tkFont.c +++ /dev/null @@ -1,4271 +0,0 @@ -/* - * tkFont.c -- - * - * This file maintains a database of fonts for the Tk toolkit. It also - * provides several utility functions 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. - */ - -#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 const TkStateMap weightMap[] = { - {TK_FW_NORMAL, "normal"}, - {TK_FW_BOLD, "bold"}, - {TK_FW_UNKNOWN, NULL} -}; - -static const TkStateMap slantMap[] = { - {TK_FS_ROMAN, "roman"}, - {TK_FS_ITALIC, "italic"}, - {TK_FS_UNKNOWN, NULL} -}; - -static const TkStateMap underlineMap[] = { - {1, "underline"}, - {0, NULL} -}; - -static const TkStateMap overstrikeMap[] = { - {1, "overstrike"}, - {0, NULL} -}; - -/* - * The following structures are used when parsing XLFD's into a set of - * TkFontAttributes. - */ - -static const 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 const TkStateMap xlfdSlantMap[] = { - {TK_FS_ROMAN, "r"}, - {TK_FS_ITALIC, "i"}, - {TK_FS_OBLIQUE, "o"}, - {TK_FS_ROMAN, NULL} /* Assume anything else is "roman". */ -}; - -static const 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 *const 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 const char *const timesAliases[] = { - "Times", /* Unix. */ - "Times New Roman", /* Windows. */ - "New York", /* Mac. */ - NULL -}; - -static const char *const helveticaAliases[] = { - "Helvetica", /* Unix. */ - "Arial", /* Windows. */ - "Geneva", /* Mac. */ - NULL -}; - -static const char *const courierAliases[] = { - "Courier", /* Unix and Mac. */ - "Courier New", /* Windows. */ - NULL -}; - -static const char *const minchoAliases[] = { - "mincho", /* Unix. */ - "\357\274\255\357\274\263 \346\230\216\346\234\235", - /* Windows (MS mincho). */ - "\346\234\254\346\230\216\346\234\235\342\210\222\357\274\255", - /* Mac (honmincho-M). */ - NULL -}; - -static const char *const gothicAliases[] = { - "gothic", /* Unix. */ - "\357\274\255\357\274\263 \343\202\264\343\202\267\343\203\203\343\202\257", - /* Windows (MS goshikku). */ - "\344\270\270\343\202\264\343\202\267\343\203\203\343\202\257\342\210\222\357\274\255", - /* Mac (goshikku-M). */ - NULL -}; - -static const char *const dingbatsAliases[] = { - "dingbats", "zapfdingbats", "itc zapfdingbats", - /* Unix. */ - /* Windows. */ - "zapf dingbats", /* Mac. */ - NULL -}; - -static const char *const *const 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 const char *const systemClass[] = { - "fixed", /* Unix. */ - /* Windows. */ - "chicago", "osaka", "sistemny", - /* Mac. */ - NULL -}; - -static const char *const serifClass[] = { - "times", "palatino", "mincho", - /* All platforms. */ - "song ti", /* Unix. */ - "ms serif", "simplified arabic", - /* Windows. */ - "latinski", /* Mac. */ - NULL -}; - -static const char *const sansClass[] = { - "helvetica", "gothic", /* All platforms. */ - /* Unix. */ - "ms sans serif", "traditional arabic", - /* Windows. */ - "bastion", /* Mac. */ - NULL -}; - -static const char *const monoClass[] = { - "courier", "gothic", /* All platforms. */ - "fangsong ti", /* Unix. */ - "simplified arabic fixed", /* Windows. */ - "monaco", "pryamoy", /* Mac. */ - NULL -}; - -static const char *const symbolClass[] = { - "symbol", "dingbats", "wingdings", NULL -}; - -static const char *const *const 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 const char *const 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(Tcl_Interp *interp, - Tk_Window tkwin, int objc, Tcl_Obj *const objv[], - TkFontAttributes *faPtr); -static void DupFontObjProc(Tcl_Obj *srcObjPtr, Tcl_Obj *dupObjPtr); -static int FieldSpecified(const char *field); -static void FreeFontObj(Tcl_Obj *objPtr); -static void FreeFontObjProc(Tcl_Obj *objPtr); -static int GetAttributeInfoObj(Tcl_Interp *interp, - const TkFontAttributes *faPtr, Tcl_Obj *objPtr); -static LayoutChunk * NewChunk(TextLayout **layoutPtrPtr, int *maxPtr, - const char *start, int numChars, int curX, - int newX, int y); -static int ParseFontNameObj(Tcl_Interp *interp, Tk_Window tkwin, - Tcl_Obj *objPtr, TkFontAttributes *faPtr); -static void RecomputeWidgets(TkWindow *winPtr); -static int SetFontFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); -static void TheWorldHasChanged(ClientData clientData); -static void UpdateDependentFonts(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. - */ - -const Tcl_ObjType tkFontObjType = { - "font", /* name */ - FreeFontObjProc, /* freeIntRepProc */ - DupFontObjProc, /* dupIntRepProc */ - NULL, /* updateStringProc */ - SetFontFromAny /* setFromAnyProc */ -}; - -/* - *--------------------------------------------------------------------------- - * - * TkFontPkgInit -- - * - * This function 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( - TkMainInfo *mainPtr) /* The application being created. */ -{ - TkFontInfo *fiPtr = 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 function 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( - TkMainInfo *mainPtr) /* The application being deleted. */ -{ - TkFontInfo *fiPtr = mainPtr->fontInfoPtr; - Tcl_HashEntry *hPtr, *searchPtr; - Tcl_HashSearch search; - int 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", - (char *) Tcl_GetHashKey(&fiPtr->fontCache, searchPtr)); -#endif - } - -#ifdef PURIFY - if (fontsLeft) { - Tcl_Panic("TkFontPkgFree: all fonts should have been freed already"); - } -#endif - - Tcl_DeleteHashTable(&fiPtr->fontCache); - - hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); - while (hPtr != NULL) { - ckfree(Tcl_GetHashValue(hPtr)); - hPtr = Tcl_NextHashEntry(&search); - } - Tcl_DeleteHashTable(&fiPtr->namedTable); - if (fiPtr->updatePending) { - Tcl_CancelIdleCall(TheWorldHasChanged, fiPtr); - } - ckfree(fiPtr); -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_FontObjCmd -- - * - * This function 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 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 = clientData; - TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - static const char *const 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 - }; - - 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, n; - const char *s; - Tk_Font tkfont; - Tcl_Obj *optPtr, *charPtr, *resultPtr; - int uniChar = 0; - const TkFontAttributes *faPtr; - TkFontAttributes fa; - - /* - * Params 0 and 1 are 'font actual'. Param 2 is the font name. 3-4 may - * be '-displayof $window' - */ - - skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - - /* - * Next parameter may be an option. - */ - - n = skip + 3; - optPtr = NULL; - charPtr = NULL; - if (n < objc) { - s = Tcl_GetString(objv[n]); - if (s[0] == '-' && s[1] != '-') { - optPtr = objv[n]; - n++; - } else { - optPtr = NULL; - } - } - - /* - * Next parameter may be '--' to mark end of options. - */ - - if (n < objc) { - if (!strcmp(Tcl_GetString(objv[n]), "--")) { - n++; - } - } - - /* - * Next parameter is the character to get font information for. - */ - - if (n < objc) { - charPtr = objv[n]; - n++; - } - - /* - * If there were fewer than 3 args, or args remain, that's an error. - */ - - if (objc < 3 || n < objc) { - Tcl_WrongNumArgs(interp, 2, objv, - "font ?-displayof window? ?option? ?--? ?char?"); - return TCL_ERROR; - } - - /* - * The 'charPtr' arg must be a single Unicode. - */ - - if (charPtr != NULL) { - const char *string = Tcl_GetString(charPtr); - int len = TkUtfToUniChar(string, &uniChar); - - if (len != charPtr->length) { - resultPtr = Tcl_NewStringObj( - "expected a single character but got \"", -1); - Tcl_AppendLimitedToObj(resultPtr, string, - -1, 40, "..."); - Tcl_AppendToObj(resultPtr, "\"", -1); - Tcl_SetObjResult(interp, resultPtr); - Tcl_SetErrorCode(interp, "TK", "VALUE", "FONT_SAMPLE", NULL); - return TCL_ERROR; - } - } - - /* - * Find the font. - */ - - tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); - if (tkfont == NULL) { - return TCL_ERROR; - } - - /* - * Determine the font attributes. - */ - - if (charPtr == NULL) { - faPtr = GetFontAttributes(tkfont); - } else { - TkpGetFontAttrsForChar(tkwin, tkfont, uniChar, &fa); - faPtr = &fa; - } - result = GetAttributeInfoObj(interp, faPtr, optPtr); - - Tk_FreeFont(tkfont); - return result; - } - case FONT_CONFIGURE: { - int result; - const char *string; - Tcl_Obj *objPtr; - NamedFont *nfPtr; - Tcl_HashEntry *namedHashPtr; - - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "fontname ?-option value ...?"); - return TCL_ERROR; - } - string = Tcl_GetString(objv[2]); - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); - nfPtr = NULL; /* lint. */ - if (namedHashPtr != NULL) { - nfPtr = Tcl_GetHashValue(namedHashPtr); - } - if ((namedHashPtr == NULL) || nfPtr->deletePending) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "named font \"%s\" doesn't exist", string)); - Tcl_SetErrorCode(interp, "TK", "LOOKUP", "FONT", string, 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 = 3, i; - const char *name; - char buf[16 + TCL_INTEGER_SPACE]; - TkFontAttributes fa; - Tcl_HashEntry *namedHashPtr; - - 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 (TkCreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) { - return TCL_ERROR; - } - Tcl_SetObjResult(interp, Tcl_NewStringObj(name, -1)); - break; - } - case FONT_DELETE: { - int i, result = TCL_OK; - const char *string; - - /* - * 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) && (result == TCL_OK); i++) { - string = Tcl_GetString(objv[i]); - result = TkDeleteNamedFont(interp, tkwin, string); - } - return result; - } - case FONT_FAMILIES: { - int 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: { - const char *string; - Tk_Font tkfont; - int length = 0, skip = 0; - - if (objc > 4) { - 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); - Tcl_SetObjResult(interp, Tcl_NewIntObj( - 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 *const 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) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "-ascent %d -descent %d -linespace %d -fixed %d", - fmPtr->ascent, fmPtr->descent, - fmPtr->ascent + fmPtr->descent, fmPtr->fixed)); - } 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_SetObjResult(interp, Tcl_NewIntObj(i)); - } - Tk_FreeFont(tkfont); - break; - } - case FONT_NAMES: { - Tcl_HashSearch search; - Tcl_HashEntry *namedHashPtr; - Tcl_Obj *resultPtr; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "names"); - return TCL_ERROR; - } - resultPtr = Tcl_NewObj(); - namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); - while (namedHashPtr != NULL) { - NamedFont *nfPtr = Tcl_GetHashValue(namedHashPtr); - - if (!nfPtr->deletePending) { - char *string = Tcl_GetHashKey(&fiPtr->namedTable, - namedHashPtr); - - Tcl_ListObjAppendElement(NULL, resultPtr, - Tcl_NewStringObj(string, -1)); - } - namedHashPtr = Tcl_NextHashEntry(&search); - } - Tcl_SetObjResult(interp, resultPtr); - 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( - 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 = 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 = Tcl_GetHashValue(cacheHashPtr); - fontPtr != NULL; fontPtr = fontPtr->nextPtr) { - if (fontPtr->namedHashPtr == namedHashPtr) { - TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa); - if (!fiPtr->updatePending) { - fiPtr->updatePending = 1; - Tcl_DoWhenIdle(TheWorldHasChanged, fiPtr); - } - } - } - cacheHashPtr = Tcl_NextHashEntry(&search); - } -} - -static void -TheWorldHasChanged( - ClientData clientData) /* Info about application's fonts. */ -{ - TkFontInfo *fiPtr = clientData; - - fiPtr->updatePending = 0; - RecomputeWidgets(fiPtr->mainPtr->winPtr); -} - -static void -RecomputeWidgets( - TkWindow *winPtr) /* Window to which command is sent. */ -{ - Tk_ClassWorldChangedProc *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); - } -} - -/* - *--------------------------------------------------------------------------- - * - * 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 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. - * - *--------------------------------------------------------------------------- - */ - -int -TkCreateNamedFont( - Tcl_Interp *interp, /* Interp for error return (can be NULL). */ - 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 = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - Tcl_HashEntry *namedHashPtr; - int isNew; - NamedFont *nfPtr; - - namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &isNew); - if (!isNew) { - nfPtr = Tcl_GetHashValue(namedHashPtr); - if (!nfPtr->deletePending) { - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "named font \"%s\" already exists", name)); - Tcl_SetErrorCode(interp, "TK", "FONT", "EXISTS", 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 = ckalloc(sizeof(NamedFont)); - nfPtr->deletePending = 0; - Tcl_SetHashValue(namedHashPtr, nfPtr); - nfPtr->fa = *faPtr; - nfPtr->refCount = 0; - nfPtr->deletePending = 0; - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * TkDeleteNamedFont -- - * - * Delete the named font. If there are still widgets using this font, - * then it isn't deleted right away. - * - *--------------------------------------------------------------------------- - */ - -int -TkDeleteNamedFont( - Tcl_Interp *interp, /* Interp for error return (can be NULL). */ - Tk_Window tkwin, /* A window associated with interp. */ - const char *name) /* Name for the new named font. */ -{ - TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - NamedFont *nfPtr; - Tcl_HashEntry *namedHashPtr; - - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, name); - if (namedHashPtr == NULL) { - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "named font \"%s\" doesn't exist", name)); - Tcl_SetErrorCode(interp, "TK", "LOOKUP", "FONT", name, NULL); - } - return TCL_ERROR; - } - nfPtr = Tcl_GetHashValue(namedHashPtr); - if (nfPtr->refCount != 0) { - nfPtr->deletePending = 1; - } else { - Tcl_DeleteHashEntry(namedHashPtr); - ckfree(nfPtr); - } - 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 function, 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( - 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. */ -{ - Tk_Font tkfont; - Tcl_Obj *strPtr; - - strPtr = Tcl_NewStringObj(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. - * - * Side effects: - * The font is added to an internal database with a reference count. For - * each call to this function, 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( - 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 = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - Tcl_HashEntry *cacheHashPtr, *namedHashPtr; - TkFont *fontPtr, *firstFontPtr, *oldFontPtr; - int isNew, descent; - NamedFont *nfPtr; - - if (objPtr->typePtr != &tkFontObjType - || objPtr->internalRep.twoPtrValue.ptr2 != fiPtr) { - SetFontFromAny(interp, objPtr); - } - - oldFontPtr = 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. - */ - - FreeFontObj(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. - */ - - isNew = 0; - if (oldFontPtr != NULL) { - cacheHashPtr = oldFontPtr->cacheHashPtr; - FreeFontObj(objPtr); - } else { - cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, - Tcl_GetString(objPtr), &isNew); - } - firstFontPtr = 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 = fontPtr; - objPtr->internalRep.twoPtrValue.ptr2 = fiPtr; - 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 = 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 (isNew) { - Tcl_DeleteHashEntry(cacheHashPtr); - } - Tcl_DecrRefCount(dupObjPtr); - return NULL; - } - Tcl_DecrRefCount(dupObjPtr); - - /* - * String contained the attributes inline. - */ - - fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa); - } - } - - /* - * Detect the system font engine going wrong and fail more gracefully. - */ - - if (fontPtr == NULL) { - if (isNew) { - Tcl_DeleteHashEntry(cacheHashPtr); - } - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "failed to allocate font due to internal system font engine" - " problem", -1)); - Tcl_SetErrorCode(interp, "TK", "FONT", "INTERNAL_PROBLEM", NULL); - return NULL; - } - - 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 = (int) (TkFontGetPixels(tkwin, fontPtr->fa.size) / 10 + 0.5); - 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 = fontPtr; - objPtr->internalRep.twoPtrValue.ptr2 = fiPtr; - 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( - 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 - || objPtr->internalRep.twoPtrValue.ptr2 != fiPtr) { - SetFontFromAny(NULL, objPtr); - } - - fontPtr = 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. - */ - - FreeFontObj(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; - FreeFontObj(objPtr); - } else { - hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr)); - } - if (hashPtr != NULL) { - for (fontPtr = Tcl_GetHashValue(hashPtr); fontPtr != NULL; - fontPtr = fontPtr->nextPtr) { - if (Tk_Screen(tkwin) == fontPtr->screen) { - fontPtr->objRefCount++; - objPtr->internalRep.twoPtrValue.ptr1 = fontPtr; - objPtr->internalRep.twoPtrValue.ptr2 = fiPtr; - return (Tk_Font) fontPtr; - } - } - } - - Tcl_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( - Tcl_Interp *interp, /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr) /* The object to convert. */ -{ - const 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; - objPtr->internalRep.twoPtrValue.ptr2 = 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( - Tk_Font tkfont) /* Font whose name is desired. */ -{ - TkFont *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( - Tk_Font tkfont) /* Font to be released. */ -{ - TkFont *fontPtr = (TkFont *) tkfont, *prevPtr; - NamedFont *nfPtr; - - if (fontPtr == NULL) { - return; - } - 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 = Tcl_GetHashValue(fontPtr->namedHashPtr); - nfPtr->refCount--; - if ((nfPtr->refCount == 0) && nfPtr->deletePending) { - Tcl_DeleteHashEntry(fontPtr->namedHashPtr); - ckfree(nfPtr); - } - } - - prevPtr = 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(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( - 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, FreeFontObj -- - * - * 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( - Tcl_Obj *objPtr) /* The object we are releasing. */ -{ - FreeFontObj(objPtr); - objPtr->typePtr = NULL; -} - -static void -FreeFontObj( - Tcl_Obj *objPtr) /* The object we are releasing. */ -{ - TkFont *fontPtr = objPtr->internalRep.twoPtrValue.ptr1; - - if (fontPtr != NULL) { - fontPtr->objRefCount--; - if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) { - ckfree(fontPtr); - } - objPtr->internalRep.twoPtrValue.ptr1 = NULL; - objPtr->internalRep.twoPtrValue.ptr2 = 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( - Tcl_Obj *srcObjPtr, /* The object we are copying from. */ - Tcl_Obj *dupObjPtr) /* The object we are copying to. */ -{ - TkFont *fontPtr = srcObjPtr->internalRep.twoPtrValue.ptr1; - - dupObjPtr->typePtr = srcObjPtr->typePtr; - dupObjPtr->internalRep.twoPtrValue.ptr1 = fontPtr; - dupObjPtr->internalRep.twoPtrValue.ptr2 - = srcObjPtr->internalRep.twoPtrValue.ptr2; - - 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 function would go away if the XGCValues structure were - * replaced with a TkGCValues structure. - * - * Results: - * As above. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -Font -Tk_FontId( - Tk_Font tkfont) /* Font that is going to be selected into - * GC. */ -{ - TkFont *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( - 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 = (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( - 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 = (TkFont *) tkfont; - Tk_Uid family, weightString, slantString; - char *src, *dest; - int upper, len; - - len = Tcl_DStringLength(dsPtr); - - /* - * 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 { - int 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 != '\0'; ) { - while (isspace(UCHAR(*src))) { /* INTL: ISO space */ - src++; - upper = 1; - } - src += TkUtfToUniChar(src, &ch); - if (ch <= 0xffff) { - if (upper) { - ch = Tcl_UniCharToUpper(ch); - upper = 0; - } else { - ch = Tcl_UniCharToLower(ch); - } - } else { - upper = 0; - } - dest += TkUniCharToUtf(ch, dest); - } - *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) { - /* Do nothing */ - } 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 (int)(fontPtr->fa.size + 0.5); -} - -/* - *--------------------------------------------------------------------------- - * - * 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( - 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, TkUnderlineCharsInContext -- - * - * These procedures draw an underline for a given range of characters in - * a given string. They don't draw the characters (which are assumed to - * have been displayed previously); they just draw the underline. These - * procedures 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 *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, int 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. */ -{ - TkUnderlineCharsInContext(display, drawable, gc, tkfont, string, - lastByte, x, y, firstByte, lastByte); -} - -void -TkUnderlineCharsInContext( - 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 numBytes, /* Number of bytes in string. */ - int x, int y, /* Coordinates at which the first character of - * the whole string would be drawn. */ - int firstByte, /* Index of first byte of first character. */ - int lastByte) /* Index of first byte after the last - * character. */ -{ - TkFont *fontPtr = (TkFont *) tkfont; - int startX, endX; - - TkpMeasureCharsInContext(tkfont, string, numBytes, 0, firstByte, -1, 0, - &startX); - TkpMeasureCharsInContext(tkfont, string, numBytes, 0, lastByte, -1, 0, - &endX); - - XFillRectangle(display, drawable, gc, x + startX, - y + fontPtr->underlinePos, (unsigned) (endX - startX), - (unsigned) 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() function to - * display the text quickly (without remeasuring it). - * - * This function 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( - 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 = (TkFont *) tkfont; - const char *start, *end, *special; - int n, y, bytesThisChunk, maxChunks, curLine, layoutHeight; - int baseline, height, curX, newX, maxWidth, *lineLengths; - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - const TkFontMetrics *fmPtr; - Tcl_DString lineBuffer; - - Tcl_DStringInit(&lineBuffer); - - 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 = 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++; - curX = newX; - flags &= ~TK_AT_LEAST_ONE; - if ((start < end) && - ((wrapLength <= 0) || (newX <= wrapLength))) { - /* - * More chars can still fit on this line. - */ - - 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 "Hello\n" are the same height. - */ - - if ((layoutPtr->numChunks > 0) && !(flags & TK_IGNORE_NEWLINES)) { - 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 functions 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 function 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( - Tk_TextLayout textLayout) /* The text layout to be released. */ -{ - TextLayout *layoutPtr = (TextLayout *) textLayout; - - if (layoutPtr != NULL) { - ckfree(layoutPtr); - } -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_DrawTextLayout -- - * - * Use the information in the Tk_TextLayout token to display a - * multi-line, justified string of text. - * - * This function 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 *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, int 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 = (TextLayout *) layout; - int i, numDisplayChars, drawX; - const char *firstByte, *lastByte; - LayoutChunk *chunkPtr; - - 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++; - } -} - -void -TkDrawAngledTextLayout( - 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, int y, /* Upper-left hand corner of rectangle in - * which to draw (pixels). */ - double angle, - 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 = (TextLayout *) layout; - int i, numDisplayChars, drawX; - const char *firstByte, *lastByte; - LayoutChunk *chunkPtr; - double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); - - 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)) { - double dx, dy; - - 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); - dx = cosA * (chunkPtr->x + drawX) + sinA * (chunkPtr->y); - dy = -sinA * (chunkPtr->x + drawX) + cosA * (chunkPtr->y); - if (angle == 0.0) { - Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, - firstByte, lastByte - firstByte, - (int)(x + dx), (int)(y + dy)); - } else { - TkDrawAngledChars(display, drawable, gc, layoutPtr->tkfont, - firstByte, lastByte - firstByte, x+dx, y+dy, angle); - } - } - 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 function does not draw the text, - * just the underline. - * - * This function 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 *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, int 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. */ -{ - int xx, yy, width, height; - - if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0) - && (width != 0)) { - TextLayout *layoutPtr = (TextLayout *) layout; - TkFont *fontPtr = (TkFont *) layoutPtr->tkfont; - - XFillRectangle(display, drawable, gc, x + xx, - y + yy + fontPtr->fm.ascent + fontPtr->underlinePos, - (unsigned) width, (unsigned) fontPtr->underlineHeight); - } -} - -void -TkUnderlineAngledTextLayout( - 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, int y, /* Upper-left hand corner of rectangle in - * which to draw (pixels). */ - double angle, - int underline) /* Index of the single character to underline, - * or -1 for no underline. */ -{ - int xx, yy, width, height; - - if (angle == 0.0) { - Tk_UnderlineTextLayout(display, drawable, gc, layout, x,y, underline); - return; - } - - if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0) - && (width != 0)) { - TextLayout *layoutPtr = (TextLayout *) layout; - TkFont *fontPtr = (TkFont *) layoutPtr->tkfont; - double sinA = sin(angle*PI/180), cosA = cos(angle*PI/180); - double dy = yy + fontPtr->fm.ascent + fontPtr->underlinePos; - XPoint points[5]; - - /* - * Note that we're careful to only round a double value once, which - * minimizes roundoff errors. - */ - - points[0].x = x + ROUND16(xx*cosA + dy*sinA); - points[0].y = y + ROUND16(dy*cosA - xx*sinA); - points[1].x = x + ROUND16(xx*cosA + dy*sinA + width*cosA); - points[1].y = y + ROUND16(dy*cosA - xx*sinA - width*sinA); - if (fontPtr->underlineHeight == 1) { - /* - * Thin underlines look better when rotated when drawn as a line - * rather than a rectangle; the rasterizer copes better. - */ - - XDrawLines(display, drawable, gc, points, 2, CoordModeOrigin); - } else { - points[2].x = x + ROUND16(xx*cosA + dy*sinA + width*cosA - + fontPtr->underlineHeight*sinA); - points[2].y = y + ROUND16(dy*cosA - xx*sinA - width*sinA - + fontPtr->underlineHeight*cosA); - points[3].x = x + ROUND16(xx*cosA + dy*sinA - + fontPtr->underlineHeight*sinA); - points[3].y = y + ROUND16(dy*cosA - xx*sinA - + fontPtr->underlineHeight*cosA); - points[4].x = points[0].x; - points[4].y = points[0].y; - XFillPolygon(display, drawable, gc, points, 5, Complex, - CoordModeOrigin); - XDrawLines(display, drawable, gc, points, 5, CoordModeOrigin); - } - } -} - -/* - *--------------------------------------------------------------------------- - * - * 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( - Tk_TextLayout layout, /* Layout information, from a previous call to - * Tk_ComputeTextLayout(). */ - int x, int y) /* Coordinates of point to check, with respect - * to the upper-left corner of the text - * layout. */ -{ - TextLayout *layoutPtr = (TextLayout *) layout; - 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. - */ - - 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( - 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, int *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, int *heightPtr) - /* Filled with the width and height of the - * bounding box for the character specified by - * index, if non-NULL. */ -{ - TextLayout *layoutPtr = (TextLayout *) layout; - LayoutChunk *chunkPtr; - int i, x = 0, w; - Tk_Font tkfont; - TkFont *fontPtr; - const char *end; - - if (index < 0) { - return 0; - } - - 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) { - return 0; - } - - /* - * Special case to get location just past last char in layout. - */ - - chunkPtr--; - x = chunkPtr->x + chunkPtr->totalWidth; - w = 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( - Tk_TextLayout layout, /* Layout information, from a previous call - * to Tk_ComputeTextLayout(). */ - int x, int 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; - TextLayout *layoutPtr = (TextLayout *) layout; - LayoutChunk *chunkPtr; - TkFont *fontPtr; - - 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( - Tk_TextLayout layout, /* Layout information, from a previous call to - * Tk_ComputeTextLayout(). */ - int x, int 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, int height) /* The width and height of the above - * rectangular area, in pixels. */ -{ - int result, i, x1, y1, x2, y2; - TextLayout *layoutPtr = (TextLayout *) layout; - 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. - */ - - 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') || (chunkPtr->numBytes == 0)) { - /* - * Newline characters and empty chunks 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; -} - -/* - *--------------------------------------------------------------------------- - * - * TkIntersectAngledTextLayout -- - * - * Determines whether a text layout that has been turned by an angle - * about its top-left coordinae 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. - * - *--------------------------------------------------------------------------- - */ - -static inline int -PointInQuadrilateral( - double qx[], - double qy[], - double x, - double y) -{ - int i; - - for (i=0 ; i<4 ; i++) { - double sideDX = qx[(i+1)%4] - qx[i]; - double sideDY = qy[(i+1)%4] - qy[i]; - double dx = x - qx[i]; - double dy = y - qy[i]; - - if (sideDX*dy < sideDY*dx) { - return 0; - } - } - return 1; -} - -static inline int -SidesIntersect( - double ax1, double ay1, double ax2, double ay2, - double bx1, double by1, double bx2, double by2) -{ -#if 0 -/* http://www.freelunchdesign.com/cgi-bin/codwiki.pl?DiscussionTopics/CollideMeUpBaby */ - - double a1, b1, c1, a2, b2, c2, r1, r2, r3, r4, denom; - - a1 = ay2 - ay1; - b1 = ax1 - ax2; - c1 = (ax2 * ay1) - (ax1 * ay2); - r3 = (a1 * bx1) + (b1 * by1) + c1; - r4 = (a1 * bx2) + (b1 * by2) + c1; - if ((r3 != 0.0) && (r4 != 0.0) && (r3*r4 > 0.0)) { - return 0; - } - - a2 = by2 - by1; - b2 = bx1 - bx2; - c2 = (bx2 * by1) - (bx1 * by2); - r1 = (a2 * ax1) + (b2 * ay1) + c2; - r2 = (a2 * ax2) + (b2 * ay2) + c2; - if ((r1 != 0.0) && (r2 != 0.0) && (r1*r2 > 0.0)) { - return 0; - } - - denom = (a1 * b2) - (a2 * b1); - return (denom != 0.0); -#else - /* - * A more efficient version. Two line segments intersect if, when seen - * from the perspective of one line, the two endpoints of the other - * segment lie on opposite sides of the line, and vice versa. "Lie on - * opposite sides" is computed by taking the cross products and seeing if - * they are of opposite signs. - */ - - double dx, dy, dx1, dy1; - - dx = ax2 - ax1; - dy = ay2 - ay1; - dx1 = bx1 - ax1; - dy1 = by1 - ay1; - if ((dx*dy1-dy*dx1 > 0.0) == (dx*(by2-ay1)-dy*(bx2-ax1) > 0.0)) { - return 0; - } - dx = bx2 - bx1; - dy = by2 - by1; - if ((dy*dx1-dx*dy1 > 0.0) == (dx*(ay2-by1)-dy*(ax2-bx1) > 0.0)) { - return 0; - } - return 1; -#endif -} - -int -TkIntersectAngledTextLayout( - Tk_TextLayout layout, /* Layout information, from a previous call to - * Tk_ComputeTextLayout(). */ - int x, int 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, int height, /* The width and height of the above - * rectangular area, in pixels. */ - double angle) -{ - int i, x1, y1, x2, y2; - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - TkFont *fontPtr; - double c = cos(angle * PI/180.0), s = sin(angle * PI/180.0); - double rx[4], ry[4]; - - if (angle == 0.0) { - return Tk_IntersectTextLayout(layout, x, y, width, height); - } - - /* - * Compute the coordinates of the rectangle, rotated into text layout - * space. - */ - - rx[0] = x*c - y*s; - ry[0] = y*c + x*s; - rx[1] = (x+width)*c - y*s; - ry[1] = y*c + (x+width)*s; - rx[2] = (x+width)*c - (y+height)*s; - ry[2] = (y+height)*c + (x+width)*s; - rx[3] = x*c - (y+height)*s; - ry[3] = (y+height)*c + x*s; - - /* - * Want to know if all chunks are inside the rectangle, or if there is any - * overlap. First, we check to see if all chunks are inside; if and only - * if they are, we're in the "inside" case. - */ - - layoutPtr = (TextLayout *) layout; - chunkPtr = layoutPtr->chunks; - fontPtr = (TkFont *) layoutPtr->tkfont; - - for (i=0 ; i<layoutPtr->numChunks ; i++,chunkPtr++) { - if (chunkPtr->start[0] == '\n') { - /* - * Newline characters are not counted when computing area - * intersection (but tab characters would still be considered). - */ - - continue; - } - - x1 = chunkPtr->x; - y1 = chunkPtr->y - fontPtr->fm.ascent; - x2 = chunkPtr->x + chunkPtr->displayWidth; - y2 = chunkPtr->y + fontPtr->fm.descent; - if ( !PointInQuadrilateral(rx, ry, x1, y1) || - !PointInQuadrilateral(rx, ry, x2, y1) || - !PointInQuadrilateral(rx, ry, x2, y2) || - !PointInQuadrilateral(rx, ry, x1, y2)) { - goto notInside; - } - } - return 1; - - /* - * Next, check to see if all the points of the rectangle are inside a - * single chunk; if they are, we're in an "overlap" case. - */ - - notInside: - chunkPtr = layoutPtr->chunks; - - for (i=0 ; i<layoutPtr->numChunks ; i++,chunkPtr++) { - double cx[4], cy[4]; - - if (chunkPtr->start[0] == '\n') { - /* - * Newline characters are not counted when computing area - * intersection (but tab characters would still be considered). - */ - - continue; - } - - cx[0] = cx[3] = chunkPtr->x; - cy[0] = cy[1] = chunkPtr->y - fontPtr->fm.ascent; - cx[1] = cx[2] = chunkPtr->x + chunkPtr->displayWidth; - cy[2] = cy[3] = chunkPtr->y + fontPtr->fm.descent; - if ( !PointInQuadrilateral(cx, cy, rx[0], ry[0]) || - !PointInQuadrilateral(cx, cy, rx[1], ry[1]) || - !PointInQuadrilateral(cx, cy, rx[2], ry[2]) || - !PointInQuadrilateral(cx, cy, rx[3], ry[3])) { - goto notReverseInside; - } - } - return 0; - - /* - * If we're overlapping now, we must be partially in and out of at least - * one chunk. If that is the case, there must be one line segment of the - * rectangle that is touching or crossing a line segment of a chunk. - */ - - notReverseInside: - chunkPtr = layoutPtr->chunks; - - for (i=0 ; i<layoutPtr->numChunks ; i++,chunkPtr++) { - int j; - - if (chunkPtr->start[0] == '\n') { - /* - * Newline characters are not counted when computing area - * intersection (but tab characters would still be considered). - */ - - continue; - } - - x1 = chunkPtr->x; - y1 = chunkPtr->y - fontPtr->fm.ascent; - x2 = chunkPtr->x + chunkPtr->displayWidth; - y2 = chunkPtr->y + fontPtr->fm.descent; - - for (j=0 ; j<4 ; j++) { - int k = (j+1) % 4; - - if ( SidesIntersect(rx[j],ry[j], rx[k],ry[k], x1,y1, x2,y1) || - SidesIntersect(rx[j],ry[j], rx[k],ry[k], x2,y1, x2,y2) || - SidesIntersect(rx[j],ry[j], rx[k],ry[k], x2,y2, x1,y2) || - SidesIntersect(rx[j],ry[j], rx[k],ry[k], x1,y2, x1,y1)) { - return 0; - } - } - } - - /* - * They must be wholly non-overlapping. - */ - - return -1; -} - -/* - *--------------------------------------------------------------------------- - * - * 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( - Tcl_Interp *interp, /* Filled with Postscript code. */ - Tk_TextLayout layout) /* The layout to be rendered. */ -{ - TextLayout *layoutPtr = (TextLayout *) layout; - LayoutChunk *chunkPtr = layoutPtr->chunks; - int baseline = chunkPtr->y; - Tcl_Obj *psObj = Tcl_NewObj(); - int i, j, len; - const char *p, *glyphname; - char uindex[5], c, *ps; - int ch; - - Tcl_AppendToObj(psObj, "[(", -1); - for (i = 0; i < layoutPtr->numChunks; i++, chunkPtr++) { - if (baseline != chunkPtr->y) { - Tcl_AppendToObj(psObj, ")]\n[(", -1); - baseline = chunkPtr->y; - } - if (chunkPtr->numDisplayChars <= 0) { - if (chunkPtr->start[0] == '\t') { - Tcl_AppendToObj(psObj, "\\t", -1); - } - continue; - } - - for (p=chunkPtr->start, j=0; j<chunkPtr->numDisplayChars; j++) { - /* - * INTL: We only handle symbols that have an encoding as a glyph - * from the standard set defined by Adobe. The rest get punted. - * Eventually this should be revised to handle more sophsticiated - * international postscript fonts. - */ - - p += TkUtfToUniChar(p, &ch); - if ((ch == '(') || (ch == ')') || (ch == '\\') || (ch < 0x20)) { - /* - * 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. - */ - - Tcl_AppendPrintfToObj(psObj, "\\%03o", ch); - continue; - } else if (ch <= 0x7f) { - /* - * Normal ASCII character. - */ - - c = (char) ch; - Tcl_AppendToObj(psObj, &c, 1); - continue; - } - - /* - * This character doesn't belong to the ASCII character set, so we - * use the full glyph name. - */ - - if (ch > 0xffff) { - goto noMapping; - } - sprintf(uindex, "%04X", ch); /* endianness? */ - glyphname = Tcl_GetVar2(interp, "::tk::psglyphs", uindex, 0); - if (glyphname) { - ps = Tcl_GetStringFromObj(psObj, &len); - if (ps[len-1] == '(') { - /* - * In-place edit. Ewww! - */ - - ps[len-1] = '/'; - } else { - Tcl_AppendToObj(psObj, ")/", -1); - } - Tcl_AppendToObj(psObj, glyphname, -1); - Tcl_AppendToObj(psObj, "(", -1); - } else { - /* - * No known mapping for the character into the space of - * PostScript glyphs. Ignore it. :-( - */ -noMapping: ; - -#ifdef TK_DEBUG_POSTSCRIPT_OUTPUT - fprintf(stderr, "Warning: no mapping to PostScript " - "glyphs for \\u%04x\n", ch); -#endif - } - } - } - Tcl_AppendToObj(psObj, ")]\n", -1); - Tcl_AppendObjToObj(Tcl_GetObjResult(interp), psObj); - Tcl_DecrRefCount(psObj); -} - -/* - *--------------------------------------------------------------------------- - * - * 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( - 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 *optionPtr, *valuePtr; - const char *value; - - for (i = 0; i < objc; i += 2) { - optionPtr = objv[i]; - - if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1, - &index) != TCL_OK) { - return TCL_ERROR; - } - if ((i+2 >= objc) && (objc & 1)) { - /* - * This test occurs after Tcl_GetIndexFromObj() so that "font - * create xyz -xyz" will return the error message that "-xyz" is a - * bad option, rather than that the value for "-xyz" is missing. - */ - - if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "value for \"%s\" option missing", - Tcl_GetString(optionPtr))); - Tcl_SetErrorCode(interp, "TK", "FONT", "NO_ATTRIBUTE", NULL); - } - return TCL_ERROR; - } - valuePtr = objv[i + 1]; - - switch (index) { - case FONT_FAMILY: - value = Tcl_GetString(valuePtr); - faPtr->family = Tk_GetUid(value); - break; - case FONT_SIZE: - if (Tcl_GetIntFromObj(interp, valuePtr, &n) != TCL_OK) { - return TCL_ERROR; - } - faPtr->size = (double)n; - break; - case FONT_WEIGHT: - n = TkFindStateNumObj(interp, optionPtr, weightMap, valuePtr); - if (n == TK_FW_UNKNOWN) { - return TCL_ERROR; - } - faPtr->weight = n; - break; - case FONT_SLANT: - n = TkFindStateNumObj(interp, optionPtr, slantMap, valuePtr); - if (n == TK_FS_UNKNOWN) { - return TCL_ERROR; - } - faPtr->slant = n; - break; - case FONT_UNDERLINE: - if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) { - return TCL_ERROR; - } - faPtr->underline = n; - break; - case FONT_OVERSTRIKE: - if (Tcl_GetBooleanFromObj(interp, valuePtr, &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: - * The return value is TCL_OK if the objPtr was non-NULL and specified a - * valid font attribute, TCL_ERROR otherwise. If TCL_OK is returned, the - * 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. If TCL_ERROR is - * returned, the interp's result is set to an error message describing - * that the objPtr did not refer to a valid option. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -static int -GetAttributeInfoObj( - 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; - const char *str; - Tcl_Obj *valuePtr, *resultPtr = NULL; - - start = 0; - end = FONT_NUMFIELDS; - if (objPtr != NULL) { - if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", TCL_EXACT, - &index) != TCL_OK) { - return TCL_ERROR; - } - start = index; - end = index + 1; - } - - valuePtr = NULL; - if (objPtr == NULL) { - resultPtr = Tcl_NewObj(); - } - for (i = start; i < end; i++) { - switch (i) { - case FONT_FAMILY: - str = faPtr->family; - valuePtr = Tcl_NewStringObj(str, ((str == NULL) ? 0 : -1)); - break; - - case FONT_SIZE: - if (faPtr->size >= 0.0) { - valuePtr = Tcl_NewIntObj((int)(faPtr->size + 0.5)); - } else { - valuePtr = Tcl_NewIntObj(-(int)(-faPtr->size + 0.5)); - } - break; - - case FONT_WEIGHT: - str = TkFindStateString(weightMap, faPtr->weight); - valuePtr = Tcl_NewStringObj(str, -1); - break; - - case FONT_SLANT: - str = TkFindStateString(slantMap, faPtr->slant); - valuePtr = Tcl_NewStringObj(str, -1); - break; - - case FONT_UNDERLINE: - valuePtr = Tcl_NewBooleanObj(faPtr->underline); - break; - - case FONT_OVERSTRIKE: - valuePtr = Tcl_NewBooleanObj(faPtr->overstrike); - break; - } - if (objPtr != NULL) { - Tcl_SetObjResult(interp, valuePtr); - return TCL_OK; - } - Tcl_ListObjAppendElement(NULL, resultPtr, - Tcl_NewStringObj(fontOpt[i], -1)); - Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr); - } - Tcl_SetObjResult(interp, resultPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * 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] [style1 [style2 ...]" - * "-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( - 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) /* Filled with attributes parsed from font - * name. Any attributes that were not - * specified in font name are filled with - * default values. */ -{ - char *dash; - int objc, result, i, n; - Tcl_Obj **objv; - const char *string; - - TkInitFontAttributes(faPtr); - - string = Tcl_GetString(objPtr); - 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]))) { /* INTL: ISO space */ - goto xlfd; - } - - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - - return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr); - } - - if (*string == '*') { - /* - * This is appears to be an XLFD. Under Unix, all valid XLFDs were - * already handled by TkpGetNativeFont. If we are here, either we have - * something that initially looks like an XLFD but isn't or we have - * encountered an XLFD on Windows or Mac. - */ - - xlfd: - result = TkFontParseXLFD(string, faPtr, NULL); - if (result == TCL_OK) { - return TCL_OK; - } - - /* - * If the string failed to parse but was considered to be a XLFD - * then it may be a "-option value" string with a hyphenated family - * name as per bug 2791352 - */ - - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - - if (ConfigAttributesObj(interp, tkwin, objc, objv, faPtr) == TCL_OK) { - return TCL_OK; - } - } - - /* - * Wasn't an XLFD or "-option value" string. Try it as a "font size style" - * list. - */ - - if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) - || (objc < 1)) { - if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "font \"%s\" doesn't exist", string)); - Tcl_SetErrorCode(interp, "TK", "LOOKUP", "FONT", string, NULL); - } - return TCL_ERROR; - } - - faPtr->family = Tk_GetUid(Tcl_GetString(objv[0])); - if (objc > 1) { - if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) { - return TCL_ERROR; - } - faPtr->size = (double)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++) { - n = TkFindStateNumObj(NULL, NULL, weightMap, objv[i]); - if (n != TK_FW_UNKNOWN) { - faPtr->weight = n; - continue; - } - n = TkFindStateNumObj(NULL, NULL, slantMap, objv[i]); - if (n != TK_FS_UNKNOWN) { - faPtr->slant = n; - continue; - } - n = TkFindStateNumObj(NULL, NULL, underlineMap, objv[i]); - if (n != 0) { - faPtr->underline = n; - continue; - } - n = TkFindStateNumObj(NULL, NULL, overstrikeMap, objv[i]); - if (n != 0) { - faPtr->overstrike = n; - continue; - } - - /* - * Unknown style. - */ - - if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "unknown font style \"%s\"", Tcl_GetString(objv[i]))); - Tcl_SetErrorCode(interp, "TK", "LOOKUP", "FONT_STYLE", - Tcl_GetString(objv[i]), NULL); - } - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * 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( - TextLayout **layoutPtrPtr, - int *maxPtr, - const char *start, - int numBytes, - int curX, - int newX, - int y) -{ - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - int maxChunks, numChars; - size_t s; - - layoutPtr = *layoutPtrPtr; - maxChunks = *maxPtr; - if (layoutPtr->numChunks == maxChunks) { - maxChunks *= 2; - s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk)); - layoutPtr = ckrealloc(layoutPtr, s); - - *layoutPtrPtr = layoutPtr; - *maxPtr = maxChunks; - } - numChars = Tcl_NumUtfChars(start, numBytes); - chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks]; - chunkPtr->start = start; - chunkPtr->numBytes = numBytes; - chunkPtr->numChars = numChars; - chunkPtr->numDisplayChars = numChars; - chunkPtr->x = curX; - chunkPtr->y = y; - chunkPtr->totalWidth = newX - curX; - chunkPtr->displayWidth = newX - curX; - layoutPtr->numChunks++; - - return chunkPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * TkFontParseXLFD -- - * - * 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 -TkFontParseXLFD( - const char *string, /* Parseable font description string. */ - TkFontAttributes *faPtr, /* Filled with attributes parsed from font - * name. Any attributes that were not - * specified in font name are filled with - * default values. */ - TkXLFDAttributes *xaPtr) /* Filled with X-specific attributes parsed - * from font name. Any attributes that were - * not specified in font name are filled with - * default values. May be NULL if such - * information is not desired. */ -{ - char *src; - const char *str; - int i, j; - char *field[XLFD_NUMFIELDS + 2]; - Tcl_DString ds; - TkXLFDAttributes xa; - - if (xaPtr == NULL) { - xaPtr = &xa; - } - TkInitFontAttributes(faPtr); - TkInitXLFDAttributes(xaPtr); - - memset(field, '\0', sizeof(field)); - - str = string; - if (*str == '-') { - str++; - } - - Tcl_DStringInit(&ds); - Tcl_DStringAppend(&ds, str, -1); - src = Tcl_DStringValue(&ds); - - field[0] = src; - for (i = 0; *src != '\0'; src++) { - if (!(*src & 0x80) - && Tcl_UniCharIsUpper(UCHAR(*src))) { - *src = (char) Tcl_UniCharToLower(UCHAR(*src)); - } - if (*src == '-') { - i++; - if (i == XLFD_NUMFIELDS) { - continue; - } - *src = '\0'; - field[i] = src + 1; - if (i > XLFD_NUMFIELDS) { - break; - } - } - } - - /* - * 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 right 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 (as a native font name), but gives a syntax error under Windows (as a - * parsed set of attributes)". - */ - - 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])) { - faPtr->family = Tk_GetUid(field[XLFD_FAMILY]); - } - if (FieldSpecified(field[XLFD_WEIGHT])) { - faPtr->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) { - faPtr->slant = TK_FS_ROMAN; - } else { - faPtr->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 for - * historical compatibility. - */ - - faPtr->size = 12.0; - - 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. - */ - - faPtr->size = atof(field[XLFD_POINT_SIZE] + 1); - } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE], - &i) == TCL_OK) { - faPtr->size = i/10.0; - } 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. - */ - - faPtr->size = atof(field[XLFD_PIXEL_SIZE] + 1); - } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE], - &i) == TCL_OK) { - faPtr->size = (double)i; - } else { - return TCL_ERROR; - } - } - - faPtr->size = -faPtr->size; - - /* XLFD_RESOLUTION_X ignored. */ - - /* XLFD_RESOLUTION_Y ignored. */ - - /* XLFD_SPACING ignored. */ - - /* XLFD_AVERAGE_WIDTH ignored. */ - - if (FieldSpecified(field[XLFD_CHARSET])) { - xaPtr->charset = Tk_GetUid(field[XLFD_CHARSET]); - } else { - xaPtr->charset = Tk_GetUid("iso8859-1"); - } - 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( - 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 != '?'); -} - -/* - *--------------------------------------------------------------------------- - * - * TkFontGetPixels -- - * - * Given a font size specification (as described in the TkFontAttributes - * structure) return the number of pixels it represents. - * - * Results: - * As above. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -double -TkFontGetPixels( - Tk_Window tkwin, /* For point->pixel conversion factor. */ - double size) /* Font size. */ -{ - double d; - - if (size <= 0.0) { - return -size; - } - - d = size * 25.4 / 72.0; - d *= WidthOfScreen(Tk_Screen(tkwin)); - d /= WidthMMOfScreen(Tk_Screen(tkwin)); - return d; -} - -/* - *--------------------------------------------------------------------------- - * - * TkFontGetPoints -- - * - * Given a font size specification (as described in the TkFontAttributes - * structure) return the number of points it represents. - * - * Results: - * As above. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -double -TkFontGetPoints( - Tk_Window tkwin, /* For pixel->point conversion factor. */ - double size) /* Font size. */ -{ - double d; - - if (size >= 0.0) { - return size; - } - - d = -size * 72.0 / 25.4; - d *= WidthMMOfScreen(Tk_Screen(tkwin)); - d /= WidthOfScreen(Tk_Screen(tkwin)); - return d; -} - -/* - *------------------------------------------------------------------------- - * - * TkFontGetAliasList -- - * - * Given a font name, find the list of all aliases for that font name. - * One of the names in this list will probably be the name that this - * platform expects when asking for the font. - * - * Results: - * As above. The return value is NULL if the font name has no aliases. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -const char *const * -TkFontGetAliasList( - const char *faceName) /* Font name to test for aliases. */ -{ - int i, j; - - for (i = 0; fontAliases[i] != NULL; i++) { - for (j = 0; fontAliases[i][j] != NULL; j++) { - if (strcasecmp(faceName, fontAliases[i][j]) == 0) { - return fontAliases[i]; - } - } - } - return NULL; -} - -/* - *------------------------------------------------------------------------- - * - * TkFontGetFallbacks -- - * - * Get the list of font fallbacks that the platform-specific code can use - * to try to find the closest matching font the name requested. - * - * Results: - * As above. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -const char *const *const * -TkFontGetFallbacks(void) -{ - return fontFallbacks; -} - -/* - *------------------------------------------------------------------------- - * - * TkFontGetGlobalClass -- - * - * Get the list of fonts to try if the requested font name does not - * exist and no fallbacks for that font name could be used either. - * The names in this list are considered preferred over all the other - * font names in the system when looking for a last-ditch fallback. - * - * Results: - * As above. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -const char *const * -TkFontGetGlobalClass(void) -{ - return globalFontClass; -} - -/* - *------------------------------------------------------------------------- - * - * TkFontGetSymbolClass -- - * - * Get the list of fonts that are symbolic; used if the operating system - * cannot apriori identify symbolic fonts on its own. - * - * Results: - * As above. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -const char *const * -TkFontGetSymbolClass(void) -{ - return symbolClass; -} - -/* - *---------------------------------------------------------------------- - * - * TkDebugFont -- - * - * This function returns debugging information about a font. - * - * Results: - * The return value is a list with one sublist for each TkFont - * corresponding to "name". Each sublist has two elements that contain - * the resourceRefCount and objRefCount fields from the TkFont structure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tcl_Obj * -TkDebugFont( - Tk_Window tkwin, /* The window in which the font will be used - * (not currently used). */ - const char *name) /* Name of the desired color. */ -{ - TkFont *fontPtr; - Tcl_HashEntry *hashPtr; - Tcl_Obj *resultPtr, *objPtr; - - resultPtr = Tcl_NewObj(); - hashPtr = Tcl_FindHashEntry( - &((TkWindow *) tkwin)->mainPtr->fontInfoPtr->fontCache, name); - if (hashPtr != NULL) { - fontPtr = Tcl_GetHashValue(hashPtr); - if (fontPtr == NULL) { - Tcl_Panic("TkDebugFont found empty hash table entry"); - } - for ( ; (fontPtr != NULL); fontPtr = fontPtr->nextPtr) { - objPtr = Tcl_NewObj(); - Tcl_ListObjAppendElement(NULL, objPtr, - Tcl_NewIntObj(fontPtr->resourceRefCount)); - Tcl_ListObjAppendElement(NULL, objPtr, - Tcl_NewIntObj(fontPtr->objRefCount)); - Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); - } - } - return resultPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkFontGetFirstTextLayout -- - * - * This function returns the first chunk of a Tk_TextLayout, i.e. until - * the first font change on the first line (or the whole first line if - * there is no such font change). - * - * Results: - * The return value is the byte length of the chunk, the chunk itself is - * copied into dst and its Tk_Font into font. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkFontGetFirstTextLayout( - Tk_TextLayout layout, /* Layout information, from a previous call to - * Tk_ComputeTextLayout(). */ - Tk_Font *font, - char *dst) -{ - TextLayout *layoutPtr = (TextLayout *) layout; - LayoutChunk *chunkPtr; - int numBytesInChunk; - - if ((layoutPtr == NULL) || (layoutPtr->numChunks == 0) - || (layoutPtr->chunks->numDisplayChars <= 0)) { - dst[0] = '\0'; - return 0; - } - chunkPtr = layoutPtr->chunks; - numBytesInChunk = chunkPtr->numBytes; - strncpy(dst, chunkPtr->start, (size_t) numBytesInChunk); - *font = layoutPtr->tkfont; - return numBytesInChunk; -} - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * End: - */ |