Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtHelp / il / ilX.c
1 /* $XConsortium: ilX.c /main/11 1996/11/12 05:02:17 pascale $ */
2 /**---------------------------------------------------------------------
3 ***     
4 ***    (c)Copyright 1991 Hewlett-Packard Co.
5 ***    
6 ***                             RESTRICTED RIGHTS LEGEND
7 ***    Use, duplication, or disclosure by the U.S. Government is subject to
8 ***    restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
9 ***    Technical Data and Computer Software clause in DFARS 252.227-7013.
10 ***                             Hewlett-Packard Company
11 ***                             3000 Hanover Street
12 ***                             Palo Alto, CA 94304 U.S.A.
13 ***    Rights for non-DOD U.S. Government Departments and Agencies are as set
14 ***    forth in FAR 52.227-19(c)(1,2).
15 ***
16 ***-------------------------------------------------------------------*/
17
18 #include "ilint.h"
19 #include "ilcontext.h"
20 #include "ilX.h"
21 #include <math.h>
22 #include <X11/Xutil.h>
23 #include "ilpipelem.h"
24 #include "ilerrors.h"
25
26
27 #define X_COLOR_MAX             65535       /* max value for X colormap RGB 
28                                                value */
29
30     /*  Buffer allocation checks.  Buffers are allocated for example when 
31         writing to a 24 bit drawable: the pipe image pixels are converted 
32         from 3 bytes to 4 bytes (CARD32).
33     */
34 #define MAX_IMAGE_BUFFER_SIZE  100000       /* force strips if larger than 
35                                                this ... */
36 #define BEST_IMAGE_BUFFER_SIZE 50000        /* to strips of this size */
37
38     /*  Masks for ilFreeColorData(); see below.
39     */
40 #define IL_FREE_XCOLORS         (1<<0)
41 #define IL_FREE_XGRAYS          (1<<1)
42
43     /*  Codes for view of X , in "ilXWCRec.i.visualType".  When the visual is
44         unsupported or an insufficient # of colors can be allocated from the
45         colormap, the drawable defaults to IL_XWC_BITONAL.  Images rendered 
46         to such an XWC are converted to bitonal, then XPutImage() of an 
47         XYBitmap is done - the XWC GC's foreground/background colors are used 
48         for black/white.
49     */
50 #define IL_X_MAX_VISUAL_TYPE  3             /* max value of IL_XWC_BITONAL 
51                                                et al*/
52
53     /*  Default # of grays or dither colors to allocate for pseudo-color. */
54 #define IL_DEFAULT_X_GRAYS  32
55 #define NRED                4
56 #define NGREEN              8
57 #define NBLUE               4
58
59     /*  Internals of an XWC (X Write Context), an IL object created by 
60         ilCreateXWC().
61         An XWC is associated with the visual "visual" and "colormap".
62         "i" contains basic information returned by ilQueryXWC().
63             If pColors is non-null, it points to a list of length "nColors",
64         of colors allocated from "colormap".  "pad" in each colorcell is 
65         used as a flag:
66         == 0 if color not allocated, else color was sucessfully allocated.
67             If non-null, colorMapImage is an image for mapping to X images 
68             using ilMap().  
69         For example, for 8 bit pseudo-color when 484 color handling is used,
70         "pColors" points to 128 colors, and "colorMapImage" points to a 256 
71         pixel image where each entry is the pixel to use for color 
72         (red*4*8 + green*8 + blue).
73         If "colorMapImage" is null then the alloc failed or has not been tried.
74         Note: above applies also to Direct/TrueColor visuals, with the same 
75         names.
76         The above also applies to the "gray" fields, with the "gray" names.
77     */
78 typedef struct {
79     ilObjectRec         o;                  /* std header: MUST BE FIRST */
80     ilXWCInfo           i;                  /* see above */
81     XVisualInfo         visualInfo;         /* X info on "visual" */
82     XColor             *pColors;            /* ptr to list of allocated 
83                                                colors or null */
84     int                 nColors;            /* size of *pColors list */
85     ilClientImage       colorMapImage;      /* see above */
86     ilBool              mapDirect;          /* ilMap(colorMapImage), 
87                                                Direct/TrueColor */
88     XColor             *pGrays;             /* ptr to list of allocated grays 
89                                                or null */
90     int                 nGrays;             /* size of *pGrays list */
91     ilClientImage       grayMapImage;       /* same as colorMapImage, but for 
92                                                grays */
93     } ilXWCRec, *ilXWCPtr;
94
95 typedef ilError   (*executeFunctionType)();
96
97         /*  ------------------------ ilFreeColorData ---------------------- */
98         /*  Free the color list and translation table in the given XWC if 
99             present. "freeMasks" indicates which should be freed: 
100             IL_FREE_XCOLORS/XGRAYS, or ~0 for everything.
101         */
102 static void ilFreeColorData (
103     register ilXWCPtr   pXWC,
104     unsigned long       freeMask
105     )
106 {
107 int                     i;
108 XColor                 *pColor;
109
110         /*  If color list present: free each color if allocated (pad != 0); 
111             free list.
112         */
113 if (freeMask & IL_FREE_XCOLORS) {
114     if (pXWC->pColors) {
115         for (i = 0, pColor = pXWC->pColors; i < pXWC->nColors; i++) {
116             if (pColor->pad)
117                 XFreeColors (pXWC->i.display, pXWC->i.colormap, 
118                              &pColor->pixel, 1, 0L);
119             pColor++;
120             }
121         IL_FREE (pXWC->pColors);
122         pXWC->pColors = (XColor *)NULL;
123         pXWC->nColors = 0;
124         }
125     if (pXWC->colorMapImage) {
126         ilDestroyObject (pXWC->colorMapImage);
127         pXWC->colorMapImage = (ilClientImage)NULL;
128         }
129     }
130
131         /*  Same for gray list
132         */
133 if (freeMask & IL_FREE_XGRAYS) {
134     if (pXWC->pGrays) {
135         for (i = 0, pColor = pXWC->pGrays; i < pXWC->nGrays; i++) {
136             if (pColor->pad)
137                 XFreeColors (pXWC->i.display, pXWC->i.colormap, 
138                              &pColor->pixel, 1, 0L);
139             pColor++;
140             }
141         IL_FREE (pXWC->pGrays);
142         pXWC->pGrays = (XColor *)NULL;
143         pXWC->nGrays = 0;
144         }
145     if (pXWC->grayMapImage) {
146         ilDestroyObject (pXWC->grayMapImage);
147         pXWC->grayMapImage = (ilClientImage)NULL;
148         }
149     }
150 }
151
152         /*  ----------------------- ilDestroyXWC -------------------------- */
153         /*  Destroy() function for XWC objects.  Free the color list if 
154             present.
155             The GC for the default XWC will be destroyed when the context is
156             freed, by ilXDestroyContext() below.
157         */
158 static void ilDestroyXWC (
159     ilPtr pPrivate
160     )
161 {
162 ilObject object = (ilObject)pPrivate;
163 register ilXWCPtr       pXWC;
164
165     pXWC = (ilXWCPtr)object;
166
167 /* ~ on signed integer is not recommended, play it safe here */
168     ilFreeColorData (pXWC, ~(0UL));
169 }
170
171
172         /*  --------------------- ilGammaCorrect -------------------------- */
173         /*  Returns a value from 0..scaleValue, given "value", from 
174             0.."maxValue" - 1, scaled up to "scaleValue" (e.g. 65535 for 
175             X color values).
176             Currently a misnomer - not doing any gamma correction 
177             (gamma = 1.0).
178         */
179 static int ilGammaCorrect (
180     long                scaleValue,
181     int                 value,
182     int                 maxValue
183     )
184 {
185 register int            allocValue;
186
187     if (value == 0) 
188         allocValue = 0;
189     else if (value == (maxValue - 1))
190         allocValue = scaleValue;
191     else {
192         allocValue = value * scaleValue / (maxValue-1);
193         if (allocValue < 0)
194             allocValue = 0;
195         else if (allocValue > scaleValue)
196             allocValue = scaleValue;
197         }
198     return allocValue;
199 }
200
201
202         /*  --------------------- ilAllocateXDitherColors ------------------ */
203         /*  Internal function to ilCreateXWC().  Attempts to allocate enough 
204             colors in pXWC->i.colormap to support the visual as a 484 
205             pseudo-color visual.
206             An error code is returned to the given context if an error 
207             (e.g. malloc) error occurs; IL_OK if the grays could not be 
208             alloc'd (but false is returned).
209         */
210 static ilBool ilAllocateXDitherColors (
211     ilContext               context,
212     register ilXWCPtr       pXWC
213     )
214 {
215
216 int             i, red, green, blue;                
217 XColor         *pColor;                             
218 ilPtr           pTranslate;                         
219 ilImageInfo     imageInfo, *pImageInfo;
220
221         context->error = IL_OK;                         /* assume no errors */
222         if (pXWC->colorMapImage)
223             return TRUE;                           /* already alloc'd; EXIT */
224
225             /*  Allocate a client image to use as LUT for mapping to X's 
226                 colors.
227                 Point pTranslate to the allocated pixels.
228             */
229         imageInfo.pDes = IL_DES_GRAY;
230         imageInfo.pFormat = IL_FORMAT_BYTE;
231         imageInfo.width = 256;
232         imageInfo.height = 1;
233         imageInfo.clientPixels = FALSE;
234         pXWC->colorMapImage = ilCreateClientImage (context, &imageInfo, 0);
235         if (!pXWC->colorMapImage) 
236             return FALSE;                               /* EXIT */
237         ilQueryClientImage (pXWC->colorMapImage, &pImageInfo, 0);
238         pTranslate = pImageInfo->plane[0].pPixels;
239
240         pXWC->nColors = NRED * NGREEN * NBLUE;
241         pXWC->pColors = (XColor *)IL_MALLOC (pXWC->nColors * sizeof(XColor));
242         if (!pXWC->pColors) {
243             ilDestroyObject (pXWC->colorMapImage);
244             pXWC->colorMapImage = (ilClientImage)NULL;
245             context->error = IL_ERROR_MALLOC;
246             return FALSE;                               /* EXIT */
247             }
248         for (i = 0, pColor = pXWC->pColors; i < pXWC->nColors; i++, pColor++)
249             pColor->pad = FALSE;            /* init pad, in case below fails */
250                                                                               
251             /*  Allocate 484 colors (128 in all) */
252         pColor = pXWC->pColors;
253         for (red = 0; red < NRED; red++)
254           for (green = 0; green < NGREEN; green++)
255               for (blue = 0; blue < NBLUE; blue++) {
256                 pColor->red = ilGammaCorrect (X_COLOR_MAX, red, NRED);
257                 pColor->green = ilGammaCorrect (X_COLOR_MAX, green, NGREEN);
258                 pColor->blue = ilGammaCorrect (X_COLOR_MAX, blue, NBLUE);
259                 if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) {
260                     ilFreeColorData (pXWC, IL_FREE_XCOLORS);
261                     return FALSE;
262                     }
263                 pTranslate [red*(NGREEN*NBLUE) + green*NBLUE + blue] = 
264                     pColor->pixel;
265                 pColor->pad = TRUE;         /* mark as alloc'd */
266                 pColor++;
267                 }
268
269     return TRUE;                            /* colors successfully alloc'd */
270 }
271                                                                              
272
273     /*  ---------------------------- ilAllocateXGrays ---------------------- */
274     /*  Allocate "nGrays" from the colormap associated with the given XWC or 
275         return error.
276         The grays are ramped evenly from 0..nGrays-1.  If there are "nGrays" 
277         existing grays, they are used, else if not nGrays, they are
278         deallocated.
279         An error code is returned to the given context if an error 
280         (e.g. malloc) error occurs; IL_OK if the grays could not be alloc'd 
281         (but false is returned).
282     */
283 static ilBool ilAllocateXGrays (
284     ilContext               context,
285     register ilXWCPtr       pXWC,
286     int                     nGrays
287     )
288 {
289 int             i, index;
290 XColor         *pColor;                             
291 ilPtr           pTranslate;                         
292 ilImageInfo     imageInfo, *pImageInfo;
293 double          spreadFactor;
294
295         /*  Use the grays if the same number, else deallocate them.
296         */
297     context->error = IL_OK;                         /* assume no errors */
298     if (pXWC->pGrays)
299         if (pXWC->nGrays == nGrays)
300             return TRUE;
301         else ilFreeColorData (pXWC, IL_FREE_XGRAYS);
302
303     if (nGrays > 256)
304         return FALSE;                               /* EXIT */
305
306         /*  Allocate a client image to use as LUT for mapping to X's colors.
307             Point pTranslate to the allocated pixels.
308         */
309     imageInfo.pDes = IL_DES_GRAY;
310     imageInfo.pFormat = IL_FORMAT_BYTE;
311     imageInfo.width = 256;
312     imageInfo.height = 1;
313     imageInfo.clientPixels = FALSE;
314     pXWC->grayMapImage = ilCreateClientImage (context, &imageInfo, 0);
315     if (!pXWC->grayMapImage) 
316         return FALSE;                               /* EXIT */
317     ilQueryClientImage (pXWC->grayMapImage, &pImageInfo, 0);
318     pTranslate = pImageInfo->plane[0].pPixels;
319
320     pXWC->nGrays = nGrays;
321     pXWC->pGrays = (XColor *)IL_MALLOC (pXWC->nGrays * sizeof(XColor));
322     if (!pXWC->pGrays) {
323         ilDestroyObject (pXWC->grayMapImage);
324         pXWC->colorMapImage = (ilClientImage)NULL;
325         context->error = IL_ERROR_MALLOC;
326         return FALSE;                               /* EXIT */
327         }
328     for (i = 0, pColor = pXWC->pGrays; i < pXWC->nGrays; i++, pColor++)
329         pColor->pad = FALSE;                /* init pad, in case below fails */
330                                                                               
331         /*  Allocate the grays; return error on any failure. */
332     for (i = 0; i < nGrays; i++) {
333         pColor = &pXWC->pGrays [i];
334         pColor->red = pColor->green = pColor->blue = 
335             ilGammaCorrect (X_COLOR_MAX, i, nGrays);
336         if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) {
337             pColor->pad = FALSE;
338             ilFreeColorData (pXWC, IL_FREE_XGRAYS);
339             return FALSE;                           /* EXIT */
340             }                                                                  
341         pColor->pad = TRUE;                                                   
342         }
343
344         /*  Grays allocated ok; spread the allocated colors over the whole 256
345             area.  In effect, color-slam all 256-level gray images into nGrays.
346             NOTE: gray images with other than 256 levels could be supported in
347             future!
348         */
349     spreadFactor = ((double)(nGrays - 1)) / (double)255;
350     pColor = pXWC->pGrays;
351     for (i = 0; i < 256; i++) {
352         index = spreadFactor * (double)i + 0.5;
353         if (index > (nGrays - 1))
354             index = nGrays - 1;
355         pTranslate [i] = pColor [index].pixel;
356         }
357
358     return TRUE;
359 }
360
361
362     /*  ---------------------- ilAllocateXDirectColors --------------------- */
363     /*  Allocate "nLevels" levels of each of RGB for a DirectColor or a 
364         TrueColor visual.
365         "nLevels" should be passed as 256; it becomes 1/2 of that if failure 
366         occurs this function recurses on failure until an unacceptable # of 
367         levels not alloc'd.
368     */
369 static ilBool ilAllocateXDirectColors (
370     register ilXWCPtr       pXWC,
371     int                     nLevels
372     )
373 {
374 int             i, j, pixel, red, green, blue, nReplicate;
375 XColor         *pColor;                             
376 ilPtr           pTranslate;                         
377 ilImageInfo     imageInfo, *pImageInfo;
378 ilContext       context;
379 #define         MIN_DIRECT_LEVELS       32  /* min # of acceptable levels */
380
381     if (pXWC->colorMapImage)
382         return TRUE;                                /* already alloc'd; EXIT */
383
384         /*  Create a 256x1 3 byte/pixel map image. */
385     context = pXWC->o.p.context;
386     imageInfo.pDes = IL_DES_RGB;
387     imageInfo.pFormat = IL_FORMAT_3BYTE_PIXEL;
388     imageInfo.width = 256;
389     imageInfo.height = 1;
390     imageInfo.clientPixels = FALSE;
391     pXWC->colorMapImage = ilCreateClientImage (context, &imageInfo, 0);
392     if (!pXWC->colorMapImage) 
393         return FALSE;
394     ilQueryClientImage (pXWC->colorMapImage, &pImageInfo, 0);
395     pTranslate = pImageInfo->plane[0].pPixels;
396
397         /*  Try to allocate nLevels read-only levels each of RGB, in a logical
398             ramp order.  Set pXWC->mapDirect to false if pixel value != RGB 
399             value, in which case pipe image pixels must be ilMap()'d to X 
400             pixel values.
401             If can't allocate, try to allocate nLevels/2 unless that is too 
402             few colors, in which we fail.  Spread the X pixels into the 256 
403             entry map image.
404         */
405     pXWC->nColors = nLevels;
406     pXWC->pColors = (XColor *)IL_MALLOC_ZERO (pXWC->nColors * sizeof(XColor));
407     if (!pXWC->pColors) {
408         ilDestroyObject (pXWC->colorMapImage);
409         pXWC->colorMapImage = (ilClientImage)NULL;
410         context->error = IL_ERROR_MALLOC;
411         return FALSE;
412         }
413
414     pXWC->mapDirect = FALSE;
415     nReplicate = 256 / nLevels;     /* # of times to replicate pixel into map 
416                                        image */
417     for (i = 0, pColor = pXWC->pColors; i < nLevels; i++, pColor++) {
418         pColor->red = pColor->green = pColor->blue = 
419             ilGammaCorrect (X_COLOR_MAX, i, nLevels);
420         pColor->flags = DoRed | DoGreen | DoBlue;
421         if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) {
422             ilFreeColorData (pXWC, IL_FREE_XCOLORS);
423             if (nLevels <= MIN_DIRECT_LEVELS)
424                 return FALSE;
425             else return ilAllocateXDirectColors (pXWC, nLevels / 2);
426             }
427         pColor->pad = TRUE;                         /* mark as alloc'd */
428         pixel = pColor->pixel;
429         red = (pixel >> 16) & 0xff;
430         green = (pixel >> 8) & 0xff;
431         blue = pixel & 0xff;
432         if ((red != i) || (green != i) || (blue != i))
433             pXWC->mapDirect = TRUE;
434         for (j = 0; j < nReplicate; j++) {       /* replicate into map image */
435             *pTranslate++ = red;
436             *pTranslate++ = green;
437             *pTranslate++ = blue;
438             }
439         }
440     return TRUE;
441 }
442
443
444
445         /*  ------------------------ ilChangeXWC --------------------------- */
446         /*  Public function; see spec.
447         */
448 ilBool ilChangeXWC (
449     ilXWC                   XWC,
450     unsigned int            code,
451     void                   *pData
452     )
453 {
454 register ilXWCPtr           pXWC;
455 register ilContext          context;
456
457     pXWC = (ilXWCPtr)XWC;
458     context = pXWC->o.p.context;
459     context->error = IL_OK;               /* assume no error */
460     if (pXWC->o.p.objectType != IL_XWC) {
461         context->error = IL_ERROR_OBJECT_TYPE;
462         return FALSE;                                           /* EXIT */
463         }
464
465     switch (code) {
466
467         /*  Allocate grays: allocate grays if gray or pseudo-color, else 
468             return true if gray display supported (e.g. to True/DirectColor).
469         */
470       case IL_XWC_ALLOC_GRAYS:
471         if (pData) {
472             context->error = IL_ERROR_OPTION_DATA;
473             return FALSE;
474             }
475         switch (pXWC->i.visualType) {
476           case IL_XWC_BITONAL:
477             return FALSE;
478           case IL_XWC_GRAY_8:
479           case IL_XWC_COLOR_8:
480             if (ilAllocateXGrays (context, pXWC, IL_DEFAULT_X_GRAYS))
481                 return TRUE;
482             else return FALSE;
483           case IL_XWC_COLOR_24:
484             return TRUE;
485             }
486
487         /*  Allocate colors: 8 and 24 bit color only */
488       case IL_XWC_ALLOC_COLORS:
489         if (pData) {
490             context->error = IL_ERROR_OPTION_DATA;
491             return FALSE;
492             }
493         if ((pXWC->i.visualType == IL_XWC_COLOR_8)
494          && ilAllocateXDitherColors (context, pXWC))
495              return TRUE;
496         else if ((pXWC->i.visualType == IL_XWC_COLOR_24)
497          && ilAllocateXDirectColors (pXWC, 256)) 
498              return TRUE;
499         else return FALSE;
500
501       case IL_XWC_FREE_GRAYS:
502         if (pData) {
503             context->error = IL_ERROR_OPTION_DATA;
504             return FALSE;
505             }
506         ilFreeColorData (pXWC, IL_FREE_XGRAYS);
507         break;
508
509         /*  Free colors if 8 or 24 bit color */
510       case IL_XWC_FREE_COLORS:
511         if (pData) {
512             context->error = IL_ERROR_OPTION_DATA;
513             return FALSE;
514             }
515         if ((pXWC->i.visualType == IL_XWC_COLOR_8) 
516          || (pXWC->i.visualType == IL_XWC_COLOR_24))
517             ilFreeColorData (pXWC, IL_FREE_XCOLORS);
518         break;
519
520       case IL_XWC_SET_DITHER_METHOD: 
521       { unsigned int ditherMethod;
522         ditherMethod = *((unsigned int *)pData);
523         if ((ditherMethod != IL_AREA_DITHER)
524          && (ditherMethod != IL_DIFFUSION)
525          && (ditherMethod != IL_QUICK_DIFFUSION)) {
526             context->error = IL_ERROR_OPTION_DATA;
527             return FALSE;
528             }
529         pXWC->i.ditherMethod = ditherMethod;
530         break;
531       }
532
533       case IL_XWC_SET_RAW_MODE:
534         pXWC->i.rawMode = *((ilBool *)pData);
535         break;
536
537       default:
538         context->error = IL_ERROR_INVALID_OPTION;
539         return FALSE;
540         }   /* END switch code */
541
542     return TRUE;
543 }
544
545
546         /*  ------------------------ ilQueryXWC --------------------------- */
547         /*  Public function; see spec.
548         */
549 ilBool ilQueryXWC (
550     ilXWC                   XWC,
551     ilXWCInfo              *pInfo
552     )
553 {
554 register ilXWCPtr           pXWC;
555
556     pXWC = (ilXWCPtr)XWC;
557     if (pXWC->o.p.objectType != IL_XWC) {
558         pXWC->o.p.context->error = IL_ERROR_OBJECT_TYPE;
559         return FALSE;                                           /* EXIT */
560         }
561
562     *pInfo = pXWC->i;
563     pXWC->o.p.context->error = IL_OK;
564     return TRUE;
565 }
566
567
568         /*  ------------------------ ilCreateXWC ------------------------- */
569         /*  Public function; see spec.
570             Return an error if no (null) display in this context.
571         */
572
573 ilXWC ilCreateXWC (
574     ilContext               context,
575     Display                *display,
576     Visual                 *visual,
577     Colormap                colormap,
578     GC                      gc,
579     unsigned long           mustBeZero1,
580     unsigned long           mustBeZero2
581     )
582 {
583 register ilXWCPtr       pXWC;
584 XVisualInfo             template, *pVisualInfo;
585 int                     notUsed;
586
587     if ((mustBeZero1 != 0) || (mustBeZero2 != 0)) {
588         context->error = IL_ERROR_PAR_NOT_ZERO;
589         return (ilXWC)NULL;                                 /* EXIT */
590         }
591
592         /*  A null visual or colormap means output will be to bitmap, else
593             get the info for the given visual; exit if not found. 
594         */
595     if (!visual || !colormap) {
596         visual = (Visual *)NULL;
597         colormap = (Colormap)0;
598         }
599     else {
600         template.visualid = XVisualIDFromVisual (visual);
601         pVisualInfo = XGetVisualInfo (display, VisualIDMask, &template, 
602                                       &notUsed);
603         if (!pVisualInfo) {
604             context->error = IL_ERROR_X_RESOURCE;
605             return (ilXWC)NULL;                             /* EXIT */
606             }
607         }
608
609         /*  Create an XWC object and fill it in.
610         */
611     pXWC = (ilXWCPtr)_ilCreateObject (context, IL_XWC, ilDestroyXWC, 
612                                       sizeof (ilXWCRec));
613     if (!pXWC)
614         return (ilXWC)NULL;                                 /* EXIT */
615
616     pXWC->i.display = display;
617     pXWC->i.visual = visual;
618     if (visual) {
619         pXWC->visualInfo = *pVisualInfo;
620         free (pVisualInfo);              /* free list from XGetVisualInfo() */
621         }
622     pXWC->i.gc = gc;
623     pXWC->i.colormap = colormap;
624     pXWC->pColors = (XColor *)NULL;
625     pXWC->nColors = 0;
626     pXWC->colorMapImage = (ilClientImage)NULL;
627     pXWC->pGrays = (XColor *)NULL;
628     pXWC->nGrays = 0;
629     pXWC->grayMapImage = (ilClientImage)NULL;
630     pXWC->i.ditherMethod = IL_AREA_DITHER;
631     pXWC->i.rawMode = FALSE;
632
633         /*  Check the class of the given visual and fill in XWC des and format.
634             If visual class not supported default to bitonal.
635             May also default to bitonal (or color demote to gray) later if 
636             insufficient colors or grays can be allocated.
637             If null visual, do bitonal output.
638         */
639     pXWC->i.staticVisual = TRUE;            /* assume non-writeable colormap */
640     if (!visual)
641         pXWC->i.visualType = IL_XWC_BITONAL;
642     else switch (pXWC->visualInfo.class) {
643         case PseudoColor:
644             pXWC->i.staticVisual = FALSE;
645         case StaticColor:
646             if (pXWC->visualInfo.depth == 8)
647                  pXWC->i.visualType = IL_XWC_COLOR_8;
648             else pXWC->i.visualType = IL_XWC_BITONAL;
649             break;
650
651             /*  Support True/DirectColor if 32 bits format 
652                 = "<unused 8><8R><8G><8B>". */
653         case DirectColor:
654             pXWC->i.staticVisual = FALSE;
655         case TrueColor:
656             if ((pXWC->visualInfo.depth == 24)
657              && (pXWC->visualInfo.red_mask == 0xff0000)
658              && (pXWC->visualInfo.green_mask == 0xff00)
659              && (pXWC->visualInfo.blue_mask == 0xff))
660                  pXWC->i.visualType = IL_XWC_COLOR_24;
661             else pXWC->i.visualType = IL_XWC_BITONAL;
662             break;
663
664         case GrayScale:
665             pXWC->i.staticVisual = FALSE;
666         case StaticGray:
667             if (pXWC->visualInfo.depth == 8)
668                  pXWC->i.visualType = IL_XWC_GRAY_8;
669             else pXWC->i.visualType = IL_XWC_BITONAL;
670             break;
671         }   /* END switch visual class */
672
673         /*  If a bitonal visual, mark as static (non-allocatable colors) */
674     if (pXWC->i.visualType == IL_XWC_BITONAL)
675         pXWC->i.staticVisual = TRUE;
676
677     context->error = IL_OK;
678     return (ilXWC)pXWC;
679 }
680
681
682
683 /*  ======================== WRITE X DRAWABLE CODE ======================== */ 
684
685     /*  Private block for ilRead/WriteXDrawable pipe element. Notes:
686         Inited by ilWriteXDrawable():
687            imageDepth      depth of image to create - set into pPriv when added
688            imageFormat     X format of image: XYBitmap (bitonal) or ZPixmap
689            isLongImage     if true: image is 32bits/pixel: set image rowBytes 
690                            to width*4.
691                            If false: set image rowBytes to row bytes of 
692                            pSrcImage.
693            bufferSize      size of buffer to create and attach to Ximage.
694            pXWC            ptr to XWC for this operation
695            drawable        id of X drawable (Window or Pixmap) to read or write
696            x, y            read: src (x,y).
697                            write: dst (x,y) from caller
698
699         Inited by ilWriteXInit():
700            Ximage          a temp XImage created by Init.  Its data ptr is 
701                            pointed directly at the read/write buffer, or 
702                            equals "pBuffer"
703            pBuffer         ptr to buffer allocated, if bufferSize > 0
704            linesDone       zeroed by Init(): # of lines written / read so far,
705                            i.e. y + linesDone is next line to read / write.
706     */
707 typedef struct {
708     int                 imageDepth;
709     int                 imageFormat;
710     ilBool              isLongImage;
711     unsigned long       bufferSize;
712     ilXWCPtr            pXWC;
713     Drawable            drawable;
714     ilPtr               pBuffer;
715     XImage             *pXImage;
716     int                 x, y;
717     long                linesDone;
718     } ilXPrivRec, *ilXPrivPtr;
719
720
721         /*  ----------------------- ilXDestroy ----------------------------- */
722         /*  Destroy() function for ilWriteXDrawable() pipe element.
723             "Destroys" the associated XWC, whose refCount must have been 
724             incremented when the element was successfully added to the pipe - 
725             Destroy downcounts it.
726         */
727 static ilError ilXDestroy (
728     ilPtr pPrivate
729     )
730 {
731     ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate;
732     ilDestroyObject ((ilObject)pPriv->pXWC);
733     return IL_OK;
734 }
735
736
737
738         /*  ------------------------- ilWriteXInit ------------------------- */
739         /*  Init() function for ilWriteXDrawable() for all src image types.
740             Creates an XImage, which is just a data structure - creates no 
741             pixel buffer.
742             The XImage is freed by ilWriteXCleanup().
743         */
744 static ilError ilWriteXInit (
745     ilPtr                  pPrivate,
746     ilImageInfo            *pSrcImage,
747     ilImageInfo            *pDstImage                   /* ignored */
748     )
749 {
750 register ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate;
751 register ilXWCPtr           pXWC;
752 register XImage            *pXImage;
753
754         /*  Create a temp buffer for image pixels if requested. */
755     if (pPriv->bufferSize > 0) {
756         pPriv->pBuffer = (ilPtr)IL_MALLOC (pPriv->bufferSize);
757         if (!pPriv->pBuffer)
758             return IL_ERROR_MALLOC;                     /* EXIT */
759         }
760     else pPriv->pBuffer = NULL;
761
762         /*  Create an XImage that will be pointed to each buffer (strip) to 
763             write. */
764     pXWC = pPriv->pXWC;
765     pXImage = XCreateImage (pXWC->i.display, pXWC->i.visual, 
766                             pPriv->imageDepth, pPriv->imageFormat, 0, 
767                             (char *)pPriv->pBuffer, pSrcImage->width, 
768                             pSrcImage->height, pSrcImage->pFormat->rowBitAlign,
769                             (pPriv->isLongImage) ? (pSrcImage->width * 4) :
770                             pSrcImage->plane[0].nBytesPerRow);
771     if (!pXImage)
772         return IL_ERROR_MALLOC;                         /* EXIT */
773
774         /*  Set bit/byte order to MSBFirst.  
775             NOTE: byte order should be set to byte order of client machine!!!
776         */
777
778 #ifdef LSB_BIT_ORDER
779     pXImage->byte_order = LSBFirst;
780 #else
781     pXImage->byte_order = MSBFirst; 
782 #endif
783     pXImage->bitmap_bit_order = MSBFirst;
784     pPriv->pXImage = pXImage;
785     pPriv->linesDone = 0;
786
787     return IL_OK;
788 }
789
790         /*  --------------------- ilWriteXCleanup -------------------------- */
791         /*  Cleanup() function for ilWriteXDrawable() for all src image types.
792             Flushes the output if not aborted; frees the XImage created by 
793             Init() below.
794         */
795 static ilError ilWriteXCleanup (
796     ilPtr                   pPrivate,
797     ilBool                  aborting
798     )
799 {
800         /*  Flush if not aborting.  Null the "data" field in image or else 
801             XDestroyImage() will try to free the pixels; destroy the image, 
802             created by Init().
803         */
804     register ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate;
805     if (!aborting)
806         XFlush (pPriv->pXWC->i.display);
807     if (pPriv->pBuffer)
808         IL_FREE (pPriv->pBuffer);
809     pPriv->pXImage->data = (char *)NULL;
810     XDestroyImage (pPriv->pXImage);
811     return IL_OK;
812 }
813
814         /*  --------------------- ilWriteXExecute ------------------------- */
815         /*  Execute() function for ilWriteXDrawable(), for rendering bit or 
816             byte data.
817             Points an XImage created by ilWriteXInit() to the src image bits
818             and does an XPutImage(), then bumps a line count so next strip is 
819             written *pNLines below this one in the drawable.
820         */
821 static ilError ilWriteXExecute (
822     register ilExecuteData  *pData,
823     long                     dstLine,
824     long                    *pNLines,
825     float                    ratio
826 )
827 {
828 register ilXPrivPtr         pPriv;
829 register XImage            *pXImage;
830 ilXWCPtr                    pXWC;
831 unsigned int                nSrcLines;
832 unsigned int                scaledWidth,scaledHeight;
833 int                         scaledX, scaledY;
834
835     pPriv = (ilXPrivPtr)pData->pPrivate;
836     nSrcLines = *pNLines;
837     pXImage = pPriv->pXImage;
838     pXImage->height = nSrcLines;
839     pXImage->data = (char *)(pData->pSrcImage->plane[0].pPixels + 
840                      pData->srcLine * pData->pSrcImage->plane[0].nBytesPerRow);
841
842     pXWC = pPriv->pXWC;
843
844     scaledWidth = pXImage->width * ratio + 0.5;
845     scaledX = pPriv->x * ratio + 0.5;
846     scaledY = (pPriv->y + pPriv->linesDone) * ratio + 0.5;
847     /* we have to think about rounding problem, so recalculate every time. */
848     scaledHeight = ((nSrcLines + pPriv->linesDone) * ratio + 0.5) 
849         - scaledY;
850
851     _XmPutScaledImage (pXWC->i.display, pPriv->drawable, 
852                        pXWC->i.gc, pXImage, 
853                        0, 0, scaledX, scaledY,
854                        pXImage->width, nSrcLines,
855                        scaledWidth,scaledHeight);
856
857     pPriv->linesDone += nSrcLines;
858
859     return IL_OK;
860 }
861
862         /*  ------------------- ilWriteXOptLongExecute --------------------- */
863         /*  Execute() function for ilWriteXDrawable(), for display to optimal 
864             4 bytes pixel frame buffers.  "Optimal" means the 4 bytes (CARD32) 
865             = "<unused 8> <8 R> <8 G> <8 B>",
866             which is the format most commonly used right now.
867             Reformat the pipe image pixels, which are 3byte pixel RGB (as 
868             required by pXWC->format), into 4 bytes words and do the 
869             XPutImage(), then bump linesDone.
870         */
871 static ilError ilWriteXOptLongExecute (
872     register ilExecuteData  *pData,
873     long                     dstLine,
874     long                    *pNLines,
875     float                    ratio
876     )
877 {
878 ilXPrivPtr                  pPriv;
879 ilImageInfo                *pSrcImage;
880 XImage                     *pXImage;
881 ilXWCPtr                    pXWC;
882 ilPtr                       pSrcLine;
883 long                        srcRowBytes, width, nSrcLines, nLinesM1;
884 register long               nLongsM1;
885 register ilPtr              pSrc;
886 register CARD32            *pDst, temp;
887 unsigned int                scaledWidth,scaledHeight;
888 int scaledX, scaledY ;
889
890     nSrcLines = *pNLines;
891     if (nSrcLines <= 0)
892         return;                                     /* no lines, EXIT */
893     pPriv = (ilXPrivPtr)pData->pPrivate;
894     pSrcImage = pData->pSrcImage;
895     width = pSrcImage->width;
896     if (width <= 0)
897         return;                                     /* no width, EXIT */
898     srcRowBytes = pSrcImage->plane[0].nBytesPerRow;
899     pSrcLine = (ilPtr)(pSrcImage->plane[0].pPixels + 
900                        pData->srcLine * srcRowBytes);
901     pXImage = pPriv->pXImage;
902     pXImage->height = nSrcLines;
903     pXImage->data = (char *)pPriv->pBuffer;
904     pDst = (CARD32 *)pPriv->pBuffer;
905
906         /*  pSrcLine points to first line of pipe image; pDst to buffer of 
907             X image.
908             Convert 3 byte pipe image to CARD32 X buffer image.  Dont need 
909             dstRowBytes because buffer is exactly "width" longs wide (we 
910             created it.)
911         */
912     nLinesM1 = nSrcLines - 1;
913     do {
914         pSrc = pSrcLine;
915         pSrcLine += srcRowBytes;
916         nLongsM1 = width - 1;
917         do {
918             temp = *pSrc++;
919             temp <<= 8;
920             temp |= *pSrc++;
921             temp <<= 8;
922             temp |= *pSrc++;
923             *pDst++ = temp;
924             } while (--nLongsM1 >= 0);
925         } while (--nLinesM1 >= 0);
926
927     pXWC = pPriv->pXWC;
928
929     scaledWidth = pXImage->width * ratio;
930     scaledHeight = nSrcLines * ratio;
931     scaledX = pPriv->x * ratio  ;
932     scaledY = (pPriv->y + pPriv->linesDone)* ratio  ;
933
934     _XmPutScaledImage (pXWC->i.display, pPriv->drawable, pXWC->i.gc, pXImage, 
935                        0, 0, scaledX, scaledY,
936                        pXImage->width, nSrcLines,
937                        scaledWidth,scaledHeight);
938
939     pPriv->linesDone += nSrcLines;
940
941     return IL_OK;
942 }
943
944
945         /*  ------------------------ ilConvertForXWrite -------------------- */
946         /*  Public function; see spec.
947             Side effect: set pXWC->i.writeType, code for how it will render.
948         */
949 ilBool ilConvertForXWrite (
950     ilPipe              pipe,
951     ilXWC               XWC,
952     ilBool              mapPixels,
953     unsigned long       mustBeZero,
954     void               *mustBeNull
955     )
956 {
957 ilPipeInfo                  info;
958 ilImageDes                  des;
959 ilImageFormat               format;
960 unsigned int                writeType;
961 register ilXWCPtr           pXWC;
962
963     /*  Table indexed by [dst visual type], yielding writeType when in raw 
964         mode */
965 static unsigned int rawWriteMethodTable [(IL_X_MAX_VISUAL_TYPE + 1)] = {
966     IL_XWC_WRITE_BITONAL,             /* IL_XWC_BITONAL  */
967     IL_XWC_WRITE_GRAY,                /* IL_XWC_GRAY_8   */
968     IL_XWC_WRITE_COLOR_DITHER,        /* IL_XWC_COLOR_8  */
969     IL_XWC_WRITE_COLOR                /* IL_XWC_COLOR_24 */ };
970
971     /*  Table indexed by [image type, dst visual type], yielding writeType,
972         assuming best case: colors/grays alloc'd succesfully; else writeType 
973         degrades.
974     */
975 static unsigned int writeTypeTable [(IL_MAX_TYPE + 1) * 
976                                    (IL_X_MAX_VISUAL_TYPE + 1)] =
977 {   /* (src) image type    (dst) visual type         writeType       */
978
979     /* IL_BITONAL          IL_XWC_BITONAL    */      IL_XWC_WRITE_BITONAL,
980     /*                     IL_XWC_GRAY_8     */      IL_XWC_WRITE_BITONAL,
981     /*                     IL_XWC_COLOR_8    */      IL_XWC_WRITE_BITONAL,
982     /*                     IL_XWC_COLOR_24   */      IL_XWC_WRITE_BITONAL,
983
984     /* IL_GRAY             IL_XWC_BITONAL    */      IL_XWC_WRITE_BITONAL,
985     /*                     IL_XWC_GRAY_8     */      IL_XWC_WRITE_GRAY,
986     /*                     IL_XWC_COLOR_8    */      IL_XWC_WRITE_GRAY,
987     /*                     IL_XWC_COLOR_24   */      IL_XWC_WRITE_COLOR,
988
989     /* IL_PALETTE          IL_XWC_BITONAL    */      IL_XWC_WRITE_BITONAL,
990     /*                     IL_XWC_GRAY_8     */      IL_XWC_WRITE_GRAY,
991     /*                     IL_XWC_COLOR_8    */      IL_XWC_WRITE_COLOR_DITHER,
992     /*                     IL_XWC_COLOR_24   */      IL_XWC_WRITE_COLOR,
993
994     /* IL_RGB              IL_XWC_BITONAL    */      IL_XWC_WRITE_BITONAL,
995     /*                     IL_XWC_GRAY_8     */      IL_XWC_WRITE_GRAY,
996     /*                     IL_XWC_COLOR_8    */      IL_XWC_WRITE_COLOR_DITHER,
997     /*                     IL_XWC_COLOR_24   */      IL_XWC_WRITE_COLOR,
998
999     /* IL_YCBCR            IL_XWC_BITONAL    */      IL_XWC_WRITE_BITONAL,
1000     /*                     IL_XWC_GRAY_8     */      IL_XWC_WRITE_GRAY,
1001     /*                     IL_XWC_COLOR_8    */      IL_XWC_WRITE_COLOR_DITHER,
1002     /*                     IL_XWC_COLOR_24   */      IL_XWC_WRITE_COLOR
1003 };
1004
1005     
1006
1007     if (pipe->objectType != IL_PIPE) {
1008         pipe->context->error = IL_ERROR_OBJECT_TYPE;
1009         return FALSE;
1010         }
1011     if (mustBeZero || mustBeNull)
1012         return ilDeclarePipeInvalid (pipe, IL_ERROR_PAR_NOT_ZERO);
1013
1014         /*  Validate that given XWC is one, and is same context as pipe. */
1015     pXWC = (ilXWCPtr)XWC;
1016     if (pXWC->o.p.objectType != IL_XWC)
1017         return ilDeclarePipeInvalid (pipe, IL_ERROR_OBJECT_TYPE);
1018     if (pXWC->o.p.context != pipe->context)
1019         return ilDeclarePipeInvalid (pipe, IL_ERROR_CONTEXT_MISMATCH);
1020
1021         /*  Get pipe info and decompress; if pipe not in IL_PIPE_FORMING state,
1022             error. */
1023     if (ilGetPipeInfo (pipe, TRUE, &info, &des, &format) != IL_PIPE_FORMING) {
1024         if (!pipe->context->error)
1025             ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
1026         return FALSE;
1027         }
1028
1029         /*  If raw mode, allocate no colors, output based on dst visual type, 
1030             except for bit/pixel images: output using bitonal approach; else:
1031             get "writeType" based on des.type (private types not supported) 
1032             and pXWC->i.visualType.  Check for allocated dither colors 
1033             (default to gray if not enough) and grays (default to bitonal if 
1034             not enough).
1035             Pretend YCbCr is RGB - an ilConvert() to RGB will be done below 
1036             anyway.
1037         */
1038     if (pXWC->i.rawMode) {
1039         if ((des.nSamplesPerPixel == 1) && (format.nBitsPerSample[0] == 1))
1040              writeType = IL_XWC_WRITE_BITONAL;
1041         else writeType = rawWriteMethodTable [pXWC->i.visualType];
1042         }
1043     else { 
1044         if (des.type > IL_MAX_TYPE)
1045             return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_TYPE);
1046         if (des.type == IL_YCBCR)
1047             des.type = IL_RGB;
1048
1049         writeType = writeTypeTable 
1050                  [des.type * (IL_X_MAX_VISUAL_TYPE + 1) + pXWC->i.visualType];
1051         if (writeType == IL_XWC_WRITE_COLOR_DITHER) {
1052             if (!pXWC->colorMapImage)
1053                 ilChangeXWC ((ilXWC)pXWC, IL_XWC_ALLOC_DITHER_COLORS, 
1054                              (ilPtr)NULL);
1055             if (!pXWC->colorMapImage) 
1056                 writeType = IL_XWC_WRITE_GRAY;
1057             }
1058         if (writeType == IL_XWC_WRITE_GRAY) {
1059             if (!pXWC->grayMapImage)
1060                 ilChangeXWC ((ilXWC)pXWC, IL_XWC_ALLOC_GRAYS, (ilPtr)NULL);
1061             if (!pXWC->grayMapImage) 
1062                 writeType = IL_XWC_WRITE_BITONAL;
1063             }
1064
1065             /*  If RGB display alloc colors or dflt to bitonal. */
1066         if (writeType == IL_XWC_WRITE_COLOR) {
1067             if (!pXWC->colorMapImage)
1068                 if (!ilAllocateXDirectColors (pXWC, 256))
1069                     writeType = IL_XWC_WRITE_BITONAL;
1070             }
1071         }   /* END not raw mode */
1072
1073         /*  Do ilConvert() and add filter(s) based on "writeType". */
1074     switch (writeType) {
1075
1076         /*  Bitonal: do an XPutImage() with XYBitmap, which renders image 0's 
1077             with GC background color, 1's with foreground, as defined by IL 
1078             spec.
1079             If rawMode, must be bit/pixel.
1080         */
1081       case IL_XWC_WRITE_BITONAL:
1082         if (pXWC->i.rawMode) {
1083             if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 1))
1084                 return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE);
1085             }
1086         else if (!ilConvert (pipe, IL_DES_BITONAL, IL_FORMAT_BIT, 0, NULL))
1087             return FALSE;
1088         break;
1089
1090         /*  Gray: do ilMap() which maps 256 gray shades to the equivalent 
1091             X pixel values, possibly using fewer shades of gray (slam; not 
1092             dithered to lesser # grays).
1093         */
1094       case IL_XWC_WRITE_GRAY:
1095         if (pXWC->i.rawMode) {
1096             if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 8))
1097                 return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE);
1098             }
1099         else {
1100             if (!ilConvert (pipe, IL_DES_GRAY, IL_FORMAT_BYTE, 0, NULL))
1101                 return FALSE;
1102             if (mapPixels)
1103                 if (!ilMap (pipe, pXWC->grayMapImage))
1104                     return FALSE;
1105             }
1106         break;
1107
1108         /*  Dithered RGB: if raw mode, accept if byte/pixel; 
1109             if a pre-dithered palette image in pipe, ilMap() to map colors to 
1110             X pixels;
1111             otherwise dither cvt to palette w/ map to the allocated colors. 
1112         */
1113       case IL_XWC_WRITE_COLOR_DITHER:
1114         if (pXWC->i.rawMode) {
1115             if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 8))
1116                 return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE);
1117             }
1118         else if ((des.flags & IL_DITHERED_PALETTE)
1119               && (des.typeInfo.palette.levels[0] == NRED)
1120               && (des.typeInfo.palette.levels[1] == NGREEN)
1121               && (des.typeInfo.palette.levels[2] == NBLUE)) {
1122                 if ((format.nBitsPerSample[0] != 8)
1123                  && !ilConvert (pipe, (ilImageDes *)NULL, IL_FORMAT_BYTE, 0, 
1124                                 NULL))
1125                     return FALSE;
1126                 if (mapPixels)
1127                     if (!ilMap (pipe, pXWC->colorMapImage))
1128                         return FALSE;
1129                 }
1130         else {
1131             ilConvertToPaletteInfo  cvt;
1132             cvt.method = pXWC->i.ditherMethod;
1133             cvt.levels[0] = NRED; 
1134             cvt.levels[1] = NGREEN; 
1135             cvt.levels[2] = NBLUE;
1136             cvt.kernelSize = 8;
1137             if (mapPixels) {
1138                 cvt.dstType = IL_GRAY;     /* any type other than IL_PALETTE */
1139                 cvt.mapImage = pXWC->colorMapImage;
1140                 }
1141             else {
1142                 cvt.dstType = IL_PALETTE;
1143                 cvt.mapImage = (ilClientImage)NULL;
1144                 }
1145             if (!ilConvert (pipe, IL_DES_PALETTE, IL_FORMAT_BYTE, 
1146                             IL_CONVERT_TO_PALETTE, &cvt))
1147                 return FALSE;
1148             }
1149         break;
1150
1151             /*  RGB: if raw mode, check format, else convert to RGB, and if 
1152                 mapPixels and map needed (ramp not 0..255 each component) do 
1153                 an ilMap().
1154             */
1155       case IL_XWC_WRITE_COLOR:
1156         {
1157         if (pXWC->i.rawMode) {
1158             if ((des.nSamplesPerPixel != 3) 
1159              || (format.nBitsPerSample[0] != 8)
1160              || (format.nBitsPerSample[1] != 8)
1161              || (format.nBitsPerSample[2] != 8)
1162              || (format.sampleOrder != IL_SAMPLE_PIXELS))
1163                 return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE);
1164             }
1165         else {
1166             if (!ilConvert (pipe, IL_DES_RGB, IL_FORMAT_3BYTE_PIXEL, 0, NULL))
1167                 return FALSE;
1168             if (mapPixels && pXWC->mapDirect)
1169                 if (!ilMap (pipe, pXWC->colorMapImage))
1170                     return FALSE;
1171             }
1172         }
1173         break;
1174     }   /* END switch writeType */
1175
1176     pXWC->i.writeType = writeType;       /* set method of writing to be used */
1177     pipe->context->error = IL_OK;
1178     return TRUE;
1179 }
1180
1181
1182         /*  ------------------------ ilWriteXDrawable ---------------------- */
1183         /*  Public function; see spec.
1184         */
1185 ilBool ilWriteXDrawable (
1186     ilPipe                  pipe,
1187     Drawable                drawable,
1188     ilXWC                   XWC,
1189     ilRect                 *pSrcRect,
1190     int                     dstX,
1191     int                     dstY,
1192     unsigned long           mustBeZero
1193     )
1194 {
1195 ilPipeInfo                  info;
1196 register ilXWCPtr           pXWC;
1197 register ilXPrivPtr         pPriv;
1198 ilSrcElementData           *pSrcData, srcData;
1199 unsigned long               bufferSize;
1200 /*
1201 ** We need to use the execute fucntion with the ratio parameter.
1202 */
1203 ilError                   (*executeFunction)( register ilExecuteData *,
1204                                               long,
1205                                               long *,
1206                                               float);
1207
1208         /*  If a src clip rect, insert an ilCrop() element before us.
1209             In the future, should look at pipe and handle some cases directly.
1210         */
1211     if (pSrcRect && !ilCrop (pipe, pSrcRect))
1212         return FALSE;
1213
1214         /*  Convert as necessary, mapping pixels to X pixels and get 
1215             pXWC->i.writeType */
1216     pXWC = (ilXWCPtr)XWC;
1217     if (!ilConvertForXWrite (pipe, (ilXWC)pXWC, TRUE, 0, NULL))
1218         return FALSE;
1219
1220     ilGetPipeInfo (pipe, FALSE, &info, (ilImageDes *)NULL, 
1221                    (ilImageFormat *)NULL);
1222
1223         /*  If writing 24 bits: use separate executeFunction, set "bufferSize"
1224             to buffer to be allocated, and if too large force pipe to give us 
1225             smaller strips.
1226         */
1227     if (pXWC->i.writeType == IL_XWC_WRITE_COLOR) {
1228         bufferSize = (info.width * 4) * info.stripHeight;
1229         if (bufferSize > MAX_IMAGE_BUFFER_SIZE) {
1230             srcData.consumerImage = (ilObject)NULL;
1231             srcData.stripHeight = BEST_IMAGE_BUFFER_SIZE / (4 * info.width);
1232             if (srcData.stripHeight < 1)
1233                 srcData.stripHeight = 1;
1234             srcData.constantStrip = FALSE;
1235             srcData.minBufferHeight = 0;
1236             pSrcData = &srcData;
1237             }
1238         else pSrcData = (ilSrcElementData *)NULL;
1239         executeFunction = ilWriteXOptLongExecute;
1240         }
1241     else {
1242         pSrcData = (ilSrcElementData *)NULL;
1243         executeFunction = ilWriteXExecute;
1244         }
1245
1246         /*  Add a consumer which does an XPutImage() using the pipe data 
1247             cvt'd above.
1248             Increment the XWC refCount; element's Destroy() function 
1249             ilXDestroy() will decrement it when this pipe element is removed.
1250         */
1251     pPriv = (ilXPrivPtr)ilAddPipeElement (pipe, IL_CONSUMER, 
1252         sizeof(ilXPrivRec), 0, pSrcData, (ilDstElementData *)NULL,
1253         ilWriteXInit, ilWriteXCleanup, ilXDestroy, NULL, executeFunction, 0);
1254     if (!pPriv) return FALSE;                          /* EXIT */
1255
1256     pPriv->pXWC = pXWC;
1257     pPriv->drawable = drawable;
1258     pPriv->x = dstX;
1259     pPriv->y = dstY;
1260     pXWC->o.refCount++;
1261
1262         /*  Set writeType-specific values in *pPriv */
1263     switch (pXWC->i.writeType) {
1264       case IL_XWC_WRITE_BITONAL:
1265         pPriv->imageDepth = 1;
1266         pPriv->imageFormat = XYBitmap;
1267         pPriv->isLongImage = FALSE;
1268         pPriv->bufferSize = 0;
1269         break;
1270       case IL_XWC_WRITE_GRAY:
1271         pPriv->imageDepth = 8;
1272         pPriv->imageFormat = ZPixmap;
1273         pPriv->isLongImage = FALSE;
1274         pPriv->bufferSize = 0;
1275         break;
1276       case IL_XWC_WRITE_COLOR_DITHER:
1277         pPriv->imageDepth = 8;
1278         pPriv->imageFormat = ZPixmap;
1279         pPriv->isLongImage = FALSE;
1280         pPriv->bufferSize = 0;
1281         break;
1282       case IL_XWC_WRITE_COLOR:
1283         pPriv->bufferSize = bufferSize;             /* from above */
1284         pPriv->imageDepth = 24;
1285         pPriv->imageFormat = ZPixmap;
1286         pPriv->isLongImage = TRUE;
1287         break;
1288         }
1289
1290     pipe->context->error = IL_OK;
1291     return TRUE;
1292 }
1293