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