xref: /plan9-contrib/sys/src/cmd/gs/src/gdevxalt.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
1 /* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 /*$Id: gdevxalt.c,v 1.2.6.1 2002/01/30 20:09:26 raph Exp $ */
20 /* Alternative X Windows drivers for help in driver debugging */
21 #include "gx.h"			/* for gx_bitmap; includes std.h */
22 #include "math_.h"
23 #include "memory_.h"
24 #include "x_.h"
25 #include "gserrors.h"
26 #include "gsparam.h"
27 #include "gsstruct.h"
28 #include "gxdevice.h"
29 #include "gsdevice.h"		/* for gs_copydevice */
30 #include "gdevx.h"
31 
32 extern const gx_device_X gs_x11_device;
33 
34 /*
35  * Define a forwarding device with a cache for the first 16 colors,
36  * which avoids all of the time-consuming color mapping calls for
37  * the black-and-white, 2-bit gray, and 1-bit CMYK devices defined here.
38  */
39 typedef struct {
40     gx_device_forward_common;
41     gx_color_index color_cache[16];
42     /*
43      * alt_map_color returns a value >= 0 if it maps directly to the final
44      * gx_color_index, or < 0 if it only sets RGB values.
45      */
46     dev_proc_map_color_rgb((*alt_map_color));
47 } gx_device_X_wrapper;
48 #define X_WRAPPER_DATA(amc_proc)\
49 	/* gx_device_forward_common */\
50     {0},			/* std_procs */\
51     0,				/* target */\
52 	/* gx_device_X_wrapper */\
53     {0},			/* cache */\
54     amc_proc
55 gs_private_st_suffix_add0_final(st_device_X_wrapper, gx_device_X_wrapper,
56   "gx_device_X_wrapper", gdevx_wrapper_enum_ptrs, gdevx_wrapper_reloc_ptrs,
57   gx_device_finalize, st_device_forward);
58 
59 /* ---------------- Generic procedures ---------------- */
60 
61 /* Forward declarations */
62 private int get_dev_target(P2(gx_device **, gx_device *));
63 
64 #define set_dev_target(tdev, dev)\
65   return_if_error(get_dev_target(&tdev, dev))
66 private int get_target_info(P1(gx_device *));
67 private gx_color_index x_alt_map_color(P2(gx_device *, gx_color_index));
68 
69 /* Clear the color mapping cache. */
70 private void
71 x_clear_color_cache(gx_device /*gx_device_X_wrapper */  * dev)
72 {
73     gx_device_X_wrapper *xdev = (gx_device_X_wrapper *) dev;
74     int i;
75 
76     for (i = 0; i < countof(xdev->color_cache); ++i)
77 	xdev->color_cache[i] = gx_no_color_index;
78     gx_device_decache_colors(dev);
79 }
80 
81 /* "Wrappers" for driver procedures */
82 
83 private int
84 x_wrap_open(gx_device * dev)
85 {
86     gx_device *tdev;
87     int rcode, code;
88 
89     set_dev_target(tdev, dev);
90     rcode = (*dev_proc(tdev, open_device)) (tdev);
91     if (rcode < 0)
92 	return rcode;
93     tdev->is_open = true;
94     code = get_target_info(dev);
95     return (code < 0 ? code : rcode);
96 }
97 
98 private int
99 x_forward_sync_output(gx_device * dev)
100 {
101     gx_device *tdev;
102 
103     set_dev_target(tdev, dev);
104     return (*dev_proc(tdev, sync_output)) (tdev);
105 }
106 
107 private int
108 x_forward_output_page(gx_device * dev, int num_copies, int flush)
109 {
110     gx_device *tdev;
111 
112     set_dev_target(tdev, dev);
113     return (*dev_proc(tdev, output_page)) (tdev, num_copies, flush);
114 }
115 
116 private int
117 x_wrap_close(gx_device * dev)
118 {
119     /*
120      * The underlying x11 device will be closed and freed as soon as there
121      * are no more pointers to it, which normally occurs in the next
122      * statement.
123      */
124     gx_device_set_target((gx_device_forward *)dev, NULL);
125     x_clear_color_cache(dev);
126     return 0;
127 }
128 
129 private int
130 x_wrap_map_color_rgb(gx_device * dev, gx_color_index color,
131 		     gx_color_value prgb[3])
132 {
133     gx_device *tdev;
134 
135     set_dev_target(tdev, dev);
136     return (*dev_proc(tdev, map_color_rgb)) (tdev,
137 					     x_alt_map_color(dev, color),
138 					     prgb);
139 }
140 
141 private int
142 x_wrap_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
143 		      gx_color_index color)
144 {
145     gx_device *tdev;
146 
147     set_dev_target(tdev, dev);
148     return (*dev_proc(tdev, fill_rectangle)) (tdev, x, y, w, h,
149 					      x_alt_map_color(dev, color));
150 }
151 
152 private int
153 x_wrap_copy_mono(gx_device * dev,
154 		 const byte * base, int sourcex, int raster, gx_bitmap_id id,
155 		 int x, int y, int w, int h,
156 		 gx_color_index zero, gx_color_index one)
157 {
158     gx_device *tdev;
159 
160     set_dev_target(tdev, dev);
161     return (*dev_proc(tdev, copy_mono)) (tdev, base, sourcex, raster, id,
162 					 x, y, w, h,
163 					 x_alt_map_color(dev, zero),
164 					 x_alt_map_color(dev, one));
165 
166 }
167 
168 private int
169 x_wrap_copy_color(gx_device * dev, const byte * base, int sourcex,
170 		  int raster, gx_bitmap_id id, int x, int y, int w, int h)
171 {
172     gx_device *tdev;
173 
174 #define mapped_bytes 480	/* must be a multiple of 3 & 4 */
175     int depth_bytes, source_bits;
176     int block_w, block_h;
177     int xblock, yblock;
178     byte mapped[mapped_bytes];
179 
180     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
181     set_dev_target(tdev, dev);
182     /* Device pixels must be an integral number of bytes. */
183     if (tdev->color_info.depth & 7)
184 	return gx_default_copy_color(dev, base, sourcex, raster, id,
185 				     x, y, w, h);
186     depth_bytes = tdev->color_info.depth >> 3;
187     source_bits = dev->color_info.depth;
188     {
189 	int mapped_pixels = mapped_bytes / depth_bytes;
190 
191 	if (w > mapped_pixels >> 1)
192 	    block_w = min(w, mapped_pixels), block_h = 1;
193 	else
194 	    block_w = w, block_h = mapped_pixels / w;
195     }
196     for (yblock = y; yblock < y + h; yblock += block_h)
197 	for (xblock = x; xblock < x + w; xblock += block_w) {
198 	    byte *p = mapped;
199 	    int xend = min(xblock + block_w, x + w);
200 	    int yend = min(yblock + block_h, y + h);
201 	    int xcur, ycur;
202 	    int code;
203 
204 	    for (ycur = yblock; ycur < yend; ++ycur)
205 		for (xcur = xblock; xcur < xend; ++xcur) {
206 		    int sbit = (xcur - x + sourcex) * source_bits;
207 		    uint sbyte =
208 			base[(ycur - y) * raster + (sbit >> 3)];
209 		    uint spixel =
210 			((sbyte << (sbit & 7)) & 0xff) >> (8 - source_bits);
211 		    gx_color_index cindex =
212 			((gx_device_X_wrapper *) dev)->color_cache[spixel];
213 
214 		    if (cindex == gx_no_color_index)
215 			cindex = x_alt_map_color(dev, spixel);
216 		    switch (depth_bytes) {
217 			case 4:
218 			    *p++ = (byte) (cindex >> 24);
219 			case 3:
220 			    *p++ = (byte) (cindex >> 16);
221 			case 2:
222 			    *p++ = (byte) (cindex >> 8);
223 			default /*case 1 */ :
224 			    *p++ = (byte) cindex;
225 		    }
226 		}
227 	    code = (*dev_proc(tdev, copy_color))
228 		(tdev, mapped, 0, (xend - xblock) * depth_bytes, gx_no_bitmap_id,
229 		 xblock, yblock, xend - xblock, yend - yblock);
230 	    if (code < 0)
231 		return code;
232 	}
233     return 0;
234 }
235 
236 
237 private int
238 x_forward_copy_color(gx_device * dev, const byte * base, int sourcex,
239 		     int raster, gx_bitmap_id id, int x, int y, int w, int h)
240 {
241     gx_device *tdev;
242 
243     set_dev_target(tdev, dev);
244     return (*dev_proc(tdev, copy_color)) (tdev, base, sourcex, raster, id,
245 					  x, y, w, h);
246 }
247 
248 private int
249 x_forward_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data)
250 {
251     gx_device *tdev;
252 
253     set_dev_target(tdev, dev);
254     return (*dev_proc(tdev, get_bits)) (tdev, y, str, actual_data);
255 }
256 
257 private int
258 x_wrap_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data)
259 {
260     int depth = dev->color_info.depth;
261     gx_device *tdev;
262     int width;
263     int sdepth;
264     byte smask;
265     uint dsize;
266     gs_memory_t *mem = dev->memory;
267     byte *row;
268     byte *base;
269     int code;
270     gx_color_index pixel_in = gx_no_color_index;
271     /*
272      * The following initialization is unnecessary: since no pixel has a
273      * value of gx_no_color_index, the test pixel != pixel_in will always
274      * succeed the first time through the loop below, so pixel_out will
275      * always be set before it is used.  We initialize pixel_out solely to
276      * suppress bogus warning messages from certain compilers.
277      */
278     gx_color_index pixel_out = 0;
279     int xi;
280     int sbit;
281 
282     DECLARE_LINE_ACCUM(str, depth, 0);
283 
284     set_dev_target(tdev, dev);
285     width = tdev->width;
286     sdepth = tdev->color_info.depth;
287     smask = (sdepth <= 8 ? (1 << sdepth) - 1 : 0xff);
288     dsize = (width * sdepth + 7) / 8;
289     row = gs_alloc_bytes(mem, dsize, "x_wrap_get_bits");
290     if (row == 0)
291 	return_error(gs_error_VMerror);
292     code = (*dev_proc(tdev, get_bits)) (tdev, y, row, &base);
293     if (code < 0)
294 	goto gx;
295     for (sbit = 0, xi = 0; xi < width; sbit += sdepth, ++xi) {
296 	const byte *sptr = base + (sbit >> 3);
297 	gx_color_index pixel;
298 	gx_color_value rgb[3];
299 	int i;
300 
301 	if (sdepth <= 8)
302 	    pixel = (*sptr >> (8 - sdepth - (sbit & 7))) & smask;
303 	else {
304 	    pixel = 0;
305 	    for (i = 0; i < sdepth; i += 8, ++sptr)
306 		pixel = (pixel << 8) + *sptr;
307 	}
308 	if (pixel != pixel_in) {
309 	    (*dev_proc(tdev, map_color_rgb))(tdev, pixel, rgb);
310 	    pixel_in = pixel;
311 	    if (dev->color_info.num_components <= 3)
312 		pixel_out = (*dev_proc(dev, map_rgb_color))
313 		    (dev, rgb[0], rgb[1], rgb[2]);
314 	    else {
315 		/* Convert RGB to CMYK. */
316 		gx_color_value c = gx_max_color_value - rgb[0];
317 		gx_color_value m = gx_max_color_value - rgb[1];
318 		gx_color_value y = gx_max_color_value - rgb[2];
319 		gx_color_value k = (c < m ? min(c, y) : min(m, y));
320 
321 		pixel_out = (*dev_proc(dev, map_cmyk_color))
322 		    (dev, c - k, m - k, y - k, k);
323 	    }
324 	}
325 	LINE_ACCUM(pixel_out, depth);
326     }
327     LINE_ACCUM_STORE(depth);
328   gx:gs_free_object(mem, row, "x_wrap_get_bits");
329     *actual_data = str;
330     return code;
331 }
332 
333 private int
334 x_wrap_get_params(gx_device * dev, gs_param_list * plist)
335 {
336     gx_device *tdev;
337     /* We assume that a get_params call has no side effects.... */
338     gx_device_X save_dev;
339     int ecode;
340 
341     set_dev_target(tdev, dev);
342     save_dev = *(gx_device_X *) tdev;
343     if (tdev->is_open)
344 	tdev->color_info = dev->color_info;
345     tdev->dname = dev->dname;
346     ecode = (*dev_proc(tdev, get_params)) (tdev, plist);
347     *(gx_device_X *) tdev = save_dev;
348     return ecode;
349 }
350 
351 private int
352 x_wrap_put_params(gx_device * dev, gs_param_list * plist)
353 {
354     gx_device *tdev;
355     gx_device_color_info cinfo;
356     const char *dname;
357     int rcode, code;
358 
359     set_dev_target(tdev, dev);
360     /*
361      * put_params will choke if we simply feed it the output of
362      * get_params; we have to substitute color_info the same way.
363      */
364     cinfo = tdev->color_info;
365     dname = tdev->dname;
366     tdev->color_info = dev->color_info;
367     tdev->dname = dev->dname;
368     rcode = (*dev_proc(tdev, put_params)) (tdev, plist);
369     tdev->color_info = cinfo;
370     tdev->dname = dname;
371     if (rcode < 0)
372 	return rcode;
373     code = get_target_info(dev);
374     return (code < 0 ? code : rcode);
375 }
376 
377 /* Internal procedures */
378 
379 /* Get the target, creating it if necessary. */
380 private int
381 get_dev_target(gx_device ** ptdev, gx_device * dev)
382 {
383     gx_device *tdev = ((gx_device_forward *) dev)->target;
384 
385     if (tdev == 0) {
386 	/* Create an X device instance. */
387 	int code = gs_copydevice(&tdev, (const gx_device *)&gs_x11_device,
388 				 dev->memory);
389 
390 	if (code < 0)
391 	    return 0;
392 	gx_device_fill_in_procs(tdev);
393 	gx_device_set_target((gx_device_forward *)dev, tdev);
394 	x_clear_color_cache(dev);
395     }
396     *ptdev = tdev;
397     return 0;
398 }
399 
400 /* Copy parameters back from the target. */
401 private int
402 get_target_info(gx_device * dev)
403 {
404     gx_device *tdev;
405 
406     set_dev_target(tdev, dev);
407 
408 #define copy(m) dev->m = tdev->m;
409 #define copy2(m) copy(m[0]); copy(m[1])
410 #define copy4(m) copy2(m); copy(m[2]); copy(m[3])
411 
412     copy(width);
413     copy(height);
414     copy2(MediaSize);
415     copy4(ImagingBBox);
416     copy(ImagingBBox_set);
417     copy2(HWResolution);
418     copy2(MarginsHWResolution);
419     copy2(Margins);
420     copy4(HWMargins);
421     if (dev->color_info.num_components == 3) {
422 	/* Leave the anti-aliasing information alone. */
423 	gx_device_anti_alias_info aa;
424 
425 	aa = dev->color_info.anti_alias;
426 	copy(color_info);
427 	dev->color_info.anti_alias = aa;
428     }
429 
430 #undef copy4
431 #undef copy2
432 #undef copy
433 
434     x_clear_color_cache(dev);
435     return 0;
436 }
437 
438 /* Map a fake CMYK or black/white color to a real X color if necessary. */
439 private gx_color_index
440 x_alt_map_color(gx_device * dev, gx_color_index color)
441 {
442     gx_device_X_wrapper *xdev = (gx_device_X_wrapper *) dev;
443     gx_device *tdev;
444     gx_color_value rgb[3];
445     gx_color_index cindex;
446     int result;
447 
448     if (color == gx_no_color_index)
449 	return color;
450     if (color < 16) {
451 	cindex = ((gx_device_X_wrapper *) dev)->color_cache[color];
452 	if (cindex != gx_no_color_index)
453 	    return cindex;
454     }
455     set_dev_target(tdev, dev);
456     result = xdev->alt_map_color(dev, color, rgb);
457     if (result >= 0)
458 	cindex = result;
459     else
460 	cindex = dev_proc(tdev, map_rgb_color)(tdev, rgb[0], rgb[1], rgb[2]);
461     if (color < 16)
462 	((gx_device_X_wrapper *) dev)->color_cache[color] = cindex;
463     return cindex;
464 }
465 
466 /* ---------------- CMYK procedures ---------------- */
467 
468 /* Device procedures */
469 private dev_proc_open_device(x_cmyk_open);
470 private dev_proc_put_params(x_cmyk_put_params);
471 private dev_proc_map_cmyk_color(x_cmyk_map_cmyk_color);
472 /* Extended device procedures */
473 private dev_proc_map_color_rgb(x_cmyk_alt_map_color);
474 
475 /* The device descriptor */
476 private const gx_device_procs x_cmyk_procs = {
477     x_cmyk_open,
478     gx_forward_get_initial_matrix,
479     x_forward_sync_output,
480     x_forward_output_page,
481     x_wrap_close,
482     NULL,			/* map_rgb_color */
483     x_wrap_map_color_rgb,
484     x_wrap_fill_rectangle,
485     gx_default_tile_rectangle,
486     x_wrap_copy_mono,
487     x_wrap_copy_color,
488     gx_default_draw_line,
489     x_wrap_get_bits,
490     x_wrap_get_params,
491     x_cmyk_put_params,
492     x_cmyk_map_cmyk_color,
493     gx_forward_get_xfont_procs,
494     gx_forward_get_xfont_device,
495     NULL,			/* map_rgb_alpha_color */
496     gx_forward_get_page_device,
497     gx_forward_get_alpha_bits,
498     NULL			/* copy_alpha */
499 };
500 
501 /* The instances are public. */
502 const gx_device_X_wrapper gs_x11cmyk_device = {
503     std_device_dci_type_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk",
504 	&st_device_X_wrapper,
505 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
506 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
507 	4, 4, 1, 1, 2, 2),
508     X_WRAPPER_DATA(x_cmyk_alt_map_color)
509 };
510 const gx_device_X_wrapper gs_x11cmyk2_device = {
511     std_device_dci_type_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk2",
512 	&st_device_X_wrapper,
513 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
514 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
515 	4, 8, 3, 3, 4, 4),
516     X_WRAPPER_DATA(x_cmyk_alt_map_color)
517 };
518 const gx_device_X_wrapper gs_x11cmyk4_device = {
519     std_device_dci_type_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk4",
520 	&st_device_X_wrapper,
521 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
522 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
523 	4, 16, 15, 15, 16, 16),
524     X_WRAPPER_DATA(x_cmyk_alt_map_color)
525 };
526 const gx_device_X_wrapper gs_x11cmyk8_device = {
527     std_device_dci_type_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk8",
528 	&st_device_X_wrapper,
529 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
530 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
531 	4, 32, 255, 255, 256, 256),
532     X_WRAPPER_DATA(x_cmyk_alt_map_color)
533 };
534 
535 /* Map a fake color to RGB. */
536 private int
537 x_cmyk_alt_map_color(gx_device * dev, gx_color_index color,
538 		     gx_color_value rgb[3])
539 {
540     int shift = dev->color_info.depth >> 2;
541     int mask = (1 << shift) - 1;
542     /* The following division is guaranteed exact. */
543     gx_color_value scale = gx_max_color_value / mask;
544     int cw = ~color & mask;
545     int cb = cw - ((color >> shift) & mask);
546     int cg = cw - ((color >> (shift * 2)) & mask);
547     int cr = cw - ((color >> (shift * 3)) & mask);
548 
549     rgb[0] = max(cr, 0) * scale;
550     rgb[1] = max(cg, 0) * scale;
551     rgb[2] = max(cb, 0) * scale;
552     return -1;
553 }
554 
555 /* Set color mapping procedures */
556 private void
557 x_cmyk_set_procs(gx_device *dev)
558 {
559     if (dev->color_info.depth == 4) {
560 	set_dev_proc(dev, map_cmyk_color, cmyk_1bit_map_cmyk_color);
561     } else {
562 	set_dev_proc(dev, map_cmyk_color, x_cmyk_map_cmyk_color);
563     }
564 }
565 
566 /* Device procedures */
567 
568 private int
569 x_cmyk_open(gx_device *dev)
570 {
571     int code = x_wrap_open(dev);
572 
573     if (code >= 0)
574 	x_cmyk_set_procs(dev);
575     return code;
576 }
577 
578 private int
579 x_cmyk_put_params(gx_device * dev, gs_param_list * plist)
580 {
581     int code = x_wrap_put_params(dev, plist);
582 
583     if (code >= 0)
584 	x_cmyk_set_procs(dev);
585     return code;
586 }
587 
588 private gx_color_index
589 x_cmyk_map_cmyk_color(gx_device * dev,
590 		      gx_color_value c, gx_color_value m, gx_color_value y,
591 		      gx_color_value k)
592 {
593     int shift = dev->color_info.depth >> 2;
594     gx_color_index pixel = c >> (gx_color_value_bits - shift);
595 
596     pixel = (pixel << shift) | (m >> (gx_color_value_bits - shift));
597     pixel = (pixel << shift) | (y >> (gx_color_value_bits - shift));
598     return (pixel << shift) | (k >> (gx_color_value_bits - shift));
599 }
600 
601 /* ---------------- Black-and-white procedures ---------------- */
602 
603 /* Extended device procedures */
604 private dev_proc_map_color_rgb(x_mono_alt_map_color);
605 
606 /* The device descriptor */
607 private const gx_device_procs x_mono_procs = {
608     x_wrap_open,
609     gx_forward_get_initial_matrix,
610     x_forward_sync_output,
611     x_forward_output_page,
612     x_wrap_close,
613     gx_default_b_w_map_rgb_color,
614     x_wrap_map_color_rgb,
615     x_wrap_fill_rectangle,
616     gx_default_tile_rectangle,
617     x_wrap_copy_mono,
618     gx_default_copy_color,	/* this is fast for the 1-bit case */
619     gx_default_draw_line,
620     x_wrap_get_bits,
621     x_wrap_get_params,
622     x_wrap_put_params,
623     gx_default_map_cmyk_color,
624     gx_forward_get_xfont_procs,
625     gx_forward_get_xfont_device,
626     NULL,			/* map_rgb_alpha_color */
627     gx_forward_get_page_device,
628     gx_forward_get_alpha_bits,
629     NULL			/* copy_alpha */
630 };
631 
632 /* The instance is public. */
633 const gx_device_X_wrapper gs_x11mono_device = {
634     std_device_dci_type_body(gx_device_X_wrapper, &x_mono_procs, "x11mono",
635 	&st_device_X_wrapper,
636 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
637 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
638 	1, 1, 1, 0, 2, 0),
639     X_WRAPPER_DATA(x_mono_alt_map_color)
640 };
641 
642 /* Map a fake color to RGB. */
643 private int
644 x_mono_alt_map_color(gx_device * dev, gx_color_index color,
645 		     gx_color_value rgb[3])
646 {
647     rgb[0] = rgb[1] = rgb[2] = (color ? 0 : gx_max_color_value);
648     return -1;
649 }
650 
651 /* ---------------- 2- and 4-bit gray-scale procedures ---------------- */
652 
653 /* Extended device procedures */
654 private dev_proc_map_color_rgb(x_gray_alt_map_color);
655 
656 /* The device descriptor */
657 private const gx_device_procs x_gray_procs = {
658     x_wrap_open,
659     gx_forward_get_initial_matrix,
660     x_forward_sync_output,
661     x_forward_output_page,
662     x_wrap_close,
663     gx_default_gray_map_rgb_color,
664     x_wrap_map_color_rgb,
665     x_wrap_fill_rectangle,
666     gx_default_tile_rectangle,
667     x_wrap_copy_mono,
668     x_wrap_copy_color,
669     gx_default_draw_line,
670     x_wrap_get_bits,
671     x_wrap_get_params,
672     x_wrap_put_params,
673     gx_default_map_cmyk_color,
674     gx_forward_get_xfont_procs,
675     gx_forward_get_xfont_device,
676     NULL,			/* map_rgb_alpha_color */
677     gx_forward_get_page_device,
678     gx_forward_get_alpha_bits,
679     NULL			/* copy_alpha */
680 };
681 
682 /* The instances are public. */
683 const gx_device_X_wrapper gs_x11gray2_device = {
684     std_device_dci_type_body(gx_device_X_wrapper, &x_gray_procs, "x11gray2",
685 	&st_device_X_wrapper,
686 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
687 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
688 	1, 2, 3, 0, 4, 0),
689     X_WRAPPER_DATA(x_gray_alt_map_color)
690 };
691 
692 const gx_device_X_wrapper gs_x11gray4_device = {
693     std_device_dci_type_body(gx_device_X_wrapper, &x_gray_procs, "x11gray4",
694 	&st_device_X_wrapper,
695 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
696 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
697 	1, 4, 15, 0, 16, 0),
698     X_WRAPPER_DATA(x_gray_alt_map_color)
699 };
700 
701 /* Map a fake color to RGB. */
702 private int
703 x_gray_alt_map_color(gx_device * dev, gx_color_index color,
704 		     gx_color_value rgb[3])
705 {
706     rgb[0] = rgb[1] = rgb[2] =
707 	color * gx_max_color_value / dev->color_info.max_gray;
708     return -1;
709 }
710 
711 #ifdef USE_BROKEN_X11ALPHA
712 /* ---------------- Alpha procedures ---------------- */
713 
714 /* Device procedures */
715 private dev_proc_map_color_rgb(x_alpha_map_color_rgb);
716 private dev_proc_map_rgb_alpha_color(x_alpha_map_rgb_alpha_color);
717 private dev_proc_copy_alpha(x_alpha_copy_alpha);
718 /* Extended device procedures */
719 private dev_proc_map_color_rgb(x_alpha_alt_map_color);
720 
721 /* The device descriptor */
722 private const gx_device_procs x_alpha_procs = {
723     x_wrap_open,
724     gx_forward_get_initial_matrix,
725     x_forward_sync_output,
726     x_forward_output_page,
727     x_wrap_close,
728     gx_forward_map_rgb_color,
729     x_alpha_map_color_rgb,
730     x_wrap_fill_rectangle,
731     gx_default_tile_rectangle,
732     x_wrap_copy_mono,
733     x_forward_copy_color,
734     gx_default_draw_line,
735     x_forward_get_bits,
736     x_wrap_get_params,
737     x_wrap_put_params,
738     gx_forward_map_cmyk_color,
739     gx_forward_get_xfont_procs,
740     gx_forward_get_xfont_device,
741     x_alpha_map_rgb_alpha_color,
742     gx_forward_get_page_device,
743     gx_default_get_alpha_bits,
744 	/*gx_default_copy_alpha */ x_alpha_copy_alpha
745 };
746 
747 /* The instance is public. */
748 const gx_device_X_wrapper gs_x11alpha_device = {
749     std_device_dci_alpha_type_body(gx_device_X_wrapper, &x_alpha_procs,
750 	"x11alpha", &st_device_X_wrapper,
751 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
752 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
753 	3, 32, 255, 255, 256, 256, 4, 4),
754     X_WRAPPER_DATA(x_alpha_alt_map_color)
755 };
756 
757 /* Map a fake color to RGB. */
758 private int
759 x_alpha_alt_map_color(gx_device * dev, gx_color_index color,
760 		      gx_color_value rgb[3])
761 {
762     return color & 0xffffff;	/* just remove alpha */
763 }
764 #endif
765 /* Device procedures */
766 
767 /* We encode a complemented alpha value in the top 8 bits of the */
768 /* device color. */
769 private int
770 x_alpha_map_color_rgb(gx_device * dev, gx_color_index color,
771 		      gx_color_value prgb[3])
772 {
773     return gx_forward_map_color_rgb(dev, color & 0xffffff, prgb);
774 }
775 private gx_color_index
776 x_alpha_map_rgb_alpha_color(gx_device * dev,
777  gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha)
778 {
779     gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b);
780     byte abyte = alpha >> (gx_color_value_bits - 8);
781 
782     return (abyte == 0 ? (gx_color_index)0xff << 24 :
783 	    ((gx_color_index) (abyte ^ 0xff) << 24) + color);
784 }
785 
786 #ifdef USE_BROKEN_X11ALPHA
787 private int
788 x_alpha_copy_alpha(gx_device * dev, const unsigned char *base, int sourcex,
789 		   int raster, gx_bitmap_id id, int x, int y, int w, int h,
790 		   gx_color_index color, int depth)
791 {
792     gx_device *tdev;
793     int xi, yi;
794     const byte *row = base;
795     gx_color_index base_color = color & 0xffffff;
796 
797     /* We fake alpha by interpreting it as saturation, i.e., */
798     /* alpha = 0 is white, alpha = 15/15 is the full color. */
799     gx_color_value rgb[3];
800     gx_color_index shades[16];
801     int i;
802 
803     set_dev_target(tdev, dev);
804     for (i = 0; i < 15; ++i)
805 	shades[i] = gx_no_color_index;
806     shades[15] = base_color;
807     (*dev_proc(tdev, map_color_rgb)) (tdev, base_color, rgb);
808     /* Do the copy operation pixel-by-pixel. */
809     /* For the moment, if the base color has alpha in it, we ignore it. */
810     for (yi = y; yi < y + h; row += raster, ++yi) {
811 	int prev_x = x;
812 	gx_color_index prev_color = gx_no_color_index;
813 	uint prev_alpha = 0x10;	/* not a possible value */
814 
815 	for (xi = x; xi < x + w; ++xi) {
816 	    int sx = sourcex + xi - x;
817 	    uint alpha2 = row[sx >> 1];
818 	    uint alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4);
819 	    gx_color_index a_color;
820 
821 	    if (alpha == prev_alpha)
822 		continue;
823 	    prev_alpha = alpha;
824 	    if (alpha == 0)
825 		a_color = gx_no_color_index;
826 	    else
827 		while ((a_color = shades[alpha]) == gx_no_color_index) {	/* Map the color now. */
828 #define make_shade(v, alpha)\
829   (gx_max_color_value -\
830    ((gx_max_color_value - (v)) * (alpha) / 15))
831 		    gx_color_value r = make_shade(rgb[0], alpha);
832 		    gx_color_value g = make_shade(rgb[1], alpha);
833 		    gx_color_value b = make_shade(rgb[2], alpha);
834 
835 #undef make_shade
836 		    a_color = (*dev_proc(tdev, map_rgb_color)) (tdev, r, g, b);
837 		    if (a_color != gx_no_color_index) {
838 			shades[alpha] = a_color;
839 			break;
840 		    }
841 		    /* Try a higher saturation.  (We know */
842 		    /* the fully saturated color exists.) */
843 		    alpha += (16 - alpha) >> 1;
844 		}
845 	    if (a_color != prev_color) {
846 		if (prev_color != gx_no_color_index)
847 		    (*dev_proc(tdev, fill_rectangle)) (tdev,
848 						 prev_x, yi, xi - prev_x, 1,
849 						       prev_color);
850 		prev_x = xi;
851 		prev_color = a_color;
852 	    }
853 	}
854 	if (prev_color != gx_no_color_index)
855 	    (*dev_proc(tdev, fill_rectangle)) (tdev,
856 					       prev_x, yi, x + w - prev_x, 1,
857 					       prev_color);
858     }
859     return 0;
860 }
861 #endif
862 
863 /* ---------------- Permuted RGB16/32 procedures ---------------- */
864 
865 /* Device procedures */
866 private dev_proc_map_rgb_color(x_rg16x_map_rgb_color);
867 private dev_proc_map_rgb_color(x_rg32x_map_rgb_color);
868 /* Extended device procedures */
869 private dev_proc_map_color_rgb(x_rg16x_alt_map_color);
870 private dev_proc_map_color_rgb(x_rg32x_alt_map_color);
871 
872 /* The device descriptor */
873 #define RGBX_PROCS(map_rgb_proc)\
874     x_wrap_open,\
875     gx_forward_get_initial_matrix,\
876     x_forward_sync_output,\
877     x_forward_output_page,\
878     x_wrap_close,\
879     map_rgb_proc,		/* differs */\
880     x_wrap_map_color_rgb,\
881     x_wrap_fill_rectangle,\
882     gx_default_tile_rectangle,\
883     x_wrap_copy_mono,\
884     x_forward_copy_color,\
885     gx_default_draw_line,\
886     x_forward_get_bits,\
887     x_wrap_get_params,\
888     x_wrap_put_params,\
889     gx_forward_map_cmyk_color,\
890     gx_forward_get_xfont_procs,\
891     gx_forward_get_xfont_device,\
892     x_alpha_map_rgb_alpha_color,\
893     gx_forward_get_page_device,\
894     gx_default_get_alpha_bits,\
895     gx_default_copy_alpha
896 
897 private const gx_device_procs x_rg16x_procs = {
898     RGBX_PROCS(x_rg16x_map_rgb_color)
899 };
900 const gx_device_X_wrapper gs_x11rg16x_device = {
901     std_device_dci_type_body(gx_device_X_wrapper, &x_rg16x_procs, "x11rg16x",
902 	&st_device_X_wrapper,
903 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
904 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
905 	3, 16, 31, 31, 32, 32),
906     X_WRAPPER_DATA(x_rg16x_alt_map_color)
907 };
908 
909 private const gx_device_procs x_rg32x_procs = {
910     RGBX_PROCS(x_rg32x_map_rgb_color)
911 };
912 const gx_device_X_wrapper gs_x11rg32x_device = {
913     std_device_dci_type_body(gx_device_X_wrapper, &x_rg32x_procs, "x11rg32x",
914 	&st_device_X_wrapper,
915 	FAKE_RES * 85 / 10, FAKE_RES * 11,	/* x and y extent (nominal) */
916 	FAKE_RES, FAKE_RES,	/* x and y density (nominal) */
917 	3, 32, 1023, 1023, 1024, 1024),
918     X_WRAPPER_DATA(x_rg32x_alt_map_color)
919 };
920 
921 /* Map RGB to a fake color. */
922 private gx_color_index
923 x_rg16x_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
924 		      gx_color_value b)
925 {
926     /* Permute the colors to G5/B5/R6. */
927     return (r >> (gx_color_value_bits - 6)) +
928 	((g >> (gx_color_value_bits - 5)) << 11) +
929 	((b >> (gx_color_value_bits - 5)) << 6);
930 }
931 private gx_color_index
932 x_rg32x_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
933 		      gx_color_value b)
934 {
935     /* Permute the colors to G11/B10/R11. */
936     return (r >> (gx_color_value_bits - 11)) +
937 	((gx_color_index)(g >> (gx_color_value_bits - 11)) << 21) +
938 	((gx_color_index)(b >> (gx_color_value_bits - 10)) << 11);
939 }
940 
941 /* Map a fake color to RGB. */
942 private int
943 x_rg16x_alt_map_color(gx_device * dev, gx_color_index color,
944 		      gx_color_value rgb[3])
945 {
946     rgb[0] = (color & 0x3f) * gx_max_color_value / 0x3f;
947     rgb[1] = ((color >> 11) & 0x1f) * gx_max_color_value / 0x1f;
948     rgb[2] = ((color >> 6) & 0x1f) * gx_max_color_value / 0x1f;
949     return -1;
950 }
951 private int
952 x_rg32x_alt_map_color(gx_device * dev, gx_color_index color,
953 		      gx_color_value rgb[3])
954 {
955     rgb[0] = (color & 0x7ff) * gx_max_color_value / 0x7ff;
956     rgb[1] = ((color >> 21) & 0x7ff) * gx_max_color_value / 0x7ff;
957     rgb[2] = ((color >> 11) & 0x3ff) * gx_max_color_value / 0x3ff;
958     return -1;
959 }
960