diff options
Diffstat (limited to 'generic/tkFont.c')
-rw-r--r-- | generic/tkFont.c | 1013 |
1 files changed, 689 insertions, 324 deletions
diff --git a/generic/tkFont.c b/generic/tkFont.c index 5d2ad43..722d16f 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -163,7 +163,7 @@ static const TkStateMap xlfdSetwidthMap[] = { * configuring a set of font attributes. */ -static const char *fontOpt[] = { +static const char *const fontOpt[] = { "-family", "-size", "-weight", @@ -188,27 +188,27 @@ static const char *fontOpt[] = { * the alias list are also automatically tried. */ -static char *timesAliases[] = { +static const char *const timesAliases[] = { "Times", /* Unix. */ "Times New Roman", /* Windows. */ "New York", /* Mac. */ NULL }; -static char *helveticaAliases[] = { +static const char *const helveticaAliases[] = { "Helvetica", /* Unix. */ "Arial", /* Windows. */ "Geneva", /* Mac. */ NULL }; -static char *courierAliases[] = { +static const char *const courierAliases[] = { "Courier", /* Unix and Mac. */ "Courier New", /* Windows. */ NULL }; -static char *minchoAliases[] = { +static const char *const minchoAliases[] = { "mincho", /* Unix. */ "\357\274\255\357\274\263 \346\230\216\346\234\235", /* Windows (MS mincho). */ @@ -217,7 +217,7 @@ static char *minchoAliases[] = { NULL }; -static char *gothicAliases[] = { +static const char *const gothicAliases[] = { "gothic", /* Unix. */ "\357\274\255\357\274\263 \343\202\264\343\202\267\343\203\203\343\202\257", /* Windows (MS goshikku). */ @@ -226,7 +226,7 @@ static char *gothicAliases[] = { NULL }; -static char *dingbatsAliases[] = { +static const char *const dingbatsAliases[] = { "dingbats", "zapfdingbats", "itc zapfdingbats", /* Unix. */ /* Windows. */ @@ -234,7 +234,7 @@ static char *dingbatsAliases[] = { NULL }; -static char **fontAliases[] = { +static const char *const *const fontAliases[] = { timesAliases, helveticaAliases, courierAliases, @@ -250,7 +250,7 @@ static char **fontAliases[] = { * be examined also. */ -static char *systemClass[] = { +static const char *const systemClass[] = { "fixed", /* Unix. */ /* Windows. */ "chicago", "osaka", "sistemny", @@ -258,7 +258,7 @@ static char *systemClass[] = { NULL }; -static char *serifClass[] = { +static const char *const serifClass[] = { "times", "palatino", "mincho", /* All platforms. */ "song ti", /* Unix. */ @@ -268,7 +268,7 @@ static char *serifClass[] = { NULL }; -static char *sansClass[] = { +static const char *const sansClass[] = { "helvetica", "gothic", /* All platforms. */ /* Unix. */ "ms sans serif", "traditional arabic", @@ -277,7 +277,7 @@ static char *sansClass[] = { NULL }; -static char *monoClass[] = { +static const char *const monoClass[] = { "courier", "gothic", /* All platforms. */ "fangsong ti", /* Unix. */ "simplified arabic fixed", /* Windows. */ @@ -285,11 +285,11 @@ static char *monoClass[] = { NULL }; -static char *symbolClass[] = { +static const char *const symbolClass[] = { "symbol", "dingbats", "wingdings", NULL }; -static char **fontFallbacks[] = { +static const char *const *const fontFallbacks[] = { systemClass, serifClass, sansClass, @@ -304,7 +304,7 @@ static char **fontFallbacks[] = { * found, all font families in the system are examined. */ -static char *globalFontClass[] = { +static const char *const globalFontClass[] = { "symbol", /* All platforms. */ /* Unix. */ "lucida sans unicode", /* Windows. */ @@ -325,6 +325,7 @@ static int ConfigAttributesObj(Tcl_Interp *interp, TkFontAttributes *faPtr); static void DupFontObjProc(Tcl_Obj *srcObjPtr, Tcl_Obj *dupObjPtr); static int FieldSpecified(const char *field); +static void FreeFontObj(Tcl_Obj *objPtr); static void FreeFontObjProc(Tcl_Obj *objPtr); static int GetAttributeInfoObj(Tcl_Interp *interp, const TkFontAttributes *faPtr, Tcl_Obj *objPtr); @@ -345,7 +346,7 @@ static void UpdateDependentFonts(TkFontInfo *fiPtr, * font object points to the TkFont structure for the font, or NULL. */ -Tcl_ObjType tkFontObjType = { +const Tcl_ObjType tkFontObjType = { "font", /* name */ FreeFontObjProc, /* freeIntRepProc */ DupFontObjProc, /* dupIntRepProc */ @@ -376,9 +377,8 @@ void TkFontPkgInit( TkMainInfo *mainPtr) /* The application being created. */ { - TkFontInfo *fiPtr; + TkFontInfo *fiPtr = ckalloc(sizeof(TkFontInfo)); - fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo)); Tcl_InitHashTable(&fiPtr->fontCache, TCL_STRING_KEYS); Tcl_InitHashTable(&fiPtr->namedTable, TCL_STRING_KEYS); fiPtr->mainPtr = mainPtr; @@ -410,21 +410,18 @@ void TkFontPkgFree( TkMainInfo *mainPtr) /* The application being deleted. */ { - TkFontInfo *fiPtr; + TkFontInfo *fiPtr = mainPtr->fontInfoPtr; Tcl_HashEntry *hPtr, *searchPtr; Tcl_HashSearch search; - int fontsLeft; + int fontsLeft = 0; - fiPtr = mainPtr->fontInfoPtr; - - fontsLeft = 0; for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); searchPtr != NULL; searchPtr = Tcl_NextHashEntry(&search)) { fontsLeft++; #ifdef DEBUG_FONTS fprintf(stderr, "Font %s still in cache.\n", - Tcl_GetHashKey(&fiPtr->fontCache, searchPtr)); + (char *) Tcl_GetHashKey(&fiPtr->fontCache, searchPtr)); #endif } @@ -438,14 +435,14 @@ TkFontPkgFree( hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); while (hPtr != NULL) { - ckfree((char *) Tcl_GetHashValue(hPtr)); + ckfree(Tcl_GetHashValue(hPtr)); hPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&fiPtr->namedTable); - if (fiPtr->updatePending != 0) { - Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr); + if (fiPtr->updatePending) { + Tcl_CancelIdleCall(TheWorldHasChanged, fiPtr); } - ckfree((char *) fiPtr); + ckfree(fiPtr); } /* @@ -473,9 +470,9 @@ Tk_FontObjCmd( Tcl_Obj *const objv[]) /* Argument objects. */ { int index; - Tk_Window tkwin; - TkFontInfo *fiPtr; - static const char *optionStrings[] = { + Tk_Window tkwin = clientData; + TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; + static const char *const optionStrings[] = { "actual", "configure", "create", "delete", "families", "measure", "metrics", "names", NULL @@ -485,9 +482,6 @@ Tk_FontObjCmd( FONT_FAMILIES, FONT_MEASURE, FONT_METRICS, FONT_NAMES }; - tkwin = (Tk_Window) clientData; - fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; @@ -528,7 +522,7 @@ Tk_FontObjCmd( s = Tcl_GetString(objv[n]); if (s[0] == '-' && s[1] != '-') { optPtr = objv[n]; - ++n; + n++; } else { optPtr = NULL; } @@ -540,7 +534,7 @@ Tk_FontObjCmd( if (n < objc) { if (!strcmp(Tcl_GetString(objv[n]), "--")) { - ++n; + n++; } } @@ -550,7 +544,7 @@ Tk_FontObjCmd( if (n < objc) { charPtr = objv[n]; - ++n; + n++; } /* @@ -575,6 +569,7 @@ Tk_FontObjCmd( -1, 40, "..."); Tcl_AppendToObj(resultPtr, "\"", -1); Tcl_SetObjResult(interp, resultPtr); + Tcl_SetErrorCode(interp, "TK", "VALUE", "FONT_SAMPLE", NULL); return TCL_ERROR; } uniChar = Tcl_GetUniChar(charPtr, 0); @@ -605,47 +600,47 @@ Tk_FontObjCmd( return result; } case FONT_CONFIGURE: { - int result; - char *string; - Tcl_Obj *objPtr; - NamedFont *nfPtr; - Tcl_HashEntry *namedHashPtr; - - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?"); - return TCL_ERROR; - } - string = Tcl_GetString(objv[2]); - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); + int result; + const char *string; + Tcl_Obj *objPtr; + NamedFont *nfPtr; + Tcl_HashEntry *namedHashPtr; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "fontname ?-option value ...?"); + return TCL_ERROR; + } + string = Tcl_GetString(objv[2]); + namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); nfPtr = NULL; /* lint. */ - if (namedHashPtr != NULL) { - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - } - if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) { - Tcl_AppendResult(interp, "named font \"", string, - "\" doesn't exist", NULL); - return TCL_ERROR; - } - if (objc == 3) { - objPtr = NULL; - } else if (objc == 4) { - objPtr = objv[3]; - } else { - result = ConfigAttributesObj(interp, tkwin, objc - 3, objv + 3, - &nfPtr->fa); - UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); - return result; - } - return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr); - } + if (namedHashPtr != NULL) { + nfPtr = Tcl_GetHashValue(namedHashPtr); + } + if ((namedHashPtr == NULL) || nfPtr->deletePending) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "named font \"%s\" doesn't exist", string)); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "FONT", string, NULL); + return TCL_ERROR; + } + if (objc == 3) { + objPtr = NULL; + } else if (objc == 4) { + objPtr = objv[3]; + } else { + result = ConfigAttributesObj(interp, tkwin, objc - 3, objv + 3, + &nfPtr->fa); + UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); + return result; + } + return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr); + } case FONT_CREATE: { - int skip, i; - char *name; + int skip = 3, i; + const char *name; char buf[16 + TCL_INTEGER_SPACE]; TkFontAttributes fa; Tcl_HashEntry *namedHashPtr; - skip = 3; if (objc < 3) { name = NULL; } else { @@ -677,12 +672,12 @@ Tk_FontObjCmd( if (TkCreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) { return TCL_ERROR; } - Tcl_AppendResult(interp, name, NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(name, -1)); break; } case FONT_DELETE: { int i, result = TCL_OK; - char *string; + const char *string; /* * Delete the named font. If there are still widgets using this font, @@ -693,16 +688,15 @@ Tk_FontObjCmd( Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?"); return TCL_ERROR; } - for (i = 2; i < objc && result == TCL_OK; i++) { + for (i = 2; (i < objc) && (result == TCL_OK); i++) { string = Tcl_GetString(objv[i]); result = TkDeleteNamedFont(interp, tkwin, string); } return result; } case FONT_FAMILIES: { - int skip; + int skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); - skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); if (skip < 0) { return TCL_ERROR; } @@ -714,10 +708,9 @@ Tk_FontObjCmd( break; } case FONT_MEASURE: { - char *string; + const char *string; Tk_Font tkfont; int length = 0, skip = 0; - Tcl_Obj *resultPtr; if (objc > 4) { skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); @@ -726,7 +719,8 @@ Tk_FontObjCmd( } } if (objc - skip != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "font ?-displayof window? text"); + Tcl_WrongNumArgs(interp, 2, objv, + "font ?-displayof window? text"); return TCL_ERROR; } tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); @@ -734,8 +728,8 @@ Tk_FontObjCmd( return TCL_ERROR; } string = Tcl_GetStringFromObj(objv[3 + skip], &length); - resultPtr = Tcl_GetObjResult(interp); - Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length)); + Tcl_SetObjResult(interp, Tcl_NewIntObj( + Tk_TextWidth(tkfont, string, length))); Tk_FreeFont(tkfont); break; } @@ -743,7 +737,7 @@ Tk_FontObjCmd( Tk_Font tkfont; int skip, index, i; const TkFontMetrics *fmPtr; - static const char *switches[] = { + static const char *const switches[] = { "-ascent", "-descent", "-linespace", "-fixed", NULL }; @@ -764,12 +758,10 @@ Tk_FontObjCmd( 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", + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "-ascent %d -descent %d -linespace %d -fixed %d", fmPtr->ascent, fmPtr->descent, - fmPtr->ascent + fmPtr->descent, fmPtr->fixed); - Tcl_AppendResult(interp, buf, NULL); + fmPtr->ascent + fmPtr->descent, fmPtr->fixed)); } else { if (Tcl_GetIndexFromObj(interp, objv[3], switches, "metric", 0, &index) != TCL_OK) { @@ -783,33 +775,35 @@ Tk_FontObjCmd( case 2: i = fmPtr->ascent + fmPtr->descent; break; case 3: i = fmPtr->fixed; break; } - Tcl_SetIntObj(Tcl_GetObjResult(interp), i); + Tcl_SetObjResult(interp, Tcl_NewIntObj(i)); } Tk_FreeFont(tkfont); break; } case FONT_NAMES: { - char *string; - NamedFont *nfPtr; Tcl_HashSearch search; Tcl_HashEntry *namedHashPtr; - Tcl_Obj *strPtr, *resultPtr; + Tcl_Obj *resultPtr; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "names"); return TCL_ERROR; } - resultPtr = Tcl_GetObjResult(interp); + resultPtr = Tcl_NewObj(); namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); while (namedHashPtr != NULL) { - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - if (nfPtr->deletePending == 0) { - string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr); - strPtr = Tcl_NewStringObj(string, -1); - Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); + NamedFont *nfPtr = Tcl_GetHashValue(namedHashPtr); + + if (!nfPtr->deletePending) { + char *string = Tcl_GetHashKey(&fiPtr->namedTable, + namedHashPtr); + + Tcl_ListObjAppendElement(NULL, resultPtr, + Tcl_NewStringObj(string, -1)); } namedHashPtr = Tcl_NextHashEntry(&search); } + Tcl_SetObjResult(interp, resultPtr); break; } } @@ -844,9 +838,8 @@ UpdateDependentFonts( Tcl_HashEntry *cacheHashPtr; Tcl_HashSearch search; TkFont *fontPtr; - NamedFont *nfPtr; + NamedFont *nfPtr = Tcl_GetHashValue(namedHashPtr); - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); if (nfPtr->refCount == 0) { /* * Well nobody's using this named font, so don't have to tell any @@ -858,13 +851,13 @@ UpdateDependentFonts( cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); while (cacheHashPtr != NULL) { - for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); + for (fontPtr = Tcl_GetHashValue(cacheHashPtr); fontPtr != NULL; fontPtr = fontPtr->nextPtr) { if (fontPtr->namedHashPtr == namedHashPtr) { TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa); - if (fiPtr->updatePending == 0) { + if (!fiPtr->updatePending) { fiPtr->updatePending = 1; - Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr); + Tcl_DoWhenIdle(TheWorldHasChanged, fiPtr); } } } @@ -876,11 +869,9 @@ static void TheWorldHasChanged( ClientData clientData) /* Info about application's fonts. */ { - TkFontInfo *fiPtr; + TkFontInfo *fiPtr = clientData; - fiPtr = (TkFontInfo *) clientData; fiPtr->updatePending = 0; - RecomputeWidgets(fiPtr->mainPtr->winPtr); } @@ -888,10 +879,11 @@ static void RecomputeWidgets( TkWindow *winPtr) /* Window to which command is sent. */ { - Tk_ClassWorldChangedProc *proc; - proc = Tk_GetClassProc(winPtr->classProcsPtr, worldChangedProc); + Tk_ClassWorldChangedProc *proc = + Tk_GetClassProc(winPtr->classProcsPtr, worldChangedProc); + if (proc != NULL) { - (*proc)(winPtr->instanceData); + proc(winPtr->instanceData); } /* @@ -949,21 +941,19 @@ TkCreateNamedFont( const char *name, /* Name for the new named font. */ TkFontAttributes *faPtr) /* Attributes for the new named font. */ { - TkFontInfo *fiPtr; + TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; Tcl_HashEntry *namedHashPtr; int isNew; NamedFont *nfPtr; - fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &isNew); - if (!isNew) { - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - if (nfPtr->deletePending == 0) { + nfPtr = Tcl_GetHashValue(namedHashPtr); + if (!nfPtr->deletePending) { if (interp) { - Tcl_AppendResult(interp, "named font \"", name, - "\" already exists", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "named font \"%s\" already exists", name)); + Tcl_SetErrorCode(interp, "TK", "FONT", "EXISTS", NULL); } return TCL_ERROR; } @@ -980,7 +970,7 @@ TkCreateNamedFont( return TCL_OK; } - nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont)); + nfPtr = ckalloc(sizeof(NamedFont)); nfPtr->deletePending = 0; Tcl_SetHashValue(namedHashPtr, nfPtr); nfPtr->fa = *faPtr; @@ -1004,28 +994,27 @@ int TkDeleteNamedFont( Tcl_Interp *interp, /* Interp for error return (can be NULL). */ Tk_Window tkwin, /* A window associated with interp. */ - CONST char *name) /* Name for the new named font. */ + const char *name) /* Name for the new named font. */ { - TkFontInfo *fiPtr; + TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; NamedFont *nfPtr; Tcl_HashEntry *namedHashPtr; - fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, name); if (namedHashPtr == NULL) { if (interp) { - Tcl_AppendResult(interp, "named font \"", name, - "\" doesn't exist", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "named font \"%s\" doesn't exist", name)); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "FONT", name, NULL); } return TCL_ERROR; } - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); + nfPtr = Tcl_GetHashValue(namedHashPtr); if (nfPtr->refCount != 0) { nfPtr->deletePending = 1; } else { Tcl_DeleteHashEntry(namedHashPtr); - ckfree((char *) nfPtr); + ckfree(nfPtr); } return TCL_OK; } @@ -1062,7 +1051,7 @@ Tk_GetFont( Tk_Font tkfont; Tcl_Obj *strPtr; - strPtr = Tcl_NewStringObj((char *) string, -1); + strPtr = Tcl_NewStringObj(string, -1); Tcl_IncrRefCount(strPtr); tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr); Tcl_DecrRefCount(strPtr); @@ -1098,19 +1087,18 @@ Tk_AllocFontFromObj( Tcl_Obj *objPtr) /* Object describing font, as: named font, * native format, or parseable string. */ { - TkFontInfo *fiPtr; + TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; Tcl_HashEntry *cacheHashPtr, *namedHashPtr; TkFont *fontPtr, *firstFontPtr, *oldFontPtr; int isNew, descent; NamedFont *nfPtr; - fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - if (objPtr->typePtr != &tkFontObjType) { + if (objPtr->typePtr != &tkFontObjType + || objPtr->internalRep.twoPtrValue.ptr2 != fiPtr) { SetFontFromAny(interp, objPtr); } - oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; - + oldFontPtr = objPtr->internalRep.twoPtrValue.ptr1; if (oldFontPtr != NULL) { if (oldFontPtr->resourceRefCount == 0) { /* @@ -1118,7 +1106,7 @@ Tk_AllocFontFromObj( * longer in use. Clear the reference. */ - FreeFontObjProc(objPtr); + FreeFontObj(objPtr); oldFontPtr = NULL; } else if (Tk_Screen(tkwin) == oldFontPtr->screen) { oldFontPtr->resourceRefCount++; @@ -1134,18 +1122,19 @@ Tk_AllocFontFromObj( isNew = 0; if (oldFontPtr != NULL) { cacheHashPtr = oldFontPtr->cacheHashPtr; - FreeFontObjProc(objPtr); + FreeFontObj(objPtr); } else { cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr), &isNew); } - firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); + firstFontPtr = Tcl_GetHashValue(cacheHashPtr); for (fontPtr = firstFontPtr; (fontPtr != NULL); fontPtr = fontPtr->nextPtr) { if (Tk_Screen(tkwin) == fontPtr->screen) { fontPtr->resourceRefCount++; fontPtr->objRefCount++; - objPtr->internalRep.twoPtrValue.ptr1 = (void *) fontPtr; + objPtr->internalRep.twoPtrValue.ptr1 = fontPtr; + objPtr->internalRep.twoPtrValue.ptr2 = fiPtr; return (Tk_Font) fontPtr; } } @@ -1161,7 +1150,7 @@ Tk_AllocFontFromObj( * Construct a font based on a named font. */ - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); + nfPtr = Tcl_GetHashValue(namedHashPtr); nfPtr->refCount++; fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa); @@ -1200,8 +1189,10 @@ Tk_AllocFontFromObj( if (isNew) { Tcl_DeleteHashEntry(cacheHashPtr); } - Tcl_AppendResult(interp, "failed to allocate font due to ", - "internal system font engine problem", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "failed to allocate font due to internal system font engine" + " problem", -1)); + Tcl_SetErrorCode(interp, "TK", "FONT", "INTERNAL_PROBLEM", NULL); return NULL; } @@ -1253,7 +1244,8 @@ Tk_AllocFontFromObj( } } - objPtr->internalRep.twoPtrValue.ptr1 = (void *) fontPtr; + objPtr->internalRep.twoPtrValue.ptr1 = fontPtr; + objPtr->internalRep.twoPtrValue.ptr2 = fiPtr; return (Tk_Font) fontPtr; } @@ -1278,19 +1270,20 @@ Tk_AllocFontFromObj( Tk_Font Tk_GetFontFromObj( - Tk_Window tkwin, /* The window that the font will be used in. */ + Tk_Window tkwin, /* The window that the font will be used + * in. */ Tcl_Obj *objPtr) /* The object from which to get the font. */ { TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; TkFont *fontPtr; Tcl_HashEntry *hashPtr; - if (objPtr->typePtr != &tkFontObjType) { + if (objPtr->typePtr != &tkFontObjType + || objPtr->internalRep.twoPtrValue.ptr2 != fiPtr) { SetFontFromAny(NULL, objPtr); } - fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; - + fontPtr = objPtr->internalRep.twoPtrValue.ptr1; if (fontPtr != NULL) { if (fontPtr->resourceRefCount == 0) { /* @@ -1298,7 +1291,7 @@ Tk_GetFontFromObj( * longer in use. Clear the reference. */ - FreeFontObjProc(objPtr); + FreeFontObj(objPtr); fontPtr = NULL; } else if (Tk_Screen(tkwin) == fontPtr->screen) { return (Tk_Font) fontPtr; @@ -1312,16 +1305,17 @@ Tk_GetFontFromObj( if (fontPtr != NULL) { hashPtr = fontPtr->cacheHashPtr; - FreeFontObjProc(objPtr); + FreeFontObj(objPtr); } else { hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr)); } if (hashPtr != NULL) { - for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL; + for (fontPtr = Tcl_GetHashValue(hashPtr); fontPtr != NULL; fontPtr = fontPtr->nextPtr) { if (Tk_Screen(tkwin) == fontPtr->screen) { fontPtr->objRefCount++; - objPtr->internalRep.twoPtrValue.ptr1 = (void *) fontPtr; + objPtr->internalRep.twoPtrValue.ptr1 = fontPtr; + objPtr->internalRep.twoPtrValue.ptr2 = fiPtr; return (Tk_Font) fontPtr; } } @@ -1363,10 +1357,11 @@ SetFontFromAny( Tcl_GetString(objPtr); typePtr = objPtr->typePtr; if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { - (*typePtr->freeIntRepProc)(objPtr); + typePtr->freeIntRepProc(objPtr); } objPtr->typePtr = &tkFontObjType; objPtr->internalRep.twoPtrValue.ptr1 = NULL; + objPtr->internalRep.twoPtrValue.ptr2 = NULL; return TCL_OK; } @@ -1394,9 +1389,8 @@ const char * Tk_NameOfFont( Tk_Font tkfont) /* Font whose name is desired. */ { - TkFont *fontPtr; + TkFont *fontPtr = (TkFont *) tkfont; - fontPtr = (TkFont *) tkfont; return fontPtr->cacheHashPtr->key.string; } @@ -1421,13 +1415,12 @@ void Tk_FreeFont( Tk_Font tkfont) /* Font to be released. */ { - TkFont *fontPtr, *prevPtr; + TkFont *fontPtr = (TkFont *) tkfont, *prevPtr; NamedFont *nfPtr; - if (tkfont == NULL) { + if (fontPtr == NULL) { return; } - fontPtr = (TkFont *) tkfont; fontPtr->resourceRefCount--; if (fontPtr->resourceRefCount > 0) { return; @@ -1438,15 +1431,15 @@ Tk_FreeFont( * the named font and free it if no-one else is using it. */ - nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr); + nfPtr = Tcl_GetHashValue(fontPtr->namedHashPtr); nfPtr->refCount--; - if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) { + if ((nfPtr->refCount == 0) && nfPtr->deletePending) { Tcl_DeleteHashEntry(fontPtr->namedHashPtr); - ckfree((char *) nfPtr); + ckfree(nfPtr); } } - prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr); + prevPtr = Tcl_GetHashValue(fontPtr->cacheHashPtr); if (prevPtr == fontPtr) { if (fontPtr->nextPtr == NULL) { Tcl_DeleteHashEntry(fontPtr->cacheHashPtr); @@ -1462,7 +1455,7 @@ Tk_FreeFont( TkpDeleteFont(fontPtr); if (fontPtr->objRefCount == 0) { - ckfree((char *) fontPtr); + ckfree(fontPtr); } } @@ -1496,7 +1489,7 @@ Tk_FreeFontFromObj( /* *--------------------------------------------------------------------------- * - * FreeFontObjProc -- + * FreeFontObjProc, FreeFontObj -- * * This proc is called to release an object reference to a font. Called * when the object's internal rep is released or when the cached fontPtr @@ -1516,14 +1509,23 @@ static void FreeFontObjProc( Tcl_Obj *objPtr) /* The object we are releasing. */ { - TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; + FreeFontObj(objPtr); + objPtr->typePtr = NULL; +} + +static void +FreeFontObj( + Tcl_Obj *objPtr) /* The object we are releasing. */ +{ + TkFont *fontPtr = objPtr->internalRep.twoPtrValue.ptr1; if (fontPtr != NULL) { fontPtr->objRefCount--; if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) { - ckfree((char *) fontPtr); + ckfree(fontPtr); } objPtr->internalRep.twoPtrValue.ptr1 = NULL; + objPtr->internalRep.twoPtrValue.ptr2 = NULL; } } @@ -1550,10 +1552,12 @@ DupFontObjProc( 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; + TkFont *fontPtr = srcObjPtr->internalRep.twoPtrValue.ptr1; dupObjPtr->typePtr = srcObjPtr->typePtr; - dupObjPtr->internalRep.twoPtrValue.ptr1 = (void *) fontPtr; + dupObjPtr->internalRep.twoPtrValue.ptr1 = fontPtr; + dupObjPtr->internalRep.twoPtrValue.ptr2 + = srcObjPtr->internalRep.twoPtrValue.ptr2; if (fontPtr != NULL) { fontPtr->objRefCount++; @@ -1584,9 +1588,8 @@ Tk_FontId( Tk_Font tkfont) /* Font that is going to be selected into * GC. */ { - TkFont *fontPtr; + TkFont *fontPtr = (TkFont *) tkfont; - fontPtr = (TkFont *) tkfont; return fontPtr->fid; } @@ -1617,9 +1620,8 @@ Tk_GetFontMetrics( Tk_FontMetrics *fmPtr) /* Pointer to structure in which font metrics * for tkfont will be stored. */ { - TkFont *fontPtr; + TkFont *fontPtr = (TkFont *) tkfont; - fontPtr = (TkFont *) tkfont; fmPtr->ascent = fontPtr->fm.ascent; fmPtr->descent = fontPtr->fm.descent; fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent; @@ -1659,13 +1661,12 @@ Tk_PostscriptFontName( * which the name of the Postscript font that * corresponds to tkfont will be appended. */ { - TkFont *fontPtr; + TkFont *fontPtr = (TkFont *) tkfont; Tk_Uid family, weightString, slantString; char *src, *dest; int upper, len; len = Tcl_DStringLength(dsPtr); - fontPtr = (TkFont *) tkfont; /* * Convert the case-insensitive Tk_Font family name to the case-sensitive @@ -1763,7 +1764,7 @@ Tk_PostscriptFontName( slantString = NULL; if (fontPtr->fa.slant == TK_FS_ROMAN) { - ; + /* Do nothing */ } else if ((strcmp(family, "Helvetica") == 0) || (strcmp(family, "Courier") == 0) || (strcmp(family, "AvantGarde") == 0)) { @@ -1891,19 +1892,17 @@ TkUnderlineCharsInContext( int lastByte) /* Index of first byte after the last * character. */ { - TkFont *fontPtr; + TkFont *fontPtr = (TkFont *) tkfont; int startX, endX; - fontPtr = (TkFont *) tkfont; - TkpMeasureCharsInContext(tkfont, string, numBytes, 0, firstByte, -1, 0, &startX); TkpMeasureCharsInContext(tkfont, string, numBytes, 0, lastByte, -1, 0, &endX); XFillRectangle(display, drawable, gc, x + startX, - y + fontPtr->underlinePos, (unsigned int) (endX - startX), - (unsigned int) fontPtr->underlineHeight); + y + fontPtr->underlinePos, (unsigned) (endX - startX), + (unsigned) fontPtr->underlineHeight); } /* @@ -1954,7 +1953,7 @@ Tk_ComputeTextLayout( int *widthPtr, /* Filled with width of string. */ int *heightPtr) /* Filled with height of string. */ { - TkFont *fontPtr; + TkFont *fontPtr = (TkFont *) tkfont; const char *start, *end, *special; int n, y, bytesThisChunk, maxChunks, curLine, layoutHeight; int baseline, height, curX, newX, maxWidth, *lineLengths; @@ -1965,7 +1964,6 @@ Tk_ComputeTextLayout( Tcl_DStringInit(&lineBuffer); - fontPtr = (TkFont *) tkfont; if ((fontPtr == NULL) || (string == NULL)) { if (widthPtr != NULL) { *widthPtr = 0; @@ -1989,8 +1987,8 @@ Tk_ComputeTextLayout( maxChunks = 1; - layoutPtr = (TextLayout *) - ckalloc(sizeof(TextLayout) + (maxChunks-1) * sizeof(LayoutChunk)); + layoutPtr = ckalloc(sizeof(TextLayout) + + (maxChunks-1) * sizeof(LayoutChunk)); layoutPtr->tkfont = tkfont; layoutPtr->string = string; layoutPtr->numChunks = 0; @@ -2154,7 +2152,7 @@ Tk_ComputeTextLayout( * on the next line. Otherwise "Hello" and "Hello\n" are the same height. */ - if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) { + if ((layoutPtr->numChunks > 0) && !(flags & TK_IGNORE_NEWLINES)) { if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') { chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX, curX, baseline); @@ -2243,11 +2241,10 @@ void Tk_FreeTextLayout( Tk_TextLayout textLayout) /* The text layout to be released. */ { - TextLayout *layoutPtr; + TextLayout *layoutPtr = (TextLayout *) textLayout; - layoutPtr = (TextLayout *) textLayout; if (layoutPtr != NULL) { - ckfree((char *) layoutPtr); + ckfree(layoutPtr); } } @@ -2275,7 +2272,8 @@ void Tk_DrawTextLayout( Display *display, /* Display on which to draw. */ Drawable drawable, /* Window or pixmap in which to draw. */ - GC gc, /* Graphics context to use for drawing text. */ + GC gc, /* Graphics context to use for drawing + * text. */ Tk_TextLayout layout, /* Layout information, from a previous call to * Tk_ComputeTextLayout(). */ int x, int y, /* Upper-left hand corner of rectangle in @@ -2287,13 +2285,11 @@ Tk_DrawTextLayout( * draw from the given text item. A number < 0 * means to draw all characters. */ { - TextLayout *layoutPtr; + TextLayout *layoutPtr = (TextLayout *) layout; int i, numDisplayChars, drawX; - const char *firstByte; - const char *lastByte; + const char *firstByte, *lastByte; LayoutChunk *chunkPtr; - layoutPtr = (TextLayout *) layout; if (layoutPtr == NULL) { return; } @@ -2318,9 +2314,78 @@ Tk_DrawTextLayout( numDisplayChars = lastChar; } lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars); - Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, - firstByte, lastByte - firstByte, - x + chunkPtr->x + drawX, y + chunkPtr->y); + Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, firstByte, + lastByte - firstByte, x+chunkPtr->x+drawX, y+chunkPtr->y); + } + firstChar -= chunkPtr->numChars; + lastChar -= chunkPtr->numChars; + if (lastChar <= 0) { + break; + } + chunkPtr++; + } +} + +void +TkDrawAngledTextLayout( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context to use for drawing + * text. */ + Tk_TextLayout layout, /* Layout information, from a previous call to + * Tk_ComputeTextLayout(). */ + int x, int y, /* Upper-left hand corner of rectangle in + * which to draw (pixels). */ + double angle, + int firstChar, /* The index of the first character to draw + * from the given text item. 0 specfies the + * beginning. */ + int lastChar) /* The index just after the last character to + * draw from the given text item. A number < 0 + * means to draw all characters. */ +{ + TextLayout *layoutPtr = (TextLayout *) layout; + int i, numDisplayChars, drawX; + const char *firstByte, *lastByte; + LayoutChunk *chunkPtr; + double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); + + if (layoutPtr == NULL) { + return; + } + + if (lastChar < 0) { + lastChar = 100000000; + } + chunkPtr = layoutPtr->chunks; + for (i = 0; i < layoutPtr->numChunks; i++) { + numDisplayChars = chunkPtr->numDisplayChars; + if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) { + double dx, dy; + + if (firstChar <= 0) { + drawX = 0; + firstChar = 0; + firstByte = chunkPtr->start; + } else { + firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar); + Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, + firstByte - chunkPtr->start, -1, 0, &drawX); + } + if (lastChar < numDisplayChars) { + numDisplayChars = lastChar; + } + lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars); + dx = cosA * (chunkPtr->x + drawX) + sinA * (chunkPtr->y); + dy = -sinA * (chunkPtr->x + drawX) + cosA * (chunkPtr->y); + if (angle == 0.0) { + Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, + firstByte, lastByte - firstByte, + (int)(x + dx), (int)(y + dy)); + } else { + TkDrawAngledChars(display, drawable, gc, layoutPtr->tkfont, + firstByte, lastByte - firstByte, x+dx, y+dy, angle); + } } firstChar -= chunkPtr->numChars; lastChar -= chunkPtr->numChars; @@ -2366,18 +2431,79 @@ Tk_UnderlineTextLayout( int underline) /* Index of the single character to underline, * or -1 for no underline. */ { - TextLayout *layoutPtr; - TkFont *fontPtr; int xx, yy, width, height; if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0) && (width != 0)) { - layoutPtr = (TextLayout *) layout; - fontPtr = (TkFont *) layoutPtr->tkfont; + TextLayout *layoutPtr = (TextLayout *) layout; + TkFont *fontPtr = (TkFont *) layoutPtr->tkfont; XFillRectangle(display, drawable, gc, x + xx, y + yy + fontPtr->fm.ascent + fontPtr->underlinePos, - (unsigned int) width, (unsigned int) fontPtr->underlineHeight); + (unsigned) width, (unsigned) fontPtr->underlineHeight); + } +} + +void +TkUnderlineAngledTextLayout( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context to use for drawing + * text. */ + Tk_TextLayout layout, /* Layout information, from a previous call to + * Tk_ComputeTextLayout(). */ + int x, int y, /* Upper-left hand corner of rectangle in + * which to draw (pixels). */ + double angle, + int underline) /* Index of the single character to underline, + * or -1 for no underline. */ +{ + int xx, yy, width, height; + + if (angle == 0.0) { + Tk_UnderlineTextLayout(display, drawable, gc, layout, x,y, underline); + return; + } + + if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0) + && (width != 0)) { + TextLayout *layoutPtr = (TextLayout *) layout; + TkFont *fontPtr = (TkFont *) layoutPtr->tkfont; + double sinA = sin(angle*PI/180), cosA = cos(angle*PI/180); + double dy = yy + fontPtr->fm.ascent + fontPtr->underlinePos; + XPoint points[5]; + + /* + * Note that we're careful to only round a double value once, which + * minimizes roundoff errors. + */ + + points[0].x = x + ROUND16(xx*cosA + dy*sinA); + points[0].y = y + ROUND16(dy*cosA - xx*sinA); + points[1].x = x + ROUND16(xx*cosA + dy*sinA + width*cosA); + points[1].y = y + ROUND16(dy*cosA - xx*sinA - width*sinA); + if (fontPtr->underlineHeight == 1) { + /* + * Thin underlines look better when rotated when drawn as a line + * rather than a rectangle; the rasterizer copes better. + */ + + XDrawLines(display, drawable, gc, points, 2, CoordModeOrigin); + } else { + points[2].x = x + ROUND16(xx*cosA + dy*sinA + width*cosA + + fontPtr->underlineHeight*sinA); + points[2].y = y + ROUND16(dy*cosA - xx*sinA - width*sinA + + fontPtr->underlineHeight*cosA); + points[3].x = x + ROUND16(xx*cosA + dy*sinA + + fontPtr->underlineHeight*sinA); + points[3].y = y + ROUND16(dy*cosA - xx*sinA + + fontPtr->underlineHeight*cosA); + points[4].x = points[0].x; + points[4].y = points[0].y; + XFillPolygon(display, drawable, gc, points, 5, Complex, + CoordModeOrigin); + XDrawLines(display, drawable, gc, points, 5, CoordModeOrigin); + } } } @@ -2421,7 +2547,7 @@ Tk_PointToChar( * to the upper-left corner of the text * layout. */ { - TextLayout *layoutPtr; + TextLayout *layoutPtr = (TextLayout *) layout; LayoutChunk *chunkPtr, *lastPtr; TkFont *fontPtr; int i, n, dummy, baseline, pos, numChars; @@ -2439,7 +2565,6 @@ Tk_PointToChar( * Find which line contains the point. */ - layoutPtr = (TextLayout *) layout; fontPtr = (TkFont *) layoutPtr->tkfont; lastPtr = chunkPtr = layoutPtr->chunks; numChars = 0; @@ -2486,8 +2611,7 @@ Tk_PointToChar( return numChars; } n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start, - chunkPtr->numBytes, x - chunkPtr->x, - 0, &dummy); + chunkPtr->numBytes, x - chunkPtr->x, 0, &dummy); return numChars + Tcl_NumUtfChars(chunkPtr->start, n); } numChars += chunkPtr->numChars; @@ -2570,7 +2694,7 @@ Tk_CharBbox( * bounding box for the character specified by * index, if non-NULL. */ { - TextLayout *layoutPtr; + TextLayout *layoutPtr = (TextLayout *) layout; LayoutChunk *chunkPtr; int i, x = 0, w; Tk_Font tkfont; @@ -2581,7 +2705,6 @@ Tk_CharBbox( return 0; } - layoutPtr = (TextLayout *) layout; chunkPtr = layoutPtr->chunks; tkfont = layoutPtr->tkfont; fontPtr = (TkFont *) tkfont; @@ -2682,11 +2805,10 @@ Tk_DistanceToTextLayout( * (in pixels). */ { int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent; + TextLayout *layoutPtr = (TextLayout *) layout; LayoutChunk *chunkPtr; - TextLayout *layoutPtr; TkFont *fontPtr; - layoutPtr = (TextLayout *) layout; fontPtr = (TkFont *) layoutPtr->tkfont; ascent = fontPtr->fm.ascent; descent = fontPtr->fm.descent; @@ -2770,7 +2892,7 @@ Tk_IntersectTextLayout( * rectangular area, in pixels. */ { int result, i, x1, y1, x2, y2; - TextLayout *layoutPtr; + TextLayout *layoutPtr = (TextLayout *) layout; LayoutChunk *chunkPtr; TkFont *fontPtr; int left, top, right, bottom; @@ -2782,7 +2904,6 @@ Tk_IntersectTextLayout( * and see if they were all inside or all outside. */ - layoutPtr = (TextLayout *) layout; chunkPtr = layoutPtr->chunks; fontPtr = (TkFont *) layoutPtr->tkfont; @@ -2793,10 +2914,11 @@ Tk_IntersectTextLayout( result = 0; for (i = 0; i < layoutPtr->numChunks; i++) { - if (chunkPtr->start[0] == '\n') { + if ((chunkPtr->start[0] == '\n') || (chunkPtr->numBytes == 0)) { /* - * Newline characters are not counted when computing area - * intersection (but tab characters would still be considered). + * Newline characters and empty chunks are not counted when + * computing area intersection (but tab characters would still be + * considered). */ chunkPtr++; @@ -2830,6 +2952,263 @@ Tk_IntersectTextLayout( /* *--------------------------------------------------------------------------- * + * TkIntersectAngledTextLayout -- + * + * Determines whether a text layout that has been turned by an angle + * about its top-left coordinae lies entirely inside, entirely outside, + * or overlaps a given rectangle. Non-displaying space characters that + * occur at the end of individual lines in the text layout are ignored + * for intersection calculations. + * + * Results: + * The return value is -1 if the text layout is entirely outside of the + * rectangle, 0 if it overlaps, and 1 if it is entirely inside of the + * rectangle. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static inline int +PointInQuadrilateral( + double qx[], + double qy[], + double x, + double y) +{ + int i; + + for (i=0 ; i<4 ; i++) { + double sideDX = qx[(i+1)%4] - qx[i]; + double sideDY = qy[(i+1)%4] - qy[i]; + double dx = x - qx[i]; + double dy = y - qy[i]; + + if (sideDX*dy < sideDY*dx) { + return 0; + } + } + return 1; +} + +static inline int +sign( + double value) +{ + return (value < 0.0) ? -1 : (value > 0.0) ? 1 : 0; +} + +static inline int +SidesIntersect( + double ax1, double ay1, double ax2, double ay2, + double bx1, double by1, double bx2, double by2) +{ +#if 0 +/* http://www.freelunchdesign.com/cgi-bin/codwiki.pl?DiscussionTopics/CollideMeUpBaby */ + + double a1, b1, c1, a2, b2, c2, r1, r2, r3, r4, denom; + + a1 = ay2 - ay1; + b1 = ax1 - ax2; + c1 = (ax2 * ay1) - (ax1 * ay2); + r3 = (a1 * bx1) + (b1 * by1) + c1; + r4 = (a1 * bx2) + (b1 * by2) + c1; + if ((r3 != 0.0) && (r4 != 0.0) && (r3*r4 > 0.0)) { + return 0; + } + + a2 = by2 - by1; + b2 = bx1 - bx2; + c2 = (bx2 * by1) - (bx1 * by2); + r1 = (a2 * ax1) + (b2 * ay1) + c2; + r2 = (a2 * ax2) + (b2 * ay2) + c2; + if ((r1 != 0.0) && (r2 != 0.0) && (r1*r2 > 0.0)) { + return 0; + } + + denom = (a1 * b2) - (a2 * b1); + return (denom != 0.0); +#else + /* + * A more efficient version. Two line segments intersect if, when seen + * from the perspective of one line, the two endpoints of the other + * segment lie on opposite sides of the line, and vice versa. "Lie on + * opposite sides" is computed by taking the cross products and seeing if + * they are of opposite signs. + */ + + double dx, dy, dx1, dy1; + + dx = ax2 - ax1; + dy = ay2 - ay1; + dx1 = bx1 - ax1; + dy1 = by1 - ay1; + if ((dx*dy1-dy*dx1 > 0.0) == (dx*(by2-ay1)-dy*(bx2-ax1) > 0.0)) { + return 0; + } + dx = bx2 - bx1; + dy = by2 - by1; + if ((dy*dx1-dx*dy1 > 0.0) == (dx*(ay2-by1)-dy*(ax2-bx1) > 0.0)) { + return 0; + } + return 1; +#endif +} + +int +TkIntersectAngledTextLayout( + Tk_TextLayout layout, /* Layout information, from a previous call to + * Tk_ComputeTextLayout(). */ + int x, int y, /* Upper-left hand corner, in pixels, of + * rectangular area to compare with text + * layout. Coordinates are with respect to the + * upper-left hand corner of the text layout + * itself. */ + int width, int height, /* The width and height of the above + * rectangular area, in pixels. */ + double angle) +{ + int i, x1, y1, x2, y2; + TextLayout *layoutPtr; + LayoutChunk *chunkPtr; + TkFont *fontPtr; + double c = cos(angle * PI/180.0), s = sin(angle * PI/180.0); + double rx[4], ry[4]; + + if (angle == 0.0) { + return Tk_IntersectTextLayout(layout, x, y, width, height); + } + + /* + * Compute the coordinates of the rectangle, rotated into text layout + * space. + */ + + rx[0] = x*c - y*s; + ry[0] = y*c + x*s; + rx[1] = (x+width)*c - y*s; + ry[1] = y*c + (x+width)*s; + rx[2] = (x+width)*c - (y+height)*s; + ry[2] = (y+height)*c + (x+width)*s; + rx[3] = x*c - (y+height)*s; + ry[3] = (y+height)*c + x*s; + + /* + * Want to know if all chunks are inside the rectangle, or if there is any + * overlap. First, we check to see if all chunks are inside; if and only + * if they are, we're in the "inside" case. + */ + + layoutPtr = (TextLayout *) layout; + chunkPtr = layoutPtr->chunks; + fontPtr = (TkFont *) layoutPtr->tkfont; + + for (i=0 ; i<layoutPtr->numChunks ; i++,chunkPtr++) { + if (chunkPtr->start[0] == '\n') { + /* + * Newline characters are not counted when computing area + * intersection (but tab characters would still be considered). + */ + + continue; + } + + x1 = chunkPtr->x; + y1 = chunkPtr->y - fontPtr->fm.ascent; + x2 = chunkPtr->x + chunkPtr->displayWidth; + y2 = chunkPtr->y + fontPtr->fm.descent; + if ( !PointInQuadrilateral(rx, ry, x1, y1) || + !PointInQuadrilateral(rx, ry, x2, y1) || + !PointInQuadrilateral(rx, ry, x2, y2) || + !PointInQuadrilateral(rx, ry, x1, y2)) { + goto notInside; + } + } + return 1; + + /* + * Next, check to see if all the points of the rectangle are inside a + * single chunk; if they are, we're in an "overlap" case. + */ + + notInside: + chunkPtr = layoutPtr->chunks; + + for (i=0 ; i<layoutPtr->numChunks ; i++,chunkPtr++) { + double cx[4], cy[4]; + + if (chunkPtr->start[0] == '\n') { + /* + * Newline characters are not counted when computing area + * intersection (but tab characters would still be considered). + */ + + continue; + } + + cx[0] = cx[3] = chunkPtr->x; + cy[0] = cy[1] = chunkPtr->y - fontPtr->fm.ascent; + cx[1] = cx[2] = chunkPtr->x + chunkPtr->displayWidth; + cy[2] = cy[3] = chunkPtr->y + fontPtr->fm.descent; + if ( !PointInQuadrilateral(cx, cy, rx[0], ry[0]) || + !PointInQuadrilateral(cx, cy, rx[1], ry[1]) || + !PointInQuadrilateral(cx, cy, rx[2], ry[2]) || + !PointInQuadrilateral(cx, cy, rx[3], ry[3])) { + goto notReverseInside; + } + } + return 0; + + /* + * If we're overlapping now, we must be partially in and out of at least + * one chunk. If that is the case, there must be one line segment of the + * rectangle that is touching or crossing a line segment of a chunk. + */ + + notReverseInside: + chunkPtr = layoutPtr->chunks; + + for (i=0 ; i<layoutPtr->numChunks ; i++,chunkPtr++) { + int j; + + if (chunkPtr->start[0] == '\n') { + /* + * Newline characters are not counted when computing area + * intersection (but tab characters would still be considered). + */ + + continue; + } + + x1 = chunkPtr->x; + y1 = chunkPtr->y - fontPtr->fm.ascent; + x2 = chunkPtr->x + chunkPtr->displayWidth; + y2 = chunkPtr->y + fontPtr->fm.descent; + + for (j=0 ; j<4 ; j++) { + int k = (j+1) % 4; + + if ( SidesIntersect(rx[j],ry[j], rx[k],ry[k], x1,y1, x2,y1) || + SidesIntersect(rx[j],ry[j], rx[k],ry[k], x2,y1, x2,y2) || + SidesIntersect(rx[j],ry[j], rx[k],ry[k], x2,y2, x1,y2) || + SidesIntersect(rx[j],ry[j], rx[k],ry[k], x1,y2, x1,y1)) { + return 0; + } + } + } + + /* + * They must be wholly non-overlapping. + */ + + return -1; +} + +/* + *--------------------------------------------------------------------------- + * * Tk_TextLayoutToPostscript -- * * Outputs the contents of a text layout in Postscript format. The set of @@ -2870,112 +3249,93 @@ Tk_TextLayoutToPostscript( Tcl_Interp *interp, /* Filled with Postscript code. */ Tk_TextLayout layout) /* The layout to be rendered. */ { -#define MAXUSE 128 - char buf[MAXUSE+30], uindex[5] = "\0\0\0\0", one_char[5]; - LayoutChunk *chunkPtr; - int i, j, used, c, baseline, charsize; + TextLayout *layoutPtr = (TextLayout *) layout; + LayoutChunk *chunkPtr = layoutPtr->chunks; + int baseline = chunkPtr->y; + Tcl_Obj *psObj = Tcl_NewObj(); + int i, j, len; + const char *p, *glyphname; + char uindex[5], c, *ps; Tcl_UniChar ch; - const char *p, *last_p, *glyphname; - TextLayout *layoutPtr; - int bytecount=0; - layoutPtr = (TextLayout *) layout; - chunkPtr = layoutPtr->chunks; - baseline = chunkPtr->y; - used = 0; - buf[used++] = '['; - buf[used++] = '('; - for (i = 0; i < layoutPtr->numChunks; i++) { + Tcl_AppendToObj(psObj, "[(", -1); + for (i = 0; i < layoutPtr->numChunks; i++, chunkPtr++) { if (baseline != chunkPtr->y) { - buf[used++] = ')'; - buf[used++] = ']'; - buf[used++] = '\n'; - buf[used++] = '['; - buf[used++] = '('; + Tcl_AppendToObj(psObj, ")]\n[(", -1); baseline = chunkPtr->y; } if (chunkPtr->numDisplayChars <= 0) { if (chunkPtr->start[0] == '\t') { - buf[used++] = '\\'; - buf[used++] = 't'; + Tcl_AppendToObj(psObj, "\\t", -1); } - } else { - p = chunkPtr->start; - for (j = 0; j < chunkPtr->numDisplayChars; j++) { + continue; + } + + for (p=chunkPtr->start, j=0; j<chunkPtr->numDisplayChars; j++) { + /* + * INTL: We only handle symbols that have an encoding as a glyph + * from the standard set defined by Adobe. The rest get punted. + * Eventually this should be revised to handle more sophsticiated + * international postscript fonts. + */ + + p += Tcl_UtfToUniChar(p, &ch); + if ((ch == '(') || (ch == ')') || (ch == '\\') || (ch < 0x20)) { /* - * 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. + * Tricky point: the "03" is necessary in the sprintf below, + * so that a full three digits of octal are always generated. + * Without the "03", a number following this sequence could be + * interpreted by Postscript as part of this sequence. */ - last_p = p; - p += (charsize = Tcl_UtfToUniChar(p,&ch)); - Tcl_UtfToExternal(interp, NULL, last_p, charsize, 0, NULL, - one_char, 4, NULL, &bytecount, NULL); - if (bytecount == 1) { - c = UCHAR(one_char[0]); - /* c = UCHAR( ch & 0xFF) */; - if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20) - || (c >= UCHAR(0x7f))) { - /* - * Tricky point: the "03" is necessary in the sprintf - * below, so that a full three digits of octal are - * always generated. Without the "03", a number - * following this sequence could be interpreted by - * Postscript as part of this sequence. - */ + Tcl_AppendPrintfToObj(psObj, "\\%03o", ch); + continue; + } else if (ch <= 0x7f) { + /* + * Normal ASCII character. + */ - sprintf(buf + used, "\\%03o", c); - used += 4; - } else { - buf[used++] = c; - } - } else { + c = (char) ch; + Tcl_AppendToObj(psObj, &c, 1); + continue; + } + + /* + * This character doesn't belong to the ASCII character set, so we + * use the full glyph name. + */ + + sprintf(uindex, "%04X", ch); /* endianness? */ + glyphname = Tcl_GetVar2(interp, "::tk::psglyphs", uindex, 0); + if (glyphname) { + ps = Tcl_GetStringFromObj(psObj, &len); + if (ps[len-1] == '(') { /* - * This character doesn't belong to system character set. - * So, we must use full glyph name. + * In-place edit. Ewww! */ - sprintf(uindex, "%04X", ch); /* endianness? */ - glyphname = Tcl_GetVar2(interp,"::tk::psglyphs",uindex,0); - if (glyphname) { - if (used > 0 && buf [used-1] == '(') { - --used; - } else { - buf[used++] = ')'; - } - buf[used++] = '/'; - while ((*glyphname) && (used < (MAXUSE+27))) { - buf[used++] = *glyphname++ ; - } - buf[used++] = '('; - } - - } - if (used >= MAXUSE) { - buf[used] = '\0'; - Tcl_AppendResult(interp, buf, NULL); - used = 0; + ps[len-1] = '/'; + } else { + Tcl_AppendToObj(psObj, ")/", -1); } - } - } - if (used >= MAXUSE) { - /* - * If there are a whole bunch of returns or tabs in a row, then - * buf[] could get filled up. - */ + Tcl_AppendToObj(psObj, glyphname, -1); + Tcl_AppendToObj(psObj, "(", -1); + } else { + /* + * No known mapping for the character into the space of + * PostScript glyphs. Ignore it. :-( + */ - buf[used] = '\0'; - Tcl_AppendResult(interp, buf, NULL); - used = 0; +#ifdef TK_DEBUG_POSTSCRIPT_OUTPUT + fprintf(stderr, "Warning: no mapping to PostScript " + "glyphs for \\u%04x\n", ch); +#endif + } } - chunkPtr++; } - buf[used++] = ')'; - buf[used++] = ']'; - buf[used++] = '\n'; - buf[used] = '\0'; - Tcl_AppendResult(interp, buf, NULL); + Tcl_AppendToObj(psObj, ")]\n", -1); + Tcl_AppendObjToObj(Tcl_GetObjResult(interp), psObj); + Tcl_DecrRefCount(psObj); } /* @@ -3011,7 +3371,7 @@ ConfigAttributesObj( { int i, n, index; Tcl_Obj *optionPtr, *valuePtr; - char *value; + const char *value; for (i = 0; i < objc; i += 2) { optionPtr = objv[i]; @@ -3028,8 +3388,10 @@ ConfigAttributesObj( */ if (interp != NULL) { - Tcl_AppendResult(interp, "value for \"", - Tcl_GetString(optionPtr), "\" option missing", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "value for \"%s\" option missing", + Tcl_GetString(optionPtr))); + Tcl_SetErrorCode(interp, "TK", "FONT", "NO_ATTRIBUTE", NULL); } return TCL_ERROR; } @@ -3110,9 +3472,7 @@ GetAttributeInfoObj( { int i, index, start, end; const char *str; - Tcl_Obj *optionPtr, *valuePtr, *resultPtr; - - resultPtr = Tcl_GetObjResult(interp); + Tcl_Obj *valuePtr, *resultPtr = NULL; start = 0; end = FONT_NUMFIELDS; @@ -3126,6 +3486,9 @@ GetAttributeInfoObj( } valuePtr = NULL; + if (objPtr == NULL) { + resultPtr = Tcl_NewObj(); + } for (i = start; i < end; i++) { switch (i) { case FONT_FAMILY: @@ -3159,10 +3522,11 @@ GetAttributeInfoObj( Tcl_SetObjResult(interp, valuePtr); return TCL_OK; } - optionPtr = Tcl_NewStringObj(fontOpt[i], -1); - Tcl_ListObjAppendElement(NULL, resultPtr, optionPtr); + Tcl_ListObjAppendElement(NULL, resultPtr, + Tcl_NewStringObj(fontOpt[i], -1)); Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr); } + Tcl_SetObjResult(interp, resultPtr); return TCL_OK; } @@ -3204,7 +3568,7 @@ ParseFontNameObj( char *dash; int objc, result, i, n; Tcl_Obj **objv; - char *string; + const char *string; TkInitFontAttributes(faPtr); @@ -3222,7 +3586,7 @@ ParseFontNameObj( } dash = strchr(string + 1, '-'); if ((dash != NULL) - && (!isspace(UCHAR(dash[-1])))) { /* INTL: ISO space */ + && !isspace(UCHAR(dash[-1]))) { /* INTL: ISO space */ goto xlfd; } @@ -3270,8 +3634,9 @@ ParseFontNameObj( if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) || (objc < 1)) { if (interp != NULL) { - Tcl_AppendResult(interp, "font \"", string, "\" doesn't exist", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "font \"%s\" doesn't exist", string)); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "FONT", string, NULL); } return TCL_ERROR; } @@ -3318,8 +3683,10 @@ ParseFontNameObj( */ if (interp != NULL) { - Tcl_AppendResult(interp, "unknown font style \"", - Tcl_GetString(objv[i]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown font style \"%s\"", Tcl_GetString(objv[i]))); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "FONT_STYLE", + Tcl_GetString(objv[i]), NULL); } return TCL_ERROR; } @@ -3367,7 +3734,7 @@ NewChunk( if (layoutPtr->numChunks == maxChunks) { maxChunks *= 2; s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk)); - layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s); + layoutPtr = ckrealloc(layoutPtr, s); *layoutPtrPtr = layoutPtr; *maxPtr = maxChunks; @@ -3439,7 +3806,7 @@ TkFontParseXLFD( } Tcl_DStringInit(&ds); - Tcl_DStringAppend(&ds, (char *) str, -1); + Tcl_DStringAppend(&ds, str, -1); src = Tcl_DStringValue(&ds); field[0] = src; @@ -3472,7 +3839,7 @@ TkFontParseXLFD( * parsed set of attributes)". */ - if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) { + if ((i > XLFD_ADD_STYLE) && FieldSpecified(field[XLFD_ADD_STYLE])) { if (atoi(field[XLFD_ADD_STYLE]) != 0) { for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) { field[j + 1] = field[j]; @@ -3701,7 +4068,6 @@ TkFontGetPoints( * platform expects when asking for the font. * * Results: - * As above. The return value is NULL if the font name has no aliases. * * Side effects: @@ -3710,7 +4076,7 @@ TkFontGetPoints( *------------------------------------------------------------------------- */ -char ** +const char *const * TkFontGetAliasList( const char *faceName) /* Font name to test for aliases. */ { @@ -3743,7 +4109,7 @@ TkFontGetAliasList( *------------------------------------------------------------------------- */ -char *** +const char *const *const * TkFontGetFallbacks(void) { return fontFallbacks; @@ -3768,7 +4134,7 @@ TkFontGetFallbacks(void) *------------------------------------------------------------------------- */ -char ** +const char *const * TkFontGetGlobalClass(void) { return globalFontClass; @@ -3791,7 +4157,7 @@ TkFontGetGlobalClass(void) *------------------------------------------------------------------------- */ -char ** +const char *const * TkFontGetSymbolClass(void) { return symbolClass; @@ -3819,7 +4185,7 @@ Tcl_Obj * TkDebugFont( Tk_Window tkwin, /* The window in which the font will be used * (not currently used). */ - char *name) /* Name of the desired color. */ + const char *name) /* Name of the desired color. */ { TkFont *fontPtr; Tcl_HashEntry *hashPtr; @@ -3829,7 +4195,7 @@ TkDebugFont( hashPtr = Tcl_FindHashEntry( &((TkWindow *) tkwin)->mainPtr->fontInfoPtr->fontCache, name); if (hashPtr != NULL) { - fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); + fontPtr = Tcl_GetHashValue(hashPtr); if (fontPtr == NULL) { Tcl_Panic("TkDebugFont found empty hash table entry"); } @@ -3871,12 +4237,11 @@ TkFontGetFirstTextLayout( Tk_Font *font, char *dst) { - TextLayout *layoutPtr; + TextLayout *layoutPtr = (TextLayout *) layout; LayoutChunk *chunkPtr; int numBytesInChunk; - layoutPtr = (TextLayout *)layout; - if ((layoutPtr==NULL) || (layoutPtr->numChunks==0) + if ((layoutPtr == NULL) || (layoutPtr->numChunks == 0) || (layoutPtr->chunks->numDisplayChars <= 0)) { dst[0] = '\0'; return 0; |