1 /*
2  * tkImgPhoto.c --
3  *
4  *	Implements images of type "photo" for Tk. Photo images are stored in
5  *	full color (32 bits per pixel including alpha channel) and displayed
6  *	using dithering if necessary.
7  *
8  * Copyright (c) 1994 The Australian National University.
9  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10  * Copyright (c) 2002-2003 Donal K. Fellows
11  * Copyright (c) 2003 ActiveState Corporation.
12  *
13  * See the file "license.terms" for information on usage and redistribution of
14  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
15  *
16  * Author: Paul Mackerras (paulus@cs.anu.edu.au),
17  *	   Department of Computer Science,
18  *	   Australian National University.
19  */
20 
21 #include "tkInt.h"
22 #include <ctype.h>
23 
24 #ifdef __WIN32__
25 #include "tkWinInt.h"
26 #elif defined(__CYGWIN__)
27 #include "tkUnixInt.h"
28 #endif
29 
30 /*
31  * Declaration for internal Xlib function used here:
32  */
33 
34 extern int _XInitImageFuncPtrs(XImage *image);
35 
36 /*
37  * A signed 8-bit integral type. If chars are unsigned and the compiler isn't
38  * an ANSI one, then we have to use short instead (which wastes space) to get
39  * signed behavior.
40  */
41 
42 #if defined(__STDC__) || defined(_AIX)
43     typedef signed char schar;
44 #else
45 #   ifndef __CHAR_UNSIGNED__
46 	typedef char schar;
47 #   else
48 	typedef short schar;
49 #   endif
50 #endif
51 
52 /*
53  * An unsigned 32-bit integral type, used for pixel values. We use int rather
54  * than long here to accommodate those systems where longs are 64 bits.
55  */
56 
57 typedef unsigned int pixel;
58 
59 /*
60  * The maximum number of pixels to transmit to the server in a single
61  * XPutImage call.
62  */
63 
64 #define MAX_PIXELS 65536
65 
66 /*
67  * The set of colors required to display a photo image in a window depends on:
68  *	- the visual used by the window
69  *	- the palette, which specifies how many levels of each primary color to
70  *	  use, and
71  *	- the gamma value for the image.
72  *
73  * Pixel values allocated for specific colors are valid only for the colormap
74  * in which they were allocated. Sets of pixel values allocated for displaying
75  * photos are re-used in other windows if possible, that is, if the display,
76  * colormap, palette and gamma values match. A hash table is used to locate
77  * these sets of pixel values, using the following data structure as key:
78  */
79 
80 typedef struct {
81     Display *display;		/* Qualifies the colormap resource ID. */
82     Colormap colormap;		/* Colormap that the windows are using. */
83     double gamma;		/* Gamma exponent value for images. */
84     Tk_Uid palette;		/* Specifies how many shades of each primary
85 				 * we want to allocate. */
86 } ColorTableId;
87 
88 /*
89  * For a particular (display, colormap, palette, gamma) combination, a data
90  * structure of the following type is used to store the allocated pixel values
91  * and other information:
92  */
93 
94 typedef struct ColorTable {
95     ColorTableId id;		/* Information used in selecting this color
96 				 * table. */
97     int	flags;			/* See below. */
98     int	refCount;		/* Number of instances using this map. */
99     int liveRefCount;		/* Number of instances which are actually in
100 				 * use, using this map. */
101     int	numColors;		/* Number of colors allocated for this map. */
102 
103     XVisualInfo	visualInfo;	/* Information about the visual for windows
104 				 * using this color table. */
105 
106     pixel redValues[256];	/* Maps 8-bit values of red intensity to a
107 				 * pixel value or index in pixelMap. */
108     pixel greenValues[256];	/* Ditto for green intensity. */
109     pixel blueValues[256];	/* Ditto for blue intensity. */
110     unsigned long *pixelMap;	/* Actual pixel values allocated. */
111 
112     unsigned char colorQuant[3][256];
113 				/* Maps 8-bit intensities to quantized
114 				 * intensities. The first index is 0 for red,
115 				 * 1 for green, 2 for blue. */
116 } ColorTable;
117 
118 /*
119  * Bit definitions for the flags field of a ColorTable.
120  * BLACK_AND_WHITE:		1 means only black and white colors are
121  *				available.
122  * COLOR_WINDOW:		1 means a full 3-D color cube has been
123  *				allocated.
124  * DISPOSE_PENDING:		1 means a call to DisposeColorTable has been
125  *				scheduled as an idle handler, but it hasn't
126  *				been invoked yet.
127  * MAP_COLORS:			1 means pixel values should be mapped through
128  *				pixelMap.
129  */
130 
131 #ifdef COLOR_WINDOW
132 #undef COLOR_WINDOW
133 #endif
134 
135 #define BLACK_AND_WHITE		1
136 #define COLOR_WINDOW		2
137 #define DISPOSE_PENDING		4
138 #define MAP_COLORS		8
139 
140 /*
141  * Definition of the data associated with each photo image master.
142  */
143 
144 typedef struct PhotoMaster {
145     Tk_ImageMaster tkMaster;	/* Tk's token for image master. NULL means the
146 				 * image is being deleted. */
147     Tcl_Interp *interp;		/* Interpreter associated with the application
148 				 * using this image. */
149     Tcl_Command imageCmd;	/* Token for image command (used to delete it
150 				 * when the image goes away). NULL means the
151 				 * image command has already been deleted. */
152     int	flags;			/* Sundry flags, defined below. */
153     int	width, height;		/* Dimensions of image. */
154     int userWidth, userHeight;	/* User-declared image dimensions. */
155     Tk_Uid palette;		/* User-specified default palette for
156 				 * instances of this image. */
157     double gamma;		/* Display gamma value to correct for. */
158     char *fileString;		/* Name of file to read into image. */
159     Tcl_Obj *dataString;	/* Object to use as contents of image. */
160     Tcl_Obj *format;		/* User-specified format of data in image file
161 				 * or string value. */
162     unsigned char *pix32;	/* Local storage for 32-bit image. */
163     int ditherX, ditherY;	/* Location of first incorrectly dithered
164 				 * pixel in image. */
165     TkRegion validRegion;	/* Tk region indicating which parts of the
166 				 * image have valid image data. */
167     struct PhotoInstance *instancePtr;
168 				/* First in the list of instances associated
169 				 * with this master. */
170 } PhotoMaster;
171 
172 /*
173  * Bit definitions for the flags field of a PhotoMaster.
174  * COLOR_IMAGE:			1 means that the image has different color
175  *				components.
176  * IMAGE_CHANGED:		1 means that the instances of this image need
177  *				to be redithered.
178  * COMPLEX_ALPHA:		1 means that the instances of this image have
179  *				alpha values that aren't 0 or 255, and so need
180  *				the copy-merge-replace renderer .
181  */
182 
183 #define COLOR_IMAGE		1
184 #define IMAGE_CHANGED		2
185 #define COMPLEX_ALPHA		4
186 
187 /*
188  * Flag to OR with the compositing rule to indicate that the source, despite
189  * having an alpha channel, has simple alpha.
190  */
191 
192 #define SOURCE_IS_SIMPLE_ALPHA_PHOTO 0x10000000
193 
194 /*
195  * The following data structure represents all of the instances of a photo
196  * image in windows on a given screen that are using the same colormap.
197  */
198 
199 typedef struct PhotoInstance {
200     PhotoMaster *masterPtr;	/* Pointer to master for image. */
201     Display *display;		/* Display for windows using this instance. */
202     Colormap colormap;		/* The image may only be used in windows with
203 				 * this particular colormap. */
204     struct PhotoInstance *nextPtr;
205 				/* Pointer to the next instance in the list of
206 				 * instances associated with this master. */
207     int refCount;		/* Number of instances using this structure. */
208     Tk_Uid palette;		/* Palette for these particular instances. */
209     double gamma;		/* Gamma value for these instances. */
210     Tk_Uid defaultPalette;	/* Default palette to use if a palette is not
211 				 * specified for the master. */
212     ColorTable *colorTablePtr;	/* Pointer to information about colors
213 				 * allocated for image display in windows like
214 				 * this one. */
215     Pixmap pixels;		/* X pixmap containing dithered image. */
216     int width, height;		/* Dimensions of the pixmap. */
217     schar *error;		/* Error image, used in dithering. */
218     XImage *imagePtr;		/* Image structure for converted pixels. */
219     XVisualInfo visualInfo;	/* Information about the visual that these
220 				 * windows are using. */
221     GC gc;			/* Graphics context for writing images to the
222 				 * pixmap. */
223 } PhotoInstance;
224 
225 /*
226  * The following data structure is used to return information from
227  * ParseSubcommandOptions:
228  */
229 
230 struct SubcommandOptions {
231     int options;		/* Individual bits indicate which options were
232 				 * specified - see below. */
233     Tcl_Obj *name;		/* Name specified without an option. */
234     int fromX, fromY;		/* Values specified for -from option. */
235     int fromX2, fromY2;		/* Second coordinate pair for -from option. */
236     int toX, toY;		/* Values specified for -to option. */
237     int toX2, toY2;		/* Second coordinate pair for -to option. */
238     int zoomX, zoomY;		/* Values specified for -zoom option. */
239     int subsampleX, subsampleY;	/* Values specified for -subsample option. */
240     Tcl_Obj *format;		/* Value specified for -format option. */
241     XColor *background;		/* Value specified for -background option. */
242     int compositingRule;	/* Value specified for -compositingrule
243 				 * option. */
244 };
245 
246 /*
247  * Bit definitions for use with ParseSubcommandOptions: each bit is set in the
248  * allowedOptions parameter on a call to ParseSubcommandOptions if that option
249  * is allowed for the current photo image subcommand. On return, the bit is
250  * set in the options field of the SubcommandOptions structure if that option
251  * was specified.
252  *
253  * OPT_BACKGROUND:		Set if -format option allowed/specified.
254  * OPT_COMPOSITE:		Set if -compositingrule option allowed/spec'd.
255  * OPT_FORMAT:			Set if -format option allowed/specified.
256  * OPT_FROM:			Set if -from option allowed/specified.
257  * OPT_GRAYSCALE:		Set if -grayscale option allowed/specified.
258  * OPT_SHRINK:			Set if -shrink option allowed/specified.
259  * OPT_SUBSAMPLE:		Set if -subsample option allowed/spec'd.
260  * OPT_TO:			Set if -to option allowed/specified.
261  * OPT_ZOOM:			Set if -zoom option allowed/specified.
262  */
263 
264 #define OPT_BACKGROUND	1
265 #define OPT_COMPOSITE	2
266 #define OPT_FORMAT	4
267 #define OPT_FROM	8
268 #define OPT_GRAYSCALE	0x10
269 #define OPT_SHRINK	0x20
270 #define OPT_SUBSAMPLE	0x40
271 #define OPT_TO		0x80
272 #define OPT_ZOOM	0x100
273 
274 /*
275  * List of option names. The order here must match the order of declarations
276  * of the OPT_* constants above.
277  */
278 
279 static const char *const optionNames[] = {
280     "-background",
281     "-compositingrule",
282     "-format",
283     "-from",
284     "-grayscale",
285     "-shrink",
286     "-subsample",
287     "-to",
288     "-zoom",
289     NULL
290 };
291 
292 /*
293  * Message to generate when an attempt to resize an image fails due to memory
294  * problems.
295  */
296 
297 #define TK_PHOTO_ALLOC_FAILURE_MESSAGE \
298 	"not enough free memory for image buffer"
299 
300 /*
301  * Functions used in the type record for photo images.
302  */
303 
304 static int		ImgPhotoCreate(Tcl_Interp *interp, char *name,
305 			    int objc, Tcl_Obj *CONST objv[],
306 			    Tk_ImageType *typePtr, Tk_ImageMaster master,
307 			    ClientData *clientDataPtr);
308 static ClientData	ImgPhotoGet(Tk_Window tkwin, ClientData clientData);
309 static void		ImgPhotoDisplay(ClientData clientData,
310 			    Display *display, Drawable drawable,
311 			    int imageX, int imageY, int width, int height,
312 			    int drawableX, int drawableY);
313 static void		ImgPhotoFree(ClientData clientData, Display *display);
314 static void		ImgPhotoDelete(ClientData clientData);
315 static int		ImgPhotoPostscript(ClientData clientData,
316 			    Tcl_Interp *interp, Tk_Window tkwin,
317 			    Tk_PostscriptInfo psInfo, int x, int y, int width,
318 			    int height, int prepass);
319 
320 /*
321  * The type record itself for photo images:
322  */
323 
324 Tk_ImageType tkPhotoImageType = {
325     "photo",			/* name */
326     ImgPhotoCreate,		/* createProc */
327     ImgPhotoGet,		/* getProc */
328     ImgPhotoDisplay,		/* displayProc */
329     ImgPhotoFree,		/* freeProc */
330     ImgPhotoDelete,		/* deleteProc */
331     ImgPhotoPostscript,		/* postscriptProc */
332     NULL			/* nextPtr */
333 };
334 
335 typedef struct ThreadSpecificData {
336     Tk_PhotoImageFormat *formatList;
337 				/* Pointer to the first in the list of known
338 				 * photo image formats.*/
339     Tk_PhotoImageFormat *oldFormatList;
340 				/* Pointer to the first in the list of known
341 				 * photo image formats.*/
342     int initialized;		/* Set to 1 if we've initialized the
343 				 * strucuture. */
344 } ThreadSpecificData;
345 static Tcl_ThreadDataKey dataKey;
346 
347 /*
348  * Default configuration
349  */
350 
351 #define DEF_PHOTO_GAMMA		"1"
352 #define DEF_PHOTO_HEIGHT	"0"
353 #define DEF_PHOTO_PALETTE	""
354 #define DEF_PHOTO_WIDTH		"0"
355 
356 /*
357  * Information used for parsing configuration specifications:
358  */
359 
360 static Tk_ConfigSpec configSpecs[] = {
361     {TK_CONFIG_STRING, "-file", NULL, NULL,
362 	 NULL, Tk_Offset(PhotoMaster, fileString), TK_CONFIG_NULL_OK},
363     {TK_CONFIG_DOUBLE, "-gamma", NULL, NULL,
364 	 DEF_PHOTO_GAMMA, Tk_Offset(PhotoMaster, gamma), 0},
365     {TK_CONFIG_INT, "-height", NULL, NULL,
366 	 DEF_PHOTO_HEIGHT, Tk_Offset(PhotoMaster, userHeight), 0},
367     {TK_CONFIG_UID, "-palette", NULL, NULL,
368 	 DEF_PHOTO_PALETTE, Tk_Offset(PhotoMaster, palette), 0},
369     {TK_CONFIG_INT, "-width", NULL, NULL,
370 	 DEF_PHOTO_WIDTH, Tk_Offset(PhotoMaster, userWidth), 0},
371     {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
372 };
373 
374 /*
375  * Hash table used to hash from (display, colormap, palette, gamma) to
376  * ColorTable address.
377  */
378 
379 static Tcl_HashTable imgPhotoColorHash;
380 static int imgPhotoColorHashInitialized;
381 #define N_COLOR_HASH	(sizeof(ColorTableId) / sizeof(int))
382 
383 /*
384  * Implementation of the Porter-Duff Source-Over compositing rule.
385  */
386 
387 #define PD_SRC_OVER(srcColor,srcAlpha,dstColor,dstAlpha) \
388 	(srcColor*srcAlpha/255) + dstAlpha*(255-srcAlpha)/255*dstColor/255
389 #define PD_SRC_OVER_ALPHA(srcAlpha,dstAlpha) \
390 	(srcAlpha + (255-srcAlpha)*dstAlpha/255)
391 
392 /*
393  * Forward declarations
394  */
395 
396 static void		PhotoFormatThreadExitProc(ClientData clientData);
397 static int		ImgPhotoCmd(ClientData clientData, Tcl_Interp *interp,
398 			    int objc, Tcl_Obj *CONST objv[]);
399 static int		ParseSubcommandOptions(
400 			    struct SubcommandOptions *optPtr,
401 			    Tcl_Interp *interp, int allowedOptions,
402 			    int *indexPtr, int objc, Tcl_Obj *const objv[]);
403 static void		ImgPhotoCmdDeletedProc(ClientData clientData);
404 static int		ImgPhotoConfigureMaster(Tcl_Interp *interp,
405 			    PhotoMaster *masterPtr, int objc,
406 			    Tcl_Obj *const objv[], int flags);
407 static void		ImgPhotoConfigureInstance(PhotoInstance *instancePtr);
408 static int		ToggleComplexAlphaIfNeeded(PhotoMaster *mPtr);
409 static void		ImgPhotoBlendComplexAlpha(XImage *bgImg,
410 			    PhotoInstance *iPtr, int xOffset, int yOffset,
411 			    int width, int height);
412 static int		ImgPhotoSetSize(PhotoMaster *masterPtr, int width,
413 			    int height);
414 static void		ImgPhotoInstanceSetSize(PhotoInstance *instancePtr);
415 static int		ImgStringWrite(Tcl_Interp *interp,
416 			    Tcl_Obj *formatString,
417 			    Tk_PhotoImageBlock *blockPtr);
418 static char *		ImgGetPhoto(PhotoMaster *masterPtr,
419 			    Tk_PhotoImageBlock *blockPtr,
420 			    struct SubcommandOptions *optPtr);
421 static int		IsValidPalette(PhotoInstance *instancePtr,
422 			    const char *palette);
423 static int		CountBits(pixel mask);
424 static void		GetColorTable(PhotoInstance *instancePtr);
425 static void		FreeColorTable(ColorTable *colorPtr, int force);
426 static void		AllocateColors(ColorTable *colorPtr);
427 static void		DisposeColorTable(ClientData clientData);
428 static void		DisposeInstance(ClientData clientData);
429 static int		ReclaimColors(ColorTableId *id, int numColors);
430 static int		MatchFileFormat(Tcl_Interp *interp, Tcl_Channel chan,
431 			    char *fileName, Tcl_Obj *formatString,
432 			    Tk_PhotoImageFormat **imageFormatPtr,
433 			    int *widthPtr, int *heightPtr, int *oldformat);
434 static int		MatchStringFormat(Tcl_Interp *interp, Tcl_Obj *data,
435 			    Tcl_Obj *formatString,
436 			    Tk_PhotoImageFormat **imageFormatPtr,
437 			    int *widthPtr, int *heightPtr, int *oldformat);
438 static Tcl_ObjCmdProc *	PhotoOptionFind(Tcl_Interp *interp, Tcl_Obj *obj);
439 static void		DitherInstance(PhotoInstance *instancePtr, int x,
440 			    int y, int width, int height);
441 static void		PhotoOptionCleanupProc(ClientData clientData,
442 			    Tcl_Interp *interp);
443 
444 #undef MIN
445 #define MIN(a, b)	((a) < (b)? (a): (b))
446 #undef MAX
447 #define MAX(a, b)	((a) > (b)? (a): (b))
448 
449 /*
450  *----------------------------------------------------------------------
451  *
452  * PhotoFormatThreadExitProc --
453  *
454  *	Clean up the registered list of photo formats.
455  *
456  * Results:
457  *	None.
458  *
459  * Side effects:
460  *	The thread's linked lists of photo image formats is deleted.
461  *
462  *----------------------------------------------------------------------
463  */
464 
465 static void
PhotoFormatThreadExitProc(ClientData clientData)466 PhotoFormatThreadExitProc(
467     ClientData clientData)	/* not used */
468 {
469     Tk_PhotoImageFormat *freePtr;
470     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
471 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
472 
473     while (tsdPtr->oldFormatList != NULL) {
474 	freePtr = tsdPtr->oldFormatList;
475 	tsdPtr->oldFormatList = tsdPtr->oldFormatList->nextPtr;
476 	ckfree((char *) freePtr);
477     }
478     while (tsdPtr->formatList != NULL) {
479 	freePtr = tsdPtr->formatList;
480 	tsdPtr->formatList = tsdPtr->formatList->nextPtr;
481 	ckfree((char *) freePtr->name);
482 	ckfree((char *) freePtr);
483     }
484 }
485 
486 /*
487  *----------------------------------------------------------------------
488  *
489  * Tk_CreateOldPhotoImageFormat, Tk_CreatePhotoImageFormat --
490  *
491  *	This function is invoked by an image file handler to register a new
492  *	photo image format and the functions that handle the new format. The
493  *	function is typically invoked during Tcl_AppInit.
494  *
495  * Results:
496  *	None.
497  *
498  * Side effects:
499  *	The new image file format is entered into a table used in the photo
500  *	image "read" and "write" subcommands.
501  *
502  *----------------------------------------------------------------------
503  */
504 
505 void
Tk_CreateOldPhotoImageFormat(Tk_PhotoImageFormat * formatPtr)506 Tk_CreateOldPhotoImageFormat(
507     Tk_PhotoImageFormat *formatPtr)
508 				/* Structure describing the format. All of the
509 				 * fields except "nextPtr" must be filled in
510 				 * by caller. */
511 {
512     Tk_PhotoImageFormat *copyPtr;
513     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
514 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
515 
516     if (!tsdPtr->initialized) {
517 	tsdPtr->initialized = 1;
518 	Tcl_CreateThreadExitHandler(PhotoFormatThreadExitProc, NULL);
519     }
520     copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
521     *copyPtr = *formatPtr;
522     copyPtr->nextPtr = tsdPtr->oldFormatList;
523     tsdPtr->oldFormatList = copyPtr;
524 }
525 
526 void
Tk_CreatePhotoImageFormat(Tk_PhotoImageFormat * formatPtr)527 Tk_CreatePhotoImageFormat(
528     Tk_PhotoImageFormat *formatPtr)
529 				/* Structure describing the format. All of the
530 				 * fields except "nextPtr" must be filled in
531 				 * by caller. */
532 {
533     Tk_PhotoImageFormat *copyPtr;
534     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
535 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
536 
537     if (!tsdPtr->initialized) {
538 	tsdPtr->initialized = 1;
539 	Tcl_CreateThreadExitHandler(PhotoFormatThreadExitProc, NULL);
540     }
541     copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
542     *copyPtr = *formatPtr;
543     if (isupper((unsigned char) *formatPtr->name)) {
544 	copyPtr->nextPtr = tsdPtr->oldFormatList;
545 	tsdPtr->oldFormatList = copyPtr;
546     } else {
547 	/* for compatibility with aMSN: make a copy of formatPtr->name */
548 	char *name = ckalloc(strlen(formatPtr->name) + 1);
549 	strcpy(name, formatPtr->name);
550 	copyPtr->name = name;
551 	copyPtr->nextPtr = tsdPtr->formatList;
552 	tsdPtr->formatList = copyPtr;
553     }
554 }
555 
556 /*
557  *----------------------------------------------------------------------
558  *
559  * ImgPhotoCreate --
560  *
561  *	This function is called by the Tk image code to create a new photo
562  *	image.
563  *
564  * Results:
565  *	A standard Tcl result.
566  *
567  * Side effects:
568  *	The data structure for a new photo image is allocated and initialized.
569  *
570  *----------------------------------------------------------------------
571  */
572 
573 static int
ImgPhotoCreate(Tcl_Interp * interp,char * name,int objc,Tcl_Obj * CONST objv[],Tk_ImageType * typePtr,Tk_ImageMaster master,ClientData * clientDataPtr)574 ImgPhotoCreate(
575     Tcl_Interp *interp,		/* Interpreter for application containing
576 				 * image. */
577     char *name,			/* Name to use for image. */
578     int objc,			/* Number of arguments. */
579     Tcl_Obj *CONST objv[],	/* Argument objects for options (doesn't
580 				 * include image name or type). */
581     Tk_ImageType *typePtr,	/* Pointer to our type record (not used). */
582     Tk_ImageMaster master,	/* Token for image, to be used by us in later
583 				 * callbacks. */
584     ClientData *clientDataPtr)	/* Store manager's token for image here; it
585 				 * will be returned in later callbacks. */
586 {
587     PhotoMaster *masterPtr;
588 
589     /*
590      * Allocate and initialize the photo image master record.
591      */
592 
593     masterPtr = (PhotoMaster *) ckalloc(sizeof(PhotoMaster));
594     memset(masterPtr, 0, sizeof(PhotoMaster));
595     masterPtr->tkMaster = master;
596     masterPtr->interp = interp;
597     masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgPhotoCmd,
598 	    (ClientData) masterPtr, ImgPhotoCmdDeletedProc);
599     masterPtr->palette = NULL;
600     masterPtr->pix32 = NULL;
601     masterPtr->instancePtr = NULL;
602     masterPtr->validRegion = TkCreateRegion();
603 
604     /*
605      * Process configuration options given in the image create command.
606      */
607 
608     if (ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, 0) != TCL_OK) {
609 	ImgPhotoDelete((ClientData) masterPtr);
610 	return TCL_ERROR;
611     }
612 
613     *clientDataPtr = (ClientData) masterPtr;
614     return TCL_OK;
615 }
616 
617 /*
618  *----------------------------------------------------------------------
619  *
620  * ImgPhotoCmd --
621  *
622  *	This function is invoked to process the Tcl command that corresponds
623  *	to a photo image. See the user documentation for details on what it
624  *	does.
625  *
626  * Results:
627  *	A standard Tcl result.
628  *
629  * Side effects:
630  *	See the user documentation.
631  *
632  *----------------------------------------------------------------------
633  */
634 
635 static int
ImgPhotoCmd(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])636 ImgPhotoCmd(
637     ClientData clientData,	/* Information about photo master. */
638     Tcl_Interp *interp,		/* Current interpreter. */
639     int objc,			/* Number of arguments. */
640     Tcl_Obj *CONST objv[])	/* Argument objects. */
641 {
642     static const char *photoOptions[] = {
643 	"blank", "cget", "configure", "copy", "data", "get", "put",
644 	"read", "redither", "transparency", "write", NULL
645     };
646     enum PhotoOptions {
647 	PHOTO_BLANK, PHOTO_CGET, PHOTO_CONFIGURE, PHOTO_COPY, PHOTO_DATA,
648 	PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_TRANS,
649 	PHOTO_WRITE
650     };
651 
652     PhotoMaster *masterPtr = (PhotoMaster *) clientData;
653     int result, index, x, y, width, height, dataWidth, dataHeight, listObjc;
654     struct SubcommandOptions options;
655     Tcl_Obj **listObjv, **srcObjv;
656     unsigned char *pixelPtr;
657     Tk_PhotoImageBlock block;
658     Tk_Window tkwin;
659     Tk_PhotoImageFormat *imageFormat;
660     int imageWidth, imageHeight, matched, length, oldformat = 0;
661     Tcl_Channel chan;
662     Tk_PhotoHandle srcHandle;
663     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
664 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
665 
666     if (objc < 2) {
667 	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
668 	return TCL_ERROR;
669     }
670 
671     if (Tcl_GetIndexFromObj(interp, objv[1], photoOptions, "option", 0,
672 	    &index) != TCL_OK) {
673 	Tcl_ObjCmdProc *proc;
674 	proc = PhotoOptionFind(interp, objv[1]);
675 	if (proc == NULL) {
676 	    return TCL_ERROR;
677 	}
678 	return proc(clientData, interp, objc, objv);
679     }
680 
681     switch ((enum PhotoOptions) index) {
682     case PHOTO_BLANK:
683 	/*
684 	 * photo blank command - just call Tk_PhotoBlank.
685 	 */
686 
687 	if (objc == 2) {
688 	    Tk_PhotoBlank(masterPtr);
689 	    return TCL_OK;
690 	} else {
691 	    Tcl_WrongNumArgs(interp, 2, objv, NULL);
692 	    return TCL_ERROR;
693 	}
694 
695     case PHOTO_CGET: {
696 	char *arg;
697 
698 	if (objc != 3) {
699 	    Tcl_WrongNumArgs(interp, 2, objv, "option");
700 	    return TCL_ERROR;
701 	}
702 	arg = Tcl_GetStringFromObj(objv[2], &length);
703 	if (strncmp(arg,"-data", (unsigned) length) == 0) {
704 	    if (masterPtr->dataString) {
705 		Tcl_SetObjResult(interp, masterPtr->dataString);
706 	    }
707 	} else if (strncmp(arg,"-format", (unsigned) length) == 0) {
708 	    if (masterPtr->format) {
709 		Tcl_SetObjResult(interp, masterPtr->format);
710 	    }
711 	} else {
712 	    Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
713 		    (char *) masterPtr, Tcl_GetString(objv[2]), 0);
714 	}
715 	return TCL_OK;
716     }
717 
718     case PHOTO_CONFIGURE:
719 	/*
720 	 * photo configure command - handle this in the standard way.
721 	 */
722 
723 	if (objc == 2) {
724 	    Tcl_Obj *obj, *subobj;
725 
726 	    result = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
727 		    configSpecs, (char *) masterPtr, NULL, 0);
728 	    if (result != TCL_OK) {
729 		return result;
730 	    }
731 	    obj = Tcl_NewObj();
732 	    subobj = Tcl_NewStringObj("-data {} {} {}", 14);
733 	    if (masterPtr->dataString) {
734 		Tcl_ListObjAppendElement(NULL, subobj, masterPtr->dataString);
735 	    } else {
736 		Tcl_AppendStringsToObj(subobj, " {}", NULL);
737 	    }
738 	    Tcl_ListObjAppendElement(interp, obj, subobj);
739 	    subobj = Tcl_NewStringObj("-format {} {} {}", 16);
740 	    if (masterPtr->format) {
741 		Tcl_ListObjAppendElement(NULL, subobj, masterPtr->format);
742 	    } else {
743 		Tcl_AppendStringsToObj(subobj, " {}", NULL);
744 	    }
745 	    Tcl_ListObjAppendElement(interp, obj, subobj);
746 	    Tcl_ListObjAppendList(interp, obj, Tcl_GetObjResult(interp));
747 	    Tcl_SetObjResult(interp, obj);
748 	    return TCL_OK;
749 
750 	} else if (objc == 3) {
751 	    char *arg = Tcl_GetStringFromObj(objv[2], &length);
752 
753 	    if (length > 1 && !strncmp(arg, "-data", (unsigned) length)) {
754 		Tcl_AppendResult(interp, "-data {} {} {}", NULL);
755 		if (masterPtr->dataString) {
756 		    Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
757 			    masterPtr->dataString);
758 		} else {
759 		    Tcl_AppendResult(interp, " {}", NULL);
760 		}
761 		return TCL_OK;
762 	    } else if (length > 1 &&
763 		    !strncmp(arg, "-format", (unsigned) length)) {
764 		Tcl_AppendResult(interp, "-format {} {} {}", NULL);
765 		if (masterPtr->format) {
766 		    Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
767 			    masterPtr->format);
768 		} else {
769 		    Tcl_AppendResult(interp, " {}", NULL);
770 		}
771 		return TCL_OK;
772 	    } else {
773 		return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
774 			configSpecs, (char *) masterPtr, arg, 0);
775 	    }
776 	}
777 	return ImgPhotoConfigureMaster(interp, masterPtr, objc-2, objv+2,
778 		TK_CONFIG_ARGV_ONLY);
779 
780     case PHOTO_COPY:
781 	/*
782 	 * photo copy command - first parse options.
783 	 */
784 
785 	index = 2;
786 	memset(&options, 0, sizeof(options));
787 	options.zoomX = options.zoomY = 1;
788 	options.subsampleX = options.subsampleY = 1;
789 	options.name = NULL;
790 	options.compositingRule = TK_PHOTO_COMPOSITE_OVERLAY;
791 	if (ParseSubcommandOptions(&options, interp,
792 		OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK |
793 		OPT_COMPOSITE, &index, objc, objv) != TCL_OK) {
794 	    return TCL_ERROR;
795 	}
796 	if (options.name == NULL || index < objc) {
797 	    Tcl_WrongNumArgs(interp, 2, objv,
798 		    "source-image ?-compositingrule rule? ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?");
799 	    return TCL_ERROR;
800 	}
801 
802 	/*
803 	 * Look for the source image and get a pointer to its image data.
804 	 * Check the values given for the -from option.
805 	 */
806 
807 	srcHandle = Tk_FindPhoto(interp, Tcl_GetString(options.name));
808 	if (srcHandle == NULL) {
809 	    Tcl_AppendResult(interp, "image \"",
810 		    Tcl_GetString(options.name), "\" doesn't",
811 		    " exist or is not a photo image", NULL);
812 	    return TCL_ERROR;
813 	}
814 	Tk_PhotoGetImage(srcHandle, &block);
815 	if ((options.fromX2 > block.width) || (options.fromY2 > block.height)
816 		|| (options.fromX2 > block.width)
817 		|| (options.fromY2 > block.height)) {
818 	    Tcl_AppendResult(interp, "coordinates for -from option extend ",
819 		    "outside source image", NULL);
820 	    return TCL_ERROR;
821 	}
822 
823 	/*
824 	 * Hack to pass through the message that the place we're coming from
825 	 * has a simple alpha channel.
826 	 */
827 
828 	if (!(((PhotoMaster *) srcHandle)->flags & COMPLEX_ALPHA)) {
829 	    options.compositingRule |= SOURCE_IS_SIMPLE_ALPHA_PHOTO;
830 	}
831 
832 	/*
833 	 * Fill in default values for unspecified parameters.
834 	 */
835 
836 	if (!(options.options & OPT_FROM) || (options.fromX2 < 0)) {
837 	    options.fromX2 = block.width;
838 	    options.fromY2 = block.height;
839 	}
840 	if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
841 	    width = options.fromX2 - options.fromX;
842 	    if (options.subsampleX > 0) {
843 		width = (width + options.subsampleX - 1) / options.subsampleX;
844 	    } else if (options.subsampleX == 0) {
845 		width = 0;
846 	    } else {
847 		width = (width - options.subsampleX - 1) / -options.subsampleX;
848 	    }
849 	    options.toX2 = options.toX + width * options.zoomX;
850 
851 	    height = options.fromY2 - options.fromY;
852 	    if (options.subsampleY > 0) {
853 		height = (height + options.subsampleY - 1)
854 			/ options.subsampleY;
855 	    } else if (options.subsampleY == 0) {
856 		height = 0;
857 	    } else {
858 		height = (height - options.subsampleY - 1)
859 			/ -options.subsampleY;
860 	    }
861 	    options.toY2 = options.toY + height * options.zoomY;
862 	}
863 
864 	/*
865 	 * Set the destination image size if the -shrink option was specified.
866 	 */
867 
868 	if (options.options & OPT_SHRINK) {
869 	    if (ImgPhotoSetSize(masterPtr, options.toX2,
870 		    options.toY2) != TCL_OK) {
871 		Tcl_ResetResult(interp);
872 		Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
873 		return TCL_ERROR;
874 	    }
875 	}
876 
877 	/*
878 	 * Copy the image data over using Tk_PhotoPutZoomedBlock.
879 	 */
880 
881 	block.pixelPtr += options.fromX * block.pixelSize
882 		+ options.fromY * block.pitch;
883 	block.width = options.fromX2 - options.fromX;
884 	block.height = options.fromY2 - options.fromY;
885 	return Tk_PhotoPutZoomedBlock(interp, (Tk_PhotoHandle) masterPtr,
886 		&block, options.toX, options.toY, options.toX2 - options.toX,
887 		options.toY2 - options.toY, options.zoomX, options.zoomY,
888 		options.subsampleX, options.subsampleY,
889 		options.compositingRule);
890 
891     case PHOTO_DATA: {
892 	char *data;
893 
894 	/*
895 	 * photo data command - first parse and check any options given.
896 	 */
897 
898 	Tk_ImageStringWriteProc *stringWriteProc = NULL;
899 
900 	index = 2;
901 	memset(&options, 0, sizeof(options));
902 	options.name = NULL;
903 	options.format = NULL;
904 	options.fromX = 0;
905 	options.fromY = 0;
906 	if (ParseSubcommandOptions(&options, interp,
907 		OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
908 		&index, objc, objv) != TCL_OK) {
909 	    return TCL_ERROR;
910 	}
911 	if ((options.name != NULL) || (index < objc)) {
912 	    Tcl_WrongNumArgs(interp, 2, objv, "?options?");
913 	    return TCL_ERROR;
914 	}
915 	if ((options.fromX > masterPtr->width)
916 		|| (options.fromY > masterPtr->height)
917 		|| (options.fromX2 > masterPtr->width)
918 		|| (options.fromY2 > masterPtr->height)) {
919 	    Tcl_AppendResult(interp, "coordinates for -from option extend ",
920 		    "outside image", NULL);
921 	    return TCL_ERROR;
922 	}
923 
924 	/*
925 	 * Fill in default values for unspecified parameters.
926 	 */
927 
928 	if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
929 	    options.fromX2 = masterPtr->width;
930 	    options.fromY2 = masterPtr->height;
931 	}
932 
933 	/*
934 	 * Search for an appropriate image string format handler.
935 	 */
936 
937 	if (options.options & OPT_FORMAT) {
938 	    matched = 0;
939 	    for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
940 	 	imageFormat = imageFormat->nextPtr) {
941 		if ((strncasecmp(Tcl_GetString(options.format),
942 			imageFormat->name, strlen(imageFormat->name)) == 0)) {
943 		    matched = 1;
944 		    if (imageFormat->stringWriteProc != NULL) {
945 			stringWriteProc = imageFormat->stringWriteProc;
946 			break;
947 		    }
948 		}
949 	    }
950 	    if (stringWriteProc == NULL) {
951 		oldformat = 1;
952 		for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
953 			imageFormat = imageFormat->nextPtr) {
954 		    if ((strncasecmp(Tcl_GetString(options.format),
955 			    imageFormat->name,
956 			    strlen(imageFormat->name)) == 0)) {
957 			matched = 1;
958 			if (imageFormat->stringWriteProc != NULL) {
959 			    stringWriteProc = imageFormat->stringWriteProc;
960 			    break;
961 			}
962 		    }
963 		}
964 	    }
965 	    if (stringWriteProc == NULL) {
966 		Tcl_AppendResult(interp, "image string format \"",
967 			Tcl_GetString(options.format), "\" is ",
968 			(matched ? "not supported" : "unknown"), NULL);
969 		return TCL_ERROR;
970 	    }
971 	} else {
972 	    stringWriteProc = ImgStringWrite;
973 	}
974 
975 	/*
976 	 * Call the handler's string write function to write out the image.
977 	 */
978 
979 	data = ImgGetPhoto(masterPtr, &block, &options);
980 
981 	if (oldformat) {
982 	    Tcl_DString buffer;
983 
984 	    Tcl_DStringInit(&buffer);
985 	    result = ((int (*) (Tcl_Interp *interp,
986 		    Tcl_DString *dataPtr, char *formatString,
987 		    Tk_PhotoImageBlock *blockPtr)) stringWriteProc)
988 		    (interp, &buffer, Tcl_GetString(options.format), &block);
989 	    if (result == TCL_OK) {
990 		Tcl_DStringResult(interp, &buffer);
991 	    } else {
992 		Tcl_DStringFree(&buffer);
993 	    }
994 	} else {
995 
996 	    result = ((int (*) (Tcl_Interp *interp,
997 		    Tcl_Obj *formatString, Tk_PhotoImageBlock *blockPtr,
998 		    void *dummy)) stringWriteProc)
999 		    (interp, options.format, &block, NULL);
1000 	}
1001 	if (options.background) {
1002 	    Tk_FreeColor(options.background);
1003 	}
1004 	if (data) {
1005 	    ckfree(data);
1006 	}
1007 	return result;
1008     }
1009 
1010     case PHOTO_GET: {
1011 	/*
1012 	 * photo get command - first parse and check parameters.
1013 	 */
1014 
1015 	char string[TCL_INTEGER_SPACE * 3];
1016 
1017 	if (objc != 4) {
1018 	    Tcl_WrongNumArgs(interp, 2, objv, "x y");
1019 	    return TCL_ERROR;
1020 	}
1021 	if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK)
1022 		|| (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) {
1023 	    return TCL_ERROR;
1024 	}
1025 	if ((x < 0) || (x >= masterPtr->width)
1026 		|| (y < 0) || (y >= masterPtr->height)) {
1027 	    Tcl_AppendResult(interp, Tcl_GetString(objv[0]), " get: ",
1028 		    "coordinates out of range", NULL);
1029 	    return TCL_ERROR;
1030 	}
1031 
1032 	/*
1033 	 * Extract the value of the desired pixel and format it as a string.
1034 	 */
1035 
1036 	pixelPtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
1037 	sprintf(string, "%d %d %d", pixelPtr[0], pixelPtr[1],
1038 		pixelPtr[2]);
1039 	Tcl_AppendResult(interp, string, NULL);
1040 	return TCL_OK;
1041     }
1042 
1043     case PHOTO_PUT:
1044 	/*
1045 	 * photo put command - first parse the options and colors specified.
1046 	 */
1047 
1048 	index = 2;
1049 	memset(&options, 0, sizeof(options));
1050 	options.name = NULL;
1051 	if (ParseSubcommandOptions(&options, interp, OPT_TO|OPT_FORMAT,
1052 		&index, objc, objv) != TCL_OK) {
1053 	    return TCL_ERROR;
1054 	}
1055 	if ((options.name == NULL) || (index < objc)) {
1056 	    Tcl_WrongNumArgs(interp, 2, objv, "data ?options?");
1057 	    return TCL_ERROR;
1058 	}
1059 
1060 	if (MatchStringFormat(interp, options.name ? objv[2]:NULL,
1061 		options.format, &imageFormat, &imageWidth,
1062 		&imageHeight, &oldformat) == TCL_OK) {
1063 	    Tcl_Obj *format, *data;
1064 
1065 	    if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
1066 		options.toX2 = options.toX + imageWidth;
1067 		options.toY2 = options.toY + imageHeight;
1068 	    }
1069 	    if (imageWidth > options.toX2 - options.toX) {
1070 		imageWidth = options.toX2 - options.toX;
1071 	    }
1072 	    if (imageHeight > options.toY2 - options.toY) {
1073 		imageHeight = options.toY2 - options.toY;
1074 	    }
1075 	    format = options.format;
1076 	    data = objv[2];
1077 	    if (oldformat) {
1078 		if (format) {
1079 		    format = (Tcl_Obj *) Tcl_GetString(format);
1080 		}
1081 		data = (Tcl_Obj *) Tcl_GetString(data);
1082 	    }
1083 	    if ((*imageFormat->stringReadProc)(interp, data,
1084 		    format, (Tk_PhotoHandle) masterPtr,
1085 		    options.toX, options.toY, imageWidth, imageHeight,
1086 		    0, 0) != TCL_OK) {
1087 		return TCL_ERROR;
1088 	    }
1089 	    masterPtr->flags |= IMAGE_CHANGED;
1090 	    return TCL_OK;
1091 	}
1092 	if (options.options & OPT_FORMAT) {
1093 	    return TCL_ERROR;
1094 	}
1095 	Tcl_ResetResult(interp);
1096 	if (Tcl_ListObjGetElements(interp, options.name,
1097 		&dataHeight, &srcObjv) != TCL_OK) {
1098 	    return TCL_ERROR;
1099 	}
1100 	tkwin = Tk_MainWindow(interp);
1101 	block.pixelPtr = NULL;
1102 	dataWidth = 0;
1103 	pixelPtr = NULL;
1104 	for (y = 0; y < dataHeight; ++y) {
1105 	    if (Tcl_ListObjGetElements(interp, srcObjv[y],
1106 		    &listObjc, &listObjv) != TCL_OK) {
1107 		break;
1108 	    }
1109 
1110 	    if (y == 0) {
1111 		if (listObjc == 0) {
1112 		    /*
1113 		     * Lines must be non-empty...
1114 		     */
1115 
1116 		    break;
1117 		}
1118 		dataWidth = listObjc;
1119 		pixelPtr = (unsigned char *)
1120 			ckalloc((unsigned) dataWidth * dataHeight * 3);
1121 		block.pixelPtr = pixelPtr;
1122 	    } else if (listObjc != dataWidth) {
1123 		Tcl_AppendResult(interp, "all elements of color list must",
1124 			" have the same number of elements", NULL);
1125 		break;
1126 	    }
1127 
1128 	    for (x = 0; x < dataWidth; ++x) {
1129 		char *colorString = Tcl_GetString(listObjv[x]);
1130 		XColor color;
1131 		int tmpr, tmpg, tmpb;
1132 
1133 		/*
1134 		 * We do not use Tk_GetColorFromObj() because we absolutely do
1135 		 * not want to invoke the fallback code.
1136 		 */
1137 
1138 		if (colorString[0] == '#') {
1139 		    if (isxdigit(UCHAR(colorString[1])) &&
1140 			    isxdigit(UCHAR(colorString[2])) &&
1141 			    isxdigit(UCHAR(colorString[3]))) {
1142 			if (colorString[4] == '\0') {
1143 			    /* Got #rgb */
1144 			    sscanf(colorString+1, "%1x%1x%1x",
1145 				    &tmpr, &tmpg, &tmpb);
1146 			    *pixelPtr++ = tmpr * 0x11;
1147 			    *pixelPtr++ = tmpg * 0x11;
1148 			    *pixelPtr++ = tmpb * 0x11;
1149 			    continue;
1150 			} else if (isxdigit(UCHAR(colorString[4])) &&
1151 				isxdigit(UCHAR(colorString[5])) &&
1152 				isxdigit(UCHAR(colorString[6])) &&
1153 				colorString[7] == '\0') {
1154 			    /* Got #rrggbb */
1155 			    sscanf(colorString+1, "%2x%2x%2x",
1156 				    &tmpr, &tmpg, &tmpb);
1157 			    *pixelPtr++ = tmpr;
1158 			    *pixelPtr++ = tmpg;
1159 			    *pixelPtr++ = tmpb;
1160 			    continue;
1161 			}
1162 		    }
1163 		}
1164 
1165 		if (!TkParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
1166 			colorString, &color)) {
1167 		    Tcl_AppendResult(interp, "can't parse color \"",
1168 			    colorString, "\"", NULL);
1169 		    break;
1170 		}
1171 		*pixelPtr++ = color.red >> 8;
1172 		*pixelPtr++ = color.green >> 8;
1173 		*pixelPtr++ = color.blue >> 8;
1174 	    }
1175 	    if (x < dataWidth) {
1176 		break;
1177 	    }
1178 	}
1179 	if (y < dataHeight || dataHeight == 0 || dataWidth == 0) {
1180 	    if (block.pixelPtr != NULL) {
1181 		ckfree((char *) block.pixelPtr);
1182 	    }
1183 	    if (y < dataHeight) {
1184 		return TCL_ERROR;
1185 	    }
1186 	    return TCL_OK;
1187 	}
1188 
1189 	/*
1190 	 * Fill in default values for the -to option, then copy the block in
1191 	 * using Tk_PhotoPutBlock.
1192 	 */
1193 
1194 	if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
1195 	    options.toX2 = options.toX + dataWidth;
1196 	    options.toY2 = options.toY + dataHeight;
1197 	}
1198 	block.width = dataWidth;
1199 	block.height = dataHeight;
1200 	block.pitch = dataWidth * 3;
1201 	block.pixelSize = 3;
1202 	block.offset[0] = 0;
1203 	block.offset[1] = 1;
1204 	block.offset[2] = 2;
1205 	block.offset[3] = 0;
1206 	result = Tk_PhotoPutBlock(interp, (ClientData)masterPtr, &block,
1207 		options.toX, options.toY, options.toX2 - options.toX,
1208 		options.toY2 - options.toY,
1209 		TK_PHOTO_COMPOSITE_SET);
1210 	ckfree((char *) block.pixelPtr);
1211 	return result;
1212 
1213     case PHOTO_READ: {
1214 	Tcl_Obj *format;
1215 
1216 	/*
1217 	 * photo read command - first parse the options specified.
1218 	 */
1219 
1220 	index = 2;
1221 	memset(&options, 0, sizeof(options));
1222 	options.name = NULL;
1223 	options.format = NULL;
1224 	if (ParseSubcommandOptions(&options, interp,
1225 		OPT_FORMAT | OPT_FROM | OPT_TO | OPT_SHRINK,
1226 		&index, objc, objv) != TCL_OK) {
1227 	    return TCL_ERROR;
1228 	}
1229 	if ((options.name == NULL) || (index < objc)) {
1230 	    Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
1231 	    return TCL_ERROR;
1232 	}
1233 
1234 	/*
1235 	 * Prevent file system access in safe interpreters.
1236 	 */
1237 
1238 	if (Tcl_IsSafe(interp)) {
1239 	    Tcl_AppendResult(interp, "can't get image from a file in a",
1240 		    " safe interpreter", NULL);
1241 	    return TCL_ERROR;
1242 	}
1243 
1244 	/*
1245 	 * Open the image file and look for a handler for it.
1246 	 */
1247 
1248 	chan = Tcl_OpenFileChannel(interp,
1249 		Tcl_GetString(options.name), "r", 0);
1250 	if (chan == NULL) {
1251 	    return TCL_ERROR;
1252 	}
1253 	if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
1254 		!= TCL_OK) {
1255 	    Tcl_Close(NULL, chan);
1256 	    return TCL_ERROR;
1257 	}
1258 	if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
1259 		!= TCL_OK) {
1260 	    Tcl_Close(NULL, chan);
1261 	    return TCL_ERROR;
1262 	}
1263 
1264 	if (MatchFileFormat(interp, chan,
1265 		Tcl_GetString(options.name), options.format, &imageFormat,
1266 		&imageWidth, &imageHeight, &oldformat) != TCL_OK) {
1267 	    Tcl_Close(NULL, chan);
1268 	    return TCL_ERROR;
1269 	}
1270 
1271 	/*
1272 	 * Check the values given for the -from option.
1273 	 */
1274 
1275 	if ((options.fromX > imageWidth) || (options.fromY > imageHeight)
1276 		|| (options.fromX2 > imageWidth)
1277 		|| (options.fromY2 > imageHeight)) {
1278 	    Tcl_AppendResult(interp, "coordinates for -from option extend ",
1279 		    "outside source image", NULL);
1280 	    Tcl_Close(NULL, chan);
1281 	    return TCL_ERROR;
1282 	}
1283 	if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
1284 	    width = imageWidth - options.fromX;
1285 	    height = imageHeight - options.fromY;
1286 	} else {
1287 	    width = options.fromX2 - options.fromX;
1288 	    height = options.fromY2 - options.fromY;
1289 	}
1290 
1291 	/*
1292 	 * If the -shrink option was specified, set the size of the image.
1293 	 */
1294 
1295 	if (options.options & OPT_SHRINK) {
1296 	    if (ImgPhotoSetSize(masterPtr, options.toX + width,
1297 		    options.toY + height) != TCL_OK) {
1298 		Tcl_ResetResult(interp);
1299 		Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
1300 		return TCL_ERROR;
1301 	    }
1302 	}
1303 
1304 	/*
1305 	 * Call the handler's file read function to read the data into the
1306 	 * image.
1307 	 */
1308 
1309 	format = options.format;
1310 	if (oldformat && format) {
1311 	    format = (Tcl_Obj *) Tcl_GetString(format);
1312 	}
1313 	result = (*imageFormat->fileReadProc)(interp, chan,
1314 		Tcl_GetString(options.name),
1315 		format, (Tk_PhotoHandle) masterPtr, options.toX,
1316 		options.toY, width, height, options.fromX, options.fromY);
1317 	if (chan != NULL) {
1318 	    Tcl_Close(NULL, chan);
1319 	}
1320 	return result;
1321     }
1322 
1323     case PHOTO_REDITHER:
1324 	if (objc != 2) {
1325 	    Tcl_WrongNumArgs(interp, 2, objv, NULL);
1326 	    return TCL_ERROR;
1327 	}
1328 
1329 	/*
1330 	 * Call Dither if any part of the image is not correctly dithered at
1331 	 * present.
1332 	 */
1333 
1334 	x = masterPtr->ditherX;
1335 	y = masterPtr->ditherY;
1336 	if (masterPtr->ditherX != 0) {
1337 	    Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y,
1338 		    masterPtr->width - x, 1);
1339 	}
1340 	if (masterPtr->ditherY < masterPtr->height) {
1341 	    x = 0;
1342 	    Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0,
1343 		    masterPtr->ditherY, masterPtr->width,
1344 		    masterPtr->height - masterPtr->ditherY);
1345 	}
1346 
1347 	if (y < masterPtr->height) {
1348 	    /*
1349 	     * Tell the core image code that part of the image has changed.
1350 	     */
1351 
1352 	    Tk_ImageChanged(masterPtr->tkMaster, x, y,
1353 		    (masterPtr->width - x), (masterPtr->height - y),
1354 		    masterPtr->width, masterPtr->height);
1355 	}
1356 	return TCL_OK;
1357 
1358     case PHOTO_TRANS: {
1359 	static const char *photoTransOptions[] = {
1360 	    "get", "set", NULL
1361 	};
1362 	enum transOptions {
1363 	    PHOTO_TRANS_GET, PHOTO_TRANS_SET
1364 	};
1365 
1366 	if (objc < 3) {
1367 	    Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?");
1368 	    return TCL_ERROR;
1369 	}
1370 	if (Tcl_GetIndexFromObj(interp, objv[2], photoTransOptions, "option",
1371 		0, &index) != TCL_OK) {
1372 	    return TCL_ERROR;
1373 	}
1374 
1375 	switch ((enum transOptions) index) {
1376 	case PHOTO_TRANS_GET: {
1377 	    XRectangle testBox;
1378 	    TkRegion testRegion;
1379 
1380 	    if (objc != 5) {
1381 		Tcl_WrongNumArgs(interp, 3, objv, "x y");
1382 		return TCL_ERROR;
1383 	    }
1384 	    if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
1385 		    || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)) {
1386 		return TCL_ERROR;
1387 	    }
1388 	    if ((x < 0) || (x >= masterPtr->width)
1389 		|| (y < 0) || (y >= masterPtr->height)) {
1390 		Tcl_AppendResult(interp, Tcl_GetString(objv[0]),
1391 			" transparency get: coordinates out of range", NULL);
1392 		return TCL_ERROR;
1393 	    }
1394 
1395 	    testBox.x = x;
1396 	    testBox.y = y;
1397 	    testBox.width = 1;
1398 	    testBox.height = 1;
1399 	    /* What a way to do a test! */
1400 	    testRegion = TkCreateRegion();
1401 	    TkUnionRectWithRegion(&testBox, testRegion, testRegion);
1402 	    TkIntersectRegion(testRegion, masterPtr->validRegion, testRegion);
1403 	    TkClipBox(testRegion, &testBox);
1404 	    TkDestroyRegion(testRegion);
1405 
1406 	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp),
1407 		    (testBox.width==0 && testBox.height==0));
1408 	    return TCL_OK;
1409 	}
1410 
1411 	case PHOTO_TRANS_SET: {
1412 	    int transFlag;
1413 	    XRectangle setBox;
1414 
1415 	    if (objc != 6) {
1416 		Tcl_WrongNumArgs(interp, 3, objv, "x y boolean");
1417 		return TCL_ERROR;
1418 	    }
1419 	    if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
1420 		    || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)
1421 		    || (Tcl_GetBooleanFromObj(interp, objv[5],
1422 		    &transFlag) != TCL_OK)) {
1423 		return TCL_ERROR;
1424 	    }
1425 	    if ((x < 0) || (x >= masterPtr->width)
1426 		|| (y < 0) || (y >= masterPtr->height)) {
1427 		Tcl_AppendResult(interp, Tcl_GetString(objv[0]),
1428 			" transparency set: coordinates out of range", NULL);
1429 		return TCL_ERROR;
1430 	    }
1431 
1432 	    setBox.x = x;
1433 	    setBox.y = y;
1434 	    setBox.width = 1;
1435 	    setBox.height = 1;
1436 	    pixelPtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
1437 
1438 	    if (transFlag) {
1439 		/*
1440 		 * Make pixel transparent.
1441 		 */
1442 
1443 		TkRegion clearRegion = TkCreateRegion();
1444 
1445 		TkUnionRectWithRegion(&setBox, clearRegion, clearRegion);
1446 		TkSubtractRegion(masterPtr->validRegion, clearRegion,
1447 			masterPtr->validRegion);
1448 		TkDestroyRegion(clearRegion);
1449 
1450 		/*
1451 		 * Set the alpha value correctly.
1452 		 */
1453 
1454 		pixelPtr[3] = 0;
1455 	    } else {
1456 		/*
1457 		 * Make pixel opaque.
1458 		 */
1459 
1460 		TkUnionRectWithRegion(&setBox, masterPtr->validRegion,
1461 			masterPtr->validRegion);
1462 		pixelPtr[3] = 255;
1463 	    }
1464 
1465 	    /*
1466 	     * Inform the generic image code that the image
1467 	     * has (potentially) changed.
1468 	     */
1469 
1470 	    Tk_ImageChanged(masterPtr->tkMaster, x, y, 1, 1,
1471 		    masterPtr->width, masterPtr->height);
1472 	    masterPtr->flags &= ~IMAGE_CHANGED;
1473 	    return TCL_OK;
1474 	}
1475 
1476 	}
1477 	Tcl_Panic("unexpected fallthrough");
1478     }
1479 
1480     case PHOTO_WRITE: {
1481 	char *data;
1482 	Tcl_Obj *format;
1483 
1484 	/*
1485 	 * Prevent file system access in safe interpreters.
1486 	 */
1487 
1488 	if (Tcl_IsSafe(interp)) {
1489 	    Tcl_AppendResult(interp, "can't write image to a file in a",
1490 		    " safe interpreter", NULL);
1491 	    return TCL_ERROR;
1492 	}
1493 
1494 	/*
1495 	 * photo write command - first parse and check any options given.
1496 	 */
1497 
1498 	index = 2;
1499 	memset(&options, 0, sizeof(options));
1500 	options.name = NULL;
1501 	options.format = NULL;
1502 	if (ParseSubcommandOptions(&options, interp,
1503 		OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
1504 		&index, objc, objv) != TCL_OK) {
1505 	    return TCL_ERROR;
1506 	}
1507 	if ((options.name == NULL) || (index < objc)) {
1508 	    Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
1509 	    return TCL_ERROR;
1510 	}
1511 	if ((options.fromX > masterPtr->width)
1512 		|| (options.fromY > masterPtr->height)
1513 		|| (options.fromX2 > masterPtr->width)
1514 		|| (options.fromY2 > masterPtr->height)) {
1515 	    Tcl_AppendResult(interp, "coordinates for -from option extend ",
1516 		    "outside image", NULL);
1517 	    return TCL_ERROR;
1518 	}
1519 
1520 	/*
1521 	 * Fill in default values for unspecified parameters.
1522 	 */
1523 
1524 	if (!(options.options & OPT_FROM) || (options.fromX2 < 0)) {
1525 	    options.fromX2 = masterPtr->width;
1526 	    options.fromY2 = masterPtr->height;
1527 	}
1528 
1529 	/*
1530 	 * Search for an appropriate image file format handler, and give an
1531 	 * error if none is found.
1532 	 */
1533 
1534 	matched = 0;
1535 	for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
1536 		imageFormat = imageFormat->nextPtr) {
1537 	    if ((options.format == NULL)
1538 		    || (strncasecmp(Tcl_GetString(options.format),
1539 		    imageFormat->name, strlen(imageFormat->name)) == 0)) {
1540 		matched = 1;
1541 		if (imageFormat->fileWriteProc != NULL) {
1542 		    break;
1543 		}
1544 	    }
1545 	}
1546 	if (imageFormat == NULL) {
1547 	    oldformat = 1;
1548 	    for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
1549 		    imageFormat = imageFormat->nextPtr) {
1550 		if ((options.format == NULL)
1551 			|| (strncasecmp(Tcl_GetString(options.format),
1552 			imageFormat->name, strlen(imageFormat->name)) == 0)) {
1553 		    matched = 1;
1554 		    if (imageFormat->fileWriteProc != NULL) {
1555 			break;
1556 		    }
1557 		}
1558 	    }
1559 	}
1560 	if (imageFormat == NULL) {
1561 	    if (options.format == NULL) {
1562 		Tcl_AppendResult(interp, "no available image file format ",
1563 			"has file writing capability", NULL);
1564 	    } else if (!matched) {
1565 		Tcl_AppendResult(interp, "image file format \"",
1566 			Tcl_GetString(options.format),
1567 			"\" is unknown", NULL);
1568 	    } else {
1569 		Tcl_AppendResult(interp, "image file format \"",
1570 			Tcl_GetString(options.format),
1571 			"\" has no file writing capability", NULL);
1572 	    }
1573 	    return TCL_ERROR;
1574 	}
1575 
1576 	/*
1577 	 * Call the handler's file write function to write out the image.
1578 	 */
1579 
1580 	data = ImgGetPhoto(masterPtr, &block, &options);
1581 	format = options.format;
1582 	if (oldformat && format) {
1583 	    format = (Tcl_Obj *) Tcl_GetString(options.format);
1584 	}
1585 	result = (*imageFormat->fileWriteProc)(interp,
1586 		Tcl_GetString(options.name), format, &block);
1587 	if (options.background) {
1588 	    Tk_FreeColor(options.background);
1589 	}
1590 	if (data) {
1591 	    ckfree(data);
1592 	}
1593 	return result;
1594     }
1595 
1596     }
1597     Tcl_Panic("unexpected fallthrough");
1598     return TCL_ERROR; /* NOT REACHED */
1599 }
1600 
1601 /*
1602  *----------------------------------------------------------------------
1603  *
1604  * ParseSubcommandOptions --
1605  *
1606  *	This function is invoked to process one of the options which may be
1607  *	specified for the photo image subcommands, namely, -from, -to, -zoom,
1608  *	-subsample, -format, -shrink, and -compositingrule.
1609  *
1610  * Results:
1611  *	A standard Tcl result.
1612  *
1613  * Side effects:
1614  *	Fields in *optPtr get filled in.
1615  *
1616  *----------------------------------------------------------------------
1617  */
1618 
1619 static int
ParseSubcommandOptions(struct SubcommandOptions * optPtr,Tcl_Interp * interp,int allowedOptions,int * optIndexPtr,int objc,Tcl_Obj * const objv[])1620 ParseSubcommandOptions(
1621     struct SubcommandOptions *optPtr,
1622 				/* Information about the options specified and
1623 				 * the values given is returned here. */
1624     Tcl_Interp *interp,		/* Interpreter to use for reporting errors. */
1625     int allowedOptions,		/* Indicates which options are valid for the
1626 				 * current command. */
1627     int *optIndexPtr,		/* Points to a variable containing the current
1628 				 * index in objv; this variable is updated by
1629 				 * this function. */
1630     int objc,			/* Number of arguments in objv[]. */
1631     Tcl_Obj *const objv[])	/* Arguments to be parsed. */
1632 {
1633     int index, c, bit, currentBit, length;
1634     int values[4], numValues, maxValues, argIndex;
1635     char *option;
1636     const char *const *listPtr;
1637 
1638     for (index = *optIndexPtr; index < objc; *optIndexPtr = ++index) {
1639 	/*
1640 	 * We can have one value specified without an option; it goes into
1641 	 * optPtr->name.
1642 	 */
1643 
1644 	option = Tcl_GetStringFromObj(objv[index], &length);
1645 	if (option[0] != '-') {
1646 	    if (optPtr->name == NULL) {
1647 		optPtr->name = objv[index];
1648 		continue;
1649 	    }
1650 	    break;
1651 	}
1652 
1653 	/*
1654 	 * Work out which option this is.
1655 	 */
1656 
1657 	c = option[0];
1658 	bit = 0;
1659 	currentBit = 1;
1660 	for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
1661 	    if ((c == *listPtr[0])
1662 		    && (strncmp(option, *listPtr, (size_t) length) == 0)) {
1663 		if (bit != 0) {
1664 		    bit = 0;	/* An ambiguous option. */
1665 		    break;
1666 		}
1667 		bit = currentBit;
1668 	    }
1669 	    currentBit <<= 1;
1670 	}
1671 
1672 	/*
1673 	 * If this option is not recognized and allowed, put an error message
1674 	 * in the interpreter and return.
1675 	 */
1676 
1677 	if ((allowedOptions & bit) == 0) {
1678 	    Tcl_AppendResult(interp, "unrecognized option \"",
1679 	    	    Tcl_GetString(objv[index]),
1680 		    "\": must be ", NULL);
1681 	    bit = 1;
1682 	    for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
1683 		if ((allowedOptions & bit) != 0) {
1684 		    if ((allowedOptions & (bit - 1)) != 0) {
1685 			Tcl_AppendResult(interp, ", ", NULL);
1686 			if ((allowedOptions & ~((bit << 1) - 1)) == 0) {
1687 			    Tcl_AppendResult(interp, "or ", NULL);
1688 			}
1689 		    }
1690 		    Tcl_AppendResult(interp, *listPtr, NULL);
1691 		}
1692 		bit <<= 1;
1693 	    }
1694 	    return TCL_ERROR;
1695 	}
1696 
1697 	/*
1698 	 * For the -from, -to, -zoom and -subsample options, parse the values
1699 	 * given. Report an error if too few or too many values are given.
1700 	 */
1701 
1702 	if (bit == OPT_BACKGROUND) {
1703 	    /*
1704 	     * The -background option takes a single XColor value.
1705 	     */
1706 
1707 	    if (index + 1 < objc) {
1708 		*optIndexPtr = ++index;
1709 		optPtr->background = Tk_GetColor(interp, Tk_MainWindow(interp),
1710 			Tk_GetUid(Tcl_GetString(objv[index])));
1711 		if (!optPtr->background) {
1712 		    return TCL_ERROR;
1713 		}
1714 	    } else {
1715 		Tcl_AppendResult(interp, "the \"-background\" option ",
1716 			"requires a value", NULL);
1717 		return TCL_ERROR;
1718 	    }
1719 	} else if (bit == OPT_FORMAT) {
1720 	    /*
1721 	     * The -format option takes a single string value. Note that
1722 	     * parsing this is outside the scope of this function.
1723 	     */
1724 
1725 	    if (index + 1 < objc) {
1726 		*optIndexPtr = ++index;
1727 		optPtr->format = objv[index];
1728 	    } else {
1729 		Tcl_AppendResult(interp, "the \"-format\" option ",
1730 			"requires a value", NULL);
1731 		return TCL_ERROR;
1732 	    }
1733 	} else if (bit == OPT_COMPOSITE) {
1734 	    /*
1735 	     * The -compositingrule option takes a single value from a
1736 	     * well-known set.
1737 	     */
1738 
1739 	    if (index + 1 < objc) {
1740 		/*
1741 		 * Note that these must match the TK_PHOTO_COMPOSITE_*
1742 		 * constants.
1743 		 */
1744 
1745 		static const char *compositingRules[] = {
1746 		    "overlay", "set", NULL
1747 		};
1748 
1749 		index++;
1750 		if (Tcl_GetIndexFromObj(interp, objv[index], compositingRules,
1751 			"compositing rule", 0, &optPtr->compositingRule)
1752 			!= TCL_OK) {
1753 		    return TCL_ERROR;
1754 		}
1755 		*optIndexPtr = index;
1756 	    } else {
1757 		Tcl_AppendResult(interp, "the \"-compositingrule\" option ",
1758 			"requires a value", NULL);
1759 		return TCL_ERROR;
1760 	    }
1761 	} else if ((bit != OPT_SHRINK) && (bit != OPT_GRAYSCALE)) {
1762 	    char *val;
1763 	    maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2;
1764 	    argIndex = index + 1;
1765 	    for (numValues = 0; numValues < maxValues; ++numValues) {
1766 		if (argIndex >= objc) {
1767 		    break;
1768 		}
1769 		val = Tcl_GetString(objv[argIndex]);
1770 		if ((argIndex < objc) && (isdigit(UCHAR(val[0]))
1771 			|| ((val[0] == '-') && isdigit(UCHAR(val[1]))))) {
1772 		    if (Tcl_GetInt(interp, val, &values[numValues])
1773 			    != TCL_OK) {
1774 			return TCL_ERROR;
1775 		    }
1776 		} else {
1777 		    break;
1778 		}
1779 		++argIndex;
1780 	    }
1781 
1782 	    if (numValues == 0) {
1783 		Tcl_AppendResult(interp, "the \"", option, "\" option ",
1784 			 "requires one ", maxValues == 2? "or two": "to four",
1785 			 " integer values", NULL);
1786 		return TCL_ERROR;
1787 	    }
1788 	    *optIndexPtr = (index += numValues);
1789 
1790 	    /*
1791 	     * Y values default to the corresponding X value if not specified.
1792 	     */
1793 
1794 	    if (numValues == 1) {
1795 		values[1] = values[0];
1796 	    }
1797 	    if (numValues == 3) {
1798 		values[3] = values[2];
1799 	    }
1800 
1801 	    /*
1802 	     * Check the values given and put them in the appropriate field of
1803 	     * the SubcommandOptions structure.
1804 	     */
1805 
1806 	    switch (bit) {
1807 	    case OPT_FROM:
1808 		if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
1809 			&& ((values[2] < 0) || (values[3] < 0)))) {
1810 		    Tcl_AppendResult(interp, "value(s) for the -from",
1811 			    " option must be non-negative", NULL);
1812 		    return TCL_ERROR;
1813 		}
1814 		if (numValues <= 2) {
1815 		    optPtr->fromX = values[0];
1816 		    optPtr->fromY = values[1];
1817 		    optPtr->fromX2 = -1;
1818 		    optPtr->fromY2 = -1;
1819 		} else {
1820 		    optPtr->fromX = MIN(values[0], values[2]);
1821 		    optPtr->fromY = MIN(values[1], values[3]);
1822 		    optPtr->fromX2 = MAX(values[0], values[2]);
1823 		    optPtr->fromY2 = MAX(values[1], values[3]);
1824 		}
1825 		break;
1826 	    case OPT_SUBSAMPLE:
1827 		optPtr->subsampleX = values[0];
1828 		optPtr->subsampleY = values[1];
1829 		break;
1830 	    case OPT_TO:
1831 		if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
1832 			&& ((values[2] < 0) || (values[3] < 0)))) {
1833 		    Tcl_AppendResult(interp, "value(s) for the -to",
1834 			    " option must be non-negative", NULL);
1835 		    return TCL_ERROR;
1836 		}
1837 		if (numValues <= 2) {
1838 		    optPtr->toX = values[0];
1839 		    optPtr->toY = values[1];
1840 		    optPtr->toX2 = -1;
1841 		    optPtr->toY2 = -1;
1842 		} else {
1843 		    optPtr->toX = MIN(values[0], values[2]);
1844 		    optPtr->toY = MIN(values[1], values[3]);
1845 		    optPtr->toX2 = MAX(values[0], values[2]);
1846 		    optPtr->toY2 = MAX(values[1], values[3]);
1847 		}
1848 		break;
1849 	    case OPT_ZOOM:
1850 		if ((values[0] <= 0) || (values[1] <= 0)) {
1851 		    Tcl_AppendResult(interp, "value(s) for the -zoom",
1852 			    " option must be positive", NULL);
1853 		    return TCL_ERROR;
1854 		}
1855 		optPtr->zoomX = values[0];
1856 		optPtr->zoomY = values[1];
1857 		break;
1858 	    }
1859 	}
1860 
1861 	/*
1862 	 * Remember that we saw this option.
1863 	 */
1864 
1865 	optPtr->options |= bit;
1866     }
1867 
1868     return TCL_OK;
1869 }
1870 
1871 /*
1872  *----------------------------------------------------------------------
1873  *
1874  * ImgPhotoConfigureMaster --
1875  *
1876  *	This function is called when a photo image is created or reconfigured.
1877  *	It processes configuration options and resets any instances of the
1878  *	image.
1879  *
1880  * Results:
1881  *	A standard Tcl return value. If TCL_ERROR is returned then an error
1882  *	message is left in the masterPtr->interp's result.
1883  *
1884  * Side effects:
1885  *	Existing instances of the image will be redisplayed to match the new
1886  *	configuration options.
1887  *
1888  *----------------------------------------------------------------------
1889  */
1890 
1891 static int
ImgPhotoConfigureMaster(Tcl_Interp * interp,PhotoMaster * masterPtr,int objc,Tcl_Obj * const objv[],int flags)1892 ImgPhotoConfigureMaster(
1893     Tcl_Interp *interp,		/* Interpreter to use for reporting errors. */
1894     PhotoMaster *masterPtr,	/* Pointer to data structure describing
1895 				 * overall photo image to (re)configure. */
1896     int objc,			/* Number of entries in objv. */
1897     Tcl_Obj *const objv[],	/* Pairs of configuration options for image. */
1898     int flags)			/* Flags to pass to Tk_ConfigureWidget, such
1899 				 * as TK_CONFIG_ARGV_ONLY. */
1900 {
1901     PhotoInstance *instancePtr;
1902     const char *oldFileString, *oldPaletteString;
1903     Tcl_Obj *oldData, *data = NULL, *oldFormat, *format = NULL;
1904     Tcl_Obj *tempdata, *tempformat;
1905     int length, i, j, result, imageWidth, imageHeight, oldformat;
1906     double oldGamma;
1907     Tcl_Channel chan;
1908     Tk_PhotoImageFormat *imageFormat;
1909     const char **args;
1910 
1911     args = (const char **) ckalloc((objc + 1) * sizeof(char *));
1912     for (i = 0, j = 0; i < objc; i++,j++) {
1913 	args[j] = Tcl_GetStringFromObj(objv[i], &length);
1914 	if ((length > 1) && (args[j][0] == '-')) {
1915 	    if ((args[j][1] == 'd') &&
1916 		    !strncmp(args[j], "-data", (size_t) length)) {
1917 		if (++i < objc) {
1918 		    data = objv[i];
1919 		    j--;
1920 		} else {
1921 		    Tcl_AppendResult(interp,
1922 			    "value for \"-data\" missing", NULL);
1923 		    return TCL_ERROR;
1924 		}
1925 	    } else if ((args[j][1] == 'f') &&
1926 		    !strncmp(args[j], "-format", (size_t) length)) {
1927 		if (++i < objc) {
1928 		    format = objv[i];
1929 		    j--;
1930 		} else {
1931 		    Tcl_AppendResult(interp,
1932 			    "value for \"-format\" missing", NULL);
1933 		    return TCL_ERROR;
1934 		}
1935 	    }
1936 	}
1937     }
1938 
1939     /*
1940      * Save the current values for fileString and dataString, so we can tell
1941      * if the user specifies them anew. IMPORTANT: if the format changes we
1942      * have to interpret "-file" and "-data" again as well! It might be that
1943      * the format string influences how "-data" or "-file" is interpreted.
1944      */
1945 
1946     oldFileString = masterPtr->fileString;
1947     if (oldFileString == NULL) {
1948 	oldData = masterPtr->dataString;
1949 	if (oldData != NULL) {
1950 	    Tcl_IncrRefCount(oldData);
1951 	}
1952     } else {
1953 	oldData = NULL;
1954     }
1955     oldFormat = masterPtr->format;
1956     if (oldFormat != NULL) {
1957 	Tcl_IncrRefCount(oldFormat);
1958     }
1959     oldPaletteString = masterPtr->palette;
1960     oldGamma = masterPtr->gamma;
1961 
1962     /*
1963      * Process the configuration options specified.
1964      */
1965 
1966     if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs,
1967 	    j, args, (char *) masterPtr, flags) != TCL_OK) {
1968 	ckfree((char *) args);
1969 	goto errorExit;
1970     }
1971     ckfree((char *) args);
1972 
1973     /*
1974      * Regard the empty string for -file, -data or -format as the null value.
1975      */
1976 
1977     if ((masterPtr->fileString != NULL) && (masterPtr->fileString[0] == 0)) {
1978 	ckfree(masterPtr->fileString);
1979 	masterPtr->fileString = NULL;
1980     }
1981     if (data) {
1982 	/*
1983 	 * Force into ByteArray format, which most (all) image handlers will
1984 	 * use anyway. Empty length means ignore the -data option.
1985 	 */
1986 
1987 	(void) Tcl_GetByteArrayFromObj(data, &length);
1988 	if (length) {
1989 	    Tcl_IncrRefCount(data);
1990 	} else {
1991 	    data = NULL;
1992 	}
1993 	if (masterPtr->dataString) {
1994 	    Tcl_DecrRefCount(masterPtr->dataString);
1995 	}
1996 	masterPtr->dataString = data;
1997     }
1998     if (format) {
1999 	/*
2000 	 * Stringify to ignore -format "". It may come in as a list or other
2001 	 * object.
2002 	 */
2003 
2004 	(void) Tcl_GetStringFromObj(format, &length);
2005 	if (length) {
2006 	    Tcl_IncrRefCount(format);
2007 	} else {
2008 	    format = NULL;
2009 	}
2010 	if (masterPtr->format) {
2011 	    Tcl_DecrRefCount(masterPtr->format);
2012 	}
2013 	masterPtr->format = format;
2014     }
2015     /*
2016      * Set the image to the user-requested size, if any, and make sure storage
2017      * is correctly allocated for this image.
2018      */
2019 
2020     if (ImgPhotoSetSize(masterPtr, masterPtr->width,
2021 	    masterPtr->height) != TCL_OK) {
2022 	Tcl_ResetResult(interp);
2023 	Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
2024 	goto errorExit;
2025     }
2026 
2027     /*
2028      * Read in the image from the file or string if the user has specified the
2029      * -file or -data option.
2030      */
2031 
2032     if ((masterPtr->fileString != NULL)
2033 	    && ((masterPtr->fileString != oldFileString)
2034 	    || (masterPtr->format != oldFormat))) {
2035 
2036 	/*
2037 	 * Prevent file system access in a safe interpreter.
2038 	 */
2039 
2040 	if (Tcl_IsSafe(interp)) {
2041 	    Tcl_ResetResult(interp);
2042 	    Tcl_AppendResult(interp,
2043 		    "can't get image from a file in a safe interpreter", NULL);
2044 	    goto errorExit;
2045 	}
2046 
2047 	chan = Tcl_OpenFileChannel(interp, masterPtr->fileString, "r", 0);
2048 	if (chan == NULL) {
2049 	    goto errorExit;
2050 	}
2051 
2052 	/*
2053 	 * -translation binary also sets -encoding binary
2054 	 */
2055 
2056 	if ((Tcl_SetChannelOption(interp, chan,
2057 		"-translation", "binary") != TCL_OK) ||
2058 		(MatchFileFormat(interp, chan, masterPtr->fileString,
2059 			masterPtr->format, &imageFormat, &imageWidth,
2060 			&imageHeight, &oldformat) != TCL_OK)) {
2061 	    Tcl_Close(NULL, chan);
2062 	    goto errorExit;
2063 	}
2064 	result = ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
2065 	if (result != TCL_OK) {
2066 	    Tcl_Close(NULL, chan);
2067 	    Tcl_ResetResult(interp);
2068 	    Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
2069 	    goto errorExit;
2070 	}
2071 	tempformat = masterPtr->format;
2072 	if (oldformat && tempformat) {
2073 	    tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
2074 	}
2075 	result = (*imageFormat->fileReadProc)(interp, chan,
2076 		masterPtr->fileString, tempformat, (Tk_PhotoHandle) masterPtr,
2077 		0, 0, imageWidth, imageHeight, 0, 0);
2078 	Tcl_Close(NULL, chan);
2079 	if (result != TCL_OK) {
2080 	    goto errorExit;
2081 	}
2082 
2083 	Tcl_ResetResult(interp);
2084 	masterPtr->flags |= IMAGE_CHANGED;
2085     }
2086 
2087     if ((masterPtr->fileString == NULL) && (masterPtr->dataString != NULL)
2088 	    && ((masterPtr->dataString != oldData)
2089 		    || (masterPtr->format != oldFormat))) {
2090 
2091 	if (MatchStringFormat(interp, masterPtr->dataString,
2092 		masterPtr->format, &imageFormat, &imageWidth,
2093 		&imageHeight, &oldformat) != TCL_OK) {
2094 	    goto errorExit;
2095 	}
2096 	if (ImgPhotoSetSize(masterPtr, imageWidth, imageHeight) != TCL_OK) {
2097 	    Tcl_ResetResult(interp);
2098 	    Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
2099 	    goto errorExit;
2100 	}
2101 	tempformat = masterPtr->format;
2102 	tempdata = masterPtr->dataString;
2103 	if (oldformat) {
2104 	    if (tempformat) {
2105 		tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
2106 	    }
2107 	    tempdata = (Tcl_Obj *) Tcl_GetString(tempdata);
2108 	}
2109 	if ((*imageFormat->stringReadProc)(interp, tempdata,
2110 		tempformat, (Tk_PhotoHandle) masterPtr,
2111 		0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) {
2112 	    goto errorExit;
2113 	}
2114 
2115 	Tcl_ResetResult(interp);
2116 	masterPtr->flags |= IMAGE_CHANGED;
2117     }
2118 
2119     /*
2120      * Enforce a reasonable value for gamma.
2121      */
2122 
2123     if (masterPtr->gamma <= 0) {
2124 	masterPtr->gamma = 1.0;
2125     }
2126 
2127     if ((masterPtr->gamma != oldGamma)
2128 	    || (masterPtr->palette != oldPaletteString)) {
2129 	masterPtr->flags |= IMAGE_CHANGED;
2130     }
2131 
2132     /*
2133      * Cycle through all of the instances of this image, regenerating the
2134      * information for each instance. Then force the image to be redisplayed
2135      * everywhere that it is used.
2136      */
2137 
2138     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
2139 	    instancePtr = instancePtr->nextPtr) {
2140 	ImgPhotoConfigureInstance(instancePtr);
2141     }
2142 
2143     /*
2144      * Inform the generic image code that the image has (potentially) changed.
2145      */
2146 
2147     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
2148 	    masterPtr->height, masterPtr->width, masterPtr->height);
2149     masterPtr->flags &= ~IMAGE_CHANGED;
2150 
2151     if (oldData != NULL) {
2152 	Tcl_DecrRefCount(oldData);
2153     }
2154     if (oldFormat != NULL) {
2155 	Tcl_DecrRefCount(oldFormat);
2156     }
2157 
2158     ToggleComplexAlphaIfNeeded(masterPtr);
2159 
2160     return TCL_OK;
2161 
2162   errorExit:
2163     if (oldData != NULL) {
2164 	Tcl_DecrRefCount(oldData);
2165     }
2166     if (oldFormat != NULL) {
2167 	Tcl_DecrRefCount(oldFormat);
2168     }
2169     return TCL_ERROR;
2170 }
2171 
2172 /*
2173  *----------------------------------------------------------------------
2174  *
2175  * ImgPhotoConfigureInstance --
2176  *
2177  *	This function is called to create displaying information for a photo
2178  *	image instance based on the configuration information in the master.
2179  *	It is invoked both when new instances are created and when the master
2180  *	is reconfigured.
2181  *
2182  * Results:
2183  *	None.
2184  *
2185  * Side effects:
2186  *	Generates errors via Tcl_BackgroundError if there are problems in
2187  *	setting up the instance.
2188  *
2189  *----------------------------------------------------------------------
2190  */
2191 
2192 static void
ImgPhotoConfigureInstance(PhotoInstance * instancePtr)2193 ImgPhotoConfigureInstance(
2194     PhotoInstance *instancePtr)	/* Instance to reconfigure. */
2195 {
2196     PhotoMaster *masterPtr = instancePtr->masterPtr;
2197     XImage *imagePtr;
2198     int bitsPerPixel;
2199     ColorTable *colorTablePtr;
2200     XRectangle validBox;
2201 
2202     /*
2203      * If the -palette configuration option has been set for the master, use
2204      * the value specified for our palette, but only if it is a valid palette
2205      * for our windows. Use the gamma value specified the master.
2206      */
2207 
2208     if ((masterPtr->palette && masterPtr->palette[0])
2209 	    && IsValidPalette(instancePtr, masterPtr->palette)) {
2210 	instancePtr->palette = masterPtr->palette;
2211     } else {
2212 	instancePtr->palette = instancePtr->defaultPalette;
2213     }
2214     instancePtr->gamma = masterPtr->gamma;
2215 
2216     /*
2217      * If we don't currently have a color table, or if the one we have no
2218      * longer applies (e.g. because our palette or gamma has changed), get a
2219      * new one.
2220      */
2221 
2222     colorTablePtr = instancePtr->colorTablePtr;
2223     if ((colorTablePtr == NULL)
2224 	    || (instancePtr->colormap != colorTablePtr->id.colormap)
2225 	    || (instancePtr->palette != colorTablePtr->id.palette)
2226 	    || (instancePtr->gamma != colorTablePtr->id.gamma)) {
2227 	/*
2228 	 * Free up our old color table, and get a new one.
2229 	 */
2230 
2231 	if (colorTablePtr != NULL) {
2232 	    colorTablePtr->liveRefCount -= 1;
2233 	    FreeColorTable(colorTablePtr, 0);
2234 	}
2235 	GetColorTable(instancePtr);
2236 
2237 	/*
2238 	 * Create a new XImage structure for sending data to the X server, if
2239 	 * necessary.
2240 	 */
2241 
2242 	if (instancePtr->colorTablePtr->flags & BLACK_AND_WHITE) {
2243 	    bitsPerPixel = 1;
2244 	} else {
2245 	    bitsPerPixel = instancePtr->visualInfo.depth;
2246 	}
2247 
2248 	if ((instancePtr->imagePtr == NULL)
2249 		|| (instancePtr->imagePtr->bits_per_pixel != bitsPerPixel)) {
2250 	    if (instancePtr->imagePtr != NULL) {
2251 		XDestroyImage(instancePtr->imagePtr);
2252 	    }
2253 	    imagePtr = XCreateImage(instancePtr->display,
2254 		    instancePtr->visualInfo.visual, (unsigned) bitsPerPixel,
2255 		    (bitsPerPixel > 1? ZPixmap: XYBitmap), 0, NULL,
2256 		    1, 1, 32, 0);
2257 	    instancePtr->imagePtr = imagePtr;
2258 
2259 	    /*
2260 	     * We create images using the local host's endianness, rather than
2261 	     * the endianness of the server; otherwise we would have to
2262 	     * byte-swap any 16 or 32 bit values that we store in the image
2263 	     * if the server's endianness is different from ours.
2264 	     */
2265 
2266 	    if (imagePtr != NULL) {
2267 #ifdef WORDS_BIGENDIAN
2268 		imagePtr->byte_order = MSBFirst;
2269 #else
2270 		imagePtr->byte_order = LSBFirst;
2271 #endif
2272 		_XInitImageFuncPtrs(imagePtr);
2273 	    }
2274 	}
2275     }
2276 
2277     /*
2278      * If the user has specified a width and/or height for the master which is
2279      * different from our current width/height, set the size to the values
2280      * specified by the user. If we have no pixmap, we do this also, since it
2281      * has the side effect of allocating a pixmap for us.
2282      */
2283 
2284     if ((instancePtr->pixels == None) || (instancePtr->error == NULL)
2285 	    || (instancePtr->width != masterPtr->width)
2286 	    || (instancePtr->height != masterPtr->height)) {
2287 	ImgPhotoInstanceSetSize(instancePtr);
2288     }
2289 
2290     /*
2291      * Redither this instance if necessary.
2292      */
2293 
2294     if ((masterPtr->flags & IMAGE_CHANGED)
2295 	    || (instancePtr->colorTablePtr != colorTablePtr)) {
2296 	TkClipBox(masterPtr->validRegion, &validBox);
2297 	if ((validBox.width > 0) && (validBox.height > 0)) {
2298 	    DitherInstance(instancePtr, validBox.x, validBox.y,
2299 		    validBox.width, validBox.height);
2300 	}
2301     }
2302 }
2303 
2304 /*
2305  *----------------------------------------------------------------------
2306  *
2307  * ImgPhotoGet --
2308  *
2309  *	This function is called for each use of a photo image in a widget.
2310  *
2311  * Results:
2312  *	The return value is a token for the instance, which is passed back to
2313  *	us in calls to ImgPhotoDisplay and ImgPhotoFree.
2314  *
2315  * Side effects:
2316  *	A data structure is set up for the instance (or, an existing instance
2317  *	is re-used for the new one).
2318  *
2319  *----------------------------------------------------------------------
2320  */
2321 
2322 static ClientData
ImgPhotoGet(Tk_Window tkwin,ClientData masterData)2323 ImgPhotoGet(
2324     Tk_Window tkwin,		/* Window in which the instance will be
2325 				 * used. */
2326     ClientData masterData)	/* Pointer to our master structure for the
2327 				 * image. */
2328 {
2329     PhotoMaster *masterPtr = (PhotoMaster *) masterData;
2330     PhotoInstance *instancePtr;
2331     Colormap colormap;
2332     int mono, nRed, nGreen, nBlue, numVisuals;
2333     XVisualInfo visualInfo, *visInfoPtr;
2334     char buf[TCL_INTEGER_SPACE * 3];
2335     XColor *white, *black;
2336     XGCValues gcValues;
2337 
2338     /*
2339      * Table of "best" choices for palette for PseudoColor displays with
2340      * between 3 and 15 bits/pixel.
2341      */
2342 
2343     static const int paletteChoice[13][3] = {
2344 	/*  #red, #green, #blue */
2345 	 {2,  2,  2,		/* 3 bits, 8 colors */},
2346 	 {2,  3,  2,		/* 4 bits, 12 colors */},
2347 	 {3,  4,  2,		/* 5 bits, 24 colors */},
2348 	 {4,  5,  3,		/* 6 bits, 60 colors */},
2349 	 {5,  6,  4,		/* 7 bits, 120 colors */},
2350 	 {7,  7,  4,		/* 8 bits, 198 colors */},
2351 	 {8, 10,  6,		/* 9 bits, 480 colors */},
2352 	{10, 12,  8,		/* 10 bits, 960 colors */},
2353 	{14, 15,  9,		/* 11 bits, 1890 colors */},
2354 	{16, 20, 12,		/* 12 bits, 3840 colors */},
2355 	{20, 24, 16,		/* 13 bits, 7680 colors */},
2356 	{26, 30, 20,		/* 14 bits, 15600 colors */},
2357 	{32, 32, 30,		/* 15 bits, 30720 colors */}
2358     };
2359 
2360     /*
2361      * See if there is already an instance for windows using the same
2362      * colormap. If so then just re-use it.
2363      */
2364 
2365     colormap = Tk_Colormap(tkwin);
2366     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
2367 	    instancePtr = instancePtr->nextPtr) {
2368 	if ((colormap == instancePtr->colormap)
2369 		&& (Tk_Display(tkwin) == instancePtr->display)) {
2370 	    /*
2371 	     * Re-use this instance.
2372 	     */
2373 
2374 	    if (instancePtr->refCount == 0) {
2375 		/*
2376 		 * We are resurrecting this instance.
2377 		 */
2378 
2379 		Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
2380 		if (instancePtr->colorTablePtr != NULL) {
2381 		    FreeColorTable(instancePtr->colorTablePtr, 0);
2382 		}
2383 		GetColorTable(instancePtr);
2384 	    }
2385 	    instancePtr->refCount++;
2386 	    return (ClientData) instancePtr;
2387 	}
2388     }
2389 
2390     /*
2391      * The image isn't already in use in a window with the same colormap. Make
2392      * a new instance of the image.
2393      */
2394 
2395     instancePtr = (PhotoInstance *) ckalloc(sizeof(PhotoInstance));
2396     instancePtr->masterPtr = masterPtr;
2397     instancePtr->display = Tk_Display(tkwin);
2398     instancePtr->colormap = Tk_Colormap(tkwin);
2399     Tk_PreserveColormap(instancePtr->display, instancePtr->colormap);
2400     instancePtr->refCount = 1;
2401     instancePtr->colorTablePtr = NULL;
2402     instancePtr->pixels = None;
2403     instancePtr->error = NULL;
2404     instancePtr->width = 0;
2405     instancePtr->height = 0;
2406     instancePtr->imagePtr = 0;
2407     instancePtr->nextPtr = masterPtr->instancePtr;
2408     masterPtr->instancePtr = instancePtr;
2409 
2410     /*
2411      * Obtain information about the visual and decide on the default palette.
2412      */
2413 
2414     visualInfo.screen = Tk_ScreenNumber(tkwin);
2415     visualInfo.visualid = XVisualIDFromVisual(Tk_Visual(tkwin));
2416     visInfoPtr = XGetVisualInfo(Tk_Display(tkwin),
2417 	    VisualScreenMask | VisualIDMask, &visualInfo, &numVisuals);
2418     if (visInfoPtr == NULL) {
2419 	Tcl_Panic("ImgPhotoGet couldn't find visual for window");
2420     }
2421 
2422     nRed = 2;
2423     nGreen = nBlue = 0;
2424     mono = 1;
2425     instancePtr->visualInfo = *visInfoPtr;
2426     switch (visInfoPtr->class) {
2427     case DirectColor:
2428     case TrueColor:
2429 	nRed = 1 << CountBits(visInfoPtr->red_mask);
2430 	nGreen = 1 << CountBits(visInfoPtr->green_mask);
2431 	nBlue = 1 << CountBits(visInfoPtr->blue_mask);
2432 	mono = 0;
2433 	break;
2434     case PseudoColor:
2435     case StaticColor:
2436 	if (visInfoPtr->depth > 15) {
2437 	    nRed = 32;
2438 	    nGreen = 32;
2439 	    nBlue = 32;
2440 	    mono = 0;
2441 	} else if (visInfoPtr->depth >= 3) {
2442 	    const int *ip = paletteChoice[visInfoPtr->depth - 3];
2443 
2444 	    nRed = ip[0];
2445 	    nGreen = ip[1];
2446 	    nBlue = ip[2];
2447 	    mono = 0;
2448 	}
2449 	break;
2450     case GrayScale:
2451     case StaticGray:
2452 	nRed = 1 << visInfoPtr->depth;
2453 	break;
2454     }
2455     XFree((char *) visInfoPtr);
2456 
2457     if (mono) {
2458 	sprintf(buf, "%d", nRed);
2459     } else {
2460 	sprintf(buf, "%d/%d/%d", nRed, nGreen, nBlue);
2461     }
2462     instancePtr->defaultPalette = Tk_GetUid(buf);
2463 
2464     /*
2465      * Make a GC with background = black and foreground = white.
2466      */
2467 
2468     white = Tk_GetColor(masterPtr->interp, tkwin, "white");
2469     black = Tk_GetColor(masterPtr->interp, tkwin, "black");
2470     gcValues.foreground = (white != NULL)? white->pixel:
2471 	    WhitePixelOfScreen(Tk_Screen(tkwin));
2472     gcValues.background = (black != NULL)? black->pixel:
2473 	    BlackPixelOfScreen(Tk_Screen(tkwin));
2474     Tk_FreeColor(white);
2475     Tk_FreeColor(black);
2476     gcValues.graphics_exposures = False;
2477     instancePtr->gc = Tk_GetGC(tkwin,
2478 	    GCForeground|GCBackground|GCGraphicsExposures, &gcValues);
2479 
2480     /*
2481      * Set configuration options and finish the initialization of the
2482      * instance. This will also dither the image if necessary.
2483      */
2484 
2485     ImgPhotoConfigureInstance(instancePtr);
2486 
2487     /*
2488      * If this is the first instance, must set the size of the image.
2489      */
2490 
2491     if (instancePtr->nextPtr == NULL) {
2492 	Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
2493 		masterPtr->width, masterPtr->height);
2494     }
2495 
2496     return (ClientData) instancePtr;
2497 }
2498 
2499 /*
2500  *----------------------------------------------------------------------
2501  *
2502  * ToggleComplexAlphaIfNeeded --
2503  *
2504  *	This function is called when an image is modified to check if any
2505  *	partially transparent pixels exist, which requires blending instead of
2506  *	straight copy.
2507  *
2508  * Results:
2509  *	None.
2510  *
2511  * Side effects:
2512  *	(Re)sets COMPLEX_ALPHA flag of master.
2513  *
2514  *----------------------------------------------------------------------
2515  */
2516 
2517 static int
ToggleComplexAlphaIfNeeded(PhotoMaster * mPtr)2518 ToggleComplexAlphaIfNeeded(
2519     PhotoMaster *mPtr)
2520 {
2521     size_t len = MAX(mPtr->userWidth, mPtr->width) *
2522 	    MAX(mPtr->userHeight, mPtr->height) * 4;
2523     unsigned char *c = mPtr->pix32;
2524     unsigned char *end = c + len;
2525 
2526     /*
2527      * Set the COMPLEX_ALPHA flag if we have an image with partially
2528      * transparent bits.
2529      */
2530 
2531     mPtr->flags &= ~COMPLEX_ALPHA;
2532     c += 3;			/* Start at first alpha byte. */
2533     for (; c < end; c += 4) {
2534 	if (*c && *c != 255) {
2535      	    mPtr->flags |= COMPLEX_ALPHA;
2536 	    break;
2537 	}
2538     }
2539     return (mPtr->flags & COMPLEX_ALPHA);
2540 }
2541 
2542 /*
2543  *----------------------------------------------------------------------
2544  *
2545  * ImgPhotoBlendComplexAlpha --
2546  *
2547  *	This function is called when an image with partially transparent
2548  *	pixels must be drawn over another image. It blends the photo data onto
2549  *	a local copy of the surface that we are drawing on, *including* the
2550  *	pixels drawn by everything that should be drawn underneath the image.
2551  *
2552  *	Much of this code has hard-coded values in for speed because this
2553  *	routine is performance critical for complex image drawing.
2554  *
2555  * Results:
2556  *	None.
2557  *
2558  * Side effects:
2559  *	Background image passed in gets drawn over with image data.
2560  *
2561  * Notes:
2562  *	This should work on all platforms that set mask and shift data
2563  *	properly from the visualInfo. RGB is really only a 24+ bpp version
2564  *	whereas RGB15 is the correct version and works for 15bpp+, but it
2565  *	slower, so it's only used for 15bpp+.
2566  *
2567  *	Note that Win32 pre-defines those operations that we really need.
2568  *
2569  *----------------------------------------------------------------------
2570  */
2571 
2572 #ifndef __WIN32__
2573 #define GetRValue(rgb)	(UCHAR(((rgb) & red_mask) >> red_shift))
2574 #define GetGValue(rgb)	(UCHAR(((rgb) & green_mask) >> green_shift))
2575 #define GetBValue(rgb)	(UCHAR(((rgb) & blue_mask) >> blue_shift))
2576 #define RGB(r, g, b)	((unsigned)( \
2577 	(UCHAR(r) << red_shift)   | \
2578 	(UCHAR(g) << green_shift) | \
2579 	(UCHAR(b) << blue_shift)  ))
2580 #define RGB15(r, g, b)	((unsigned)( \
2581 	(((r) * red_mask / 255)   & red_mask)   | \
2582 	(((g) * green_mask / 255) & green_mask) | \
2583 	(((b) * blue_mask / 255)  & blue_mask)  ))
2584 #endif /* !__WIN32__ */
2585 
2586 static void
ImgPhotoBlendComplexAlpha(XImage * bgImg,PhotoInstance * iPtr,int xOffset,int yOffset,int width,int height)2587 ImgPhotoBlendComplexAlpha(
2588     XImage *bgImg,		/* Background image to draw on. */
2589     PhotoInstance *iPtr,	/* Image instance to draw. */
2590     int xOffset, int yOffset,	/* X & Y offset into image instance to
2591 				 * draw. */
2592     int width, int height)	/* Width & height of image to draw. */
2593 {
2594     int x, y, line;
2595     unsigned long pixel;
2596     unsigned char r, g, b, alpha, unalpha, *masterPtr;
2597     unsigned char *alphaAr = iPtr->masterPtr->pix32;
2598 
2599     /*
2600      * This blending is an integer version of the Source-Over compositing rule
2601      * (see Porter&Duff, "Compositing Digital Images", proceedings of SIGGRAPH
2602      * 1984) that has been hard-coded (for speed) to work with targetting a
2603      * solid surface.
2604      *
2605      * The 'unalpha' field must be 255-alpha; it is separated out to encourage
2606      * more efficient compilation.
2607      */
2608 
2609 #define ALPHA_BLEND(bgPix, imgPix, alpha, unalpha) \
2610 	((bgPix * unalpha + imgPix * alpha) / 255)
2611 
2612     /*
2613      * We have to get the mask and shift info from the visual on non-Win32 so
2614      * that the macros Get*Value(), RGB() and RGB15() work correctly. This
2615      * might be cached for better performance.
2616      */
2617 
2618 #ifndef __WIN32__
2619     unsigned long red_mask, green_mask, blue_mask;
2620     unsigned long red_shift, green_shift, blue_shift;
2621     Visual *visual = iPtr->visualInfo.visual;
2622 
2623     red_mask = visual->red_mask;
2624     green_mask = visual->green_mask;
2625     blue_mask = visual->blue_mask;
2626     red_shift = 0;
2627     green_shift = 0;
2628     blue_shift = 0;
2629     while ((0x0001 & (red_mask >> red_shift)) == 0) {
2630 	red_shift++;
2631     }
2632     while ((0x0001 & (green_mask >> green_shift)) == 0) {
2633 	green_shift++;
2634     }
2635     while ((0x0001 & (blue_mask >> blue_shift)) == 0) {
2636 	blue_shift++;
2637     }
2638 #endif /* !__WIN32__ */
2639 
2640     /*
2641      * Only UNIX requires the special case for <24bpp. It varies with 3 extra
2642      * shifts and uses RGB15. The 24+bpp version could also then be further
2643      * optimized.
2644      */
2645 
2646 #if !(defined(__WIN32__) || defined(MAC_OSX_TK))
2647     if (bgImg->depth < 24) {
2648 	unsigned char red_mlen, green_mlen, blue_mlen;
2649 
2650 	red_mlen = 8 - CountBits(red_mask >> red_shift);
2651 	green_mlen = 8 - CountBits(green_mask >> green_shift);
2652 	blue_mlen = 8 - CountBits(blue_mask >> blue_shift);
2653 	for (y = 0; y < height; y++) {
2654 	    line = (y + yOffset) * iPtr->masterPtr->width;
2655 	    for (x = 0; x < width; x++) {
2656 		masterPtr = alphaAr + ((line + x + xOffset) * 4);
2657 		alpha = masterPtr[3];
2658 
2659 		/*
2660 		 * Ignore pixels that are fully transparent
2661 		 */
2662 
2663 		if (alpha) {
2664 		    /*
2665 		     * We could perhaps be more efficient than XGetPixel for
2666 		     * 24 and 32 bit displays, but this seems "fast enough".
2667 		     */
2668 
2669 		    r = masterPtr[0];
2670 		    g = masterPtr[1];
2671 		    b = masterPtr[2];
2672 		    if (alpha != 255) {
2673 			/*
2674 			 * Only blend pixels that have some transparency
2675 			 */
2676 
2677 			unsigned char ra, ga, ba;
2678 
2679 			pixel = XGetPixel(bgImg, x, y);
2680 			ra = GetRValue(pixel) << red_mlen;
2681 			ga = GetGValue(pixel) << green_mlen;
2682 			ba = GetBValue(pixel) << blue_mlen;
2683 			unalpha = 255 - alpha;	/* Calculate once. */
2684 			r = ALPHA_BLEND(ra, r, alpha, unalpha);
2685 			g = ALPHA_BLEND(ga, g, alpha, unalpha);
2686 			b = ALPHA_BLEND(ba, b, alpha, unalpha);
2687 		    }
2688 		    XPutPixel(bgImg, x, y, RGB15(r, g, b));
2689 		}
2690 	    }
2691 	}
2692 	return;
2693     }
2694 #endif /* !__WIN32__ && !MAC_OSX_TK */
2695 
2696     for (y = 0; y < height; y++) {
2697 	line = (y + yOffset) * iPtr->masterPtr->width;
2698 	for (x = 0; x < width; x++) {
2699 	    masterPtr = alphaAr + ((line + x + xOffset) * 4);
2700 	    alpha = masterPtr[3];
2701 
2702 	    /*
2703 	     * Ignore pixels that are fully transparent
2704 	     */
2705 
2706 	    if (alpha) {
2707 		/*
2708 		 * We could perhaps be more efficient than XGetPixel for 24
2709 		 * and 32 bit displays, but this seems "fast enough".
2710 		 */
2711 
2712 		r = masterPtr[0];
2713 		g = masterPtr[1];
2714 		b = masterPtr[2];
2715 		if (alpha != 255) {
2716 		    /*
2717 		     * Only blend pixels that have some transparency
2718 		     */
2719 
2720 		    unsigned char ra, ga, ba;
2721 
2722 		    pixel = XGetPixel(bgImg, x, y);
2723 		    ra = GetRValue(pixel);
2724 		    ga = GetGValue(pixel);
2725 		    ba = GetBValue(pixel);
2726 		    unalpha = 255 - alpha;	/* Calculate once. */
2727 		    r = ALPHA_BLEND(ra, r, alpha, unalpha);
2728 		    g = ALPHA_BLEND(ga, g, alpha, unalpha);
2729 		    b = ALPHA_BLEND(ba, b, alpha, unalpha);
2730 		}
2731 		XPutPixel(bgImg, x, y, RGB(r, g, b));
2732 	    }
2733 	}
2734     }
2735 #undef ALPHA_BLEND
2736 }
2737 
2738 /*
2739  *----------------------------------------------------------------------
2740  *
2741  * ImgPhotoDisplay --
2742  *
2743  *	This function is invoked to draw a photo image.
2744  *
2745  * Results:
2746  *	None.
2747  *
2748  * Side effects:
2749  *	A portion of the image gets rendered in a pixmap or window.
2750  *
2751  *----------------------------------------------------------------------
2752  */
2753 
2754 static void
ImgPhotoDisplay(ClientData clientData,Display * display,Drawable drawable,int imageX,int imageY,int width,int height,int drawableX,int drawableY)2755 ImgPhotoDisplay(
2756     ClientData clientData,	/* Pointer to PhotoInstance structure for
2757 				 * instance to be displayed. */
2758     Display *display,		/* Display on which to draw image. */
2759     Drawable drawable,		/* Pixmap or window in which to draw image. */
2760     int imageX, int imageY,	/* Upper-left corner of region within image to
2761 				 * draw. */
2762     int width, int height,	/* Dimensions of region within image to
2763 				 * draw. */
2764     int drawableX,int drawableY)/* Coordinates within drawable that correspond
2765 				 * to imageX and imageY. */
2766 {
2767     PhotoInstance *instancePtr = (PhotoInstance *) clientData;
2768     XVisualInfo visInfo = instancePtr->visualInfo;
2769 
2770     /*
2771      * If there's no pixmap, it means that an error occurred while creating
2772      * the image instance so it can't be displayed.
2773      */
2774 
2775     if (instancePtr->pixels == None) {
2776 	return;
2777     }
2778 
2779     if ((instancePtr->masterPtr->flags & COMPLEX_ALPHA)
2780 	    && visInfo.depth >= 15
2781 	    && (visInfo.class == DirectColor || visInfo.class == TrueColor)) {
2782 	Tk_ErrorHandler handler;
2783 	XImage *bgImg = NULL;
2784 
2785 	/*
2786 	 * Create an error handler to suppress the case where the input was
2787 	 * not properly constrained, which can cause an X error. [Bug 979239]
2788 	 */
2789 
2790 	handler = Tk_CreateErrorHandler(display, -1, -1, -1, NULL,
2791 		(ClientData) NULL);
2792 
2793 	/*
2794 	 * Pull the current background from the display to blend with
2795 	 */
2796 
2797 	bgImg = XGetImage(display, drawable, drawableX, drawableY,
2798 		(unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap);
2799 	if (bgImg == NULL) {
2800 	    Tk_DeleteErrorHandler(handler);
2801 	    /* We failed to get the image so draw without blending alpha. It's the best we can do */
2802 	    goto fallBack;
2803 	}
2804 
2805 	ImgPhotoBlendComplexAlpha(bgImg, instancePtr, imageX, imageY, width,
2806 		height);
2807 
2808 	/*
2809 	 * Color info is unimportant as we only do this operation for depth >=
2810 	 * 15.
2811 	 */
2812 
2813 	TkPutImage(NULL, 0, display, drawable, instancePtr->gc,
2814 		bgImg, 0, 0, drawableX, drawableY,
2815 		(unsigned int) width, (unsigned int) height);
2816 	XDestroyImage(bgImg);
2817 	Tk_DeleteErrorHandler(handler);
2818     } else {
2819 	/*
2820 	 * masterPtr->region describes which parts of the image contain valid
2821 	 * data. We set this region as the clip mask for the gc, setting its
2822 	 * origin appropriately, and use it when drawing the image.
2823 	 */
2824 
2825     fallBack:
2826 	TkSetRegion(display, instancePtr->gc,
2827 		instancePtr->masterPtr->validRegion);
2828 	XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
2829 		drawableY - imageY);
2830 	XCopyArea(display, instancePtr->pixels, drawable, instancePtr->gc,
2831 		imageX, imageY, (unsigned) width, (unsigned) height,
2832 		drawableX, drawableY);
2833 	XSetClipMask(display, instancePtr->gc, None);
2834 	XSetClipOrigin(display, instancePtr->gc, 0, 0);
2835     }
2836     XFlush(display);
2837 }
2838 
2839 /*
2840  *----------------------------------------------------------------------
2841  *
2842  * ImgPhotoFree --
2843  *
2844  *	This function is called when a widget ceases to use a particular
2845  *	instance of an image. We don't actually get rid of the instance until
2846  *	later because we may be about to get this instance again.
2847  *
2848  * Results:
2849  *	None.
2850  *
2851  * Side effects:
2852  *	Internal data structures get cleaned up, later.
2853  *
2854  *----------------------------------------------------------------------
2855  */
2856 
2857 static void
ImgPhotoFree(ClientData clientData,Display * display)2858 ImgPhotoFree(
2859     ClientData clientData,	/* Pointer to PhotoInstance structure for
2860 				 * instance to be displayed. */
2861     Display *display)		/* Display containing window that used
2862 				 * image. */
2863 {
2864     PhotoInstance *instancePtr = (PhotoInstance *) clientData;
2865     ColorTable *colorPtr;
2866 
2867     instancePtr->refCount -= 1;
2868     if (instancePtr->refCount > 0) {
2869 	return;
2870     }
2871 
2872     /*
2873      * There are no more uses of the image within this widget. Decrement the
2874      * count of live uses of its color table, so that its colors can be
2875      * reclaimed if necessary, and set up an idle call to free the instance
2876      * structure.
2877      */
2878 
2879     colorPtr = instancePtr->colorTablePtr;
2880     if (colorPtr != NULL) {
2881 	colorPtr->liveRefCount -= 1;
2882     }
2883 
2884     Tcl_DoWhenIdle(DisposeInstance, (ClientData) instancePtr);
2885 }
2886 
2887 /*
2888  *----------------------------------------------------------------------
2889  *
2890  * ImgPhotoDelete --
2891  *
2892  *	This function is called by the image code to delete the master
2893  *	structure for an image.
2894  *
2895  * Results:
2896  *	None.
2897  *
2898  * Side effects:
2899  *	Resources associated with the image get freed.
2900  *
2901  *----------------------------------------------------------------------
2902  */
2903 
2904 static void
ImgPhotoDelete(ClientData masterData)2905 ImgPhotoDelete(
2906     ClientData masterData)	/* Pointer to PhotoMaster structure for image.
2907 				 * Must not have any more instances. */
2908 {
2909     PhotoMaster *masterPtr = (PhotoMaster *) masterData;
2910     PhotoInstance *instancePtr;
2911 
2912     while ((instancePtr = masterPtr->instancePtr) != NULL) {
2913 	if (instancePtr->refCount > 0) {
2914 	    Tcl_Panic("tried to delete photo image when instances still exist");
2915 	}
2916 	Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
2917 	DisposeInstance((ClientData) instancePtr);
2918     }
2919     masterPtr->tkMaster = NULL;
2920     if (masterPtr->imageCmd != NULL) {
2921 	Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
2922     }
2923     if (masterPtr->pix32 != NULL) {
2924 	ckfree((char *) masterPtr->pix32);
2925     }
2926     if (masterPtr->validRegion != NULL) {
2927 	TkDestroyRegion(masterPtr->validRegion);
2928     }
2929     if (masterPtr->dataString != NULL) {
2930 	Tcl_DecrRefCount(masterPtr->dataString);
2931     }
2932     if (masterPtr->format != NULL) {
2933 	Tcl_DecrRefCount(masterPtr->format);
2934     }
2935     Tk_FreeOptions(configSpecs, (char *) masterPtr, NULL, 0);
2936     ckfree((char *) masterPtr);
2937 }
2938 
2939 /*
2940  *----------------------------------------------------------------------
2941  *
2942  * ImgPhotoCmdDeletedProc --
2943  *
2944  *	This function is invoked when the image command for an image is
2945  *	deleted. It deletes the image.
2946  *
2947  * Results:
2948  *	None.
2949  *
2950  * Side effects:
2951  *	The image is deleted.
2952  *
2953  *----------------------------------------------------------------------
2954  */
2955 
2956 static void
ImgPhotoCmdDeletedProc(ClientData clientData)2957 ImgPhotoCmdDeletedProc(
2958     ClientData clientData)	/* Pointer to PhotoMaster structure for
2959 				 * image. */
2960 {
2961     PhotoMaster *masterPtr = (PhotoMaster *) clientData;
2962 
2963     masterPtr->imageCmd = NULL;
2964     if (masterPtr->tkMaster != NULL) {
2965 	Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
2966     }
2967 }
2968 
2969 /*
2970  *----------------------------------------------------------------------
2971  *
2972  * ImgPhotoSetSize --
2973  *
2974  *	This function reallocates the image storage and instance pixmaps for a
2975  *	photo image, as necessary, to change the image's size to `width' x
2976  *	`height' pixels.
2977  *
2978  * Results:
2979  *	TCL_OK if successful, TCL_ERROR if failure occurred (currently just
2980  *	with memory allocation.)
2981  *
2982  * Side effects:
2983  *	Storage gets reallocated, for the master and all its instances.
2984  *
2985  *----------------------------------------------------------------------
2986  */
2987 
2988 static int
ImgPhotoSetSize(PhotoMaster * masterPtr,int width,int height)2989 ImgPhotoSetSize(
2990     PhotoMaster *masterPtr,
2991     int width, int height)
2992 {
2993     unsigned char *newPix32 = NULL;
2994     int h, offset, pitch;
2995     unsigned char *srcPtr, *destPtr;
2996     XRectangle validBox, clipBox;
2997     TkRegion clipRegion;
2998     PhotoInstance *instancePtr;
2999 
3000     if (masterPtr->userWidth > 0) {
3001 	width = masterPtr->userWidth;
3002     }
3003     if (masterPtr->userHeight > 0) {
3004 	height = masterPtr->userHeight;
3005     }
3006 
3007     pitch = width * 4;
3008 
3009     /*
3010      * Test if we're going to (re)allocate the main buffer now, so that any
3011      * failures will leave the photo unchanged.
3012      */
3013 
3014     if ((width != masterPtr->width) || (height != masterPtr->height)
3015 	    || (masterPtr->pix32 == NULL)) {
3016 	/*
3017 	 * Not a u-long, but should be one.
3018 	 */
3019 
3020 	unsigned /*long*/ newPixSize = (unsigned /*long*/) (height * pitch);
3021 
3022 	/*
3023 	 * Some mallocs() really hate allocating zero bytes. [Bug 619544]
3024 	 */
3025 
3026 	if (newPixSize == 0) {
3027 	    newPix32 = NULL;
3028 	} else {
3029 	    newPix32 = (unsigned char *) attemptckalloc(newPixSize);
3030 	    if (newPix32 == NULL) {
3031 		return TCL_ERROR;
3032 	    }
3033 	}
3034     }
3035 
3036     /*
3037      * We have to trim the valid region if it is currently larger than the new
3038      * image size.
3039      */
3040 
3041     TkClipBox(masterPtr->validRegion, &validBox);
3042     if ((validBox.x + validBox.width > width)
3043 	    || (validBox.y + validBox.height > height)) {
3044 	clipBox.x = 0;
3045 	clipBox.y = 0;
3046 	clipBox.width = width;
3047 	clipBox.height = height;
3048 	clipRegion = TkCreateRegion();
3049 	TkUnionRectWithRegion(&clipBox, clipRegion, clipRegion);
3050 	TkIntersectRegion(masterPtr->validRegion, clipRegion,
3051 		masterPtr->validRegion);
3052 	TkDestroyRegion(clipRegion);
3053 	TkClipBox(masterPtr->validRegion, &validBox);
3054     }
3055 
3056     /*
3057      * Use the reallocated storage (allocation above) for the 32-bit image and
3058      * copy over valid regions. Note that this test is true precisely when the
3059      * allocation has already been done.
3060      */
3061 
3062     if (newPix32 != NULL) {
3063 	/*
3064 	 * Zero the new array. The dithering code shouldn't read the areas
3065 	 * outside validBox, but they might be copied to another photo image
3066 	 * or written to a file.
3067 	 */
3068 
3069 	if ((masterPtr->pix32 != NULL)
3070 	    && ((width == masterPtr->width) || (width == validBox.width))) {
3071 	    if (validBox.y > 0) {
3072 		memset(newPix32, 0, (size_t) (validBox.y * pitch));
3073 	    }
3074 	    h = validBox.y + validBox.height;
3075 	    if (h < height) {
3076 		memset(newPix32 + h*pitch, 0, (size_t) ((height - h) * pitch));
3077 	    }
3078 	} else {
3079 	    memset(newPix32, 0, (size_t) (height * pitch));
3080 	}
3081 
3082 	if (masterPtr->pix32 != NULL) {
3083 	    /*
3084 	     * Copy the common area over to the new array array and free the
3085 	     * old array.
3086 	     */
3087 
3088 	    if (width == masterPtr->width) {
3089 
3090 		/*
3091 		 * The region to be copied is contiguous.
3092 		 */
3093 
3094 		offset = validBox.y * pitch;
3095 		memcpy(newPix32 + offset, masterPtr->pix32 + offset,
3096 			(size_t) (validBox.height * pitch));
3097 
3098 	    } else if ((validBox.width > 0) && (validBox.height > 0)) {
3099 		/*
3100 		 * Area to be copied is not contiguous - copy line by line.
3101 		 */
3102 
3103 		destPtr = newPix32 + (validBox.y * width + validBox.x) * 4;
3104 		srcPtr = masterPtr->pix32 + (validBox.y * masterPtr->width
3105 			+ validBox.x) * 4;
3106 		for (h = validBox.height; h > 0; h--) {
3107 		    memcpy(destPtr, srcPtr, (size_t) (validBox.width * 4));
3108 		    destPtr += width * 4;
3109 		    srcPtr += masterPtr->width * 4;
3110 		}
3111 	    }
3112 
3113 	    ckfree((char *) masterPtr->pix32);
3114 	}
3115 
3116 	masterPtr->pix32 = newPix32;
3117 	masterPtr->width = width;
3118 	masterPtr->height = height;
3119 
3120 	/*
3121 	 * Dithering will be correct up to the end of the last pre-existing
3122 	 * complete scanline.
3123 	 */
3124 
3125 	if ((validBox.x > 0) || (validBox.y > 0)) {
3126 	    masterPtr->ditherX = 0;
3127 	    masterPtr->ditherY = 0;
3128 	} else if (validBox.width == width) {
3129 	    if ((int) validBox.height < masterPtr->ditherY) {
3130 		masterPtr->ditherX = 0;
3131 		masterPtr->ditherY = validBox.height;
3132 	    }
3133 	} else if ((masterPtr->ditherY > 0)
3134 		|| ((int) validBox.width < masterPtr->ditherX)) {
3135 	    masterPtr->ditherX = validBox.width;
3136 	    masterPtr->ditherY = 0;
3137 	}
3138     }
3139 
3140     ToggleComplexAlphaIfNeeded(masterPtr);
3141 
3142     /*
3143      * Now adjust the sizes of the pixmaps for all of the instances.
3144      */
3145 
3146     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
3147 	    instancePtr = instancePtr->nextPtr) {
3148 	ImgPhotoInstanceSetSize(instancePtr);
3149     }
3150 
3151     return TCL_OK;
3152 }
3153 
3154 /*
3155  *----------------------------------------------------------------------
3156  *
3157  * ImgPhotoInstanceSetSize --
3158  *
3159  *	This function reallocates the instance pixmap and dithering error
3160  *	array for a photo instance, as necessary, to change the image's size
3161  *	to `width' x `height' pixels.
3162  *
3163  * Results:
3164  *	None.
3165  *
3166  * Side effects:
3167  *	Storage gets reallocated, here and in the X server.
3168  *
3169  *----------------------------------------------------------------------
3170  */
3171 
3172 static void
ImgPhotoInstanceSetSize(PhotoInstance * instancePtr)3173 ImgPhotoInstanceSetSize(
3174     PhotoInstance *instancePtr)	/* Instance whose size is to be changed. */
3175 {
3176     PhotoMaster *masterPtr;
3177     schar *newError, *errSrcPtr, *errDestPtr;
3178     int h, offset;
3179     XRectangle validBox;
3180     Pixmap newPixmap;
3181 
3182     masterPtr = instancePtr->masterPtr;
3183     TkClipBox(masterPtr->validRegion, &validBox);
3184 
3185     if ((instancePtr->width != masterPtr->width)
3186 	    || (instancePtr->height != masterPtr->height)
3187 	    || (instancePtr->pixels == None)) {
3188 	newPixmap = Tk_GetPixmap(instancePtr->display,
3189 		RootWindow(instancePtr->display,
3190 			instancePtr->visualInfo.screen),
3191 		(masterPtr->width > 0) ? masterPtr->width: 1,
3192 		(masterPtr->height > 0) ? masterPtr->height: 1,
3193 		instancePtr->visualInfo.depth);
3194 	if (!newPixmap) {
3195 	    Tcl_Panic("Fail to create pixmap with Tk_GetPixmap in ImgPhotoInstanceSetSize.\n");
3196 	}
3197 
3198 	/*
3199 	 * The following is a gross hack needed to properly support colormaps
3200 	 * under Windows. Before the pixels can be copied to the pixmap, the
3201 	 * relevent colormap must be associated with the drawable. Normally we
3202 	 * can infer this association from the window that was used to create
3203 	 * the pixmap. However, in this case we're using the root window, so
3204 	 * we have to be more explicit.
3205 	 */
3206 
3207 	TkSetPixmapColormap(newPixmap, instancePtr->colormap);
3208 
3209 	if (instancePtr->pixels != None) {
3210 	    /*
3211 	     * Copy any common pixels from the old pixmap and free it.
3212 	     */
3213 
3214 	    XCopyArea(instancePtr->display, instancePtr->pixels, newPixmap,
3215 		    instancePtr->gc, validBox.x, validBox.y,
3216 		    validBox.width, validBox.height, validBox.x, validBox.y);
3217 	    Tk_FreePixmap(instancePtr->display, instancePtr->pixels);
3218 	}
3219 	instancePtr->pixels = newPixmap;
3220     }
3221 
3222     if ((instancePtr->width != masterPtr->width)
3223 	    || (instancePtr->height != masterPtr->height)
3224 	    || (instancePtr->error == NULL)) {
3225 
3226 	if (masterPtr->height > 0 && masterPtr->width > 0) {
3227 	    newError = (schar *) ckalloc((unsigned)
3228 		    masterPtr->height * masterPtr->width * 3 * sizeof(schar));
3229 
3230 	    /*
3231 	     * Zero the new array so that we don't get bogus error values
3232 	     * propagating into areas we dither later.
3233 	     */
3234 
3235 	    if ((instancePtr->error != NULL)
3236 		    && ((instancePtr->width == masterPtr->width)
3237 		    || (validBox.width == masterPtr->width))) {
3238 		if (validBox.y > 0) {
3239 		    memset(newError, 0, (size_t)
3240 			    validBox.y * masterPtr->width * 3 * sizeof(schar));
3241 		}
3242 		h = validBox.y + validBox.height;
3243 		if (h < masterPtr->height) {
3244 		    memset(newError + h*masterPtr->width*3, 0,
3245 			    (size_t) (masterPtr->height - h)
3246 			    * masterPtr->width * 3 * sizeof(schar));
3247 		}
3248 	    } else {
3249 		memset(newError, 0, (size_t)
3250 			masterPtr->height * masterPtr->width *3*sizeof(schar));
3251 	    }
3252 	} else {
3253 	    newError = NULL;
3254 	}
3255 
3256 	if (instancePtr->error != NULL) {
3257 	    /*
3258 	     * Copy the common area over to the new array and free the old
3259 	     * array.
3260 	     */
3261 
3262 	    if (masterPtr->width == instancePtr->width) {
3263 		offset = validBox.y * masterPtr->width * 3;
3264 		memcpy(newError + offset, instancePtr->error + offset,
3265 			(size_t) (validBox.height
3266 			* masterPtr->width * 3 * sizeof(schar)));
3267 
3268 	    } else if (validBox.width > 0 && validBox.height > 0) {
3269 		errDestPtr = newError +
3270 			(validBox.y * masterPtr->width + validBox.x) * 3;
3271 		errSrcPtr = instancePtr->error +
3272 			(validBox.y * instancePtr->width + validBox.x) * 3;
3273 
3274 		for (h = validBox.height; h > 0; --h) {
3275 		    memcpy(errDestPtr, errSrcPtr,
3276 			    validBox.width * 3 * sizeof(schar));
3277 		    errDestPtr += masterPtr->width * 3;
3278 		    errSrcPtr += instancePtr->width * 3;
3279 		}
3280 	    }
3281 	    ckfree((char *) instancePtr->error);
3282 	}
3283 
3284 	instancePtr->error = newError;
3285     }
3286 
3287     instancePtr->width = masterPtr->width;
3288     instancePtr->height = masterPtr->height;
3289 }
3290 
3291 /*
3292  *----------------------------------------------------------------------
3293  *
3294  * IsValidPalette --
3295  *
3296  *	This function is called to check whether a value given for the
3297  *	-palette option is valid for a particular instance of a photo image.
3298  *
3299  * Results:
3300  *	A boolean value: 1 if the palette is acceptable, 0 otherwise.
3301  *
3302  * Side effects:
3303  *	None.
3304  *
3305  *----------------------------------------------------------------------
3306  */
3307 
3308 static int
IsValidPalette(PhotoInstance * instancePtr,const char * palette)3309 IsValidPalette(
3310     PhotoInstance *instancePtr,	/* Instance to which the palette specification
3311 				 * is to be applied. */
3312     const char *palette)	/* Palette specification string. */
3313 {
3314     int nRed, nGreen, nBlue, mono, numColors;
3315     char *endp;
3316 
3317     /*
3318      * First parse the specification: it must be of the form %d or %d/%d/%d.
3319      */
3320 
3321     nRed = strtol(palette, &endp, 10);
3322     if ((endp == palette) || ((*endp != 0) && (*endp != '/'))
3323 	    || (nRed < 2) || (nRed > 256)) {
3324 	return 0;
3325     }
3326 
3327     if (*endp == 0) {
3328 	mono = 1;
3329 	nGreen = nBlue = nRed;
3330     } else {
3331 	palette = endp + 1;
3332 	nGreen = strtol(palette, &endp, 10);
3333 	if ((endp == palette) || (*endp != '/') || (nGreen < 2)
3334 		|| (nGreen > 256)) {
3335 	    return 0;
3336 	}
3337 	palette = endp + 1;
3338 	nBlue = strtol(palette, &endp, 10);
3339 	if ((endp == palette) || (*endp != 0) || (nBlue < 2)
3340 		|| (nBlue > 256)) {
3341 	    return 0;
3342 	}
3343 	mono = 0;
3344     }
3345 
3346     switch (instancePtr->visualInfo.class) {
3347     case DirectColor:
3348     case TrueColor:
3349 	if ((nRed > (1 << CountBits(instancePtr->visualInfo.red_mask)))
3350 		|| (nGreen>(1<<CountBits(instancePtr->visualInfo.green_mask)))
3351 		|| (nBlue>(1<<CountBits(instancePtr->visualInfo.blue_mask)))) {
3352 	    return 0;
3353 	}
3354 	break;
3355     case PseudoColor:
3356     case StaticColor:
3357 	numColors = nRed;
3358 	if (!mono) {
3359 	    numColors *= nGreen*nBlue;
3360 	}
3361 	if (numColors > (1 << instancePtr->visualInfo.depth)) {
3362 	    return 0;
3363 	}
3364 	break;
3365     case GrayScale:
3366     case StaticGray:
3367 	if (!mono || (nRed > (1 << instancePtr->visualInfo.depth))) {
3368 	    return 0;
3369 	}
3370 	break;
3371     }
3372 
3373     return 1;
3374 }
3375 
3376 /*
3377  *----------------------------------------------------------------------
3378  *
3379  * CountBits --
3380  *
3381  *	This function counts how many bits are set to 1 in `mask'.
3382  *
3383  * Results:
3384  *	The integer number of bits.
3385  *
3386  * Side effects:
3387  *	None.
3388  *
3389  *----------------------------------------------------------------------
3390  */
3391 
3392 static int
CountBits(pixel mask)3393 CountBits(
3394     pixel mask)			/* Value to count the 1 bits in. */
3395 {
3396     int n;
3397 
3398     for (n=0 ; mask!=0 ; mask&=mask-1) {
3399 	n++;
3400     }
3401     return n;
3402 }
3403 
3404 /*
3405  *----------------------------------------------------------------------
3406  *
3407  * GetColorTable --
3408  *
3409  *	This function is called to allocate a table of colormap information
3410  *	for an instance of a photo image. Only one such table is allocated for
3411  *	all photo instances using the same display, colormap, palette and
3412  *	gamma values, so that the application need only request a set of
3413  *	colors from the X server once for all such photo widgets. This
3414  *	function maintains a hash table to find previously-allocated
3415  *	ColorTables.
3416  *
3417  * Results:
3418  *	None.
3419  *
3420  * Side effects:
3421  *	A new ColorTable may be allocated and placed in the hash table, and
3422  *	have colors allocated for it.
3423  *
3424  *----------------------------------------------------------------------
3425  */
3426 
3427 static void
GetColorTable(PhotoInstance * instancePtr)3428 GetColorTable(
3429     PhotoInstance *instancePtr)	/* Instance needing a color table. */
3430 {
3431     ColorTable *colorPtr;
3432     Tcl_HashEntry *entry;
3433     ColorTableId id;
3434     int isNew;
3435 
3436     /*
3437      * Look for an existing ColorTable in the hash table.
3438      */
3439 
3440     memset(&id, 0, sizeof(id));
3441     id.display = instancePtr->display;
3442     id.colormap = instancePtr->colormap;
3443     id.palette = instancePtr->palette;
3444     id.gamma = instancePtr->gamma;
3445     if (!imgPhotoColorHashInitialized) {
3446 	Tcl_InitHashTable(&imgPhotoColorHash, N_COLOR_HASH);
3447 	imgPhotoColorHashInitialized = 1;
3448     }
3449     entry = Tcl_CreateHashEntry(&imgPhotoColorHash, (char *) &id, &isNew);
3450 
3451     if (!isNew) {
3452 	/*
3453 	 * Re-use the existing entry.
3454 	 */
3455 
3456 	colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3457     } else {
3458 	/*
3459 	 * No color table currently available; need to make one.
3460 	 */
3461 
3462 	colorPtr = (ColorTable *) ckalloc(sizeof(ColorTable));
3463 
3464 	/*
3465 	 * The following line of code should not normally be needed due to the
3466 	 * assignment in the following line. However, it compensates for bugs
3467 	 * in some compilers (HP, for example) where sizeof(ColorTable) is 24
3468 	 * but the assignment only copies 20 bytes, leaving 4 bytes
3469 	 * uninitialized; these cause problems when using the id for lookups
3470 	 * in imgPhotoColorHash, and can result in core dumps.
3471 	 */
3472 
3473 	memset(&colorPtr->id, 0, sizeof(ColorTableId));
3474 	colorPtr->id = id;
3475 	Tk_PreserveColormap(colorPtr->id.display, colorPtr->id.colormap);
3476 	colorPtr->flags = 0;
3477 	colorPtr->refCount = 0;
3478 	colorPtr->liveRefCount = 0;
3479 	colorPtr->numColors = 0;
3480 	colorPtr->visualInfo = instancePtr->visualInfo;
3481 	colorPtr->pixelMap = NULL;
3482 	Tcl_SetHashValue(entry, colorPtr);
3483     }
3484 
3485     colorPtr->refCount++;
3486     colorPtr->liveRefCount++;
3487     instancePtr->colorTablePtr = colorPtr;
3488     if (colorPtr->flags & DISPOSE_PENDING) {
3489 	Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr);
3490 	colorPtr->flags &= ~DISPOSE_PENDING;
3491     }
3492 
3493     /*
3494      * Allocate colors for this color table if necessary.
3495      */
3496 
3497     if ((colorPtr->numColors == 0)
3498 	    && ((colorPtr->flags & BLACK_AND_WHITE) == 0)) {
3499 	AllocateColors(colorPtr);
3500     }
3501 }
3502 
3503 /*
3504  *----------------------------------------------------------------------
3505  *
3506  * FreeColorTable --
3507  *
3508  *	This function is called when an instance ceases using a color table.
3509  *
3510  * Results:
3511  *	None.
3512  *
3513  * Side effects:
3514  *	If no other instances are using this color table, a when-idle handler
3515  *	is registered to free up the color table and the colors allocated for
3516  *	it.
3517  *
3518  *----------------------------------------------------------------------
3519  */
3520 
3521 static void
FreeColorTable(ColorTable * colorPtr,int force)3522 FreeColorTable(
3523     ColorTable *colorPtr,	/* Pointer to the color table which is no
3524 				 * longer required by an instance. */
3525     int force)			/* Force free to happen immediately. */
3526 {
3527     colorPtr->refCount--;
3528     if (colorPtr->refCount > 0) {
3529 	return;
3530     }
3531 
3532     if (force) {
3533 	if ((colorPtr->flags & DISPOSE_PENDING) != 0) {
3534 	    Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr);
3535 	    colorPtr->flags &= ~DISPOSE_PENDING;
3536 	}
3537 	DisposeColorTable((ClientData) colorPtr);
3538     } else if ((colorPtr->flags & DISPOSE_PENDING) == 0) {
3539 	Tcl_DoWhenIdle(DisposeColorTable, (ClientData) colorPtr);
3540 	colorPtr->flags |= DISPOSE_PENDING;
3541     }
3542 }
3543 
3544 /*
3545  *----------------------------------------------------------------------
3546  *
3547  * AllocateColors --
3548  *
3549  *	This function allocates the colors required by a color table, and sets
3550  *	up the fields in the color table data structure which are used in
3551  *	dithering.
3552  *
3553  * Results:
3554  *	None.
3555  *
3556  * Side effects:
3557  *	Colors are allocated from the X server. Fields in the color table data
3558  *	structure are updated.
3559  *
3560  *----------------------------------------------------------------------
3561  */
3562 
3563 static void
AllocateColors(ColorTable * colorPtr)3564 AllocateColors(
3565     ColorTable *colorPtr)	/* Pointer to the color table requiring colors
3566 				 * to be allocated. */
3567 {
3568     int i, r, g, b, rMult, mono;
3569     int numColors, nRed, nGreen, nBlue;
3570     double fr, fg, fb, igam;
3571     XColor *colors;
3572     unsigned long *pixels;
3573 
3574     /*
3575      * 16-bit intensity value for i/n of full intensity.
3576      */
3577 #define CFRAC(i, n)	((i) * 65535 / (n))
3578 
3579     /* As for CFRAC, but apply exponent of g. */
3580 #define CGFRAC(i, n, g)	((int)(65535 * pow((double)(i) / (n), (g))))
3581 
3582     /*
3583      * First parse the palette specification to get the required number of
3584      * shades of each primary.
3585      */
3586 
3587     mono = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed, &nGreen, &nBlue)
3588 	    <= 1;
3589     igam = 1.0 / colorPtr->id.gamma;
3590 
3591     /*
3592      * Each time around this loop, we reduce the number of colors we're trying
3593      * to allocate until we succeed in allocating all of the colors we need.
3594      */
3595 
3596     for (;;) {
3597 	/*
3598 	 * If we are using 1 bit/pixel, we don't need to allocate any colors
3599 	 * (we just use the foreground and background colors in the GC).
3600 	 */
3601 
3602 	if (mono && (nRed <= 2)) {
3603 	    colorPtr->flags |= BLACK_AND_WHITE;
3604 	    return;
3605 	}
3606 
3607 	/*
3608 	 * Calculate the RGB coordinates of the colors we want to allocate and
3609 	 * store them in *colors.
3610 	 */
3611 
3612 	if ((colorPtr->visualInfo.class == DirectColor)
3613 		|| (colorPtr->visualInfo.class == TrueColor)) {
3614 
3615 	    /*
3616 	     * Direct/True Color: allocate shades of red, green, blue
3617 	     * independently.
3618 	     */
3619 
3620 	    if (mono) {
3621 		numColors = nGreen = nBlue = nRed;
3622 	    } else {
3623 		numColors = MAX(MAX(nRed, nGreen), nBlue);
3624 	    }
3625 	    colors = (XColor *) ckalloc(numColors * sizeof(XColor));
3626 
3627 	    for (i = 0; i < numColors; ++i) {
3628 		if (igam == 1.0) {
3629 		    colors[i].red = CFRAC(i, nRed - 1);
3630 		    colors[i].green = CFRAC(i, nGreen - 1);
3631 		    colors[i].blue = CFRAC(i, nBlue - 1);
3632 		} else {
3633 		    colors[i].red = CGFRAC(i, nRed - 1, igam);
3634 		    colors[i].green = CGFRAC(i, nGreen - 1, igam);
3635 		    colors[i].blue = CGFRAC(i, nBlue - 1, igam);
3636 		}
3637 	    }
3638 	} else {
3639 	    /*
3640 	     * PseudoColor, StaticColor, GrayScale or StaticGray visual: we
3641 	     * have to allocate each color in the color cube separately.
3642 	     */
3643 
3644 	    numColors = (mono) ? nRed: (nRed * nGreen * nBlue);
3645 	    colors = (XColor *) ckalloc(numColors * sizeof(XColor));
3646 
3647 	    if (!mono) {
3648 		/*
3649 		 * Color display using a PseudoColor or StaticColor visual.
3650 		 */
3651 
3652 		i = 0;
3653 		for (r = 0; r < nRed; ++r) {
3654 		    for (g = 0; g < nGreen; ++g) {
3655 			for (b = 0; b < nBlue; ++b) {
3656 			    if (igam == 1.0) {
3657 				colors[i].red = CFRAC(r, nRed - 1);
3658 				colors[i].green = CFRAC(g, nGreen - 1);
3659 				colors[i].blue = CFRAC(b, nBlue - 1);
3660 			    } else {
3661 				colors[i].red = CGFRAC(r, nRed - 1, igam);
3662 				colors[i].green = CGFRAC(g, nGreen - 1, igam);
3663 				colors[i].blue = CGFRAC(b, nBlue - 1, igam);
3664 			    }
3665 			    i++;
3666 			}
3667 		    }
3668 		}
3669 	    } else {
3670 		/*
3671 		 * Monochrome display - allocate the shades of grey we want.
3672 		 */
3673 
3674 		for (i = 0; i < numColors; ++i) {
3675 		    if (igam == 1.0) {
3676 			r = CFRAC(i, numColors - 1);
3677 		    } else {
3678 			r = CGFRAC(i, numColors - 1, igam);
3679 		    }
3680 		    colors[i].red = colors[i].green = colors[i].blue = r;
3681 		}
3682 	    }
3683 	}
3684 
3685 	/*
3686 	 * Now try to allocate the colors we've calculated.
3687 	 */
3688 
3689 	pixels = (unsigned long *) ckalloc(numColors * sizeof(unsigned long));
3690 	for (i = 0; i < numColors; ++i) {
3691 	    if (!XAllocColor(colorPtr->id.display, colorPtr->id.colormap,
3692 		    &colors[i])) {
3693 		/*
3694 		 * Can't get all the colors we want in the default colormap;
3695 		 * first try freeing colors from other unused color tables.
3696 		 */
3697 
3698 		if (!ReclaimColors(&colorPtr->id, numColors - i)
3699 			|| !XAllocColor(colorPtr->id.display,
3700 			colorPtr->id.colormap, &colors[i])) {
3701 		    /*
3702 		     * Still can't allocate the color.
3703 		     */
3704 
3705 		    break;
3706 		}
3707 	    }
3708 	    pixels[i] = colors[i].pixel;
3709 	}
3710 
3711 	/*
3712 	 * If we didn't get all of the colors, reduce the resolution of the
3713 	 * color cube, free the ones we got, and try again.
3714 	 */
3715 
3716 	if (i >= numColors) {
3717 	    break;
3718 	}
3719 	XFreeColors(colorPtr->id.display, colorPtr->id.colormap, pixels, i, 0);
3720 	ckfree((char *) colors);
3721 	ckfree((char *) pixels);
3722 
3723 	if (!mono) {
3724 	    if ((nRed == 2) && (nGreen == 2) && (nBlue == 2)) {
3725 		/*
3726 		 * Fall back to 1-bit monochrome display.
3727 		 */
3728 
3729 		mono = 1;
3730 	    } else {
3731 		/*
3732 		 * Reduce the number of shades of each primary to about 3/4 of
3733 		 * the previous value. This should reduce the total number of
3734 		 * colors required to about half the previous value for
3735 		 * PseudoColor displays.
3736 		 */
3737 
3738 		nRed = (nRed * 3 + 2) / 4;
3739 		nGreen = (nGreen * 3 + 2) / 4;
3740 		nBlue = (nBlue * 3 + 2) / 4;
3741 	    }
3742 	} else {
3743 	    /*
3744 	     * Reduce the number of shades of gray to about 1/2.
3745 	     */
3746 
3747 	    nRed = nRed / 2;
3748 	}
3749     }
3750 
3751     /*
3752      * We have allocated all of the necessary colors: fill in various fields
3753      * of the ColorTable record.
3754      */
3755 
3756     if (!mono) {
3757 	colorPtr->flags |= COLOR_WINDOW;
3758 
3759 	/*
3760 	 * The following is a hairy hack. We only want to index into the
3761 	 * pixelMap on colormap displays. However, if the display is on
3762 	 * Windows, then we actually want to store the index not the value
3763 	 * since we will be passing the color table into the TkPutImage call.
3764 	 */
3765 
3766 #ifndef __WIN32__
3767 	if ((colorPtr->visualInfo.class != DirectColor)
3768 		&& (colorPtr->visualInfo.class != TrueColor)) {
3769 	    colorPtr->flags |= MAP_COLORS;
3770 	}
3771 #endif /* __WIN32__ */
3772     }
3773 
3774     colorPtr->numColors = numColors;
3775     colorPtr->pixelMap = pixels;
3776 
3777     /*
3778      * Set up quantization tables for dithering.
3779      */
3780 
3781     rMult = nGreen * nBlue;
3782     for (i = 0; i < 256; ++i) {
3783 	r = (i * (nRed - 1) + 127) / 255;
3784 	if (mono) {
3785 	    fr = (double) colors[r].red / 65535.0;
3786 	    if (colorPtr->id.gamma != 1.0 ) {
3787 		fr = pow(fr, colorPtr->id.gamma);
3788 	    }
3789 	    colorPtr->colorQuant[0][i] = (int)(fr * 255.99);
3790 	    colorPtr->redValues[i] = colors[r].pixel;
3791 	} else {
3792 	    g = (i * (nGreen - 1) + 127) / 255;
3793 	    b = (i * (nBlue - 1) + 127) / 255;
3794 	    if ((colorPtr->visualInfo.class == DirectColor)
3795 		    || (colorPtr->visualInfo.class == TrueColor)) {
3796 		colorPtr->redValues[i] =
3797 			colors[r].pixel & colorPtr->visualInfo.red_mask;
3798 		colorPtr->greenValues[i] =
3799 			colors[g].pixel & colorPtr->visualInfo.green_mask;
3800 		colorPtr->blueValues[i] =
3801 			colors[b].pixel & colorPtr->visualInfo.blue_mask;
3802 	    } else {
3803 		r *= rMult;
3804 		g *= nBlue;
3805 		colorPtr->redValues[i] = r;
3806 		colorPtr->greenValues[i] = g;
3807 		colorPtr->blueValues[i] = b;
3808 	    }
3809 	    fr = (double) colors[r].red / 65535.0;
3810 	    fg = (double) colors[g].green / 65535.0;
3811 	    fb = (double) colors[b].blue / 65535.0;
3812 	    if (colorPtr->id.gamma != 1.0) {
3813 		fr = pow(fr, colorPtr->id.gamma);
3814 		fg = pow(fg, colorPtr->id.gamma);
3815 		fb = pow(fb, colorPtr->id.gamma);
3816 	    }
3817 	    colorPtr->colorQuant[0][i] = (int)(fr * 255.99);
3818 	    colorPtr->colorQuant[1][i] = (int)(fg * 255.99);
3819 	    colorPtr->colorQuant[2][i] = (int)(fb * 255.99);
3820 	}
3821     }
3822 
3823     ckfree((char *) colors);
3824 }
3825 
3826 /*
3827  *----------------------------------------------------------------------
3828  *
3829  * DisposeColorTable --
3830  *
3831  *	Release a color table and its associated resources.
3832  *
3833  * Results:
3834  *	None.
3835  *
3836  * Side effects:
3837  *	The colors in the argument color table are freed, as is the color
3838  *	table structure itself. The color table is removed from the hash table
3839  *	which is used to locate color tables.
3840  *
3841  *----------------------------------------------------------------------
3842  */
3843 
3844 static void
DisposeColorTable(ClientData clientData)3845 DisposeColorTable(
3846     ClientData clientData)	/* Pointer to the ColorTable whose
3847 				 * colors are to be released. */
3848 {
3849     ColorTable *colorPtr = (ColorTable *) clientData;
3850     Tcl_HashEntry *entry;
3851 
3852     if (colorPtr->pixelMap != NULL) {
3853 	if (colorPtr->numColors > 0) {
3854 	    XFreeColors(colorPtr->id.display, colorPtr->id.colormap,
3855 		    colorPtr->pixelMap, colorPtr->numColors, 0);
3856 	    Tk_FreeColormap(colorPtr->id.display, colorPtr->id.colormap);
3857 	}
3858 	ckfree((char *) colorPtr->pixelMap);
3859     }
3860 
3861     entry = Tcl_FindHashEntry(&imgPhotoColorHash, (char *) &colorPtr->id);
3862     if (entry == NULL) {
3863 	Tcl_Panic("DisposeColorTable couldn't find hash entry");
3864     }
3865     Tcl_DeleteHashEntry(entry);
3866 
3867     ckfree((char *) colorPtr);
3868 }
3869 
3870 /*
3871  *----------------------------------------------------------------------
3872  *
3873  * ReclaimColors --
3874  *
3875  *	This function is called to try to free up colors in the colormap used
3876  *	by a color table. It looks for other color tables with the same
3877  *	colormap and with a zero live reference count, and frees their colors.
3878  *	It only does so if there is the possibility of freeing up at least
3879  *	`numColors' colors.
3880  *
3881  * Results:
3882  *	The return value is TRUE if any colors were freed, FALSE otherwise.
3883  *
3884  * Side effects:
3885  *	ColorTables which are not currently in use may lose their color
3886  *	allocations.
3887  *
3888  *----------------------------------------------------------------------
3889  */
3890 
3891 static int
ReclaimColors(ColorTableId * id,int numColors)3892 ReclaimColors(
3893     ColorTableId *id,		/* Pointer to information identifying
3894 				 * the color table which needs more colors. */
3895     int numColors)		/* Number of colors required. */
3896 {
3897     Tcl_HashSearch srch;
3898     Tcl_HashEntry *entry;
3899     ColorTable *colorPtr;
3900     int nAvail = 0;
3901 
3902     /*
3903      * First scan through the color hash table to get an upper bound on how
3904      * many colors we might be able to free.
3905      */
3906 
3907     entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch);
3908     while (entry != NULL) {
3909 	colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3910 	if ((colorPtr->id.display == id->display)
3911 		&& (colorPtr->id.colormap == id->colormap)
3912 		&& (colorPtr->liveRefCount == 0 )&& (colorPtr->numColors != 0)
3913 		&& ((colorPtr->id.palette != id->palette)
3914 			|| (colorPtr->id.gamma != id->gamma))) {
3915 	    /*
3916 	     * We could take this guy's colors off him.
3917 	     */
3918 
3919 	    nAvail += colorPtr->numColors;
3920 	}
3921 	entry = Tcl_NextHashEntry(&srch);
3922     }
3923 
3924     /*
3925      * nAvail is an (over)estimate of the number of colors we could free.
3926      */
3927 
3928     if (nAvail < numColors) {
3929 	return 0;
3930     }
3931 
3932     /*
3933      * Scan through a second time freeing colors.
3934      */
3935 
3936     entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch);
3937     while ((entry != NULL) && (numColors > 0)) {
3938 	colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3939 	if ((colorPtr->id.display == id->display)
3940 		&& (colorPtr->id.colormap == id->colormap)
3941 		&& (colorPtr->liveRefCount == 0) && (colorPtr->numColors != 0)
3942 		&& ((colorPtr->id.palette != id->palette)
3943 			|| (colorPtr->id.gamma != id->gamma))) {
3944 	    /*
3945 	     * Free the colors that this ColorTable has.
3946 	     */
3947 
3948 	    XFreeColors(colorPtr->id.display, colorPtr->id.colormap,
3949 		    colorPtr->pixelMap, colorPtr->numColors, 0);
3950 	    numColors -= colorPtr->numColors;
3951 	    colorPtr->numColors = 0;
3952 	    ckfree((char *) colorPtr->pixelMap);
3953 	    colorPtr->pixelMap = NULL;
3954 	}
3955 
3956 	entry = Tcl_NextHashEntry(&srch);
3957     }
3958     return 1;			/* We freed some colors. */
3959 }
3960 
3961 /*
3962  *----------------------------------------------------------------------
3963  *
3964  * DisposeInstance --
3965  *
3966  *	This function is called to finally free up an instance of a photo
3967  *	image which is no longer required.
3968  *
3969  * Results:
3970  *	None.
3971  *
3972  * Side effects:
3973  *	The instance data structure and the resources it references are freed.
3974  *
3975  *----------------------------------------------------------------------
3976  */
3977 
3978 static void
DisposeInstance(ClientData clientData)3979 DisposeInstance(
3980     ClientData clientData)	/* Pointer to the instance whose resources are
3981 				 * to be released. */
3982 {
3983     PhotoInstance *instancePtr = (PhotoInstance *) clientData;
3984     PhotoInstance *prevPtr;
3985 
3986     if (instancePtr->pixels != None) {
3987 	Tk_FreePixmap(instancePtr->display, instancePtr->pixels);
3988     }
3989     if (instancePtr->gc != None) {
3990 	Tk_FreeGC(instancePtr->display, instancePtr->gc);
3991     }
3992     if (instancePtr->imagePtr != NULL) {
3993 	XDestroyImage(instancePtr->imagePtr);
3994     }
3995     if (instancePtr->error != NULL) {
3996 	ckfree((char *) instancePtr->error);
3997     }
3998     if (instancePtr->colorTablePtr != NULL) {
3999 	FreeColorTable(instancePtr->colorTablePtr, 1);
4000     }
4001 
4002     if (instancePtr->masterPtr->instancePtr == instancePtr) {
4003 	instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
4004     } else {
4005 	for (prevPtr = instancePtr->masterPtr->instancePtr;
4006 		prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
4007 	    /* Empty loop body. */
4008 	}
4009 	prevPtr->nextPtr = instancePtr->nextPtr;
4010     }
4011     Tk_FreeColormap(instancePtr->display, instancePtr->colormap);
4012     ckfree((char *) instancePtr);
4013 }
4014 
4015 /*
4016  *----------------------------------------------------------------------
4017  *
4018  * MatchFileFormat --
4019  *
4020  *	This function is called to find a photo image file format handler
4021  *	which can parse the image data in the given file. If a user-specified
4022  *	format string is provided, only handlers whose names match a prefix of
4023  *	the format string are tried.
4024  *
4025  * Results:
4026  *	A standard TCL return value. If the return value is TCL_OK, a pointer
4027  *	to the image format record is returned in *imageFormatPtr, and the
4028  *	width and height of the image are returned in *widthPtr and
4029  *	*heightPtr.
4030  *
4031  * Side effects:
4032  *	None.
4033  *
4034  *----------------------------------------------------------------------
4035  */
4036 
4037 static int
MatchFileFormat(Tcl_Interp * interp,Tcl_Channel chan,char * fileName,Tcl_Obj * formatObj,Tk_PhotoImageFormat ** imageFormatPtr,int * widthPtr,int * heightPtr,int * oldformat)4038 MatchFileFormat(
4039     Tcl_Interp *interp,		/* Interpreter to use for reporting errors. */
4040     Tcl_Channel chan,		/* The image file, open for reading. */
4041     char *fileName,		/* The name of the image file. */
4042     Tcl_Obj *formatObj,		/* User-specified format string, or NULL. */
4043     Tk_PhotoImageFormat **imageFormatPtr,
4044 				/* A pointer to the photo image format record
4045 				 * is returned here. */
4046     int *widthPtr, int *heightPtr,
4047 				/* The dimensions of the image are returned
4048 				 * here. */
4049     int *oldformat)		/* Returns 1 if the old image API is used. */
4050 {
4051     int matched = 0, useoldformat = 0;
4052     Tk_PhotoImageFormat *formatPtr;
4053     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
4054 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
4055     char *formatString = NULL;
4056 
4057     if (formatObj) {
4058 	formatString = Tcl_GetString(formatObj);
4059     }
4060 
4061     /*
4062      * Scan through the table of file format handlers to find one which can
4063      * handle the image.
4064      */
4065 
4066     for (formatPtr = tsdPtr->formatList; formatPtr != NULL;
4067 	    formatPtr = formatPtr->nextPtr) {
4068 	if (formatObj != NULL) {
4069 	    if (strncasecmp(formatString,
4070 		    formatPtr->name, strlen(formatPtr->name)) != 0) {
4071 		continue;
4072 	    }
4073 	    matched = 1;
4074 	    if (formatPtr->fileMatchProc == NULL) {
4075 		Tcl_AppendResult(interp, "-file option isn't supported for ",
4076 			formatString, " images", NULL);
4077 		return TCL_ERROR;
4078 	    }
4079 	}
4080 	if (formatPtr->fileMatchProc != NULL) {
4081 	    (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
4082 
4083 	    if ((*formatPtr->fileMatchProc)(chan, fileName, formatObj,
4084 		    widthPtr, heightPtr, interp)) {
4085 		if (*widthPtr < 1) {
4086 		    *widthPtr = 1;
4087 		}
4088 		if (*heightPtr < 1) {
4089 		    *heightPtr = 1;
4090 		}
4091 		break;
4092 	    }
4093 	}
4094     }
4095     if (formatPtr == NULL) {
4096 	useoldformat = 1;
4097 	for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
4098 		formatPtr = formatPtr->nextPtr) {
4099 	    if (formatString != NULL) {
4100 		if (strncasecmp(formatString,
4101 			formatPtr->name, strlen(formatPtr->name)) != 0) {
4102 		    continue;
4103 		}
4104 		matched = 1;
4105 		if (formatPtr->fileMatchProc == NULL) {
4106 		    Tcl_AppendResult(interp, "-file option isn't supported",
4107 			    " for ", formatString, " images", NULL);
4108 		    return TCL_ERROR;
4109 		}
4110 	    }
4111 	    if (formatPtr->fileMatchProc != NULL) {
4112 		(void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
4113 		if ((*formatPtr->fileMatchProc)(chan, fileName, (Tcl_Obj *)
4114 			formatString, widthPtr, heightPtr, interp)) {
4115 		    if (*widthPtr < 1) {
4116 			*widthPtr = 1;
4117 		    }
4118 		    if (*heightPtr < 1) {
4119 			*heightPtr = 1;
4120 		    }
4121 		    break;
4122 		}
4123 	    }
4124 	}
4125     }
4126 
4127     if (formatPtr == NULL) {
4128 	if ((formatObj != NULL) && !matched) {
4129 	    Tcl_AppendResult(interp, "image file format \"", formatString,
4130 		    "\" is not supported", NULL);
4131 	} else {
4132 	    Tcl_AppendResult(interp,
4133 		    "couldn't recognize data in image file \"", fileName, "\"",
4134 		    NULL);
4135 	}
4136 	return TCL_ERROR;
4137     }
4138 
4139     *imageFormatPtr = formatPtr;
4140     *oldformat = useoldformat;
4141     (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
4142     return TCL_OK;
4143 }
4144 
4145 /*
4146  *----------------------------------------------------------------------
4147  *
4148  * MatchStringFormat --
4149  *
4150  *	This function is called to find a photo image file format handler
4151  *	which can parse the image data in the given string. If a
4152  *	user-specified format string is provided, only handlers whose names
4153  *	match a prefix of the format string are tried.
4154  *
4155  * Results:
4156  *	A standard TCL return value. If the return value is TCL_OK, a pointer
4157  *	to the image format record is returned in *imageFormatPtr, and the
4158  *	width and height of the image are returned in *widthPtr and
4159  *	*heightPtr.
4160  *
4161  * Side effects:
4162  *	None.
4163  *
4164  *----------------------------------------------------------------------
4165  */
4166 
4167 static int
MatchStringFormat(Tcl_Interp * interp,Tcl_Obj * data,Tcl_Obj * formatObj,Tk_PhotoImageFormat ** imageFormatPtr,int * widthPtr,int * heightPtr,int * oldformat)4168 MatchStringFormat(
4169     Tcl_Interp *interp,		/* Interpreter to use for reporting errors. */
4170     Tcl_Obj *data,		/* Object containing the image data. */
4171     Tcl_Obj *formatObj,		/* User-specified format string, or NULL. */
4172     Tk_PhotoImageFormat **imageFormatPtr,
4173 				/* A pointer to the photo image format record
4174 				 * is returned here. */
4175     int *widthPtr, int *heightPtr,
4176 				/* The dimensions of the image are returned
4177 				 * here. */
4178     int *oldformat)		/* Returns 1 if the old image API is used. */
4179 {
4180     int matched = 0, useoldformat = 0;
4181     Tk_PhotoImageFormat *formatPtr;
4182     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
4183 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
4184     char *formatString = NULL;
4185 
4186     if (formatObj) {
4187 	formatString = Tcl_GetString(formatObj);
4188     }
4189 
4190     /*
4191      * Scan through the table of file format handlers to find one which can
4192      * handle the image.
4193      */
4194 
4195     for (formatPtr = tsdPtr->formatList; formatPtr != NULL;
4196 	    formatPtr = formatPtr->nextPtr) {
4197 	if (formatObj != NULL) {
4198 	    if (strncasecmp(formatString,
4199 		    formatPtr->name, strlen(formatPtr->name)) != 0) {
4200 		continue;
4201 	    }
4202 	    matched = 1;
4203 	    if (formatPtr->stringMatchProc == NULL) {
4204 		Tcl_AppendResult(interp, "-data option isn't supported for ",
4205 			formatString, " images", NULL);
4206 		return TCL_ERROR;
4207 	    }
4208 	}
4209 	if ((formatPtr->stringMatchProc != NULL)
4210 		&& (formatPtr->stringReadProc != NULL)
4211 		&& (*formatPtr->stringMatchProc)(data, formatObj,
4212 		widthPtr, heightPtr, interp)) {
4213 	    break;
4214 	}
4215     }
4216 
4217     if (formatPtr == NULL) {
4218 	useoldformat = 1;
4219 	for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
4220 		formatPtr = formatPtr->nextPtr) {
4221 	    if (formatObj != NULL) {
4222 		if (strncasecmp(formatString,
4223 			formatPtr->name, strlen(formatPtr->name)) != 0) {
4224 		    continue;
4225 		}
4226 		matched = 1;
4227 		if (formatPtr->stringMatchProc == NULL) {
4228 		    Tcl_AppendResult(interp, "-data option isn't supported",
4229 			    " for ", formatString, " images", NULL);
4230 		    return TCL_ERROR;
4231 		}
4232 	    }
4233 	    if ((formatPtr->stringMatchProc != NULL)
4234 		    && (formatPtr->stringReadProc != NULL)
4235 		    && (*formatPtr->stringMatchProc)(
4236 			    (Tcl_Obj *) Tcl_GetString(data),
4237 			    (Tcl_Obj *) formatString,
4238 			    widthPtr, heightPtr, interp)) {
4239 		break;
4240 	    }
4241 	}
4242     }
4243     if (formatPtr == NULL) {
4244 	if ((formatObj != NULL) && !matched) {
4245 	    Tcl_AppendResult(interp, "image format \"", formatString,
4246 		    "\" is not supported", NULL);
4247 	} else {
4248 	    Tcl_AppendResult(interp, "couldn't recognize image data", NULL);
4249 	}
4250 	return TCL_ERROR;
4251     }
4252 
4253     *imageFormatPtr = formatPtr;
4254     *oldformat = useoldformat;
4255     return TCL_OK;
4256 }
4257 
4258 /*
4259  *----------------------------------------------------------------------
4260  *
4261  * Tk_FindPhoto --
4262  *
4263  *	This function is called to get an opaque handle (actually a
4264  *	PhotoMaster *) for a given image, which can be used in subsequent
4265  *	calls to Tk_PhotoPutBlock, etc. The `name' parameter is the name of
4266  *	the image.
4267  *
4268  * Results:
4269  *	The handle for the photo image, or NULL if there is no photo image
4270  *	with the name given.
4271  *
4272  * Side effects:
4273  *	None.
4274  *
4275  *----------------------------------------------------------------------
4276  */
4277 
4278 Tk_PhotoHandle
Tk_FindPhoto(Tcl_Interp * interp,CONST char * imageName)4279 Tk_FindPhoto(
4280     Tcl_Interp *interp,		/* Interpreter (application) in which image
4281 				 * exists. */
4282     CONST char *imageName)	/* Name of the desired photo image. */
4283 {
4284     ClientData clientData;
4285     Tk_ImageType *typePtr;
4286 
4287     clientData = Tk_GetImageMasterData(interp, imageName, &typePtr);
4288     if ((typePtr == NULL) || (typePtr->name != tkPhotoImageType.name)) {
4289 	return NULL;
4290     }
4291     return (Tk_PhotoHandle) clientData;
4292 }
4293 
4294 /*
4295  *----------------------------------------------------------------------
4296  *
4297  * Tk_PhotoPutBlock --
4298  *
4299  *	This function is called to put image data into a photo image.
4300  *
4301  * Results:
4302  *	A standard Tcl result code.
4303  *
4304  * Side effects:
4305  *	The image data is stored. The image may be expanded. The Tk image code
4306  *	is informed that the image has changed. If the result code is
4307  *	TCL_ERROR, an error message will be placed in the interpreter (if
4308  *	non-NULL).
4309  *
4310  *----------------------------------------------------------------------
4311  */
4312 
4313 int
Tk_PhotoPutBlock(Tcl_Interp * interp,Tk_PhotoHandle handle,register Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int compRule)4314 Tk_PhotoPutBlock(
4315     Tcl_Interp *interp,		/* Interpreter for passing back error
4316 				 * messages, or NULL. */
4317     Tk_PhotoHandle handle,	/* Opaque handle for the photo image to be
4318 				 * updated. */
4319     register Tk_PhotoImageBlock *blockPtr,
4320 				/* Pointer to a structure describing the pixel
4321 				 * data to be copied into the image. */
4322     int x, int y,		/* Coordinates of the top-left pixel to be
4323 				 * updated in the image. */
4324     int width, int height,	/* Dimensions of the area of the image to be
4325 				 * updated. */
4326     int compRule)		/* Compositing rule to use when processing
4327 				 * transparent pixels. */
4328 {
4329     register PhotoMaster *masterPtr;
4330     int xEnd, yEnd, greenOffset, blueOffset, alphaOffset;
4331     int wLeft, hLeft, wCopy, hCopy, pitch;
4332     unsigned char *srcPtr, *srcLinePtr, *destPtr, *destLinePtr;
4333     int sourceIsSimplePhoto = compRule & SOURCE_IS_SIMPLE_ALPHA_PHOTO;
4334     XRectangle rect;
4335 
4336     masterPtr = (PhotoMaster *) handle;
4337     compRule &= ~SOURCE_IS_SIMPLE_ALPHA_PHOTO;
4338 
4339     if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
4340 	width = masterPtr->userWidth - x;
4341     }
4342     if ((masterPtr->userHeight != 0)
4343 	    && ((y + height) > masterPtr->userHeight)) {
4344 	height = masterPtr->userHeight - y;
4345     }
4346     if ((width <= 0) || (height <= 0)) {
4347 	return TCL_OK;
4348     }
4349 
4350     xEnd = x + width;
4351     yEnd = y + height;
4352     if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
4353 	int sameSrc = (blockPtr->pixelPtr == masterPtr->pix32);
4354 
4355 	if (ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
4356 		MAX(yEnd, masterPtr->height)) == TCL_ERROR) {
4357 	    if (interp != NULL) {
4358 		Tcl_ResetResult(interp);
4359 		Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
4360 	    }
4361 	    return TCL_ERROR;
4362 	}
4363 	if (sameSrc) {
4364 	    blockPtr->pixelPtr = masterPtr->pix32;
4365 	    blockPtr->pitch = masterPtr->width * 4;
4366 	}
4367     }
4368 
4369     if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
4370 	    && (x < masterPtr->ditherX))) {
4371 	/*
4372 	 * The dithering isn't correct past the start of this block.
4373 	 */
4374 
4375 	masterPtr->ditherX = x;
4376 	masterPtr->ditherY = y;
4377     }
4378 
4379     /*
4380      * If this image block could have different red, green and blue
4381      * components, mark it as a color image.
4382      */
4383 
4384     greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
4385     blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
4386     alphaOffset = blockPtr->offset[3];
4387     if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
4388 	alphaOffset = 0;
4389 	sourceIsSimplePhoto = 1;
4390     } else {
4391 	alphaOffset -= blockPtr->offset[0];
4392     }
4393     if ((greenOffset != 0) || (blueOffset != 0)) {
4394 	masterPtr->flags |= COLOR_IMAGE;
4395     }
4396 
4397     /*
4398      * Copy the data into our local 32-bit/pixel array. If we can do it with a
4399      * single memmove, we do.
4400      */
4401 
4402     destLinePtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
4403     pitch = masterPtr->width * 4;
4404 
4405     /*
4406      * Test to see if we can do the whole write in a single copy. This test is
4407      * probably too restrictive. We should also be able to do a memmove if
4408      * pixelSize == 3 and alphaOffset == 0. Maybe other cases too.
4409      */
4410 
4411     if ((blockPtr->pixelSize == 4)
4412 	    && (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3)
4413 	    && (width <= blockPtr->width) && (height <= blockPtr->height)
4414 	    && ((height == 1) || ((x == 0) && (width == masterPtr->width)
4415 		&& (blockPtr->pitch == pitch)))
4416 	    && (compRule == TK_PHOTO_COMPOSITE_SET)) {
4417 	memmove(destLinePtr, blockPtr->pixelPtr + blockPtr->offset[0],
4418 		(size_t) (height * width * 4));
4419 
4420 	/*
4421 	 * We know there's an alpha offset and we're setting the data, so skip
4422 	 * directly to the point when we recompute the photo validity region.
4423 	 */
4424 
4425 	goto recalculateValidRegion;
4426     }
4427 
4428     /*
4429      * Copy and merge pixels according to the compositing rule.
4430      */
4431 
4432     for (hLeft = height; hLeft > 0;) {
4433 	int pixelSize = blockPtr->pixelSize;
4434 	int compRuleSet = (compRule == TK_PHOTO_COMPOSITE_SET);
4435 
4436 	srcLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
4437 	hCopy = MIN(hLeft, blockPtr->height);
4438 	hLeft -= hCopy;
4439 	for (; hCopy > 0; --hCopy) {
4440 	    /*
4441 	     * If the layout of the source line matches our memory layout and
4442 	     * we're setting, we can just copy the bytes directly, which is
4443 	     * much faster.
4444 	     */
4445 
4446 	    if ((pixelSize == 4) && (greenOffset == 1)
4447 		    && (blueOffset == 2) && (alphaOffset == 3)
4448 		    && (width <= blockPtr->width)
4449 		    && compRuleSet) {
4450 		memcpy(destLinePtr, srcLinePtr, (size_t) (width * 4));
4451 		srcLinePtr += blockPtr->pitch;
4452 		destLinePtr += pitch;
4453 		continue;
4454 	    }
4455 
4456 	    /*
4457 	     * Have to copy the slow way.
4458 	     */
4459 
4460 	    destPtr = destLinePtr;
4461 	    for (wLeft = width; wLeft > 0;) {
4462 		wCopy = MIN(wLeft, blockPtr->width);
4463 		wLeft -= wCopy;
4464 		srcPtr = srcLinePtr;
4465 
4466 		/*
4467 		 * But we might be lucky and be able to use fairly fast loops.
4468 		 * It's worth checking...
4469 		 */
4470 
4471 		if (alphaOffset == 0) {
4472 		    /*
4473 		     * This is the non-alpha case, so can still be fairly
4474 		     * fast. Note that in the non-alpha-source case, the
4475 		     * compositing rule doesn't apply.
4476 		     */
4477 
4478 		    for (; wCopy>0 ; --wCopy, srcPtr+=pixelSize) {
4479 			*destPtr++ = srcPtr[0];
4480 			*destPtr++ = srcPtr[greenOffset];
4481 			*destPtr++ = srcPtr[blueOffset];
4482 			*destPtr++ = 255;
4483 		    }
4484 		    continue;
4485 		} else if (compRuleSet) {
4486 		    /*
4487 		     * This is the SET compositing rule, which just replaces
4488 		     * what was there before with the new data. This is
4489 		     * another fairly fast case. No point in doing a memcpy();
4490 		     * the order of channels is probably wrong.
4491 		     */
4492 
4493 		    for (; wCopy>0 ; --wCopy, srcPtr+=pixelSize) {
4494 			*destPtr++ = srcPtr[0];
4495 			*destPtr++ = srcPtr[greenOffset];
4496 			*destPtr++ = srcPtr[blueOffset];
4497 			*destPtr++ = srcPtr[alphaOffset];
4498 		    }
4499 		    continue;
4500 		}
4501 
4502 		/*
4503 		 * Bother; need to consider the alpha value of each pixel to
4504 		 * know what to do.
4505 		 */
4506 
4507 		for (; wCopy>0 ; --wCopy, srcPtr+=pixelSize) {
4508 		    int alpha = srcPtr[alphaOffset];
4509 
4510 		    if (alpha == 255 || !destPtr[3]) {
4511 			/*
4512 			 * Either the source is 100% opaque, or the
4513 			 * destination is entirely blank. In all cases, we
4514 			 * just set the destination to the source.
4515 			 */
4516 
4517 			*destPtr++ = srcPtr[0];
4518 			*destPtr++ = srcPtr[greenOffset];
4519 			*destPtr++ = srcPtr[blueOffset];
4520 			*destPtr++ = alpha;
4521 			continue;
4522 		    }
4523 
4524 		    /*
4525 		     * Can still skip doing work if the source is 100%
4526 		     * transparent at this point.
4527 		     */
4528 
4529 		    if (alpha) {
4530 			int Alpha = destPtr[3];
4531 
4532 			/*
4533 			 * OK, there's real work to be done. Luckily, there's
4534 			 * a substantial literature on what to do in this
4535 			 * case. In particular, Porter and Duff have done a
4536 			 * taxonomy of compositing rules, and the right one is
4537 			 * the "Source Over" rule. This code implements that.
4538 			 */
4539 
4540 			destPtr[0] = PD_SRC_OVER(srcPtr[0], alpha, destPtr[0],
4541 				Alpha);
4542 			destPtr[1] = PD_SRC_OVER(srcPtr[greenOffset], alpha,
4543 				destPtr[1], Alpha);
4544 			destPtr[2] = PD_SRC_OVER(srcPtr[blueOffset], alpha,
4545 				destPtr[2], Alpha);
4546 			destPtr[3] = PD_SRC_OVER_ALPHA(alpha, Alpha);
4547 		    }
4548 
4549 		    destPtr += 4;
4550 		}
4551 	    }
4552 	    srcLinePtr += blockPtr->pitch;
4553 	    destLinePtr += pitch;
4554 	}
4555     }
4556 
4557     /*
4558      * Add this new block to the region which specifies which data is valid.
4559      */
4560 
4561     if (alphaOffset) {
4562 	/*
4563 	 * This block is grossly inefficient. For each row in the image, it
4564 	 * finds each continguous string of nontransparent pixels, then marks
4565 	 * those areas as valid in the validRegion mask. This makes drawing
4566 	 * very efficient, because of the way we use X: we just say, here's
4567 	 * your mask, and here's your data. We need not worry about the
4568 	 * current background color, etc. But this costs us a lot on the image
4569 	 * setup. Still, image setup only happens once, whereas the drawing
4570 	 * happens many times, so this might be the best way to go.
4571 	 *
4572 	 * An alternative might be to not set up this mask, and instead, at
4573 	 * drawing time, for each transparent pixel, set its color to the
4574 	 * color of the background behind that pixel. This is what I suspect
4575 	 * most of programs do. However, they don't have to deal with the
4576 	 * canvas, which could have many different background colors.
4577 	 * Determining the correct bg color for a given pixel might be
4578 	 * expensive.
4579 	 */
4580 
4581 	if (compRule != TK_PHOTO_COMPOSITE_OVERLAY) {
4582 	    TkRegion workRgn;
4583 
4584 	    /*
4585 	     * Don't need this when using the OVERLAY compositing rule, which
4586 	     * always strictly increases the valid region.
4587 	     */
4588 
4589 	recalculateValidRegion:
4590 	    workRgn = TkCreateRegion();
4591 	    rect.x = x;
4592 	    rect.y = y;
4593 	    rect.width = width;
4594 	    rect.height = height;
4595 	    TkUnionRectWithRegion(&rect, workRgn, workRgn);
4596 	    TkSubtractRegion(masterPtr->validRegion, workRgn,
4597 		    masterPtr->validRegion);
4598 	    TkDestroyRegion(workRgn);
4599 	}
4600 
4601 	/*
4602 	 * Factorize out the main part of the building of the region data to
4603 	 * allow for more efficient per-platform implementations. [Bug 919066]
4604 	 */
4605 
4606 	TkpBuildRegionFromAlphaData(masterPtr->validRegion, (unsigned) x,
4607 		(unsigned) y, (unsigned) width, (unsigned) height,
4608 		masterPtr->pix32 + (y * masterPtr->width + x) * 4 + 3,
4609 		4, (unsigned) masterPtr->width * 4);
4610     } else {
4611 	rect.x = x;
4612 	rect.y = y;
4613 	rect.width = width;
4614 	rect.height = height;
4615 	TkUnionRectWithRegion(&rect, masterPtr->validRegion,
4616 		masterPtr->validRegion);
4617     }
4618 
4619     /*
4620      * Check if display code needs alpha blending...
4621      */
4622 
4623     if (!sourceIsSimplePhoto && (width == 1) && (height == 1)) {
4624 	/*
4625 	 * Optimize the single pixel case if we can. This speeds up code that
4626 	 * builds up large simple-alpha images by single pixels.  We don't
4627 	 * negate COMPLEX_ALPHA in this case. [Bug 1409140]
4628 	 */
4629 
4630 	if (!(masterPtr->flags & COMPLEX_ALPHA)) {
4631 	    unsigned char newAlpha;
4632 
4633 	    destLinePtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
4634 	    newAlpha = destLinePtr[3];
4635 
4636 	    if (newAlpha && newAlpha != 255) {
4637 		masterPtr->flags |= COMPLEX_ALPHA;
4638 	    }
4639 	}
4640     } else if ((alphaOffset != 0) || (masterPtr->flags & COMPLEX_ALPHA)) {
4641 	/*
4642 	 * Check for partial transparency if alpha pixels are specified, or
4643 	 * rescan if we already knew such pixels existed.  To restrict this
4644 	 * Toggle to only checking the changed pixels requires knowing where
4645 	 * the alpha pixels are.
4646 	 */
4647 
4648 	ToggleComplexAlphaIfNeeded(masterPtr);
4649     }
4650 
4651     /*
4652      * Update each instance.
4653      */
4654 
4655     Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height);
4656 
4657     /*
4658      * Tell the core image code that this image has changed.
4659      */
4660 
4661     Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height,
4662 	    masterPtr->width, masterPtr->height);
4663     return TCL_OK;
4664 }
4665 
4666 /*
4667  *----------------------------------------------------------------------
4668  *
4669  * Tk_PhotoPutZoomedBlock --
4670  *
4671  *	This function is called to put image data into a photo image, with
4672  *	possible subsampling and/or zooming of the pixels.
4673  *
4674  * Results:
4675  *	None.
4676  *
4677  * Side effects:
4678  *	The image data is stored. The image may be expanded. The Tk image code
4679  *	is informed that the image has changed.
4680  *
4681  *----------------------------------------------------------------------
4682  */
4683 
4684 int
Tk_PhotoPutZoomedBlock(Tcl_Interp * interp,Tk_PhotoHandle handle,register Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int zoomX,int zoomY,int subsampleX,int subsampleY,int compRule)4685 Tk_PhotoPutZoomedBlock(
4686     Tcl_Interp *interp,		/* Interpreter for passing back error
4687 				 * messages, or NULL. */
4688     Tk_PhotoHandle handle,	/* Opaque handle for the photo image to be
4689 				 * updated. */
4690     register Tk_PhotoImageBlock *blockPtr,
4691 				/* Pointer to a structure describing the pixel
4692 				 * data to be copied into the image. */
4693     int x, int y,		/* Coordinates of the top-left pixel to be
4694 				 * updated in the image. */
4695     int width, int height,	/* Dimensions of the area of the image to be
4696 				 * updated. */
4697     int zoomX, int zoomY,	/* Zoom factors for the X and Y axes. */
4698     int subsampleX, int subsampleY,
4699 				/* Subsampling factors for the X and Y
4700 				 * axes. */
4701     int compRule)		/* Compositing rule to use when processing
4702 				 * transparent pixels. */
4703 {
4704     register PhotoMaster *masterPtr = (PhotoMaster *) handle;
4705     int xEnd, yEnd, greenOffset, blueOffset, alphaOffset;
4706     int wLeft, hLeft, wCopy, hCopy, blockWid, blockHt;
4707     unsigned char *srcPtr, *srcLinePtr, *srcOrigPtr, *destPtr, *destLinePtr;
4708     int pitch, xRepeat, yRepeat, blockXSkip, blockYSkip, sourceIsSimplePhoto;
4709     XRectangle rect;
4710 
4711     if (zoomX==1 && zoomY==1 && subsampleX==1 && subsampleY==1) {
4712 	return Tk_PhotoPutBlock(interp, handle, blockPtr, x, y, width, height,
4713 		compRule);
4714     }
4715 
4716     sourceIsSimplePhoto = compRule & SOURCE_IS_SIMPLE_ALPHA_PHOTO;
4717     compRule &= ~SOURCE_IS_SIMPLE_ALPHA_PHOTO;
4718 
4719     if (zoomX <= 0 || zoomY <= 0) {
4720 	return TCL_OK;
4721     }
4722     if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
4723 	width = masterPtr->userWidth - x;
4724     }
4725     if ((masterPtr->userHeight != 0)
4726 	    && ((y + height) > masterPtr->userHeight)) {
4727 	height = masterPtr->userHeight - y;
4728     }
4729     if (width <= 0 || height <= 0) {
4730 	return TCL_OK;
4731     }
4732 
4733     xEnd = x + width;
4734     yEnd = y + height;
4735     if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
4736 	int sameSrc = (blockPtr->pixelPtr == masterPtr->pix32);
4737 	if (ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
4738 		MAX(yEnd, masterPtr->height)) == TCL_ERROR) {
4739 	    if (interp != NULL) {
4740 		Tcl_ResetResult(interp);
4741 		Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
4742 	    }
4743 	    return TCL_ERROR;
4744 	}
4745 	if (sameSrc) {
4746 	    blockPtr->pixelPtr = masterPtr->pix32;
4747 	    blockPtr->pitch = masterPtr->width * 4;
4748 	}
4749     }
4750 
4751     if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
4752 	   && (x < masterPtr->ditherX))) {
4753 	/*
4754 	 * The dithering isn't correct past the start of this block.
4755 	 */
4756 
4757 	masterPtr->ditherX = x;
4758 	masterPtr->ditherY = y;
4759     }
4760 
4761     /*
4762      * If this image block could have different red, green and blue
4763      * components, mark it as a color image.
4764      */
4765 
4766     greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
4767     blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
4768     alphaOffset = blockPtr->offset[3];
4769     if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
4770 	alphaOffset = 0;
4771 	sourceIsSimplePhoto = 1;
4772     } else {
4773 	alphaOffset -= blockPtr->offset[0];
4774     }
4775     if ((greenOffset != 0) || (blueOffset != 0)) {
4776 	masterPtr->flags |= COLOR_IMAGE;
4777     }
4778 
4779     /*
4780      * Work out what area the pixel data in the block expands to after
4781      * subsampling and zooming.
4782      */
4783 
4784     blockXSkip = subsampleX * blockPtr->pixelSize;
4785     blockYSkip = subsampleY * blockPtr->pitch;
4786     if (subsampleX > 0) {
4787 	blockWid = ((blockPtr->width + subsampleX - 1) / subsampleX) * zoomX;
4788     } else if (subsampleX == 0) {
4789 	blockWid = width;
4790     } else {
4791 	blockWid = ((blockPtr->width - subsampleX - 1) / -subsampleX) * zoomX;
4792     }
4793     if (subsampleY > 0) {
4794 	blockHt = ((blockPtr->height + subsampleY - 1) / subsampleY) * zoomY;
4795     } else if (subsampleY == 0) {
4796 	blockHt = height;
4797     } else {
4798 	blockHt = ((blockPtr->height - subsampleY - 1) / -subsampleY) * zoomY;
4799     }
4800 
4801     /*
4802      * Copy the data into our local 32-bit/pixel array.
4803      */
4804 
4805     destLinePtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
4806     srcOrigPtr = blockPtr->pixelPtr + blockPtr->offset[0];
4807     if (subsampleX < 0) {
4808 	srcOrigPtr += (blockPtr->width - 1) * blockPtr->pixelSize;
4809     }
4810     if (subsampleY < 0) {
4811 	srcOrigPtr += (blockPtr->height - 1) * blockPtr->pitch;
4812     }
4813 
4814     pitch = masterPtr->width * 4;
4815     for (hLeft = height; hLeft > 0; ) {
4816 	hCopy = MIN(hLeft, blockHt);
4817 	hLeft -= hCopy;
4818 	yRepeat = zoomY;
4819 	srcLinePtr = srcOrigPtr;
4820 	for (; hCopy > 0; --hCopy) {
4821 	    destPtr = destLinePtr;
4822 	    for (wLeft = width; wLeft > 0;) {
4823 		wCopy = MIN(wLeft, blockWid);
4824 		wLeft -= wCopy;
4825 		srcPtr = srcLinePtr;
4826 		for (; wCopy > 0; wCopy -= zoomX) {
4827 		    for (xRepeat = MIN(wCopy, zoomX); xRepeat > 0; xRepeat--) {
4828 			int alpha = srcPtr[alphaOffset];/* Source alpha. */
4829 
4830 			/*
4831 			 * Common case (solid pixels) first
4832 			 */
4833 
4834 			if (!alphaOffset || (alpha == 255)) {
4835 			    *destPtr++ = srcPtr[0];
4836 			    *destPtr++ = srcPtr[greenOffset];
4837 			    *destPtr++ = srcPtr[blueOffset];
4838 			    *destPtr++ = 255;
4839 			    continue;
4840  			}
4841 
4842 			if (compRule==TK_PHOTO_COMPOSITE_SET || !destPtr[3]) {
4843 			    /*
4844 			     * Either this is the SET rule (we overwrite
4845 			     * whatever is there) or the destination is
4846 			     * entirely blank. In both cases, we just set the
4847 			     * destination to the source.
4848 			     */
4849 
4850 			    *destPtr++ = srcPtr[0];
4851 			    *destPtr++ = srcPtr[greenOffset];
4852 			    *destPtr++ = srcPtr[blueOffset];
4853 			    *destPtr++ = alpha;
4854 			} else if (alpha) {
4855 			    int Alpha = destPtr[3];	/* Destination
4856 							 * alpha. */
4857 
4858 			    destPtr[0] = PD_SRC_OVER(srcPtr[0], alpha,
4859 				    destPtr[0], Alpha);
4860 			    destPtr[1] = PD_SRC_OVER(srcPtr[greenOffset],alpha,
4861 				    destPtr[1], Alpha);
4862 			    destPtr[2] = PD_SRC_OVER(srcPtr[blueOffset], alpha,
4863 				    destPtr[2], Alpha);
4864 			    destPtr[3] = PD_SRC_OVER_ALPHA(alpha, Alpha);
4865 
4866 			    destPtr += 4;
4867 			} else {
4868 			    destPtr += 4;
4869 			}
4870 		    }
4871 		    srcPtr += blockXSkip;
4872 		}
4873 	    }
4874 	    destLinePtr += pitch;
4875 	    yRepeat--;
4876 	    if (yRepeat <= 0) {
4877 		srcLinePtr += blockYSkip;
4878 		yRepeat = zoomY;
4879 	    }
4880 	}
4881     }
4882 
4883     /*
4884      * Recompute the region of data for which we have valid pixels to plot.
4885      */
4886 
4887     if (alphaOffset) {
4888 	if (compRule != TK_PHOTO_COMPOSITE_OVERLAY) {
4889 	    /*
4890 	     * Don't need this when using the OVERLAY compositing rule, which
4891 	     * always strictly increases the valid region.
4892 	     */
4893 
4894 	    TkRegion workRgn = TkCreateRegion();
4895 
4896 	    rect.x = x;
4897 	    rect.y = y;
4898 	    rect.width = width;
4899 	    rect.height = 1;
4900 	    TkUnionRectWithRegion(&rect, workRgn, workRgn);
4901 	    TkSubtractRegion(masterPtr->validRegion, workRgn,
4902 		    masterPtr->validRegion);
4903 	    TkDestroyRegion(workRgn);
4904 	}
4905 
4906 	TkpBuildRegionFromAlphaData(masterPtr->validRegion,
4907 		(unsigned)x, (unsigned)y, (unsigned)width, (unsigned)height,
4908 		&masterPtr->pix32[(y * masterPtr->width + x) * 4 + 3], 4,
4909 		(unsigned) masterPtr->width * 4);
4910     } else {
4911 	rect.x = x;
4912 	rect.y = y;
4913 	rect.width = width;
4914 	rect.height = height;
4915 	TkUnionRectWithRegion(&rect, masterPtr->validRegion,
4916 		masterPtr->validRegion);
4917     }
4918 
4919     /*
4920      * Check if display code needs alpha blending...
4921      */
4922 
4923     if (!sourceIsSimplePhoto && (width == 1) && (height == 1)) {
4924 	/*
4925 	 * Optimize the single pixel case if we can. This speeds up code that
4926 	 * builds up large simple-alpha images by single pixels.  We don't
4927 	 * negate COMPLEX_ALPHA in this case. [Bug 1409140]
4928 	 */
4929 	if (!(masterPtr->flags & COMPLEX_ALPHA)) {
4930 	    unsigned char newAlpha;
4931 
4932 	    destLinePtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
4933 	    newAlpha = destLinePtr[3];
4934 
4935 	    if (newAlpha && newAlpha != 255) {
4936 		masterPtr->flags |= COMPLEX_ALPHA;
4937 	    }
4938 	}
4939     } else if ((alphaOffset != 0) || (masterPtr->flags & COMPLEX_ALPHA)) {
4940 	/*
4941 	 * Check for partial transparency if alpha pixels are specified, or
4942 	 * rescan if we already knew such pixels existed.  To restrict this
4943 	 * Toggle to only checking the changed pixels requires knowing where
4944 	 * the alpha pixels are.
4945 	 */
4946 	ToggleComplexAlphaIfNeeded(masterPtr);
4947     }
4948 
4949     /*
4950      * Update each instance.
4951      */
4952 
4953     Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y, width, height);
4954 
4955     /*
4956      * Tell the core image code that this image has changed.
4957      */
4958 
4959     Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height, masterPtr->width,
4960 	    masterPtr->height);
4961     return TCL_OK;
4962 }
4963 
4964 /*
4965  *----------------------------------------------------------------------
4966  *
4967  * Tk_DitherPhoto --
4968  *
4969  *	This function is called to update an area of each instance's pixmap by
4970  *	dithering the corresponding area of the image master.
4971  *
4972  * Results:
4973  *	None.
4974  *
4975  * Side effects:
4976  *	The pixmap of each instance of this image gets updated. The fields in
4977  *	*masterPtr indicating which area of the image is correctly dithered
4978  *	get updated.
4979  *
4980  *----------------------------------------------------------------------
4981  */
4982 
4983 void
Tk_DitherPhoto(Tk_PhotoHandle photo,int x,int y,int width,int height)4984 Tk_DitherPhoto(
4985     Tk_PhotoHandle photo,	/* Image master whose instances are to be
4986 				 * updated. */
4987     int x, int y,		/* Coordinates of the top-left pixel in the
4988 				 * area to be dithered. */
4989     int width, int height)	/* Dimensions of the area to be dithered. */
4990 {
4991     PhotoMaster *masterPtr = (PhotoMaster *) photo;
4992     PhotoInstance *instancePtr;
4993 
4994     if ((width <= 0) || (height <= 0)) {
4995 	return;
4996     }
4997 
4998     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
4999 	    instancePtr = instancePtr->nextPtr) {
5000 	DitherInstance(instancePtr, x, y, width, height);
5001     }
5002 
5003     /*
5004      * Work out whether this block will be correctly dithered and whether it
5005      * will extend the correctly dithered region.
5006      */
5007 
5008     if (((y < masterPtr->ditherY)
5009 	    || ((y == masterPtr->ditherY) && (x <= masterPtr->ditherX)))
5010 	    && ((y + height) > (masterPtr->ditherY))) {
5011 	/*
5012 	 * This block starts inside (or immediately after) the correctly
5013 	 * dithered region, so the first scan line at least will be right.
5014 	 * Furthermore this block extends into scanline masterPtr->ditherY.
5015 	 */
5016 
5017 	if ((x == 0) && (width == masterPtr->width)) {
5018 	    /*
5019 	     * We are doing the full width, therefore the dithering will be
5020 	     * correct to the end.
5021 	     */
5022 
5023 	    masterPtr->ditherX = 0;
5024 	    masterPtr->ditherY = y + height;
5025 	} else {
5026 	    /*
5027 	     * We are doing partial scanlines, therefore the
5028 	     * correctly-dithered region will be extended by at most one scan
5029 	     * line.
5030 	     */
5031 
5032 	    if (x <= masterPtr->ditherX) {
5033 		masterPtr->ditherX = x + width;
5034 		if (masterPtr->ditherX >= masterPtr->width) {
5035 		    masterPtr->ditherX = 0;
5036 		    masterPtr->ditherY++;
5037 		}
5038 	    }
5039 	}
5040     }
5041 }
5042 
5043 /*
5044  *----------------------------------------------------------------------
5045  *
5046  * DitherInstance --
5047  *
5048  *	This function is called to update an area of an instance's pixmap by
5049  *	dithering the corresponding area of the master.
5050  *
5051  * Results:
5052  *	None.
5053  *
5054  * Side effects:
5055  *	The instance's pixmap gets updated.
5056  *
5057  *----------------------------------------------------------------------
5058  */
5059 
5060 static void
DitherInstance(PhotoInstance * instancePtr,int xStart,int yStart,int width,int height)5061 DitherInstance(
5062     PhotoInstance *instancePtr,	/* The instance to be updated. */
5063     int xStart, int yStart,	/* Coordinates of the top-left pixel in the
5064 				 * block to be dithered. */
5065     int width, int height)	/* Dimensions of the block to be dithered. */
5066 {
5067     PhotoMaster *masterPtr = instancePtr->masterPtr;
5068     ColorTable *colorPtr = instancePtr->colorTablePtr;
5069     XImage *imagePtr;
5070     int nLines, bigEndian, i, c, x, y, xEnd, doDithering = 1;
5071     int bitsPerPixel, bytesPerLine, lineLength;
5072     unsigned char *srcLinePtr;
5073     schar *errLinePtr;
5074     pixel firstBit, word, mask;
5075 
5076     /*
5077      * Turn dithering off in certain cases where it is not needed (TrueColor,
5078      * DirectColor with many colors).
5079      */
5080 
5081     if ((colorPtr->visualInfo.class == DirectColor)
5082 	    || (colorPtr->visualInfo.class == TrueColor)) {
5083 	int nRed, nGreen, nBlue, result;
5084 
5085 	result = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed,
5086 		&nGreen, &nBlue);
5087 	if ((nRed >= 256)
5088 		&& ((result == 1) || ((nGreen >= 256) && (nBlue >= 256)))) {
5089 	    doDithering = 0;
5090 	}
5091     }
5092 
5093     /*
5094      * First work out how many lines to do at a time, then how many bytes
5095      * we'll need for pixel storage, and allocate it.
5096      */
5097 
5098     nLines = (MAX_PIXELS + width - 1) / width;
5099     if (nLines < 1) {
5100 	nLines = 1;
5101     }
5102     if (nLines > height ) {
5103 	nLines = height;
5104     }
5105 
5106     imagePtr = instancePtr->imagePtr;
5107     if (imagePtr == NULL) {
5108 	return;			/* We must be really tight on memory. */
5109     }
5110     bitsPerPixel = imagePtr->bits_per_pixel;
5111     bytesPerLine = ((bitsPerPixel * width + 31) >> 3) & ~3;
5112     imagePtr->width = width;
5113     imagePtr->height = nLines;
5114     imagePtr->bytes_per_line = bytesPerLine;
5115     imagePtr->data = (char *)
5116 	    ckalloc((unsigned) (imagePtr->bytes_per_line * nLines));
5117     bigEndian = imagePtr->bitmap_bit_order == MSBFirst;
5118     firstBit = bigEndian? (1 << (imagePtr->bitmap_unit - 1)): 1;
5119 
5120     lineLength = masterPtr->width * 3;
5121     srcLinePtr = masterPtr->pix32 + (yStart * masterPtr->width + xStart) * 4;
5122     errLinePtr = instancePtr->error + yStart * lineLength + xStart * 3;
5123     xEnd = xStart + width;
5124 
5125     /*
5126      * Loop over the image, doing at most nLines lines before updating the
5127      * screen image.
5128      */
5129 
5130     for (; height > 0; height -= nLines) {
5131 	unsigned char *dstLinePtr = (unsigned char *) imagePtr->data;
5132 	int yEnd;
5133 
5134 	if (nLines > height) {
5135 	    nLines = height;
5136 	}
5137 	yEnd = yStart + nLines;
5138 	for (y = yStart; y < yEnd; ++y) {
5139 	    unsigned char *srcPtr = srcLinePtr;
5140 	    schar *errPtr = errLinePtr;
5141 	    unsigned char *destBytePtr = dstLinePtr;
5142 	    pixel *destLongPtr = (pixel *) dstLinePtr;
5143 
5144 	    if (colorPtr->flags & COLOR_WINDOW) {
5145 		/*
5146 		 * Color window. We dither the three components independently,
5147 		 * using Floyd-Steinberg dithering, which propagates errors
5148 		 * from the quantization of pixels to the pixels below and to
5149 		 * the right.
5150 		 */
5151 
5152 		for (x = xStart; x < xEnd; ++x) {
5153 		    int col[3];
5154 
5155 		    if (doDithering) {
5156 			for (i = 0; i < 3; ++i) {
5157 			    /*
5158 			     * Compute the error propagated into this pixel
5159 			     * for this component. If e[x,y] is the array of
5160 			     * quantization error values, we compute
5161 			     *     7/16 * e[x-1,y] + 1/16 * e[x-1,y-1]
5162 			     *   + 5/16 * e[x,y-1] + 3/16 * e[x+1,y-1]
5163 			     * and round it to an integer.
5164 			     *
5165 			     * The expression ((c + 2056) >> 4) - 128 computes
5166 			     * round(c / 16), and works correctly on machines
5167 			     * without a sign-extending right shift.
5168 			     */
5169 
5170 			    c = (x > 0) ? errPtr[-3] * 7: 0;
5171 			    if (y > 0) {
5172 				if (x > 0) {
5173 				    c += errPtr[-lineLength-3];
5174 				}
5175 				c += errPtr[-lineLength] * 5;
5176 				if ((x + 1) < masterPtr->width) {
5177 				    c += errPtr[-lineLength+3] * 3;
5178 				}
5179 			    }
5180 
5181 			    /*
5182 			     * Add the propagated error to the value of this
5183 			     * component, quantize it, and store the
5184 			     * quantization error.
5185 			     */
5186 
5187 			    c = ((c + 2056) >> 4) - 128 + *srcPtr++;
5188 			    if (c < 0) {
5189 				c = 0;
5190 			    } else if (c > 255) {
5191 				c = 255;
5192 			    }
5193 			    col[i] = colorPtr->colorQuant[i][c];
5194 			    *errPtr++ = c - col[i];
5195 			}
5196 		    } else {
5197 			/*
5198 			 * Output is virtually continuous in this case, so
5199 			 * don't bother dithering.
5200 			 */
5201 
5202 			col[0] = *srcPtr++;
5203 			col[1] = *srcPtr++;
5204 			col[2] = *srcPtr++;
5205 		    }
5206 		    srcPtr++;
5207 
5208 		    /*
5209 		     * Translate the quantized component values into an X
5210 		     * pixel value, and store it in the image.
5211 		     */
5212 
5213 		    i = colorPtr->redValues[col[0]]
5214 			    + colorPtr->greenValues[col[1]]
5215 			    + colorPtr->blueValues[col[2]];
5216 		    if (colorPtr->flags & MAP_COLORS) {
5217 			i = colorPtr->pixelMap[i];
5218 		    }
5219 		    switch (bitsPerPixel) {
5220 		    case NBBY:
5221 			*destBytePtr++ = i;
5222 			break;
5223 #ifndef __WIN32__
5224 			/*
5225 			 * This case is not valid for Windows because the
5226 			 * image format is different from the pixel format in
5227 			 * Win32. Eventually we need to fix the image code in
5228 			 * Tk to use the Windows native image ordering. This
5229 			 * would speed up the image code for all of the common
5230 			 * sizes.
5231 			 */
5232 
5233 		    case NBBY * sizeof(pixel):
5234 			*destLongPtr++ = i;
5235 			break;
5236 #endif
5237 		    default:
5238 			XPutPixel(imagePtr, x - xStart, y - yStart,
5239 				(unsigned) i);
5240 		    }
5241 		}
5242 
5243 	    } else if (bitsPerPixel > 1) {
5244 		/*
5245 		 * Multibit monochrome window. The operation here is similar
5246 		 * to the color window case above, except that there is only
5247 		 * one component. If the master image is in color, use the
5248 		 * luminance computed as
5249 		 *	0.344 * red + 0.5 * green + 0.156 * blue.
5250 		 */
5251 
5252 		for (x = xStart; x < xEnd; ++x) {
5253 		    c = (x > 0) ? errPtr[-1] * 7: 0;
5254 		    if (y > 0) {
5255 			if (x > 0)  {
5256 			    c += errPtr[-lineLength-1];
5257 			}
5258 			c += errPtr[-lineLength] * 5;
5259 			if (x + 1 < masterPtr->width) {
5260 			    c += errPtr[-lineLength+1] * 3;
5261 			}
5262 		    }
5263 		    c = ((c + 2056) >> 4) - 128;
5264 
5265 		    if ((masterPtr->flags & COLOR_IMAGE) == 0) {
5266 			c += srcPtr[0];
5267 		    } else {
5268 			c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
5269 				+ srcPtr[2] * 5 + 16) >> 5;
5270 		    }
5271 		    srcPtr += 4;
5272 
5273 		    if (c < 0) {
5274 			c = 0;
5275 		    } else if (c > 255) {
5276 			c = 255;
5277 		    }
5278 		    i = colorPtr->colorQuant[0][c];
5279 		    *errPtr++ = c - i;
5280 		    i = colorPtr->redValues[i];
5281 		    switch (bitsPerPixel) {
5282 		    case NBBY:
5283 			*destBytePtr++ = i;
5284 			break;
5285 #ifndef __WIN32__
5286 			/*
5287 			 * This case is not valid for Windows because the
5288 			 * image format is different from the pixel format in
5289 			 * Win32. Eventually we need to fix the image code in
5290 			 * Tk to use the Windows native image ordering. This
5291 			 * would speed up the image code for all of the common
5292 			 * sizes.
5293 			 */
5294 
5295 		    case NBBY * sizeof(pixel):
5296 			*destLongPtr++ = i;
5297 			break;
5298 #endif
5299 		    default:
5300 			XPutPixel(imagePtr, x - xStart, y - yStart,
5301 				(unsigned) i);
5302 		    }
5303 		}
5304 	    } else {
5305 		/*
5306 		 * 1-bit monochrome window. This is similar to the multibit
5307 		 * monochrome case above, except that the quantization is
5308 		 * simpler (we only have black = 0 and white = 255), and we
5309 		 * produce an XY-Bitmap.
5310 		 */
5311 
5312 		word = 0;
5313 		mask = firstBit;
5314 		for (x = xStart; x < xEnd; ++x) {
5315 		    /*
5316 		     * If we have accumulated a whole word, store it in the
5317 		     * image and start a new word.
5318 		     */
5319 
5320 		    if (mask == 0) {
5321 			*destLongPtr++ = word;
5322 			mask = firstBit;
5323 			word = 0;
5324 		    }
5325 
5326 		    c = (x > 0) ? errPtr[-1] * 7: 0;
5327 		    if (y > 0) {
5328 			if (x > 0) {
5329 			    c += errPtr[-lineLength-1];
5330 			}
5331 			c += errPtr[-lineLength] * 5;
5332 			if (x + 1 < masterPtr->width) {
5333 			    c += errPtr[-lineLength+1] * 3;
5334 			}
5335 		    }
5336 		    c = ((c + 2056) >> 4) - 128;
5337 
5338 		    if ((masterPtr->flags & COLOR_IMAGE) == 0) {
5339 			c += srcPtr[0];
5340 		    } else {
5341 			c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
5342 				+ srcPtr[2] * 5 + 16) >> 5;
5343 		    }
5344 		    srcPtr += 4;
5345 
5346 		    if (c < 0) {
5347 			c = 0;
5348 		    } else if (c > 255) {
5349 			c = 255;
5350 		    }
5351 		    if (c >= 128) {
5352 			word |= mask;
5353 			*errPtr++ = c - 255;
5354 		    } else {
5355 			*errPtr++ = c;
5356 		    }
5357 		    mask = bigEndian? (mask >> 1): (mask << 1);
5358 		}
5359 		*destLongPtr = word;
5360 	    }
5361 	    srcLinePtr += masterPtr->width * 4;
5362 	    errLinePtr += lineLength;
5363 	    dstLinePtr += bytesPerLine;
5364 	}
5365 
5366 	/*
5367 	 * Update the pixmap for this instance with the block of pixels that
5368 	 * we have just computed.
5369 	 */
5370 
5371 	TkPutImage(colorPtr->pixelMap, colorPtr->numColors,
5372 		instancePtr->display, instancePtr->pixels,
5373 		instancePtr->gc, imagePtr, 0, 0, xStart, yStart,
5374 		(unsigned) width, (unsigned) nLines);
5375 	yStart = yEnd;
5376     }
5377 
5378     ckfree(imagePtr->data);
5379     imagePtr->data = NULL;
5380 }
5381 
5382 /*
5383  *----------------------------------------------------------------------
5384  *
5385  * Tk_PhotoBlank --
5386  *
5387  *	This function is called to clear an entire photo image.
5388  *
5389  * Results:
5390  *	None.
5391  *
5392  * Side effects:
5393  *	The valid region for the image is set to the null region. The generic
5394  *	image code is notified that the image has changed.
5395  *
5396  *----------------------------------------------------------------------
5397  */
5398 
5399 void
Tk_PhotoBlank(Tk_PhotoHandle handle)5400 Tk_PhotoBlank(
5401     Tk_PhotoHandle handle)	/* Handle for the image to be blanked. */
5402 {
5403     PhotoMaster *masterPtr = (PhotoMaster *) handle;
5404     PhotoInstance *instancePtr;
5405 
5406     masterPtr->ditherX = masterPtr->ditherY = 0;
5407     masterPtr->flags = 0;
5408 
5409     /*
5410      * The image has valid data nowhere.
5411      */
5412 
5413     if (masterPtr->validRegion != NULL) {
5414 	TkDestroyRegion(masterPtr->validRegion);
5415     }
5416     masterPtr->validRegion = TkCreateRegion();
5417 
5418     /*
5419      * Clear out the 32-bit pixel storage array. Clear out the dithering error
5420      * arrays for each instance.
5421      */
5422 
5423     memset(masterPtr->pix32, 0,
5424 	    (size_t) (masterPtr->width * masterPtr->height * 4));
5425     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
5426 	    instancePtr = instancePtr->nextPtr) {
5427 	if (instancePtr->error) {
5428 	    memset(instancePtr->error, 0,
5429 		    (size_t) (masterPtr->width * masterPtr->height
5430 		    * 3 * sizeof(schar)));
5431 	}
5432     }
5433 
5434     /*
5435      * Tell the core image code that this image has changed.
5436      */
5437 
5438     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
5439 	    masterPtr->height, masterPtr->width, masterPtr->height);
5440 }
5441 
5442 /*
5443  *----------------------------------------------------------------------
5444  *
5445  * Tk_PhotoExpand --
5446  *
5447  *	This function is called to request that a photo image be expanded if
5448  *	necessary to be at least `width' pixels wide and `height' pixels high.
5449  *	If the user has declared a definite image size (using the -width and
5450  *	-height configuration options) then this call has no effect.
5451  *
5452  * Results:
5453  *	None.
5454  *
5455  * Side effects:
5456  *	The size of the photo image may change; if so the generic image code
5457  *	is informed.
5458  *
5459  *----------------------------------------------------------------------
5460  */
5461 
5462 int
Tk_PhotoExpand(Tcl_Interp * interp,Tk_PhotoHandle handle,int width,int height)5463 Tk_PhotoExpand(
5464     Tcl_Interp *interp,		/* Interpreter for passing back error
5465 				 * messages, or NULL. */
5466     Tk_PhotoHandle handle,	/* Handle for the image to be expanded. */
5467     int width, int height)	/* Desired minimum dimensions of the image. */
5468 {
5469     PhotoMaster *masterPtr = (PhotoMaster *) handle;
5470 
5471     if (width <= masterPtr->width) {
5472 	width = masterPtr->width;
5473     }
5474     if (height <= masterPtr->height) {
5475 	height = masterPtr->height;
5476     }
5477     if ((width != masterPtr->width) || (height != masterPtr->height)) {
5478 	if (ImgPhotoSetSize(masterPtr, MAX(width, masterPtr->width),
5479 		MAX(height, masterPtr->height)) == TCL_ERROR) {
5480 	    if (interp != NULL) {
5481 		Tcl_ResetResult(interp);
5482 		Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
5483 	    }
5484 	    return TCL_ERROR;
5485 	}
5486 	Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
5487 		masterPtr->height);
5488     }
5489     return TCL_OK;
5490 }
5491 
5492 /*
5493  *----------------------------------------------------------------------
5494  *
5495  * Tk_PhotoGetSize --
5496  *
5497  *	This function is called to obtain the current size of a photo image.
5498  *
5499  * Results:
5500  *	The image's width and height are returned in *widthp and *heightp.
5501  *
5502  * Side effects:
5503  *	None.
5504  *
5505  *----------------------------------------------------------------------
5506  */
5507 
5508 void
Tk_PhotoGetSize(Tk_PhotoHandle handle,int * widthPtr,int * heightPtr)5509 Tk_PhotoGetSize(
5510     Tk_PhotoHandle handle,	/* Handle for the image whose dimensions are
5511 				 * requested. */
5512     int *widthPtr, int *heightPtr)
5513 				/* The dimensions of the image are returned
5514 				 * here. */
5515 {
5516     PhotoMaster *masterPtr = (PhotoMaster *) handle;
5517 
5518     *widthPtr = masterPtr->width;
5519     *heightPtr = masterPtr->height;
5520 }
5521 
5522 /*
5523  *----------------------------------------------------------------------
5524  *
5525  * Tk_PhotoSetSize --
5526  *
5527  *	This function is called to set size of a photo image. This call is
5528  *	equivalent to using the -width and -height configuration options.
5529  *
5530  * Results:
5531  *	None.
5532  *
5533  * Side effects:
5534  *	The size of the image may change; if so the generic image code is
5535  *	informed.
5536  *
5537  *----------------------------------------------------------------------
5538  */
5539 
5540 int
Tk_PhotoSetSize(Tcl_Interp * interp,Tk_PhotoHandle handle,int width,int height)5541 Tk_PhotoSetSize(
5542     Tcl_Interp *interp,		/* Interpreter for passing back error
5543 				 * messages, or NULL. */
5544     Tk_PhotoHandle handle,	/* Handle for the image whose size is to be
5545 				 * set. */
5546     int width, int height)	/* New dimensions for the image. */
5547 {
5548     PhotoMaster *masterPtr = (PhotoMaster *) handle;
5549 
5550     masterPtr->userWidth = width;
5551     masterPtr->userHeight = height;
5552     if (ImgPhotoSetSize(masterPtr, ((width > 0) ? width: masterPtr->width),
5553 	    ((height > 0) ? height: masterPtr->height)) == TCL_ERROR) {
5554 	if (interp != NULL) {
5555 	    Tcl_ResetResult(interp);
5556 	    Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
5557 	}
5558 	return TCL_ERROR;
5559     }
5560     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
5561 	    masterPtr->width, masterPtr->height);
5562     return TCL_OK;
5563 }
5564 
5565 /*
5566  *----------------------------------------------------------------------
5567  *
5568  * TkGetPhotoValidRegion --
5569  *
5570  *	This function is called to get the part of the photo where there is
5571  *	valid data. Or, conversely, the part of the photo which is
5572  *	transparent.
5573  *
5574  * Results:
5575  *	A TkRegion value that indicates the current area of the photo that is
5576  *	valid. This value should not be used after any modification to the
5577  *	photo image.
5578  *
5579  * Side Effects:
5580  *	None.
5581  *
5582  *----------------------------------------------------------------------
5583  */
5584 
5585 TkRegion
TkPhotoGetValidRegion(Tk_PhotoHandle handle)5586 TkPhotoGetValidRegion(
5587     Tk_PhotoHandle handle)	/* Handle for the image whose valid region is
5588 				 * to obtained. */
5589 {
5590     PhotoMaster *masterPtr = (PhotoMaster *) handle;
5591 
5592     return masterPtr->validRegion;
5593 }
5594 
5595 /*
5596  *----------------------------------------------------------------------
5597  *
5598  * ImgGetPhoto --
5599  *
5600  *	This function is called to obtain image data from a photo image. This
5601  *	function fills in the Tk_PhotoImageBlock structure pointed to by
5602  *	`blockPtr' with details of the address and layout of the image data in
5603  *	memory.
5604  *
5605  * Results:
5606  *	A pointer to the allocated data which should be freed later. NULL if
5607  *	there is no need to free data because blockPtr->pixelPtr points
5608  *	directly to the image data.
5609  *
5610  * Side effects:
5611  *	None.
5612  *
5613  *----------------------------------------------------------------------
5614  */
5615 
5616 static char *
ImgGetPhoto(PhotoMaster * masterPtr,Tk_PhotoImageBlock * blockPtr,struct SubcommandOptions * optPtr)5617 ImgGetPhoto(
5618     PhotoMaster *masterPtr,	/* Handle for the photo image from which image
5619 				 * data is desired. */
5620     Tk_PhotoImageBlock *blockPtr,
5621 				/* Information about the address and layout of
5622 				 * the image data is returned here. */
5623     struct SubcommandOptions *optPtr)
5624 {
5625     unsigned char *pixelPtr;
5626     int x, y, greenOffset, blueOffset, alphaOffset;
5627 
5628     Tk_PhotoGetImage((Tk_PhotoHandle) masterPtr, blockPtr);
5629     blockPtr->pixelPtr += optPtr->fromY * blockPtr->pitch
5630 	    + optPtr->fromX * blockPtr->pixelSize;
5631     blockPtr->width = optPtr->fromX2 - optPtr->fromX;
5632     blockPtr->height = optPtr->fromY2 - optPtr->fromY;
5633 
5634     if (!(masterPtr->flags & COLOR_IMAGE) &&
5635 	    (!(optPtr->options & OPT_BACKGROUND)
5636 	    || ((optPtr->background->red == optPtr->background->green)
5637 	    && (optPtr->background->red == optPtr->background->blue)))) {
5638 	blockPtr->offset[0] = blockPtr->offset[1] = blockPtr->offset[2];
5639     }
5640     alphaOffset = 0;
5641     for (y = 0; y < blockPtr->height; y++) {
5642 	pixelPtr = blockPtr->pixelPtr + (y * blockPtr->pitch)
5643 		+ blockPtr->pixelSize - 1;
5644 	for (x = 0; x < blockPtr->width; x++) {
5645 	    if (*pixelPtr != 255) {
5646 		alphaOffset = 3;
5647 		break;
5648 	    }
5649 	    pixelPtr += blockPtr->pixelSize;
5650 	}
5651 	if (alphaOffset) {
5652 	    break;
5653 	}
5654     }
5655     if (!alphaOffset) {
5656 	blockPtr->offset[3]= -1; /* Tell caller alpha need not be read */
5657     }
5658     greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
5659     blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
5660     if (((optPtr->options & OPT_BACKGROUND) && alphaOffset) ||
5661 	    ((optPtr->options & OPT_GRAYSCALE) && (greenOffset||blueOffset))) {
5662 	int newPixelSize,x,y;
5663 	unsigned char *srcPtr, *destPtr;
5664 	char *data;
5665 
5666 	newPixelSize = (!(optPtr->options & OPT_BACKGROUND) && alphaOffset)
5667 		? 2 : 1;
5668 	if ((greenOffset||blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) {
5669 	    newPixelSize += 2;
5670 	}
5671 	data = ckalloc((unsigned int) (newPixelSize *
5672 		blockPtr->width * blockPtr->height));
5673 	srcPtr = blockPtr->pixelPtr + blockPtr->offset[0];
5674 	destPtr = (unsigned char *) data;
5675 	if (!greenOffset && !blueOffset) {
5676 	    for (y = blockPtr->height; y > 0; y--) {
5677 		for (x = blockPtr->width; x > 0; x--) {
5678 		    *destPtr = *srcPtr;
5679 		    srcPtr += blockPtr->pixelSize;
5680 		    destPtr += newPixelSize;
5681 		}
5682 		srcPtr += blockPtr->pitch -
5683 			blockPtr->width * blockPtr->pixelSize;
5684 	    }
5685 	} else if (optPtr->options & OPT_GRAYSCALE) {
5686 	    for (y = blockPtr->height; y > 0; y--) {
5687 		for (x = blockPtr->width; x > 0; x--) {
5688 		    *destPtr = (unsigned char) ((srcPtr[0]*11 + srcPtr[1]*16
5689 			    + srcPtr[2]*5 + 16) >> 5);
5690 		    srcPtr += blockPtr->pixelSize;
5691 		    destPtr += newPixelSize;
5692 		}
5693 		srcPtr += blockPtr->pitch -
5694 			blockPtr->width * blockPtr->pixelSize;
5695 	    }
5696 	} else {
5697 	    for (y = blockPtr->height; y > 0; y--) {
5698 		for (x = blockPtr->width; x > 0; x--) {
5699 		    destPtr[0] = srcPtr[0];
5700 		    destPtr[1] = srcPtr[1];
5701 		    destPtr[2] = srcPtr[2];
5702 		    srcPtr += blockPtr->pixelSize;
5703 		    destPtr += newPixelSize;
5704 		}
5705 		srcPtr += blockPtr->pitch -
5706 			blockPtr->width * blockPtr->pixelSize;
5707 	    }
5708 	}
5709 	srcPtr = blockPtr->pixelPtr + alphaOffset;
5710 	destPtr = (unsigned char *) data;
5711 	if (!alphaOffset) {
5712 	    /*
5713 	     * Nothing to be done.
5714 	     */
5715 	} else if (optPtr->options & OPT_BACKGROUND) {
5716 	    if (newPixelSize > 2) {
5717 		int red = optPtr->background->red>>8;
5718 		int green = optPtr->background->green>>8;
5719 		int blue = optPtr->background->blue>>8;
5720 
5721 		for (y = blockPtr->height; y > 0; y--) {
5722 		    for (x = blockPtr->width; x > 0; x--) {
5723 			destPtr[0] += (unsigned char) (((255 - *srcPtr) *
5724 				(red-destPtr[0])) / 255);
5725 			destPtr[1] += (unsigned char) (((255 - *srcPtr) *
5726 				(green-destPtr[1])) / 255);
5727 			destPtr[2] += (unsigned char) (((255 - *srcPtr) *
5728 				(blue-destPtr[2])) / 255);
5729 			srcPtr += blockPtr->pixelSize;
5730 			destPtr += newPixelSize;
5731 		    }
5732 		    srcPtr += blockPtr->pitch -
5733 			    blockPtr->width * blockPtr->pixelSize;
5734 		}
5735 	    } else {
5736 	 	int gray = (unsigned char) (((optPtr->background->red>>8) * 11
5737 			+ (optPtr->background->green>>8) * 16
5738 			+ (optPtr->background->blue>>8) * 5 + 16) >> 5);
5739 
5740 		for (y = blockPtr->height; y > 0; y--) {
5741 		    for (x = blockPtr->width; x > 0; x--) {
5742 			destPtr[0] += ((255 - *srcPtr) *
5743 				(gray-destPtr[0])) / 255;
5744 			srcPtr += blockPtr->pixelSize;
5745 			destPtr += newPixelSize;
5746 		    }
5747 		    srcPtr += blockPtr->pitch -
5748 			    blockPtr->width * blockPtr->pixelSize;
5749 		}
5750 	    }
5751 	} else {
5752 	    destPtr += newPixelSize-1;
5753 	    for (y = blockPtr->height; y > 0; y--) {
5754 		for (x = blockPtr->width; x > 0; x--) {
5755 		    *destPtr = *srcPtr;
5756 		    srcPtr += blockPtr->pixelSize;
5757 		    destPtr += newPixelSize;
5758 		}
5759 		srcPtr += blockPtr->pitch -
5760 			blockPtr->width * blockPtr->pixelSize;
5761 	    }
5762 	}
5763 	blockPtr->pixelPtr = (unsigned char *) data;
5764 	blockPtr->pixelSize = newPixelSize;
5765 	blockPtr->pitch = newPixelSize * blockPtr->width;
5766 	blockPtr->offset[0] = 0;
5767 	if (newPixelSize>2) {
5768 	    blockPtr->offset[1]= 1;
5769 	    blockPtr->offset[2]= 2;
5770 	    blockPtr->offset[3]= 3;
5771 	} else {
5772 	    blockPtr->offset[1]= 0;
5773 	    blockPtr->offset[2]= 0;
5774 	    blockPtr->offset[3]= 1;
5775 	}
5776 	return data;
5777     }
5778     return NULL;
5779 }
5780 
5781 /*
5782  *----------------------------------------------------------------------
5783  *
5784  * ImgStringWrite --
5785  *
5786  *	Default string write function. The data is formatted in the default
5787  *	format as accepted by the "<img> put" command.
5788  *
5789  * Results:
5790  *	A standard Tcl result.
5791  *
5792  * Side effects:
5793  *	See the user documentation.
5794  *
5795  *----------------------------------------------------------------------
5796  */
5797 
5798 static int
ImgStringWrite(Tcl_Interp * interp,Tcl_Obj * formatString,Tk_PhotoImageBlock * blockPtr)5799 ImgStringWrite(
5800     Tcl_Interp *interp,
5801     Tcl_Obj *formatString,
5802     Tk_PhotoImageBlock *blockPtr)
5803 {
5804     int row, col;
5805     char *line, *linePtr;
5806     unsigned char *pixelPtr;
5807     int greenOffset, blueOffset;
5808     Tcl_DString data;
5809 
5810     greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
5811     blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
5812 
5813     Tcl_DStringInit(&data);
5814     if ((blockPtr->width > 0) && (blockPtr->height > 0)) {
5815 	line = (char *) ckalloc((unsigned int) ((8 * blockPtr->width) + 2));
5816 	for (row=0; row<blockPtr->height; row++) {
5817 	    pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] +
5818 		    row * blockPtr->pitch;
5819 	    linePtr = line;
5820 	    for (col=0; col<blockPtr->width; col++) {
5821 		sprintf(linePtr, " #%02x%02x%02x", *pixelPtr,
5822 			pixelPtr[greenOffset], pixelPtr[blueOffset]);
5823 		pixelPtr += blockPtr->pixelSize;
5824 		linePtr += 8;
5825 	    }
5826 	    Tcl_DStringAppendElement(&data, line+1);
5827 	}
5828 	ckfree (line);
5829     }
5830     Tcl_DStringResult(interp, &data);
5831     return TCL_OK;
5832 }
5833 
5834 /*
5835  *----------------------------------------------------------------------
5836  *
5837  * Tk_PhotoGetImage --
5838  *
5839  *	This function is called to obtain image data from a photo image. This
5840  *	function fills in the Tk_PhotoImageBlock structure pointed to by
5841  *	`blockPtr' with details of the address and layout of the image data in
5842  *	memory.
5843  *
5844  * Results:
5845  *	TRUE (1) indicating that image data is available, for backwards
5846  *	compatibility with the old photo widget.
5847  *
5848  * Side effects:
5849  *	None.
5850  *
5851  *----------------------------------------------------------------------
5852  */
5853 
5854 int
Tk_PhotoGetImage(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr)5855 Tk_PhotoGetImage(
5856     Tk_PhotoHandle handle,	/* Handle for the photo image from which image
5857 				 * data is desired. */
5858     Tk_PhotoImageBlock *blockPtr)
5859 				/* Information about the address and layout of
5860 				 * the image data is returned here. */
5861 {
5862     PhotoMaster *masterPtr = (PhotoMaster *) handle;
5863 
5864     blockPtr->pixelPtr = masterPtr->pix32;
5865     blockPtr->width = masterPtr->width;
5866     blockPtr->height = masterPtr->height;
5867     blockPtr->pitch = masterPtr->width * 4;
5868     blockPtr->pixelSize = 4;
5869     blockPtr->offset[0] = 0;
5870     blockPtr->offset[1] = 1;
5871     blockPtr->offset[2] = 2;
5872     blockPtr->offset[3] = 3;
5873     return 1;
5874 }
5875 
5876 /*
5877  *----------------------------------------------------------------------
5878  *
5879  * PhotoOptionFind --
5880  *
5881  *	Finds a specific Photo option.
5882  *
5883  * Results:
5884  *	None.
5885  *
5886  * Side effects:
5887  *	After commands are removed.
5888  *
5889  *----------------------------------------------------------------------
5890  */
5891 
5892 typedef struct OptionAssocData {
5893     struct OptionAssocData *nextPtr;
5894 				/* Pointer to next OptionAssocData. */
5895     Tcl_ObjCmdProc *command;	/* Command associated with this option. */
5896     char name[1];		/* Name of option (remaining chars) */
5897 } OptionAssocData;
5898 
5899 static Tcl_ObjCmdProc *
PhotoOptionFind(Tcl_Interp * interp,Tcl_Obj * obj)5900 PhotoOptionFind(
5901     Tcl_Interp *interp,		/* Interpreter that is being deleted. */
5902     Tcl_Obj *obj)		/* Name of option to be found. */
5903 {
5904     int length;
5905     char *name = Tcl_GetStringFromObj(obj, &length);
5906     char *prevname = NULL;
5907     Tcl_ObjCmdProc *proc = NULL;
5908     OptionAssocData *list = (OptionAssocData *) Tcl_GetAssocData(interp,
5909 	    "photoOption", NULL);
5910 
5911     while (list != NULL) {
5912 	if (strncmp(name, list->name, (unsigned) length) == 0) {
5913 	    if (proc != NULL) {
5914 		Tcl_ResetResult(interp);
5915 		Tcl_AppendResult(interp, "ambiguous option \"", name,
5916 			"\": must be ", prevname, NULL);
5917 		while (list->nextPtr != NULL) {
5918 		    Tcl_AppendResult(interp, prevname, ", ",NULL);
5919 		    list = list->nextPtr;
5920 		    prevname = list->name;
5921 		}
5922 		Tcl_AppendResult(interp, ", or", prevname, NULL);
5923 		return NULL;
5924 	    }
5925 	    proc = list->command;
5926 	    prevname = list->name;
5927 	}
5928 	list = list->nextPtr;
5929     }
5930     if (proc != NULL) {
5931 	Tcl_ResetResult(interp);
5932     }
5933     return proc;
5934 }
5935 
5936 /*
5937  *----------------------------------------------------------------------
5938  *
5939  * PhotoOptionCleanupProc --
5940  *
5941  *	This function is invoked whenever an interpreter is deleted to cleanup
5942  *	the AssocData for "photoVisitor".
5943  *
5944  * Results:
5945  *	None.
5946  *
5947  * Side effects:
5948  *	Photo Visitor options are removed.
5949  *
5950  *----------------------------------------------------------------------
5951  */
5952 
5953 static void
PhotoOptionCleanupProc(ClientData clientData,Tcl_Interp * interp)5954 PhotoOptionCleanupProc(
5955     ClientData clientData,	/* Points to "photoVisitor" AssocData for the
5956 				 * interpreter. */
5957     Tcl_Interp *interp)		/* Interpreter that is being deleted. */
5958 {
5959     OptionAssocData *list = (OptionAssocData *) clientData;
5960 
5961     while (list != NULL) {
5962 	register OptionAssocData *ptr;
5963 
5964 	list = (ptr = list)->nextPtr;
5965 	ckfree((char *) ptr);
5966     }
5967 }
5968 
5969 /*
5970  *--------------------------------------------------------------
5971  *
5972  * Tk_CreatePhotoOption --
5973  *
5974  *	This function may be invoked to add a new kind of photo option to the
5975  *	core photo command supported by Tk.
5976  *
5977  * Results:
5978  *	None.
5979  *
5980  * Side effects:
5981  *	From now on, the new option will be useable by the photo command.
5982  *
5983  *--------------------------------------------------------------
5984  */
5985 
5986 MODULE_SCOPE void
Tk_CreatePhotoOption(Tcl_Interp * interp,CONST char * name,Tcl_ObjCmdProc * proc)5987 Tk_CreatePhotoOption(
5988     Tcl_Interp *interp,		/* Interpreter. */
5989     CONST char *name,		/* Option name. */
5990     Tcl_ObjCmdProc *proc)	/* Function to execute command. */
5991 {
5992     OptionAssocData *typePtr2, *prevPtr, *ptr;
5993     OptionAssocData *list = (OptionAssocData *)
5994 	    Tcl_GetAssocData(interp, "photoOption", NULL);
5995 
5996     /*
5997      * If there's already a photo option with the given name, remove it.
5998      */
5999 
6000     for (typePtr2 = list, prevPtr = NULL; typePtr2 != NULL;
6001 	    prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
6002 	if (strcmp(typePtr2->name, name) == 0) {
6003 	    if (prevPtr == NULL) {
6004 		list = typePtr2->nextPtr;
6005 	    } else {
6006 		prevPtr->nextPtr = typePtr2->nextPtr;
6007 	    }
6008 	    ckfree((char *) typePtr2);
6009 	    break;
6010 	}
6011     }
6012     ptr = (OptionAssocData *) ckalloc(sizeof(OptionAssocData) + strlen(name));
6013     strcpy(&(ptr->name[0]), name);
6014     ptr->command = proc;
6015     ptr->nextPtr = list;
6016     Tcl_SetAssocData(interp, "photoOption", PhotoOptionCleanupProc,
6017 	    (ClientData) ptr);
6018 }
6019 
6020 /*
6021  *--------------------------------------------------------------
6022  *
6023  * TkPostscriptPhoto --
6024  *
6025  *	This function is called to output the contents of a photo image in
6026  *	Postscript by calling the Tk_PostscriptPhoto function.
6027  *
6028  * Results:
6029  *	Returns a standard Tcl return value.
6030  *
6031  * Side effects:
6032  *	None.
6033  *
6034  *--------------------------------------------------------------
6035  */
6036 
6037 static int
ImgPhotoPostscript(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tk_PostscriptInfo psInfo,int x,int y,int width,int height,int prepass)6038 ImgPhotoPostscript(
6039     ClientData clientData,	/* Handle for the photo image. */
6040     Tcl_Interp *interp,		/* Interpreter. */
6041     Tk_Window tkwin,		/* (unused) */
6042     Tk_PostscriptInfo psInfo,	/* Postscript info. */
6043     int x, int y,		/* First pixel to output. */
6044     int width, int height,	/* Width and height of area. */
6045     int prepass)		/* (unused) */
6046 {
6047     Tk_PhotoImageBlock block;
6048 
6049     Tk_PhotoGetImage((Tk_PhotoHandle) clientData, &block);
6050     block.pixelPtr += y * block.pitch + x * block.pixelSize;
6051 
6052     return Tk_PostscriptPhoto(interp, &block, psInfo, width, height);
6053 }
6054 
6055 /*
6056  *----------------------------------------------------------------------
6057  *
6058  * Tk_PhotoPutBlock_NoComposite, Tk_PhotoPutZoomedBlock_NoComposite --
6059  *
6060  * These backward-compatability functions just exist to fill slots in stubs
6061  * table. For the behaviour of *_NoComposite, refer to the corresponding
6062  * function without the extra suffix, except that the compositing rule is
6063  * always "overlay" and the function always panics on memory-allocation
6064  * failure.
6065  *
6066  *----------------------------------------------------------------------
6067  */
6068 
6069 void
Tk_PhotoPutBlock_NoComposite(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height)6070 Tk_PhotoPutBlock_NoComposite(
6071     Tk_PhotoHandle handle,
6072     Tk_PhotoImageBlock *blockPtr,
6073     int x, int y, int width, int height)
6074 {
6075     if (Tk_PhotoPutBlock(NULL, handle, blockPtr, x, y, width, height,
6076 	    TK_PHOTO_COMPOSITE_OVERLAY) != TCL_OK) {
6077 	Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6078     }
6079 }
6080 
6081 void
Tk_PhotoPutZoomedBlock_NoComposite(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int zoomX,int zoomY,int subsampleX,int subsampleY)6082 Tk_PhotoPutZoomedBlock_NoComposite(
6083     Tk_PhotoHandle handle,
6084     Tk_PhotoImageBlock *blockPtr,
6085     int x, int y, int width, int height,
6086     int zoomX, int zoomY, int subsampleX, int subsampleY)
6087 {
6088     if (Tk_PhotoPutZoomedBlock(NULL, handle, blockPtr, x, y, width, height,
6089 	    zoomX, zoomY, subsampleX, subsampleY,
6090 	    TK_PHOTO_COMPOSITE_OVERLAY) != TCL_OK) {
6091 	Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6092     }
6093 }
6094 
6095 /*
6096  *----------------------------------------------------------------------
6097  *
6098  * Tk_PhotoExpand_Panic, Tk_PhotoPutBlock_Panic,
6099  * Tk_PhotoPutZoomedBlock_Panic, Tk_PhotoSetSize_Panic
6100  *
6101  * Backward compatability functions for preserving the old behaviour (i.e.
6102  * panic on memory allocation failure) so that extensions do not need to be
6103  * significantly updated to take account of TIP #116. These call the new
6104  * interface (i.e. the interface without the extra suffix), but panic if an
6105  * error condition is returned.
6106  *
6107  *----------------------------------------------------------------------
6108  */
6109 
6110 void
Tk_PhotoExpand_Panic(Tk_PhotoHandle handle,int width,int height)6111 Tk_PhotoExpand_Panic(
6112     Tk_PhotoHandle handle,
6113     int width, int height)
6114 {
6115     if (Tk_PhotoExpand(NULL, handle, width, height) != TCL_OK) {
6116 	Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6117     }
6118 }
6119 
6120 void
Tk_PhotoPutBlock_Panic(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int compRule)6121 Tk_PhotoPutBlock_Panic(
6122     Tk_PhotoHandle handle,
6123     Tk_PhotoImageBlock *blockPtr,
6124     int x, int y, int width, int height, int compRule)
6125 {
6126     if (Tk_PhotoPutBlock(NULL, handle, blockPtr, x, y, width, height,
6127 	    compRule) != TCL_OK) {
6128 	Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6129     }
6130 }
6131 
6132 void
Tk_PhotoPutZoomedBlock_Panic(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int zoomX,int zoomY,int subsampleX,int subsampleY,int compRule)6133 Tk_PhotoPutZoomedBlock_Panic(
6134     Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr,
6135     int x, int y, int width, int height,
6136     int zoomX, int zoomY, int subsampleX, int subsampleY,
6137     int compRule)
6138 {
6139     if (Tk_PhotoPutZoomedBlock(NULL, handle, blockPtr, x, y, width, height,
6140 	    zoomX, zoomY, subsampleX, subsampleY, compRule) != TCL_OK) {
6141 	Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6142     }
6143 }
6144 
6145 void
Tk_PhotoSetSize_Panic(Tk_PhotoHandle handle,int width,int height)6146 Tk_PhotoSetSize_Panic(
6147     Tk_PhotoHandle handle,
6148     int width, int height)
6149 {
6150     if (Tk_PhotoSetSize(NULL, handle, width, height) != TCL_OK) {
6151 	Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6152     }
6153 }
6154 
6155 /*
6156  * Local Variables:
6157  * mode: c
6158  * c-basic-offset: 4
6159  * fill-column: 78
6160  * End:
6161  */
6162