1/*
2 * tkImgBmap.c --
3 *
4 *	This procedure implements images of type "bitmap" for Tk.
5 *
6 * Copyright (c) 1994 The Regents of the University of California.
7 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
8 * Copyright (c) 1999 by Scriptics Corporation.
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: tkImgBmap.c,v 1.15.2.2 2006/09/22 14:53:06 dkf Exp $
14 */
15
16#include "tkInt.h"
17#include "tkPort.h"
18
19/*
20 * The following data structure represents the master for a bitmap
21 * image:
22 */
23
24typedef struct BitmapMaster {
25    Tk_ImageMaster tkMaster;	/* Tk's token for image master.  NULL means
26				 * the image is being deleted. */
27    Tcl_Interp *interp;		/* Interpreter for application that is
28				 * using image. */
29    Tcl_Command imageCmd;	/* Token for image command (used to delete
30				 * it when the image goes away).  NULL means
31				 * the image command has already been
32				 * deleted. */
33    int width, height;		/* Dimensions of image. */
34    char *data;			/* Data comprising bitmap (suitable for
35				 * input to XCreateBitmapFromData).   May
36				 * be NULL if no data.  Malloc'ed. */
37    char *maskData;		/* Data for bitmap's mask (suitable for
38				 * input to XCreateBitmapFromData).
39				 * Malloc'ed. */
40    Tk_Uid fgUid;		/* Value of -foreground option (malloc'ed). */
41    Tk_Uid bgUid;		/* Value of -background option (malloc'ed). */
42    char *fileString;		/* Value of -file option (malloc'ed). */
43    char *dataString;		/* Value of -data option (malloc'ed). */
44    char *maskFileString;	/* Value of -maskfile option (malloc'ed). */
45    char *maskDataString;	/* Value of -maskdata option (malloc'ed). */
46    struct BitmapInstance *instancePtr;
47				/* First in list of all instances associated
48				 * with this master. */
49} BitmapMaster;
50
51/*
52 * The following data structure represents all of the instances of an
53 * image that lie within a particular window:
54 */
55
56typedef struct BitmapInstance {
57    int refCount;		/* Number of instances that share this
58				 * data structure. */
59    BitmapMaster *masterPtr;	/* Pointer to master for image. */
60    Tk_Window tkwin;		/* Window in which the instances will be
61				 * displayed. */
62    XColor *fg;			/* Foreground color for displaying image. */
63    XColor *bg;			/* Background color for displaying image. */
64    Pixmap bitmap;		/* The bitmap to display. */
65    Pixmap mask;		/* Mask: only display bitmap pixels where
66				 * there are 1's here. */
67    GC gc;			/* Graphics context for displaying bitmap.
68				 * None means there was an error while
69				 * setting up the instance, so it cannot
70				 * be displayed. */
71    struct BitmapInstance *nextPtr;
72				/* Next in list of all instance structures
73				 * associated with masterPtr (NULL means
74				 * end of list). */
75} BitmapInstance;
76
77/*
78 * The type record for bitmap images:
79 */
80
81static int		GetByte _ANSI_ARGS_((Tcl_Channel chan));
82static int		ImgBmapCreate _ANSI_ARGS_((Tcl_Interp *interp,
83			    char *name, int argc, Tcl_Obj *CONST objv[],
84			    Tk_ImageType *typePtr, Tk_ImageMaster master,
85			    ClientData *clientDataPtr));
86static ClientData	ImgBmapGet _ANSI_ARGS_((Tk_Window tkwin,
87			    ClientData clientData));
88static void		ImgBmapDisplay _ANSI_ARGS_((ClientData clientData,
89			    Display *display, Drawable drawable,
90			    int imageX, int imageY, int width, int height,
91			    int drawableX, int drawableY));
92static void		ImgBmapFree _ANSI_ARGS_((ClientData clientData,
93			    Display *display));
94static void		ImgBmapDelete _ANSI_ARGS_((ClientData clientData));
95static int		ImgBmapPostscript _ANSI_ARGS_((ClientData clientData,
96			    Tcl_Interp *interp, Tk_Window tkwin,
97			    Tk_PostscriptInfo psinfo, int x, int y,
98			    int width, int height, int prepass));
99
100Tk_ImageType tkBitmapImageType = {
101    "bitmap",			/* name */
102    ImgBmapCreate,		/* createProc */
103    ImgBmapGet,			/* getProc */
104    ImgBmapDisplay,		/* displayProc */
105    ImgBmapFree,		/* freeProc */
106    ImgBmapDelete,		/* deleteProc */
107    ImgBmapPostscript,		/* postscriptProc */
108    (Tk_ImageType *) NULL	/* nextPtr */
109};
110
111/*
112 * Information used for parsing configuration specs:
113 */
114
115static Tk_ConfigSpec configSpecs[] = {
116    {TK_CONFIG_UID, "-background", (char *) NULL, (char *) NULL,
117	"", Tk_Offset(BitmapMaster, bgUid), 0},
118    {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,
119	(char *) NULL, Tk_Offset(BitmapMaster, dataString), TK_CONFIG_NULL_OK},
120    {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
121	(char *) NULL, Tk_Offset(BitmapMaster, fileString), TK_CONFIG_NULL_OK},
122    {TK_CONFIG_UID, "-foreground", (char *) NULL, (char *) NULL,
123	"#000000", Tk_Offset(BitmapMaster, fgUid), 0},
124    {TK_CONFIG_STRING, "-maskdata", (char *) NULL, (char *) NULL,
125	(char *) NULL, Tk_Offset(BitmapMaster, maskDataString),
126	TK_CONFIG_NULL_OK},
127    {TK_CONFIG_STRING, "-maskfile", (char *) NULL, (char *) NULL,
128	(char *) NULL, Tk_Offset(BitmapMaster, maskFileString),
129	TK_CONFIG_NULL_OK},
130    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
131	(char *) NULL, 0, 0}
132};
133
134/*
135 * The following data structure is used to describe the state of
136 * parsing a bitmap file or string.  It is used for communication
137 * between TkGetBitmapData and NextBitmapWord.
138 */
139
140#define MAX_WORD_LENGTH 100
141typedef struct ParseInfo {
142    char *string;		/* Next character of string data for bitmap,
143				 * or NULL if bitmap is being read from
144				 * file. */
145    Tcl_Channel chan;		/* File containing bitmap data, or NULL
146				 * if no file. */
147    char word[MAX_WORD_LENGTH+1];
148				/* Current word of bitmap data, NULL
149				 * terminated. */
150    int wordLength;		/* Number of non-NULL bytes in word. */
151} ParseInfo;
152
153/*
154 * Prototypes for procedures used only locally in this file:
155 */
156
157static int		ImgBmapCmd _ANSI_ARGS_((ClientData clientData,
158			    Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]));
159static void		ImgBmapCmdDeletedProc _ANSI_ARGS_((
160			    ClientData clientData));
161static void		ImgBmapConfigureInstance _ANSI_ARGS_((
162			    BitmapInstance *instancePtr));
163static int		ImgBmapConfigureMaster _ANSI_ARGS_((
164			    BitmapMaster *masterPtr, int argc, Tcl_Obj *CONST objv[],
165			    int flags));
166static int		NextBitmapWord _ANSI_ARGS_((ParseInfo *parseInfoPtr));
167
168/*
169 *----------------------------------------------------------------------
170 *
171 * ImgBmapCreate --
172 *
173 *	This procedure is called by the Tk image code to create "test"
174 *	images.
175 *
176 * Results:
177 *	A standard Tcl result.
178 *
179 * Side effects:
180 *	The data structure for a new image is allocated.
181 *
182 *----------------------------------------------------------------------
183 */
184
185	/* ARGSUSED */
186static int
187ImgBmapCreate(interp, name, argc, argv, typePtr, master, clientDataPtr)
188    Tcl_Interp *interp;		/* Interpreter for application containing
189				 * image. */
190    char *name;			/* Name to use for image. */
191    int argc;			/* Number of arguments. */
192    Tcl_Obj *CONST argv[];	/* Argument objects for options (doesn't
193				 * include image name or type). */
194    Tk_ImageType *typePtr;	/* Pointer to our type record (not used). */
195    Tk_ImageMaster master;	/* Token for image, to be used by us in
196				 * later callbacks. */
197    ClientData *clientDataPtr;	/* Store manager's token for image here;
198				 * it will be returned in later callbacks. */
199{
200    BitmapMaster *masterPtr;
201
202    masterPtr = (BitmapMaster *) ckalloc(sizeof(BitmapMaster));
203    masterPtr->tkMaster = master;
204    masterPtr->interp = interp;
205    masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgBmapCmd,
206	    (ClientData) masterPtr, ImgBmapCmdDeletedProc);
207    masterPtr->width = masterPtr->height = 0;
208    masterPtr->data = NULL;
209    masterPtr->maskData = NULL;
210    masterPtr->fgUid = NULL;
211    masterPtr->bgUid = NULL;
212    masterPtr->fileString = NULL;
213    masterPtr->dataString = NULL;
214    masterPtr->maskFileString = NULL;
215    masterPtr->maskDataString = NULL;
216    masterPtr->instancePtr = NULL;
217    if (ImgBmapConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) {
218	ImgBmapDelete((ClientData) masterPtr);
219	return TCL_ERROR;
220    }
221    *clientDataPtr = (ClientData) masterPtr;
222    return TCL_OK;
223}
224
225/*
226 *----------------------------------------------------------------------
227 *
228 * ImgBmapConfigureMaster --
229 *
230 *	This procedure is called when a bitmap image is created or
231 *	reconfigured.  It process configuration options and resets
232 *	any instances of the image.
233 *
234 * Results:
235 *	A standard Tcl return value.  If TCL_ERROR is returned then
236 *	an error message is left in the masterPtr->interp's result.
237 *
238 * Side effects:
239 *	Existing instances of the image will be redisplayed to match
240 *	the new configuration options.
241 *
242 *----------------------------------------------------------------------
243 */
244
245static int
246ImgBmapConfigureMaster(masterPtr, objc, objv, flags)
247    BitmapMaster *masterPtr;	/* Pointer to data structure describing
248				 * overall bitmap image to (reconfigure). */
249    int objc;			/* Number of entries in objv. */
250    Tcl_Obj *CONST objv[];	/* Pairs of configuration options for image. */
251    int flags;			/* Flags to pass to Tk_ConfigureWidget,
252				 * such as TK_CONFIG_ARGV_ONLY. */
253{
254    BitmapInstance *instancePtr;
255    int maskWidth, maskHeight, dummy1, dummy2;
256
257    CONST char **argv = (CONST char **) ckalloc((objc+1) * sizeof(char *));
258    for (dummy1 = 0; dummy1 < objc; dummy1++) {
259	argv[dummy1]=Tcl_GetString(objv[dummy1]);
260    }
261    argv[objc] = NULL;
262
263    if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp),
264	    configSpecs, objc, argv, (char *) masterPtr, flags)
265	    != TCL_OK) {
266	ckfree((char *) argv);
267	return TCL_ERROR;
268    }
269    ckfree((char *) argv);
270
271    /*
272     * Parse the bitmap and/or mask to create binary data.  Make sure that
273     * the bitmap and mask have the same dimensions.
274     */
275
276    if (masterPtr->data != NULL) {
277	ckfree(masterPtr->data);
278	masterPtr->data = NULL;
279    }
280    if ((masterPtr->fileString != NULL) || (masterPtr->dataString != NULL)) {
281	masterPtr->data = TkGetBitmapData(masterPtr->interp,
282		masterPtr->dataString, masterPtr->fileString,
283		&masterPtr->width, &masterPtr->height, &dummy1, &dummy2);
284	if (masterPtr->data == NULL) {
285	    return TCL_ERROR;
286	}
287    }
288    if (masterPtr->maskData != NULL) {
289	ckfree(masterPtr->maskData);
290	masterPtr->maskData = NULL;
291    }
292    if ((masterPtr->maskFileString != NULL)
293	    || (masterPtr->maskDataString != NULL)) {
294	if (masterPtr->data == NULL) {
295	    Tcl_SetResult(masterPtr->interp, "can't have mask without bitmap",
296		    TCL_STATIC);
297	    return TCL_ERROR;
298	}
299	masterPtr->maskData = TkGetBitmapData(masterPtr->interp,
300		masterPtr->maskDataString, masterPtr->maskFileString,
301		&maskWidth, &maskHeight, &dummy1, &dummy2);
302	if (masterPtr->maskData == NULL) {
303	    return TCL_ERROR;
304	}
305	if ((maskWidth != masterPtr->width)
306		|| (maskHeight != masterPtr->height)) {
307	    ckfree(masterPtr->maskData);
308	    masterPtr->maskData = NULL;
309	    Tcl_SetResult(masterPtr->interp,
310		    "bitmap and mask have different sizes", TCL_STATIC);
311	    return TCL_ERROR;
312	}
313    }
314
315    /*
316     * Cycle through all of the instances of this image, regenerating
317     * the information for each instance.  Then force the image to be
318     * redisplayed everywhere that it is used.
319     */
320
321    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
322	    instancePtr = instancePtr->nextPtr) {
323	ImgBmapConfigureInstance(instancePtr);
324    }
325    Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
326	    masterPtr->height, masterPtr->width, masterPtr->height);
327    return TCL_OK;
328}
329
330/*
331 *----------------------------------------------------------------------
332 *
333 * ImgBmapConfigureInstance --
334 *
335 *	This procedure is called to create displaying information for
336 *	a bitmap image instance based on the configuration information
337 *	in the master.  It is invoked both when new instances are
338 *	created and when the master is reconfigured.
339 *
340 * Results:
341 *	None.
342 *
343 * Side effects:
344 *	Generates errors via Tcl_BackgroundError if there are problems
345 *	in setting up the instance.
346 *
347 *----------------------------------------------------------------------
348 */
349
350static void
351ImgBmapConfigureInstance(instancePtr)
352    BitmapInstance *instancePtr;	/* Instance to reconfigure. */
353{
354    BitmapMaster *masterPtr = instancePtr->masterPtr;
355    XColor *colorPtr;
356    XGCValues gcValues;
357    GC gc;
358    unsigned int mask;
359    Pixmap oldBitmap, oldMask;
360
361    /*
362     * For each of the options in masterPtr, translate the string
363     * form into an internal form appropriate for instancePtr.
364     */
365
366    if (*masterPtr->bgUid != 0) {
367	colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
368		masterPtr->bgUid);
369	if (colorPtr == NULL) {
370	    goto error;
371	}
372    } else {
373	colorPtr = NULL;
374    }
375    if (instancePtr->bg != NULL) {
376	Tk_FreeColor(instancePtr->bg);
377    }
378    instancePtr->bg = colorPtr;
379
380    colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
381	    masterPtr->fgUid);
382    if (colorPtr == NULL) {
383	goto error;
384    }
385    if (instancePtr->fg != NULL) {
386	Tk_FreeColor(instancePtr->fg);
387    }
388    instancePtr->fg = colorPtr;
389
390    oldMask = instancePtr->mask;
391    instancePtr->mask = None;
392
393    /*
394     * Careful: We have to allocate new Pixmaps before deleting the old ones.
395     * Otherwise, The XID allocator will always return the same XID for the
396     * new Pixmaps as was used for the old Pixmaps. And that will prevent the
397     * data and/or mask from changing in the GC below.
398     */
399
400    oldBitmap = instancePtr->bitmap;
401    instancePtr->bitmap = None;
402    oldMask = instancePtr->mask;
403    instancePtr->mask = None;
404
405    if (masterPtr->data != NULL) {
406	instancePtr->bitmap = XCreateBitmapFromData(
407		Tk_Display(instancePtr->tkwin),
408		RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
409		masterPtr->data, (unsigned) masterPtr->width,
410		(unsigned) masterPtr->height);
411    }
412    if (masterPtr->maskData != NULL) {
413	instancePtr->mask = XCreateBitmapFromData(
414		Tk_Display(instancePtr->tkwin),
415		RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
416		masterPtr->maskData, (unsigned) masterPtr->width,
417		(unsigned) masterPtr->height);
418    }
419
420    if (oldMask != None) {
421	Tk_FreePixmap(Tk_Display(instancePtr->tkwin), oldMask);
422    }
423    if (oldBitmap != None) {
424	Tk_FreePixmap(Tk_Display(instancePtr->tkwin), oldBitmap);
425    }
426
427    if (masterPtr->data != NULL) {
428	gcValues.foreground = instancePtr->fg->pixel;
429	gcValues.graphics_exposures = False;
430	mask = GCForeground|GCGraphicsExposures;
431	if (instancePtr->bg != NULL) {
432	    gcValues.background = instancePtr->bg->pixel;
433	    mask |= GCBackground;
434	    if (instancePtr->mask != None) {
435		gcValues.clip_mask = instancePtr->mask;
436		mask |= GCClipMask;
437	    }
438	} else {
439	    gcValues.clip_mask = instancePtr->bitmap;
440	    mask |= GCClipMask;
441	}
442	gc = Tk_GetGC(instancePtr->tkwin, mask, &gcValues);
443    } else {
444	gc = None;
445    }
446    if (instancePtr->gc != None) {
447	Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
448    }
449    instancePtr->gc = gc;
450    return;
451
452    error:
453    /*
454     * An error occurred: clear the graphics context in the instance to
455     * make it clear that this instance cannot be displayed.  Then report
456     * the error.
457     */
458
459    if (instancePtr->gc != None) {
460	Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
461    }
462    instancePtr->gc = None;
463    Tcl_AddErrorInfo(masterPtr->interp, "\n    (while configuring image \"");
464    Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
465    Tcl_AddErrorInfo(masterPtr->interp, "\")");
466    Tcl_BackgroundError(masterPtr->interp);
467}
468
469/*
470 *----------------------------------------------------------------------
471 *
472 * TkGetBitmapData --
473 *
474 *	Given a file name or ASCII string, this procedure parses the
475 *	file or string contents to produce binary data for a bitmap.
476 *
477 * Results:
478 *	If the bitmap description was parsed successfully then the
479 *	return value is a malloc-ed array containing the bitmap data.
480 *	The dimensions of the data are stored in *widthPtr and
481 *	*heightPtr.  *hotXPtr and *hotYPtr are set to the bitmap
482 *	hotspot if one is defined, otherwise they are set to -1, -1.
483 *	If an error occurred, NULL is returned and an error message is
484 *	left in the interp's result.
485 *
486 * Side effects:
487 *	A bitmap is created.
488 *
489 *----------------------------------------------------------------------
490 */
491
492char *
493TkGetBitmapData(interp, string, fileName, widthPtr, heightPtr,
494	hotXPtr, hotYPtr)
495    Tcl_Interp *interp;			/* For reporting errors, or NULL. */
496    char *string;			/* String describing bitmap.  May
497					 * be NULL. */
498    char *fileName;			/* Name of file containing bitmap
499					 * description.  Used only if string
500					 * is NULL.  Must not be NULL if
501					 * string is NULL. */
502    int *widthPtr, *heightPtr;		/* Dimensions of bitmap get returned
503					 * here. */
504    int *hotXPtr, *hotYPtr;		/* Position of hot spot or -1,-1. */
505{
506    int width, height, numBytes, hotX, hotY;
507    CONST char *expandedFileName;
508    char *p, *end;
509    ParseInfo pi;
510    char *data = NULL;
511    Tcl_DString buffer;
512
513    pi.string = string;
514    if (string == NULL) {
515        if ((interp != NULL) && Tcl_IsSafe(interp)) {
516            Tcl_AppendResult(interp, "can't get bitmap data from a file in a",
517                    " safe interpreter", (char *) NULL);
518            return NULL;
519        }
520	expandedFileName = Tcl_TranslateFileName(interp, fileName, &buffer);
521	if (expandedFileName == NULL) {
522	    return NULL;
523	}
524	pi.chan = Tcl_OpenFileChannel(interp, expandedFileName, "r", 0);
525	Tcl_DStringFree(&buffer);
526	if (pi.chan == NULL) {
527	    if (interp != NULL) {
528		Tcl_ResetResult(interp);
529		Tcl_AppendResult(interp, "couldn't read bitmap file \"",
530			fileName, "\": ", Tcl_PosixError(interp),
531			(char *) NULL);
532	    }
533	    return NULL;
534	}
535
536        if (Tcl_SetChannelOption(interp, pi.chan, "-translation", "binary")
537		!= TCL_OK) {
538            return NULL;
539        }
540        if (Tcl_SetChannelOption(interp, pi.chan, "-encoding", "binary")
541		!= TCL_OK) {
542            return NULL;
543        }
544    } else {
545	pi.chan = NULL;
546    }
547
548    /*
549     * Parse the lines that define the dimensions of the bitmap,
550     * plus the first line that defines the bitmap data (it declares
551     * the name of a data variable but doesn't include any actual
552     * data).  These lines look something like the following:
553     *
554     *		#define foo_width 16
555     *		#define foo_height 16
556     *		#define foo_x_hot 3
557     *		#define foo_y_hot 3
558     *		static char foo_bits[] = {
559     *
560     * The x_hot and y_hot lines may or may not be present.  It's
561     * important to check for "char" in the last line, in order to
562     * reject old X10-style bitmaps that used shorts.
563     */
564
565    width = 0;
566    height = 0;
567    hotX = -1;
568    hotY = -1;
569    while (1) {
570	if (NextBitmapWord(&pi) != TCL_OK) {
571	    goto error;
572	}
573	if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
574		&& (strcmp(pi.word+pi.wordLength-6, "_width") == 0)) {
575	    if (NextBitmapWord(&pi) != TCL_OK) {
576		goto error;
577	    }
578	    width = strtol(pi.word, &end, 0);
579	    if ((end == pi.word) || (*end != 0)) {
580		goto error;
581	    }
582	} else if ((pi.wordLength >= 7) && (pi.word[pi.wordLength-7] == '_')
583		&& (strcmp(pi.word+pi.wordLength-7, "_height") == 0)) {
584	    if (NextBitmapWord(&pi) != TCL_OK) {
585		goto error;
586	    }
587	    height = strtol(pi.word, &end, 0);
588	    if ((end == pi.word) || (*end != 0)) {
589		goto error;
590	    }
591	} else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
592		&& (strcmp(pi.word+pi.wordLength-6, "_x_hot") == 0)) {
593	    if (NextBitmapWord(&pi) != TCL_OK) {
594		goto error;
595	    }
596	    hotX = strtol(pi.word, &end, 0);
597	    if ((end == pi.word) || (*end != 0)) {
598		goto error;
599	    }
600	} else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
601		&& (strcmp(pi.word+pi.wordLength-6, "_y_hot") == 0)) {
602	    if (NextBitmapWord(&pi) != TCL_OK) {
603		goto error;
604	    }
605	    hotY = strtol(pi.word, &end, 0);
606	    if ((end == pi.word) || (*end != 0)) {
607		goto error;
608	    }
609	} else if ((pi.word[0] == 'c') && (strcmp(pi.word, "char") == 0)) {
610	    while (1) {
611		if (NextBitmapWord(&pi) != TCL_OK) {
612		    goto error;
613		}
614		if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
615		    goto getData;
616		}
617	    }
618	} else if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
619	    if (interp != NULL) {
620		Tcl_AppendResult(interp, "format error in bitmap data; ",
621			"looks like it's an obsolete X10 bitmap file",
622			(char *) NULL);
623	    }
624	    goto errorCleanup;
625	}
626    }
627
628    /*
629     * Now we've read everything but the data.  Allocate an array
630     * and read in the data.
631     */
632
633    getData:
634    if ((width <= 0) || (height <= 0)) {
635	goto error;
636    }
637    numBytes = ((width+7)/8) * height;
638    data = (char *) ckalloc((unsigned) numBytes);
639    for (p = data; numBytes > 0; p++, numBytes--) {
640	if (NextBitmapWord(&pi) != TCL_OK) {
641	    goto error;
642	}
643	*p = (char) strtol(pi.word, &end, 0);
644	if (end == pi.word) {
645	    goto error;
646	}
647    }
648
649    /*
650     * All done.  Clean up and return.
651     */
652
653    if (pi.chan != NULL) {
654	Tcl_Close(NULL, pi.chan);
655    }
656    *widthPtr = width;
657    *heightPtr = height;
658    *hotXPtr = hotX;
659    *hotYPtr = hotY;
660    return data;
661
662    error:
663    if (interp != NULL) {
664	Tcl_SetResult(interp, "format error in bitmap data", TCL_STATIC);
665    }
666
667    errorCleanup:
668    if (data != NULL) {
669	ckfree(data);
670    }
671    if (pi.chan != NULL) {
672	Tcl_Close(NULL, pi.chan);
673    }
674    return NULL;
675}
676
677/*
678 *----------------------------------------------------------------------
679 *
680 * NextBitmapWord --
681 *
682 *	This procedure retrieves the next word of information (stuff
683 *	between commas or white space) from a bitmap description.
684 *
685 * Results:
686 *	Returns TCL_OK if all went well.  In this case the next word,
687 *	and its length, will be availble in *parseInfoPtr.  If the end
688 *	of the bitmap description was reached then TCL_ERROR is returned.
689 *
690 * Side effects:
691 *	None.
692 *
693 *----------------------------------------------------------------------
694 */
695
696static int
697NextBitmapWord(parseInfoPtr)
698    ParseInfo *parseInfoPtr;		/* Describes what we're reading
699					 * and where we are in it. */
700{
701    char *src, *dst;
702    int c;
703
704    parseInfoPtr->wordLength = 0;
705    dst = parseInfoPtr->word;
706    if (parseInfoPtr->string != NULL) {
707	for (src = parseInfoPtr->string; isspace(UCHAR(*src)) || (*src == ',');
708		src++) {
709	    if (*src == 0) {
710		return TCL_ERROR;
711	    }
712	}
713	for ( ; !isspace(UCHAR(*src)) && (*src != ',') && (*src != 0); src++) {
714	    *dst = *src;
715	    dst++;
716	    parseInfoPtr->wordLength++;
717	    if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
718		return TCL_ERROR;
719	    }
720	}
721	parseInfoPtr->string = src;
722    } else {
723	for (c = GetByte(parseInfoPtr->chan); isspace(UCHAR(c)) || (c == ',');
724		c = GetByte(parseInfoPtr->chan)) {
725	    if (c == EOF) {
726		return TCL_ERROR;
727	    }
728	}
729	for ( ; !isspace(UCHAR(c)) && (c != ',') && (c != EOF);
730		c = GetByte(parseInfoPtr->chan)) {
731	    *dst = c;
732	    dst++;
733	    parseInfoPtr->wordLength++;
734	    if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
735		return TCL_ERROR;
736	    }
737	}
738    }
739    if (parseInfoPtr->wordLength == 0) {
740	return TCL_ERROR;
741    }
742    parseInfoPtr->word[parseInfoPtr->wordLength] = 0;
743    return TCL_OK;
744}
745
746/*
747 *--------------------------------------------------------------
748 *
749 * ImgBmapCmd --
750 *
751 *	This procedure is invoked to process the Tcl command
752 *	that corresponds to an image managed by this module.
753 *	See the user documentation for details on what it does.
754 *
755 * Results:
756 *	A standard Tcl result.
757 *
758 * Side effects:
759 *	See the user documentation.
760 *
761 *--------------------------------------------------------------
762 */
763
764static int
765ImgBmapCmd(clientData, interp, objc, objv)
766    ClientData clientData;	/* Information about the image master. */
767    Tcl_Interp *interp;		/* Current interpreter. */
768    int objc;			/* Number of arguments. */
769    Tcl_Obj *CONST objv[];	/* Argument objects. */
770{
771    static CONST char *bmapOptions[] = {"cget", "configure", (char *) NULL};
772    BitmapMaster *masterPtr = (BitmapMaster *) clientData;
773    int code, index;
774
775    if (objc < 2) {
776	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
777	return TCL_ERROR;
778    }
779    if (Tcl_GetIndexFromObj(interp, objv[1], bmapOptions, "option", 0,
780	    &index) != TCL_OK) {
781	return TCL_ERROR;
782    }
783    switch (index) {
784      case 0: {
785	if (objc != 3) {
786	    Tcl_WrongNumArgs(interp, 2, objv, "option");
787	    return TCL_ERROR;
788	}
789	return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
790		(char *) masterPtr, Tcl_GetString(objv[2]), 0);
791      }
792      case 1: {
793	if (objc == 2) {
794	    code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
795		    configSpecs, (char *) masterPtr, (char *) NULL, 0);
796	} else if (objc == 3) {
797	    code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
798		    configSpecs, (char *) masterPtr,
799		    Tcl_GetString(objv[2]), 0);
800	} else {
801	    code = ImgBmapConfigureMaster(masterPtr, objc-2, objv+2,
802		    TK_CONFIG_ARGV_ONLY);
803	}
804	return code;
805      }
806      default: {
807	panic("bad const entries to bmapOptions in ImgBmapCmd");
808      }
809    }
810    return TCL_OK;
811}
812
813/*
814 *----------------------------------------------------------------------
815 *
816 * ImgBmapGet --
817 *
818 *	This procedure is called for each use of a bitmap image in a
819 *	widget.
820 *
821 * Results:
822 *	The return value is a token for the instance, which is passed
823 *	back to us in calls to ImgBmapDisplay and ImgBmapFree.
824 *
825 * Side effects:
826 *	A data structure is set up for the instance (or, an existing
827 *	instance is re-used for the new one).
828 *
829 *----------------------------------------------------------------------
830 */
831
832static ClientData
833ImgBmapGet(tkwin, masterData)
834    Tk_Window tkwin;		/* Window in which the instance will be
835				 * used. */
836    ClientData masterData;	/* Pointer to our master structure for the
837				 * image. */
838{
839    BitmapMaster *masterPtr = (BitmapMaster *) masterData;
840    BitmapInstance *instancePtr;
841
842    /*
843     * See if there is already an instance for this window.  If so
844     * then just re-use it.
845     */
846
847    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
848	    instancePtr = instancePtr->nextPtr) {
849	if (instancePtr->tkwin == tkwin) {
850	    instancePtr->refCount++;
851	    return (ClientData) instancePtr;
852	}
853    }
854
855    /*
856     * The image isn't already in use in this window.  Make a new
857     * instance of the image.
858     */
859
860    instancePtr = (BitmapInstance *) ckalloc(sizeof(BitmapInstance));
861    instancePtr->refCount = 1;
862    instancePtr->masterPtr = masterPtr;
863    instancePtr->tkwin = tkwin;
864    instancePtr->fg = NULL;
865    instancePtr->bg = NULL;
866    instancePtr->bitmap = None;
867    instancePtr->mask = None;
868    instancePtr->gc = None;
869    instancePtr->nextPtr = masterPtr->instancePtr;
870    masterPtr->instancePtr = instancePtr;
871    ImgBmapConfigureInstance(instancePtr);
872
873    /*
874     * If this is the first instance, must set the size of the image.
875     */
876
877    if (instancePtr->nextPtr == NULL) {
878	Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
879		masterPtr->height);
880    }
881
882    return (ClientData) instancePtr;
883}
884
885/*
886 *----------------------------------------------------------------------
887 *
888 * ImgBmapDisplay --
889 *
890 *	This procedure is invoked to draw a bitmap image.
891 *
892 * Results:
893 *	None.
894 *
895 * Side effects:
896 *	A portion of the image gets rendered in a pixmap or window.
897 *
898 *----------------------------------------------------------------------
899 */
900
901static void
902ImgBmapDisplay(clientData, display, drawable, imageX, imageY, width,
903	height, drawableX, drawableY)
904    ClientData clientData;	/* Pointer to BitmapInstance structure for
905				 * for instance to be displayed. */
906    Display *display;		/* Display on which to draw image. */
907    Drawable drawable;		/* Pixmap or window in which to draw image. */
908    int imageX, imageY;		/* Upper-left corner of region within image
909				 * to draw. */
910    int width, height;		/* Dimensions of region within image to draw. */
911    int drawableX, drawableY;	/* Coordinates within drawable that
912				 * correspond to imageX and imageY. */
913{
914    BitmapInstance *instancePtr = (BitmapInstance *) clientData;
915    int masking;
916
917    /*
918     * If there's no graphics context, it means that an error occurred
919     * while creating the image instance so it can't be displayed.
920     */
921
922    if (instancePtr->gc == None) {
923	return;
924    }
925
926    /*
927     * If masking is in effect, must modify the mask origin within
928     * the graphics context to line up with the image's origin.
929     * Then draw the image and reset the clip origin, if there's
930     * a mask.
931     */
932
933    masking = (instancePtr->mask != None) || (instancePtr->bg == NULL);
934    if (masking) {
935	XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
936		drawableY - imageY);
937    }
938    XCopyPlane(display, instancePtr->bitmap, drawable, instancePtr->gc,
939	    imageX, imageY, (unsigned) width, (unsigned) height,
940	    drawableX, drawableY, 1);
941    if (masking) {
942	XSetClipOrigin(display, instancePtr->gc, 0, 0);
943    }
944}
945
946/*
947 *----------------------------------------------------------------------
948 *
949 * ImgBmapFree --
950 *
951 *	This procedure is called when a widget ceases to use a
952 *	particular instance of an image.
953 *
954 * Results:
955 *	None.
956 *
957 * Side effects:
958 *	Internal data structures get cleaned up.
959 *
960 *----------------------------------------------------------------------
961 */
962
963static void
964ImgBmapFree(clientData, display)
965    ClientData clientData;	/* Pointer to BitmapInstance structure for
966				 * for instance to be displayed. */
967    Display *display;		/* Display containing window that used image. */
968{
969    BitmapInstance *instancePtr = (BitmapInstance *) clientData;
970    BitmapInstance *prevPtr;
971
972    instancePtr->refCount--;
973    if (instancePtr->refCount > 0) {
974	return;
975    }
976
977    /*
978     * There are no more uses of the image within this widget.  Free
979     * the instance structure.
980     */
981
982    if (instancePtr->fg != NULL) {
983	Tk_FreeColor(instancePtr->fg);
984    }
985    if (instancePtr->bg != NULL) {
986	Tk_FreeColor(instancePtr->bg);
987    }
988    if (instancePtr->bitmap != None) {
989	Tk_FreePixmap(display, instancePtr->bitmap);
990    }
991    if (instancePtr->mask != None) {
992	Tk_FreePixmap(display, instancePtr->mask);
993    }
994    if (instancePtr->gc != None) {
995	Tk_FreeGC(display, instancePtr->gc);
996    }
997    if (instancePtr->masterPtr->instancePtr == instancePtr) {
998	instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
999    } else {
1000	for (prevPtr = instancePtr->masterPtr->instancePtr;
1001		prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
1002	    /* Empty loop body */
1003	}
1004	prevPtr->nextPtr = instancePtr->nextPtr;
1005    }
1006    ckfree((char *) instancePtr);
1007}
1008
1009/*
1010 *----------------------------------------------------------------------
1011 *
1012 * ImgBmapDelete --
1013 *
1014 *	This procedure is called by the image code to delete the
1015 *	master structure for an image.
1016 *
1017 * Results:
1018 *	None.
1019 *
1020 * Side effects:
1021 *	Resources associated with the image get freed.
1022 *
1023 *----------------------------------------------------------------------
1024 */
1025
1026static void
1027ImgBmapDelete(masterData)
1028    ClientData masterData;	/* Pointer to BitmapMaster structure for
1029				 * image.  Must not have any more instances. */
1030{
1031    BitmapMaster *masterPtr = (BitmapMaster *) masterData;
1032
1033    if (masterPtr->instancePtr != NULL) {
1034	panic("tried to delete bitmap image when instances still exist");
1035    }
1036    masterPtr->tkMaster = NULL;
1037    if (masterPtr->imageCmd != NULL) {
1038	Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
1039    }
1040    if (masterPtr->data != NULL) {
1041	ckfree(masterPtr->data);
1042    }
1043    if (masterPtr->maskData != NULL) {
1044	ckfree(masterPtr->maskData);
1045    }
1046    Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
1047    ckfree((char *) masterPtr);
1048}
1049
1050/*
1051 *----------------------------------------------------------------------
1052 *
1053 * ImgBmapCmdDeletedProc --
1054 *
1055 *	This procedure is invoked when the image command for an image
1056 *	is deleted.  It deletes the image.
1057 *
1058 * Results:
1059 *	None.
1060 *
1061 * Side effects:
1062 *	The image is deleted.
1063 *
1064 *----------------------------------------------------------------------
1065 */
1066
1067static void
1068ImgBmapCmdDeletedProc(clientData)
1069    ClientData clientData;	/* Pointer to BitmapMaster structure for
1070				 * image. */
1071{
1072    BitmapMaster *masterPtr = (BitmapMaster *) clientData;
1073
1074    masterPtr->imageCmd = NULL;
1075    if (masterPtr->tkMaster != NULL) {
1076	Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
1077    }
1078}
1079
1080/*
1081 *----------------------------------------------------------------------
1082 *
1083 * GetByte --
1084 *
1085 *	Get the next byte from the open channel.
1086 *
1087 * Results:
1088 *	The next byte or EOF.
1089 *
1090 * Side effects:
1091 *	We read from the channel.
1092 *
1093 *----------------------------------------------------------------------
1094 */
1095
1096static int
1097GetByte(chan)
1098    Tcl_Channel chan;	/* The channel we read from. */
1099{
1100    char buffer;
1101    int size;
1102
1103    size = Tcl_Read(chan, &buffer, 1);
1104    if (size <= 0) {
1105	return EOF;
1106    } else {
1107	return buffer;
1108    }
1109}
1110
1111
1112/*
1113 *----------------------------------------------------------------------
1114 *
1115 * ImgBmapPsImagemask --
1116 *
1117 *	This procedure generates postscript suitable for rendering a
1118 *      single bitmap of an image.  A single bitmap image might contain both
1119 *      a foreground and a background bitmap.  This routine is called once
1120 *      for each such bitmap in a bitmap image.
1121 *
1122 *      Prior to invoking this routine, the following setup has occurred:
1123 *
1124 *	   1.  The postscript foreground color has been set to the color
1125 *	       used to render the bitmap.
1126 *
1127 *	   2.  The origin of the postscript coordinate system is set to
1128 *             the lower left corner of the bitmap.
1129 *
1130 *	   3.  The postscript coordinate system has been scaled so that
1131 *	       the entire bitmap is one unit squared.
1132 *
1133 * 	Some postscript implementations cannot handle bitmap strings
1134 *	longer than about 60k characters.  If the bitmap data is that big
1135 *	or bigger, then we render it by splitting it into several smaller
1136 *	bitmaps.
1137 *
1138 * Results:
1139 *	Returns TCL_OK on success.  Returns TCL_ERROR and leaves and error
1140 *	message in interp->result if there is a problem.
1141 *
1142 * Side effects:
1143 *	Postscript code is appended to interp->result.
1144 *
1145 *----------------------------------------------------------------------
1146 */
1147
1148static int
1149ImgBmapPsImagemask(interp, width, height, data)
1150    Tcl_Interp *interp;       /* Append postscript to this interpreter */
1151    int width, height;        /* Width and height of the bitmap in pixels */
1152    char *data;               /* Data for the bitmap */
1153{
1154    int i, j, nBytePerRow;
1155    char buffer[200];
1156
1157    /*
1158     * The bit order of bitmaps in Tk is the opposite of the bit order that
1159     * postscript uses.  (In Tk, the least significant bit is on the right
1160     * side of the bitmap and in postscript the least significant bit is shown
1161     * on the left.)  The following array is used to reverse the order of bits
1162     * within a byte so that the bits will be in the order postscript expects.
1163     */
1164    static unsigned char bit_reverse[] = {
1165       0, 128, 64, 192, 32, 160,  96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
1166       8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
1167       4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
1168      12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
1169       2, 130, 66, 194, 34, 162,  98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
1170      10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
1171       6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
1172      14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
1173       1, 129, 65, 193, 33, 161,  97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
1174       9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
1175       5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
1176      13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
1177       3, 131, 67, 195, 35, 163,  99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
1178      11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
1179       7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
1180      15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255,
1181    };
1182
1183    if (width*height > 60000) {
1184	Tcl_ResetResult(interp);
1185	Tcl_AppendResult(interp, "unable to generate postscript for bitmaps "
1186		"larger than 60000 pixels", NULL);
1187	return TCL_ERROR;
1188    }
1189    sprintf(buffer, "0 0 moveto %d %d true [%d 0 0 %d 0 %d] {<\n",
1190      width, height, width, -height, height);
1191    Tcl_AppendResult(interp, buffer, NULL);
1192    nBytePerRow = (width+7)/8;
1193    for(i=0; i<height; i++){
1194      for(j=0; j<nBytePerRow; j++){
1195        sprintf(buffer, " %02x", bit_reverse[0xff & data[i*nBytePerRow + j]]);
1196        Tcl_AppendResult(interp, buffer, NULL);
1197      }
1198      Tcl_AppendResult(interp, "\n", NULL);
1199    }
1200    Tcl_AppendResult(interp, ">} imagemask \n", NULL);
1201    return TCL_OK;
1202}
1203
1204/*
1205 *----------------------------------------------------------------------
1206 *
1207 * ImgBmapPostscript --
1208 *
1209 *	This procedure generates postscript for rendering a bitmap image.
1210 *
1211 * Results:
1212 *	On success, this routine writes postscript code into interp->result
1213 *      and returns TCL_OK  TCL_ERROR is returned and an error
1214 *      message is left in interp->result if anything goes wrong.
1215 *
1216 * Side effects:
1217 *	None.
1218 *
1219 *----------------------------------------------------------------------
1220 */
1221
1222static int
1223ImgBmapPostscript(clientData, interp, tkwin, psinfo, x, y, width, height,
1224	prepass)
1225    ClientData clientData;
1226    Tcl_Interp *interp;
1227    Tk_Window tkwin;
1228    Tk_PostscriptInfo psinfo;
1229    int x, y, width, height, prepass;
1230{
1231    BitmapMaster *masterPtr = (BitmapMaster *) clientData;
1232    char buffer[200];
1233
1234    if (prepass) {
1235	return TCL_OK;
1236    }
1237
1238    /*
1239     * There is nothing to do for bitmaps with zero width or height
1240     */
1241    if( width<=0 || height<=0 || masterPtr->width<=0 || masterPtr->height<=0 ){
1242	return TCL_OK;
1243    }
1244
1245    /*
1246     * Translate the origin of the coordinate system to be the lower-left
1247     * corner of the bitmap and adjust the scale of the coordinate system
1248     * so that entire bitmap covers one square unit of the page.
1249     * The calling function put a "gsave" into the postscript and
1250     * will add a "grestore" at after this routine returns, so it is safe
1251     * to make whatever changes are necessary here.
1252     */
1253    if( x!=0 || y!=0 ){
1254	sprintf(buffer, "%d %d moveto\n", x, y);
1255	Tcl_AppendResult(interp, buffer, NULL);
1256    }
1257    if( width!=1 || height!=1 ){
1258	sprintf(buffer, "%d %d scale\n", width, height);
1259 	Tcl_AppendResult(interp, buffer, NULL);
1260    }
1261
1262    /*
1263     * Color the background, if there is one.  This step is skipped if the
1264     * background is transparent.  If the background is not transparent and
1265     * there is no background mask, then color the complete rectangle that
1266     * encloses the bitmap.  If there is a background mask, then only apply
1267     * color to the bits specified by the mask.
1268     */
1269    if ((masterPtr->bgUid != NULL) && (masterPtr->bgUid[0] != '\000')) {
1270	XColor color;
1271	XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->bgUid,
1272		&color);
1273	if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) {
1274	    return TCL_ERROR;
1275	}
1276	if (masterPtr->maskData == NULL) {
1277	    Tcl_AppendResult(interp,
1278		"0 0 moveto 1 0 rlineto 0 1 rlineto -1 0 rlineto "
1279		"closepath fill\n", NULL);
1280	} else if (ImgBmapPsImagemask(interp, masterPtr->width,
1281		     masterPtr->height, masterPtr->maskData) != TCL_OK) {
1282	    return TCL_ERROR;
1283	}
1284    }
1285
1286    /*
1287     * Draw the bitmap foreground, assuming there is one.
1288     */
1289    if ( (masterPtr->fgUid != NULL) && (masterPtr->data != NULL) ) {
1290	XColor color;
1291	XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->fgUid,
1292		&color);
1293	if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) {
1294	    return TCL_ERROR;
1295	}
1296	if (ImgBmapPsImagemask(interp, masterPtr->width, masterPtr->height,
1297		masterPtr->data) != TCL_OK) {
1298	    return TCL_ERROR;
1299	}
1300    }
1301    return TCL_OK;
1302}
1303