1 /*
2  * tkCanvBmap.c --
3  *
4  *	This file implements bitmap items for canvas widgets.
5  *
6  * Copyright (c) 1992-1994 The Regents of the University of California.
7  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
8  *
9  * See the file "license.terms" for information on usage and redistribution of
10  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  */
12 
13 #include "tkInt.h"
14 #include "tkCanvas.h"
15 #include "default.h"
16 
17 /*
18  * The structure below defines the record for each bitmap item.
19  */
20 
21 typedef struct BitmapItem  {
22     Tk_Item header;		/* Generic stuff that's the same for all
23 				 * types. MUST BE FIRST IN STRUCTURE. */
24     double x, y;		/* Coordinates of positioning point for
25 				 * bitmap. */
26     Tk_Anchor anchor;		/* Where to anchor bitmap relative to (x,y) */
27     Pixmap bitmap;		/* Bitmap to display in window. */
28     Pixmap activeBitmap;	/* Bitmap to display in window. */
29     Pixmap disabledBitmap;	/* Bitmap to display in window. */
30     XColor *fgColor;		/* Foreground color to use for bitmap. */
31     XColor *activeFgColor;	/* Foreground color to use for bitmap. */
32     XColor *disabledFgColor;	/* Foreground color to use for bitmap. */
33     XColor *bgColor;		/* Background color to use for bitmap. */
34     XColor *activeBgColor;	/* Background color to use for bitmap. */
35     XColor *disabledBgColor;	/* Background color to use for bitmap. */
36     GC gc;			/* Graphics context to use for drawing bitmap
37 				 * on screen. */
38 } BitmapItem;
39 
40 /*
41  * Information used for parsing configuration specs:
42  */
43 
44 static const Tk_CustomOption stateOption = {
45     TkStateParseProc, TkStatePrintProc, INT2PTR(2)
46 };
47 static const Tk_CustomOption tagsOption = {
48     Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, NULL
49 };
50 
51 static const Tk_ConfigSpec configSpecs[] = {
52     {TK_CONFIG_COLOR, "-activebackground", NULL, NULL,
53 	NULL, Tk_Offset(BitmapItem, activeBgColor), TK_CONFIG_NULL_OK, NULL},
54     {TK_CONFIG_BITMAP, "-activebitmap", NULL, NULL,
55 	NULL, Tk_Offset(BitmapItem, activeBitmap), TK_CONFIG_NULL_OK, NULL},
56     {TK_CONFIG_COLOR, "-activeforeground", NULL, NULL,
57 	NULL, Tk_Offset(BitmapItem, activeFgColor), TK_CONFIG_NULL_OK, NULL},
58     {TK_CONFIG_ANCHOR, "-anchor", NULL, NULL,
59 	"center", Tk_Offset(BitmapItem, anchor), TK_CONFIG_DONT_SET_DEFAULT, NULL},
60     {TK_CONFIG_COLOR, "-background", NULL, NULL,
61 	NULL, Tk_Offset(BitmapItem, bgColor), TK_CONFIG_NULL_OK, NULL},
62     {TK_CONFIG_BITMAP, "-bitmap", NULL, NULL,
63 	NULL, Tk_Offset(BitmapItem, bitmap), TK_CONFIG_NULL_OK, NULL},
64     {TK_CONFIG_COLOR, "-disabledbackground", NULL, NULL,
65 	NULL, Tk_Offset(BitmapItem, disabledBgColor),
66 	TK_CONFIG_NULL_OK, NULL},
67     {TK_CONFIG_BITMAP, "-disabledbitmap", NULL, NULL,
68 	NULL, Tk_Offset(BitmapItem, disabledBitmap),
69 	TK_CONFIG_NULL_OK, NULL},
70     {TK_CONFIG_COLOR, "-disabledforeground", NULL, NULL,
71 	NULL, Tk_Offset(BitmapItem, disabledFgColor),
72 	TK_CONFIG_NULL_OK, NULL},
73     {TK_CONFIG_COLOR, "-foreground", NULL, NULL,
74 	DEF_CANVBMAP_FG, Tk_Offset(BitmapItem, fgColor), 0, NULL},
75     {TK_CONFIG_CUSTOM, "-state", NULL, NULL,
76 	NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK,
77 	&stateOption},
78     {TK_CONFIG_CUSTOM, "-tags", NULL, NULL,
79 	NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
80     {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0, NULL}
81 };
82 
83 /*
84  * Prototypes for functions defined in this file:
85  */
86 
87 static int		BitmapCoords(Tcl_Interp *interp,
88 			    Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
89 			    Tcl_Obj *const objv[]);
90 static int		BitmapToArea(Tk_Canvas canvas,
91 			    Tk_Item *itemPtr, double *rectPtr);
92 static double		BitmapToPoint(Tk_Canvas canvas,
93 			    Tk_Item *itemPtr, double *coordPtr);
94 static int		BitmapToPostscript(Tcl_Interp *interp,
95 			    Tk_Canvas canvas, Tk_Item *itemPtr, int prepass);
96 static void		ComputeBitmapBbox(Tk_Canvas canvas,
97 			    BitmapItem *bmapPtr);
98 static int		ConfigureBitmap(Tcl_Interp *interp,
99 			    Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
100 			    Tcl_Obj *const objv[], int flags);
101 static int		TkcCreateBitmap(Tcl_Interp *interp,
102 			    Tk_Canvas canvas, struct Tk_Item *itemPtr,
103 			    int objc, Tcl_Obj *const objv[]);
104 static void		DeleteBitmap(Tk_Canvas canvas,
105 			    Tk_Item *itemPtr, Display *display);
106 static void		DisplayBitmap(Tk_Canvas canvas,
107 			    Tk_Item *itemPtr, Display *display, Drawable dst,
108 			    int x, int y, int width, int height);
109 static void		ScaleBitmap(Tk_Canvas canvas,
110 			    Tk_Item *itemPtr, double originX, double originY,
111 			    double scaleX, double scaleY);
112 static void		TranslateBitmap(Tk_Canvas canvas, Tk_Item *itemPtr,
113 			    double deltaX, double deltaY);
114 
115 /*
116  * The structures below defines the bitmap item type in terms of functions
117  * that can be invoked by generic item code.
118  */
119 
120 Tk_ItemType tkBitmapType = {
121     "bitmap",			/* name */
122     sizeof(BitmapItem),		/* itemSize */
123     TkcCreateBitmap,		/* createProc */
124     configSpecs,		/* configSpecs */
125     ConfigureBitmap,		/* configureProc */
126     BitmapCoords,		/* coordProc */
127     DeleteBitmap,		/* deleteProc */
128     DisplayBitmap,		/* displayProc */
129     TK_CONFIG_OBJS,		/* flags */
130     BitmapToPoint,		/* pointProc */
131     BitmapToArea,		/* areaProc */
132     BitmapToPostscript,		/* postscriptProc */
133     ScaleBitmap,		/* scaleProc */
134     TranslateBitmap,		/* translateProc */
135     NULL,			/* indexProc */
136     NULL,			/* icursorProc */
137     NULL,			/* selectionProc */
138     NULL,			/* insertProc */
139     NULL,			/* dTextProc */
140     NULL,			/* nextPtr */
141     NULL, 0, NULL, NULL
142 };
143 
144 /*
145  *--------------------------------------------------------------
146  *
147  * TkcCreateBitmap --
148  *
149  *	This function is invoked to create a new bitmap item in a canvas.
150  *
151  * Results:
152  *	A standard Tcl return value. If an error occurred in creating the
153  *	item, then an error message is left in the interp's result; in this
154  *	case itemPtr is left uninitialized, so it can be safely freed by the
155  *	caller.
156  *
157  * Side effects:
158  *	A new bitmap item is created.
159  *
160  *--------------------------------------------------------------
161  */
162 
163 static int
TkcCreateBitmap(Tcl_Interp * interp,Tk_Canvas canvas,Tk_Item * itemPtr,int objc,Tcl_Obj * const objv[])164 TkcCreateBitmap(
165     Tcl_Interp *interp,		/* Interpreter for error reporting. */
166     Tk_Canvas canvas,		/* Canvas to hold new item. */
167     Tk_Item *itemPtr,		/* Record to hold new item; header has been
168 				 * initialized by caller. */
169     int objc,			/* Number of arguments in objv. */
170     Tcl_Obj *const objv[])	/* Arguments describing rectangle. */
171 {
172     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
173     int i;
174 
175     if (objc == 0) {
176 	Tcl_Panic("canvas did not pass any coords");
177     }
178 
179     /*
180      * Initialize item's record.
181      */
182 
183     bmapPtr->anchor = TK_ANCHOR_CENTER;
184     bmapPtr->bitmap = None;
185     bmapPtr->activeBitmap = None;
186     bmapPtr->disabledBitmap = None;
187     bmapPtr->fgColor = NULL;
188     bmapPtr->activeFgColor = NULL;
189     bmapPtr->disabledFgColor = NULL;
190     bmapPtr->bgColor = NULL;
191     bmapPtr->activeBgColor = NULL;
192     bmapPtr->disabledBgColor = NULL;
193     bmapPtr->gc = NULL;
194 
195     /*
196      * Process the arguments to fill in the item record. Only 1 (list) or 2 (x
197      * y) coords are allowed.
198      */
199 
200     if (objc == 1) {
201 	i = 1;
202     } else {
203 	const char *arg = Tcl_GetString(objv[1]);
204 	i = 2;
205 	if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) {
206 	    i = 1;
207 	}
208     }
209     if (BitmapCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) {
210 	goto error;
211     }
212     if (ConfigureBitmap(interp, canvas, itemPtr, objc-i, objv+i, 0)
213 	    == TCL_OK) {
214 	return TCL_OK;
215     }
216 
217   error:
218     DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
219     return TCL_ERROR;
220 }
221 
222 /*
223  *--------------------------------------------------------------
224  *
225  * BitmapCoords --
226  *
227  *	This function is invoked to process the "coords" widget command on
228  *	bitmap items. See the user documentation for details on what it does.
229  *
230  * Results:
231  *	Returns TCL_OK or TCL_ERROR, and sets the interp's result.
232  *
233  * Side effects:
234  *	The coordinates for the given item may be changed.
235  *
236  *--------------------------------------------------------------
237  */
238 
239 static int
BitmapCoords(Tcl_Interp * interp,Tk_Canvas canvas,Tk_Item * itemPtr,int objc,Tcl_Obj * const objv[])240 BitmapCoords(
241     Tcl_Interp *interp,		/* Used for error reporting. */
242     Tk_Canvas canvas,		/* Canvas containing item. */
243     Tk_Item *itemPtr,		/* Item whose coordinates are to be read or
244 				 * modified. */
245     int objc,			/* Number of coordinates supplied in objv. */
246     Tcl_Obj *const objv[])	/* Array of coordinates: x1, y1, x2, y2, ... */
247 {
248     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
249 
250     if (objc == 0) {
251 	Tcl_Obj *obj = Tcl_NewObj();
252 
253 	Tcl_ListObjAppendElement(NULL, obj, Tcl_NewDoubleObj(bmapPtr->x));
254 	Tcl_ListObjAppendElement(NULL, obj, Tcl_NewDoubleObj(bmapPtr->y));
255 	Tcl_SetObjResult(interp, obj);
256     } else if (objc < 3) {
257 	if (objc == 1) {
258 	    if (Tcl_ListObjGetElements(interp, objv[0], &objc,
259 		    (Tcl_Obj ***) &objv) != TCL_OK) {
260 		return TCL_ERROR;
261 	    } else if (objc != 2) {
262 		Tcl_SetObjResult(interp, Tcl_ObjPrintf(
263 			"wrong # coordinates: expected 2, got %d", objc));
264 		Tcl_SetErrorCode(interp, "TK", "CANVAS", "COORDS", "BITMAP",
265 			NULL);
266 		return TCL_ERROR;
267 	    }
268 	}
269 	if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0],
270 		&bmapPtr->x) != TCL_OK)
271 		|| (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1],
272 			&bmapPtr->y) != TCL_OK)) {
273 	    return TCL_ERROR;
274 	}
275 	ComputeBitmapBbox(canvas, bmapPtr);
276     } else {
277 	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
278 		"wrong # coordinates: expected 0 or 2, got %d", objc));
279 	Tcl_SetErrorCode(interp, "TK", "CANVAS", "COORDS", "BITMAP", NULL);
280 	return TCL_ERROR;
281     }
282     return TCL_OK;
283 }
284 
285 /*
286  *--------------------------------------------------------------
287  *
288  * ConfigureBitmap --
289  *
290  *	This function is invoked to configure various aspects of a bitmap
291  *	item, such as its anchor position.
292  *
293  * Results:
294  *	A standard Tcl result code. If an error occurs, then an error message
295  *	is left in the interp's result.
296  *
297  * Side effects:
298  *	Configuration information may be set for itemPtr.
299  *
300  *--------------------------------------------------------------
301  */
302 
303 static int
ConfigureBitmap(Tcl_Interp * interp,Tk_Canvas canvas,Tk_Item * itemPtr,int objc,Tcl_Obj * const objv[],int flags)304 ConfigureBitmap(
305     Tcl_Interp *interp,		/* Used for error reporting. */
306     Tk_Canvas canvas,		/* Canvas containing itemPtr. */
307     Tk_Item *itemPtr,		/* Bitmap item to reconfigure. */
308     int objc,			/* Number of elements in objv.  */
309     Tcl_Obj *const objv[],	/* Arguments describing things to configure. */
310     int flags)			/* Flags to pass to Tk_ConfigureWidget. */
311 {
312     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
313     XGCValues gcValues;
314     GC newGC;
315     Tk_Window tkwin;
316     unsigned long mask;
317     XColor *fgColor;
318     XColor *bgColor;
319     Pixmap bitmap;
320     Tk_State state;
321 
322     tkwin = Tk_CanvasTkwin(canvas);
323     if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc,
324 	    (const char **) objv, (char *) bmapPtr, flags|TK_CONFIG_OBJS)) {
325 	return TCL_ERROR;
326     }
327 
328     /*
329      * A few of the options require additional processing, such as those that
330      * determine the graphics context.
331      */
332 
333     state = itemPtr->state;
334 
335     if (bmapPtr->activeFgColor!=NULL ||
336 	    bmapPtr->activeBgColor!=NULL ||
337 	    bmapPtr->activeBitmap!=None) {
338 	itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT;
339     } else {
340 	itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT;
341     }
342 
343     if (state == TK_STATE_NULL) {
344 	state = Canvas(canvas)->canvas_state;
345     }
346     if (state == TK_STATE_HIDDEN) {
347 	ComputeBitmapBbox(canvas, bmapPtr);
348 	return TCL_OK;
349     }
350     fgColor = bmapPtr->fgColor;
351     bgColor = bmapPtr->bgColor;
352     bitmap = bmapPtr->bitmap;
353     if (Canvas(canvas)->currentItemPtr == itemPtr) {
354 	if (bmapPtr->activeFgColor!=NULL) {
355 	    fgColor = bmapPtr->activeFgColor;
356 	}
357 	if (bmapPtr->activeBgColor!=NULL) {
358 	    bgColor = bmapPtr->activeBgColor;
359 	}
360 	if (bmapPtr->activeBitmap!=None) {
361 	    bitmap = bmapPtr->activeBitmap;
362 	}
363     } else if (state == TK_STATE_DISABLED) {
364 	if (bmapPtr->disabledFgColor!=NULL) {
365 	    fgColor = bmapPtr->disabledFgColor;
366 	}
367 	if (bmapPtr->disabledBgColor!=NULL) {
368 	    bgColor = bmapPtr->disabledBgColor;
369 	}
370 	if (bmapPtr->disabledBitmap!=None) {
371 	    bitmap = bmapPtr->disabledBitmap;
372 	}
373     }
374 
375     if (bitmap == None) {
376 	newGC = NULL;
377     } else {
378 	gcValues.foreground = fgColor->pixel;
379 	mask = GCForeground;
380 	if (bgColor != NULL) {
381 	    gcValues.background = bgColor->pixel;
382 	    mask |= GCBackground;
383 	} else {
384 	    gcValues.clip_mask = bitmap;
385 	    mask |= GCClipMask;
386 	}
387 	newGC = Tk_GetGC(tkwin, mask, &gcValues);
388     }
389     if (bmapPtr->gc != NULL) {
390 	Tk_FreeGC(Tk_Display(tkwin), bmapPtr->gc);
391     }
392     bmapPtr->gc = newGC;
393 
394     ComputeBitmapBbox(canvas, bmapPtr);
395     return TCL_OK;
396 }
397 
398 /*
399  *--------------------------------------------------------------
400  *
401  * DeleteBitmap --
402  *
403  *	This function is called to clean up the data structure associated with
404  *	a bitmap item.
405  *
406  * Results:
407  *	None.
408  *
409  * Side effects:
410  *	Resources associated with itemPtr are released.
411  *
412  *--------------------------------------------------------------
413  */
414 
415 static void
DeleteBitmap(Tk_Canvas canvas,Tk_Item * itemPtr,Display * display)416 DeleteBitmap(
417     Tk_Canvas canvas,		/* Info about overall canvas widget. */
418     Tk_Item *itemPtr,		/* Item that is being deleted. */
419     Display *display)		/* Display containing window for canvas. */
420 {
421     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
422 
423     if (bmapPtr->bitmap != None) {
424 	Tk_FreeBitmap(display, bmapPtr->bitmap);
425     }
426     if (bmapPtr->activeBitmap != None) {
427 	Tk_FreeBitmap(display, bmapPtr->activeBitmap);
428     }
429     if (bmapPtr->disabledBitmap != None) {
430 	Tk_FreeBitmap(display, bmapPtr->disabledBitmap);
431     }
432     if (bmapPtr->fgColor != NULL) {
433 	Tk_FreeColor(bmapPtr->fgColor);
434     }
435     if (bmapPtr->activeFgColor != NULL) {
436 	Tk_FreeColor(bmapPtr->activeFgColor);
437     }
438     if (bmapPtr->disabledFgColor != NULL) {
439 	Tk_FreeColor(bmapPtr->disabledFgColor);
440     }
441     if (bmapPtr->bgColor != NULL) {
442 	Tk_FreeColor(bmapPtr->bgColor);
443     }
444     if (bmapPtr->activeBgColor != NULL) {
445 	Tk_FreeColor(bmapPtr->activeBgColor);
446     }
447     if (bmapPtr->disabledBgColor != NULL) {
448 	Tk_FreeColor(bmapPtr->disabledBgColor);
449     }
450     if (bmapPtr->gc != NULL) {
451 	Tk_FreeGC(display, bmapPtr->gc);
452     }
453 }
454 
455 /*
456  *--------------------------------------------------------------
457  *
458  * ComputeBitmapBbox --
459  *
460  *	This function is invoked to compute the bounding box of all the pixels
461  *	that may be drawn as part of a bitmap item. This function is where the
462  *	child bitmap's placement is computed.
463  *
464  * Results:
465  *	None.
466  *
467  * Side effects:
468  *	The fields x1, y1, x2, and y2 are updated in the header for itemPtr.
469  *
470  *--------------------------------------------------------------
471  */
472 
473 	/* ARGSUSED */
474 static void
ComputeBitmapBbox(Tk_Canvas canvas,BitmapItem * bmapPtr)475 ComputeBitmapBbox(
476     Tk_Canvas canvas,		/* Canvas that contains item. */
477     BitmapItem *bmapPtr)	/* Item whose bbox is to be recomputed. */
478 {
479     int width, height;
480     int x, y;
481     Pixmap bitmap;
482     Tk_State state = bmapPtr->header.state;
483 
484     if (state == TK_STATE_NULL) {
485 	state = Canvas(canvas)->canvas_state;
486     }
487     bitmap = bmapPtr->bitmap;
488     if (Canvas(canvas)->currentItemPtr == (Tk_Item *)bmapPtr) {
489 	if (bmapPtr->activeBitmap!=None) {
490 	    bitmap = bmapPtr->activeBitmap;
491 	}
492     } else if (state==TK_STATE_DISABLED) {
493 	if (bmapPtr->disabledBitmap!=None) {
494 	    bitmap = bmapPtr->disabledBitmap;
495 	}
496     }
497 
498     x = (int) (bmapPtr->x + ((bmapPtr->x >= 0) ? 0.5 : - 0.5));
499     y = (int) (bmapPtr->y + ((bmapPtr->y >= 0) ? 0.5 : - 0.5));
500 
501     if (state==TK_STATE_HIDDEN || bitmap == None) {
502 	bmapPtr->header.x1 = bmapPtr->header.x2 = x;
503 	bmapPtr->header.y1 = bmapPtr->header.y2 = y;
504 	return;
505     }
506 
507     /*
508      * Compute location and size of bitmap, using anchor information.
509      */
510 
511     Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap,
512 	    &width, &height);
513     switch (bmapPtr->anchor) {
514     case TK_ANCHOR_N:
515 	x -= width/2;
516 	break;
517     case TK_ANCHOR_NE:
518 	x -= width;
519 	break;
520     case TK_ANCHOR_E:
521 	x -= width;
522 	y -= height/2;
523 	break;
524     case TK_ANCHOR_SE:
525 	x -= width;
526 	y -= height;
527 	break;
528     case TK_ANCHOR_S:
529 	x -= width/2;
530 	y -= height;
531 	break;
532     case TK_ANCHOR_SW:
533 	y -= height;
534 	break;
535     case TK_ANCHOR_W:
536 	y -= height/2;
537 	break;
538     case TK_ANCHOR_NW:
539 	break;
540     case TK_ANCHOR_CENTER:
541 	x -= width/2;
542 	y -= height/2;
543 	break;
544     }
545 
546     /*
547      * Store the information in the item header.
548      */
549 
550     bmapPtr->header.x1 = x;
551     bmapPtr->header.y1 = y;
552     bmapPtr->header.x2 = x + width;
553     bmapPtr->header.y2 = y + height;
554 }
555 
556 /*
557  *--------------------------------------------------------------
558  *
559  * DisplayBitmap --
560  *
561  *	This function is invoked to draw a bitmap item in a given drawable.
562  *
563  * Results:
564  *	None.
565  *
566  * Side effects:
567  *	ItemPtr is drawn in drawable using the transformation information in
568  *	canvas.
569  *
570  *--------------------------------------------------------------
571  */
572 
573 static void
DisplayBitmap(Tk_Canvas canvas,Tk_Item * itemPtr,Display * display,Drawable drawable,int x,int y,int width,int height)574 DisplayBitmap(
575     Tk_Canvas canvas,		/* Canvas that contains item. */
576     Tk_Item *itemPtr,		/* Item to be displayed. */
577     Display *display,		/* Display on which to draw item. */
578     Drawable drawable,		/* Pixmap or window in which to draw item. */
579     int x, int y, int width, int height)
580 				/* Describes region of canvas that must be
581 				 * redisplayed (not used). */
582 {
583     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
584     int bmapX, bmapY, bmapWidth, bmapHeight;
585     short drawableX, drawableY;
586     Pixmap bitmap;
587     Tk_State state = itemPtr->state;
588 
589     /*
590      * If the area being displayed doesn't cover the whole bitmap, then only
591      * redisplay the part of the bitmap that needs redisplay.
592      */
593 
594     if (state == TK_STATE_NULL) {
595 	state = Canvas(canvas)->canvas_state;
596     }
597     bitmap = bmapPtr->bitmap;
598     if (Canvas(canvas)->currentItemPtr == itemPtr) {
599 	if (bmapPtr->activeBitmap!=None) {
600 	    bitmap = bmapPtr->activeBitmap;
601 	}
602     } else if (state == TK_STATE_DISABLED) {
603 	if (bmapPtr->disabledBitmap!=None) {
604 	    bitmap = bmapPtr->disabledBitmap;
605 	}
606     }
607 
608     if (bitmap != None) {
609 	if (x > bmapPtr->header.x1) {
610 	    bmapX = x - bmapPtr->header.x1;
611 	    bmapWidth = bmapPtr->header.x2 - x;
612 	} else {
613 	    bmapX = 0;
614 	    if ((x+width) < bmapPtr->header.x2) {
615 		bmapWidth = x + width - bmapPtr->header.x1;
616 	    } else {
617 		bmapWidth = bmapPtr->header.x2 - bmapPtr->header.x1;
618 	    }
619 	}
620 	if (y > bmapPtr->header.y1) {
621 	    bmapY = y - bmapPtr->header.y1;
622 	    bmapHeight = bmapPtr->header.y2 - y;
623 	} else {
624 	    bmapY = 0;
625 	    if ((y+height) < bmapPtr->header.y2) {
626 		bmapHeight = y + height - bmapPtr->header.y1;
627 	    } else {
628 		bmapHeight = bmapPtr->header.y2 - bmapPtr->header.y1;
629 	    }
630 	}
631 	Tk_CanvasDrawableCoords(canvas,
632 		(double) (bmapPtr->header.x1 + bmapX),
633 		(double) (bmapPtr->header.y1 + bmapY),
634 		&drawableX, &drawableY);
635 
636 	/*
637 	 * Must modify the mask origin within the graphics context to line up
638 	 * with the bitmap's origin (in order to make bitmaps with
639 	 * "-background {}" work right).
640 	 */
641 
642 	XSetClipOrigin(display, bmapPtr->gc, drawableX - bmapX,
643 		drawableY - bmapY);
644 	XCopyPlane(display, bitmap, drawable,
645 		bmapPtr->gc, bmapX, bmapY, (unsigned int) bmapWidth,
646 		(unsigned int) bmapHeight, drawableX, drawableY, 1);
647 	XSetClipOrigin(display, bmapPtr->gc, 0, 0);
648     }
649 }
650 
651 /*
652  *--------------------------------------------------------------
653  *
654  * BitmapToPoint --
655  *
656  *	Computes the distance from a given point to a given rectangle, in
657  *	canvas units.
658  *
659  * Results:
660  *	The return value is 0 if the point whose x and y coordinates are
661  *	coordPtr[0] and coordPtr[1] is inside the bitmap. If the point isn't
662  *	inside the bitmap then the return value is the distance from the point
663  *	to the bitmap.
664  *
665  * Side effects:
666  *	None.
667  *
668  *--------------------------------------------------------------
669  */
670 
671 	/* ARGSUSED */
672 static double
BitmapToPoint(Tk_Canvas canvas,Tk_Item * itemPtr,double * coordPtr)673 BitmapToPoint(
674     Tk_Canvas canvas,		/* Canvas containing item. */
675     Tk_Item *itemPtr,		/* Item to check against point. */
676     double *coordPtr)		/* Pointer to x and y coordinates. */
677 {
678     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
679     double x1, x2, y1, y2, xDiff, yDiff;
680 
681     x1 = bmapPtr->header.x1;
682     y1 = bmapPtr->header.y1;
683     x2 = bmapPtr->header.x2;
684     y2 = bmapPtr->header.y2;
685 
686     /*
687      * Point is outside rectangle.
688      */
689 
690     if (coordPtr[0] < x1) {
691 	xDiff = x1 - coordPtr[0];
692     } else if (coordPtr[0] > x2)  {
693 	xDiff = coordPtr[0] - x2;
694     } else {
695 	xDiff = 0;
696     }
697 
698     if (coordPtr[1] < y1) {
699 	yDiff = y1 - coordPtr[1];
700     } else if (coordPtr[1] > y2)  {
701 	yDiff = coordPtr[1] - y2;
702     } else {
703 	yDiff = 0;
704     }
705 
706     return hypot(xDiff, yDiff);
707 }
708 
709 /*
710  *--------------------------------------------------------------
711  *
712  * BitmapToArea --
713  *
714  *	This function is called to determine whether an item lies entirely
715  *	inside, entirely outside, or overlapping a given rectangle.
716  *
717  * Results:
718  *	-1 is returned if the item is entirely outside the area given by
719  *	rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given
720  *	area.
721  *
722  * Side effects:
723  *	None.
724  *
725  *--------------------------------------------------------------
726  */
727 
728 	/* ARGSUSED */
729 static int
BitmapToArea(Tk_Canvas canvas,Tk_Item * itemPtr,double * rectPtr)730 BitmapToArea(
731     Tk_Canvas canvas,		/* Canvas containing item. */
732     Tk_Item *itemPtr,		/* Item to check against rectangle. */
733     double *rectPtr)		/* Pointer to array of four coordinates
734 				 * (x1,y1,x2,y2) describing rectangular
735 				 * area. */
736 {
737     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
738 
739     if ((rectPtr[2] <= bmapPtr->header.x1)
740 	    || (rectPtr[0] >= bmapPtr->header.x2)
741 	    || (rectPtr[3] <= bmapPtr->header.y1)
742 	    || (rectPtr[1] >= bmapPtr->header.y2)) {
743 	return -1;
744     }
745     if ((rectPtr[0] <= bmapPtr->header.x1)
746 	    && (rectPtr[1] <= bmapPtr->header.y1)
747 	    && (rectPtr[2] >= bmapPtr->header.x2)
748 	    && (rectPtr[3] >= bmapPtr->header.y2)) {
749 	return 1;
750     }
751     return 0;
752 }
753 
754 /*
755  *--------------------------------------------------------------
756  *
757  * ScaleBitmap --
758  *
759  *	This function is invoked to rescale a bitmap item in a canvas. It is
760  *	one of the standard item functions for bitmap items, and is invoked by
761  *	the generic canvas code.
762  *
763  * Results:
764  *	None.
765  *
766  * Side effects:
767  *	The item referred to by itemPtr is rescaled so that the following
768  *	transformation is applied to all point coordinates:
769  *		x' = originX + scaleX*(x-originX)
770  *		y' = originY + scaleY*(y-originY)
771  *
772  *--------------------------------------------------------------
773  */
774 
775 static void
ScaleBitmap(Tk_Canvas canvas,Tk_Item * itemPtr,double originX,double originY,double scaleX,double scaleY)776 ScaleBitmap(
777     Tk_Canvas canvas,		/* Canvas containing rectangle. */
778     Tk_Item *itemPtr,		/* Rectangle to be scaled. */
779     double originX, double originY,
780 				/* Origin about which to scale item. */
781     double scaleX,		/* Amount to scale in X direction. */
782     double scaleY)		/* Amount to scale in Y direction. */
783 {
784     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
785 
786     bmapPtr->x = originX + scaleX*(bmapPtr->x - originX);
787     bmapPtr->y = originY + scaleY*(bmapPtr->y - originY);
788     ComputeBitmapBbox(canvas, bmapPtr);
789 }
790 
791 /*
792  *--------------------------------------------------------------
793  *
794  * TranslateBitmap --
795  *
796  *	This function is called to move an item by a given amount.
797  *
798  * Results:
799  *	None.
800  *
801  * Side effects:
802  *	The position of the item is offset by (xDelta, yDelta), and the
803  *	bounding box is updated in the generic part of the item structure.
804  *
805  *--------------------------------------------------------------
806  */
807 
808 static void
TranslateBitmap(Tk_Canvas canvas,Tk_Item * itemPtr,double deltaX,double deltaY)809 TranslateBitmap(
810     Tk_Canvas canvas,		/* Canvas containing item. */
811     Tk_Item *itemPtr,		/* Item that is being moved. */
812     double deltaX, double deltaY)
813 				/* Amount by which item is to be moved. */
814 {
815     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
816 
817     bmapPtr->x += deltaX;
818     bmapPtr->y += deltaY;
819     ComputeBitmapBbox(canvas, bmapPtr);
820 }
821 
822 /*
823  *--------------------------------------------------------------
824  *
825  * BitmapToPostscript --
826  *
827  *	This function is called to generate Postscript for bitmap items.
828  *
829  * Results:
830  *	The return value is a standard Tcl result. If an error occurs in
831  *	generating Postscript then an error message is left in the interp's
832  *	result, replacing whatever used to be there. If no error occurs, then
833  *	Postscript for the item is appended to the result.
834  *
835  * Side effects:
836  *	None.
837  *
838  *--------------------------------------------------------------
839  */
840 
841 static int
BitmapToPostscript(Tcl_Interp * interp,Tk_Canvas canvas,Tk_Item * itemPtr,int prepass)842 BitmapToPostscript(
843     Tcl_Interp *interp,		/* Leave Postscript or error message here. */
844     Tk_Canvas canvas,		/* Information about overall canvas. */
845     Tk_Item *itemPtr,		/* Item for which Postscript is wanted. */
846     int prepass)		/* 1 means this is a prepass to collect font
847 				 * information; 0 means final Postscript is
848 				 * being created. */
849 {
850     BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
851     double x, y;
852     int width, height, rowsAtOnce, rowsThisTime;
853     int curRow;
854     XColor *fgColor;
855     XColor *bgColor;
856     Pixmap bitmap;
857     Tk_State state = itemPtr->state;
858     Tcl_Obj *psObj;
859     Tcl_InterpState interpState;
860 
861     if (state == TK_STATE_NULL) {
862 	state = Canvas(canvas)->canvas_state;
863     }
864     fgColor = bmapPtr->fgColor;
865     bgColor = bmapPtr->bgColor;
866     bitmap = bmapPtr->bitmap;
867     if (Canvas(canvas)->currentItemPtr == itemPtr) {
868 	if (bmapPtr->activeFgColor!=NULL) {
869 	    fgColor = bmapPtr->activeFgColor;
870 	}
871 	if (bmapPtr->activeBgColor!=NULL) {
872 	    bgColor = bmapPtr->activeBgColor;
873 	}
874 	if (bmapPtr->activeBitmap!=None) {
875 	    bitmap = bmapPtr->activeBitmap;
876 	}
877     } else if (state == TK_STATE_DISABLED) {
878 	if (bmapPtr->disabledFgColor!=NULL) {
879 	    fgColor = bmapPtr->disabledFgColor;
880 	}
881 	if (bmapPtr->disabledBgColor!=NULL) {
882 	    bgColor = bmapPtr->disabledBgColor;
883 	}
884 	if (bmapPtr->disabledBitmap!=None) {
885 	    bitmap = bmapPtr->disabledBitmap;
886 	}
887     }
888 
889     if (bitmap == None) {
890 	return TCL_OK;
891     }
892 
893     /*
894      * Compute the coordinates of the lower-left corner of the bitmap, taking
895      * into account the anchor position for the bitmp.
896      */
897 
898     x = bmapPtr->x;
899     y = Tk_CanvasPsY(canvas, bmapPtr->y);
900     Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap,
901 	    &width, &height);
902     switch (bmapPtr->anchor) {
903     case TK_ANCHOR_NW:			   y -= height;		break;
904     case TK_ANCHOR_N:	   x -= width/2.0; y -= height;		break;
905     case TK_ANCHOR_NE:	   x -= width;	   y -= height;		break;
906     case TK_ANCHOR_E:	   x -= width;	   y -= height/2.0;	break;
907     case TK_ANCHOR_SE:	   x -= width;				break;
908     case TK_ANCHOR_S:	   x -= width/2.0;			break;
909     case TK_ANCHOR_SW:						break;
910     case TK_ANCHOR_W:			   y -= height/2.0;	break;
911     case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0;	break;
912     }
913 
914     /*
915      * Make our working space.
916      */
917 
918     psObj = Tcl_NewObj();
919     interpState = Tcl_SaveInterpState(interp, TCL_OK);
920 
921     /*
922      * Color the background, if there is one.
923      */
924 
925     if (bgColor != NULL) {
926 	Tcl_AppendPrintfToObj(psObj,
927 		"%.15g %.15g moveto %d 0 rlineto 0 %d rlineto "
928 		"%d 0 rlineto closepath\n",
929 		x, y, width, height, -width);
930 
931 	Tcl_ResetResult(interp);
932 	if (Tk_CanvasPsColor(interp, canvas, bgColor) != TCL_OK) {
933 	    goto error;
934 	}
935 	Tcl_AppendObjToObj(psObj, Tcl_GetObjResult(interp));
936 
937 	Tcl_AppendToObj(psObj, "fill\n", -1);
938     }
939 
940     /*
941      * Draw the bitmap, if there is a foreground color. If the bitmap is very
942      * large, then chop it up into multiple bitmaps, each consisting of one or
943      * more rows. This is needed because Postscript can't handle single
944      * strings longer than 64 KBytes long.
945      */
946 
947     if (fgColor != NULL) {
948 	Tcl_ResetResult(interp);
949 	if (Tk_CanvasPsColor(interp, canvas, fgColor) != TCL_OK) {
950 	    goto error;
951 	}
952 	Tcl_AppendObjToObj(psObj, Tcl_GetObjResult(interp));
953 
954 	if (width > 60000) {
955 	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
956 		    "can't generate Postscript for bitmaps more than 60000"
957 		    " pixels wide", -1));
958 	    Tcl_SetErrorCode(interp, "TK", "CANVAS", "PS", "MEMLIMIT", NULL);
959 	    goto error;
960 	}
961 
962 	rowsAtOnce = 60000/width;
963 	if (rowsAtOnce < 1) {
964 	    rowsAtOnce = 1;
965 	}
966 
967 	Tcl_AppendPrintfToObj(psObj, "%.15g %.15g translate\n", x, y+height);
968 
969 	for (curRow = 0; curRow < height; curRow += rowsAtOnce) {
970 	    rowsThisTime = rowsAtOnce;
971 	    if (rowsThisTime > (height - curRow)) {
972 		rowsThisTime = height - curRow;
973 	    }
974 
975 	    Tcl_AppendPrintfToObj(psObj,
976 		    "0 -%.15g translate\n%d %d true matrix {\n",
977 		    (double) rowsThisTime, width, rowsThisTime);
978 
979 	    Tcl_ResetResult(interp);
980 	    if (Tk_CanvasPsBitmap(interp, canvas, bitmap,
981 		    0, curRow, width, rowsThisTime) != TCL_OK) {
982 		goto error;
983 	    }
984 	    Tcl_AppendObjToObj(psObj, Tcl_GetObjResult(interp));
985 
986 	    Tcl_AppendToObj(psObj, "\n} imagemask\n", -1);
987 	}
988     }
989 
990     /*
991      * Plug the accumulated postscript back into the result.
992      */
993 
994     (void) Tcl_RestoreInterpState(interp, interpState);
995     Tcl_AppendObjToObj(Tcl_GetObjResult(interp), psObj);
996     Tcl_DecrRefCount(psObj);
997     return TCL_OK;
998 
999   error:
1000     Tcl_DiscardInterpState(interpState);
1001     Tcl_DecrRefCount(psObj);
1002     return TCL_ERROR;
1003 }
1004 
1005 /*
1006  * Local Variables:
1007  * mode: c
1008  * c-basic-offset: 4
1009  * fill-column: 78
1010  * End:
1011  */
1012