1 
2 /*
3  * bltBitmap.c --
4  *
5  *	This module implements Tcl bitmaps for the Tk toolkit.
6  *
7  *	Much of the code is taken from XRdBitF.c and XWrBitF.c
8  *	from the MIT X11R5 distribution.
9  *
10  * Copyright, 1987, Massachusetts Institute of Technology Permission
11  * to use, copy, modify, distribute, and sell this software and its
12  * documentation for any purpose is hereby granted without fee,
13  * provided that the above copyright notice appear in all copies and
14  * that both that copyright notice and this permission notice appear
15  * in supporting documentation, and that the name of M.I.T. not be
16  * used in advertising or publicity pertaining to distribution of the
17  * software without specific, written prior permission.  M.I.T. makes
18  * no representations about the suitability of this software for any
19  * purpose.  It is provided "as is" without express or implied
20  * warranty.
21  *
22  * Copyright 1993-1998 Lucent Technologies, Inc.
23  *
24  * Permission to use, copy, modify, and distribute this software and
25  * its documentation for any purpose and without fee is hereby
26  * granted, provided that the above copyright notice appear in all
27  * copies and that both that the copyright notice and warranty
28  * disclaimer appear in supporting documentation, and that the names
29  * of Lucent Technologies any of their entities not be used in
30  * advertising or publicity pertaining to distribution of the software
31  * without specific, written prior permission.
32  *
33  * Lucent Technologies disclaims all warranties with regard to this
34  * software, including all implied warranties of merchantability and
35  * fitness.  In no event shall Lucent Technologies be liable for any
36  * special, indirect or consequential damages or any damages
37  * whatsoever resulting from loss of use, data or profits, whether in
38  * an action of contract, negligence or other tortuous action, arising
39  * out of or in connection with the use or performance of this
40  * software.
41  *
42  * The "bitmap" command created by George Howlett.  */
43 
44 /*
45   Predefined table holds bitmap info (source width, height)
46   Name table holds bitmap names
47   Id table hold bitmap ids
48   Both id and name tables get you the actual bitmap.
49  */
50 #include "bltInt.h"
51 
52 #ifndef NO_BITMAP
53 #include "bltHash.h"
54 #include <X11/Xutil.h>
55 
56 #define BITMAP_THREAD_KEY	"BLT Bitmap Data"
57 
58 /*
59  * BitmapInterpData --
60  *
61  *	Tk's routine to create a bitmap, Tk_DefineBitmap, assumes that
62  *	the source (bit array) is always statically allocated.  This
63  *	isn't true here (we dynamically allocate the arrays), so we have
64  *	to save them in a hashtable and cleanup after the interpreter
65  *	is deleted.
66  */
67 typedef struct {
68     Blt_HashTable bitmapTable;	/* Hash table of bitmap data keyed by
69 				 * the name of the bitmap. */
70     Tcl_Interp *interp;
71     Display *display;		/* Display of interpreter. */
72     Tk_Window tkwin;		/* Main window of interpreter. */
73 } BitmapInterpData;
74 
75 #define MAX_SIZE 255
76 
77 /*
78  * BitmapInfo --
79  */
80 typedef struct {
81     double rotate;		/* Rotation of text string */
82     double scale;		/* Scaling factor */
83     Tk_Font font;		/* Font pointer */
84     Tk_Justify justify;		/* Justify text */
85     Blt_Pad padX, padY;		/* Padding around the text */
86 } BitmapInfo;
87 
88 /*
89  * BitmapData --
90  */
91 typedef struct {
92     int width, height;		/* Dimension of image */
93     unsigned char *bits;	/* Data array for bitmap image */
94     int arraySize;		/* Number of bytes in data array */
95 } BitmapData;
96 
97 #define DEF_BITMAP_FONT		STD_FONT
98 #define DEF_BITMAP_PAD		"4"
99 #define DEF_BITMAP_ROTATE	"0.0"
100 #define DEF_BITMAP_SCALE	"1.0"
101 #define DEF_BITMAP_JUSTIFY	"center"
102 
103 #define ROTATE_0	0
104 #define ROTATE_90	1
105 #define ROTATE_180	2
106 #define ROTATE_270	3
107 
108 
109 extern Tk_CustomOption bltPadOption;
110 
111 static Tk_ConfigSpec composeConfigSpecs[] =
112 {
113     {TK_CONFIG_FONT, "-font", (char *)NULL, (char *)NULL,
114 	DEF_BITMAP_FONT, Tk_Offset(BitmapInfo, font), 0},
115     {TK_CONFIG_JUSTIFY, "-justify", (char *)NULL, (char *)NULL,
116 	DEF_BITMAP_JUSTIFY, Tk_Offset(BitmapInfo, justify),
117 	TK_CONFIG_DONT_SET_DEFAULT},
118     {TK_CONFIG_CUSTOM, "-padx", (char *)NULL, (char *)NULL,
119 	DEF_BITMAP_PAD, Tk_Offset(BitmapInfo, padX),
120 	TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption},
121     {TK_CONFIG_CUSTOM, "-pady", (char *)NULL, (char *)NULL,
122 	DEF_BITMAP_PAD, Tk_Offset(BitmapInfo, padY),
123 	TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption},
124     {TK_CONFIG_DOUBLE, "-rotate", (char *)NULL, (char *)NULL,
125 	DEF_BITMAP_ROTATE, Tk_Offset(BitmapInfo, rotate),
126 	TK_CONFIG_DONT_SET_DEFAULT},
127     {TK_CONFIG_DOUBLE, "-scale", (char *)NULL, (char *)NULL,
128 	DEF_BITMAP_SCALE, Tk_Offset(BitmapInfo, scale),
129 	TK_CONFIG_DONT_SET_DEFAULT},
130     {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
131 	(char *)NULL, 0, 0}
132 };
133 
134 static Tk_ConfigSpec defineConfigSpecs[] =
135 {
136     {TK_CONFIG_DOUBLE, "-rotate", (char *)NULL, (char *)NULL,
137 	DEF_BITMAP_ROTATE, Tk_Offset(BitmapInfo, rotate),
138 	TK_CONFIG_DONT_SET_DEFAULT},
139     {TK_CONFIG_DOUBLE, "-scale", (char *)NULL, (char *)NULL,
140 	DEF_BITMAP_SCALE, Tk_Offset(BitmapInfo, scale),
141 	TK_CONFIG_DONT_SET_DEFAULT},
142     {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
143 	(char *)NULL, 0, 0}
144 };
145 
146 /* Shared data for the image read/parse logic */
147 static char hexTable[256];	/* conversion value */
148 static int initialized = 0;	/* easier to fill in at run time */
149 
150 #define blt_width 40
151 #define blt_height 40
152 static unsigned char blt_bits[] =
153 {
154     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x04,
155     0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0xe4, 0x33, 0x3f,
156     0x01, 0x00, 0x64, 0x36, 0x0c, 0x01, 0x00, 0x64, 0x36, 0x8c, 0x00, 0x00,
157     0xe4, 0x33, 0x8c, 0x00, 0x00, 0x64, 0x36, 0x8c, 0x00, 0x00, 0x64, 0x36,
158     0x0c, 0x01, 0x00, 0xe4, 0xf3, 0x0d, 0x01, 0x00, 0x04, 0x00, 0x00, 0x02,
159     0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c,
160     0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf8, 0xff,
161     0x03, 0x80, 0xed, 0x07, 0x00, 0x04, 0xe0, 0x0c, 0x00, 0x20, 0x09, 0x10,
162     0x0c, 0x00, 0x00, 0x12, 0x10, 0x0c, 0x00, 0x00, 0x10, 0x30, 0x00, 0x00,
163     0x00, 0x19, 0xd0, 0x03, 0x00, 0x00, 0x14, 0xb0, 0xfe, 0xff, 0xff, 0x1b,
164     0x50, 0x55, 0x55, 0x55, 0x0d, 0xe8, 0xaa, 0xaa, 0xaa, 0x16, 0xe4, 0xff,
165     0xff, 0xff, 0x2f, 0xf4, 0xff, 0xff, 0xff, 0x27, 0xd8, 0xae, 0xaa, 0xbd,
166     0x2d, 0x6c, 0x5f, 0xd5, 0x67, 0x1b, 0xbc, 0xf3, 0x7f, 0xd0, 0x36, 0xf8,
167     0x01, 0x10, 0xcc, 0x1f, 0xe0, 0x45, 0x8e, 0x92, 0x0f, 0xb0, 0x32, 0x41,
168     0x43, 0x0b, 0xd0, 0xcf, 0x3c, 0x7c, 0x0d, 0xb0, 0xaa, 0xc2, 0xab, 0x0a,
169     0x60, 0x55, 0x55, 0x55, 0x05, 0xc0, 0xff, 0xab, 0xaa, 0x03, 0x00, 0x00,
170     0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
171 };
172 
173 #define bigblt_width 64
174 #define bigblt_height 64
175 static unsigned char bigblt_bits[] =
176 {
177     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x3f, 0x00,
179     0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00,
180     0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00,
181     0x00, 0x00, 0xe2, 0x0f, 0xc7, 0xff, 0x10, 0x00, 0x00, 0x00, 0xe2, 0x1f,
182     0xc7, 0xff, 0x10, 0x00, 0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00,
183     0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x38,
184     0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x1f, 0x07, 0x1c, 0x04, 0x00,
185     0x00, 0x00, 0xe2, 0x1f, 0x07, 0x1c, 0x04, 0x00, 0x00, 0x00, 0xe2, 0x38,
186     0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00,
187     0x00, 0x00, 0xe2, 0x38, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x1f,
188     0xff, 0x1c, 0x10, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0xff, 0x1c, 0x10, 0x00,
189     0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00,
190     0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00,
191     0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x06, 0x00,
192     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
193     0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
194     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0xff, 0xff, 0x07, 0x00,
195     0x00, 0xe0, 0xf6, 0x3f, 0x00, 0x00, 0x38, 0x00, 0x00, 0x1c, 0x06, 0x00,
196     0x00, 0x00, 0xc0, 0x00, 0x80, 0x03, 0x06, 0x00, 0x00, 0xc0, 0x08, 0x03,
197     0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x06, 0x00,
198     0x00, 0x00, 0x40, 0x04, 0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04,
199     0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x00,
200     0x00, 0x00, 0x0c, 0x06, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
201     0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x06, 0x40, 0x55, 0xff, 0xff,
202     0xff, 0xff, 0x7f, 0x05, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06,
203     0x80, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0x40, 0xab, 0xaa, 0xaa,
204     0xaa, 0xaa, 0xaa, 0x01, 0x70, 0x57, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x04,
205     0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0b, 0xd8, 0xff, 0xff, 0xff,
206     0xff, 0xff, 0xff, 0x14, 0xd0, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13,
207     0xf0, 0xda, 0xbf, 0xaa, 0xba, 0xfd, 0xd6, 0x0b, 0x70, 0xed, 0x77, 0x55,
208     0x57, 0xe5, 0xad, 0x07, 0xb8, 0xf7, 0xab, 0xaa, 0xaa, 0xd2, 0x5b, 0x0f,
209     0xf8, 0xfb, 0x54, 0x55, 0x75, 0x94, 0xf7, 0x1e, 0xf0, 0x7b, 0xfa, 0xff,
210     0x9f, 0xa9, 0xef, 0x1f, 0xc0, 0xbf, 0x00, 0x20, 0x40, 0x54, 0xfe, 0x0f,
211     0x00, 0x1f, 0x92, 0x00, 0x04, 0xa9, 0xfc, 0x01, 0xc0, 0x5f, 0x41, 0xf9,
212     0x04, 0x21, 0xfd, 0x00, 0xc0, 0x9b, 0x28, 0x04, 0xd8, 0x0a, 0x9a, 0x03,
213     0x40, 0x5d, 0x08, 0x40, 0x44, 0x44, 0x62, 0x03, 0xc0, 0xaa, 0x67, 0xe2,
214     0x03, 0x64, 0xba, 0x02, 0x40, 0x55, 0xd5, 0x55, 0xfd, 0xdb, 0x55, 0x03,
215     0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x57, 0x55, 0x55,
216     0x55, 0x55, 0xd5, 0x00, 0x00, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00,
217     0x00, 0xf0, 0xff, 0x57, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, 0xf8,
218     0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
220 };
221 
222 static Tcl_CmdProc BitmapCmd;
223 static Tcl_InterpDeleteProc BitmapInterpDeleteProc;
224 
225 /*
226  * -----------------------------------------------------------------------
227  *
228  * GetHexValue --
229  *
230  *	Converts the hexadecimal string into an unsigned integer
231  *	value.  The hexadecimal string need not have a leading "0x".
232  *
233  * Results:
234  *	Returns a standard TCL result. If the conversion was
235  *	successful, TCL_OK is returned, otherwise TCL_ERROR.
236  *
237  * Side Effects:
238  * 	If the conversion fails, interp->result is filled with an
239  *	error message.
240  *
241  * -----------------------------------------------------------------------
242  */
243 static int
GetHexValue(interp,string,valuePtr)244 GetHexValue(interp, string, valuePtr)
245     Tcl_Interp *interp;
246     char *string;
247     int *valuePtr;
248 {
249     register int c;
250     register char *s;
251     register int value;
252 
253     s = string;
254     if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) {
255 	s += 2;
256     }
257     if (s[0] == '\0') {
258 	Tcl_AppendResult(interp, "expecting hex value: got \"", string, "\"",
259 	    (char *)NULL);
260 	return TCL_ERROR;	/* Only found "0x"  */
261     }
262     value = 0;
263     for ( /*empty*/ ; *s != '\0'; s++) {
264 	/* Trim high bits, check type and accumulate */
265 	c = *s & 0xff;
266 	if (!isxdigit(c)) {
267 	    Tcl_AppendResult(interp, "expecting hex value: got \"", string,
268 		"\"", (char *)NULL);
269 	    return TCL_ERROR;	/* Not a hexadecimal number */
270 	}
271 	value = (value << 4) + hexTable[c];
272     }
273     *valuePtr = value;
274     return TCL_OK;
275 }
276 
277 #ifdef WIN32
278 /*
279  * -----------------------------------------------------------------------
280  *
281  * BitmapToData --
282  *
283  *	Converts a bitmap into an data array.
284  *
285  * Results:
286  *	Returns the number of bytes in an data array representing the bitmap.
287  *
288  * Side Effects:
289  *	Memory is allocated for the data array. Caller must free
290  *	array later.
291  *
292  * -----------------------------------------------------------------------
293  */
294 static int
BitmapToData(Tk_Window tkwin,Pixmap bitmap,int width,int height,unsigned char ** bitsPtr)295 BitmapToData(
296     Tk_Window tkwin,		/* Main window of interpreter */
297     Pixmap bitmap,		/* Bitmap to be queried */
298     int width, int height,	/* Dimensions of the bitmap */
299     unsigned char **bitsPtr)	/* Pointer to converted array of data */
300 {
301     int value, bitMask;
302     unsigned long pixel;
303     register int x, y;
304     int count;
305     int arraySize, bytes_per_line;
306     unsigned char *bits;
307     unsigned char *srcPtr, *srcBits;
308     int bytesPerRow;
309 
310     *bitsPtr = NULL;
311     srcBits = Blt_GetBitmapData(Tk_Display(tkwin), bitmap, width, height,
312 	&bytesPerRow);
313     if (srcBits == NULL) {
314         OutputDebugString("BitmapToData: Can't get bitmap data");
315 	return 0;
316     }
317     bytes_per_line = (width + 7) / 8;
318     arraySize = height * bytes_per_line;
319     bits = Blt_Malloc(sizeof(unsigned char) * arraySize);
320     assert(bits);
321     count = 0;
322     for (y = height - 1; y >= 0; y--) {
323 	srcPtr = srcBits + (bytesPerRow * y);
324 	value = 0, bitMask = 1;
325 	for (x = 0; x < width; /* empty */ ) {
326 	    pixel = (*srcPtr & (0x80 >> (x % 8)));
327 	    if (pixel) {
328 		value |= bitMask;
329 	    }
330 	    bitMask <<= 1;
331 	    x++;
332 	    if (!(x & 7)) {
333 		bits[count++] = (unsigned char)value;
334 		value = 0, bitMask = 1;
335 		srcPtr++;
336 	    }
337 	}
338 	if (x & 7) {
339 	    bits[count++] = (unsigned char)value;
340 	}
341     }
342     *bitsPtr = bits;
343     return count;
344 }
345 
346 #else
347 
348 /*
349  * -----------------------------------------------------------------------
350  *
351  * BitmapToData --
352  *
353  *	Converts a bitmap into an data array.
354  *
355  * Results:
356  *	Returns the number of bytes in an data array representing the bitmap.
357  *
358  * Side Effects:
359  *	Memory is allocated for the data array. Caller must free
360  *	array later.
361  *
362  * -----------------------------------------------------------------------
363  */
364 static int
BitmapToData(tkwin,bitmap,width,height,bitsPtr)365 BitmapToData(tkwin, bitmap, width, height, bitsPtr)
366     Tk_Window tkwin;		/* Main window of interpreter */
367     Pixmap bitmap;		/* Bitmap to be queried */
368     int width, height;		/* Dimensions of the bitmap */
369     unsigned char **bitsPtr;	/* Pointer to converted array of data */
370 {
371     int value, bitMask;
372     unsigned long pixel;
373     register int x, y;
374     int count;
375     int arraySize, bytes_per_line;
376     Display *display;
377     XImage *imagePtr;
378     unsigned char *bits;
379 
380     display = Tk_Display(tkwin);
381     /* Convert the bitmap to an image */
382     imagePtr = XGetImage(display, bitmap, 0, 0, width, height, 1L, XYPixmap);
383     /*
384      * The slow but robust brute force method of converting an image:
385      */
386     bytes_per_line = (width + 7) / 8;
387     arraySize = height * bytes_per_line;
388     bits = Blt_Malloc(sizeof(unsigned char) * arraySize);
389     assert(bits);
390     count = 0;
391     for (y = 0; y < height; y++) {
392 	value = 0, bitMask = 1;
393 	for (x = 0; x < width; /*empty*/ ) {
394 	    pixel = XGetPixel(imagePtr, x, y);
395 	    if (pixel) {
396 		value |= bitMask;
397 	    }
398 	    bitMask <<= 1;
399 	    x++;
400 	    if (!(x & 7)) {
401 		bits[count++] = (unsigned char)value;
402 		value = 0, bitMask = 1;
403 	    }
404 	}
405 	if (x & 7) {
406 	    bits[count++] = (unsigned char)value;
407 	}
408     }
409     XDestroyImage(imagePtr);
410     *bitsPtr = bits;
411     return count;
412 }
413 
414 #endif
415 
416 /*
417  * -----------------------------------------------------------------------
418  *
419  * AsciiToData --
420  *
421  *	Converts a Tcl list of ASCII values into a data array.
422  *
423  * Results:
424  *	A standard TCL result.
425  *
426  * Side Effects:
427  * 	If an error occurs while processing the data, interp->result
428  * 	is filled with a corresponding error message.
429  *
430  * -----------------------------------------------------------------------
431  */
432 static int
AsciiToData(interp,elemList,width,height,bitsPtr)433 AsciiToData(interp, elemList, width, height, bitsPtr)
434     Tcl_Interp *interp;		/* Interpreter to report results to */
435     char *elemList;		/* List of of hex numbers representing
436 				 * bitmap data */
437     int width, height;		/* Height and width */
438     unsigned char **bitsPtr;	/* data array (output) */
439 {
440     int arraySize;		/* Number of bytes of data */
441     int value;			/* from an input line */
442     int padding;		/* to handle alignment */
443     int bytesPerLine;		/* per scanline of data */
444     unsigned char *bits;
445     register int count;
446     enum Formats {
447 	V10, V11
448     } format;
449     register int i;		/*  */
450     char **valueArr;
451     int nValues;
452 
453     /* First time through initialize the ascii->hex translation table */
454     if (!initialized) {
455 	Blt_InitHexTable(hexTable);
456 	initialized = 1;
457     }
458     if (Tcl_SplitList(interp, elemList, &nValues, &valueArr) != TCL_OK) {
459 	return -1;
460     }
461     bytesPerLine = (width + 7) / 8;
462     arraySize = bytesPerLine * height;
463     if (nValues == arraySize) {
464 	format = V11;
465     } else if (nValues == (arraySize / 2)) {
466 	format = V10;
467     } else {
468 	Tcl_AppendResult(interp, "bitmap has wrong # of data values",
469 	    (char *)NULL);
470 	goto error;
471     }
472     padding = 0;
473     if (format == V10) {
474 	padding = ((width % 16) && ((width % 16) < 9));
475 	if (padding) {
476 	    bytesPerLine = (width + 7) / 8 + padding;
477 	    arraySize = bytesPerLine * height;
478 	}
479     }
480     bits = Blt_Calloc(sizeof(unsigned char), arraySize);
481     if (bits == NULL) {
482 	Tcl_AppendResult(interp, "can't allocate memory for bitmap",
483 	    (char *)NULL);
484 	goto error;
485     }
486     count = 0;
487     for (i = 0; i < nValues; i++) {
488 	if (GetHexValue(interp, valueArr[i], &value) != TCL_OK) {
489 	    Blt_Free(bits);
490 	    goto error;
491 	}
492 	bits[count++] = (unsigned char)value;
493 	if (format == V10) {
494 	    if ((!padding) || (((i * 2) + 2) % bytesPerLine)) {
495 		bits[count++] = value >> 8;
496 	    }
497 	}
498     }
499     Blt_Free(valueArr);
500     *bitsPtr = bits;
501     return count;
502   error:
503     Blt_Free(valueArr);
504     return -1;
505 }
506 
507 
508 static int
ParseListData(interp,string,widthPtr,heightPtr,bitsPtr)509 ParseListData(interp, string, widthPtr, heightPtr, bitsPtr)
510     Tcl_Interp *interp;
511     char *string;
512     int *widthPtr;
513     int *heightPtr;
514     unsigned char **bitsPtr;
515 {
516     register char *p;
517     char **elemArr;
518     int nElem;
519     int width, height;
520     int result;
521     int arraySize;
522 
523     arraySize = -1;
524     if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) {
525 	return -1;
526     }
527     if (nElem == 2) {
528 	char **dimArr;
529 	int nDim;
530 
531 	if (Tcl_SplitList(interp, elemArr[0], &nDim, &dimArr) != TCL_OK) {
532 	    goto error;
533 	}
534 	if (nDim != 2) {
535 	    Tcl_AppendResult(interp, "wrong # of bitmap dimensions: ",
536 			     "should be \"width height\"", (char *)NULL);
537 	    result = TCL_ERROR;
538 	} else {
539 	    result = ((Tcl_GetInt(interp, dimArr[0], &width) == TCL_OK) &&
540 		      (Tcl_GetInt(interp, dimArr[1], &height) == TCL_OK));
541 	}
542 	Blt_Free(dimArr);
543 	if (!result) {
544 	    goto error;
545 	}
546 	string = elemArr[1];
547     } else if (nElem == 3) {
548 	if ((Tcl_GetInt(interp, elemArr[0], &width) != TCL_OK) ||
549 	    (Tcl_GetInt(interp, elemArr[1], &height) != TCL_OK)) {
550 	    goto error;
551 	}
552 	string = elemArr[2];
553     } else {
554 	Tcl_AppendResult(interp, "wrong # of bitmap data components: ",
555 			 "should be \"dimensions sourceData\"", (char *)NULL);
556 	goto error;
557     }
558     if ((width < 1) || (height < 1)) {
559 	Tcl_AppendResult(interp, "bad bitmap dimensions", (char *)NULL);
560 	goto error;
561     }
562     /* Convert commas to blank spaces */
563 
564     for (p = string; *p != '\0'; p++) {
565 	if (*p == ',') {
566 	    *p = ' ';
567 	}
568     }
569     arraySize = AsciiToData(interp, string, width, height, bitsPtr);
570     *widthPtr = width;
571     *heightPtr = height;
572  error:
573     Blt_Free(elemArr);
574     return arraySize;
575 }
576 
577 /*
578  * Parse the lines that define the dimensions of the bitmap,
579  * plus the first line that defines the bitmap data (it declares
580  * the name of a data variable but doesn't include any actual
581  * data).  These lines look something like the following:
582  *
583  *		#define foo_width 16
584  *		#define foo_height 16
585  *		#define foo_x_hot 3
586  *		#define foo_y_hot 3
587  *		static char foo_bits[] = {
588  *
589  * The x_hot and y_hot lines may or may not be present.  It's
590  * important to check for "char" in the last line, in order to
591  * reject old X10-style bitmaps that used shorts.
592  */
593 
594 static int
ParseStructData(interp,string,widthPtr,heightPtr,bitsPtr)595 ParseStructData(interp, string, widthPtr, heightPtr, bitsPtr)
596     Tcl_Interp *interp;
597     char *string;
598     int *widthPtr;
599     int *heightPtr;
600     unsigned char **bitsPtr;
601 {
602     int width, height;
603     int hotX, hotY;
604     char *line, *nextline;
605     register char *p;
606     Tcl_RegExp re;
607     char *name, *value, *data;
608     int len;
609     int arraySize;
610 
611     width = height = 0;
612     hotX = hotY = -1;
613     data = NULL;
614     nextline = string;
615     for (line = string; nextline != NULL; line = nextline + 1) {
616 	nextline = strchr(line, '\n');
617 	if ((nextline == NULL) || (line == nextline)) {
618 	    continue;		/* Empty line */
619 	}
620 	*nextline = '\0';
621 	re = Tcl_RegExpCompile(interp, " *# *define +");
622 	if (Tcl_RegExpExec(interp, re, line, line)) {
623 	    char *start, *end;
624 
625 	    Tcl_RegExpRange(re, 0, &start, &end);
626 	    name = strtok(end, " \t");
627 	    value = strtok(NULL, " \t");
628 	    if ((name == NULL) || (value == NULL)) {
629 		return TCL_ERROR;
630 	    }
631 	    len = strlen(name);
632 	    if ((len >= 6) && (name[len-6] == '_') &&
633 		(strcmp(name+len-6, "_width") == 0)) {
634 		if (Tcl_GetInt(interp, value, &width) != TCL_OK) {
635 		    return -1;
636 		}
637 	    } else if ((len >= 7) && (name[len-7] == '_') &&
638 		       (strcmp(name+len-7, "_height") == 0)) {
639 		if (Tcl_GetInt(interp, value, &height) != TCL_OK) {
640 		    return -1;
641 		}
642 	    } else if ((len >= 6) && (name[len-6] == '_') &&
643 		       (strcmp(name+len-6, "_x_hot") == 0)) {
644 		if (Tcl_GetInt(interp, value, &hotX) != TCL_OK) {
645 		    return -1;
646 		}
647 	    } else if ((len >= 6) && (name[len-6] == '_') &&
648 		       (strcmp(name+len-6, "_y_hot") == 0)) {
649 		if (Tcl_GetInt(interp, value, &hotY) != TCL_OK) {
650 		    return -1;
651 		}
652 	    }
653 	} else {
654 	    re = Tcl_RegExpCompile(interp, " *static +.*char +");
655 	    if (Tcl_RegExpExec(interp, re, line, line)) {
656 		/* Find the { */
657 	        /* Repair the string so we can search the entire string. */
658  	        *nextline = ' ';
659 		p = strchr(line, '{');
660 		if (p == NULL) {
661 		    return -1;
662 		}
663 		data = p + 1;
664 		break;
665 	    } else {
666 		Tcl_AppendResult(interp, "unknown bitmap format: ",
667 		 "obsolete X10 bitmap file?", (char *) NULL);
668 		return -1;
669 	    }
670 	}
671     }
672     /*
673      * Now we've read everything but the data.  Allocate an array
674      * and read in the data.
675      */
676     if ((width <= 0) || (height <= 0)) {
677 	Tcl_AppendResult(interp, "invalid bitmap dimensions \"", (char *)NULL);
678 	Tcl_AppendResult(interp, Blt_Itoa(width), " x ", (char *)NULL);
679 	Tcl_AppendResult(interp, Blt_Itoa(height), "\"", (char *)NULL);
680 	return -1;
681     }
682     *widthPtr = width;
683     *heightPtr = height;
684     for (p = data; *p != '\0'; p++) {
685 	if ((*p == ',') || (*p == ';') || (*p == '}')) {
686 	    *p = ' ';
687 	}
688     }
689     arraySize = AsciiToData(interp, data, width, height, bitsPtr);
690     return arraySize;
691 }
692 
693 /*
694  * -----------------------------------------------------------------------
695  *
696  * ScaleRotateData --
697  *
698  *	Creates a new data array of the rotated and scaled bitmap.
699  *
700  * Results:
701  *	A standard Tcl result. If the bitmap data is rotated
702  *	successfully, TCL_OK is returned.  But if memory could not be
703  *	allocated for the new data array, TCL_ERROR is returned and an
704  *	error message is left in interp->result.
705  *
706  * Side Effects:
707  *	Memory is allocated for rotated, scaled data array. Caller
708  *	must free array later.
709  *
710  * -----------------------------------------------------------------------
711  */
712 static int
ScaleRotateData(Tcl_Interp * interp,BitmapData * srcPtr,double theta,double scale,BitmapData * destPtr)713 ScaleRotateData(
714     Tcl_Interp *interp,		/* Interpreter to report results to */
715     BitmapData *srcPtr,		/* Source bitmap to transform. */
716     double theta,		/* Number of degrees to rotate the bitmap. */
717     double scale,		/* Factor to scale the bitmap. */
718     BitmapData *destPtr)	/* Destination bitmap. */
719 {
720     register int x, y, sx, sy;
721     double srcX, srcY, destX, destY;	/* Origins of source and destination
722 					 * bitmaps */
723     double dx, dy;
724     double sinTheta, cosTheta;
725     double rotWidth, rotHeight;
726     double radians;
727     unsigned char *bits;
728     int arraySize;
729     int pixel, ipixel;
730     int srcBytesPerLine, destBytesPerLine;
731 
732     srcBytesPerLine = (srcPtr->width + 7) / 8;
733     Blt_GetBoundingBox(srcPtr->width, srcPtr->height, theta, &rotWidth,
734 	&rotHeight, (Point2D *)NULL);
735     destPtr->width = (int)(rotWidth * scale + 0.5) ;
736     destPtr->height = (int)(rotHeight * scale + 0.5);
737 
738     destBytesPerLine = (destPtr->width + 7) / 8;
739     arraySize = destPtr->height * destBytesPerLine;
740     bits = Blt_Calloc(arraySize, sizeof(unsigned char));
741     if (bits == NULL) {
742 	Tcl_AppendResult(interp, "can't allocate bitmap data array",
743 	    (char *)NULL);
744 	return TCL_ERROR;
745     }
746     scale = 1.0 / scale;
747     destPtr->bits = bits;
748     destPtr->arraySize = arraySize;
749 
750     radians = (theta / 180.0) * M_PI;
751     sinTheta = sin(radians);
752     cosTheta = cos(radians);
753 
754     /*
755      * Coordinates of the centers of the source and destination rectangles
756      */
757     srcX = srcPtr->width * 0.5;
758     srcY = srcPtr->height * 0.5;
759     destX = rotWidth * 0.5;
760     destY = rotHeight * 0.5;
761 
762     /*
763      * Rotate each pixel of dest image, placing results in source image
764      */
765     for (y = 0; y < destPtr->height; y++) {
766 	for (x = 0; x < destPtr->width; x++) {
767 	    dx = scale * (double)x;
768 	    dy = scale * (double)y;
769 	    if (theta == 270.0) {
770 		sx = (int)dy, sy = (int)(rotWidth - dx) - 1;
771 	    } else if (theta == 180.0) {
772 		sx = (int)(rotWidth - dx) - 1, sy = (int)(rotHeight - dy) - 1;
773 	    } else if (theta == 90.0) {
774 		sx = (int)(rotHeight - dy) - 1, sy = (int)dx;
775 	    } else if (theta == 0.0) {
776 		sx = (int)dx, sy = (int)dy;
777 	    } else {
778 		double transX, transY, rotX, rotY;
779 		/* Translate origin to center of destination image */
780 
781 		transX = dx - destX;
782 		transY = dy - destY;
783 
784 		/* Rotate the coordinates about the origin */
785 
786 		rotX = (transX * cosTheta) - (transY * sinTheta);
787 		rotY = (transX * sinTheta) + (transY * cosTheta);
788 
789 		/* Translate back to the center of the source image */
790 		rotX += srcX;
791 		rotY += srcY;
792 
793 		sx = ROUND(rotX);
794 		sy = ROUND(rotY);
795 
796 		/*
797 		 * Verify the coordinates, since the destination image
798 		 * can be bigger than the source.
799 		 */
800 
801 		if ((sx >= srcPtr->width) || (sx < 0) ||
802 		    (sy >= srcPtr->height) || (sy < 0)) {
803 		    continue;
804 		}
805 	    }
806 	    ipixel = (srcBytesPerLine * sy) + (sx / 8);
807 	    pixel = srcPtr->bits[ipixel] & (1 << (sx % 8));
808 	    if (pixel) {
809 		ipixel = (destBytesPerLine * y) + (x / 8);
810 		bits[ipixel] |= (1 << (x % 8));
811 	    }
812 	}
813     }
814     return TCL_OK;
815 }
816 
817 /*
818  * -----------------------------------------------------------------------
819  *
820  * BitmapDataToString --
821  *
822  *	Returns a list of hex values corresponding to the data
823  *	bits of the bitmap given.
824  *
825  *	Converts the unsigned character value into a two character
826  *	hexadecimal string.  A separator is also added, which may
827  *	either a newline or space according the the number of bytes
828  *	already output.
829  *
830  * Results:
831  *	Returns TCL_ERROR if a data array can't be generated
832  *	from the bitmap (memory allocation failure), otherwise TCL_OK.
833  *
834  * -----------------------------------------------------------------------
835  */
836 static void
BitmapDataToString(tkwin,bitmap,resultPtr)837 BitmapDataToString(tkwin, bitmap, resultPtr)
838     Tk_Window tkwin;		/* Main window of interpreter */
839     Pixmap bitmap;		/* Bitmap to be queried */
840     Tcl_DString *resultPtr;	/* Dynamic string to output results to */
841 {
842     unsigned char *bits;
843     char *separator;
844     int arraySize;
845     register int i;
846     char string[200];
847     int width, height;
848 
849     /* Get the dimensions of the bitmap */
850     Tk_SizeOfBitmap(Tk_Display(tkwin), bitmap, &width, &height);
851     arraySize = BitmapToData(tkwin, bitmap, width, height, &bits);
852 #define BYTES_PER_OUTPUT_LINE 24
853     for (i = 0; i < arraySize; i++) {
854 	separator = (i % BYTES_PER_OUTPUT_LINE) ? " " : "\n    ";
855 	sprintf(string, "%s%02x", separator, bits[i]);
856 	Tcl_DStringAppend(resultPtr, string, -1);
857     }
858     if (bits != NULL) {
859         Blt_Free(bits);
860     }
861 }
862 
863 /*
864  *--------------------------------------------------------------
865  *
866  * ComposeOp --
867  *
868  *	Converts the text string into an internal bitmap.
869  *
870  *	There's a lot of extra (read unnecessary) work going on here,
871  *	but I don't (right now) think that it matters much.  The
872  *	rotated bitmap (formerly an image) is converted back to an
873  *	image just so we can convert it to a data array for
874  *	Tk_DefineBitmap.
875  *
876  * Results:
877  *	A standard TCL result.
878  *
879  * Side Effects:
880  * 	If an error occurs while processing the data, interp->result
881  * 	is filled with a corresponding error message.
882  *
883  *--------------------------------------------------------------
884  */
885 static int
ComposeOp(clientData,interp,argc,argv)886 ComposeOp(clientData, interp, argc, argv)
887     ClientData clientData;	/* Thread-specific data for bitmaps. */
888     Tcl_Interp *interp;		/* Interpreter to report results to */
889     int argc;			/* Number of arguments */
890     char **argv;		/* Argument list */
891 {
892     BitmapInterpData *dataPtr = clientData;
893     int width, height;		/* Dimensions of bitmap */
894     Pixmap bitmap;		/* Text bitmap */
895     unsigned char *bits;	/* Data array derived from text bitmap */
896     int arraySize;
897     BitmapInfo info;		/* Text rotation and font information */
898     int result;
899     double theta;
900     TextStyle ts;
901     TextLayout *textPtr;
902     Tk_Window tkwin;		/* Main window of interpreter */
903     Blt_HashEntry *hPtr;
904     int isNew;
905 
906     tkwin = dataPtr->tkwin;
907     bitmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[2]));
908     Tcl_ResetResult(interp);
909     if (bitmap != None) {
910 	Tk_FreeBitmap(dataPtr->display, bitmap);
911 	return TCL_OK;
912     }
913     /* Initialize info and process flags */
914     info.justify = TK_JUSTIFY_CENTER;
915     info.rotate = 0.0;		/* No rotation or scaling by default */
916     info.scale = 1.0;
917     info.padLeft = info.padRight = 0;
918     info.padTop = info.padBottom = 0;
919     info.font = (Tk_Font)NULL;	/* Initialized by Tk_ConfigureWidget */
920     if (Tk_ConfigureWidget(interp, tkwin, composeConfigSpecs,
921 	    argc - 4, argv + 4, (char *)&info, 0) != TCL_OK) {
922 	return TCL_ERROR;
923     }
924     theta = FMOD(info.rotate, (double)360.0);
925     if (theta < 0.0) {
926 	theta += 360.0;
927     }
928     Blt_InitTextStyle(&ts);
929     ts.font = info.font;
930     ts.theta = 0.0;
931     ts.justify = info.justify;
932     ts.padX = info.padX;
933     ts.padY = info.padY;
934     ts.leader = 0;
935     ts.anchor = TK_ANCHOR_CENTER;
936 
937     textPtr = Blt_GetTextLayout(argv[3], &ts);
938     bitmap = Blt_CreateTextBitmap(tkwin, textPtr, &ts, &width, &height);
939     Blt_Free(textPtr);
940     if (bitmap == None) {
941 	Tcl_AppendResult(interp, "can't create bitmap", (char *)NULL);
942 	return TCL_ERROR;
943     }
944     /* Free the font structure, since we don't need it anymore */
945     Tk_FreeOptions(composeConfigSpecs, (char *)&info, dataPtr->display, 0);
946 
947     /* Convert bitmap back to a data array */
948     arraySize = BitmapToData(tkwin, bitmap, width, height, &bits);
949     Tk_FreePixmap(dataPtr->display, bitmap);
950     if (arraySize == 0) {
951 	Tcl_AppendResult(interp, "can't get bitmap data", (char *)NULL);
952 	return TCL_ERROR;
953     }
954     /* If bitmap is to be rotated or scale, do it here */
955     if ((theta != 0.0) || (info.scale != 1.0)) {
956 	BitmapData srcData, destData;
957 
958 	srcData.bits = bits;
959 	srcData.width = width;
960 	srcData.height = height;
961 	srcData.arraySize = arraySize;
962 
963 	result = ScaleRotateData(interp, &srcData, theta, info.scale,
964 		 &destData);
965 	Blt_Free(bits);		/* Free the un-transformed data array. */
966 	if (result != TCL_OK) {
967 	    return TCL_ERROR;
968 	}
969 	bits = destData.bits;
970 	width = destData.width;
971 	height = destData.height;
972     }
973     /* Create the bitmap again, this time using Tk's bitmap facilities */
974     result = Tk_DefineBitmap(interp, Tk_GetUid(argv[2]), (char *)bits,
975 	width, height);
976     if (result != TCL_OK) {
977 	Blt_Free(bits);
978     }
979     hPtr = Blt_CreateHashEntry(&(dataPtr->bitmapTable), argv[2], &isNew);
980     Blt_SetHashValue(hPtr, bits);
981     return result;
982 }
983 
984 /*
985  *--------------------------------------------------------------
986  *
987  * DefineOp --
988  *
989  *	Converts the dataList into an internal bitmap.
990  *
991  * Results:
992  *	A standard TCL result.
993  *
994  * Side Effects:
995  * 	If an error occurs while processing the data, interp->result
996  *	is filled with a corresponding error message.
997  *
998  *--------------------------------------------------------------
999  */
1000 /* ARGSUSED */
1001 static int
DefineOp(clientData,interp,argc,argv)1002 DefineOp(clientData, interp, argc, argv)
1003     ClientData clientData;	/* Thread-specific data for bitmaps. */
1004     Tcl_Interp *interp;		/* Interpreter to report results to */
1005     int argc;			/* Number of arguments */
1006     char **argv;		/* Argument list */
1007 {
1008     BitmapInterpData *dataPtr = clientData;
1009     int width, height;		/* Dimensions of bitmap */
1010     unsigned char *bits;	/* working variable */
1011     register char *p;
1012     char *defn;			/* Definition of bitmap. */
1013     BitmapInfo info;		/* Not used. */
1014     int arraySize;
1015     int result;
1016     double theta;
1017     Pixmap bitmap;
1018     Blt_HashEntry *hPtr;
1019     int isNew;
1020 
1021     bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2]));
1022     Tcl_ResetResult(interp);
1023     if (bitmap != None) {
1024 	Tk_FreeBitmap(dataPtr->display, bitmap);
1025 	return TCL_OK;
1026     }
1027     /* Initialize info and then process flags */
1028     info.rotate = 0.0;		/* No rotation by default */
1029     info.scale = 1.0;		/* No scaling by default */
1030     if (Tk_ConfigureWidget(interp, dataPtr->tkwin, defineConfigSpecs,
1031 	    argc - 4, argv + 4, (char *)&info, 0) != TCL_OK) {
1032 	return TCL_ERROR;
1033     }
1034     /* Skip leading spaces. */
1035     for (p = argv[3]; isspace(UCHAR(*p)); p++) {
1036 	/*empty*/
1037     }
1038     defn = Blt_Strdup(p);
1039     bits = NULL;
1040     if (*p == '#') {
1041 	arraySize = ParseStructData(interp, defn, &width, &height, &bits);
1042     } else {
1043 	arraySize = ParseListData(interp, defn, &width, &height, &bits);
1044     }
1045     Blt_Free(defn);
1046     if (arraySize <= 0) {
1047 	return TCL_ERROR;
1048     }
1049     theta = FMOD(info.rotate, 360.0);
1050     if (theta < 0.0) {
1051 	theta += 360.0;
1052     }
1053     /* If bitmap is to be rotated or scale, do it here */
1054     if ((theta != 0.0) || (info.scale != 1.0)) {
1055 	BitmapData srcData, destData;
1056 
1057 	srcData.bits = bits;
1058 	srcData.width = width;
1059 	srcData.height = height;
1060 	srcData.arraySize = arraySize;
1061 
1062 	result = ScaleRotateData(interp, &srcData, theta, info.scale,
1063 		 &destData);
1064 	Blt_Free(bits);		/* Free the array of un-transformed data. */
1065 	if (result != TCL_OK) {
1066 	    return TCL_ERROR;
1067 	}
1068 	bits = destData.bits;
1069 	width = destData.width;
1070 	height = destData.height;
1071     }
1072     result = Tk_DefineBitmap(interp, Tk_GetUid(argv[2]), (char *)bits,
1073 	width, height);
1074     if (result != TCL_OK) {
1075 	Blt_Free(bits);
1076     }
1077     hPtr = Blt_CreateHashEntry(&(dataPtr->bitmapTable), argv[2], &isNew);
1078     Blt_SetHashValue(hPtr, bits);
1079     return result;
1080 }
1081 
1082 /*
1083  *--------------------------------------------------------------
1084  *
1085  * ExistOp --
1086  *
1087  *	Indicates if the named bitmap exists.
1088  *
1089  *--------------------------------------------------------------
1090  */
1091 /*ARGSUSED*/
1092 static int
ExistsOp(clientData,interp,argc,argv)1093 ExistsOp(clientData, interp, argc, argv)
1094     ClientData clientData;	/* Thread-specific data for bitmaps. */
1095     Tcl_Interp *interp;		/* Interpreter to report results to */
1096     int argc;			/* Not used. */
1097     char **argv;		/* Argument list */
1098 {
1099     BitmapInterpData *dataPtr = clientData;
1100     Pixmap bitmap;
1101 
1102     bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2]));
1103     Tcl_ResetResult(interp);
1104     if (bitmap != None) {
1105 	Tk_FreeBitmap(dataPtr->display, bitmap);
1106     }
1107     Blt_SetBooleanResult(interp, (bitmap != None));
1108     return TCL_OK;
1109 }
1110 
1111 /*
1112  *--------------------------------------------------------------
1113  *
1114  * HeightOp --
1115  *
1116  *	Returns the height of the named bitmap.
1117  *
1118  *--------------------------------------------------------------
1119  */
1120 /*ARGSUSED*/
1121 static int
HeightOp(clientData,interp,argc,argv)1122 HeightOp(clientData, interp, argc, argv)
1123     ClientData clientData;	/* Thread-specific data for bitmaps. */
1124     Tcl_Interp *interp;		/* Interpreter to report results to */
1125     int argc;			/* Not used. */
1126     char **argv;		/* Argument list */
1127 {
1128     BitmapInterpData *dataPtr = clientData;
1129     int width, height;
1130     Pixmap bitmap;
1131 
1132     bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2]));
1133     if (bitmap == None) {
1134 	return TCL_ERROR;
1135     }
1136     Tk_SizeOfBitmap(dataPtr->display, bitmap, &width, &height);
1137     Tcl_SetResult(interp, Blt_Itoa(height), TCL_VOLATILE);
1138     Tk_FreeBitmap(dataPtr->display, bitmap);
1139     return TCL_OK;
1140 }
1141 
1142 /*
1143  *--------------------------------------------------------------
1144  *
1145  * WidthOp --
1146  *
1147  *	Returns the width of the named bitmap.
1148  *
1149  *--------------------------------------------------------------
1150  */
1151 /*ARGSUSED*/
1152 static int
WidthOp(clientData,interp,argc,argv)1153 WidthOp(clientData, interp, argc, argv)
1154     ClientData clientData;	/* Thread-specific data for bitmaps. */
1155     Tcl_Interp *interp;		/* Interpreter to report results to */
1156     int argc;			/* Not used. */
1157     char **argv;		/* Argument list */
1158 {
1159     BitmapInterpData *dataPtr = clientData;
1160     int width, height;
1161     Pixmap bitmap;
1162 
1163     bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2]));
1164     if (bitmap == None) {
1165 	return TCL_ERROR;
1166     }
1167     Tk_SizeOfBitmap(dataPtr->display, bitmap, &width, &height);
1168     Tcl_SetResult(interp, Blt_Itoa(width), TCL_VOLATILE);
1169     Tk_FreeBitmap(dataPtr->display, bitmap);
1170     return TCL_OK;
1171 }
1172 
1173 /*
1174  *--------------------------------------------------------------
1175  *
1176  * SourceOp --
1177  *
1178  *	Returns the data array (excluding width and height)
1179  *	of the named bitmap.
1180  *
1181  *--------------------------------------------------------------
1182  */
1183 /*ARGSUSED*/
1184 static int
SourceOp(clientData,interp,argc,argv)1185 SourceOp(clientData, interp, argc, argv)
1186     ClientData clientData;	/* Thread-specific data for bitmaps. */
1187     Tcl_Interp *interp;		/* Interpreter to report results to */
1188     int argc;			/* Not used. */
1189     char **argv;		/* Argument list */
1190 {
1191     BitmapInterpData *dataPtr = clientData;
1192     Pixmap bitmap;
1193     Tcl_DString dString;
1194 
1195     bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2]));
1196     if (bitmap == None) {
1197 	return TCL_ERROR;
1198     }
1199     Tcl_DStringInit(&dString);
1200     BitmapDataToString(dataPtr->tkwin, bitmap, &dString);
1201     Tk_FreeBitmap(dataPtr->display, bitmap);
1202     Tcl_DStringResult(interp, &dString);
1203     return TCL_OK;
1204 }
1205 
1206 /*
1207  *--------------------------------------------------------------
1208  *
1209  * DataOp --
1210  *
1211  *	Returns the data array, including width and height,
1212  *	of the named bitmap.
1213  *
1214  *--------------------------------------------------------------
1215  */
1216 /*ARGSUSED*/
1217 static int
DataOp(clientData,interp,argc,argv)1218 DataOp(clientData, interp, argc, argv)
1219     ClientData clientData;	/* Thread-specific data for bitmaps. */
1220     Tcl_Interp *interp;		/* Interpreter to report results to */
1221     int argc;			/* Not used. */
1222     char **argv;		/* Argument list */
1223 {
1224     BitmapInterpData *dataPtr = clientData;
1225     Pixmap bitmap;
1226     int width, height;
1227     Tcl_DString dString;
1228 
1229     bitmap = Tk_GetBitmap(interp, dataPtr->tkwin, Tk_GetUid(argv[2]));
1230     if (bitmap == None) {
1231 	return TCL_ERROR;
1232     }
1233     Tk_SizeOfBitmap(dataPtr->display, bitmap, &width, &height);
1234     Tcl_DStringInit(&dString);
1235     Tcl_DStringAppendElement(&dString, Blt_Itoa(width));
1236     Tcl_DStringAppendElement(&dString, Blt_Itoa(height));
1237     Tcl_DStringStartSublist(&dString);
1238     BitmapDataToString(dataPtr->tkwin, bitmap, &dString);
1239     Tcl_DStringEndSublist(&dString);
1240     Tk_FreeBitmap(dataPtr->display, bitmap);
1241     Tcl_DStringResult(interp, &dString);
1242     return TCL_OK;
1243 }
1244 
1245 /*
1246  *--------------------------------------------------------------
1247  *
1248  * BLT Sub-command specification:
1249  *
1250  *	- Name of the sub-command.
1251  *	- Minimum number of characters needed to unambiguously
1252  *        recognize the sub-command.
1253  *	- Pointer to the function to be called for the sub-command.
1254  *	- Minimum number of arguments accepted.
1255  *	- Maximum number of arguments accepted.
1256  *	- String to be displayed for usage.
1257  *
1258  *--------------------------------------------------------------
1259  */
1260 static Blt_OpSpec bitmapOps[] =
1261 {
1262     {"compose", 1, (Blt_Op)ComposeOp, 4, 0, "bitmapName text ?flags?",},
1263     {"data", 2, (Blt_Op)DataOp, 3, 3, "bitmapName",},
1264     {"define", 2, (Blt_Op)DefineOp, 4, 0, "bitmapName data ?flags?",},
1265     {"exists", 1, (Blt_Op)ExistsOp, 3, 3, "bitmapName",},
1266     {"height", 1, (Blt_Op)HeightOp, 3, 3, "bitmapName",},
1267     {"source", 1, (Blt_Op)SourceOp, 3, 3, "bitmapName",},
1268     {"width", 1, (Blt_Op)WidthOp, 3, 3, "bitmapName",},
1269 };
1270 static int nBitmapOps = sizeof(bitmapOps) / sizeof(Blt_OpSpec);
1271 
1272 /*
1273  *--------------------------------------------------------------
1274  *
1275  * BitmapCmd --
1276  *
1277  *	This procedure is invoked to process the Tcl command
1278  *	that corresponds to bitmaps managed by this module.
1279  *	See the user documentation for details on what it does.
1280  *
1281  * Results:
1282  *	A standard Tcl result.
1283  *
1284  * Side effects:
1285  *	See the user documentation.
1286  *
1287  *--------------------------------------------------------------
1288  */
1289 /*ARGSUSED*/
1290 static int
BitmapCmd(clientData,interp,argc,argv)1291 BitmapCmd(clientData, interp, argc, argv)
1292     ClientData clientData;	/* Thread-specific data for bitmaps. */
1293     Tcl_Interp *interp;		/* Interpreter to report results to */
1294     int argc;
1295     char **argv;
1296 {
1297     Blt_Op proc;
1298     int result;
1299 
1300     proc = Blt_GetOp(interp, nBitmapOps, bitmapOps, BLT_OP_ARG1, argc, argv,0);
1301     if (proc == NULL) {
1302 	return TCL_ERROR;
1303     }
1304     result = (*proc) (clientData, interp, argc, argv);
1305     return result;
1306 }
1307 
1308 /*
1309  * -----------------------------------------------------------------------
1310  *
1311  * BitmapInterpDeleteProc --
1312  *
1313  *	This is called when the interpreter is deleted. All the tiles
1314  *	are specific to that interpreter are destroyed.
1315  *
1316  * Results:
1317  *	None.
1318  *
1319  * Side effects:
1320  *	Destroys the tile table.
1321  *
1322  * ------------------------------------------------------------------------
1323  */
1324 /* ARGSUSED */
1325 static void
BitmapInterpDeleteProc(clientData,interp)1326 BitmapInterpDeleteProc(clientData, interp)
1327     ClientData clientData;	/* Thread-specific data. */
1328     Tcl_Interp *interp;
1329 {
1330     BitmapInterpData *dataPtr = clientData;
1331     Blt_HashEntry *hPtr;
1332     unsigned char *bits;
1333     Blt_HashSearch cursor;
1334 
1335     for (hPtr = Blt_FirstHashEntry(&(dataPtr->bitmapTable), &cursor);
1336 	 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1337 	bits = (unsigned char *)Blt_GetHashValue(hPtr);
1338 	Blt_Free(bits);
1339     }
1340     Blt_DeleteHashTable(&(dataPtr->bitmapTable));
1341     Tcl_DeleteAssocData(interp, BITMAP_THREAD_KEY);
1342     Blt_Free(dataPtr);
1343 }
1344 
1345 static BitmapInterpData *
GetBitmapInterpData(interp)1346 GetBitmapInterpData(interp)
1347     Tcl_Interp *interp;
1348 {
1349     BitmapInterpData *dataPtr;
1350     Tcl_InterpDeleteProc *proc;
1351 
1352     dataPtr = (BitmapInterpData *)
1353 	Tcl_GetAssocData(interp, BITMAP_THREAD_KEY, &proc);
1354     if (dataPtr == NULL) {
1355 	dataPtr = Blt_Malloc(sizeof(BitmapInterpData));
1356 	assert(dataPtr);
1357 	dataPtr->interp = interp;
1358 	dataPtr->tkwin = Tk_MainWindow(interp);
1359 	dataPtr->display = Tk_Display(dataPtr->tkwin);
1360 	Tcl_SetAssocData(interp, BITMAP_THREAD_KEY, BitmapInterpDeleteProc,
1361 		 dataPtr);
1362 	Blt_InitHashTable(&(dataPtr->bitmapTable), BLT_STRING_KEYS);
1363     }
1364     return dataPtr;
1365 }
1366 
1367 /*
1368  *--------------------------------------------------------------
1369  *
1370  * Blt_BitmapInit --
1371  *
1372  *	This procedure is invoked to initialize the bitmap command.
1373  *
1374  * Results:
1375  *	None.
1376  *
1377  * Side effects:
1378  *	Adds the command to the interpreter and sets an array variable
1379  *	which its version number.
1380  *
1381  *--------------------------------------------------------------
1382  */
1383 int
Blt_BitmapInit(interp)1384 Blt_BitmapInit(interp)
1385     Tcl_Interp *interp;
1386 {
1387     BitmapInterpData *dataPtr;
1388     static Blt_CmdSpec cmdSpec =
1389     {"bitmap", BitmapCmd};
1390 
1391     /* Define the BLT logo bitmaps */
1392 
1393     dataPtr = GetBitmapInterpData(interp);
1394     cmdSpec.clientData = dataPtr;
1395     if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) {
1396 	return TCL_ERROR;
1397     }
1398     Tk_DefineBitmap(interp, Tk_GetUid("bigBLT"), (char *)bigblt_bits,
1399 	bigblt_width, bigblt_height);
1400     Tk_DefineBitmap(interp, Tk_GetUid("BLT"), (char *)blt_bits,
1401 	blt_width, blt_height);
1402     Tcl_ResetResult(interp);
1403     return TCL_OK;
1404 }
1405 
1406 #endif /* NO_BITMAP */
1407