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