summaryrefslogtreecommitdiffstats
path: root/generic/tkObj.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tkObj.c')
-rw-r--r--generic/tkObj.c163
1 files changed, 105 insertions, 58 deletions
diff --git a/generic/tkObj.c b/generic/tkObj.c
index dad50e2..8877d42 100644
--- a/generic/tkObj.c
+++ b/generic/tkObj.c
@@ -7,8 +7,6 @@
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkObj.c,v 1.28 2010/02/13 13:47:49 nijtmans Exp $
*/
#include "tkInt.h"
@@ -41,6 +39,19 @@ typedef struct PixelRep {
#define GET_COMPLEXPIXEL(objPtr) \
((PixelRep *) (objPtr)->internalRep.twoPtrValue.ptr2)
+/*
+ * One of these structures is created per thread to store thread-specific
+ * data. In this case, it is used to contain references to selected
+ * Tcl_ObjTypes that we can use as screen distances without conversion. The
+ * "dataKey" below is used to locate the ThreadSpecificData for the current
+ * thread.
+ */
+
+typedef struct ThreadSpecificData {
+ const Tcl_ObjType *doubleTypePtr;
+ const Tcl_ObjType *intTypePtr;
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
/*
* The following structure is the internal representation for mm objects.
@@ -71,11 +82,12 @@ typedef struct WindowRep {
*/
static void DupMMInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
-static void DupPixelInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
-static void DupWindowInternalRep(Tcl_Obj *srcPtr,Tcl_Obj *copyPtr);
+static void DupPixelInternalRep(Tcl_Obj *srcPtr, Tcl_Obj*copyPtr);
+static void DupWindowInternalRep(Tcl_Obj *srcPtr,Tcl_Obj*copyPtr);
static void FreeMMInternalRep(Tcl_Obj *objPtr);
static void FreePixelInternalRep(Tcl_Obj *objPtr);
static void FreeWindowInternalRep(Tcl_Obj *objPtr);
+static ThreadSpecificData *GetTypeCache(void);
static void UpdateStringOfMM(Tcl_Obj *objPtr);
static int SetMMFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static int SetPixelFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
@@ -125,6 +137,31 @@ static const Tcl_ObjType windowObjType = {
/*
*----------------------------------------------------------------------
*
+ * GetTypeCache --
+ *
+ * Get (and build if necessary) the cache of useful Tcl object types for
+ * comparisons in the conversion functions. This allows optimized checks
+ * for standard cases.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static ThreadSpecificData *
+GetTypeCache(void)
+{
+ ThreadSpecificData *tsdPtr =
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ if (tsdPtr->doubleTypePtr == NULL) {
+ tsdPtr->doubleTypePtr = Tcl_GetObjType("double");
+ tsdPtr->intTypePtr = Tcl_GetObjType("int");
+ }
+ return tsdPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* GetPixelsFromObjEx --
*
* Attempt to return a pixel value from the Tcl object "objPtr". If the
@@ -152,54 +189,74 @@ GetPixelsFromObjEx(
int *intPtr,
double *dblPtr) /* Places to store resulting pixels. */
{
- int result,fresh;
+ int result, fresh;
double d;
PixelRep *pixelPtr;
static const double bias[] = {
1.0, 10.0, 25.4, 0.35278 /*25.4 / 72.0*/
};
- retry:
+ /*
+ * Special hacks where the type of the object is known to be something
+ * that is just numeric and cannot require distance conversion. This pokes
+ * holes in Tcl's abstractions, but they are just for optimization, not
+ * semantics.
+ */
+
if (objPtr->typePtr != &pixelObjType) {
+ ThreadSpecificData *typeCache = GetTypeCache();
+
+ if (objPtr->typePtr == typeCache->doubleTypePtr) {
+ (void) Tcl_GetDoubleFromObj(interp, objPtr, &d);
+ if (dblPtr != NULL) {
+ *dblPtr = d;
+ }
+ *intPtr = (int) (d<0 ? d-0.5 : d+0.5);
+ return TCL_OK;
+ } else if (objPtr->typePtr == typeCache->intTypePtr) {
+ (void) Tcl_GetIntFromObj(interp, objPtr, intPtr);
+ if (dblPtr) {
+ *dblPtr = (double) (*intPtr);
+ }
+ return TCL_OK;
+ }
+ }
+
+ retry:
+ fresh = (objPtr->typePtr != &pixelObjType);
+ if (fresh) {
result = SetPixelFromAny(interp, objPtr);
if (result != TCL_OK) {
return result;
}
- fresh=1;
- } else {
- fresh=0;
}
if (SIMPLE_PIXELREP(objPtr)) {
*intPtr = GET_SIMPLEPIXEL(objPtr);
if (dblPtr) {
- *dblPtr=(double)(*intPtr);
+ *dblPtr = (double) (*intPtr);
}
} else {
pixelPtr = GET_COMPLEXPIXEL(objPtr);
- if ((!fresh) && (pixelPtr->tkwin != tkwin))
- {
- /* in case of exo-screen conversions of non-pixels
- * we force a recomputation from the string
- */
-
- FreePixelInternalRep(objPtr);
- goto retry;
- }
- if ((pixelPtr->tkwin != tkwin)||dblPtr) {
+ if ((!fresh) && (pixelPtr->tkwin != tkwin)) {
+ /*
+ * In the case of exo-screen conversions of non-pixels, we force a
+ * recomputation from the string.
+ */
+
+ FreePixelInternalRep(objPtr);
+ goto retry;
+ }
+ if ((pixelPtr->tkwin != tkwin) || dblPtr) {
d = pixelPtr->value;
if (pixelPtr->units >= 0) {
d *= bias[pixelPtr->units] * WidthOfScreen(Tk_Screen(tkwin));
d /= WidthMMOfScreen(Tk_Screen(tkwin));
}
- if (d < 0) {
- pixelPtr->returnValue = (int) (d - 0.5);
- } else {
- pixelPtr->returnValue = (int) (d + 0.5);
- }
+ pixelPtr->returnValue = (int) (d<0 ? d-0.5 : d+0.5);
pixelPtr->tkwin = tkwin;
if (dblPtr) {
- *dblPtr=(double)d;
+ *dblPtr = d;
}
}
*intPtr = pixelPtr->returnValue;
@@ -235,7 +292,7 @@ Tk_GetPixelsFromObj(
Tcl_Obj *objPtr, /* The object from which to get pixels. */
int *intPtr) /* Place to store resulting pixels. */
{
- return GetPixelsFromObjEx(interp,tkwin,objPtr,intPtr,NULL);
+ return GetPixelsFromObjEx(interp, tkwin, objPtr, intPtr, NULL);
}
/*
@@ -267,19 +324,22 @@ Tk_GetDoublePixelsFromObj(
double *doublePtr) /* Place to store resulting pixels. */
{
double d;
- int result,val;
+ int result, val;
- result=GetPixelsFromObjEx(interp, tkwin, objPtr, &val, &d);
+ result = GetPixelsFromObjEx(interp, tkwin, objPtr, &val, &d);
if (result != TCL_OK) {
return result;
}
- if (!SIMPLE_PIXELREP(objPtr)) {
- PixelRep *pixelPtr;
- pixelPtr = GET_COMPLEXPIXEL(objPtr);
+ if (objPtr->typePtr == &pixelObjType && !SIMPLE_PIXELREP(objPtr)) {
+ PixelRep *pixelPtr = GET_COMPLEXPIXEL(objPtr);
+
if (pixelPtr->units >= 0) {
- /* internally "shimmer" to pixel units */
- pixelPtr->units=-1;
- pixelPtr->value=d;
+ /*
+ * Internally "shimmer" to pixel units.
+ */
+
+ pixelPtr->units = -1;
+ pixelPtr->value = d;
}
}
*doublePtr = d;
@@ -308,10 +368,9 @@ static void
FreePixelInternalRep(
Tcl_Obj *objPtr) /* Pixel object with internal rep to free. */
{
- PixelRep *pixelPtr;
-
if (!SIMPLE_PIXELREP(objPtr)) {
- pixelPtr = GET_COMPLEXPIXEL(objPtr);
+ PixelRep *pixelPtr = GET_COMPLEXPIXEL(objPtr);
+
ckfree(pixelPtr);
}
SET_SIMPLEPIXEL(objPtr, 0);
@@ -341,13 +400,13 @@ DupPixelInternalRep(
register Tcl_Obj *srcPtr, /* Object with internal rep to copy. */
register Tcl_Obj *copyPtr) /* Object with internal rep to set. */
{
- PixelRep *oldPtr, *newPtr;
-
copyPtr->typePtr = srcPtr->typePtr;
if (SIMPLE_PIXELREP(srcPtr)) {
SET_SIMPLEPIXEL(copyPtr, GET_SIMPLEPIXEL(srcPtr));
} else {
+ PixelRep *oldPtr, *newPtr;
+
oldPtr = GET_COMPLEXPIXEL(srcPtr);
newPtr = ckalloc(sizeof(PixelRep));
newPtr->value = oldPtr->value;
@@ -637,6 +696,7 @@ SetMMFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr) /* The object to convert. */
{
+ ThreadSpecificData *typeCache = GetTypeCache();
const Tcl_ObjType *typePtr;
const char *string;
char *rest;
@@ -644,23 +704,10 @@ SetMMFromAny(
int units;
MMRep *mmPtr;
- static const Tcl_ObjType *tclDoubleObjType = NULL;
- static const Tcl_ObjType *tclIntObjType = NULL;
-
- if (tclDoubleObjType == NULL) {
- /*
- * Cache the object types for comaprison below. This allows optimized
- * checks for standard cases.
- */
-
- tclDoubleObjType = Tcl_GetObjType("double");
- tclIntObjType = Tcl_GetObjType("int");
- }
-
- if (objPtr->typePtr == tclDoubleObjType) {
+ if (objPtr->typePtr == typeCache->doubleTypePtr) {
Tcl_GetDoubleFromObj(interp, objPtr, &d);
units = -1;
- } else if (objPtr->typePtr == tclIntObjType) {
+ } else if (objPtr->typePtr == typeCache->intTypePtr) {
Tcl_GetIntFromObj(interp, objPtr, &units);
d = (double) units;
units = -1;
@@ -979,12 +1026,12 @@ TkParsePadAmount(
Tcl_Obj **objv; /* The objects in the list */
/*
- * Check for a common case where a single object would otherwise
- * be shimmered between a list and a pixel spec.
+ * Check for a common case where a single object would otherwise be
+ * shimmered between a list and a pixel spec.
*/
if (specObj->typePtr == &pixelObjType) {
- if (Tk_GetPixelsFromObj(interp, tkwin, specObj, &firstInt) != TCL_OK) {
+ if (Tk_GetPixelsFromObj(interp, tkwin, specObj, &firstInt) != TCL_OK){
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad pad value \"",
Tcl_GetString(specObj),