4 * This file contains a collection of utility functions used by the
5 * implementations of various canvas item types.
7 * Copyright (c) 1994 Sun Microsystems, Inc.
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
17 * Structures defined only in this file.
20 typedef struct SmoothAssocData {
21 struct SmoothAssocData *nextPtr;
22 /* Pointer to next SmoothAssocData. */
23 Tk_SmoothMethod smooth; /* Name and functions associated with this
27 const Tk_SmoothMethod tkBezierSmoothMethod = {
30 (void (*) (Tcl_Interp *interp, Tk_Canvas canvas, double *coordPtr,
31 int numPoints, int numSteps))(void *)TkMakeBezierPostscript,
33 static const Tk_SmoothMethod tkRawSmoothMethod = {
36 (void (*) (Tcl_Interp *interp, Tk_Canvas canvas, double *coordPtr,
37 int numPoints, int numSteps))(void *)TkMakeRawCurvePostscript,
42 * Function forward-declarations.
45 static void SmoothMethodCleanupProc(ClientData clientData,
47 static SmoothAssocData *InitSmoothMethods(Tcl_Interp *interp);
48 static int DashConvert(char *l, const char *p, int n,
50 static void TranslateAndAppendCoords(TkCanvas *canvPtr,
51 double x, double y, XPoint *outArr, int numOut);
52 static inline Tcl_Obj * GetPostscriptBuffer(Tcl_Interp *interp);
54 #define ABS(a) ((a>=0)?(a):(-(a)))
56 static inline Tcl_Obj *
60 Tcl_Obj *psObj = Tcl_GetObjResult(interp);
62 if (Tcl_IsShared(psObj)) {
63 psObj = Tcl_DuplicateObj(psObj);
64 Tcl_SetObjResult(interp, psObj);
70 *----------------------------------------------------------------------
74 * Given a token for a canvas, this function returns the widget that
75 * represents the canvas.
78 * The return value is a handle for the widget.
83 *----------------------------------------------------------------------
88 Tk_Canvas canvas) /* Token for the canvas. */
90 return Canvas(canvas)->tkwin;
94 *----------------------------------------------------------------------
96 * Tk_CanvasDrawableCoords --
98 * Given an (x,y) coordinate pair within a canvas, this function
99 * returns the corresponding coordinates at which the point should
100 * be drawn in the drawable used for display.
103 * There is no return value. The values at *drawableXPtr and
104 * *drawableYPtr are filled in with the coordinates at which x and y
105 * should be drawn. These coordinates are clipped to fit within a
106 * "short", since this is what X uses in most cases for drawing.
111 *----------------------------------------------------------------------
115 Tk_CanvasDrawableCoords(
116 Tk_Canvas canvas, /* Token for the canvas. */
117 double x, /* Coordinates in canvas space. */
119 short *drawableXPtr, /* Screen coordinates are stored here. */
124 tmp = x - Canvas(canvas)->drawableXOrigin;
131 *drawableXPtr = 32767;
132 } else if (tmp < -32768) {
133 *drawableXPtr = -32768;
135 *drawableXPtr = (short) tmp;
138 tmp = y - Canvas(canvas)->drawableYOrigin;
145 *drawableYPtr = 32767;
146 } else if (tmp < -32768) {
147 *drawableYPtr = -32768;
149 *drawableYPtr = (short) tmp;
154 *----------------------------------------------------------------------
156 * Tk_CanvasWindowCoords --
158 * Given an (x,y) coordinate pair within a canvas, this function returns
159 * the corresponding coordinates in the canvas's window.
162 * There is no return value. The values at *screenXPtr and *screenYPtr
163 * are filled in with the coordinates at which (x,y) appears in the
164 * canvas's window. These coordinates are clipped to fit within a
165 * "short", since this is what X uses in most cases for drawing.
170 *----------------------------------------------------------------------
174 Tk_CanvasWindowCoords(
175 Tk_Canvas canvas, /* Token for the canvas. */
176 double x, /* Coordinates in canvas space. */
178 short *screenXPtr, /* Screen coordinates are stored here. */
183 tmp = x - Canvas(canvas)->xOrigin;
191 } else if (tmp < -32768) {
192 *screenXPtr = -32768;
194 *screenXPtr = (short) tmp;
197 tmp = y - Canvas(canvas)->yOrigin;
205 } else if (tmp < -32768) {
206 *screenYPtr = -32768;
208 *screenYPtr = (short) tmp;
213 *--------------------------------------------------------------
215 * Tk_CanvasGetCoord --
217 * Given a string, returns a floating-point canvas coordinate
218 * corresponding to that string.
221 * The return value is a standard Tcl return result. If TCL_OK is
222 * returned, then everything went well and the canvas coordinate is
223 * stored at *doublePtr; otherwise TCL_ERROR is returned and an error
224 * message is left in the interp's result.
229 *--------------------------------------------------------------
234 Tcl_Interp *interp, /* Interpreter for error reporting. */
235 Tk_Canvas canvas, /* Canvas to which coordinate applies. */
236 const char *string, /* Describes coordinate (any screen coordinate
237 * form may be used here). */
238 double *doublePtr) /* Place to store converted coordinate. */
240 if (Tk_GetScreenMM(Canvas(canvas)->interp, Canvas(canvas)->tkwin, string,
241 doublePtr) != TCL_OK) {
244 *doublePtr *= Canvas(canvas)->pixelsPerMM;
249 *--------------------------------------------------------------
251 * Tk_CanvasGetCoordFromObj --
253 * Given a string, returns a floating-point canvas coordinate
254 * corresponding to that string.
257 * The return value is a standard Tcl return result. If TCL_OK is
258 * returned, then everything went well and the canvas coordinate is
259 * stored at *doublePtr; otherwise TCL_ERROR is returned and an error
260 * message is left in interp->result.
265 *--------------------------------------------------------------
269 Tk_CanvasGetCoordFromObj(
270 Tcl_Interp *interp, /* Interpreter for error reporting. */
271 Tk_Canvas canvas, /* Canvas to which coordinate applies. */
272 Tcl_Obj *obj, /* Describes coordinate (any screen coordinate
273 * form may be used here). */
274 double *doublePtr) /* Place to store converted coordinate. */
276 return Tk_GetDoublePixelsFromObj(Canvas(canvas)->interp, Canvas(canvas)->tkwin, obj, doublePtr);
280 *----------------------------------------------------------------------
282 * Tk_CanvasSetStippleOrigin --
284 * This function sets the stipple origin in a graphics context so that
285 * stipples drawn with the GC will line up with other stipples previously
286 * drawn in the canvas.
292 * The graphics context is modified.
294 *----------------------------------------------------------------------
298 Tk_CanvasSetStippleOrigin(
299 Tk_Canvas canvas, /* Token for a canvas. */
300 GC gc) /* Graphics context that is about to be used
301 * to draw a stippled pattern as part of
302 * redisplaying the canvas. */
304 XSetTSOrigin(Canvas(canvas)->display, gc,
305 -Canvas(canvas)->drawableXOrigin,
306 -Canvas(canvas)->drawableYOrigin);
310 *----------------------------------------------------------------------
312 * Tk_CanvasSetOffset--
314 * This function sets the stipple offset in a graphics context so that
315 * stipples drawn with the GC will line up with other stipples with the
322 * The graphics context is modified.
324 *----------------------------------------------------------------------
329 Tk_Canvas canvas, /* Token for a canvas. */
330 GC gc, /* Graphics context that is about to be used
331 * to draw a stippled pattern as part of
332 * redisplaying the canvas. */
333 Tk_TSOffset *offset) /* Offset (may be NULL pointer)*/
335 TkCanvas *canvasPtr = Canvas(canvas);
337 int x = - canvasPtr->drawableXOrigin;
338 int y = - canvasPtr->drawableYOrigin;
340 if (offset != NULL) {
341 flags = offset->flags;
342 x += offset->xoffset;
343 y += offset->yoffset;
345 if ((flags & TK_OFFSET_RELATIVE) && !(flags & TK_OFFSET_INDEX)) {
346 Tk_SetTSOrigin(canvasPtr->tkwin, gc, x - canvasPtr->xOrigin,
347 y - canvasPtr->yOrigin);
349 XSetTSOrigin(canvasPtr->display, gc, x, y);
354 *----------------------------------------------------------------------
356 * Tk_CanvasGetTextInfo --
358 * This function returns a pointer to a structure containing information
359 * about the selection and insertion cursor for a canvas widget. Items
360 * such as text items save the pointer and use it to share access to the
361 * information with the generic canvas code.
364 * The return value is a pointer to the structure holding text
365 * information for the canvas. Most of the fields should not be modified
366 * outside the generic canvas code; see the user documentation for
372 *----------------------------------------------------------------------
376 Tk_CanvasGetTextInfo(
377 Tk_Canvas canvas) /* Token for the canvas widget. */
379 return &Canvas(canvas)->textInfo;
383 *--------------------------------------------------------------
385 * Tk_CanvasTagsParseProc --
387 * This function is invoked during option processing to handle "-tags"
388 * options for canvas items.
391 * A standard Tcl return value.
394 * The tags for a given item get replaced by those indicated in the value
397 *--------------------------------------------------------------
401 Tk_CanvasTagsParseProc(
402 ClientData clientData, /* Not used.*/
403 Tcl_Interp *interp, /* Used for reporting errors. */
404 Tk_Window tkwin, /* Window containing canvas widget. */
405 const char *value, /* Value of option (list of tag names). */
406 char *widgRec, /* Pointer to record for item. */
407 int offset) /* Offset into item (ignored). */
409 Tk_Item *itemPtr = (Tk_Item *) widgRec;
415 * Break the value up into the individual tag names.
418 if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) {
423 * Make sure that there's enough space in the item to hold the tag names.
426 if (itemPtr->tagSpace < argc) {
427 newPtr = ckalloc(argc * sizeof(Tk_Uid));
428 for (i = itemPtr->numTags-1; i >= 0; i--) {
429 newPtr[i] = itemPtr->tagPtr[i];
431 if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
432 ckfree(itemPtr->tagPtr);
434 itemPtr->tagPtr = newPtr;
435 itemPtr->tagSpace = argc;
437 itemPtr->numTags = argc;
438 for (i = 0; i < argc; i++) {
439 itemPtr->tagPtr[i] = Tk_GetUid(argv[i]);
446 *--------------------------------------------------------------
448 * Tk_CanvasTagsPrintProc --
450 * This function is invoked by the Tk configuration code to produce a
451 * printable string for the "-tags" configuration option for canvas
455 * The return value is a string describing all the tags for the item
456 * referred to by "widgRec". In addition, *freeProcPtr is filled in with
457 * the address of a function to call to free the result string when it's
458 * no longer needed (or NULL to indicate that the string doesn't need to
464 *--------------------------------------------------------------
468 Tk_CanvasTagsPrintProc(
469 ClientData clientData, /* Ignored. */
470 Tk_Window tkwin, /* Window containing canvas widget. */
471 char *widgRec, /* Pointer to record for item. */
472 int offset, /* Ignored. */
473 Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with
474 * information about how to reclaim storage
475 * for return string. */
477 Tk_Item *itemPtr = (Tk_Item *) widgRec;
479 if (itemPtr->numTags == 0) {
483 if (itemPtr->numTags == 1) {
485 return (const char *) itemPtr->tagPtr[0];
487 *freeProcPtr = TCL_DYNAMIC;
488 return Tcl_Merge(itemPtr->numTags, (const char **) itemPtr->tagPtr);
492 *--------------------------------------------------------------
494 * TkCanvasDashParseProc --
496 * This function is invoked during option processing to handle "-dash",
497 * "-activedash" and "-disableddash" options for canvas objects.
500 * A standard Tcl return value.
503 * The dash list for a given canvas object gets replaced by those
504 * indicated in the value argument.
506 *--------------------------------------------------------------
510 TkCanvasDashParseProc(
511 ClientData clientData, /* Not used.*/
512 Tcl_Interp *interp, /* Used for reporting errors. */
513 Tk_Window tkwin, /* Window containing canvas widget. */
514 const char *value, /* Value of option. */
515 char *widgRec, /* Pointer to record for item. */
516 int offset) /* Offset into item. */
518 return Tk_GetDash(interp, value, (Tk_Dash *) (widgRec+offset));
522 *--------------------------------------------------------------
524 * TkCanvasDashPrintProc --
526 * This function is invoked by the Tk configuration code to produce a
527 * printable string for the "-dash", "-activedash" and "-disableddash"
528 * configuration options for canvas items.
531 * The return value is a string describing all the dash list for the item
532 * referred to by "widgRec"and "offset". In addition, *freeProcPtr is
533 * filled in with the address of a function to call to free the result
534 * string when it's no longer needed (or NULL to indicate that the string
535 * doesn't need to be freed).
540 *--------------------------------------------------------------
544 TkCanvasDashPrintProc(
545 ClientData clientData, /* Ignored. */
546 Tk_Window tkwin, /* Window containing canvas widget. */
547 char *widgRec, /* Pointer to record for item. */
548 int offset, /* Offset in record for item. */
549 Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with
550 * information about how to reclaim storage
551 * for return string. */
553 Tk_Dash *dash = (Tk_Dash *) (widgRec+offset);
555 int i = dash->number;
559 *freeProcPtr = TCL_DYNAMIC;
560 buffer = ckalloc(i + 1);
561 p = (i > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
562 memcpy(buffer, p, (unsigned int) i);
569 buffer = ckalloc(4 * i);
570 *freeProcPtr = TCL_DYNAMIC;
572 p = (i > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
573 sprintf(buffer, "%d", *p++ & 0xff);
575 sprintf(buffer+strlen(buffer), " %d", *p++ & 0xff);
581 *--------------------------------------------------------------
583 * InitSmoothMethods --
585 * This function is invoked to set up the initial state of the list of
586 * "-smooth" methods. It should only be called when the list installed
587 * in the interpreter is NULL.
590 * Pointer to the start of the list of default smooth methods.
593 * A linked list of smooth methods is created and attached to the
594 * interpreter's association key "smoothMethod"
596 *--------------------------------------------------------------
599 static SmoothAssocData *
603 SmoothAssocData *methods, *ptr;
605 methods = ckalloc(sizeof(SmoothAssocData));
606 methods->smooth.name = tkRawSmoothMethod.name;
607 methods->smooth.coordProc = tkRawSmoothMethod.coordProc;
608 methods->smooth.postscriptProc = tkRawSmoothMethod.postscriptProc;
610 ptr = methods->nextPtr = ckalloc(sizeof(SmoothAssocData));
611 ptr->smooth.name = tkBezierSmoothMethod.name;
612 ptr->smooth.coordProc = tkBezierSmoothMethod.coordProc;
613 ptr->smooth.postscriptProc = tkBezierSmoothMethod.postscriptProc;
616 Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc,methods);
621 *--------------------------------------------------------------
623 * Tk_CreateSmoothMethod --
625 * This function is invoked to add additional values for the "-smooth"
626 * option to the list.
629 * A standard Tcl return value.
632 * In the future "-smooth <name>" will be accepted as smooth method for
633 * the line and polygon.
635 *--------------------------------------------------------------
639 Tk_CreateSmoothMethod(
641 const Tk_SmoothMethod *smooth)
643 SmoothAssocData *methods, *typePtr2, *prevPtr, *ptr;
644 methods = Tcl_GetAssocData(interp, "smoothMethod", NULL);
647 * Initialize if we were not previously initialized.
650 if (methods == NULL) {
651 methods = InitSmoothMethods(interp);
655 * If there's already a smooth method with the given name, remove it.
658 for (typePtr2 = methods, prevPtr = NULL; typePtr2 != NULL;
659 prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
660 if (!strcmp(typePtr2->smooth.name, smooth->name)) {
661 if (prevPtr == NULL) {
662 methods = typePtr2->nextPtr;
664 prevPtr->nextPtr = typePtr2->nextPtr;
670 ptr = ckalloc(sizeof(SmoothAssocData));
671 ptr->smooth.name = smooth->name;
672 ptr->smooth.coordProc = smooth->coordProc;
673 ptr->smooth.postscriptProc = smooth->postscriptProc;
674 ptr->nextPtr = methods;
675 Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc, ptr);
679 *----------------------------------------------------------------------
681 * SmoothMethodCleanupProc --
683 * This function is invoked whenever an interpreter is deleted to
684 * cleanup the smooth methods.
690 * Smooth methods are removed.
692 *----------------------------------------------------------------------
696 SmoothMethodCleanupProc(
697 ClientData clientData, /* Points to "smoothMethod" AssocData for the
699 Tcl_Interp *interp) /* Interpreter that is being deleted. */
701 SmoothAssocData *ptr, *methods = clientData;
703 while (methods != NULL) {
705 methods = methods->nextPtr;
710 *--------------------------------------------------------------
712 * TkSmoothParseProc --
714 * This function is invoked during option processing to handle the
718 * A standard Tcl return value.
721 * The smooth option for a given item gets replaced by the value
722 * indicated in the value argument.
724 *--------------------------------------------------------------
729 ClientData clientData, /* Ignored. */
730 Tcl_Interp *interp, /* Used for reporting errors. */
731 Tk_Window tkwin, /* Window containing canvas widget. */
732 const char *value, /* Value of option. */
733 char *widgRec, /* Pointer to record for item. */
734 int offset) /* Offset into item. */
736 const Tk_SmoothMethod **smoothPtr =
737 (const Tk_SmoothMethod **) (widgRec + offset);
738 const Tk_SmoothMethod *smooth = NULL;
741 SmoothAssocData *methods;
743 if (value == NULL || *value == 0) {
747 length = strlen(value);
748 methods = Tcl_GetAssocData(interp, "smoothMethod", NULL);
751 * Not initialized yet; fix that now.
754 if (methods == NULL) {
755 methods = InitSmoothMethods(interp);
759 * Backward compatibility hack.
762 if (strncmp(value, "bezier", length) == 0) {
763 smooth = &tkBezierSmoothMethod;
767 * Search the list of installed smooth methods.
770 while (methods != NULL) {
771 if (strncmp(value, methods->smooth.name, length) == 0) {
772 if (smooth != NULL) {
773 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
774 "ambiguous smooth method \"%s\"", value));
775 Tcl_SetErrorCode(interp, "TK", "LOOKUP", "SMOOTH", value,
779 smooth = &methods->smooth;
781 methods = methods->nextPtr;
789 * Did not find it. Try parsing as a boolean instead.
792 if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) {
795 *smoothPtr = b ? &tkBezierSmoothMethod : NULL;
799 *--------------------------------------------------------------
801 * TkSmoothPrintProc --
803 * This function is invoked by the Tk configuration code to produce a
804 * printable string for the "-smooth" configuration option.
807 * The return value is a string describing the smooth option for the item
808 * referred to by "widgRec". In addition, *freeProcPtr is filled in with
809 * the address of a function to call to free the result string when it's
810 * no longer needed (or NULL to indicate that the string doesn't need to
816 *--------------------------------------------------------------
821 ClientData clientData, /* Ignored. */
822 Tk_Window tkwin, /* Window containing canvas widget. */
823 char *widgRec, /* Pointer to record for item. */
824 int offset, /* Offset into item. */
825 Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with
826 * information about how to reclaim storage
827 * for return string. */
829 const Tk_SmoothMethod *smoothPtr =
830 * (Tk_SmoothMethod **) (widgRec + offset);
832 return smoothPtr ? smoothPtr->name : "0";
835 *--------------------------------------------------------------
839 * This function is used to parse a string, assuming it is dash
843 * The return value is a standard Tcl result: TCL_OK means that the dash
844 * information was parsed ok, and TCL_ERROR means it couldn't be parsed.
847 * Dash information in the dash structure is updated.
849 *--------------------------------------------------------------
854 Tcl_Interp *interp, /* Used for error reporting. */
855 const char *value, /* Textual specification of dash list. */
856 Tk_Dash *dash) /* Pointer to record in which to store dash
860 const char **largv, **argv = NULL;
863 if ((value == NULL) || (*value == '\0')) {
869 * switch is usually compiled more efficiently than a chain of conditions.
873 case '.': case ',': case '-': case '_':
874 i = DashConvert(NULL, value, -1, 0.0);
879 if (i > (int) sizeof(char *)) {
880 dash->pattern.pt = pt = ckalloc(strlen(value));
882 pt = dash->pattern.array;
884 memcpy(pt, value, (unsigned) i);
889 if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) {
890 Tcl_ResetResult(interp);
894 if ((unsigned) ABS(dash->number) > sizeof(char *)) {
895 ckfree(dash->pattern.pt);
897 if (argc > (int) sizeof(char *)) {
898 dash->pattern.pt = pt = ckalloc(argc);
900 pt = dash->pattern.array;
906 if (Tcl_GetInt(interp, *largv, &i) != TCL_OK || i < 1 || i>255) {
907 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
908 "expected integer in the range 1..255 but got \"%s\"",
910 Tcl_SetErrorCode(interp, "TK", "VALUE", "DASH", NULL);
924 * Something went wrong. Generate error message, clean up and return.
928 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
929 "bad dash list \"%s\": must be a list of integers or a format like \"-..\"",
931 Tcl_SetErrorCode(interp, "TK", "VALUE", "DASH", NULL);
936 if ((unsigned) ABS(dash->number) > sizeof(char *)) {
937 ckfree(dash->pattern.pt);
944 *--------------------------------------------------------------
948 * This function initializes the Tk_Outline structure with default
957 *--------------------------------------------------------------
962 Tk_Outline *outline) /* Outline structure to be filled in. */
965 outline->width = 1.0;
966 outline->activeWidth = 0.0;
967 outline->disabledWidth = 0.0;
969 outline->dash.number = 0;
970 outline->activeDash.number = 0;
971 outline->disabledDash.number = 0;
972 outline->tsoffset.flags = 0;
973 outline->tsoffset.xoffset = 0;
974 outline->tsoffset.yoffset = 0;
975 outline->color = NULL;
976 outline->activeColor = NULL;
977 outline->disabledColor = NULL;
978 outline->stipple = None;
979 outline->activeStipple = None;
980 outline->disabledStipple = None;
984 *--------------------------------------------------------------
988 * This function frees all memory that might be allocated and referenced
989 * in the Tk_Outline structure.
997 *--------------------------------------------------------------
1002 Display *display, /* Display containing window. */
1003 Tk_Outline *outline)
1005 if (outline->gc != NULL) {
1006 Tk_FreeGC(display, outline->gc);
1008 if ((unsigned) ABS(outline->dash.number) > sizeof(char *)) {
1009 ckfree(outline->dash.pattern.pt);
1011 if ((unsigned) ABS(outline->activeDash.number) > sizeof(char *)) {
1012 ckfree(outline->activeDash.pattern.pt);
1014 if ((unsigned) ABS(outline->disabledDash.number) > sizeof(char *)) {
1015 ckfree(outline->disabledDash.pattern.pt);
1017 if (outline->color != NULL) {
1018 Tk_FreeColor(outline->color);
1020 if (outline->activeColor != NULL) {
1021 Tk_FreeColor(outline->activeColor);
1023 if (outline->disabledColor != NULL) {
1024 Tk_FreeColor(outline->disabledColor);
1026 if (outline->stipple != None) {
1027 Tk_FreeBitmap(display, outline->stipple);
1029 if (outline->activeStipple != None) {
1030 Tk_FreeBitmap(display, outline->activeStipple);
1032 if (outline->disabledStipple != None) {
1033 Tk_FreeBitmap(display, outline->disabledStipple);
1038 *--------------------------------------------------------------
1040 * Tk_ConfigOutlineGC
1042 * This function should be called in the canvas object during the
1043 * configure command. The graphics context description in gcValues is
1044 * updated according to the information in the dash structure, as far as
1048 * The return-value is a mask, indicating which elements of gcValues have
1049 * been updated. 0 means there is no outline.
1052 * GC information in gcValues is updated.
1054 *--------------------------------------------------------------
1059 XGCValues *gcValues,
1062 Tk_Outline *outline)
1069 Tk_State state = item->state;
1071 if (outline->width < 0.0) {
1072 outline->width = 0.0;
1074 if (outline->activeWidth < 0.0) {
1075 outline->activeWidth = 0.0;
1077 if (outline->disabledWidth < 0) {
1078 outline->disabledWidth = 0.0;
1080 if (state==TK_STATE_HIDDEN) {
1084 width = outline->width;
1088 dash = &(outline->dash);
1089 color = outline->color;
1090 stipple = outline->stipple;
1091 if (state == TK_STATE_NULL) {
1092 state = Canvas(canvas)->canvas_state;
1094 if (Canvas(canvas)->currentItemPtr == item) {
1095 if (outline->activeWidth>width) {
1096 width = outline->activeWidth;
1098 if (outline->activeDash.number != 0) {
1099 dash = &(outline->activeDash);
1101 if (outline->activeColor!=NULL) {
1102 color = outline->activeColor;
1104 if (outline->activeStipple!=None) {
1105 stipple = outline->activeStipple;
1107 } else if (state == TK_STATE_DISABLED) {
1108 if (outline->disabledWidth>0) {
1109 width = outline->disabledWidth;
1111 if (outline->disabledDash.number != 0) {
1112 dash = &(outline->disabledDash);
1114 if (outline->disabledColor!=NULL) {
1115 color = outline->disabledColor;
1117 if (outline->disabledStipple!=None) {
1118 stipple = outline->disabledStipple;
1126 gcValues->line_width = (int) (width + 0.5);
1127 if (color != NULL) {
1128 gcValues->foreground = color->pixel;
1129 mask = GCForeground|GCLineWidth;
1130 if (stipple != None) {
1131 gcValues->stipple = stipple;
1132 gcValues->fill_style = FillStippled;
1133 mask |= GCStipple|GCFillStyle;
1136 if (mask && (dash->number != 0)) {
1137 gcValues->line_style = LineOnOffDash;
1138 gcValues->dash_offset = outline->offset;
1139 if ((unsigned int)ABS(dash->number) > sizeof(char *)) {
1140 gcValues->dashes = dash->pattern.pt[0];
1141 } else if (dash->number != 0) {
1142 gcValues->dashes = dash->pattern.array[0];
1144 gcValues->dashes = (char) (4 * width + 0.5);
1146 mask |= GCLineStyle|GCDashList|GCDashOffset;
1152 *--------------------------------------------------------------
1154 * Tk_ChangeOutlineGC
1156 * Updates the GC to represent the full information of the dash
1157 * structure. Partly this is already done in Tk_ConfigOutlineGC(). This
1158 * function should be called just before drawing the dashed item.
1161 * 1 if there is a stipple pattern, and 0 otherwise.
1166 *--------------------------------------------------------------
1173 Tk_Outline *outline)
1180 Tk_State state = item->state;
1182 width = outline->width;
1186 dash = &(outline->dash);
1187 color = outline->color;
1188 stipple = outline->stipple;
1189 if (state == TK_STATE_NULL) {
1190 state = Canvas(canvas)->canvas_state;
1192 if (Canvas(canvas)->currentItemPtr == item) {
1193 if (outline->activeWidth > width) {
1194 width = outline->activeWidth;
1196 if (outline->activeDash.number != 0) {
1197 dash = &(outline->activeDash);
1199 if (outline->activeColor != NULL) {
1200 color = outline->activeColor;
1202 if (outline->activeStipple != None) {
1203 stipple = outline->activeStipple;
1205 } else if (state == TK_STATE_DISABLED) {
1206 if (outline->disabledWidth > width) {
1207 width = outline->disabledWidth;
1209 if (outline->disabledDash.number != 0) {
1210 dash = &(outline->disabledDash);
1212 if (outline->disabledColor != NULL) {
1213 color = outline->disabledColor;
1215 if (outline->disabledStipple != None) {
1216 stipple = outline->disabledStipple;
1223 if ((dash->number<-1) ||
1224 ((dash->number == -1) && (dash->pattern.array[0] != ','))) {
1226 int i = -dash->number;
1228 p = (i > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
1230 i = DashConvert(q, p, i, width);
1231 XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset, q,i);
1233 } else if (dash->number>2 || (dash->number==2 &&
1234 (dash->pattern.array[0]!=dash->pattern.array[1]))) {
1235 p = (dash->number > (int) sizeof(char *))
1236 ? dash->pattern.pt : dash->pattern.array;
1237 XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset, p,
1240 if (stipple!=None) {
1241 int w = 0; int h = 0;
1242 Tk_TSOffset *tsoffset = &outline->tsoffset;
1243 int flags = tsoffset->flags;
1245 if (!(flags & TK_OFFSET_INDEX) &&
1246 (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) {
1247 Tk_SizeOfBitmap(Canvas(canvas)->display, stipple, &w, &h);
1248 if (flags & TK_OFFSET_CENTER) {
1253 if (flags & TK_OFFSET_MIDDLE) {
1259 tsoffset->xoffset -= w;
1260 tsoffset->yoffset -= h;
1261 Tk_CanvasSetOffset(canvas, outline->gc, tsoffset);
1262 tsoffset->xoffset += w;
1263 tsoffset->yoffset += h;
1271 *--------------------------------------------------------------
1275 * Restores the GC to the situation before Tk_ChangeOutlineGC() was
1276 * called. This function should be called just after the dashed item is
1277 * drawn, because the GC is supposed to be read-only.
1280 * 1 if there is a stipple pattern, and 0 otherwise.
1285 *--------------------------------------------------------------
1292 Tk_Outline *outline)
1299 Tk_State state = item->state;
1301 width = outline->width;
1305 dash = &(outline->dash);
1306 color = outline->color;
1307 stipple = outline->stipple;
1308 if (state == TK_STATE_NULL) {
1309 state = Canvas(canvas)->canvas_state;
1311 if (Canvas(canvas)->currentItemPtr == item) {
1312 if (outline->activeWidth>width) {
1313 width = outline->activeWidth;
1315 if (outline->activeDash.number != 0) {
1316 dash = &(outline->activeDash);
1318 if (outline->activeColor!=NULL) {
1319 color = outline->activeColor;
1321 if (outline->activeStipple!=None) {
1322 stipple = outline->activeStipple;
1324 } else if (state == TK_STATE_DISABLED) {
1325 if (outline->disabledWidth>width) {
1326 width = outline->disabledWidth;
1328 if (outline->disabledDash.number != 0) {
1329 dash = &(outline->disabledDash);
1331 if (outline->disabledColor!=NULL) {
1332 color = outline->disabledColor;
1334 if (outline->disabledStipple!=None) {
1335 stipple = outline->disabledStipple;
1342 if ((dash->number > 2) || (dash->number < -1) || (dash->number==2 &&
1343 (dash->pattern.array[0] != dash->pattern.array[1])) ||
1344 ((dash->number == -1) && (dash->pattern.array[0] != ','))) {
1345 if ((unsigned int)ABS(dash->number) > sizeof(char *)) {
1346 dashList = dash->pattern.pt[0];
1347 } else if (dash->number != 0) {
1348 dashList = dash->pattern.array[0];
1350 dashList = (char) (4 * width + 0.5);
1352 XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset,
1355 if (stipple != None) {
1356 XSetTSOrigin(Canvas(canvas)->display, outline->gc, 0, 0);
1363 *--------------------------------------------------------------
1365 * Tk_CanvasPsOutline
1367 * Creates the postscript command for the correct Outline-information
1368 * (width, dash, color and stipple).
1371 * TCL_OK if succeeded, otherwise TCL_ERROR.
1374 * canvas->interp->result contains the postscript string, or an error
1375 * message if the result was TCL_ERROR.
1377 *--------------------------------------------------------------
1384 Tk_Outline *outline)
1388 char *ptr, *lptr = pattern;
1389 Tcl_Interp *interp = Canvas(canvas)->interp;
1390 double width = outline->width;
1391 Tk_Dash *dash = &outline->dash;
1392 XColor *color = outline->color;
1393 Pixmap stipple = outline->stipple;
1394 Tk_State state = item->state;
1395 Tcl_Obj *psObj = GetPostscriptBuffer(interp);
1397 if (state == TK_STATE_NULL) {
1398 state = Canvas(canvas)->canvas_state;
1401 if (Canvas(canvas)->currentItemPtr == item) {
1402 if (outline->activeWidth > width) {
1403 width = outline->activeWidth;
1405 if (outline->activeDash.number > 0) {
1406 dash = &outline->activeDash;
1408 if (outline->activeColor != NULL) {
1409 color = outline->activeColor;
1411 if (outline->activeStipple != None) {
1412 stipple = outline->activeStipple;
1414 } else if (state == TK_STATE_DISABLED) {
1415 if (outline->disabledWidth > 0) {
1416 width = outline->disabledWidth;
1418 if (outline->disabledDash.number > 0) {
1419 dash = &outline->disabledDash;
1421 if (outline->disabledColor != NULL) {
1422 color = outline->disabledColor;
1424 if (outline->disabledStipple != None) {
1425 stipple = outline->disabledStipple;
1429 Tcl_AppendPrintfToObj(psObj, "%.15g setlinewidth\n", width);
1431 ptr = ((unsigned) ABS(dash->number) > sizeof(char *)) ?
1432 dash->pattern.pt : dash->pattern.array;
1433 Tcl_AppendToObj(psObj, "[", -1);
1434 if (dash->number > 0) {
1438 converted = Tcl_ObjPrintf("%d", *p++ & 0xff);
1439 for (i = dash->number-1 ; i>0 ; i--) {
1440 Tcl_AppendPrintfToObj(converted, " %d", *p++ & 0xff);
1442 Tcl_AppendObjToObj(psObj, converted);
1443 if (dash->number & 1) {
1444 Tcl_AppendToObj(psObj, " ", -1);
1445 Tcl_AppendObjToObj(psObj, converted);
1447 Tcl_DecrRefCount(converted);
1448 Tcl_AppendPrintfToObj(psObj, "] %d setdash\n", outline->offset);
1449 } else if (dash->number < 0) {
1450 if (dash->number < -5) {
1451 lptr = ckalloc(1 - 2*dash->number);
1453 i = DashConvert(lptr, ptr, -dash->number, width);
1457 Tcl_AppendPrintfToObj(psObj, "%d", *p++ & 0xff);
1459 Tcl_AppendPrintfToObj(psObj, " %d", *p++ & 0xff);
1461 Tcl_AppendPrintfToObj(psObj, "] %d setdash\n", outline->offset);
1463 Tcl_AppendToObj(psObj, "] 0 setdash\n", -1);
1465 if (lptr != pattern) {
1469 Tcl_AppendToObj(psObj, "] 0 setdash\n", -1);
1472 if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) {
1477 * Note that psObj might hold an invalid reference now.
1480 if (stipple != None) {
1481 Tcl_AppendToObj(GetPostscriptBuffer(interp), "StrokeClip ", -1);
1482 if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) {
1486 Tcl_AppendToObj(GetPostscriptBuffer(interp), "stroke\n", -1);
1493 *--------------------------------------------------------------
1497 * Converts a character-like dash-list (e.g. "-..") into an X11-style. l
1498 * must point to a string that holds room to at least 2*n characters. If
1499 * l == NULL, this function can be used for syntax checking only.
1502 * The length of the resulting X11 compatible dash-list. -1 if failed.
1507 *--------------------------------------------------------------
1512 char *l, /* Must be at least 2*n chars long, or NULL to
1513 * indicate "just check syntax". */
1514 const char *p, /* String to parse. */
1515 int n, /* Length of string to parse, or -1 to
1516 * indicate that strlen() should be used. */
1517 double width) /* Width of line. */
1525 intWidth = (int) (width + 0.5);
1534 l[-1] += intWidth + 1;
1555 *l++ = size * intWidth;
1556 *l++ = 4 * intWidth;
1564 *----------------------------------------------------------------------
1566 * TranslateAndAppendCoords --
1568 * This is a helper routine for TkCanvTranslatePath() below.
1570 * Given an (x,y) coordinate pair within a canvas, this function computes
1571 * the corresponding coordinates at which the point should be drawn in
1572 * the drawable used for display. Those coordinates are then written into
1573 * outArr[numOut*2] and outArr[numOut*2+1].
1576 * There is no return value.
1581 *----------------------------------------------------------------------
1585 TranslateAndAppendCoords(
1586 TkCanvas *canvPtr, /* The canvas. */
1587 double x, /* Coordinates in canvas space. */
1589 XPoint *outArr, /* Write results into this array */
1590 int numOut) /* Num of prior entries in outArr[] */
1594 tmp = x - canvPtr->drawableXOrigin;
1600 outArr[numOut].x = (short) tmp;
1602 tmp = y - canvPtr->drawableYOrigin;
1608 outArr[numOut].y = (short) tmp;
1612 *--------------------------------------------------------------
1614 * TkCanvTranslatePath
1616 * Translate a line or polygon path so that all vertices are within a
1617 * rectangle that is 1000 pixels larger than the total size of the canvas
1618 * window. This will prevent pixel coordinates from overflowing the
1619 * 16-bit integer size limitation imposed by most windowing systems.
1621 * coordPtr must point to an array of doubles, two doubles per vertex.
1622 * There are a total of numVertex vertices, or 2*numVertex entries in
1623 * coordPtr. The result vertices written into outArr have their
1624 * coordinate origin shifted to canvPtr->drawableXOrigin by
1625 * canvPtr->drawableYOrigin. There might be as many as 3 times more
1626 * output vertices than there are input vertices. The calling function
1627 * should allocate space accordingly.
1629 * This routine limits the width and height of a canvas window to 31767
1630 * pixels. At the highest resolution display devices available today (210
1631 * ppi in Jan 2003) that's a window that is over 13 feet wide and tall.
1632 * Should be enough for the near future.
1635 * Clipped and translated path vertices are written into outArr[]. There
1636 * might be as many as twice the vertices in outArr[] as there are in
1637 * coordPtr[]. The return value is the number of vertices actually
1638 * written into outArr[].
1643 *--------------------------------------------------------------
1647 TkCanvTranslatePath(
1648 TkCanvas *canvPtr, /* The canvas */
1649 int numVertex, /* Number of vertices specified by
1651 double *coordArr, /* X and Y coordinates for each vertex */
1652 int closedPath, /* True if this is a closed polygon */
1653 XPoint *outArr) /* Write results here, if not NULL */
1655 int numOutput = 0; /* Number of output coordinates */
1656 double lft, rgh; /* Left and right sides of the bounding box */
1657 double top, btm; /* Top and bottom sizes of the bounding box */
1658 double *tempArr; /* Temporary storage used by the clipper */
1659 double *a, *b, *t; /* Pointers to parts of the temporary
1661 int i, j; /* Loop counters */
1662 double limit[4]; /* Boundries at which clipping occurs */
1663 double staticSpace[480]; /* Temp space from the stack */
1666 * Constrain all vertices of the path to be within a box that is no larger
1667 * than 32000 pixels wide or height. The top-left corner of this clipping
1668 * box is 1000 pixels above and to the left of the top left corner of the
1669 * window on which the canvas is displayed.
1671 * This means that a canvas will not display properly on a canvas window
1672 * that is larger than 31000 pixels wide or high. That is not a problem
1673 * today, but might someday become a factor for ultra-high resolutions
1676 * The X11 protocol allows us (in theory) to expand the size of the
1677 * clipping box to 32767 pixels. But we have found experimentally that
1678 * XFree86 sometimes fails to draw lines correctly if they are longer than
1679 * about 32500 pixels. So we have left a little margin in the size to mask
1683 lft = canvPtr->xOrigin - 1000.0;
1684 top = canvPtr->yOrigin - 1000.0;
1685 rgh = lft + 32000.0;
1686 btm = top + 32000.0;
1689 * Try the common case first - no clipping. Loop over the input
1690 * coordinates and translate them into appropriate output coordinates.
1691 * But if a vertex outside of the bounding box is seen, break out of the
1694 * Most of the time, no clipping is needed, so this one loop is sufficient
1695 * to do the translation.
1698 for (i=0; i<numVertex; i++){
1702 y = coordArr[i*2 + 1];
1703 if (x<lft || x>rgh || y<top || y>btm) {
1706 TranslateAndAppendCoords(canvPtr, x, y, outArr, numOutput++);
1708 if (i == numVertex){
1709 assert(numOutput == numVertex);
1714 * If we reach this point, it means that some clipping is required. Begin
1715 * by allocating some working storage - at least 6 times as much space as
1716 * coordArr[] requires. Divide this space into two separate arrays a[] and
1717 * b[]. Initialize a[] to be equal to coordArr[].
1720 if (numVertex*12 <= (int) (sizeof(staticSpace) / sizeof(double))) {
1721 tempArr = staticSpace;
1723 tempArr = ckalloc(numVertex * 12 * sizeof(double));
1725 for (i=0; i<numVertex*2; i++){
1726 tempArr[i] = coordArr[i];
1729 b = &tempArr[numVertex*6];
1732 * We will make four passes through the input data. On each pass, we copy
1733 * the contents of a[] over into b[]. As we copy, we clip any line
1734 * segments that extend to the right past xClip then we rotate the
1735 * coordinate system 90 degrees clockwise. After each pass is complete, we
1736 * interchange a[] and b[] in preparation for the next pass.
1738 * Each pass clips line segments that extend beyond a single side of the
1739 * bounding box, and four passes rotate the coordinate system back to its
1740 * original value. I'm not an expert on graphics algorithms, but I think
1741 * this is called Cohen-Sutherland polygon clipping.
1743 * The limit[] array contains the xClip value used for each of the four
1753 * This is the loop that makes the four passes through the data.
1756 for (j=0; j<4; j++) {
1757 double xClip = limit[j];
1758 int inside = a[0] < xClip;
1759 double priorY = a[1];
1763 * Clip everything to the right of xClip. Store the results in b[]
1764 * rotated by 90 degrees clockwise.
1767 for (i=0; i<numVertex; i++) {
1769 double y = a[i*2 + 1];
1773 * The current vertex is to the right of xClip.
1778 * If the current vertex is to the right of xClip but the
1779 * previous vertex was left of xClip, then draw a line
1780 * segment from the previous vertex to until it intersects
1781 * the vertical at xClip.
1789 yN = y0 + (y - y0)*(xClip-x0)/(x-x0);
1790 b[numOutput*2] = -yN;
1791 b[numOutput*2 + 1] = xClip;
1793 assert(numOutput <= numVertex*3);
1796 } else if (i == 0) {
1798 * If the first vertex is to the right of xClip, add a
1799 * vertex that is the projection of the first vertex onto
1800 * the vertical xClip line.
1810 * The current vertex is to the left of xClip
1815 * If the current vertex is on the left of xClip and one
1816 * or more prior vertices where to the right, then we have
1817 * to draw a line segment along xClip that extends from
1818 * the spot where we first crossed from left to right to
1819 * the spot where we cross back from right to left.
1827 yN = y0 + (y - y0)*(xClip-x0)/(x-x0);
1829 b[numOutput*2] = -yN;
1830 b[numOutput*2 + 1] = xClip;
1832 assert(numOutput <= numVertex*3);
1836 b[numOutput*2] = -y;
1837 b[numOutput*2 + 1] = x;
1839 assert(numOutput <= numVertex*3);
1844 * Interchange a[] and b[] in preparation for the next pass.
1850 numVertex = numOutput;
1854 * All clipping is now finished. Convert the coordinates from doubles into
1855 * XPoints and translate the origin for the drawable.
1858 for (i=0; i<numVertex; i++) {
1859 TranslateAndAppendCoords(canvPtr, a[i*2], a[i*2+1], outArr, i);
1861 if (tempArr != staticSpace) {