diff options
Diffstat (limited to 'tk8.6/generic/tkCanvUtil.c')
-rw-r--r-- | tk8.6/generic/tkCanvUtil.c | 1869 |
1 files changed, 1869 insertions, 0 deletions
diff --git a/tk8.6/generic/tkCanvUtil.c b/tk8.6/generic/tkCanvUtil.c new file mode 100644 index 0000000..cbbc2b4 --- /dev/null +++ b/tk8.6/generic/tkCanvUtil.c @@ -0,0 +1,1869 @@ +/* + * tkCanvUtil.c -- + * + * This file contains a collection of utility functions used by the + * implementations of various canvas item types. + * + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#include "tkInt.h" +#include "tkCanvas.h" +#include <assert.h> + +/* + * Structures defined only in this file. + */ + +typedef struct SmoothAssocData { + struct SmoothAssocData *nextPtr; + /* Pointer to next SmoothAssocData. */ + Tk_SmoothMethod smooth; /* Name and functions associated with this + * option. */ +} SmoothAssocData; + +const Tk_SmoothMethod tkBezierSmoothMethod = { + "true", + TkMakeBezierCurve, + (void (*) (Tcl_Interp *interp, Tk_Canvas canvas, double *coordPtr, + int numPoints, int numSteps)) TkMakeBezierPostscript, +}; +static const Tk_SmoothMethod tkRawSmoothMethod = { + "raw", + TkMakeRawCurve, + (void (*) (Tcl_Interp *interp, Tk_Canvas canvas, double *coordPtr, + int numPoints, int numSteps)) TkMakeRawCurvePostscript, +}; + +/* + * Function forward-declarations. + */ + +static void SmoothMethodCleanupProc(ClientData clientData, + Tcl_Interp *interp); +static SmoothAssocData *InitSmoothMethods(Tcl_Interp *interp); +static int DashConvert(char *l, const char *p, int n, + double width); +static void TranslateAndAppendCoords(TkCanvas *canvPtr, + double x, double y, XPoint *outArr, int numOut); +static inline Tcl_Obj * GetPostscriptBuffer(Tcl_Interp *interp); + +#define ABS(a) ((a>=0)?(a):(-(a))) + +static inline Tcl_Obj * +GetPostscriptBuffer( + Tcl_Interp *interp) +{ + Tcl_Obj *psObj = Tcl_GetObjResult(interp); + + if (Tcl_IsShared(psObj)) { + psObj = Tcl_DuplicateObj(psObj); + Tcl_SetObjResult(interp, psObj); + } + return psObj; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_CanvasTkwin -- + * + * Given a token for a canvas, this function returns the widget that + * represents the canvas. + * + * Results: + * The return value is a handle for the widget. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tk_Window +Tk_CanvasTkwin( + Tk_Canvas canvas) /* Token for the canvas. */ +{ + return Canvas(canvas)->tkwin; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_CanvasDrawableCoords -- + * + * Given an (x,y) coordinate pair within a canvas, this function + * returns the corresponding coordinates at which the point should + * be drawn in the drawable used for display. + * + * Results: + * There is no return value. The values at *drawableXPtr and + * *drawableYPtr are filled in with the coordinates at which x and y + * should be drawn. These coordinates are clipped to fit within a + * "short", since this is what X uses in most cases for drawing. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tk_CanvasDrawableCoords( + Tk_Canvas canvas, /* Token for the canvas. */ + double x, /* Coordinates in canvas space. */ + double y, + short *drawableXPtr, /* Screen coordinates are stored here. */ + short *drawableYPtr) +{ + double tmp; + + tmp = x - Canvas(canvas)->drawableXOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + if (tmp > 32767) { + *drawableXPtr = 32767; + } else if (tmp < -32768) { + *drawableXPtr = -32768; + } else { + *drawableXPtr = (short) tmp; + } + + tmp = y - Canvas(canvas)->drawableYOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + if (tmp > 32767) { + *drawableYPtr = 32767; + } else if (tmp < -32768) { + *drawableYPtr = -32768; + } else { + *drawableYPtr = (short) tmp; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_CanvasWindowCoords -- + * + * Given an (x,y) coordinate pair within a canvas, this function returns + * the corresponding coordinates in the canvas's window. + * + * Results: + * There is no return value. The values at *screenXPtr and *screenYPtr + * are filled in with the coordinates at which (x,y) appears in the + * canvas's window. These coordinates are clipped to fit within a + * "short", since this is what X uses in most cases for drawing. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tk_CanvasWindowCoords( + Tk_Canvas canvas, /* Token for the canvas. */ + double x, /* Coordinates in canvas space. */ + double y, + short *screenXPtr, /* Screen coordinates are stored here. */ + short *screenYPtr) +{ + double tmp; + + tmp = x - Canvas(canvas)->xOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + if (tmp > 32767) { + *screenXPtr = 32767; + } else if (tmp < -32768) { + *screenXPtr = -32768; + } else { + *screenXPtr = (short) tmp; + } + + tmp = y - Canvas(canvas)->yOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + if (tmp > 32767) { + *screenYPtr = 32767; + } else if (tmp < -32768) { + *screenYPtr = -32768; + } else { + *screenYPtr = (short) tmp; + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasGetCoord -- + * + * Given a string, returns a floating-point canvas coordinate + * corresponding to that string. + * + * Results: + * The return value is a standard Tcl return result. If TCL_OK is + * returned, then everything went well and the canvas coordinate is + * stored at *doublePtr; otherwise TCL_ERROR is returned and an error + * message is left in the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasGetCoord( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_Canvas canvas, /* Canvas to which coordinate applies. */ + const char *string, /* Describes coordinate (any screen coordinate + * form may be used here). */ + double *doublePtr) /* Place to store converted coordinate. */ +{ + if (Tk_GetScreenMM(Canvas(canvas)->interp, Canvas(canvas)->tkwin, string, + doublePtr) != TCL_OK) { + return TCL_ERROR; + } + *doublePtr *= Canvas(canvas)->pixelsPerMM; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasGetCoordFromObj -- + * + * Given a string, returns a floating-point canvas coordinate + * corresponding to that string. + * + * Results: + * The return value is a standard Tcl return result. If TCL_OK is + * returned, then everything went well and the canvas coordinate is + * stored at *doublePtr; otherwise TCL_ERROR is returned and an error + * message is left in interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasGetCoordFromObj( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_Canvas canvas, /* Canvas to which coordinate applies. */ + Tcl_Obj *obj, /* Describes coordinate (any screen coordinate + * form may be used here). */ + double *doublePtr) /* Place to store converted coordinate. */ +{ + return Tk_GetDoublePixelsFromObj(Canvas(canvas)->interp, Canvas(canvas)->tkwin, obj, doublePtr); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_CanvasSetStippleOrigin -- + * + * This function sets the stipple origin in a graphics context so that + * stipples drawn with the GC will line up with other stipples previously + * drawn in the canvas. + * + * Results: + * None. + * + * Side effects: + * The graphics context is modified. + * + *---------------------------------------------------------------------- + */ + +void +Tk_CanvasSetStippleOrigin( + Tk_Canvas canvas, /* Token for a canvas. */ + GC gc) /* Graphics context that is about to be used + * to draw a stippled pattern as part of + * redisplaying the canvas. */ +{ + XSetTSOrigin(Canvas(canvas)->display, gc, + -Canvas(canvas)->drawableXOrigin, + -Canvas(canvas)->drawableYOrigin); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_CanvasSetOffset-- + * + * This function sets the stipple offset in a graphics context so that + * stipples drawn with the GC will line up with other stipples with the + * same offset. + * + * Results: + * None. + * + * Side effects: + * The graphics context is modified. + * + *---------------------------------------------------------------------- + */ + +void +Tk_CanvasSetOffset( + Tk_Canvas canvas, /* Token for a canvas. */ + GC gc, /* Graphics context that is about to be used + * to draw a stippled pattern as part of + * redisplaying the canvas. */ + Tk_TSOffset *offset) /* Offset (may be NULL pointer)*/ +{ + register TkCanvas *canvasPtr = Canvas(canvas); + int flags = 0; + int x = - canvasPtr->drawableXOrigin; + int y = - canvasPtr->drawableYOrigin; + + if (offset != NULL) { + flags = offset->flags; + x += offset->xoffset; + y += offset->yoffset; + } + if ((flags & TK_OFFSET_RELATIVE) && !(flags & TK_OFFSET_INDEX)) { + Tk_SetTSOrigin(canvasPtr->tkwin, gc, x - canvasPtr->xOrigin, + y - canvasPtr->yOrigin); + } else { + XSetTSOrigin(canvasPtr->display, gc, x, y); + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_CanvasGetTextInfo -- + * + * This function returns a pointer to a structure containing information + * about the selection and insertion cursor for a canvas widget. Items + * such as text items save the pointer and use it to share access to the + * information with the generic canvas code. + * + * Results: + * The return value is a pointer to the structure holding text + * information for the canvas. Most of the fields should not be modified + * outside the generic canvas code; see the user documentation for + * details. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tk_CanvasTextInfo * +Tk_CanvasGetTextInfo( + Tk_Canvas canvas) /* Token for the canvas widget. */ +{ + return &Canvas(canvas)->textInfo; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasTagsParseProc -- + * + * This function is invoked during option processing to handle "-tags" + * options for canvas items. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The tags for a given item get replaced by those indicated in the value + * argument. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasTagsParseProc( + ClientData clientData, /* Not used.*/ + Tcl_Interp *interp, /* Used for reporting errors. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + const char *value, /* Value of option (list of tag names). */ + char *widgRec, /* Pointer to record for item. */ + int offset) /* Offset into item (ignored). */ +{ + register Tk_Item *itemPtr = (Tk_Item *) widgRec; + int argc, i; + const char **argv; + Tk_Uid *newPtr; + + /* + * Break the value up into the individual tag names. + */ + + if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Make sure that there's enough space in the item to hold the tag names. + */ + + if (itemPtr->tagSpace < argc) { + newPtr = ckalloc(argc * sizeof(Tk_Uid)); + for (i = itemPtr->numTags-1; i >= 0; i--) { + newPtr[i] = itemPtr->tagPtr[i]; + } + if (itemPtr->tagPtr != itemPtr->staticTagSpace) { + ckfree(itemPtr->tagPtr); + } + itemPtr->tagPtr = newPtr; + itemPtr->tagSpace = argc; + } + itemPtr->numTags = argc; + for (i = 0; i < argc; i++) { + itemPtr->tagPtr[i] = Tk_GetUid(argv[i]); + } + ckfree(argv); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasTagsPrintProc -- + * + * This function is invoked by the Tk configuration code to produce a + * printable string for the "-tags" configuration option for canvas + * items. + * + * Results: + * The return value is a string describing all the tags for the item + * referred to by "widgRec". In addition, *freeProcPtr is filled in with + * the address of a function to call to free the result string when it's + * no longer needed (or NULL to indicate that the string doesn't need to + * be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +const char * +Tk_CanvasTagsPrintProc( + ClientData clientData, /* Ignored. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + char *widgRec, /* Pointer to record for item. */ + int offset, /* Ignored. */ + Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with + * information about how to reclaim storage + * for return string. */ +{ + register Tk_Item *itemPtr = (Tk_Item *) widgRec; + + if (itemPtr->numTags == 0) { + *freeProcPtr = NULL; + return ""; + } + if (itemPtr->numTags == 1) { + *freeProcPtr = NULL; + return (const char *) itemPtr->tagPtr[0]; + } + *freeProcPtr = TCL_DYNAMIC; + return Tcl_Merge(itemPtr->numTags, (const char **) itemPtr->tagPtr); +} + +/* + *-------------------------------------------------------------- + * + * TkCanvasDashParseProc -- + * + * This function is invoked during option processing to handle "-dash", + * "-activedash" and "-disableddash" options for canvas objects. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The dash list for a given canvas object gets replaced by those + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkCanvasDashParseProc( + ClientData clientData, /* Not used.*/ + Tcl_Interp *interp, /* Used for reporting errors. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + const char *value, /* Value of option. */ + char *widgRec, /* Pointer to record for item. */ + int offset) /* Offset into item. */ +{ + return Tk_GetDash(interp, value, (Tk_Dash *) (widgRec+offset)); +} + +/* + *-------------------------------------------------------------- + * + * TkCanvasDashPrintProc -- + * + * This function is invoked by the Tk configuration code to produce a + * printable string for the "-dash", "-activedash" and "-disableddash" + * configuration options for canvas items. + * + * Results: + * The return value is a string describing all the dash list for the item + * referred to by "widgRec"and "offset". In addition, *freeProcPtr is + * filled in with the address of a function to call to free the result + * string when it's no longer needed (or NULL to indicate that the string + * doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +const char * +TkCanvasDashPrintProc( + ClientData clientData, /* Ignored. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + char *widgRec, /* Pointer to record for item. */ + int offset, /* Offset in record for item. */ + Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with + * information about how to reclaim storage + * for return string. */ +{ + Tk_Dash *dash = (Tk_Dash *) (widgRec+offset); + char *buffer, *p; + int i = dash->number; + + if (i < 0) { + i = -i; + *freeProcPtr = TCL_DYNAMIC; + buffer = ckalloc(i + 1); + p = (i > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + memcpy(buffer, p, (unsigned int) i); + buffer[i] = 0; + return buffer; + } else if (!i) { + *freeProcPtr = NULL; + return ""; + } + buffer = ckalloc(4 * i); + *freeProcPtr = TCL_DYNAMIC; + + p = (i > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + sprintf(buffer, "%d", *p++ & 0xff); + while (--i) { + sprintf(buffer+strlen(buffer), " %d", *p++ & 0xff); + } + return buffer; +} + +/* + *-------------------------------------------------------------- + * + * InitSmoothMethods -- + * + * This function is invoked to set up the initial state of the list of + * "-smooth" methods. It should only be called when the list installed + * in the interpreter is NULL. + * + * Results: + * Pointer to the start of the list of default smooth methods. + * + * Side effects: + * A linked list of smooth methods is created and attached to the + * interpreter's association key "smoothMethod" + * + *-------------------------------------------------------------- + */ + +static SmoothAssocData * +InitSmoothMethods( + Tcl_Interp *interp) +{ + SmoothAssocData *methods, *ptr; + + methods = ckalloc(sizeof(SmoothAssocData)); + methods->smooth.name = tkRawSmoothMethod.name; + methods->smooth.coordProc = tkRawSmoothMethod.coordProc; + methods->smooth.postscriptProc = tkRawSmoothMethod.postscriptProc; + + ptr = methods->nextPtr = ckalloc(sizeof(SmoothAssocData)); + ptr->smooth.name = tkBezierSmoothMethod.name; + ptr->smooth.coordProc = tkBezierSmoothMethod.coordProc; + ptr->smooth.postscriptProc = tkBezierSmoothMethod.postscriptProc; + ptr->nextPtr = NULL; + + Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc,methods); + return methods; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreateSmoothMethod -- + * + * This function is invoked to add additional values for the "-smooth" + * option to the list. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * In the future "-smooth <name>" will be accepted as smooth method for + * the line and polygon. + * + *-------------------------------------------------------------- + */ + +void +Tk_CreateSmoothMethod( + Tcl_Interp *interp, + const Tk_SmoothMethod *smooth) +{ + SmoothAssocData *methods, *typePtr2, *prevPtr, *ptr; + methods = Tcl_GetAssocData(interp, "smoothMethod", NULL); + + /* + * Initialize if we were not previously initialized. + */ + + if (methods == NULL) { + methods = InitSmoothMethods(interp); + } + + /* + * If there's already a smooth method with the given name, remove it. + */ + + for (typePtr2 = methods, prevPtr = NULL; typePtr2 != NULL; + prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) { + if (!strcmp(typePtr2->smooth.name, smooth->name)) { + if (prevPtr == NULL) { + methods = typePtr2->nextPtr; + } else { + prevPtr->nextPtr = typePtr2->nextPtr; + } + ckfree(typePtr2); + break; + } + } + ptr = ckalloc(sizeof(SmoothAssocData)); + ptr->smooth.name = smooth->name; + ptr->smooth.coordProc = smooth->coordProc; + ptr->smooth.postscriptProc = smooth->postscriptProc; + ptr->nextPtr = methods; + Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc, ptr); +} + +/* + *---------------------------------------------------------------------- + * + * SmoothMethodCleanupProc -- + * + * This function is invoked whenever an interpreter is deleted to + * cleanup the smooth methods. + * + * Results: + * None. + * + * Side effects: + * Smooth methods are removed. + * + *---------------------------------------------------------------------- + */ + +static void +SmoothMethodCleanupProc( + ClientData clientData, /* Points to "smoothMethod" AssocData for the + * interpreter. */ + Tcl_Interp *interp) /* Interpreter that is being deleted. */ +{ + SmoothAssocData *ptr, *methods = clientData; + + while (methods != NULL) { + ptr = methods; + methods = methods->nextPtr; + ckfree(ptr); + } +} +/* + *-------------------------------------------------------------- + * + * TkSmoothParseProc -- + * + * This function is invoked during option processing to handle the + * "-smooth" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The smooth option for a given item gets replaced by the value + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkSmoothParseProc( + ClientData clientData, /* Ignored. */ + Tcl_Interp *interp, /* Used for reporting errors. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + const char *value, /* Value of option. */ + char *widgRec, /* Pointer to record for item. */ + int offset) /* Offset into item. */ +{ + register const Tk_SmoothMethod **smoothPtr = + (const Tk_SmoothMethod **) (widgRec + offset); + const Tk_SmoothMethod *smooth = NULL; + int b; + size_t length; + SmoothAssocData *methods; + + if (value == NULL || *value == 0) { + *smoothPtr = NULL; + return TCL_OK; + } + length = strlen(value); + methods = Tcl_GetAssocData(interp, "smoothMethod", NULL); + + /* + * Not initialized yet; fix that now. + */ + + if (methods == NULL) { + methods = InitSmoothMethods(interp); + } + + /* + * Backward compatability hack. + */ + + if (strncmp(value, "bezier", length) == 0) { + smooth = &tkBezierSmoothMethod; + } + + /* + * Search the list of installed smooth methods. + */ + + while (methods != NULL) { + if (strncmp(value, methods->smooth.name, length) == 0) { + if (smooth != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "ambiguous smooth method \"%s\"", value)); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "SMOOTH", value, + NULL); + return TCL_ERROR; + } + smooth = &methods->smooth; + } + methods = methods->nextPtr; + } + if (smooth) { + *smoothPtr = smooth; + return TCL_OK; + } + + /* + * Did not find it. Try parsing as a boolean instead. + */ + + if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) { + return TCL_ERROR; + } + *smoothPtr = b ? &tkBezierSmoothMethod : NULL; + return TCL_OK; +} +/* + *-------------------------------------------------------------- + * + * TkSmoothPrintProc -- + * + * This function is invoked by the Tk configuration code to produce a + * printable string for the "-smooth" configuration option. + * + * Results: + * The return value is a string describing the smooth option for the item + * referred to by "widgRec". In addition, *freeProcPtr is filled in with + * the address of a function to call to free the result string when it's + * no longer needed (or NULL to indicate that the string doesn't need to + * be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +const char * +TkSmoothPrintProc( + ClientData clientData, /* Ignored. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + char *widgRec, /* Pointer to record for item. */ + int offset, /* Offset into item. */ + Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with + * information about how to reclaim storage + * for return string. */ +{ + register const Tk_SmoothMethod *smoothPtr = + * (Tk_SmoothMethod **) (widgRec + offset); + + return smoothPtr ? smoothPtr->name : "0"; +} +/* + *-------------------------------------------------------------- + * + * Tk_GetDash + * + * This function is used to parse a string, assuming it is dash + * information. + * + * Results: + * The return value is a standard Tcl result: TCL_OK means that the dash + * information was parsed ok, and TCL_ERROR means it couldn't be parsed. + * + * Side effects: + * Dash information in the dash structure is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_GetDash( + Tcl_Interp *interp, /* Used for error reporting. */ + const char *value, /* Textual specification of dash list. */ + Tk_Dash *dash) /* Pointer to record in which to store dash + * information. */ +{ + int argc, i; + const char **largv, **argv = NULL; + char *pt; + + if ((value == NULL) || (*value == '\0')) { + dash->number = 0; + return TCL_OK; + } + + /* + * switch is usually compiled more efficiently than a chain of conditions. + */ + + switch (*value) { + case '.': case ',': case '-': case '_': + i = DashConvert(NULL, value, -1, 0.0); + if (i <= 0) { + goto badDashList; + } + i = strlen(value); + if (i > (int) sizeof(char *)) { + dash->pattern.pt = pt = ckalloc(strlen(value)); + } else { + pt = dash->pattern.array; + } + memcpy(pt, value, (unsigned) i); + dash->number = -i; + return TCL_OK; + } + + if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) { + Tcl_ResetResult(interp); + goto badDashList; + } + + if ((unsigned) ABS(dash->number) > sizeof(char *)) { + ckfree(dash->pattern.pt); + } + if (argc > (int) sizeof(char *)) { + dash->pattern.pt = pt = ckalloc(argc); + } else { + pt = dash->pattern.array; + } + dash->number = argc; + + largv = argv; + while (argc > 0) { + if (Tcl_GetInt(interp, *largv, &i) != TCL_OK || i < 1 || i>255) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected integer in the range 1..255 but got \"%s\"", + *largv)); + Tcl_SetErrorCode(interp, "TK", "VALUE", "DASH", NULL); + goto syntaxError; + } + *pt++ = i; + argc--; + largv++; + } + + if (argv != NULL) { + ckfree(argv); + } + return TCL_OK; + + /* + * Something went wrong. Generate error message, clean up and return. + */ + + badDashList: + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad dash list \"%s\": must be a list of integers or a format like \"-..\"", + value)); + Tcl_SetErrorCode(interp, "TK", "VALUE", "DASH", NULL); + syntaxError: + if (argv != NULL) { + ckfree(argv); + } + if ((unsigned) ABS(dash->number) > sizeof(char *)) { + ckfree(dash->pattern.pt); + } + dash->number = 0; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreateOutline + * + * This function initializes the Tk_Outline structure with default + * values. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +void +Tk_CreateOutline( + Tk_Outline *outline) /* Outline structure to be filled in. */ +{ + outline->gc = None; + outline->width = 1.0; + outline->activeWidth = 0.0; + outline->disabledWidth = 0.0; + outline->offset = 0; + outline->dash.number = 0; + outline->activeDash.number = 0; + outline->disabledDash.number = 0; + outline->tsoffset.flags = 0; + outline->tsoffset.xoffset = 0; + outline->tsoffset.yoffset = 0; + outline->color = NULL; + outline->activeColor = NULL; + outline->disabledColor = NULL; + outline->stipple = None; + outline->activeStipple = None; + outline->disabledStipple = None; +} + +/* + *-------------------------------------------------------------- + * + * Tk_DeleteOutline + * + * This function frees all memory that might be allocated and referenced + * in the Tk_Outline structure. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +void +Tk_DeleteOutline( + Display *display, /* Display containing window. */ + Tk_Outline *outline) +{ + if (outline->gc != None) { + Tk_FreeGC(display, outline->gc); + } + if ((unsigned) ABS(outline->dash.number) > sizeof(char *)) { + ckfree(outline->dash.pattern.pt); + } + if ((unsigned) ABS(outline->activeDash.number) > sizeof(char *)) { + ckfree(outline->activeDash.pattern.pt); + } + if ((unsigned) ABS(outline->disabledDash.number) > sizeof(char *)) { + ckfree(outline->disabledDash.pattern.pt); + } + if (outline->color != NULL) { + Tk_FreeColor(outline->color); + } + if (outline->activeColor != NULL) { + Tk_FreeColor(outline->activeColor); + } + if (outline->disabledColor != NULL) { + Tk_FreeColor(outline->disabledColor); + } + if (outline->stipple != None) { + Tk_FreeBitmap(display, outline->stipple); + } + if (outline->activeStipple != None) { + Tk_FreeBitmap(display, outline->activeStipple); + } + if (outline->disabledStipple != None) { + Tk_FreeBitmap(display, outline->disabledStipple); + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_ConfigOutlineGC + * + * This function should be called in the canvas object during the + * configure command. The graphics context description in gcValues is + * updated according to the information in the dash structure, as far as + * possible. + * + * Results: + * The return-value is a mask, indicating which elements of gcValues have + * been updated. 0 means there is no outline. + * + * Side effects: + * GC information in gcValues is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_ConfigOutlineGC( + XGCValues *gcValues, + Tk_Canvas canvas, + Tk_Item *item, + Tk_Outline *outline) +{ + int mask = 0; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + if (outline->width < 0.0) { + outline->width = 0.0; + } + if (outline->activeWidth < 0.0) { + outline->activeWidth = 0.0; + } + if (outline->disabledWidth < 0) { + outline->disabledWidth = 0.0; + } + if (state==TK_STATE_HIDDEN) { + return 0; + } + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if (state == TK_STATE_NULL) { + state = Canvas(canvas)->canvas_state; + } + if (Canvas(canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state == TK_STATE_DISABLED) { + if (outline->disabledWidth>0) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + + if (color==NULL) { + return 0; + } + + gcValues->line_width = (int) (width + 0.5); + if (color != NULL) { + gcValues->foreground = color->pixel; + mask = GCForeground|GCLineWidth; + if (stipple != None) { + gcValues->stipple = stipple; + gcValues->fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + } + if (mask && (dash->number != 0)) { + gcValues->line_style = LineOnOffDash; + gcValues->dash_offset = outline->offset; + if (dash->number > 0) { + gcValues->dashes = dash->pattern.array[0]; + } else { + gcValues->dashes = (char) (4 * width + 0.5); + } + mask |= GCLineStyle|GCDashList|GCDashOffset; + } + return mask; +} + +/* + *-------------------------------------------------------------- + * + * Tk_ChangeOutlineGC + * + * Updates the GC to represent the full information of the dash + * structure. Partly this is already done in Tk_ConfigOutlineGC(). This + * function should be called just before drawing the dashed item. + * + * Results: + * 1 if there is a stipple pattern, and 0 otherwise. + * + * Side effects: + * GC is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_ChangeOutlineGC( + Tk_Canvas canvas, + Tk_Item *item, + Tk_Outline *outline) +{ + const char *p; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if (state == TK_STATE_NULL) { + state = Canvas(canvas)->canvas_state; + } + if (Canvas(canvas)->currentItemPtr == item) { + if (outline->activeWidth > width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor != NULL) { + color = outline->activeColor; + } + if (outline->activeStipple != None) { + stipple = outline->activeStipple; + } + } else if (state == TK_STATE_DISABLED) { + if (outline->disabledWidth > width) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor != NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple != None) { + stipple = outline->disabledStipple; + } + } + if (color==NULL) { + return 0; + } + + if ((dash->number<-1) || + ((dash->number == -1) && (dash->pattern.array[0] != ','))) { + char *q; + int i = -dash->number; + + p = (i > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + q = ckalloc(2 * i); + i = DashConvert(q, p, i, width); + XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset, q,i); + ckfree(q); + } else if (dash->number>2 || (dash->number==2 && + (dash->pattern.array[0]!=dash->pattern.array[1]))) { + p = (dash->number > (int) sizeof(char *)) + ? dash->pattern.pt : dash->pattern.array; + XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset, p, + dash->number); + } + if (stipple!=None) { + int w = 0; int h = 0; + Tk_TSOffset *tsoffset = &outline->tsoffset; + int flags = tsoffset->flags; + + if (!(flags & TK_OFFSET_INDEX) && + (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) { + Tk_SizeOfBitmap(Canvas(canvas)->display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + Tk_CanvasSetOffset(canvas, outline->gc, tsoffset); + tsoffset->xoffset += w; + tsoffset->yoffset += h; + return 1; + } + return 0; +} + + +/* + *-------------------------------------------------------------- + * + * Tk_ResetOutlineGC + * + * Restores the GC to the situation before Tk_ChangeOutlineGC() was + * called. This function should be called just after the dashed item is + * drawn, because the GC is supposed to be read-only. + * + * Results: + * 1 if there is a stipple pattern, and 0 otherwise. + * + * Side effects: + * GC is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_ResetOutlineGC( + Tk_Canvas canvas, + Tk_Item *item, + Tk_Outline *outline) +{ + char dashList; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if (state == TK_STATE_NULL) { + state = Canvas(canvas)->canvas_state; + } + if (Canvas(canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state == TK_STATE_DISABLED) { + if (outline->disabledWidth>width) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + if (color==NULL) { + return 0; + } + + if ((dash->number > 2) || (dash->number < -1) || (dash->number==2 && + (dash->pattern.array[0] != dash->pattern.array[1])) || + ((dash->number == -1) && (dash->pattern.array[0] != ','))) { + if (dash->number > 0) { + dashList = dash->pattern.array[0]; + } else { + dashList = (char) (4 * width + 0.5); + } + XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset, + &dashList , 1); + } + if (stipple != None) { + XSetTSOrigin(Canvas(canvas)->display, outline->gc, 0, 0); + return 1; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsOutline + * + * Creates the postscript command for the correct Outline-information + * (width, dash, color and stipple). + * + * Results: + * TCL_OK if succeeded, otherwise TCL_ERROR. + * + * Side effects: + * canvas->interp->result contains the postscript string, or an error + * message if the result was TCL_ERROR. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsOutline( + Tk_Canvas canvas, + Tk_Item *item, + Tk_Outline *outline) +{ + char pattern[11]; + int i; + char *ptr, *lptr = pattern; + Tcl_Interp *interp = Canvas(canvas)->interp; + double width = outline->width; + Tk_Dash *dash = &outline->dash; + XColor *color = outline->color; + Pixmap stipple = outline->stipple; + Tk_State state = item->state; + Tcl_Obj *psObj = GetPostscriptBuffer(interp); + + if (state == TK_STATE_NULL) { + state = Canvas(canvas)->canvas_state; + } + + if (Canvas(canvas)->currentItemPtr == item) { + if (outline->activeWidth > width) { + width = outline->activeWidth; + } + if (outline->activeDash.number > 0) { + dash = &outline->activeDash; + } + if (outline->activeColor != NULL) { + color = outline->activeColor; + } + if (outline->activeStipple != None) { + stipple = outline->activeStipple; + } + } else if (state == TK_STATE_DISABLED) { + if (outline->disabledWidth > 0) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number > 0) { + dash = &outline->disabledDash; + } + if (outline->disabledColor != NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple != None) { + stipple = outline->disabledStipple; + } + } + + Tcl_AppendPrintfToObj(psObj, "%.15g setlinewidth\n", width); + + ptr = ((unsigned) ABS(dash->number) > sizeof(char *)) ? + dash->pattern.pt : dash->pattern.array; + Tcl_AppendToObj(psObj, "[", -1); + if (dash->number > 0) { + Tcl_Obj *converted; + char *p = ptr; + + converted = Tcl_ObjPrintf("%d", *p++ & 0xff); + for (i = dash->number-1 ; i>0 ; i--) { + Tcl_AppendPrintfToObj(converted, " %d", *p++ & 0xff); + } + Tcl_AppendObjToObj(psObj, converted); + if (dash->number & 1) { + Tcl_AppendToObj(psObj, " ", -1); + Tcl_AppendObjToObj(psObj, converted); + } + Tcl_DecrRefCount(converted); + Tcl_AppendPrintfToObj(psObj, "] %d setdash\n", outline->offset); + } else if (dash->number < 0) { + if (dash->number < -5) { + lptr = ckalloc(1 - 2*dash->number); + } + i = DashConvert(lptr, ptr, -dash->number, width); + if (i > 0) { + char *p = lptr; + + Tcl_AppendPrintfToObj(psObj, "%d", *p++ & 0xff); + for (; --i>0 ;) { + Tcl_AppendPrintfToObj(psObj, " %d", *p++ & 0xff); + } + Tcl_AppendPrintfToObj(psObj, "] %d setdash\n", outline->offset); + } else { + Tcl_AppendToObj(psObj, "] 0 setdash\n", -1); + } + if (lptr != pattern) { + ckfree(lptr); + } + } else { + Tcl_AppendToObj(psObj, "] 0 setdash\n", -1); + } + + if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Note that psObj might hold an invalid reference now. + */ + + if (stipple != None) { + Tcl_AppendToObj(GetPostscriptBuffer(interp), "StrokeClip ", -1); + if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendToObj(GetPostscriptBuffer(interp), "stroke\n", -1); + } + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DashConvert + * + * Converts a character-like dash-list (e.g. "-..") into an X11-style. l + * must point to a string that holds room to at least 2*n characters. If + * l == NULL, this function can be used for syntax checking only. + * + * Results: + * The length of the resulting X11 compatible dash-list. -1 if failed. + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +static int +DashConvert( + char *l, /* Must be at least 2*n chars long, or NULL to + * indicate "just check syntax". */ + const char *p, /* String to parse. */ + int n, /* Length of string to parse, or -1 to + * indicate that strlen() should be used. */ + double width) /* Width of line. */ +{ + int result = 0; + int size, intWidth; + + if (n < 0) { + n = strlen(p); + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + while (n-- && *p) { + switch (*p++) { + case ' ': + if (result) { + if (l) { + l[-1] += intWidth + 1; + } + continue; + } + return 0; + case '_': + size = 8; + break; + case '-': + size = 6; + break; + case ',': + size = 4; + break; + case '.': + size = 2; + break; + default: + return -1; + } + if (l) { + *l++ = size * intWidth; + *l++ = 4 * intWidth; + } + result += 2; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TranslateAndAppendCoords -- + * + * This is a helper routine for TkCanvTranslatePath() below. + * + * Given an (x,y) coordinate pair within a canvas, this function computes + * the corresponding coordinates at which the point should be drawn in + * the drawable used for display. Those coordinates are then written into + * outArr[numOut*2] and outArr[numOut*2+1]. + * + * Results: + * There is no return value. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +TranslateAndAppendCoords( + TkCanvas *canvPtr, /* The canvas. */ + double x, /* Coordinates in canvas space. */ + double y, + XPoint *outArr, /* Write results into this array */ + int numOut) /* Num of prior entries in outArr[] */ +{ + double tmp; + + tmp = x - canvPtr->drawableXOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + outArr[numOut].x = (short) tmp; + + tmp = y - canvPtr->drawableYOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + outArr[numOut].y = (short) tmp; +} + +/* + *-------------------------------------------------------------- + * + * TkCanvTranslatePath + * + * Translate a line or polygon path so that all vertices are within a + * rectangle that is 1000 pixels larger than the total size of the canvas + * window. This will prevent pixel coordinates from overflowing the + * 16-bit integer size limitation imposed by most windowing systems. + * + * coordPtr must point to an array of doubles, two doubles per vertex. + * There are a total of numVertex vertices, or 2*numVertex entries in + * coordPtr. The result vertices written into outArr have their + * coordinate origin shifted to canvPtr->drawableXOrigin by + * canvPtr->drawableYOrigin. There might be as many as 3 times more + * output vertices than there are input vertices. The calling function + * should allocate space accordingly. + * + * This routine limits the width and height of a canvas window to 31767 + * pixels. At the highest resolution display devices available today (210 + * ppi in Jan 2003) that's a window that is over 13 feet wide and tall. + * Should be enough for the near future. + * + * Results: + * Clipped and translated path vertices are written into outArr[]. There + * might be as many as twice the vertices in outArr[] as there are in + * coordPtr[]. The return value is the number of vertices actually + * written into outArr[]. + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +int +TkCanvTranslatePath( + TkCanvas *canvPtr, /* The canvas */ + int numVertex, /* Number of vertices specified by + * coordArr[] */ + double *coordArr, /* X and Y coordinates for each vertex */ + int closedPath, /* True if this is a closed polygon */ + XPoint *outArr) /* Write results here, if not NULL */ +{ + int numOutput = 0; /* Number of output coordinates */ + double lft, rgh; /* Left and right sides of the bounding box */ + double top, btm; /* Top and bottom sizes of the bounding box */ + double *tempArr; /* Temporary storage used by the clipper */ + double *a, *b, *t; /* Pointers to parts of the temporary + * storage */ + int i, j; /* Loop counters */ + double limit[4]; /* Boundries at which clipping occurs */ + double staticSpace[480]; /* Temp space from the stack */ + + /* + * Constrain all vertices of the path to be within a box that is no larger + * than 32000 pixels wide or height. The top-left corner of this clipping + * box is 1000 pixels above and to the left of the top left corner of the + * window on which the canvas is displayed. + * + * This means that a canvas will not display properly on a canvas window + * that is larger than 31000 pixels wide or high. That is not a problem + * today, but might someday become a factor for ultra-high resolutions + * displays. + * + * The X11 protocol allows us (in theory) to expand the size of the + * clipping box to 32767 pixels. But we have found experimentally that + * XFree86 sometimes fails to draw lines correctly if they are longer than + * about 32500 pixels. So we have left a little margin in the size to mask + * that bug. + */ + + lft = canvPtr->xOrigin - 1000.0; + top = canvPtr->yOrigin - 1000.0; + rgh = lft + 32000.0; + btm = top + 32000.0; + + /* + * Try the common case first - no clipping. Loop over the input + * coordinates and translate them into appropriate output coordinates. + * But if a vertex outside of the bounding box is seen, break out of the + * loop. + * + * Most of the time, no clipping is needed, so this one loop is sufficient + * to do the translation. + */ + + for (i=0; i<numVertex; i++){ + double x, y; + + x = coordArr[i*2]; + y = coordArr[i*2 + 1]; + if (x<lft || x>rgh || y<top || y>btm) { + break; + } + TranslateAndAppendCoords(canvPtr, x, y, outArr, numOutput++); + } + if (i == numVertex){ + assert(numOutput == numVertex); + return numOutput; + } + + /* + * If we reach this point, it means that some clipping is required. Begin + * by allocating some working storage - at least 6 times as much space as + * coordArr[] requires. Divide this space into two separate arrays a[] and + * b[]. Initialize a[] to be equal to coordArr[]. + */ + + if (numVertex*12 <= (int) (sizeof(staticSpace) / sizeof(double))) { + tempArr = staticSpace; + } else { + tempArr = ckalloc(numVertex * 12 * sizeof(double)); + } + for (i=0; i<numVertex*2; i++){ + tempArr[i] = coordArr[i]; + } + a = tempArr; + b = &tempArr[numVertex*6]; + + /* + * We will make four passes through the input data. On each pass, we copy + * the contents of a[] over into b[]. As we copy, we clip any line + * segments that extend to the right past xClip then we rotate the + * coordinate system 90 degrees clockwise. After each pass is complete, we + * interchange a[] and b[] in preparation for the next pass. + * + * Each pass clips line segments that extend beyond a single side of the + * bounding box, and four passes rotate the coordinate system back to its + * original value. I'm not an expert on graphics algorithms, but I think + * this is called Cohen-Sutherland polygon clipping. + * + * The limit[] array contains the xClip value used for each of the four + * passes. + */ + + limit[0] = rgh; + limit[1] = -top; + limit[2] = -lft; + limit[3] = btm; + + /* + * This is the loop that makes the four passes through the data. + */ + + for (j=0; j<4; j++) { + double xClip = limit[j]; + int inside = a[0] < xClip; + double priorY = a[1]; + numOutput = 0; + + /* + * Clip everything to the right of xClip. Store the results in b[] + * rotated by 90 degrees clockwise. + */ + + for (i=0; i<numVertex; i++) { + double x = a[i*2]; + double y = a[i*2 + 1]; + + if (x >= xClip) { + /* + * The current vertex is to the right of xClip. + */ + + if (inside) { + /* + * If the current vertex is to the right of xClip but the + * previous vertex was left of xClip, then draw a line + * segment from the previous vertex to until it intersects + * the vertical at xClip. + */ + + double x0, y0, yN; + + assert(i > 0); + x0 = a[i*2 - 2]; + y0 = a[i*2 - 1]; + yN = y0 + (y - y0)*(xClip-x0)/(x-x0); + b[numOutput*2] = -yN; + b[numOutput*2 + 1] = xClip; + numOutput++; + assert(numOutput <= numVertex*3); + priorY = yN; + inside = 0; + } else if (i == 0) { + /* + * If the first vertex is to the right of xClip, add a + * vertex that is the projection of the first vertex onto + * the vertical xClip line. + */ + + b[0] = -y; + b[1] = xClip; + numOutput = 1; + priorY = y; + } + } else { + /* + * The current vertex is to the left of xClip + */ + + if (!inside) { + /* + * If the current vertex is on the left of xClip and one + * or more prior vertices where to the right, then we have + * to draw a line segment along xClip that extends from + * the spot where we first crossed from left to right to + * the spot where we cross back from right to left. + */ + + double x0, y0, yN; + + assert(i > 0); + x0 = a[i*2 - 2]; + y0 = a[i*2 - 1]; + yN = y0 + (y - y0)*(xClip-x0)/(x-x0); + if (yN != priorY) { + b[numOutput*2] = -yN; + b[numOutput*2 + 1] = xClip; + numOutput++; + assert(numOutput <= numVertex*3); + } + inside = 1; + } + b[numOutput*2] = -y; + b[numOutput*2 + 1] = x; + numOutput++; + assert(numOutput <= numVertex*3); + } + } + + /* + * Interchange a[] and b[] in preparation for the next pass. + */ + + t = a; + a = b; + b = t; + numVertex = numOutput; + } + + /* + * All clipping is now finished. Convert the coordinates from doubles into + * XPoints and translate the origin for the drawable. + */ + + for (i=0; i<numVertex; i++) { + TranslateAndAppendCoords(canvPtr, a[i*2], a[i*2+1], outArr, i); + } + if (tempArr != staticSpace) { + ckfree(tempArr); + } + return numOutput; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |