summaryrefslogtreecommitdiffstats
path: root/generic/tkFont.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tkFont.c')
-rw-r--r--generic/tkFont.c1498
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;
+}