diff options
Diffstat (limited to 'generic/tkFont.c')
-rw-r--r-- | generic/tkFont.c | 1498 |
1 files changed, 1073 insertions, 425 deletions
diff --git a/generic/tkFont.c b/generic/tkFont.c index 4c0ebb9..995fb01 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -6,14 +6,15 @@ * displaying text. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkFont.c,v 1.2 1998/09/14 18:23:10 stanton Exp $ + * RCS: @(#) $Id: tkFont.c,v 1.3 1999/04/16 01:51:14 stanton Exp $ */ +#include "tkPort.h" #include "tkInt.h" #include "tkFont.h" @@ -25,26 +26,19 @@ typedef struct TkFontInfo { Tcl_HashTable fontCache; /* Map a string to an existing Tk_Font. - * Keys are CachedFontKey structs, values are - * TkFont structs. */ + * 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 - * Tk_Uids, values are NamedFont structs. */ + * strings, values are NamedFont pointers. */ TkMainInfo *mainPtr; /* Application that owns this structure. */ - int updatePending; + int updatePending; /* Non-zero when a World Changed event has + * already been queued to handle a change to + * a named font. */ } TkFontInfo; /* - * The following structure is used as a key in the fontCache. - */ - -typedef struct CachedFontKey { - Display *display; /* Display for which font was constructed. */ - Tk_Uid string; /* String that describes font. */ -} CachedFontKey; - -/* * The following data structure is used to keep track of the font attributes * for each named font that has been defined. The named font is only deleted * when the last reference to it goes away. @@ -77,6 +71,7 @@ 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 @@ -168,13 +163,6 @@ static TkStateMap xlfdSetwidthMap[] = { {TK_SW_UNKNOWN, NULL} }; -static TkStateMap xlfdCharsetMap[] = { - {TK_CS_NORMAL, "iso8859"}, - {TK_CS_SYMBOL, "adobe"}, - {TK_CS_SYMBOL, "sun"}, - {TK_CS_OTHER, NULL} -}; - /* * The following structure and defines specify the valid builtin options * when configuring a set of font attributes. @@ -196,7 +184,135 @@ static char *fontOpt[] = { #define FONT_SLANT 3 #define FONT_UNDERLINE 4 #define FONT_OVERSTRIKE 5 -#define FONT_NUMFIELDS 6 /* Length of fontOpt array. */ +#define FONT_NUMFIELDS 6 + +/* + * Hardcoded font aliases. These are used to describe (mostly) identical + * fonts whose names differ from platform to platform. If the + * user-supplied font name matches any of the names in one of the alias + * lists, the other names in the alias list are also automatically tried. + */ + +static char *timesAliases[] = { + "Times", /* Unix. */ + "Times New Roman", /* Windows. */ + "New York", /* Mac. */ + NULL +}; + +static char *helveticaAliases[] = { + "Helvetica", /* Unix. */ + "Arial", /* Windows. */ + "Geneva", /* Mac. */ + NULL +}; + +static char *courierAliases[] = { + "Courier", /* Unix and Mac. */ + "Courier New", /* Windows. */ + NULL +}; + +static char *minchoAliases[] = { + "mincho", /* Unix. */ + "\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 char *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 char *dingbatsAliases[] = { + "dingbats", "zapfdingbats", "itc zapfdingbats", + /* Unix. */ + /* Windows. */ + "zapf dingbats", /* Mac. */ + NULL +}; + +static char **fontAliases[] = { + timesAliases, + helveticaAliases, + courierAliases, + minchoAliases, + gothicAliases, + dingbatsAliases, + NULL +}; + +/* + * Hardcoded font classes. If the character cannot be found in the base + * font, the classes are examined in order to see if some other similar + * font should be examined also. + */ + +static char *systemClass[] = { + "fixed", /* Unix. */ + /* Windows. */ + "chicago", "osaka", "sistemny", /* Mac. */ + NULL +}; + +static char *serifClass[] = { + "times", "palatino", "mincho", /* All platforms. */ + "song ti", /* Unix. */ + "ms serif", "simplified arabic", /* Windows. */ + "latinski", /* Mac. */ + NULL +}; + +static char *sansClass[] = { + "helvetica", "gothic", /* All platforms. */ + /* Unix. */ + "ms sans serif", "traditional arabic", + /* Windows. */ + "bastion", /* Mac. */ + NULL +}; + +static char *monoClass[] = { + "courier", "gothic", /* All platforms. */ + "fangsong ti", /* Unix. */ + "simplified arabic fixed", /* Windows. */ + "monaco", "pryamoy", /* Mac. */ + NULL +}; + +static char *symbolClass[] = { + "symbol", "dingbats", "wingdings", NULL +}; + +static char **fontFallbacks[] = { + systemClass, + serifClass, + sansClass, + monoClass, + symbolClass, + NULL +}; + +/* + * Global fallbacks. If the character could not be found in the preferred + * fallback list, this list is examined. If the character still cannot be + * found, all font families in the system are examined. + */ + +static char *globalFontClass[] = { + "symbol", /* All platforms. */ + /* Unix. */ + "lucida sans unicode", /* Windows. */ + "chicago", /* Mac. */ + NULL +}; #define GetFontAttributes(tkfont) \ ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa) @@ -208,7 +324,13 @@ static char *fontOpt[] = { static int ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[], TkFontAttributes *faPtr)); +static int CreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, CONST char *name, + TkFontAttributes *faPtr)); +static void DupFontObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr, + Tcl_Obj *dupObjPtr)); static int FieldSpecified _ANSI_ARGS_((CONST char *field)); +static void FreeFontObjProc _ANSI_ARGS_((Tcl_Obj *objPtr)); static int GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp, CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr)); static LayoutChunk * NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr, @@ -218,12 +340,27 @@ static int ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, TkFontAttributes *faPtr)); static void RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr)); +static int SetFontFromAny _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr)); static void TheWorldHasChanged _ANSI_ARGS_(( ClientData clientData)); -static void UpdateDependantFonts _ANSI_ARGS_((TkFontInfo *fiPtr, +static void UpdateDependentFonts _ANSI_ARGS_((TkFontInfo *fiPtr, Tk_Window tkwin, Tcl_HashEntry *namedHashPtr)); - +/* + * The following structure defines the implementation of the "font" Tcl + * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of + * each font object points to the TkFont structure for the font, or + * NULL. + */ + +static Tcl_ObjType fontObjType = { + "font", /* name */ + FreeFontObjProc, /* freeIntRepProc */ + DupFontObjProc, /* dupIntRepProc */ + NULL, /* updateStringProc */ + SetFontFromAny /* setFromAnyProc */ +}; /* @@ -236,8 +373,8 @@ static void UpdateDependantFonts _ANSI_ARGS_((TkFontInfo *fiPtr, * package on a per application basis. * * Results: - * Returns a token that must be stored in the TkMainInfo for this - * application. + * Stores a token in the mainPtr to hold information needed by this + * package on a per application basis. * * Side effects: * Memory allocated. @@ -251,11 +388,13 @@ TkFontPkgInit(mainPtr) TkFontInfo *fiPtr; fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo)); - Tcl_InitHashTable(&fiPtr->fontCache, sizeof(CachedFontKey) / sizeof(int)); - Tcl_InitHashTable(&fiPtr->namedTable, TCL_ONE_WORD_KEYS); + 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); } /* @@ -281,12 +420,21 @@ TkFontPkgFree(mainPtr) TkMainInfo *mainPtr; /* The application being deleted. */ { TkFontInfo *fiPtr; - Tcl_HashEntry *hPtr; + Tcl_HashEntry *hPtr, *searchPtr; Tcl_HashSearch search; + int fontsLeft; fiPtr = mainPtr->fontInfoPtr; - if (fiPtr->fontCache.numEntries != 0) { + fontsLeft = 0; + for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); + searchPtr != NULL; + searchPtr = Tcl_NextHashEntry(&search)) { + fontsLeft++; + fprintf(stderr, "Font %s still in cache.\n", + Tcl_GetHashKey(&fiPtr->fontCache, searchPtr)); + } + if (fontsLeft) { panic("TkFontPkgFree: all fonts should have been freed already"); } Tcl_DeleteHashTable(&fiPtr->fontCache); @@ -368,7 +516,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) "font ?-displayof window? ?option?"); return TCL_ERROR; } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); + tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); if (tkfont == NULL) { return TCL_ERROR; } @@ -394,14 +542,14 @@ Tk_FontObjCmd(clientData, interp, objc, objv) Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?"); return TCL_ERROR; } - string = Tk_GetUid(Tcl_GetStringFromObj(objv[2], NULL)); + string = Tcl_GetString(objv[2]); namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); nfPtr = NULL; /* lint. */ if (namedHashPtr != NULL) { nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); } if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string, + Tcl_AppendResult(interp, "named font \"", string, "\" doesn't exist", NULL); return TCL_ERROR; } @@ -412,7 +560,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) } else { result = ConfigAttributesObj(interp, tkwin, objc - 3, objv + 3, &nfPtr->fa); - UpdateDependantFonts(fiPtr, tkwin, namedHashPtr); + UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); return result; } return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr); @@ -420,7 +568,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) case FONT_CREATE: { int skip, i; char *name; - char buf[32]; + char buf[16 + TCL_INTEGER_SPACE]; TkFontAttributes fa; Tcl_HashEntry *namedHashPtr; @@ -428,7 +576,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) if (objc < 3) { name = NULL; } else { - name = Tcl_GetStringFromObj(objv[2], NULL); + name = Tcl_GetString(objv[2]); if (name[0] == '-') { name = NULL; } @@ -440,8 +588,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) for (i = 1; ; i++) { sprintf(buf, "font%d", i); - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, - Tk_GetUid(buf)); + namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, buf); if (namedHashPtr == NULL) { break; } @@ -454,10 +601,10 @@ Tk_FontObjCmd(clientData, interp, objc, objv) &fa) != TCL_OK) { return TCL_ERROR; } - if (TkCreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) { + if (CreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) { return TCL_ERROR; } - Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1); + Tcl_AppendResult(interp, name, NULL); break; } case FONT_DELETE: { @@ -476,10 +623,10 @@ Tk_FontObjCmd(clientData, interp, objc, objv) return TCL_ERROR; } for (i = 2; i < objc; i++) { - string = Tk_GetUid(Tcl_GetStringFromObj(objv[i], NULL)); + string = Tcl_GetString(objv[i]); namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); if (namedHashPtr == NULL) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string, + Tcl_AppendResult(interp, "named font \"", string, "\" doesn't exist", (char *) NULL); return TCL_ERROR; } @@ -511,6 +658,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) char *string; Tk_Font tkfont; int length, skip; + Tcl_Obj *resultPtr; skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); if (skip < 0) { @@ -521,17 +669,17 @@ Tk_FontObjCmd(clientData, interp, objc, objv) "font ?-displayof window? text"); return TCL_ERROR; } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); + tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); if (tkfont == NULL) { return TCL_ERROR; } string = Tcl_GetStringFromObj(objv[3 + skip], &length); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_TextWidth(tkfont, string, length)); + resultPtr = Tcl_GetObjResult(interp); + Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length)); Tk_FreeFont(tkfont); break; } case FONT_METRICS: { - char buf[64]; Tk_Font tkfont; int skip, index, i; CONST TkFontMetrics *fmPtr; @@ -548,7 +696,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) "font ?-displayof window? ?option?"); return TCL_ERROR; } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); + tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); if (tkfont == NULL) { return TCL_ERROR; } @@ -556,11 +704,13 @@ Tk_FontObjCmd(clientData, interp, objc, objv) objv += skip; fmPtr = GetFontMetrics(tkfont); if (objc == 3) { + char buf[64 + TCL_INTEGER_SPACE * 4]; + sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d", fmPtr->ascent, fmPtr->descent, fmPtr->ascent + fmPtr->descent, fmPtr->fixed); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); + Tcl_AppendResult(interp, buf, NULL); } else { if (Tcl_GetIndexFromObj(interp, objv[3], switches, "metric", 0, &index) != TCL_OK) { @@ -582,22 +732,23 @@ Tk_FontObjCmd(clientData, interp, objc, objv) } case FONT_NAMES: { char *string; - Tcl_Obj *strPtr; NamedFont *nfPtr; Tcl_HashSearch search; Tcl_HashEntry *namedHashPtr; + Tcl_Obj *strPtr, *resultPtr; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "names"); return TCL_ERROR; } + resultPtr = Tcl_GetObjResult(interp); namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); while (namedHashPtr != NULL) { nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); if (nfPtr->deletePending == 0) { string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr); strPtr = Tcl_NewStringObj(string, -1); - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); } namedHashPtr = Tcl_NextHashEntry(&search); } @@ -610,7 +761,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) /* *--------------------------------------------------------------------------- * - * UpdateDependantFonts, TheWorldHasChanged, RecomputeWidgets -- + * 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 @@ -627,7 +778,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) */ static void -UpdateDependantFonts(fiPtr, tkwin, namedHashPtr) +UpdateDependentFonts(fiPtr, tkwin, namedHashPtr) TkFontInfo *fiPtr; /* Info about application's fonts. */ Tk_Window tkwin; /* A window in the application. */ Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */ @@ -647,15 +798,16 @@ UpdateDependantFonts(fiPtr, tkwin, namedHashPtr) return; } - cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); while (cacheHashPtr != NULL) { - fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); - if (fontPtr->namedHashPtr == namedHashPtr) { - TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa); - if (fiPtr->updatePending == 0) { - fiPtr->updatePending = 1; - Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr); + for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); + fontPtr != NULL; fontPtr = fontPtr->nextPtr) { + if (fontPtr->namedHashPtr == namedHashPtr) { + TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa); + if (fiPtr->updatePending == 0) { + fiPtr->updatePending = 1; + Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr); + } } } cacheHashPtr = Tcl_NextHashEntry(&search); @@ -690,7 +842,7 @@ RecomputeWidgets(winPtr) /* *--------------------------------------------------------------------------- * - * TkCreateNamedFont -- + * CreateNamedFont -- * * Create the specified named font with the given attributes in the * named font table associated with the interp. @@ -698,7 +850,7 @@ RecomputeWidgets(winPtr) * Results: * Returns TCL_OK if the font was successfully created, or TCL_ERROR * if the named font already existed. If TCL_ERROR is returned, an - * error message is left in interp->result. + * error message is left in the interp's result. * * Side effects: * Assume there used to exist a named font by the specified name, and @@ -711,8 +863,8 @@ RecomputeWidgets(winPtr) *--------------------------------------------------------------------------- */ -int -TkCreateNamedFont(interp, tkwin, name, faPtr) +static int +CreateNamedFont(interp, tkwin, name, faPtr) Tcl_Interp *interp; /* Interp for error return. */ Tk_Window tkwin; /* A window associated with interp. */ CONST char *name; /* Name for the new named font. */ @@ -725,14 +877,13 @@ TkCreateNamedFont(interp, tkwin, name, faPtr) fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - name = Tk_GetUid(name); namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new); if (new == 0) { nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); if (nfPtr->deletePending == 0) { - interp->result[0] = '\0'; - Tcl_AppendResult(interp, "font \"", name, + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "named font \"", name, "\" already exists", (char *) NULL); return TCL_ERROR; } @@ -745,7 +896,7 @@ TkCreateNamedFont(interp, tkwin, name, faPtr) nfPtr->fa = *faPtr; nfPtr->deletePending = 0; - UpdateDependantFonts(fiPtr, tkwin, namedHashPtr); + UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); return TCL_OK; } @@ -769,13 +920,13 @@ TkCreateNamedFont(interp, tkwin, name, faPtr) * Results: * The return value is token for the font, or NULL if an error * prevented the font from being created. If NULL is returned, an - * error message will be left in interp->result. + * error message will be left in the interp's result. * * Side effects: - * Calls Tk_GetFontFromObj(), which modifies interp's result object, - * then copies the string from the result object into interp->result. - * This procedure will go away when Tk_ConfigureWidget() is - * made into an object command. + * The font is added to an internal database with a reference + * count. For each call to this procedure, there should eventually + * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the + * database is cleaned up when fonts aren't in use anymore. * *--------------------------------------------------------------------------- */ @@ -787,26 +938,20 @@ Tk_GetFont(interp, tkwin, string) CONST char *string; /* String describing font, as: named font, * native format, or parseable string. */ { + Tk_Font tkfont; Tcl_Obj *strPtr; - Tk_Font tkfont; - - strPtr = Tcl_NewStringObj((char *) string, -1); - - tkfont = Tk_GetFontFromObj(interp, tkwin, strPtr); - if (tkfont == NULL) { - Tcl_SetResult(interp, - Tcl_GetStringFromObj(Tcl_GetObjResult(interp), NULL), - TCL_VOLATILE); - } - Tcl_DecrRefCount(strPtr); /* done with object */ + strPtr = Tcl_NewStringObj((char *) string, -1); + Tcl_IncrRefCount(strPtr); + tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr); + Tcl_DecrRefCount(strPtr); return tkfont; } /* *--------------------------------------------------------------------------- * - * Tk_GetFontFromObj -- + * Tk_AllocFontFromObj -- * * Given a string description of a font, map the description to a * corresponding Tk_Font that represents the font. @@ -819,46 +964,77 @@ Tk_GetFont(interp, tkwin, string) * Side effects: * The font is added to an internal database with a reference * count. For each call to this procedure, there should eventually - * be a call to Tk_FreeFont() so that the database is cleaned up when - * fonts aren't in use anymore. + * 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_GetFontFromObj(interp, tkwin, objPtr) +Tk_AllocFontFromObj(interp, tkwin, objPtr) Tcl_Interp *interp; /* Interp for database and error return. */ - Tk_Window tkwin; /* For display on which font will be used. */ + 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; - CachedFontKey key; Tcl_HashEntry *cacheHashPtr, *namedHashPtr; - TkFont *fontPtr; + TkFont *fontPtr, *firstFontPtr, *oldFontPtr; int new, descent; NamedFont *nfPtr; - char *string; - + fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - string = Tcl_GetStringFromObj(objPtr, NULL); + if (objPtr->typePtr != &fontObjType) { + SetFontFromAny(interp, objPtr); + } - key.display = Tk_Display(tkwin); - key.string = Tk_GetUid(string); - cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, (char *) &key, &new); + oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; - if (new == 0) { - /* - * We have already constructed a font with this description for - * this display. Bump the reference count of the cached font. - */ + 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. + */ - fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); - fontPtr->refCount++; - return (Tk_Font) fontPtr; + FreeFontObjProc(objPtr); + oldFontPtr = NULL; + } else if (Tk_Screen(tkwin) == oldFontPtr->screen) { + oldFontPtr->resourceRefCount++; + return (Tk_Font) oldFontPtr; + } + } + + /* + * Next, search the list of fonts that have the name we want, to see + * if one of them is for the right screen. + */ + + new = 0; + if (oldFontPtr != NULL) { + cacheHashPtr = oldFontPtr->cacheHashPtr; + FreeFontObjProc(objPtr); + } else { + cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, + Tcl_GetString(objPtr), &new); + } + firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); + for (fontPtr = firstFontPtr; (fontPtr != NULL); + fontPtr = fontPtr->nextPtr) { + if (Tk_Screen(tkwin) == fontPtr->screen) { + fontPtr->resourceRefCount++; + fontPtr->objRefCount++; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; + return (Tk_Font) fontPtr; + } } - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, key.string); + /* + * 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. @@ -873,15 +1049,19 @@ Tk_GetFontFromObj(interp, tkwin, objPtr) * Native font? */ - fontPtr = TkpGetNativeFont(tkwin, string); + fontPtr = TkpGetNativeFont(tkwin, Tcl_GetString(objPtr)); if (fontPtr == NULL) { TkFontAttributes fa; + Tcl_Obj *dupObjPtr = Tcl_DuplicateObj(objPtr); - TkInitFontAttributes(&fa); - if (ParseFontNameObj(interp, tkwin, objPtr, &fa) != TCL_OK) { - Tcl_DeleteHashEntry(cacheHashPtr); + if (ParseFontNameObj(interp, tkwin, dupObjPtr, &fa) != TCL_OK) { + if (new) { + Tcl_DeleteHashEntry(cacheHashPtr); + } + Tcl_DecrRefCount(dupObjPtr); return NULL; } + Tcl_DecrRefCount(dupObjPtr); /* * String contained the attributes inline. @@ -890,13 +1070,16 @@ Tk_GetFontFromObj(interp, tkwin, objPtr) fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa); } } - Tcl_SetHashValue(cacheHashPtr, fontPtr); - fontPtr->refCount = 1; - fontPtr->cacheHashPtr = cacheHashPtr; - fontPtr->namedHashPtr = namedHashPtr; + 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, 0, 0, &fontPtr->tabWidth); + Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, -1, 0, &fontPtr->tabWidth); if (fontPtr->tabWidth == 0) { fontPtr->tabWidth = fontPtr->fm.maxWidth; } @@ -918,7 +1101,7 @@ Tk_GetFontFromObj(interp, tkwin, objPtr) descent = fontPtr->fm.descent; fontPtr->underlinePos = descent / 2; - fontPtr->underlineHeight = fontPtr->fa.pointsize / 10; + fontPtr->underlineHeight = TkFontGetPixels(tkwin, fontPtr->fa.size) / 10; if (fontPtr->underlineHeight == 0) { fontPtr->underlineHeight = 1; } @@ -936,10 +1119,125 @@ Tk_GetFontFromObj(interp, tkwin, objPtr) } } + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; return (Tk_Font) fontPtr; } /* + *---------------------------------------------------------------------- + * + * Tk_GetFontFromObj -- + * + * Find the font that corresponds to a given object. The font must + * have already been created by Tk_GetFont or Tk_AllocFontFromObj. + * + * Results: + * The return value is a token for the font that matches objPtr + * and is suitable for use in tkwin. + * + * Side effects: + * If the object is not already a font ref, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +Tk_Font +Tk_GetFontFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window that the font will be used in. */ + Tcl_Obj *objPtr; /* The object from which to get the font. */ +{ + TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; + TkFont *fontPtr; + Tcl_HashEntry *hashPtr; + + if (objPtr->typePtr != &fontObjType) { + SetFontFromAny((Tcl_Interp *) NULL, objPtr); + } + + fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; + + if (fontPtr != NULL) { + if (fontPtr->resourceRefCount == 0) { + /* + * This is a stale reference: it refers to a TkFont that's + * no longer in use. Clear the reference. + */ + + FreeFontObjProc(objPtr); + fontPtr = NULL; + } else if (Tk_Screen(tkwin) == fontPtr->screen) { + return (Tk_Font) fontPtr; + } + } + + /* + * Next, search the list of fonts that have the name we want, to see + * if one of them is for the right screen. + */ + + if (fontPtr != NULL) { + hashPtr = fontPtr->cacheHashPtr; + FreeFontObjProc(objPtr); + } else { + hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr)); + } + if (hashPtr != NULL) { + for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL; + fontPtr = fontPtr->nextPtr) { + if (Tk_Screen(tkwin) == fontPtr->screen) { + fontPtr->objRefCount++; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; + return (Tk_Font) fontPtr; + } + } + } + + panic("Tk_GetFontFromObj called with non-existent font!"); + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * SetFontFromAny -- + * + * Convert the internal representation of a Tcl object to the + * font internal form. + * + * Results: + * Always returns TCL_OK. + * + * Side effects: + * The object is left with its typePtr pointing to fontObjType. + * The TkFont pointer is NULL. + * + *---------------------------------------------------------------------- + */ + +static int +SetFontFromAny(interp, objPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_ObjType *typePtr; + + /* + * Free the old internalRep before setting the new one. + */ + + Tcl_GetString(objPtr); + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + objPtr->typePtr = &fontObjType; + objPtr->internalRep.twoPtrValue.ptr1 = NULL; + + return TCL_OK; +} + +/* *--------------------------------------------------------------------------- * * Tk_NameOfFont -- @@ -963,14 +1261,9 @@ Tk_NameOfFont(tkfont) Tk_Font tkfont; /* Font whose name is desired. */ { TkFont *fontPtr; - Tcl_HashEntry *hPtr; - CachedFontKey *keyPtr; fontPtr = (TkFont *) tkfont; - hPtr = fontPtr->cacheHashPtr; - - keyPtr = (CachedFontKey *) Tcl_GetHashKey(hPtr->tablePtr, hPtr); - return (char *) keyPtr->string; + return fontPtr->cacheHashPtr->key.string; } /* @@ -994,30 +1287,144 @@ void Tk_FreeFont(tkfont) Tk_Font tkfont; /* Font to be released. */ { - TkFont *fontPtr; + TkFont *fontPtr, *prevPtr; NamedFont *nfPtr; if (tkfont == NULL) { return; } fontPtr = (TkFont *) tkfont; - fontPtr->refCount--; - if (fontPtr->refCount == 0) { - if (fontPtr->namedHashPtr != NULL) { - /* - * The font is being deleted. Determine if the associated named - * font definition should and/or can be deleted too. - */ + fontPtr->resourceRefCount--; + if (fontPtr->resourceRefCount > 0) { + return; + } + if (fontPtr->namedHashPtr != NULL) { + /* + * This font derived from a named font. Reduce the reference + * count on the named font and free it if no-one else is + * using it. + */ - nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr); - nfPtr->refCount--; - if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) { - Tcl_DeleteHashEntry(fontPtr->namedHashPtr); - ckfree((char *) nfPtr); - } + nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr); + nfPtr->refCount--; + if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) { + Tcl_DeleteHashEntry(fontPtr->namedHashPtr); + ckfree((char *) nfPtr); } - Tcl_DeleteHashEntry(fontPtr->cacheHashPtr); - TkpDeleteFont(fontPtr); + } + + prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr); + if (prevPtr == fontPtr) { + if (fontPtr->nextPtr == NULL) { + Tcl_DeleteHashEntry(fontPtr->cacheHashPtr); + } else { + Tcl_SetHashValue(fontPtr->cacheHashPtr, fontPtr->nextPtr); + } + } else { + while (prevPtr->nextPtr != fontPtr) { + prevPtr = prevPtr->nextPtr; + } + prevPtr->nextPtr = fontPtr->nextPtr; + } + + TkpDeleteFont(fontPtr); + if (fontPtr->objRefCount == 0) { + ckfree((char *) fontPtr); + } +} + +/* + *--------------------------------------------------------------------------- + * + * Tk_FreeFontFromObj -- + * + * Called to release a font inside a Tcl_Obj *. Decrements the refCount + * of the font and removes it from the hash tables if necessary. + * + * Results: + * None. + * + * Side effects: + * The reference count associated with font is decremented, and + * only deallocated when no one is using it. + * + *--------------------------------------------------------------------------- + */ + +void +Tk_FreeFontFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window this font lives in. Needed + * for the screen value. */ + Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */ +{ + Tk_FreeFont(Tk_GetFontFromObj(tkwin, objPtr)); +} + +/* + *--------------------------------------------------------------------------- + * + * FreeFontObjProc -- + * + * This proc is called to release an object reference to a font. + * Called when the object's internal rep is released or when + * the cached fontPtr needs to be changed. + * + * Results: + * None. + * + * Side effects: + * The object reference count is decremented. When both it + * and the hash ref count go to zero, the font's resources + * are released. + * + *--------------------------------------------------------------------------- + */ + +static void +FreeFontObjProc(objPtr) + Tcl_Obj *objPtr; /* The object we are releasing. */ +{ + TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; + + if (fontPtr != NULL) { + fontPtr->objRefCount--; + if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) { + ckfree((char *) fontPtr); + objPtr->internalRep.twoPtrValue.ptr1 = NULL; + } + } +} + +/* + *--------------------------------------------------------------------------- + * + * DupFontObjProc -- + * + * When a cached font object is duplicated, this is called to + * update the internal reps. + * + * Results: + * None. + * + * Side effects: + * The font's objRefCount is incremented and the internal rep + * of the copy is set to point to it. + * + *--------------------------------------------------------------------------- + */ + +static void +DupFontObjProc(srcObjPtr, dupObjPtr) + Tcl_Obj *srcObjPtr; /* The object we are copying from. */ + Tcl_Obj *dupObjPtr; /* The object we are copying to. */ +{ + TkFont *fontPtr = (TkFont *) srcObjPtr->internalRep.twoPtrValue.ptr1; + + dupObjPtr->typePtr = srcObjPtr->typePtr; + dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; + + if (fontPtr != NULL) { + fontPtr->objRefCount++; } } @@ -1112,7 +1519,6 @@ Tk_GetFontMetrics(tkfont, fmPtr) *--------------------------------------------------------------------------- */ - int Tk_PostscriptFontName(tkfont, dsPtr) Tk_Font tkfont; /* Font in which text will be printed. */ @@ -1154,6 +1560,8 @@ Tk_PostscriptFontName(tkfont, dsPtr) } else if (strcasecmp(family, "ZapfDingbats") == 0) { family = "ZapfDingbats"; } else { + Tcl_UniChar ch; + /* * Inline, capitalize the first letter of each word, lowercase the * rest of the letters in each word, and then take out the spaces @@ -1165,16 +1573,19 @@ Tk_PostscriptFontName(tkfont, dsPtr) src = dest = Tcl_DStringValue(dsPtr) + len; upper = 1; - for (; *src != '\0'; src++, dest++) { - while (isspace(UCHAR(*src))) { + for (; *src != '\0'; ) { + while (isspace(UCHAR(*src))) { /* INTL: ISO space */ src++; upper = 1; } - *dest = *src; - if ((upper != 0) && (islower(UCHAR(*src)))) { - *dest = toupper(UCHAR(*src)); + src += Tcl_UtfToUniChar(src, &ch); + if (upper) { + ch = Tcl_UniCharToUpper(ch); + upper = 0; + } else { + ch = Tcl_UniCharToLower(ch); } - upper = 0; + dest += Tcl_UniCharToUtf(ch, dest); } *dest = '\0'; Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr)); @@ -1251,7 +1662,7 @@ Tk_PostscriptFontName(tkfont, dsPtr) } } - return fontPtr->fa.pointsize; + return fontPtr->fa.size; } /* @@ -1273,18 +1684,18 @@ Tk_PostscriptFontName(tkfont, dsPtr) */ int -Tk_TextWidth(tkfont, string, numChars) +Tk_TextWidth(tkfont, string, numBytes) Tk_Font tkfont; /* Font in which text will be measured. */ CONST char *string; /* String whose width will be computed. */ - int numChars; /* Number of characters to consider from + int numBytes; /* Number of bytes to consider from * string, or < 0 for strlen(). */ { int width; - if (numChars < 0) { - numChars = strlen(string); + if (numBytes < 0) { + numBytes = strlen(string); } - Tk_MeasureChars(tkfont, string, numChars, 0, 0, &width); + Tk_MeasureChars(tkfont, string, numBytes, -1, 0, &width); return width; } @@ -1311,8 +1722,8 @@ Tk_TextWidth(tkfont, string, numChars) */ void -Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstChar, - lastChar) +Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstByte, + lastByte) Display *display; /* Display on which to draw. */ Drawable drawable; /* Window or pixmap in which to draw. */ GC gc; /* Graphics context for actually drawing @@ -1324,16 +1735,17 @@ Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstChar, * underlined or overstruck. */ int x, y; /* Coordinates at which first character of * string is drawn. */ - int firstChar; /* Index of first character. */ - int lastChar; /* Index of one after the last character. */ + int firstByte; /* Index of first byte of first character. */ + int lastByte; /* Index of first byte after the last + * character. */ { TkFont *fontPtr; int startX, endX; fontPtr = (TkFont *) tkfont; - Tk_MeasureChars(tkfont, string, firstChar, 0, 0, &startX); - Tk_MeasureChars(tkfont, string, lastChar, 0, 0, &endX); + Tk_MeasureChars(tkfont, string, firstByte, -1, 0, &startX); + Tk_MeasureChars(tkfont, string, lastByte, -1, 0, &endX); XFillRectangle(display, drawable, gc, x + startX, y + fontPtr->underlinePos, (unsigned int) (endX - startX), @@ -1394,18 +1806,16 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, { TkFont *fontPtr; CONST char *start, *end, *special; - int n, y, charsThisChunk, maxChunks; + int n, y, bytesThisChunk, maxChunks; int baseline, height, curX, newX, maxWidth; TextLayout *layoutPtr; LayoutChunk *chunkPtr; CONST TkFontMetrics *fmPtr; -#define MAX_LINES 50 - int staticLineLengths[MAX_LINES]; + Tcl_DString lineBuffer; int *lineLengths; - int maxLines, curLine, layoutHeight; + int curLine, layoutHeight; - lineLengths = staticLineLengths; - maxLines = MAX_LINES; + Tcl_DStringInit(&lineBuffer); fontPtr = (TkFont *) tkfont; fmPtr = &fontPtr->fm; @@ -1413,7 +1823,10 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, height = fmPtr->ascent + fmPtr->descent; if (numChars < 0) { - numChars = strlen(string); + numChars = Tcl_NumUtfChars(string, -1); + } + if (wrapLength == 0) { + wrapLength = -1; } maxChunks = 1; @@ -1433,16 +1846,20 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, curX = 0; - end = string + numChars; + end = Tcl_UtfAtIndex(string, numChars); special = string; flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES; flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE; - curLine = 0; for (start = string; start < end; ) { if (start >= special) { /* * Find the next special character in the string. + * + * 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++) { @@ -1466,15 +1883,15 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, chunkPtr = NULL; if (start < special) { - charsThisChunk = Tk_MeasureChars(tkfont, start, special - start, + bytesThisChunk = Tk_MeasureChars(tkfont, start, special - start, wrapLength - curX, flags, &newX); newX += curX; flags &= ~TK_AT_LEAST_ONE; - if (charsThisChunk > 0) { + if (bytesThisChunk > 0) { chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, - charsThisChunk, curX, newX, baseline); + bytesThisChunk, curX, newX, baseline); - start += charsThisChunk; + start += bytesThisChunk; curX = newX; } } @@ -1482,6 +1899,9 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, 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; @@ -1515,7 +1935,7 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, * Consume all extra spaces at end of line. */ - while ((start < end) && isspace(UCHAR(*start))) { + while ((start < end) && isspace(UCHAR(*start))) { /* INTL: ISO space */ if (!(flags & TK_IGNORE_NEWLINES)) { if ((*start == '\n') || (*start == '\r')) { break; @@ -1529,15 +1949,21 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, start++; } if (chunkPtr != NULL) { + CONST char *end; + /* * Append all the extra spaces on this line to the end of the - * last text chunk. + * last text chunk. This is a little tricky because we are + * switching back and forth between characters and bytes. */ - charsThisChunk = start - (chunkPtr->start + chunkPtr->numChars); - if (charsThisChunk > 0) { - chunkPtr->numChars += Tk_MeasureChars(tkfont, - chunkPtr->start + chunkPtr->numChars, charsThisChunk, - 0, 0, &chunkPtr->totalWidth); + + 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; } } @@ -1559,19 +1985,7 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, * can be centered or right justified, if necessary. */ - if (curLine >= maxLines) { - int *newLengths; - - newLengths = (int *) ckalloc(2 * maxLines * sizeof(int)); - memcpy((void *) newLengths, lineLengths, maxLines * sizeof(int)); - if (lineLengths != staticLineLengths) { - ckfree((char *) lineLengths); - } - lineLengths = newLengths; - maxLines *= 2; - } - lineLengths[curLine] = curX; - curLine++; + Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX)); curX = 0; baseline += height; @@ -1588,34 +2002,11 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX, 1000000000, baseline); chunkPtr->numDisplayChars = -1; + Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX)); baseline += height; } } - /* - * Using maximum line length, shift all the chunks so that the lines are - * all justified correctly. - */ - - curLine = 0; - chunkPtr = layoutPtr->chunks; - y = chunkPtr->y; - for (n = 0; n < layoutPtr->numChunks; n++) { - int extra; - - if (chunkPtr->y != y) { - curLine++; - y = chunkPtr->y; - } - extra = maxWidth - lineLengths[curLine]; - if (justify == TK_JUSTIFY_CENTER) { - chunkPtr->x += extra / 2; - } else if (justify == TK_JUSTIFY_RIGHT) { - chunkPtr->x += extra; - } - chunkPtr++; - } - layoutPtr->width = maxWidth; layoutHeight = baseline - fmPtr->ascent; if (layoutPtr->numChunks == 0) { @@ -1629,12 +2020,38 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, 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) { @@ -1643,9 +2060,7 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, if (heightPtr != NULL) { *heightPtr = layoutHeight; } - if (lineLengths != staticLineLengths) { - ckfree((char *) lineLengths); - } + Tcl_DStringFree(&lineBuffer); return (Tk_TextLayout) layoutPtr; } @@ -1718,6 +2133,8 @@ Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar) { TextLayout *layoutPtr; int i, numDisplayChars, drawX; + CONST char *firstByte; + CONST char *lastByte; LayoutChunk *chunkPtr; layoutPtr = (TextLayout *) layout; @@ -1735,15 +2152,18 @@ Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar) if (firstChar <= 0) { drawX = 0; firstChar = 0; + firstByte = chunkPtr->start; } else { - Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, firstChar, - 0, 0, &drawX); + 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, - chunkPtr->start + firstChar, numDisplayChars - firstChar, + firstByte, lastByte - firstByte, x + chunkPtr->x + drawX, y + chunkPtr->y); } firstChar -= chunkPtr->numChars; @@ -1849,7 +2269,7 @@ Tk_PointToChar(layout, x, y) TextLayout *layoutPtr; LayoutChunk *chunkPtr, *lastPtr; TkFont *fontPtr; - int i, n, dummy, baseline, pos; + int i, n, dummy, baseline, pos, numChars; if (y < 0) { /* @@ -1867,6 +2287,7 @@ Tk_PointToChar(layout, x, y) layoutPtr = (TextLayout *) layout; fontPtr = (TkFont *) layoutPtr->tkfont; lastPtr = chunkPtr = layoutPtr->chunks; + numChars = 0; for (i = 0; i < layoutPtr->numChunks; i++) { baseline = chunkPtr->y; if (y < baseline + fontPtr->fm.descent) { @@ -1876,7 +2297,7 @@ Tk_PointToChar(layout, x, y) * the index of the first character on this line. */ - return chunkPtr->start - layoutPtr->string; + return numChars; } if (x >= layoutPtr->width) { /* @@ -1907,13 +2328,14 @@ Tk_PointToChar(layout, x, y) * tab or newline char. */ - return chunkPtr->start - layoutPtr->string; + return numChars; } n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start, - chunkPtr->numChars, x + 1 - chunkPtr->x, - TK_PARTIAL_OK, &dummy); - return (chunkPtr->start + n - 1) - layoutPtr->string; + chunkPtr->numBytes, x - chunkPtr->x, + 0, &dummy); + return numChars + Tcl_NumUtfChars(chunkPtr->start, n); } + numChars += chunkPtr->numChars; lastPtr = chunkPtr; chunkPtr++; i++; @@ -1925,12 +2347,13 @@ Tk_PointToChar(layout, x, y) * chunk on this line. */ - pos = (lastPtr->start + lastPtr->numChars) - layoutPtr->string; + pos = numChars; if (i < layoutPtr->numChunks) { pos--; } return pos; } + numChars += chunkPtr->numChars; lastPtr = chunkPtr; chunkPtr++; } @@ -1997,6 +2420,7 @@ Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr) int i, x, w; Tk_Font tkfont; TkFont *fontPtr; + CONST char *end; if (index < 0) { return 0; @@ -2015,12 +2439,15 @@ Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr) goto check; } } else if (index < chunkPtr->numChars) { + end = Tcl_UtfAtIndex(chunkPtr->start, index); if (xPtr != NULL) { - Tk_MeasureChars(tkfont, chunkPtr->start, index, 0, 0, &x); + Tk_MeasureChars(tkfont, chunkPtr->start, + end - chunkPtr->start, -1, 0, &x); x += chunkPtr->x; } if (widthPtr != NULL) { - Tk_MeasureChars(tkfont, chunkPtr->start + index, 1, 0, 0, &w); + Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end, + -1, 0, &w); } goto check; } @@ -2276,7 +2703,7 @@ Tk_IntersectTextLayout(layout, x, y, width, height) * location of the baseline for the string. * * Results: - * Interp->result is modified to hold the Postscript code that + * The interp's result is modified to hold the Postscript code that * will render the text layout. * * Side effects: @@ -2294,6 +2721,8 @@ Tk_TextLayoutToPostscript(interp, layout) char buf[MAXUSE+10]; LayoutChunk *chunkPtr; int i, j, used, c, baseline; + Tcl_UniChar ch; + CONST char *p; TextLayout *layoutPtr; layoutPtr = (TextLayout *) layout; @@ -2314,8 +2743,16 @@ Tk_TextLayoutToPostscript(interp, layout) buf[used++] = 't'; } } else { + p = chunkPtr->start; for (j = 0; j < chunkPtr->numDisplayChars; j++) { - c = UCHAR(chunkPtr->start[j]); + /* + * INTL: For now we just treat the characters as binary + * data and display the lower byte. Eventually this should + * be revised to handle international postscript fonts. + */ + + p += Tcl_UtfToUniChar(p, &ch); + c = UCHAR(ch & 0xff); if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20) || (c >= UCHAR(0x7f))) { /* @@ -2359,36 +2796,6 @@ Tk_TextLayoutToPostscript(interp, layout) /* *--------------------------------------------------------------------------- * - * TkInitFontAttributes -- - * - * Initialize the font attributes structure to contain sensible - * values. This must be called before using any other font - * attributes functions. - * - * Results: - * None. - * - * Side effects. - * None. - * - *--------------------------------------------------------------------------- - */ - -void -TkInitFontAttributes(faPtr) - TkFontAttributes *faPtr; /* The attributes structure to initialize. */ -{ - faPtr->family = NULL; - faPtr->pointsize = 0; - faPtr->weight = TK_FW_NORMAL; - faPtr->slant = TK_FS_ROMAN; - faPtr->underline = 0; - faPtr->overstrike = 0; -} - -/* - *--------------------------------------------------------------------------- - * * ConfigAttributesObj -- * * Process command line options to fill in fields of a properly @@ -2419,68 +2826,74 @@ ConfigAttributesObj(interp, tkwin, objc, objv, faPtr) * be properly initialized. */ { int i, n, index; - Tcl_Obj *value; - char *option, *string; + Tcl_Obj *optionPtr, *valuePtr; + char *value; - if (objc & 1) { - string = Tcl_GetStringFromObj(objv[objc - 1], NULL); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "missing value for \"", - string, "\" option", (char *) NULL); - return TCL_ERROR; - } - for (i = 0; i < objc; i += 2) { - option = Tcl_GetStringFromObj(objv[i], NULL); - value = objv[i + 1]; + optionPtr = objv[i]; + valuePtr = objv[i + 1]; - if (Tcl_GetIndexFromObj(interp, objv[i], fontOpt, "option", 1, + if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1, &index) != TCL_OK) { return TCL_ERROR; } + if (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. + */ + + Tcl_AppendResult(interp, "value for \"", + Tcl_GetString(optionPtr), "\" option missing", + (char *) NULL); + return TCL_ERROR; + } + switch (index) { - case FONT_FAMILY: - string = Tcl_GetStringFromObj(value, NULL); - faPtr->family = Tk_GetUid(string); + case FONT_FAMILY: { + value = Tcl_GetString(valuePtr); + faPtr->family = Tk_GetUid(value); break; - - case FONT_SIZE: - if (Tcl_GetIntFromObj(interp, value, &n) != TCL_OK) { + } + case FONT_SIZE: { + if (Tcl_GetIntFromObj(interp, valuePtr, &n) != TCL_OK) { return TCL_ERROR; } - faPtr->pointsize = n; + faPtr->size = n; break; - - case FONT_WEIGHT: - string = Tcl_GetStringFromObj(value, NULL); - n = TkFindStateNum(interp, option, weightMap, string); + } + case FONT_WEIGHT: { + n = TkFindStateNumObj(interp, optionPtr, weightMap, valuePtr); if (n == TK_FW_UNKNOWN) { return TCL_ERROR; } faPtr->weight = n; break; - - case FONT_SLANT: - string = Tcl_GetStringFromObj(value, NULL); - n = TkFindStateNum(interp, option, slantMap, string); + } + 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, value, &n) != TCL_OK) { + } + 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, value, &n) != TCL_OK) { + } + case FONT_OVERSTRIKE: { + if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) { return TCL_ERROR; } faPtr->overstrike = n; break; + } } } return TCL_OK; @@ -2515,18 +2928,19 @@ GetAttributeInfoObj(interp, faPtr, objPtr) 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. */ + * returned. Otherwise information is + * returned for all options. */ { - int i, index, start, end, num; + int i, index, start, end; char *str; - Tcl_Obj *newPtr; + Tcl_Obj *optionPtr, *valuePtr, *resultPtr; + + resultPtr = Tcl_GetObjResult(interp); start = 0; end = FONT_NUMFIELDS; if (objPtr != NULL) { - if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", 1, + if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } @@ -2534,55 +2948,43 @@ GetAttributeInfoObj(interp, faPtr, objPtr) end = index + 1; } + valuePtr = NULL; for (i = start; i < end; i++) { - str = NULL; - num = 0; /* Needed only to prevent compiler - * warning. */ switch (i) { case FONT_FAMILY: str = faPtr->family; - if (str == NULL) { - str = ""; - } + valuePtr = Tcl_NewStringObj(str, ((str == NULL) ? 0 : -1)); break; case FONT_SIZE: - num = faPtr->pointsize; + valuePtr = Tcl_NewIntObj(faPtr->size); 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: - num = faPtr->underline; + valuePtr = Tcl_NewBooleanObj(faPtr->underline); break; case FONT_OVERSTRIKE: - num = faPtr->overstrike; + valuePtr = Tcl_NewBooleanObj(faPtr->overstrike); break; } - if (objPtr == NULL) { - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), - Tcl_NewStringObj(fontOpt[i], -1)); - if (str != NULL) { - newPtr = Tcl_NewStringObj(str, -1); - } else { - newPtr = Tcl_NewIntObj(num); - } - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), - newPtr); - } else { - if (str != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), str, -1); - } else { - Tcl_SetIntObj(Tcl_GetObjResult(interp), num); - } + if (objPtr != NULL) { + Tcl_SetObjResult(interp, valuePtr); + return TCL_OK; } + optionPtr = Tcl_NewStringObj(fontOpt[i], -1); + Tcl_ListObjAppendElement(NULL, resultPtr, optionPtr); + Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr); } return TCL_OK; } @@ -2597,7 +2999,7 @@ GetAttributeInfoObj(interp, faPtr, objPtr) * * The string rep of the object can be one of the following forms: * XLFD (see X documentation) - * "Family [size [style] [style ...]]" + * "family [size] [style1 [style2 ...]" * "-option value [-option value ...]" * * Results: @@ -2614,20 +3016,25 @@ GetAttributeInfoObj(interp, faPtr, objPtr) static int ParseFontNameObj(interp, tkwin, objPtr, faPtr) - Tcl_Interp *interp; /* Interp for error return. */ + Tcl_Interp *interp; /* Interp for error return. Must not be + * NULL. */ Tk_Window tkwin; /* For display on which font is used. */ Tcl_Obj *objPtr; /* Parseable font description object. */ - TkFontAttributes *faPtr; /* Font attributes structure whose fields - * are to be modified. Structure must already - * be properly initialized. */ + 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; - TkXLFDAttributes xa; + Tcl_Obj *resultPtr; char *string; - string = Tcl_GetStringFromObj(objPtr, NULL); + TkInitFontAttributes(faPtr); + resultPtr = Tcl_GetObjResult(interp); + + string = Tcl_GetString(objPtr); if (*string == '-') { /* * This may be an XLFD or an "-option value" string. @@ -2640,7 +3047,8 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) goto xlfd; } dash = strchr(string + 1, '-'); - if ((dash != NULL) && (!isspace(UCHAR(dash[-1])))) { + if ((dash != NULL) + && (!isspace(UCHAR(dash[-1])))) { /* INTL: ISO space */ goto xlfd; } @@ -2653,15 +3061,16 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) if (*string == '*') { /* - * This appears to be an XLFD. + * 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: - xa.fa = *faPtr; - result = TkParseXLFD(string, &xa); + result = TkFontParseXLFD(string, faPtr, NULL); if (result == TCL_OK) { - *faPtr = xa.fa; - return result; + return TCL_OK; } } @@ -2670,21 +3079,19 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) * "font size style" list. */ - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - if (objc < 1) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "font \"", string, - "\" doesn't exist", (char *) NULL); + if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) + || (objc < 1)) { + Tcl_AppendResult(interp, "font \"", string, "\" doesn't exist", + (char *) NULL); return TCL_ERROR; } - faPtr->family = Tk_GetUid(Tcl_GetStringFromObj(objv[0], NULL)); + faPtr->family = Tk_GetUid(Tcl_GetString(objv[0])); if (objc > 1) { if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) { return TCL_ERROR; } - faPtr->pointsize = n; + faPtr->size = n; } i = 2; @@ -2695,23 +3102,22 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) i = 0; } for ( ; i < objc; i++) { - string = Tcl_GetStringFromObj(objv[i], NULL); - n = TkFindStateNum(NULL, NULL, weightMap, string); + n = TkFindStateNumObj(NULL, NULL, weightMap, objv[i]); if (n != TK_FW_UNKNOWN) { faPtr->weight = n; continue; } - n = TkFindStateNum(NULL, NULL, slantMap, string); + n = TkFindStateNumObj(NULL, NULL, slantMap, objv[i]); if (n != TK_FS_UNKNOWN) { faPtr->slant = n; continue; } - n = TkFindStateNum(NULL, NULL, underlineMap, string); + n = TkFindStateNumObj(NULL, NULL, underlineMap, objv[i]); if (n != 0) { faPtr->underline = n; continue; } - n = TkFindStateNum(NULL, NULL, overstrikeMap, string); + n = TkFindStateNumObj(NULL, NULL, overstrikeMap, objv[i]); if (n != 0) { faPtr->overstrike = n; continue; @@ -2721,9 +3127,8 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) * Unknown style. */ - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "unknown font style \"", string, "\"", - (char *) NULL); + Tcl_AppendResult(interp, "unknown font style \"", + Tcl_GetString(objv[i]), "\"", (char *) NULL); return TCL_ERROR; } return TCL_OK; @@ -2732,7 +3137,69 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) /* *--------------------------------------------------------------------------- * - * TkParseXLFD -- + * NewChunk -- + * + * Helper function for Tk_ComputeTextLayout(). Encapsulates a + * measured set of characters in a chunk that can be quickly + * drawn. + * + * Results: + * A pointer to the new chunk in the text layout. + * + * Side effects: + * The text layout is reallocated to hold more chunks as necessary. + * + * Currently, Tk_ComputeTextLayout() stores contiguous ranges of + * "normal" characters in a chunk, along with individual tab + * and newline chars in their own chunks. All characters in the + * text layout are accounted for. + * + *--------------------------------------------------------------------------- + */ +static LayoutChunk * +NewChunk(layoutPtrPtr, maxPtr, start, numBytes, curX, newX, y) + 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 = (TextLayout *) ckrealloc((char *) 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. * @@ -2748,18 +3215,31 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) */ int -TkParseXLFD(string, xaPtr) +TkFontParseXLFD(string, faPtr, xaPtr) CONST char *string; /* Parseable font description string. */ - TkXLFDAttributes *xaPtr; /* XLFD attributes structure whose fields - * are to be modified. Structure must already - * be properly initialized. */ + 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; @@ -2773,27 +3253,32 @@ TkParseXLFD(string, xaPtr) field[0] = src; for (i = 0; *src != '\0'; src++) { - if (isupper(UCHAR(*src))) { - *src = tolower(UCHAR(*src)); + if (!(*src & 0x90) + && isupper(UCHAR(*src))) { /* INTL: 7-bit ISO only. */ + *src = tolower(UCHAR(*src)); /* INTL: 7-bit ISO only. */ } if (*src == '-') { i++; - if (i > XLFD_NUMFIELDS) { - break; + 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, + * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common, * but it is (strictly) malformed, because the first * is eliding both * the Setwidth and the Addstyle fields. If the Addstyle field is a * number, then assume the above incorrect form was used and shift all - * the rest of the fields up by one, so the number gets interpreted + * 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, but gives a syntax error under Windows". + * 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]))) { @@ -2820,19 +3305,19 @@ TkParseXLFD(string, xaPtr) } if (FieldSpecified(field[XLFD_FAMILY])) { - xaPtr->fa.family = Tk_GetUid(field[XLFD_FAMILY]); + faPtr->family = Tk_GetUid(field[XLFD_FAMILY]); } if (FieldSpecified(field[XLFD_WEIGHT])) { - xaPtr->fa.weight = TkFindStateNum(NULL, NULL, xlfdWeightMap, + 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) { - xaPtr->fa.slant = TK_FS_ROMAN; + faPtr->slant = TK_FS_ROMAN; } else { - xaPtr->fa.slant = TK_FS_ITALIC; + faPtr->slant = TK_FS_ITALIC; } } if (FieldSpecified(field[XLFD_SETWIDTH])) { @@ -2843,9 +3328,12 @@ TkParseXLFD(string, xaPtr) /* XLFD_ADD_STYLE ignored. */ /* - * Pointsize in tenths of a point, but treat it as tenths of a pixel. + * Pointsize in tenths of a point, but treat it as tenths of a pixel + * for historical compatibility. */ + faPtr->size = 12; + if (FieldSpecified(field[XLFD_POINT_SIZE])) { if (field[XLFD_POINT_SIZE][0] == '[') { /* @@ -2858,10 +3346,10 @@ TkParseXLFD(string, xaPtr) * the purpose of, so I ignore them. */ - xaPtr->fa.pointsize = atoi(field[XLFD_POINT_SIZE] + 1); + faPtr->size = atoi(field[XLFD_POINT_SIZE] + 1); } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE], - &xaPtr->fa.pointsize) == TCL_OK) { - xaPtr->fa.pointsize /= 10; + &faPtr->size) == TCL_OK) { + faPtr->size /= 10; } else { return TCL_ERROR; } @@ -2883,14 +3371,14 @@ TkParseXLFD(string, xaPtr) * the purpose of, so I ignore them. */ - xaPtr->fa.pointsize = atoi(field[XLFD_PIXEL_SIZE] + 1); + faPtr->size = atoi(field[XLFD_PIXEL_SIZE] + 1); } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE], - &xaPtr->fa.pointsize) != TCL_OK) { + &faPtr->size) != TCL_OK) { return TCL_ERROR; } } - xaPtr->fa.pointsize = -xaPtr->fa.pointsize; + faPtr->size = -faPtr->size; /* XLFD_RESOLUTION_X ignored. */ @@ -2900,14 +3388,11 @@ TkParseXLFD(string, xaPtr) /* XLFD_AVERAGE_WIDTH ignored. */ - if (FieldSpecified(field[XLFD_REGISTRY])) { - xaPtr->charset = TkFindStateNum(NULL, NULL, xlfdCharsetMap, - field[XLFD_REGISTRY]); - } - if (FieldSpecified(field[XLFD_ENCODING])) { - xaPtr->encoding = atoi(field[XLFD_ENCODING]); + 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; } @@ -2949,60 +3434,223 @@ FieldSpecified(field) /* *--------------------------------------------------------------------------- * - * NewChunk -- + * TkFontGetPixels -- * - * Helper function for Tk_ComputeTextLayout(). Encapsulates a - * measured set of characters in a chunk that can be quickly - * drawn. + * Given a font size specification (as described in the TkFontAttributes + * structure) return the number of pixels it represents. * * Results: - * A pointer to the new chunk in the text layout. + * As above. * * Side effects: - * The text layout is reallocated to hold more chunks as necessary. + * None. * - * 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. + *--------------------------------------------------------------------------- + */ + +int +TkFontGetPixels(tkwin, size) + Tk_Window tkwin; /* For point->pixel conversion factor. */ + int size; /* Font size. */ +{ + double d; + + if (size < 0) { + return -size; + } + + d = size * 25.4 / 72.0; + d *= WidthOfScreen(Tk_Screen(tkwin)); + d /= WidthMMOfScreen(Tk_Screen(tkwin)); + return (int) (d + 0.5); +} + +/* + *--------------------------------------------------------------------------- + * + * 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. * *--------------------------------------------------------------------------- */ -static LayoutChunk * -NewChunk(layoutPtrPtr, maxPtr, start, numChars, curX, newX, y) - TextLayout **layoutPtrPtr; - int *maxPtr; - CONST char *start; - int numChars; - int curX; - int newX; - int y; + +int +TkFontGetPoints(tkwin, size) + Tk_Window tkwin; /* For pixel->point conversion factor. */ + int size; /* Font size. */ { - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - int maxChunks; - size_t s; - - layoutPtr = *layoutPtrPtr; - maxChunks = *maxPtr; - if (layoutPtr->numChunks == maxChunks) { - maxChunks *= 2; - s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk)); - layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s); + double d; - *layoutPtrPtr = layoutPtr; - *maxPtr = maxChunks; + if (size >= 0) { + return size; } - chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks]; - chunkPtr->start = start; - chunkPtr->numChars = numChars; - chunkPtr->numDisplayChars = numChars; - chunkPtr->x = curX; - chunkPtr->y = y; - chunkPtr->totalWidth = newX - curX; - chunkPtr->displayWidth = newX - curX; - layoutPtr->numChunks++; - return chunkPtr; + d = -size * 72.0 / 25.4; + d *= WidthMMOfScreen(Tk_Screen(tkwin)); + d /= WidthOfScreen(Tk_Screen(tkwin)); + return (int) (d + 0.5); } + +/* + *------------------------------------------------------------------------- + * + * 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. + * + *------------------------------------------------------------------------- + */ + +char ** +TkFontGetAliasList(faceName) + 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. + * + *------------------------------------------------------------------------- + */ + +char *** +TkFontGetFallbacks() +{ + 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. + * + *------------------------------------------------------------------------- + */ + +char ** +TkFontGetGlobalClass() +{ + 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. + * + *------------------------------------------------------------------------- + */ + +char ** +TkFontGetSymbolClass() +{ + return symbolClass; +} + +/* + *---------------------------------------------------------------------- + * + * TkDebugFont -- + * + * This procedure 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(tkwin, name) + Tk_Window tkwin; /* The window in which the font will be + * used (not currently used). */ + 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 = (TkFont *) Tcl_GetHashValue(hashPtr); + if (fontPtr == NULL) { + 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; +} |