tkCanvUtil.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:48k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkCanvUtil.c --
  3.  *
  4.  * This procedure contains a collection of utility procedures
  5.  * used by the implementations of various canvas item types.
  6.  *
  7.  * Copyright (c) 1994 Sun Microsystems, Inc.
  8.  * Copyright (c) 1994 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * RCS: @(#) $Id: tkCanvUtil.c,v 1.10 2003/01/17 19:54:09 drh Exp $
  14.  */
  15. #include "tkInt.h"
  16. #include "tkCanvas.h"
  17. #include "tkPort.h"
  18. #include <assert.h>
  19. /*
  20.  *----------------------------------------------------------------------
  21.  *
  22.  * Tk_CanvasTkwin --
  23.  *
  24.  * Given a token for a canvas, this procedure returns the
  25.  * widget that represents the canvas.
  26.  *
  27.  * Results:
  28.  * The return value is a handle for the widget.
  29.  *
  30.  * Side effects:
  31.  * None.
  32.  *
  33.  *----------------------------------------------------------------------
  34.  */
  35. Tk_Window
  36. Tk_CanvasTkwin(canvas)
  37.     Tk_Canvas canvas; /* Token for the canvas. */
  38. {
  39.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  40.     return canvasPtr->tkwin;
  41. }
  42. /*
  43.  *----------------------------------------------------------------------
  44.  *
  45.  * Tk_CanvasDrawableCoords --
  46.  *
  47.  * Given an (x,y) coordinate pair within a canvas, this procedure
  48.  * returns the corresponding coordinates at which the point should
  49.  * be drawn in the drawable used for display.
  50.  *
  51.  * Results:
  52.  * There is no return value.  The values at *drawableXPtr and
  53.  * *drawableYPtr are filled in with the coordinates at which
  54.  * x and y should be drawn.  These coordinates are clipped
  55.  * to fit within a "short", since this is what X uses in
  56.  * most cases for drawing.
  57.  *
  58.  * Side effects:
  59.  * None.
  60.  *
  61.  *----------------------------------------------------------------------
  62.  */
  63. void
  64. Tk_CanvasDrawableCoords(canvas, x, y, drawableXPtr, drawableYPtr)
  65.     Tk_Canvas canvas; /* Token for the canvas. */
  66.     double x, y; /* Coordinates in canvas space. */
  67.     short *drawableXPtr, *drawableYPtr; /* Screen coordinates are stored
  68.  * here. */
  69. {
  70.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  71.     double tmp;
  72.     tmp = x - canvasPtr->drawableXOrigin;
  73.     if (tmp > 0) {
  74. tmp += 0.5;
  75.     } else {
  76. tmp -= 0.5;
  77.     }
  78.     if (tmp > 32767) {
  79. *drawableXPtr = 32767;
  80.     } else if (tmp < -32768) {
  81. *drawableXPtr = -32768;
  82.     } else {
  83. *drawableXPtr = (short) tmp;
  84.     }
  85.     tmp = y  - canvasPtr->drawableYOrigin;
  86.     if (tmp > 0) {
  87. tmp += 0.5;
  88.     } else {
  89. tmp -= 0.5;
  90.     }
  91.     if (tmp > 32767) {
  92. *drawableYPtr = 32767;
  93.     } else if (tmp < -32768) {
  94. *drawableYPtr = -32768;
  95.     } else {
  96. *drawableYPtr = (short) tmp;
  97.     }
  98. }
  99. /*
  100.  *----------------------------------------------------------------------
  101.  *
  102.  * Tk_CanvasWindowCoords --
  103.  *
  104.  * Given an (x,y) coordinate pair within a canvas, this procedure
  105.  * returns the corresponding coordinates in the canvas's window.
  106.  *
  107.  * Results:
  108.  * There is no return value.  The values at *screenXPtr and
  109.  * *screenYPtr are filled in with the coordinates at which
  110.  * (x,y) appears in the canvas's window.  These coordinates
  111.  * are clipped to fit within a "short", since this is what X
  112.  * uses in most cases for drawing.
  113.  *
  114.  * Side effects:
  115.  * None.
  116.  *
  117.  *----------------------------------------------------------------------
  118.  */
  119. void
  120. Tk_CanvasWindowCoords(canvas, x, y, screenXPtr, screenYPtr)
  121.     Tk_Canvas canvas; /* Token for the canvas. */
  122.     double x, y; /* Coordinates in canvas space. */
  123.     short *screenXPtr, *screenYPtr; /* Screen coordinates are stored
  124.  * here. */
  125. {
  126.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  127.     double tmp;
  128.     tmp = x - canvasPtr->xOrigin;
  129.     if (tmp > 0) {
  130. tmp += 0.5;
  131.     } else {
  132. tmp -= 0.5;
  133.     }
  134.     if (tmp > 32767) {
  135. *screenXPtr = 32767;
  136.     } else if (tmp < -32768) {
  137. *screenXPtr = -32768;
  138.     } else {
  139. *screenXPtr = (short) tmp;
  140.     }
  141.     tmp = y  - canvasPtr->yOrigin;
  142.     if (tmp > 0) {
  143. tmp += 0.5;
  144.     } else {
  145. tmp -= 0.5;
  146.     }
  147.     if (tmp > 32767) {
  148. *screenYPtr = 32767;
  149.     } else if (tmp < -32768) {
  150. *screenYPtr = -32768;
  151.     } else {
  152. *screenYPtr = (short) tmp;
  153.     }
  154. }
  155. /*
  156.  *--------------------------------------------------------------
  157.  *
  158.  * Tk_CanvasGetCoord --
  159.  *
  160.  * Given a string, returns a floating-point canvas coordinate
  161.  * corresponding to that string.
  162.  *
  163.  * Results:
  164.  * The return value is a standard Tcl return result.  If
  165.  * TCL_OK is returned, then everything went well and the
  166.  * canvas coordinate is stored at *doublePtr;  otherwise
  167.  * TCL_ERROR is returned and an error message is left in
  168.  * the interp's result.
  169.  *
  170.  * Side effects:
  171.  * None.
  172.  *
  173.  *--------------------------------------------------------------
  174.  */
  175. int
  176. Tk_CanvasGetCoord(interp, canvas, string, doublePtr)
  177.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  178.     Tk_Canvas canvas; /* Canvas to which coordinate applies. */
  179.     CONST char *string; /* Describes coordinate (any screen
  180.  * coordinate form may be used here). */
  181.     double *doublePtr; /* Place to store converted coordinate. */
  182. {
  183.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  184.     if (Tk_GetScreenMM(canvasPtr->interp, canvasPtr->tkwin, string,
  185.     doublePtr) != TCL_OK) {
  186. return TCL_ERROR;
  187.     }
  188.     *doublePtr *= canvasPtr->pixelsPerMM;
  189.     return TCL_OK;
  190. }
  191. /*
  192.  *--------------------------------------------------------------
  193.  *
  194.  * Tk_CanvasGetCoordFromObj --
  195.  *
  196.  * Given a string, returns a floating-point canvas coordinate
  197.  * corresponding to that string.
  198.  *
  199.  * Results:
  200.  * The return value is a standard Tcl return result.  If
  201.  * TCL_OK is returned, then everything went well and the
  202.  * canvas coordinate is stored at *doublePtr;  otherwise
  203.  * TCL_ERROR is returned and an error message is left in
  204.  * interp->result.
  205.  *
  206.  * Side effects:
  207.  * None.
  208.  *
  209.  *--------------------------------------------------------------
  210.  */
  211. int
  212. Tk_CanvasGetCoordFromObj(interp, canvas, obj, doublePtr)
  213.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  214.     Tk_Canvas canvas; /* Canvas to which coordinate applies. */
  215.     Tcl_Obj *obj; /* Describes coordinate (any screen
  216.  * coordinate form may be used here). */
  217.     double *doublePtr; /* Place to store converted coordinate. */
  218. {
  219.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  220.     if (Tk_GetMMFromObj(canvasPtr->interp, canvasPtr->tkwin, obj,
  221.     doublePtr) != TCL_OK) {
  222. return TCL_ERROR;
  223.     }
  224.     *doublePtr *= canvasPtr->pixelsPerMM;
  225.     return TCL_OK;
  226. }
  227. /*
  228.  *----------------------------------------------------------------------
  229.  *
  230.  * Tk_CanvasSetStippleOrigin --
  231.  *
  232.  * This procedure sets the stipple origin in a graphics context
  233.  * so that stipples drawn with the GC will line up with other
  234.  * stipples previously drawn in the canvas.
  235.  *
  236.  * Results:
  237.  * None.
  238.  *
  239.  * Side effects:
  240.  * The graphics context is modified.
  241.  *
  242.  *----------------------------------------------------------------------
  243.  */
  244. void
  245. Tk_CanvasSetStippleOrigin(canvas, gc)
  246.     Tk_Canvas canvas; /* Token for a canvas. */
  247.     GC gc; /* Graphics context that is about to be
  248.  * used to draw a stippled pattern as
  249.  * part of redisplaying the canvas. */
  250. {
  251.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  252.     XSetTSOrigin(canvasPtr->display, gc, -canvasPtr->drawableXOrigin,
  253.     -canvasPtr->drawableYOrigin);
  254. }
  255. /*
  256.  *----------------------------------------------------------------------
  257.  *
  258.  * Tk_CanvasSetOffset--
  259.  *
  260.  * This procedure sets the stipple offset in a graphics
  261.  * context so that stipples drawn with the GC will
  262.  * line up with other stipples with the same offset.
  263.  *
  264.  * Results:
  265.  * None.
  266.  *
  267.  * Side effects:
  268.  * The graphics context is modified.
  269.  *
  270.  *----------------------------------------------------------------------
  271.  */
  272. void
  273. Tk_CanvasSetOffset(canvas, gc, offset)
  274.     Tk_Canvas canvas; /* Token for a canvas. */
  275.     GC gc; /* Graphics context that is about to be
  276.  * used to draw a stippled pattern as
  277.  * part of redisplaying the canvas. */
  278.     Tk_TSOffset *offset; /* offset (may be NULL pointer)*/
  279. {
  280.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  281.     int flags = 0;
  282.     int x = - canvasPtr->drawableXOrigin;
  283.     int y = - canvasPtr->drawableYOrigin;
  284.     if (offset != NULL) {
  285. flags = offset->flags;
  286. x += offset->xoffset;
  287. y += offset->yoffset;
  288.     }
  289.     if ((flags & TK_OFFSET_RELATIVE) && !(flags & TK_OFFSET_INDEX)) {
  290. Tk_SetTSOrigin(canvasPtr->tkwin, gc, x - canvasPtr->xOrigin,
  291. y - canvasPtr->yOrigin);
  292.     } else {
  293. XSetTSOrigin(canvasPtr->display, gc, x, y);
  294.     }
  295. }
  296. /*
  297.  *----------------------------------------------------------------------
  298.  *
  299.  * Tk_CanvasGetTextInfo --
  300.  *
  301.  * This procedure returns a pointer to a structure containing
  302.  * information about the selection and insertion cursor for
  303.  * a canvas widget.  Items such as text items save the pointer
  304.  * and use it to share access to the information with the generic
  305.  * canvas code.
  306.  *
  307.  * Results:
  308.  * The return value is a pointer to the structure holding text
  309.  * information for the canvas.  Most of the fields should not
  310.  * be modified outside the generic canvas code;  see the user
  311.  * documentation for details.
  312.  *
  313.  * Side effects:
  314.  * None.
  315.  *
  316.  *----------------------------------------------------------------------
  317.  */
  318. Tk_CanvasTextInfo *
  319. Tk_CanvasGetTextInfo(canvas)
  320.     Tk_Canvas canvas; /* Token for the canvas widget. */
  321. {
  322.     return &((TkCanvas *) canvas)->textInfo;
  323. }
  324. /*
  325.  *--------------------------------------------------------------
  326.  *
  327.  * Tk_CanvasTagsParseProc --
  328.  *
  329.  * This procedure is invoked during option processing to handle
  330.  * "-tags" options for canvas items.
  331.  *
  332.  * Results:
  333.  * A standard Tcl return value.
  334.  *
  335.  * Side effects:
  336.  * The tags for a given item get replaced by those indicated
  337.  * in the value argument.
  338.  *
  339.  *--------------------------------------------------------------
  340.  */
  341. int
  342. Tk_CanvasTagsParseProc(clientData, interp, tkwin, value, widgRec, offset)
  343.     ClientData clientData; /* Not used.*/
  344.     Tcl_Interp *interp; /* Used for reporting errors. */
  345.     Tk_Window tkwin; /* Window containing canvas widget. */
  346.     CONST char *value; /* Value of option (list of tag
  347.  * names). */
  348.     char *widgRec; /* Pointer to record for item. */
  349.     int offset; /* Offset into item (ignored). */
  350. {
  351.     register Tk_Item *itemPtr = (Tk_Item *) widgRec;
  352.     int argc, i;
  353.     CONST char **argv;
  354.     Tk_Uid *newPtr;
  355.     /*
  356.      * Break the value up into the individual tag names.
  357.      */
  358.     if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) {
  359. return TCL_ERROR;
  360.     }
  361.     /*
  362.      * Make sure that there's enough space in the item to hold the
  363.      * tag names.
  364.      */
  365.     if (itemPtr->tagSpace < argc) {
  366. newPtr = (Tk_Uid *) ckalloc((unsigned) (argc * sizeof(Tk_Uid)));
  367. for (i = itemPtr->numTags-1; i >= 0; i--) {
  368.     newPtr[i] = itemPtr->tagPtr[i];
  369. }
  370. if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
  371.     ckfree((char *) itemPtr->tagPtr);
  372. }
  373. itemPtr->tagPtr = newPtr;
  374. itemPtr->tagSpace = argc;
  375.     }
  376.     itemPtr->numTags = argc;
  377.     for (i = 0; i < argc; i++) {
  378. itemPtr->tagPtr[i] = Tk_GetUid(argv[i]);
  379.     }
  380.     ckfree((char *) argv);
  381.     return TCL_OK;
  382. }
  383. /*
  384.  *--------------------------------------------------------------
  385.  *
  386.  * Tk_CanvasTagsPrintProc --
  387.  *
  388.  * This procedure is invoked by the Tk configuration code
  389.  * to produce a printable string for the "-tags" configuration
  390.  * option for canvas items.
  391.  *
  392.  * Results:
  393.  * The return value is a string describing all the tags for
  394.  * the item referred to by "widgRec".  In addition, *freeProcPtr
  395.  * is filled in with the address of a procedure to call to free
  396.  * the result string when it's no longer needed (or NULL to
  397.  * indicate that the string doesn't need to be freed).
  398.  *
  399.  * Side effects:
  400.  * None.
  401.  *
  402.  *--------------------------------------------------------------
  403.  */
  404. char *
  405. Tk_CanvasTagsPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  406.     ClientData clientData; /* Ignored. */
  407.     Tk_Window tkwin; /* Window containing canvas widget. */
  408.     char *widgRec; /* Pointer to record for item. */
  409.     int offset; /* Ignored. */
  410.     Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
  411.  * information about how to reclaim
  412.  * storage for return string. */
  413. {
  414.     register Tk_Item *itemPtr = (Tk_Item *) widgRec;
  415.     if (itemPtr->numTags == 0) {
  416. *freeProcPtr = (Tcl_FreeProc *) NULL;
  417. return "";
  418.     }
  419.     if (itemPtr->numTags == 1) {
  420. *freeProcPtr = (Tcl_FreeProc *) NULL;
  421. return (char *) itemPtr->tagPtr[0];
  422.     }
  423.     *freeProcPtr = TCL_DYNAMIC;
  424.     return Tcl_Merge(itemPtr->numTags, (CONST char **) itemPtr->tagPtr);
  425. }
  426. static int DashConvert _ANSI_ARGS_((char *l, CONST char *p,
  427. int n, double width));
  428. #define ABS(a) ((a>=0)?(a):(-(a)))
  429. /*
  430.  *--------------------------------------------------------------
  431.  *
  432.  * TkCanvasDashParseProc --
  433.  *
  434.  * This procedure is invoked during option processing to handle
  435.  * "-dash", "-activedash" and "-disableddash" options for canvas
  436.  * objects.
  437.  *
  438.  * Results:
  439.  * A standard Tcl return value.
  440.  *
  441.  * Side effects:
  442.  * The dash list for a given canvas object gets replaced by
  443.  * those indicated in the value argument.
  444.  *
  445.  *--------------------------------------------------------------
  446.  */
  447. int
  448. TkCanvasDashParseProc(clientData, interp, tkwin, value, widgRec, offset)
  449.     ClientData clientData; /* Not used.*/
  450.     Tcl_Interp *interp; /* Used for reporting errors. */
  451.     Tk_Window tkwin; /* Window containing canvas widget. */
  452.     CONST char *value; /* Value of option. */
  453.     char *widgRec; /* Pointer to record for item. */
  454.     int offset; /* Offset into item. */
  455. {
  456.     return Tk_GetDash(interp, value, (Tk_Dash *)(widgRec+offset));
  457. }
  458. /*
  459.  *--------------------------------------------------------------
  460.  *
  461.  * TkCanvasDashPrintProc --
  462.  *
  463.  * This procedure is invoked by the Tk configuration code
  464.  * to produce a printable string for the "-dash", "-activedash"
  465.  * and "-disableddash" configuration options for canvas items.
  466.  *
  467.  * Results:
  468.  * The return value is a string describing all the dash list for
  469.  * the item referred to by "widgRec"and "offset".  In addition,
  470.  * *freeProcPtr is filled in with the address of a procedure to
  471.  * call to free the result string when it's no longer needed (or
  472.  * NULL to indicate that the string doesn't need to be freed).
  473.  *
  474.  * Side effects:
  475.  * None.
  476.  *
  477.  *--------------------------------------------------------------
  478.  */
  479. char *
  480. TkCanvasDashPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  481.     ClientData clientData; /* Ignored. */
  482.     Tk_Window tkwin; /* Window containing canvas widget. */
  483.     char *widgRec; /* Pointer to record for item. */
  484.     int offset; /* Offset in record for item. */
  485.     Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
  486.  * information about how to reclaim
  487.  * storage for return string. */
  488. {
  489.     Tk_Dash *dash = (Tk_Dash *) (widgRec+offset);
  490.     char *buffer;
  491.     char *p;
  492.     int i = dash->number;
  493.     if (i < 0) {
  494. i = -i;
  495. *freeProcPtr = TCL_DYNAMIC;
  496. buffer = (char *) ckalloc((unsigned int) (i+1));
  497. p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
  498. memcpy(buffer, p, (unsigned int) i);
  499. buffer[i] = 0;
  500. return buffer;
  501.     } else if (!i) {
  502. *freeProcPtr = (Tcl_FreeProc *) NULL;
  503. return "";
  504.     }
  505.     buffer = (char *)ckalloc((unsigned int) (4*i));
  506.     *freeProcPtr = TCL_DYNAMIC;
  507.     p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
  508.     sprintf(buffer, "%d", *p++ & 0xff);
  509.     while(--i) {
  510. sprintf(buffer+strlen(buffer), " %d", *p++ & 0xff);
  511.     }
  512.     return buffer;
  513. }
  514. /*
  515.  *--------------------------------------------------------------
  516.  *
  517.  * Tk_CreateSmoothMethod --
  518.  *
  519.  * This procedure is invoked to add additional values
  520.  * for the "-smooth" option to the list.
  521.  *
  522.  * Results:
  523.  * A standard Tcl return value.
  524.  *
  525.  * Side effects:
  526.  * In the future "-smooth <name>" will be accepted as
  527.  * smooth method for the line and polygon.
  528.  *
  529.  *--------------------------------------------------------------
  530.  */
  531. Tk_SmoothMethod tkBezierSmoothMethod = {
  532.     "bezier",
  533.     TkMakeBezierCurve,
  534.     (void (*) _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
  535.     double *coordPtr, int numPoints, int numSteps)))
  536. TkMakeBezierPostscript,
  537. };
  538. static void SmoothMethodCleanupProc _ANSI_ARGS_((ClientData clientData,
  539. Tcl_Interp *interp));
  540. typedef struct SmoothAssocData {
  541.     struct SmoothAssocData *nextPtr; /* pointer to next SmoothAssocData */
  542.     Tk_SmoothMethod smooth; /* name and functions associated with this
  543.  * option */
  544. } SmoothAssocData;
  545. void
  546. Tk_CreateSmoothMethod(interp, smooth)
  547.     Tcl_Interp *interp;
  548.     Tk_SmoothMethod *smooth;
  549. {
  550.     SmoothAssocData *methods, *typePtr2, *prevPtr, *ptr;
  551.     methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod",
  552.     (Tcl_InterpDeleteProc **) NULL);
  553.     /*
  554.      * If there's already a smooth method with the given name, remove it.
  555.      */
  556.     for (typePtr2 = methods, prevPtr = NULL; typePtr2 != NULL;
  557.     prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
  558. if (!strcmp(typePtr2->smooth.name, smooth->name)) {
  559.     if (prevPtr == NULL) {
  560. methods = typePtr2->nextPtr;
  561.     } else {
  562. prevPtr->nextPtr = typePtr2->nextPtr;
  563.     }
  564.     ckfree((char *) typePtr2);
  565.     break;
  566. }
  567.     }
  568.     ptr = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData));
  569.     ptr->smooth.name = smooth->name;
  570.     ptr->smooth.coordProc = smooth->coordProc;
  571.     ptr->smooth.postscriptProc = smooth->postscriptProc;
  572.     ptr->nextPtr = methods;
  573.     Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc,
  574. (ClientData) ptr);
  575. }
  576. /*
  577.  *----------------------------------------------------------------------
  578.  *
  579.  * SmoothMethodCleanupProc --
  580.  *
  581.  * This procedure is invoked whenever an interpreter is deleted
  582.  * to cleanup the smooth methods.
  583.  *
  584.  * Results:
  585.  * None.
  586.  *
  587.  * Side effects:
  588.  * Smooth methods are removed.
  589.  *
  590.  *----------------------------------------------------------------------
  591.  */
  592. static void
  593. SmoothMethodCleanupProc(clientData, interp)
  594.     ClientData clientData; /* Points to "smoothMethod" AssocData
  595.  * for the interpreter. */
  596.     Tcl_Interp *interp; /* Interpreter that is being deleted. */
  597. {
  598.     SmoothAssocData *ptr, *methods = (SmoothAssocData *) clientData;
  599.     while (methods != NULL) {
  600. methods = (ptr = methods)->nextPtr;
  601. ckfree((char *) ptr);
  602.     }
  603. }
  604. /*
  605.  *--------------------------------------------------------------
  606.  *
  607.  * TkSmoothParseProc --
  608.  *
  609.  * This procedure is invoked during option processing to handle
  610.  * the "-smooth" option.
  611.  *
  612.  * Results:
  613.  * A standard Tcl return value.
  614.  *
  615.  * Side effects:
  616.  * The smooth option for a given item gets replaced by the value
  617.  * indicated in the value argument.
  618.  *
  619.  *--------------------------------------------------------------
  620.  */
  621. int
  622. TkSmoothParseProc(clientData, interp, tkwin, value, widgRec, offset)
  623.     ClientData clientData; /* some flags.*/
  624.     Tcl_Interp *interp; /* Used for reporting errors. */
  625.     Tk_Window tkwin; /* Window containing canvas widget. */
  626.     CONST char *value; /* Value of option. */
  627.     char *widgRec; /* Pointer to record for item. */
  628.     int offset; /* Offset into item. */
  629. {
  630.     register Tk_SmoothMethod **smoothPtr =
  631. (Tk_SmoothMethod **) (widgRec + offset);
  632.     Tk_SmoothMethod *smooth = NULL;
  633.     int b;
  634.     size_t length;
  635.     SmoothAssocData *methods;
  636.     if (value == NULL || *value == 0) {
  637. *smoothPtr = (Tk_SmoothMethod *) NULL;
  638. return TCL_OK;
  639.     }
  640.     length = strlen(value);
  641.     methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod",
  642.     (Tcl_InterpDeleteProc **) NULL);
  643.     while (methods != (SmoothAssocData *) NULL) {
  644. if (strncmp(value, methods->smooth.name, length) == 0) {
  645.     if (smooth != (Tk_SmoothMethod *) NULL) {
  646. Tcl_AppendResult(interp, "ambigeous smooth method "", value,
  647. """, (char *) NULL);
  648. return TCL_ERROR;
  649.     }
  650.     smooth = &methods->smooth;
  651. }
  652. methods = methods->nextPtr;
  653.     }
  654.     if (smooth) {
  655. *smoothPtr = smooth;
  656. return TCL_OK;
  657.     } else if (strncmp(value, tkBezierSmoothMethod.name, length) == 0) {
  658. /*
  659.  * We need to do handle the built-in bezier method.
  660.  */
  661. *smoothPtr = &tkBezierSmoothMethod;
  662. return TCL_OK;
  663.     }
  664.     if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) {
  665. return TCL_ERROR;
  666.     }
  667.     *smoothPtr = b ? &tkBezierSmoothMethod : (Tk_SmoothMethod*) NULL;
  668.     return TCL_OK;
  669. }
  670. /*
  671.  *--------------------------------------------------------------
  672.  *
  673.  * TkSmoothPrintProc --
  674.  *
  675.  * This procedure is invoked by the Tk configuration code
  676.  * to produce a printable string for the "-smooth"
  677.  * configuration option.
  678.  *
  679.  * Results:
  680.  * The return value is a string describing the smooth option for
  681.  * the item referred to by "widgRec".  In addition, *freeProcPtr
  682.  * is filled in with the address of a procedure to call to free
  683.  * the result string when it's no longer needed (or NULL to
  684.  * indicate that the string doesn't need to be freed).
  685.  *
  686.  * Side effects:
  687.  * None.
  688.  *
  689.  *--------------------------------------------------------------
  690.  */
  691. char *
  692. TkSmoothPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
  693.     ClientData clientData; /* Ignored. */
  694.     Tk_Window tkwin; /* Window containing canvas widget. */
  695.     char *widgRec; /* Pointer to record for item. */
  696.     int offset; /* Offset into item. */
  697.     Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
  698.  * information about how to reclaim
  699.  * storage for return string. */
  700. {
  701.     register Tk_SmoothMethod **smoothPtr = (Tk_SmoothMethod **) (widgRec + offset);
  702.     return (*smoothPtr) ? (*smoothPtr)->name : "0";
  703. }
  704. /*
  705.  *--------------------------------------------------------------
  706.  *
  707.  * Tk_GetDash
  708.  *
  709.  * This procedure is used to parse a string, assuming
  710.  * it is dash information.
  711.  *
  712.  * Results:
  713.  * The return value is a standard Tcl result:  TCL_OK means
  714.  * that the dash information was parsed ok, and
  715.  * TCL_ERROR means it couldn't be parsed.
  716.  *
  717.  * Side effects:
  718.  * Dash information in the dash structure is updated.
  719.  *
  720.  *--------------------------------------------------------------
  721.  */
  722. int
  723. Tk_GetDash(interp, value, dash)
  724.     Tcl_Interp *interp; /* Used for error reporting. */
  725.     CONST char *value; /* Textual specification of dash list. */
  726.     Tk_Dash *dash; /* Pointer to record in which to
  727.  * store dash information. */
  728. {
  729.     int argc, i;
  730.     CONST char **largv, **argv = NULL;
  731.     char *pt;
  732.     if ((value==(char *) NULL) || (*value==0) ) {
  733. dash->number = 0;
  734. return TCL_OK;
  735.     }
  736.     if ((*value == '.') || (*value == ',') ||
  737.     (*value == '-') || (*value == '_')) {
  738. i = DashConvert((char *) NULL, value, -1, 0.0);
  739. if (i>0) {
  740.     i = strlen(value);
  741. } else {
  742.     goto badDashList;
  743. }
  744. if (i > sizeof(char *)) {
  745.     dash->pattern.pt = pt = (char *) ckalloc(strlen(value));
  746. } else {
  747.     pt = dash->pattern.array;
  748. }
  749. memcpy(pt,value, (unsigned int) i);
  750. dash->number = -i;
  751. return TCL_OK;
  752.     }
  753.     if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) {
  754. Tcl_ResetResult(interp);
  755.     badDashList:
  756. Tcl_AppendResult(interp, "bad dash list "", value,
  757. "": must be a list of integers or a format like "-.."",
  758. (char *) NULL);
  759.     syntaxError:
  760. if (argv != NULL) {
  761.     ckfree((char *) argv);
  762. }
  763. if (ABS(dash->number) > sizeof(char *))
  764.     ckfree((char *) dash->pattern.pt);
  765. dash->number = 0;
  766. return TCL_ERROR;
  767.     }
  768.     if (ABS(dash->number) > sizeof(char *)) {
  769. ckfree((char *) dash->pattern.pt);
  770.     }
  771.     if (argc > sizeof(char *)) {
  772. dash->pattern.pt = pt = (char *) ckalloc((unsigned int) argc);
  773.     } else {
  774. pt = dash->pattern.array;
  775.     }
  776.     dash->number = argc;
  777.     largv = argv;
  778.     while(argc>0) {
  779. if (Tcl_GetInt(interp, *largv, &i) != TCL_OK ||
  780.     i < 1 || i>255) {
  781.     Tcl_ResetResult(interp);
  782.     Tcl_AppendResult(interp, "expected integer in the range 1..255 but got "",
  783.  *largv, """, (char *) NULL);
  784.     goto syntaxError;
  785. }
  786. *pt++ = i;
  787. argc--; largv++; 
  788.     }
  789.   
  790.     if (argv != NULL) {
  791. ckfree((char *) argv);
  792.     }
  793.     return TCL_OK;
  794. }
  795. /*
  796.  *--------------------------------------------------------------
  797.  *
  798.  * Tk_CreateOutline
  799.  *
  800.  * This procedure initializes the Tk_Outline structure
  801.  * with default values.
  802.  *
  803.  * Results:
  804.  * None
  805.  *
  806.  * Side effects:
  807.  * None
  808.  *
  809.  *--------------------------------------------------------------
  810.  */
  811. void Tk_CreateOutline(outline)
  812.     Tk_Outline *outline;
  813. {
  814.     outline->gc = None;
  815.     outline->width = 1.0;
  816.     outline->activeWidth = 0.0;
  817.     outline->disabledWidth = 0.0;
  818.     outline->offset = 0;
  819.     outline->dash.number = 0;
  820.     outline->activeDash.number = 0;
  821.     outline->disabledDash.number = 0;
  822.     outline->tsoffset.flags = 0;
  823.     outline->tsoffset.xoffset = 0;
  824.     outline->tsoffset.yoffset = 0;
  825.     outline->color = NULL;
  826.     outline->activeColor = NULL;
  827.     outline->disabledColor = NULL;
  828.     outline->stipple = None;
  829.     outline->activeStipple = None;
  830.     outline->disabledStipple = None;
  831. }
  832. /*
  833.  *--------------------------------------------------------------
  834.  *
  835.  * Tk_DeleteOutline
  836.  *
  837.  * This procedure frees all memory that might be
  838.  * allocated and referenced in the Tk_Outline structure.
  839.  *
  840.  * Results:
  841.  * None
  842.  *
  843.  * Side effects:
  844.  * None
  845.  *
  846.  *--------------------------------------------------------------
  847.  */
  848. void Tk_DeleteOutline(display, outline)
  849.     Display *display; /* Display containing window */
  850.     Tk_Outline *outline;
  851. {
  852.     if (outline->gc != None) {
  853. Tk_FreeGC(display, outline->gc);
  854.     }
  855.     if (ABS(outline->dash.number) > sizeof(char *)) {
  856. ckfree((char *) outline->dash.pattern.pt);
  857.     }
  858.     if (ABS(outline->activeDash.number) > sizeof(char *)) {
  859. ckfree((char *) outline->activeDash.pattern.pt);
  860.     }
  861.     if (ABS(outline->disabledDash.number) > sizeof(char *)) {
  862. ckfree((char *) outline->disabledDash.pattern.pt);
  863.     }
  864.     if (outline->color != NULL) {
  865. Tk_FreeColor(outline->color);
  866.     }
  867.     if (outline->activeColor != NULL) {
  868. Tk_FreeColor(outline->activeColor);
  869.     }
  870.     if (outline->disabledColor != NULL) {
  871. Tk_FreeColor(outline->disabledColor);
  872.     }
  873.     if (outline->stipple != None) {
  874. Tk_FreeBitmap(display, outline->stipple);
  875.     }
  876.     if (outline->activeStipple != None) {
  877. Tk_FreeBitmap(display, outline->activeStipple);
  878.     }
  879.     if (outline->disabledStipple != None) {
  880. Tk_FreeBitmap(display, outline->disabledStipple);
  881.     }
  882. }
  883. /*
  884.  *--------------------------------------------------------------
  885.  *
  886.  * Tk_ConfigOutlineGC
  887.  *
  888.  * This procedure should be called in the canvas object
  889.  * during the configure command. The graphics context
  890.  * description in gcValues is updated according to the
  891.  * information in the dash structure, as far as possible.
  892.  *
  893.  * Results:
  894.  * The return-value is a mask, indicating which
  895.  * elements of gcValues have been updated.
  896.  * 0 means there is no outline.
  897.  *
  898.  * Side effects:
  899.  * GC information in gcValues is updated.
  900.  *
  901.  *--------------------------------------------------------------
  902.  */
  903. int Tk_ConfigOutlineGC(gcValues, canvas, item, outline)
  904.     XGCValues *gcValues;
  905.     Tk_Canvas canvas;
  906.     Tk_Item *item;
  907.     Tk_Outline *outline;
  908. {
  909.     int mask = 0;
  910.     double width;
  911.     Tk_Dash *dash;
  912.     XColor *color;
  913.     Pixmap stipple;
  914.     Tk_State state = item->state;
  915.     if (outline->width < 0.0) {
  916. outline->width = 0.0;
  917.     }
  918.     if (outline->activeWidth < 0.0) {
  919. outline->activeWidth = 0.0;
  920.     }
  921.     if (outline->disabledWidth < 0) {
  922. outline->disabledWidth = 0.0;
  923.     }
  924.     if (state==TK_STATE_HIDDEN) {
  925. return 0;
  926.     }
  927.     width = outline->width;
  928.     if (width < 1.0) {
  929. width = 1.0;
  930.     }
  931.     dash = &(outline->dash);
  932.     color = outline->color;
  933.     stipple = outline->stipple;
  934.     if (state == TK_STATE_NULL) {
  935. state = ((TkCanvas *)canvas)->canvas_state;
  936.     }
  937.     if (((TkCanvas *)canvas)->currentItemPtr == item) {
  938. if (outline->activeWidth>width) {
  939.     width = outline->activeWidth;
  940. }
  941. if (outline->activeDash.number != 0) {
  942.     dash = &(outline->activeDash);
  943. }
  944. if (outline->activeColor!=NULL) {
  945.     color = outline->activeColor;
  946. }
  947. if (outline->activeStipple!=None) {
  948.     stipple = outline->activeStipple;
  949. }
  950.     } else if (state==TK_STATE_DISABLED) {
  951. if (outline->disabledWidth>0) {
  952.     width = outline->disabledWidth;
  953. }
  954. if (outline->disabledDash.number != 0) {
  955.     dash = &(outline->disabledDash);
  956. }
  957. if (outline->disabledColor!=NULL) {
  958.     color = outline->disabledColor;
  959. }
  960. if (outline->disabledStipple!=None) {
  961.     stipple = outline->disabledStipple;
  962. }
  963.     }
  964.     if (color==NULL) {
  965. return 0;
  966.     }
  967.     gcValues->line_width = (int) (width + 0.5);
  968.     if (color != NULL) {
  969. gcValues->foreground = color->pixel;
  970. mask = GCForeground|GCLineWidth;
  971. if (stipple != None) {
  972.     gcValues->stipple = stipple;
  973.     gcValues->fill_style = FillStippled;
  974.     mask |= GCStipple|GCFillStyle;
  975. }
  976.     }
  977.     if (mask && (dash->number != 0)) {
  978. gcValues->line_style = LineOnOffDash;
  979. gcValues->dash_offset = outline->offset;
  980. if (dash->number >= 2) {
  981.     gcValues->dashes = 4;
  982. } else if (dash->number > 0) {
  983.     gcValues->dashes = dash->pattern.array[0];
  984. } else {
  985.     gcValues->dashes = (char) (4 * width);
  986. }
  987. mask |= GCLineStyle|GCDashList|GCDashOffset;
  988.     }
  989.     return mask;
  990. }
  991. /*
  992.  *--------------------------------------------------------------
  993.  *
  994.  * Tk_ChangeOutlineGC
  995.  *
  996.  * Updates the GC to represent the full information of
  997.  * the dash structure. Partly this is already done in
  998.  * Tk_ConfigOutlineGC().
  999.  * This function should be called just before drawing
  1000.  * the dashed item.
  1001.  *
  1002.  * Results:
  1003.  * 1 if there is a stipple pattern.
  1004.  * 0 otherwise.
  1005.  *
  1006.  * Side effects:
  1007.  * GC is updated.
  1008.  *
  1009.  *--------------------------------------------------------------
  1010.  */
  1011. int
  1012. Tk_ChangeOutlineGC(canvas, item, outline)
  1013.     Tk_Canvas canvas;
  1014.     Tk_Item *item;
  1015.     Tk_Outline *outline;
  1016. {
  1017.     CONST char *p;
  1018.     double width;
  1019.     Tk_Dash *dash;
  1020.     XColor *color;
  1021.     Pixmap stipple;
  1022.     Tk_State state = item->state;
  1023.     width = outline->width;
  1024.     if (width < 1.0) {
  1025. width = 1.0;
  1026.     }
  1027.     dash = &(outline->dash);
  1028.     color = outline->color;
  1029.     stipple = outline->stipple;
  1030.     if (state == TK_STATE_NULL) {
  1031. state = ((TkCanvas *)canvas)->canvas_state;
  1032.     }
  1033.     if (((TkCanvas *)canvas)->currentItemPtr == item) {
  1034. if (outline->activeWidth > width) {
  1035.     width = outline->activeWidth;
  1036. }
  1037. if (outline->activeDash.number != 0) {
  1038.     dash = &(outline->activeDash);
  1039. }
  1040. if (outline->activeColor != NULL) {
  1041.     color = outline->activeColor;
  1042. }
  1043. if (outline->activeStipple != None) {
  1044.     stipple = outline->activeStipple;
  1045. }
  1046.     } else if (state == TK_STATE_DISABLED) {
  1047. if (outline->disabledWidth > width) {
  1048.     width = outline->disabledWidth;
  1049. }
  1050. if (outline->disabledDash.number != 0) {
  1051.     dash = &(outline->disabledDash);
  1052. }
  1053. if (outline->disabledColor != NULL) {
  1054.     color = outline->disabledColor;
  1055. }
  1056. if (outline->disabledStipple != None) {
  1057.     stipple = outline->disabledStipple;
  1058. }
  1059.     }
  1060.     if (color==NULL) {
  1061. return 0;
  1062.     }
  1063.     if ((dash->number<-1) || ((dash->number == -1) && (dash->pattern.array[1]!=','))) {
  1064. char *q;
  1065. int i = -dash->number;
  1066.         p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
  1067. q = (char *) ckalloc(2*(unsigned int)i);
  1068. i = DashConvert(q, p, i, width);
  1069. XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, q, i);
  1070. ckfree(q);
  1071.     } else if ( dash->number>2 || (dash->number==2 &&
  1072. (dash->pattern.array[0]!=dash->pattern.array[1]))) {
  1073.         p = (char *) (dash->number > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
  1074. XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, p, dash->number);
  1075.     }
  1076.     if (stipple!=None) {
  1077. int w=0; int h=0;
  1078. Tk_TSOffset *tsoffset = &outline->tsoffset;
  1079. int flags = tsoffset->flags;
  1080. if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) {
  1081.     Tk_SizeOfBitmap(((TkCanvas *)canvas)->display, stipple, &w, &h);
  1082.     if (flags & TK_OFFSET_CENTER) {
  1083. w /= 2;
  1084.     } else {
  1085. w = 0;
  1086.     }
  1087.     if (flags & TK_OFFSET_MIDDLE) {
  1088. h /= 2;
  1089.     } else {
  1090. h = 0;
  1091.     }
  1092. }
  1093. tsoffset->xoffset -= w;
  1094. tsoffset->yoffset -= h;
  1095. Tk_CanvasSetOffset(canvas, outline->gc, tsoffset);
  1096. tsoffset->xoffset += w;
  1097. tsoffset->yoffset += h;
  1098. return 1;
  1099.     }
  1100.     return 0;
  1101. }
  1102. /*
  1103.  *--------------------------------------------------------------
  1104.  *
  1105.  * Tk_ResetOutlineGC
  1106.  *
  1107.  * Restores the GC to the situation before 
  1108.  * Tk_ChangeDashGC() was called.
  1109.  * This function should be called just after the dashed
  1110.  * item is drawn, because the GC is supposed to be
  1111.  * read-only.
  1112.  *
  1113.  * Results:
  1114.  * 1 if there is a stipple pattern.
  1115.  * 0 otherwise.
  1116.  *
  1117.  * Side effects:
  1118.  * GC is updated.
  1119.  *
  1120.  *--------------------------------------------------------------
  1121.  */
  1122. int
  1123. Tk_ResetOutlineGC(canvas, item, outline)
  1124.     Tk_Canvas canvas;
  1125.     Tk_Item *item;
  1126.     Tk_Outline *outline;
  1127. {
  1128.     char dashList;
  1129.     double width;
  1130.     Tk_Dash *dash;
  1131.     XColor *color;
  1132.     Pixmap stipple;
  1133.     Tk_State state = item->state;
  1134.     width = outline->width;
  1135.     if (width < 1.0) {
  1136. width = 1.0;
  1137.     }
  1138.     dash = &(outline->dash);
  1139.     color = outline->color;
  1140.     stipple = outline->stipple;
  1141.     if (state == TK_STATE_NULL) {
  1142. state = ((TkCanvas *)canvas)->canvas_state;
  1143.     }
  1144.     if (((TkCanvas *)canvas)->currentItemPtr == item) {
  1145. if (outline->activeWidth>width) {
  1146.     width = outline->activeWidth;
  1147. }
  1148. if (outline->activeDash.number != 0) {
  1149.     dash = &(outline->activeDash);
  1150. }
  1151. if (outline->activeColor!=NULL) {
  1152.     color = outline->activeColor;
  1153. }
  1154. if (outline->activeStipple!=None) {
  1155.     stipple = outline->activeStipple;
  1156. }
  1157.     } else if (state==TK_STATE_DISABLED) {
  1158. if (outline->disabledWidth>width) {
  1159.     width = outline->disabledWidth;
  1160. }
  1161. if (outline->disabledDash.number != 0) {
  1162.     dash = &(outline->disabledDash);
  1163. }
  1164. if (outline->disabledColor!=NULL) {
  1165.     color = outline->disabledColor;
  1166. }
  1167. if (outline->disabledStipple!=None) {
  1168.     stipple = outline->disabledStipple;
  1169. }
  1170.     }
  1171.     if (color==NULL) {
  1172. return 0;
  1173.     }
  1174.     if ((dash->number > 2) || (dash->number < -1) || (dash->number==2 &&
  1175. (dash->pattern.array[0] != dash->pattern.array[1])) ||
  1176. ((dash->number == -1) && (dash->pattern.array[1] != ','))) {
  1177. if (dash->number < 0) {
  1178.     dashList = (int) (4 * width + 0.5);
  1179. } else if (dash->number<3) {
  1180.     dashList = dash->pattern.array[0];
  1181. } else {
  1182.     dashList = 4;
  1183. }
  1184. XSetDashes(((TkCanvas *)canvas)->display, outline->gc,
  1185. outline->offset, &dashList , 1);
  1186.     }
  1187.     if (stipple != None) {
  1188. XSetTSOrigin(((TkCanvas *)canvas)->display, outline->gc, 0, 0);
  1189. return 1;
  1190.     }
  1191.     return 0;
  1192. }
  1193. /*
  1194.  *--------------------------------------------------------------
  1195.  *
  1196.  * Tk_CanvasPsOutline
  1197.  *
  1198.  * Creates the postscript command for the correct
  1199.  * Outline-information (width, dash, color and stipple).
  1200.  *
  1201.  * Results:
  1202.  * TCL_OK if succeeded, otherwise TCL_ERROR.
  1203.  *
  1204.  * Side effects:
  1205.  * canvas->interp->result contains the postscript string,
  1206.  * or an error message if the result was TCL_ERROR.
  1207.  *
  1208.  *--------------------------------------------------------------
  1209.  */
  1210. int
  1211. Tk_CanvasPsOutline(canvas, item, outline)
  1212.     Tk_Canvas canvas;
  1213.     Tk_Item *item;
  1214.     Tk_Outline *outline;
  1215. {
  1216.     char string[41];
  1217.     char pattern[11];
  1218.     int i;
  1219.     char *ptr;
  1220.     char *str = string;
  1221.     char *lptr = pattern;
  1222.     Tcl_Interp *interp = ((TkCanvas *)canvas)->interp;
  1223.     double width;
  1224.     Tk_Dash *dash;
  1225.     XColor *color;
  1226.     Pixmap stipple;
  1227.     Tk_State state = item->state;
  1228.     width = outline->width;
  1229.     dash = &(outline->dash);
  1230.     color = outline->color;
  1231.     stipple = outline->stipple;
  1232.     if (state == TK_STATE_NULL) {
  1233. state = ((TkCanvas *)canvas)->canvas_state;
  1234.     }
  1235.     if (((TkCanvas *)canvas)->currentItemPtr == item) {
  1236. if (outline->activeWidth > width) {
  1237.     width = outline->activeWidth;
  1238. }
  1239. if (outline->activeDash.number > 0) {
  1240.     dash = &(outline->activeDash);
  1241. }
  1242. if (outline->activeColor != NULL) {
  1243.     color = outline->activeColor;
  1244. }
  1245. if (outline->activeStipple != None) {
  1246.     stipple = outline->activeStipple;
  1247. }
  1248.     } else if (state == TK_STATE_DISABLED) {
  1249. if (outline->disabledWidth > 0) {
  1250.     width = outline->disabledWidth;
  1251. }
  1252. if (outline->disabledDash.number > 0) {
  1253.     dash = &(outline->disabledDash);
  1254. }
  1255. if (outline->disabledColor != NULL) {
  1256.     color = outline->disabledColor;
  1257. }
  1258. if (outline->disabledStipple != None) {
  1259.     stipple = outline->disabledStipple;
  1260. }
  1261.     }
  1262.     sprintf(string, "%.15g setlinewidthn", width);
  1263.     Tcl_AppendResult(interp, string, (char *) NULL);
  1264.     if (dash->number > 10) {
  1265. str = (char *)ckalloc((unsigned int) (1 + 4*dash->number));
  1266.     } else if (dash->number < -5) {
  1267. str = (char *)ckalloc((unsigned int) (1 - 8*dash->number));
  1268. lptr = (char *)ckalloc((unsigned int) (1 - 2*dash->number));
  1269.     }
  1270.     ptr = (char *) ((ABS(dash->number) > sizeof(char *)) ) ?
  1271. dash->pattern.pt : dash->pattern.array;
  1272.     if (dash->number > 0) {
  1273. char *ptr0 = ptr;
  1274. sprintf(str, "[%d", *ptr++ & 0xff);
  1275. i = dash->number-1;
  1276. while (i--) {
  1277.     sprintf(str+strlen(str), " %d", *ptr++ & 0xff);
  1278. }
  1279. Tcl_AppendResult(interp, str, (char *)NULL);
  1280. if (dash->number&1) {
  1281.     Tcl_AppendResult(interp, " ", str+1, (char *)NULL);
  1282. }
  1283. sprintf(str, "] %d setdashn", outline->offset);
  1284. Tcl_AppendResult(interp, str, (char *)NULL);
  1285. ptr = ptr0;
  1286.     } else if (dash->number < 0) {
  1287. if ((i = DashConvert(lptr, ptr, -dash->number, width)) != 0) {
  1288.     char *lptr0 = lptr;
  1289.     sprintf(str, "[%d", *lptr++ & 0xff);
  1290.     while (--i) {
  1291. sprintf(str+strlen(str), " %d", *lptr++ & 0xff);
  1292.     }
  1293.     Tcl_AppendResult(interp, str, (char *)NULL);
  1294.     sprintf(str, "] %d setdashn", outline->offset);
  1295.     Tcl_AppendResult(interp, str, (char *)NULL);
  1296.     lptr = lptr0;
  1297. } else {
  1298.     Tcl_AppendResult(interp, "[] 0 setdashn", (char *)NULL);
  1299. }
  1300.     } else {
  1301. Tcl_AppendResult(interp, "[] 0 setdashn", (char *)NULL);
  1302.     }
  1303.     if (str != string) {
  1304. ckfree(str);
  1305.     }
  1306.     if (lptr != pattern) {
  1307. ckfree(lptr);
  1308.     }
  1309.     if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) {
  1310. return TCL_ERROR;
  1311.     }
  1312.     if (stipple != None) {
  1313. Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL);
  1314. if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) {
  1315.     return TCL_ERROR;
  1316. }
  1317.     } else {
  1318. Tcl_AppendResult(interp, "stroken", (char *) NULL);
  1319.     }
  1320.     return TCL_OK;
  1321. }
  1322. /*
  1323.  *--------------------------------------------------------------
  1324.  *
  1325.  * DashConvert
  1326.  *
  1327.  * Converts a character-like dash-list (e.g. "-..")
  1328.  * into an X11-style. l must point to a string that
  1329.  * holds room to at least 2*n characters. if
  1330.  * l == NULL, this function can be used for
  1331.  * syntax checking only.
  1332.  *
  1333.  * Results:
  1334.  * The length of the resulting X11 compatible
  1335.  * dash-list. -1 if failed.
  1336.  *
  1337.  * Side effects:
  1338.  * None
  1339.  *
  1340.  *--------------------------------------------------------------
  1341.  */
  1342. static int
  1343. DashConvert (l, p, n, width)
  1344.     char *l;
  1345.     CONST char *p;
  1346.     int n;
  1347.     double width;
  1348. {
  1349.     int result = 0;
  1350.     int size, intWidth;
  1351.     if (n<0) {
  1352. n = strlen(p);
  1353.     }
  1354.     intWidth = (int) (width + 0.5);
  1355.     if (intWidth < 1) {
  1356. intWidth = 1;
  1357.     }
  1358.     while (n-- && *p) {
  1359. switch (*p++) {
  1360.     case ' ':
  1361. if (result) {
  1362.     if (l) {
  1363. l[-1] += intWidth + 1;
  1364.     }
  1365.     continue;
  1366. } else {
  1367.     return 0;
  1368. }
  1369. break;
  1370.     case '_':
  1371. size = 8;
  1372. break;
  1373.     case '-':
  1374. size = 6;
  1375. break;
  1376.     case ',':
  1377. size = 4;
  1378. break;
  1379.     case '.':
  1380. size = 2;
  1381. break;
  1382.     default:
  1383. return -1;
  1384. }
  1385. if (l) {
  1386.     *l++ = size * intWidth;
  1387.     *l++ = 4 * intWidth;
  1388. }
  1389. result += 2;
  1390.     }
  1391.     return result;
  1392. }
  1393. /*
  1394.  *----------------------------------------------------------------------
  1395.  *
  1396.  * translateAndAppendCoords --
  1397.  *
  1398.  * This is a helper routine for TkCanvTranslatePath() below.
  1399.  *
  1400.  * Given an (x,y) coordinate pair within a canvas, this procedure
  1401.  * computes the corresponding coordinates at which the point should
  1402.  * be drawn in the drawable used for display.  Those coordinates are
  1403.  * then written into outArr[numOut*2] and outArr[numOut*2+1].
  1404.  *
  1405.  * Results:
  1406.  * There is no return value.
  1407.  *
  1408.  * Side effects:
  1409.  * None.
  1410.  *
  1411.  *----------------------------------------------------------------------
  1412.  */
  1413. static void
  1414. translateAndAppendCoords(canvPtr, x, y, outArr, numOut)
  1415.     TkCanvas *canvPtr; /* The canvas. */
  1416.     double x, y; /* Coordinates in canvas space. */
  1417.     XPoint *outArr;                     /* Write results into this array */
  1418.     int numOut;                         /* Num of prior entries in outArr[] */
  1419. {
  1420.     double tmp;
  1421.     tmp = x - canvPtr->drawableXOrigin;
  1422.     if (tmp > 0) {
  1423. tmp += 0.5;
  1424.     } else {
  1425. tmp -= 0.5;
  1426.     }
  1427.     outArr[numOut].x = (short) tmp;
  1428.     tmp = y  - canvPtr->drawableYOrigin;
  1429.     if (tmp > 0) {
  1430. tmp += 0.5;
  1431.     } else {
  1432. tmp -= 0.5;
  1433.     }
  1434.     outArr[numOut].y = (short) tmp;
  1435. }
  1436. /*
  1437.  *--------------------------------------------------------------
  1438.  *
  1439.  * TkCanvTranslatePath
  1440.  *
  1441.  * Translate a line or polygon path so that all vertices are
  1442.  * within a rectangle that is 1000 pixels larger than the total
  1443.  * size of the canvas window.  This will prevent pixel coordinates
  1444.  * from overflowing the 16-bit integer size limitation imposed by
  1445.  * most windowing systems.
  1446.  *
  1447.  *      coordPtr must point to an array of doubles, two doubles per
  1448.  *      vertex.  There are a total of numVertex vertices, or 2*numVertex
  1449.  *      entries in coordPtr.  The result vertices written into outArr
  1450.  *      have their coordinate origin shifted to canvPtr->drawableXOrigin
  1451.  *      by canvPtr->drawableYOrigin.  There might be as many as 3 times
  1452.  *      more output vertices than there are input vertices.  The calling
  1453.  *      function should allocate space accordingly.
  1454.  *
  1455.  * This routine limits the width and height of a canvas window
  1456.  * to 31767 pixels.  At the highest resolution display devices
  1457.  * available today (210 ppi in Jan 2003) that's a window that is
  1458.  *      over 13 feet wide and tall.  Should be enough for the near
  1459.  * future.
  1460.  *
  1461.  * Results:
  1462.  *      Clipped and translated path vertices are written into outArr[].
  1463.  *      There might be as many as twice the vertices in outArr[] as there
  1464.  *      are in coordPtr[].  The return value is the number of vertices
  1465.  *      actually written into outArr[].
  1466.  *
  1467.  * Side effects:
  1468.  * None
  1469.  *
  1470.  *--------------------------------------------------------------
  1471.  */
  1472. int
  1473. TkCanvTranslatePath (canvPtr, numVertex, coordArr, closedPath, outArr)
  1474.     TkCanvas *canvPtr;  /* The canvas */
  1475.     int numVertex;      /* Number of vertices specified by coordArr[] */
  1476.     double *coordArr;   /* X and Y coordinates for each vertex */
  1477.     int closedPath;     /* True if this is a closed polygon */
  1478.     XPoint *outArr;     /* Write results here, if not NULL */
  1479. {
  1480.     int numOutput = 0;  /* Number of output coordinates */
  1481.     double lft, rgh;    /* Left and right sides of the bounding box */
  1482.     double top, btm;    /* Top and bottom sizes of the bounding box */
  1483.     double *tempArr;    /* Temporary storage used by the clipper */
  1484.     double *a, *b, *t;  /* Pointers to parts of the temporary storage */
  1485.     int i, j;           /* Loop counters */
  1486.     int maxOutput;      /* Maximum number of outputs that we will allow */
  1487.     double limit[4];          /* Boundries at which clipping occurs */
  1488.     double staticSpace[480];  /* Temp space from the stack */
  1489.     /*
  1490.     ** Constrain all vertices of the path to be within a box that is no
  1491.     ** larger than 32000 pixels wide or height.  The top-left corner of
  1492.     ** this clipping box is 1000 pixels above and to the left of the top
  1493.     ** left corner of the window on which the canvas is displayed.
  1494.     **
  1495.     ** This means that a canvas will not display properly on a canvas
  1496.     ** window that is larger than 31000 pixels wide or high.  That is not
  1497.     ** a problem today, but might someday become a factor for ultra-high
  1498.     ** resolutions displays.
  1499.     **
  1500.     ** The X11 protocol allows us (in theory) to expand the size of the
  1501.     ** clipping box to 32767 pixels.  But we have found experimentally that
  1502.     ** XFree86 sometimes fails to draw lines correctly if they are longer
  1503.     ** than about 32500 pixels.  So we have left a little margin in the
  1504.     ** size to mask that bug.
  1505.     */
  1506.     lft = canvPtr->xOrigin - 1000.0;
  1507.     top = canvPtr->yOrigin - 1000.0;
  1508.     rgh = lft + 32000.0;
  1509.     btm = top + 32000.0;
  1510.     /* Try the common case first - no clipping.  Loop over the input
  1511.     ** coordinates and translate them into appropriate output coordinates.
  1512.     ** But if a vertex outside of the bounding box is seen, break out of
  1513.     ** the loop.
  1514.     **
  1515.     ** Most of the time, no clipping is needed, so this one loop is 
  1516.     ** sufficient to do the translation.
  1517.     */
  1518.     for(i=0; i<numVertex; i++){
  1519.         double x, y;
  1520.         x = coordArr[i*2];
  1521.         y = coordArr[i*2+1];
  1522.         if( x<lft || x>rgh || y<top || y>btm ) break;
  1523.         translateAndAppendCoords(canvPtr, x, y, outArr, numOutput++);
  1524.     }
  1525.     if( i==numVertex ){
  1526.         assert( numOutput==numVertex );
  1527.         return numOutput;
  1528.     }
  1529.     /* If we reach this point, it means that some clipping is required.
  1530.     ** Begin by allocating some working storage - at least 6 times as much space
  1531.     ** as coordArr[] requires.  Divide this space into two separate arrays
  1532.     ** a[] and b[].  Initialize a[] to be equal to coordArr[].
  1533.     */
  1534.     if( numVertex*12 <= sizeof(staticSpace)/sizeof(staticSpace[0]) ){
  1535.         tempArr = staticSpace;
  1536.     } else {
  1537.         tempArr = (double*)ckalloc( numVertex*12*sizeof(tempArr[0]) );
  1538.     }
  1539.     for(i=0; i<numVertex*2; i++){
  1540.         tempArr[i] = coordArr[i];
  1541.     }
  1542.     a = tempArr;
  1543.     b = &tempArr[numVertex*6];
  1544.     /* We will make four passes through the input data.  On each pass,
  1545.     ** we copy the contents of a[] over into b[].  As we copy, we clip
  1546.     ** any line segments that extend to the right past xClip then we
  1547.     ** rotate the coordinate system 90 degrees clockwise.  After each
  1548.     ** pass is complete, we interchange a[] and b[] in preparation for
  1549.     ** the next pass.
  1550.     **
  1551.     ** Each pass clips line segments that extend beyond a single side
  1552.     ** of the bounding box, and four passes rotate the coordinate system
  1553.     ** back to its original value.  I'm not an expert on graphics 
  1554.     ** algorithms, but I think this is called Cohen-Sutherland polygon
  1555.     ** clipping.
  1556.     **
  1557.     ** The limit[] array contains the xClip value used for each of the
  1558.     ** four passes.
  1559.     */
  1560.     limit[0] = rgh;
  1561.     limit[1] = -top;
  1562.     limit[2] = -lft;
  1563.     limit[3] = btm;
  1564.     /* This is the loop that makes the four passes through the data.
  1565.     */
  1566.     maxOutput = numVertex*3;
  1567.     for(j=0; j<4; j++){
  1568.         double xClip = limit[j];
  1569.         int inside = a[0]<xClip;
  1570.         double priorY = a[1];
  1571.         numOutput = 0;
  1572.         /* Clip everything to the right of xClip.  Store the results in
  1573.         ** b[] rotated by 90 degrees clockwise.
  1574.         */
  1575.         for(i=0; i<numVertex; i++){
  1576.             double x = a[i*2];
  1577.             double y = a[i*2+1];
  1578.             if( x>=xClip ){
  1579.                 /* The current vertex is to the right of xClip.
  1580.                 */
  1581.                 if( inside ){
  1582.                     /* If the current vertex is to the right of xClip but
  1583.                     ** the previous vertex was left of xClip, then draw a
  1584.                     ** line segment from the previous vertex to until it
  1585.                     ** intersects the vertical at xClip.
  1586.                     */
  1587.                     double x0, y0, yN;
  1588.                     assert( i>0 );
  1589.                     x0 = a[i*2-2];
  1590.                     y0 = a[i*2-1];
  1591.                     yN = y0 + (y - y0)*(xClip-x0)/(x-x0);
  1592.                     b[numOutput*2] = -yN;
  1593.                     b[numOutput*2+1] = xClip;
  1594.                     numOutput++;
  1595.                     assert( numOutput<=maxOutput );
  1596.                     priorY = yN;
  1597.                     inside = 0;
  1598.                 }else if( i==0 ){
  1599.                     /* If the first vertex is to the right of xClip, add
  1600.                     ** a vertex that is the projection of the first vertex
  1601.                     ** onto the vertical xClip line.
  1602.                     */
  1603.                     b[0] = -y;
  1604.                     b[1] = xClip;
  1605.                     numOutput = 1;
  1606.                     priorY = y;
  1607.                 }
  1608.             }else{
  1609.                 /* The current vertex is to the left of xClip
  1610.                 */
  1611.                 if( !inside ){
  1612.                     /* If the current vertex is on the left of xClip and
  1613.                     ** one or more prior vertices where to the right, then
  1614.                     ** we have to draw a line segment along xClip that extends
  1615.                     ** from the spot where we first crossed from left to right
  1616.                     ** to the spot where we cross back from right to left.
  1617.                     */
  1618.                     double x0, y0, yN;
  1619.                     assert( i>0 );
  1620.                     x0 = a[i*2-2];
  1621.                     y0 = a[i*2-1];
  1622.                     yN = y0 + (y - y0)*(xClip-x0)/(x-x0);
  1623.                     if( yN!=priorY ){
  1624.                         b[numOutput*2] = -yN;
  1625.                         b[numOutput*2+1] = xClip;
  1626.                         numOutput++;
  1627.                         assert( numOutput<=maxOutput );
  1628.                     }
  1629.                     inside = 1;
  1630.                 }
  1631.                 b[numOutput*2] = -y;
  1632.                 b[numOutput*2+1] = x;
  1633.                 numOutput++;
  1634.                 assert( numOutput<=maxOutput );
  1635.             }
  1636.         }
  1637.         /* Interchange a[] and b[] in preparation for the next pass.
  1638.         */
  1639.         t = a;
  1640.         a = b;
  1641.         b = t;
  1642.         numVertex = numOutput;
  1643.     }
  1644.     /* All clipping is now finished.  Convert the coordinates from doubles
  1645.     ** into XPoints and translate the origin for the drawable.
  1646.     */
  1647.     for(i=0; i<numVertex; i++){
  1648.         translateAndAppendCoords(canvPtr, a[i*2], a[i*2+1], outArr, i);
  1649.     }
  1650.     if( tempArr!=staticSpace ){
  1651.         ckfree((char *) tempArr);
  1652.     }
  1653.     return numOutput;
  1654. }