xref: /plan9/sys/src/cmd/gs/src/gdevdsp.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2001-2005, Ghostgum Software Pty Ltd.  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 /* gdevdsp.c */
18 /* $Id: gdevdsp.c,v 1.35 2005/09/04 05:44:43 dan Exp $ */
19 
20 /*
21  * DLL based display device driver.
22  *
23  * by Russell Lang, Ghostgum Software Pty Ltd
24  *
25  * This device is intended to be used for displays when
26  * Ghostscript is loaded as a DLL/shared library/static library.
27  * It is intended to work for Windows, OS/2, Linux, Mac OS 9 and
28  * hopefully others.
29  *
30  * Before this device is opened, the address of a structure must
31  * be provided using gsapi_set_display_callback(minst, callback);
32  * This structure contains callback functions to notify the
33  * caller when the device is opened, closed, resized, showpage etc.
34  * The structure is defined in gdevdsp.h.
35  *
36  * Not all combinations of display formats have been tested.
37  * At the end of this file is some example code showing which
38  * formats have been tested.
39  */
40 
41 #include "string_.h"
42 #include "gx.h"
43 #include "gserrors.h"
44 #include "gsdevice.h"		/* for gs_copydevice */
45 #include "gxdevice.h"
46 
47 #include "gp.h"
48 #include "gpcheck.h"
49 #include "gsparam.h"
50 
51 #include "gdevpccm.h"		/* 4-bit PC color */
52 #include "gxdevmem.h"
53 #include "gdevdevn.h"
54 #include "gsequivc.h"
55 #include "gdevdsp.h"
56 #include "gdevdsp2.h"
57 
58 /* Initial values for width and height */
59 #define INITIAL_RESOLUTION 96
60 #define INITIAL_WIDTH ((INITIAL_RESOLUTION * 85 + 5) / 10)
61 #define INITIAL_HEIGHT ((INITIAL_RESOLUTION * 110 + 5) / 10)
62 
63 /* Device procedures */
64 
65 /* See gxdevice.h for the definitions of the procedures. */
66 private dev_proc_open_device(display_open);
67 private dev_proc_get_initial_matrix(display_get_initial_matrix);
68 private dev_proc_sync_output(display_sync_output);
69 private dev_proc_output_page(display_output_page);
70 private dev_proc_close_device(display_close);
71 
72 private dev_proc_map_rgb_color(display_map_rgb_color_device4);
73 private dev_proc_map_color_rgb(display_map_color_rgb_device4);
74 private dev_proc_encode_color(display_encode_color_device8);
75 private dev_proc_decode_color(display_decode_color_device8);
76 private dev_proc_map_rgb_color(display_map_rgb_color_device16);
77 private dev_proc_map_color_rgb(display_map_color_rgb_device16);
78 private dev_proc_map_rgb_color(display_map_rgb_color_rgb);
79 private dev_proc_map_color_rgb(display_map_color_rgb_rgb);
80 private dev_proc_map_rgb_color(display_map_rgb_color_bgr24);
81 private dev_proc_map_color_rgb(display_map_color_rgb_bgr24);
82 
83 private dev_proc_fill_rectangle(display_fill_rectangle);
84 private dev_proc_copy_mono(display_copy_mono);
85 private dev_proc_copy_color(display_copy_color);
86 private dev_proc_get_bits(display_get_bits);
87 private dev_proc_get_params(display_get_params);
88 private dev_proc_put_params(display_put_params);
89 private dev_proc_finish_copydevice(display_finish_copydevice);
90 
91 private dev_proc_get_color_mapping_procs(display_separation_get_color_mapping_procs);
92 private dev_proc_get_color_comp_index(display_separation_get_color_comp_index);
93 private dev_proc_encode_color(display_separation_encode_color);
94 private dev_proc_decode_color(display_separation_decode_color);
95 private dev_proc_update_spot_equivalent_colors(display_update_spot_equivalent_colors);
96 
97 
98 private const gx_device_procs display_procs =
99 {
100     display_open,
101     display_get_initial_matrix,
102     display_sync_output,
103     display_output_page,
104     display_close,
105     gx_default_w_b_map_rgb_color,
106     gx_default_w_b_map_color_rgb,
107     display_fill_rectangle,
108     NULL,				/* tile rectangle */
109     display_copy_mono,
110     display_copy_color,
111     NULL,				/* draw line */
112     display_get_bits,
113     display_get_params,
114     display_put_params,
115     gx_default_cmyk_map_cmyk_color, 	/* map_cmyk_color */
116     gx_default_get_xfont_procs,
117     NULL,				/* get_xfont_device */
118     NULL,				/* map_rgb_alpha_color */
119     gx_page_device_get_page_device,
120     /* extra entries */
121     NULL,				/* get_alpha_bits */
122     NULL,				/* copy_alpha */
123     NULL,				/* get_band */
124     NULL,				/* copy_rop */
125     NULL,				/* fill_path */
126     NULL,				/* stroke_path */
127     NULL,				/* fill_mask */
128     NULL,				/* fill_trapezoid */
129     NULL,				/* fill_parallelogram */
130     NULL,				/* fill_triangle */
131     NULL,				/* draw_thin_line */
132     NULL,				/* begin_image */
133     NULL,				/* image_data */
134     NULL,				/* end_image */
135     NULL,				/* strip_tile_rectangle */
136     NULL,				/* strip_copy_rop */
137     NULL,				/* get_clipping_box */
138     NULL,				/* begin_typed_image */
139     NULL,				/* get_bits_rectangle */
140     NULL,				/* map_color_rgb_alpha */
141     NULL,				/* create_compositor */
142     NULL,				/* get_hardware_params */
143     NULL,				/* text_begin */
144     display_finish_copydevice,		/* finish_copydevice */
145     NULL,				/* begin_transparency_group */
146     NULL,				/* end_transparency_group */
147     NULL,				/* begin_transparency_mask */
148     NULL,				/* end_transparency_mask */
149     NULL,				/* discard_transparency_layer */
150     NULL,				/* get_color_mapping_procs */
151     NULL,				/* get_color_comp_index */
152     NULL,           			/* encode_color */
153     NULL,           			/* decode_color */
154     NULL,                          	/* pattern_manage */
155     NULL,				/* fill_rectangle_hl_color */\
156     NULL,				/* include_color_space */\
157     NULL,				/* fill_linear_color_scanline */\
158     NULL,				/* fill_linear_color_trapezoid */\
159     NULL,				/* fill_linear_color_triangle */\
160     display_update_spot_equivalent_colors /* update_spot_equivalent_colors */
161 };
162 
163 /* GC descriptor */
164 public_st_device_display();
165 
166 private
167 ENUM_PTRS_WITH(display_enum_ptrs, gx_device_display *ddev)
168     if (index == 0) {
169 	if (ddev->mdev) {
170 	    return ENUM_OBJ(gx_device_enum_ptr((gx_device *)ddev->mdev));
171 	}
172 	return 0;
173     }
174     else if (index-1 < ddev->devn_params.separations.num_separations)
175         ENUM_RETURN(ddev->devn_params.separations.names[index-1].data);
176     else
177 	return 0;
178 ENUM_PTRS_END
179 
180 private
181 RELOC_PTRS_WITH(display_reloc_ptrs, gx_device_display *ddev)
182     if (ddev->mdev) {
183 	ddev->mdev = (gx_device_memory *)
184 	    gx_device_reloc_ptr((gx_device *)ddev->mdev, gcst);
185     }
186     {   int i;
187         for (i = 0; i < ddev->devn_params.separations.num_separations; ++i) {
188             RELOC_PTR(gx_device_display, devn_params.separations.names[i].data);
189         }
190     }
191 RELOC_PTRS_END
192 
193 
194 const gx_device_display gs_display_device =
195 {
196     std_device_std_body_type(gx_device_display, &display_procs, "display",
197 			&st_device_display,
198 			INITIAL_WIDTH, INITIAL_HEIGHT,
199 			INITIAL_RESOLUTION, INITIAL_RESOLUTION),
200     {0},			/* std_procs */
201     NULL,			/* mdev */
202     NULL,			/* callback */
203     NULL,			/* pHandle */
204     0,				/* nFormat */
205     NULL,			/* pBitmap */
206     0, 				/* ulBitmapSize */
207     0, 				/* HWResolution_set */
208 
209     {    /* devn_params specific parameters */
210       8,        /* Bits per color - must match ncomp, depth, etc. */
211       DeviceCMYKComponents,     /* Names of color model colorants */
212       4,                        /* Number of colorants for CMYK */
213       0,                        /* MaxSeparations has not been specified */
214       {0},                      /* SeparationNames */
215       {0},                      /* SeparationOrder names */
216       {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
217     },
218     { true }                   /* equivalent CMYK colors for spot colors */
219 };
220 
221 
222 
223 /* prototypes for internal procedures */
224 private int display_check_structure(gx_device_display *dev);
225 private void display_free_bitmap(gx_device_display * dev);
226 private int display_alloc_bitmap(gx_device_display *, gx_device *);
227 private int display_set_color_format(gx_device_display *dev, int nFormat);
228 private int display_set_separations(gx_device_display *dev);
229 private int display_raster(gx_device_display *dev);
230 
231 /* Open the display driver. */
232 private int
display_open(gx_device * dev)233 display_open(gx_device * dev)
234 {
235     gx_device_display *ddev = (gx_device_display *) dev;
236     int ccode;
237 
238     /* Erase these, in case we are opening a copied device. */
239     ddev->mdev = NULL;
240     ddev->pBitmap = NULL;
241     ddev->ulBitmapSize = 0;
242 
243     /* Allow device to be opened "disabled" without a callback. */
244     /* The callback will be set later and the device re-opened. */
245     if (ddev->callback == NULL)
246 	return 0;
247 
248     /* Make sure we have been passed a valid callback structure. */
249     if ((ccode = display_check_structure(ddev)) < 0)
250 	return_error(ccode);
251 
252     /* set color info */
253     if ((ccode = display_set_color_format(ddev, ddev->nFormat)) < 0)
254 	return_error(ccode);
255 
256     /* Tell caller that the device is open. */
257     /* This is always the first callback */
258     ccode = (*(ddev->callback->display_open))(ddev->pHandle, dev);
259     if (ccode < 0)
260 	return_error(ccode);
261 
262     /* Tell caller the proposed device parameters */
263     ccode = (*(ddev->callback->display_presize)) (ddev->pHandle, dev,
264 	dev->width, dev->height, display_raster(ddev), ddev->nFormat);
265     if (ccode < 0) {
266 	(*(ddev->callback->display_close))(ddev->pHandle, dev);
267 	return_error(ccode);
268     }
269 
270     /* allocate the image */
271     ccode = display_alloc_bitmap(ddev, dev);
272     if (ccode < 0) {
273 	(*(ddev->callback->display_close))(ddev->pHandle, dev);
274 	return_error(ccode);
275     }
276 
277     /* Tell caller the device parameters */
278     ccode = (*(ddev->callback->display_size)) (ddev->pHandle, dev,
279 	dev->width, dev->height, display_raster(ddev), ddev->nFormat,
280 	ddev->mdev->base);
281     if (ccode < 0) {
282 	display_free_bitmap(ddev);
283 	(*(ddev->callback->display_close))(ddev->pHandle, dev);
284 	return_error(ccode);
285     }
286 
287     return 0;
288 }
289 
290 private void
display_get_initial_matrix(gx_device * dev,gs_matrix * pmat)291 display_get_initial_matrix(gx_device * dev, gs_matrix * pmat)
292 {
293     gx_device_display *ddev = (gx_device_display *) dev;
294     if ((ddev->nFormat & DISPLAY_FIRSTROW_MASK) == DISPLAY_TOPFIRST)
295 	gx_default_get_initial_matrix(dev, pmat);
296     else
297 	gx_upright_get_initial_matrix(dev, pmat);  /* Windows / OS/2 */
298 }
299 
300 /* Update the display. */
301 int
display_sync_output(gx_device * dev)302 display_sync_output(gx_device * dev)
303 {
304     gx_device_display *ddev = (gx_device_display *) dev;
305     if (ddev->callback == NULL)
306 	return 0;
307     display_set_separations(ddev);
308 
309     (*(ddev->callback->display_sync))(ddev->pHandle, dev);
310     return (0);
311 }
312 
313 /* Update the display, bring to foreground. */
314 /* If you want to pause on showpage, delay your return from callback */
315 int
display_output_page(gx_device * dev,int copies,int flush)316 display_output_page(gx_device * dev, int copies, int flush)
317 {
318     gx_device_display *ddev = (gx_device_display *) dev;
319     int code;
320     if (ddev->callback == NULL)
321 	return 0;
322     display_set_separations(ddev);
323 
324     code = (*(ddev->callback->display_page))
325 			(ddev->pHandle, dev, copies, flush);
326 
327     if (code >= 0)
328 	code = gx_finish_output_page(dev, copies, flush);
329     return code;
330 }
331 
332 /* Close the display driver */
333 private int
display_close(gx_device * dev)334 display_close(gx_device * dev)
335 {
336     gx_device_display *ddev = (gx_device_display *) dev;
337     if (ddev->callback == NULL)
338 	return 0;
339 
340     /* Tell caller that device is about to be closed. */
341     (*(ddev->callback->display_preclose))(ddev->pHandle, dev);
342 
343     /* Release memory. */
344     display_free_bitmap(ddev);
345 
346     /* Tell caller that device is closed. */
347     /* This is always the last callback */
348     (*(ddev->callback->display_close))(ddev->pHandle, dev);
349 
350     return 0;
351 }
352 
353 /*
354  * This routine will encode a 1 Black on white color.
355  */
356 private gx_color_index
gx_b_w_gray_encode(gx_device * dev,const gx_color_value cv[])357 gx_b_w_gray_encode(gx_device * dev, const gx_color_value cv[])
358 {
359     return 1 - (cv[0] >> (gx_color_value_bits - 1));
360 }
361 
362 /* DISPLAY_COLORS_NATIVE, 4bit/pixel */
363 /* Map a r-g-b color to a color code */
364 private gx_color_index
display_map_rgb_color_device4(gx_device * dev,const gx_color_value cv[])365 display_map_rgb_color_device4(gx_device * dev, const gx_color_value cv[])
366 {
367     return pc_4bit_map_rgb_color(dev, cv);
368 }
369 
370 /* Map a color code to r-g-b. */
371 private int
display_map_color_rgb_device4(gx_device * dev,gx_color_index color,gx_color_value prgb[3])372 display_map_color_rgb_device4(gx_device * dev, gx_color_index color,
373 		 gx_color_value prgb[3])
374 {
375     pc_4bit_map_color_rgb(dev, color, prgb);
376     return 0;
377 }
378 
379 /* DISPLAY_COLORS_NATIVE, 8bit/pixel */
380 /* Map a r-g-b-k color to a color code */
381 private gx_color_index
display_encode_color_device8(gx_device * dev,const gx_color_value cv[])382 display_encode_color_device8(gx_device * dev, const gx_color_value cv[])
383 {
384     /* palette of 96 colors */
385     /* 0->63 = 00RRGGBB, 64->95 = 010YYYYY */
386     gx_color_value r = cv[0];
387     gx_color_value g = cv[1];
388     gx_color_value b = cv[2];
389     gx_color_value k = cv[3]; /* 0 = black */
390     if ((r == 0) && (g == 0) && (b == 0)) {
391 	k = ((k >> (gx_color_value_bits - 6)) + 1) >> 1;
392 	if (k > 0x1f)
393 	    k = 0x1f;
394 	return (k + 0x40);
395     }
396     if (k > 0) {
397 	/* The RGB->RGBK color mapping shouldn't generate this. */
398 	r = ((r+k) > gx_max_color_value) ? gx_max_color_value :
399 	    (gx_color_value)(r+k);
400 	g = ((g+k) > gx_max_color_value) ? gx_max_color_value :
401 	    (gx_color_value)(g+k);
402 	b = ((b+k) > gx_max_color_value) ? gx_max_color_value :
403 	    (gx_color_value)(b+k);
404     }
405     r = ((r >> (gx_color_value_bits - 3)) + 1) >> 1;
406     if (r > 0x3)
407 	r = 0x3;
408     g = ((g >> (gx_color_value_bits - 3)) + 1) >> 1;
409     if (g > 0x3)
410 	g = 0x3;
411     b = ((b >> (gx_color_value_bits - 3)) + 1) >> 1;
412     if (b > 0x3)
413 	b = 0x3;
414     return (r << 4) + (g << 2) + b;
415 }
416 
417 /* Map a color code to r-g-b-k. */
418 private int
display_decode_color_device8(gx_device * dev,gx_color_index color,gx_color_value prgb[4])419 display_decode_color_device8(gx_device * dev, gx_color_index color,
420 		 gx_color_value prgb[4])
421 {
422     gx_color_value one;
423     /* palette of 96 colors */
424     /* 0->63 = 00RRGGBB, 64->95 = 010YYYYY */
425     if (color < 64) {
426 	one = (gx_color_value) (gx_max_color_value / 3);
427 	prgb[0] = (gx_color_value) (((color >> 4) & 3) * one);
428 	prgb[1] = (gx_color_value) (((color >> 2) & 3) * one);
429 	prgb[2] = (gx_color_value) (((color) & 3) * one);
430 	prgb[3] = 0;
431     }
432     else if (color < 96) {
433 	one = (gx_color_value) (gx_max_color_value / 31);
434 	prgb[0] = prgb[1] = prgb[2] = 0;
435 	prgb[3] = (gx_color_value) ((color & 0x1f) * one);
436     }
437     else {
438 	prgb[0] = prgb[1] = prgb[2] = prgb[3] = 0;
439     }
440     return 0;
441 }
442 
443 
444 /* DISPLAY_COLORS_NATIVE, 16bit/pixel */
445 /* Map a r-g-b color to a color code */
446 private gx_color_index
display_map_rgb_color_device16(gx_device * dev,const gx_color_value cv[])447 display_map_rgb_color_device16(gx_device * dev, const gx_color_value cv[])
448 {
449     gx_device_display *ddev = (gx_device_display *) dev;
450     gx_color_value r = cv[0];
451     gx_color_value g = cv[1];
452     gx_color_value b = cv[2];
453     if ((ddev->nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN) {
454 	if ((ddev->nFormat & DISPLAY_555_MASK) == DISPLAY_NATIVE_555)
455 	    /* byte0=0RRRRRGG byte1=GGGBBBBB */
456 	    return ((r >> (gx_color_value_bits - 5)) << 10) +
457 		((g >> (gx_color_value_bits - 5)) << 5) +
458 		(b >> (gx_color_value_bits - 5));
459 	else
460 	    /* byte0=RRRRRGGG byte1=GGGBBBBB */
461 	    return ((r >> (gx_color_value_bits - 5)) << 11) +
462 		((g >> (gx_color_value_bits - 6)) << 5) +
463 		(b >> (gx_color_value_bits - 5));
464     }
465 
466     if ((ddev->nFormat & DISPLAY_555_MASK) == DISPLAY_NATIVE_555)
467 	/* byte0=GGGBBBBB byte1=0RRRRRGG */
468 	return ((r >> (gx_color_value_bits - 5)) << 2) +
469 	    (((g >> (gx_color_value_bits - 5)) & 0x7) << 13) +
470 	    (((g >> (gx_color_value_bits - 5)) & 0x18) >> 3) +
471 	    ((b >> (gx_color_value_bits - 5)) << 8);
472 
473     /* byte0=GGGBBBBB byte1=RRRRRGGG */
474     return ((r >> (gx_color_value_bits - 5)) << 3) +
475 	(((g >> (gx_color_value_bits - 6)) & 0x7) << 13) +
476 	(((g >> (gx_color_value_bits - 6)) & 0x38) >> 3) +
477 	((b >> (gx_color_value_bits - 5)) << 8);
478 }
479 
480 
481 
482 /* Map a color code to r-g-b. */
483 private int
display_map_color_rgb_device16(gx_device * dev,gx_color_index color,gx_color_value prgb[3])484 display_map_color_rgb_device16(gx_device * dev, gx_color_index color,
485 		 gx_color_value prgb[3])
486 {
487     gx_device_display *ddev = (gx_device_display *) dev;
488     ushort value;
489 
490     if ((ddev->nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN) {
491 	if ((ddev->nFormat & DISPLAY_555_MASK) == DISPLAY_NATIVE_555) {
492 	    /* byte0=0RRRRRGG byte1=GGGBBBBB */
493 	    value = (ushort) (color >> 10);
494 	    prgb[0] = (gx_color_value)
495 		(((value << 11) + (value << 6) + (value << 1) +
496 		(value >> 4)) >> (16 - gx_color_value_bits));
497 	    value = (ushort) ((color >> 5) & 0x1f);
498 	    prgb[1] = (gx_color_value)
499 		(((value << 11) + (value << 6) + (value << 1) +
500 		(value >> 4)) >> (16 - gx_color_value_bits));
501 	    value = (ushort) (color & 0x1f);
502 	    prgb[2] = (gx_color_value)
503 		(((value << 11) + (value << 6) + (value << 1) +
504 		(value >> 4)) >> (16 - gx_color_value_bits));
505 	}
506 	else {
507 	    /* byte0=RRRRRGGG byte1=GGGBBBBB */
508 	    value = (ushort) (color >> 11);
509 	    prgb[0] = ((value << 11) + (value << 6) + (value << 1) +
510 		(value >> 4)) >> (16 - gx_color_value_bits);
511 	    value = (ushort) ((color >> 5) & 0x3f);
512 	    prgb[1] = (gx_color_value)
513 		((value << 10) + (value << 4) + (value >> 2))
514 		      >> (16 - gx_color_value_bits);
515 	    value = (ushort) (color & 0x1f);
516 	    prgb[2] = (gx_color_value)
517 		((value << 11) + (value << 6) + (value << 1) +
518 		(value >> 4)) >> (16 - gx_color_value_bits);
519 	}
520     }
521     else {
522 	if ((ddev->nFormat & DISPLAY_555_MASK) == DISPLAY_NATIVE_555) {
523 	    /* byte0=GGGBBBBB byte1=0RRRRRGG */
524 	    value = (ushort) ((color >> 2) & 0x1f);
525 	    prgb[0] = (gx_color_value)
526 		((value << 11) + (value << 6) + (value << 1) +
527 		(value >> 4)) >> (16 - gx_color_value_bits);
528 	    value = (ushort)
529 		(((color << 3) & 0x18) +  ((color >> 13) & 0x7));
530 	    prgb[1] = (gx_color_value)
531 		((value << 11) + (value << 6) + (value << 1) +
532 		(value >> 4)) >> (16 - gx_color_value_bits);
533 	    value = (ushort) ((color >> 8) & 0x1f);
534 	    prgb[2] = (gx_color_value)
535 		((value << 11) + (value << 6) + (value << 1) +
536 		(value >> 4)) >> (16 - gx_color_value_bits);
537 	}
538 	else {
539 	    /* byte0=GGGBBBBB byte1=RRRRRGGG */
540 	    value = (ushort) ((color >> 3) & 0x1f);
541 	    prgb[0] = (gx_color_value)
542 		(((value << 11) + (value << 6) + (value << 1) +
543 		(value >> 4)) >> (16 - gx_color_value_bits));
544 	    value = (ushort)
545 		(((color << 3) & 0x38) +  ((color >> 13) & 0x7));
546 	    prgb[1] = (gx_color_value)
547 		(((value << 10) + (value << 4) + (value >> 2))
548 		      >> (16 - gx_color_value_bits));
549 	    value = (ushort) ((color >> 8) & 0x1f);
550 	    prgb[2] = (gx_color_value)
551 		(((value << 11) + (value << 6) + (value << 1) +
552 		(value >> 4)) >> (16 - gx_color_value_bits));
553 	}
554     }
555     return 0;
556 }
557 
558 
559 /* Map a r-g-b color to a color code */
560 private gx_color_index
display_map_rgb_color_rgb(gx_device * dev,const gx_color_value cv[])561 display_map_rgb_color_rgb(gx_device * dev, const gx_color_value cv[])
562 {
563     gx_device_display *ddev = (gx_device_display *) dev;
564     gx_color_value r = cv[0];
565     gx_color_value g = cv[1];
566     gx_color_value b = cv[2];
567     int drop = gx_color_value_bits - 8;
568     gx_color_value red, green, blue;
569 
570     red  = r >> drop;
571     green = g >> drop;
572     blue = b >> drop;
573 
574     switch (ddev->nFormat & DISPLAY_ALPHA_MASK) {
575 	case DISPLAY_ALPHA_NONE:
576 	    if ((ddev->nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN) {
577                 gx_color_value rgb[3];
578                 rgb[0] = r; rgb[1] = g; rgb[2] = b;
579 		return gx_default_rgb_map_rgb_color(dev, rgb); /* RGB */
580             }
581 	    else
582 		return (blue<<16) + (green<<8) + red;		/* BGR */
583 	case DISPLAY_ALPHA_FIRST:
584 	case DISPLAY_UNUSED_FIRST:
585 	    if ((ddev->nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN)
586 		return ((gx_color_index)red<<16) + (green<<8) + blue;		/* xRGB */
587 	    else
588 		return ((gx_color_index)blue<<16) + (green<<8) + red;		/* xBGR */
589 	case DISPLAY_ALPHA_LAST:
590 	case DISPLAY_UNUSED_LAST:
591 	    if ((ddev->nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN)
592 		return ((gx_color_index)red<<24) + (green<<16) + (blue<<8);	/* RGBx */
593 	    else
594 		return ((gx_color_index)blue<<24) + (green<<16) + (red<<8);	/* BGRx */
595     }
596     return 0;
597 }
598 
599 /* Map a color code to r-g-b. */
600 private int
display_map_color_rgb_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])601 display_map_color_rgb_rgb(gx_device * dev, gx_color_index color,
602 		 gx_color_value prgb[3])
603 {
604     gx_device_display *ddev = (gx_device_display *) dev;
605     uint bits_per_color = 8;
606     uint color_mask;
607 
608     color_mask = (1 << bits_per_color) - 1;
609 
610     switch (ddev->nFormat & DISPLAY_ALPHA_MASK) {
611 	case DISPLAY_ALPHA_NONE:
612 	    if ((ddev->nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN)
613 		return gx_default_rgb_map_color_rgb(dev, color, prgb); /* RGB */
614 	    else {
615 		/* BGR */
616 		prgb[0] = (gx_color_value) (((color) & color_mask) *
617 			(ulong) gx_max_color_value / color_mask);
618 		prgb[1] = (gx_color_value)
619 			(((color >> bits_per_color) & color_mask) *
620 			(ulong) gx_max_color_value / color_mask);
621 		prgb[2] = (gx_color_value)
622 			(((color >> 2*bits_per_color) & color_mask) *
623 			(ulong) gx_max_color_value / color_mask);
624 	    }
625 	    break;
626 	case DISPLAY_ALPHA_FIRST:
627 	case DISPLAY_UNUSED_FIRST:
628 	    if ((ddev->nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN) {
629 		/* xRGB */
630 		prgb[0] = (gx_color_value)
631 			(((color >> 2*bits_per_color) & color_mask) *
632 			(ulong) gx_max_color_value / color_mask);
633 		prgb[1] = (gx_color_value)
634 			(((color >> bits_per_color) & color_mask) *
635 			(ulong) gx_max_color_value / color_mask);
636 		prgb[2] = (gx_color_value) (((color) & color_mask) *
637 			(ulong) gx_max_color_value / color_mask);
638 	    }
639 	    else {
640 		/* xBGR */
641 		prgb[0] = (gx_color_value)
642 			(((color) & color_mask) *
643 			(ulong) gx_max_color_value / color_mask);
644 		prgb[1] = (gx_color_value)
645 			(((color >> bits_per_color)   & color_mask) *
646 			(ulong) gx_max_color_value / color_mask);
647 		prgb[2] = (gx_color_value)
648 			(((color >> 2*bits_per_color) & color_mask) *
649 			(ulong) gx_max_color_value / color_mask);
650 	    }
651 	    break;
652 	case DISPLAY_ALPHA_LAST:
653 	case DISPLAY_UNUSED_LAST:
654 	    if ((ddev->nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN) {
655 		/* RGBx */
656 		prgb[0] = (gx_color_value)
657 			(((color >> 3*bits_per_color) & color_mask) *
658 			(ulong) gx_max_color_value / color_mask);
659 		prgb[1] = (gx_color_value)
660 			(((color >> 2*bits_per_color) & color_mask) *
661 			(ulong) gx_max_color_value / color_mask);
662 		prgb[2] = (gx_color_value)
663 			(((color >> bits_per_color)   & color_mask) *
664 			(ulong) gx_max_color_value / color_mask);
665 	    }
666 	    else {
667 		/* BGRx */
668 		prgb[0] = (gx_color_value)
669 			(((color >> bits_per_color)   & color_mask) *
670 			(ulong) gx_max_color_value / color_mask);
671 		prgb[1] = (gx_color_value)
672 			(((color >> 2*bits_per_color) & color_mask) *
673 			(ulong) gx_max_color_value / color_mask);
674 		prgb[2] = (gx_color_value)
675 			(((color >> 3*bits_per_color) & color_mask) *
676 			(ulong) gx_max_color_value / color_mask);
677 	    }
678     }
679     return 0;
680 }
681 
682 /* Map a r-g-b color to a color code */
683 private gx_color_index
display_map_rgb_color_bgr24(gx_device * dev,const gx_color_value cv[])684 display_map_rgb_color_bgr24(gx_device * dev, const gx_color_value cv[])
685 {
686     gx_color_value r = cv[0];
687     gx_color_value g = cv[1];
688     gx_color_value b = cv[2];
689     return (gx_color_value_to_byte(b)<<16) +
690            (gx_color_value_to_byte(g)<<8) +
691             gx_color_value_to_byte(r);
692 }
693 
694 /* Map a color code to r-g-b. */
695 private int
display_map_color_rgb_bgr24(gx_device * dev,gx_color_index color,gx_color_value prgb[3])696 display_map_color_rgb_bgr24(gx_device * dev, gx_color_index color,
697 		 gx_color_value prgb[3])
698 {
699     prgb[0] = gx_color_value_from_byte(color & 0xff);
700     prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
701     prgb[2] = gx_color_value_from_byte((color >> 16) & 0xff);
702     return 0;
703 }
704 
705 /* Fill a rectangle */
706 private int
display_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)707 display_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
708 		  gx_color_index color)
709 {
710     gx_device_display *ddev = (gx_device_display *) dev;
711     if (ddev->callback == NULL)
712 	return 0;
713     dev_proc(ddev->mdev, fill_rectangle)((gx_device *)ddev->mdev,
714 	x, y, w, h, color);
715     if (ddev->callback->display_update)
716 	(*(ddev->callback->display_update))(ddev->pHandle, dev, x, y, w, h);
717     return 0;
718 }
719 
720 /* Copy a monochrome bitmap */
721 private int
display_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)722 display_copy_mono(gx_device * dev,
723 	     const byte * base, int sourcex, int raster, gx_bitmap_id id,
724 	     int x, int y, int w, int h,
725 	     gx_color_index zero, gx_color_index one)
726 {
727     gx_device_display *ddev = (gx_device_display *) dev;
728     if (ddev->callback == NULL)
729 	return 0;
730     dev_proc(ddev->mdev, copy_mono)((gx_device *)ddev->mdev,
731 	base, sourcex, raster, id, x, y, w, h, zero, one);
732     if (ddev->callback->display_update)
733 	(*(ddev->callback->display_update))(ddev->pHandle, dev, x, y, w, h);
734     return 0;
735 }
736 
737 /* Copy a color pixel map  */
738 private int
display_copy_color(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)739 display_copy_color(gx_device * dev,
740 	      const byte * base, int sourcex, int raster, gx_bitmap_id id,
741 	      int x, int y, int w, int h)
742 {
743     gx_device_display *ddev = (gx_device_display *) dev;
744     if (ddev->callback == NULL)
745 	return 0;
746     dev_proc(ddev->mdev, copy_color)((gx_device *)ddev->mdev,
747 	base, sourcex, raster, id, x, y, w, h);
748     if (ddev->callback->display_update)
749 	(*(ddev->callback->display_update))(ddev->pHandle, dev, x, y, w, h);
750     return 0;
751 }
752 
753 private int
display_get_bits(gx_device * dev,int y,byte * str,byte ** actual_data)754 display_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data)
755 {
756     gx_device_display *ddev = (gx_device_display *) dev;
757     if (ddev->callback == NULL)
758 	return 0;
759     return dev_proc(ddev->mdev, get_bits)((gx_device *)ddev->mdev,
760 	y, str, actual_data);
761 }
762 
763 private int
display_get_params(gx_device * dev,gs_param_list * plist)764 display_get_params(gx_device * dev, gs_param_list * plist)
765 {
766     gx_device_display *ddev = (gx_device_display *) dev;
767     int code;
768     gs_param_string dhandle;
769     int idx;
770     int val;
771     int i = 0;
772     size_t dptr;
773     char buf[64];
774 
775     idx = ((int)sizeof(size_t)) * 8 - 4;
776     buf[i++] = '1';
777     buf[i++] = '6';
778     buf[i++] = '#';
779     dptr = (size_t)(ddev->pHandle);
780     while (idx >= 0) {
781 	val = (int)(dptr >> idx) & 0xf;
782         if (val <= 9)
783 	    buf[i++] = '0' + val;
784 	else
785 	    buf[i++] = 'a' - 10 + val;
786 	idx -= 4;
787     }
788     buf[i] = '\0';
789 
790     param_string_from_transient_string(dhandle, buf);
791 
792     code = gx_default_get_params(dev, plist);
793     (void)(code < 0 ||
794 	(code = param_write_string(plist,
795 	    "DisplayHandle", &dhandle)) < 0 ||
796 	(code = param_write_int(plist,
797 	    "DisplayFormat", &ddev->nFormat)) < 0 ||
798 	(code = param_write_float(plist,
799 	    "DisplayResolution", &ddev->HWResolution[1])) < 0);
800     if (code >= 0 &&
801 	(ddev->nFormat & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION)
802 	code = devn_get_params(dev, plist, &ddev->devn_params,
803 		&ddev->equiv_cmyk_colors);
804     return code;
805 }
806 
807 /* Put parameters. */
808 /* The parameters "DisplayHandle" and "DisplayFormat"
809  * can be changed when the device is closed, but not when open.
810  * The device width and height can be changed when open.
811  */
812 private int
display_put_params(gx_device * dev,gs_param_list * plist)813 display_put_params(gx_device * dev, gs_param_list * plist)
814 {
815     gx_device_display *ddev = (gx_device_display *) dev;
816     int ecode = 0, code;
817     bool is_open = dev->is_open;
818     gs_param_float_array hwra;
819     float dispres = 0.0;
820 
821     int old_width = dev->width;
822     int old_height = dev->height;
823     int old_format = ddev->nFormat;
824     void *old_handle = ddev->pHandle;
825 
826     gs_devn_params *pdevn_params = &ddev->devn_params;
827     equivalent_cmyk_color_params *pequiv_colors = &ddev->equiv_cmyk_colors;
828     /* Save current data in case we have a problem */
829     gs_devn_params saved_devn_params = *pdevn_params;
830     equivalent_cmyk_color_params saved_equiv_colors = *pequiv_colors;
831 
832     int format;
833     void *handle;
834     int found_string_handle = 0;
835     gs_param_string dh = { 0 };
836 
837     /* Handle extra parameters */
838 
839     switch (code = param_read_int(plist, "DisplayFormat", &format)) {
840 	case 0:
841 	    if (dev->is_open) {
842  		if (ddev->nFormat != format)
843 		    ecode = gs_error_rangecheck;
844 		else
845 		    break;
846 	    }
847 	    else {
848 		code = display_set_color_format(ddev, format);
849 		if (code < 0)
850 		    ecode = code;
851 		else
852 		    break;
853 	    }
854 	    goto cfe;
855 	default:
856 	    ecode = code;
857 	  cfe:param_signal_error(plist, "DisplayFormat", ecode);
858 	case 1:
859 	    break;
860     }
861 
862     /* 64-bit systems need to use DisplayHandle as a string */
863     switch (code = param_read_string(plist, "DisplayHandle", &dh)) {
864 	case 0:
865     	    found_string_handle = 1;
866 	    break;
867 	default:
868 	    if ((code == gs_error_typecheck) && (sizeof(size_t) <= 4)) {
869 		/* 32-bit systems can use the older long type */
870 		switch (code = param_read_long(plist, "DisplayHandle",
871 		    (long *)(&handle))) {
872 		    case 0:
873 			if (dev->is_open) {
874 			    if (ddev->pHandle != handle)
875 				ecode = gs_error_rangecheck;
876 			    else
877 				break;
878 			}
879 			else {
880 			    ddev->pHandle = handle;
881 			    break;
882 			}
883 			goto hdle;
884 		    default:
885 			ecode = code;
886 		      hdle:param_signal_error(plist, "DisplayHandle", ecode);
887 		    case 1:
888 			break;
889 		}
890 		break;
891 	    }
892 	    ecode = code;
893 	    param_signal_error(plist, "DisplayHandle", ecode);
894 	    /* fall through */
895 	case 1:
896 	    dh.data = 0;
897 	    break;
898     }
899     if (found_string_handle) {
900 	/*
901 	 * Convert from a string to a pointer.
902 	 * It is assumed that size_t has the same size as a pointer.
903 	 * Allow formats (1234), (10#1234) or (16#04d2).
904 	 */
905 	size_t ptr = 0;
906  	int i;
907 	int base = 10;
908  	int val;
909 	code = 0;
910 	for (i=0; i<dh.size; i++) {
911 	    val = dh.data[i];
912 	    if ((val >= '0') && (val <= '9'))
913 		val = val - '0';
914 	    else if ((val >= 'A') && (val <= 'F'))
915 		val = val - 'A' + 10;
916 	    else if ((val >= 'a') && (val <= 'f'))
917 		val = val - 'a' + 10;
918 	    else if (val == '#') {
919 		base = (int)ptr;
920 		ptr = 0;
921 		if ((base != 10) && (base != 16)) {
922 		    code = gs_error_rangecheck;
923 		    break;
924 		}
925 		continue;
926 	    }
927 	    else {
928 		code = gs_error_rangecheck;
929 		break;
930 	    }
931 
932 	    if (base == 10)
933 		ptr = ptr * 10 + val;
934 	    else if (base == 16)
935 		ptr = ptr * 16 + val;
936 	    else {
937 		code = gs_error_rangecheck;
938 		break;
939 	    }
940 	}
941 	if (code == 0) {
942 	    if (dev->is_open) {
943 		if (ddev->pHandle != (void *)ptr)
944 		    code = gs_error_rangecheck;
945 	    }
946 	    else
947 		ddev->pHandle = (void *)ptr;
948 	}
949 	if (code < 0) {
950 	    ecode = code;
951 	    param_signal_error(plist, "DisplayHandle", ecode);
952 	}
953     }
954 
955     /*
956      * Set the initial display resolution.
957      * If HWResolution is explicitly set, e.g. using -rDPI on the
958      * command line, then use that.  Otherwise, use DisplayResolution
959      * which is typically set by the client to the display
960      * logical resolution.  Once either of these have been
961      * used, ignore all further DisplayResolution parameters.
962      */
963     if (param_read_float_array(plist, "HWResolution", &hwra) == 0)
964 	ddev->HWResolution_set = 1;
965 
966     switch (code = param_read_float(plist, "DisplayResolution", &dispres)) {
967 	case 0:
968 	    if (!ddev->HWResolution_set) {
969 	        gx_device_set_resolution(dev, dispres, dispres);
970 		ddev->HWResolution_set = 1;
971 	    }
972 	    break;
973 	default:
974 	    ecode = code;
975 	    param_signal_error(plist, "DisplayResolution", ecode);
976 	case 1:
977 	    break;
978     }
979 
980     if (ecode >= 0 &&
981 	    (ddev->nFormat & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION) {
982 	/* Use utility routine to handle devn parameters */
983 	ecode = devn_put_params(dev, plist, pdevn_params, pequiv_colors);
984         /*
985 	 * Setting MaxSeparations changes color_info.depth in
986 	 * devn_put_params, but we always use 64bpp,
987 	 * so reset it to the the correct value.
988 	 */
989 	dev->color_info.depth = arch_sizeof_color_index * 8;
990     }
991 
992     if (ecode >= 0) {
993 	/* Prevent gx_default_put_params from closing the device. */
994 	dev->is_open = false;
995 	ecode = gx_default_put_params(dev, plist);
996 	dev->is_open = is_open;
997     }
998     if (ecode < 0) {
999 	/* If we have an error then restore original data. */
1000 	*pdevn_params = saved_devn_params;
1001 	*pequiv_colors = saved_equiv_colors;
1002 	if (format != old_format)
1003 	    display_set_color_format(ddev, old_format);
1004 	ddev->pHandle = old_handle;
1005 	dev->width = old_width;
1006 	dev->height = old_height;
1007 	return ecode;
1008     }
1009 
1010 
1011     if ( is_open && ddev->callback &&
1012 	((old_width != dev->width) || (old_height != dev->height)) ) {
1013 	/* We can resize this device while it is open, but we cannot
1014 	 * change the color format or handle.
1015 	 */
1016 	/* Tell caller we are about to change the device parameters */
1017 	if ((*ddev->callback->display_presize)(ddev->pHandle, dev,
1018 	    dev->width, dev->height, display_raster(ddev),
1019 	    ddev->nFormat) < 0) {
1020 	    /* caller won't let us change the size */
1021 	    /* restore parameters then return an error */
1022 	    *pdevn_params = saved_devn_params;
1023 	    *pequiv_colors = saved_equiv_colors;
1024 	    display_set_color_format(ddev, old_format);
1025 	    ddev->nFormat = old_format;
1026 	    ddev->pHandle = old_handle;
1027 	    dev->width = old_width;
1028 	    dev->height = old_height;
1029 	    return_error(gs_error_rangecheck);
1030 	}
1031 
1032 	display_free_bitmap(ddev);
1033 
1034 	code = display_alloc_bitmap(ddev, dev);
1035 	if (code < 0) {
1036 	    /* No bitmap, so tell the caller it is zero size */
1037 	    (*ddev->callback->display_size)(ddev->pHandle, dev,
1038 	        0, 0, 0, ddev->nFormat, NULL);
1039 	    return_error(code);
1040         }
1041 
1042 	/* tell caller about the new size */
1043 	if ((*ddev->callback->display_size)(ddev->pHandle, dev,
1044 	    dev->width, dev->height, display_raster(ddev),
1045 	    ddev->nFormat, ddev->mdev->base) < 0)
1046 	    return_error(gs_error_rangecheck);
1047     }
1048 
1049     return 0;
1050 }
1051 
1052 /* Clean up the instance after making a copy. */
1053 int
display_finish_copydevice(gx_device * dev,const gx_device * from_dev)1054 display_finish_copydevice(gx_device *dev, const gx_device *from_dev)
1055 {
1056     gx_device_display *ddev = (gx_device_display *) dev;
1057 
1058     /* Mark the new instance as closed. */
1059     ddev->is_open = false;
1060 
1061     /* Clear pointers */
1062     ddev->mdev = NULL;
1063     ddev->pBitmap = NULL;
1064     ddev->ulBitmapSize = 0;
1065 
1066     return 0;
1067 }
1068 
1069 /*
1070  * The following procedures are used to map the standard color spaces into
1071  * the separation color components for the display device.
1072  */
1073 private void
display_separation_gray_cs_to_cmyk_cm(gx_device * dev,frac gray,frac out[])1074 display_separation_gray_cs_to_cmyk_cm(gx_device * dev, frac gray, frac out[])
1075 {
1076     int * map =
1077       (int *)(&((gx_device_display *) dev)->devn_params.separation_order_map);
1078 
1079     gray_cs_to_devn_cm(dev, map, gray, out);
1080 }
1081 
1082 private void
display_separation_rgb_cs_to_cmyk_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])1083 display_separation_rgb_cs_to_cmyk_cm(gx_device * dev,
1084     const gs_imager_state *pis, frac r, frac g, frac b, frac out[])
1085 {
1086     int * map =
1087       (int *)(&((gx_device_display *) dev)->devn_params.separation_order_map);
1088 
1089     rgb_cs_to_devn_cm(dev, map, pis, r, g, b, out);
1090 }
1091 
1092 private void
display_separation_cmyk_cs_to_cmyk_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])1093 display_separation_cmyk_cs_to_cmyk_cm(gx_device * dev,
1094     frac c, frac m, frac y, frac k, frac out[])
1095 {
1096     int * map =
1097       (int *)(&((gx_device_display *) dev)->devn_params.separation_order_map);
1098 
1099     cmyk_cs_to_devn_cm(dev, map, c, m, y, k, out);
1100 }
1101 
1102 private const gx_cm_color_map_procs display_separation_cm_procs = {
1103     display_separation_gray_cs_to_cmyk_cm,
1104     display_separation_rgb_cs_to_cmyk_cm,
1105     display_separation_cmyk_cs_to_cmyk_cm
1106 };
1107 
1108 private const gx_cm_color_map_procs *
display_separation_get_color_mapping_procs(const gx_device * dev)1109 display_separation_get_color_mapping_procs(const gx_device * dev)
1110 {
1111     return &display_separation_cm_procs;
1112 }
1113 
1114 
1115 /*
1116  * Encode a list of colorant values into a gx_color_index_value.
1117  */
1118 private gx_color_index
display_separation_encode_color(gx_device * dev,const gx_color_value colors[])1119 display_separation_encode_color(gx_device *dev, const gx_color_value colors[])
1120 {
1121     int bpc = ((gx_device_display *)dev)->devn_params.bitspercomponent;
1122     int drop = sizeof(gx_color_value) * 8 - bpc;
1123     gx_color_index color = 0;
1124     int i = 0;
1125     int ncomp = dev->color_info.num_components;
1126 
1127     for (; i<ncomp; i++) {
1128 	color <<= bpc;
1129 	color |= (colors[i] >> drop);
1130     }
1131     if (bpc*ncomp < arch_sizeof_color_index * 8)
1132 	color <<= (arch_sizeof_color_index * 8 - ncomp * bpc);
1133     return (color == gx_no_color_index ? color ^ 1 : color);
1134 }
1135 
1136 /*
1137  * Decode a gx_color_index value back to a list of colorant values.
1138  */
1139 private int
display_separation_decode_color(gx_device * dev,gx_color_index color,gx_color_value * out)1140 display_separation_decode_color(gx_device * dev, gx_color_index color,
1141     gx_color_value * out)
1142 {
1143     int bpc = ((gx_device_display *)dev)->devn_params.bitspercomponent;
1144     int drop = sizeof(gx_color_value) * 8 - bpc;
1145     int mask = (1 << bpc) - 1;
1146     int i = 0;
1147     int ncomp = dev->color_info.num_components;
1148 
1149     if (bpc*ncomp < arch_sizeof_color_index * 8)
1150 	color >>= (arch_sizeof_color_index * 8 - ncomp * bpc);
1151     for (; i<ncomp; i++) {
1152 	out[ncomp - i - 1] = (gx_color_value) ((color & mask) << drop);
1153 	color >>= bpc;
1154     }
1155     return 0;
1156 }
1157 
1158 /*
1159  *  Device proc for updating the equivalent CMYK color for spot colors.
1160  */
1161 private int
display_update_spot_equivalent_colors(gx_device * dev,const gs_state * pgs)1162 display_update_spot_equivalent_colors(gx_device * dev, const gs_state * pgs)
1163 {
1164     gx_device_display * ddev = (gx_device_display *)dev;
1165 
1166     if ((ddev->nFormat & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION)
1167         update_spot_equivalent_cmyk_colors(dev, pgs,
1168 		    &ddev->devn_params, &ddev->equiv_cmyk_colors);
1169     return 0;
1170 }
1171 
1172 /*
1173  * This routine will check to see if the color component name  match those
1174  * that are available amoung the current device's color components.
1175  *
1176  * Parameters:
1177  *   dev - pointer to device data structure.
1178  *   pname - pointer to name (zero termination not required)
1179  *   nlength - length of the name
1180  *
1181  * This routine returns a positive value (0 to n) which is the device colorant
1182  * number if the name is found.  It returns GX_DEVICE_COLOR_MAX_COMPONENTS if
1183  * the colorant is not being used due to a SeparationOrder device parameter.
1184  * It returns a negative value if not found.
1185  */
1186 private int
display_separation_get_color_comp_index(gx_device * dev,const char * pname,int name_size,int component_type)1187 display_separation_get_color_comp_index(gx_device * dev,
1188     const char * pname, int name_size, int component_type)
1189 {
1190     return devn_get_color_comp_index(dev,
1191 		&(((gx_device_display *)dev)->devn_params),
1192 		&(((gx_device_display *)dev)->equiv_cmyk_colors),
1193 		pname, name_size, component_type, ENABLE_AUTO_SPOT_COLORS);
1194 }
1195 
1196 
1197 /* ------ Internal routines ------ */
1198 
1199 /* Make sure we have been given a valid structure */
1200 /* Return 0 on success, gs_error_rangecheck on failure */
display_check_structure(gx_device_display * ddev)1201 private int display_check_structure(gx_device_display *ddev)
1202 {
1203     if (ddev->callback == 0)
1204 	return_error(gs_error_rangecheck);
1205 
1206     if (ddev->callback->size == sizeof(struct display_callback_v1_s)) {
1207 	/* Original V1 structure */
1208 	if (ddev->callback->version_major != DISPLAY_VERSION_MAJOR_V1)
1209 	    return_error(gs_error_rangecheck);
1210 
1211 	/* complain if caller asks for newer features */
1212 	if (ddev->callback->version_minor > DISPLAY_VERSION_MINOR_V1)
1213 	    return_error(gs_error_rangecheck);
1214     }
1215     else {
1216 	/* V2 structure with added display_separation callback */
1217 	if (ddev->callback->size != sizeof(display_callback))
1218 	    return_error(gs_error_rangecheck);
1219 
1220 	if (ddev->callback->version_major != DISPLAY_VERSION_MAJOR)
1221 	    return_error(gs_error_rangecheck);
1222 
1223 	/* complain if caller asks for newer features */
1224 	if (ddev->callback->version_minor > DISPLAY_VERSION_MINOR)
1225 	    return_error(gs_error_rangecheck);
1226     }
1227 
1228     if ((ddev->callback->display_open == NULL) ||
1229 	(ddev->callback->display_close == NULL) ||
1230 	(ddev->callback->display_presize == NULL) ||
1231 	(ddev->callback->display_size == NULL) ||
1232 	(ddev->callback->display_sync == NULL) ||
1233 	(ddev->callback->display_page == NULL))
1234 	return_error(gs_error_rangecheck);
1235 
1236     /* Don't test display_update, display_memalloc or display_memfree
1237      * since these may be NULL if not provided.
1238      * Don't test display_separation, since this may be NULL if
1239      * separation format is not supported.
1240      */
1241 
1242     return 0;
1243 }
1244 
1245 private void
display_free_bitmap(gx_device_display * ddev)1246 display_free_bitmap(gx_device_display * ddev)
1247 {
1248     if (ddev->callback == NULL)
1249 	return;
1250     if (ddev->pBitmap) {
1251 	if (ddev->callback->display_memalloc
1252 	    && ddev->callback->display_memfree
1253 	    && ddev->pBitmap) {
1254 	    (*ddev->callback->display_memfree)(ddev->pHandle, ddev,
1255 		ddev->pBitmap);
1256 	}
1257 	else {
1258 	    gs_free_object(ddev->memory->non_gc_memory,
1259 		ddev->pBitmap, "display_free_bitmap");
1260 	}
1261 	ddev->pBitmap = NULL;
1262 	if (ddev->mdev)
1263 	    ddev->mdev->base = NULL;
1264     }
1265     if (ddev->mdev) {
1266 	dev_proc(ddev->mdev, close_device)((gx_device *)ddev->mdev);
1267         gx_device_retain((gx_device *)(ddev->mdev), false);
1268 	ddev->mdev = NULL;
1269     }
1270 }
1271 
1272 /* calculate byte length of a row */
1273 private int
display_raster(gx_device_display * dev)1274 display_raster(gx_device_display *dev)
1275 {
1276     int align = 0;
1277     int bytewidth = dev->width * dev->color_info.depth/8;
1278     switch (dev->nFormat & DISPLAY_ROW_ALIGN_MASK) {
1279 	case DISPLAY_ROW_ALIGN_4:
1280 	    align = 4;
1281 	    break;
1282 	case DISPLAY_ROW_ALIGN_8:
1283 	    align = 8;
1284 	    break;
1285 	case DISPLAY_ROW_ALIGN_16:
1286 	    align = 16;
1287 	    break;
1288 	case DISPLAY_ROW_ALIGN_32:
1289 	    align = 32;
1290 	    break;
1291 	case DISPLAY_ROW_ALIGN_64:
1292 	    align = 64;
1293 	    break;
1294     }
1295     if (align < ARCH_ALIGN_PTR_MOD)
1296 	align = ARCH_ALIGN_PTR_MOD;
1297     align -= 1;
1298     bytewidth = (bytewidth + align) & (~align);
1299     return bytewidth;
1300 }
1301 
1302 /* Allocate the backing bitmap. */
1303 private int
display_alloc_bitmap(gx_device_display * ddev,gx_device * param_dev)1304 display_alloc_bitmap(gx_device_display * ddev, gx_device * param_dev)
1305 {
1306     int ccode;
1307     const gx_device_memory *mdproto;
1308     if (ddev->callback == NULL)
1309 	return 0;
1310 
1311     /* free old bitmap (if any) */
1312     display_free_bitmap(ddev);
1313 
1314     /* allocate a memory device for rendering */
1315     mdproto = gdev_mem_device_for_bits(ddev->color_info.depth);
1316     if (mdproto == 0)
1317 	return_error(gs_error_rangecheck);
1318 
1319     ddev->mdev = gs_alloc_struct(gs_memory_stable(ddev->memory),
1320 	    gx_device_memory, &st_device_memory, "display_memory_device");
1321     if (ddev->mdev == 0)
1322         return_error(gs_error_VMerror);
1323 
1324     gs_make_mem_device(ddev->mdev, mdproto, gs_memory_stable(ddev->memory),
1325 	0, (gx_device *) NULL);
1326     check_device_separable((gx_device *)(ddev->mdev));
1327     gx_device_fill_in_procs((gx_device *)(ddev->mdev));
1328     /* Mark the memory device as retained.  When the bitmap is closed,
1329      * we will clear this and the memory device will be then be freed.
1330      */
1331     gx_device_retain((gx_device *)(ddev->mdev), true);
1332 
1333     /* Memory device width may be larger than device width
1334      * if row alignment is not 4.
1335      */
1336     ddev->mdev->width = param_dev->width;
1337     ddev->mdev->width = display_raster(ddev) * 8 / ddev->color_info.depth;
1338     ddev->mdev->height = param_dev->height;
1339 
1340     /* Tell the memory device to allocate the line pointers separately
1341      * so we can place the bitmap in special memory.
1342      */
1343     ddev->mdev->line_pointer_memory = ddev->mdev->memory;
1344     ddev->ulBitmapSize = gdev_mem_bits_size(ddev->mdev,
1345 	ddev->mdev->width, ddev->mdev->height);
1346 
1347     /* allocate bitmap using an allocator not subject to GC */
1348     if (ddev->callback->display_memalloc
1349 	&& ddev->callback->display_memfree) {
1350         ddev->pBitmap = (*ddev->callback->display_memalloc)(ddev->pHandle,
1351 	    ddev, ddev->ulBitmapSize);
1352     }
1353     else {
1354 	ddev->pBitmap = gs_alloc_byte_array_immovable(ddev->memory->non_gc_memory,
1355 		(uint)ddev->ulBitmapSize, 1, "display_alloc_bitmap");
1356     }
1357 
1358     if (ddev->pBitmap == NULL) {
1359 	ddev->mdev->width = 0;
1360 	ddev->mdev->height = 0;
1361 	return_error(gs_error_VMerror);
1362     }
1363 
1364     ddev->mdev->base = (byte *) ddev->pBitmap;
1365     ddev->mdev->foreign_bits = true;
1366 
1367     ccode = dev_proc(ddev->mdev, open_device)((gx_device *)ddev->mdev);
1368     if (ccode < 0)
1369 	display_free_bitmap(ddev);
1370 
1371     /* erase bitmap - before display gets redrawn */
1372     if (ccode == 0) {
1373 	int i;
1374         gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1375 	for (i=0; i<GX_DEVICE_COLOR_MAX_COMPONENTS; i++)
1376 	    cv[i] = (ddev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE)
1377 		? gx_max_color_value : 0;
1378 	dev_proc(ddev, fill_rectangle)((gx_device *)ddev,
1379                  0, 0, ddev->width, ddev->height,
1380                  ddev->procs.encode_color((gx_device *)ddev, cv));
1381     }
1382 
1383     return ccode;
1384 }
1385 
1386 private int
display_set_separations(gx_device_display * dev)1387 display_set_separations(gx_device_display *dev)
1388 {
1389     if (((dev->nFormat & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION) &&
1390 	(dev->callback->version_major > DISPLAY_VERSION_MAJOR_V1) &&
1391 	(dev->callback->display_separation != NULL)) {
1392 	/* Tell the client about the separation to composite mapping */
1393 	char name[64];
1394 	int num_spot = dev->devn_params.separations.num_separations;
1395 	int num_std_colorants = dev->devn_params.num_std_colorant_names;
1396  	int num_comp = num_std_colorants + num_spot;
1397         int comp_map[GX_DEVICE_COLOR_MAX_COMPONENTS];
1398 	int comp_num;
1399 	int sep_num;
1400 	int sep_name_size;
1401 	unsigned int c, m, y, k;
1402 
1403 	/* Map the separation numbers to component numbers */
1404 	memset(comp_map, 0, sizeof(comp_map));
1405 	for (sep_num = 0; sep_num < num_comp; sep_num++) {
1406 	    comp_num = dev->devn_params.separation_order_map[sep_num];
1407 	    if (comp_num >= 0 && comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS)
1408 		comp_map[comp_num] = sep_num;
1409 	}
1410 	/* For each component, tell the client the separation mapping */
1411 	for (comp_num = 0; comp_num < num_comp; comp_num++) {
1412 	    c = y = m = k = 0;
1413 	    sep_num = comp_map[comp_num];
1414 	    /* Get the CMYK equivalent */
1415 	    if (sep_num < dev->devn_params.num_std_colorant_names) {
1416 		sep_name_size =
1417 		    strlen(dev->devn_params.std_colorant_names[sep_num]);
1418 		if (sep_name_size > sizeof(name)-2)
1419 		    sep_name_size = sizeof(name)-1;
1420 		memcpy(name, dev->devn_params.std_colorant_names[sep_num],
1421 		    sep_name_size);
1422 		name[sep_name_size] = '\0';
1423 		switch (sep_num) {
1424 		    case 0: c = 65535; break;
1425 		    case 1: m = 65535; break;
1426 		    case 2: y = 65535; break;
1427 		    case 3: k = 65535; break;
1428 		}
1429 	    }
1430 	    else {
1431 		sep_num -= dev->devn_params.num_std_colorant_names;
1432 		sep_name_size =
1433 		    dev->devn_params.separations.names[sep_num].size;
1434 		if (sep_name_size > sizeof(name)-2)
1435 		    sep_name_size = sizeof(name)-1;
1436 		memcpy(name, dev->devn_params.separations.names[sep_num].data,
1437 		    sep_name_size);
1438 		name[sep_name_size] = '\0';
1439 		if (dev->equiv_cmyk_colors.color[sep_num].color_info_valid) {
1440 		    c = dev->equiv_cmyk_colors.color[sep_num].c
1441 			   * 65535 / frac_1;
1442 		    m = dev->equiv_cmyk_colors.color[sep_num].m
1443 			   * 65535 / frac_1;
1444 		    y = dev->equiv_cmyk_colors.color[sep_num].y
1445 			   * 65535 / frac_1;
1446 		    k = dev->equiv_cmyk_colors.color[sep_num].k
1447 			   * 65535 / frac_1;
1448 		}
1449 	    }
1450 	    (*dev->callback->display_separation)(dev->pHandle, dev,
1451 		comp_num, name,
1452 		(unsigned short)c, (unsigned short)m,
1453 		(unsigned short)y, (unsigned short)k);
1454 	}
1455     }
1456     return 0;
1457 }
1458 
1459 typedef enum DISPLAY_MODEL_e {
1460     DISPLAY_MODEL_GRAY=0,
1461     DISPLAY_MODEL_RGB=1,
1462     DISPLAY_MODEL_RGBK=2,
1463     DISPLAY_MODEL_CMYK=3,
1464     DISPLAY_MODEL_SEP=4
1465 } DISPLAY_MODEL;
1466 
1467 /*
1468  * This is a utility routine to build the display device's color_info
1469  * structure (except for the anti alias info).
1470  */
1471 private void
set_color_info(gx_device_color_info * pdci,DISPLAY_MODEL model,int nc,int depth,int maxgray,int maxcolor)1472 set_color_info(gx_device_color_info * pdci, DISPLAY_MODEL model,
1473     int nc, int depth, int maxgray, int maxcolor)
1474 {
1475     pdci->num_components = pdci->max_components = nc;
1476     pdci->depth = depth;
1477     pdci->gray_index = 0;
1478     pdci->max_gray = maxgray;
1479     pdci->max_color = maxcolor;
1480     pdci->dither_grays = maxgray + 1;
1481     pdci->dither_colors = maxcolor + 1;
1482     pdci->separable_and_linear = GX_CINFO_UNKNOWN_SEP_LIN;
1483     switch (model) {
1484 	case DISPLAY_MODEL_GRAY:
1485 	    pdci->polarity = GX_CINFO_POLARITY_ADDITIVE;
1486 	    pdci->cm_name = "DeviceGray";
1487 	    pdci->gray_index = 0;
1488 	    break;
1489 	case DISPLAY_MODEL_RGB:
1490 	    pdci->polarity = GX_CINFO_POLARITY_ADDITIVE;
1491 	    pdci->cm_name = "DeviceRGB";
1492 	    pdci->gray_index = GX_CINFO_COMP_NO_INDEX;
1493 	    break;
1494 	case DISPLAY_MODEL_RGBK:
1495 	    pdci->polarity = GX_CINFO_POLARITY_ADDITIVE;
1496 	    pdci->cm_name = "DeviceRGBK";
1497 	    pdci->gray_index = 3;
1498 	    break;
1499 	case DISPLAY_MODEL_CMYK:
1500 	    pdci->polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
1501 	    pdci->cm_name = "DeviceCMYK";
1502 	    pdci->gray_index = 3;
1503 	    break;
1504 	default:
1505 	case DISPLAY_MODEL_SEP:
1506 	    /* Anything else is separations */
1507 	    pdci->polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
1508 	    pdci->cm_name = "DeviceCMYK";
1509 	    pdci->gray_index = GX_CINFO_COMP_NO_INDEX; /* may not have K */
1510 	    break;
1511     }
1512 }
1513 
1514 /*
1515  * This is an utility routine to set up the color procs for the display
1516  * device.  The display device can change its setup.
1517  */
1518 private void
1519 set_color_procs(gx_device * pdev,
1520 	dev_t_proc_encode_color((*encode_color), gx_device),
1521 	dev_t_proc_decode_color((*decode_color), gx_device),
1522 	dev_t_proc_get_color_mapping_procs((*get_color_mapping_procs), gx_device),
1523 	dev_t_proc_get_color_comp_index((*get_color_comp_index), gx_device))
1524 {
1525 #if 0				/* These procs are no longer used */
1526     pdev->procs.map_rgb_color = encode_color;
1527     pdev->procs.map_color_rgb = decode_color;
1528 #endif
1529     pdev->procs.get_color_mapping_procs = get_color_mapping_procs;
1530     pdev->procs.get_color_comp_index = get_color_comp_index;
1531     pdev->procs.encode_color = encode_color;
1532     pdev->procs.decode_color = decode_color;
1533 }
1534 
1535 /*
1536  * This is an utility routine to set up the color procs for the display
1537  * device.  This routine is used when the display device is Gray.
1538  */
1539 private void
1540 set_gray_color_procs(gx_device * pdev,
1541 	dev_t_proc_encode_color((*encode_color), gx_device),
1542 	dev_t_proc_decode_color((*decode_color), gx_device))
1543 {
1544     set_color_procs(pdev, encode_color, decode_color,
1545 	gx_default_DevGray_get_color_mapping_procs,
1546 	gx_default_DevGray_get_color_comp_index);
1547 }
1548 
1549 /*
1550  * This is an utility routine to set up the color procs for the display
1551  * device.  This routine is used when the display device is RGB.
1552  */
1553 private void
1554 set_rgb_color_procs(gx_device * pdev,
1555 	dev_t_proc_encode_color((*encode_color), gx_device),
1556 	dev_t_proc_decode_color((*decode_color), gx_device))
1557 {
1558     set_color_procs(pdev, encode_color, decode_color,
1559 	gx_default_DevRGB_get_color_mapping_procs,
1560 	gx_default_DevRGB_get_color_comp_index);
1561 }
1562 
1563 /*
1564  * This is an utility routine to set up the color procs for the display
1565  * device.  This routine is used when the display device is RGBK.
1566  */
1567 private void
1568 set_rgbk_color_procs(gx_device * pdev,
1569 	dev_t_proc_encode_color((*encode_color), gx_device),
1570 	dev_t_proc_decode_color((*decode_color), gx_device))
1571 {
1572     set_color_procs(pdev, encode_color, decode_color,
1573 	gx_default_DevRGBK_get_color_mapping_procs,
1574 	gx_default_DevRGBK_get_color_comp_index);
1575 }
1576 
1577 /*
1578  * This is an utility routine to set up the color procs for the display
1579  * device.  This routine is used when the display device is CMYK.
1580  */
1581 private void
1582 set_cmyk_color_procs(gx_device * pdev,
1583 	dev_t_proc_encode_color((*encode_color), gx_device),
1584 	dev_t_proc_decode_color((*decode_color), gx_device))
1585 {
1586     set_color_procs(pdev, encode_color, decode_color,
1587 	gx_default_DevCMYK_get_color_mapping_procs,
1588 	gx_default_DevCMYK_get_color_comp_index);
1589 }
1590 
1591 /* Set the color_info and mapping functions for this instance of the device */
1592 private int
display_set_color_format(gx_device_display * ddev,int nFormat)1593 display_set_color_format(gx_device_display *ddev, int nFormat)
1594 {
1595     gx_device * pdev = (gx_device *) ddev;
1596     gx_device_color_info dci = ddev->color_info;
1597     int bpc;	/* bits per component */
1598     int bpp;	/* bits per pixel */
1599     int maxvalue;
1600     int align;
1601 
1602     switch (nFormat & DISPLAY_DEPTH_MASK) {
1603 	case DISPLAY_DEPTH_1:
1604 	    bpc = 1;
1605 	    break;
1606 	case DISPLAY_DEPTH_2:
1607 	    bpc = 2;
1608 	    break;
1609 	case DISPLAY_DEPTH_4:
1610 	    bpc = 4;
1611 	    break;
1612 	case DISPLAY_DEPTH_8:
1613 	    bpc = 8;
1614 	    break;
1615 	case DISPLAY_DEPTH_12:
1616 	    bpc = 12;
1617 	    break;
1618 	case DISPLAY_DEPTH_16:
1619 	    bpc = 16;
1620 	    break;
1621 	default:
1622 	    return_error(gs_error_rangecheck);
1623     }
1624     maxvalue = (1 << bpc) - 1;
1625     ddev->devn_params.bitspercomponent = bpc;
1626 
1627     switch (ddev->nFormat & DISPLAY_ROW_ALIGN_MASK) {
1628 	case DISPLAY_ROW_ALIGN_DEFAULT:
1629 	    align = ARCH_ALIGN_PTR_MOD;
1630 	    break;
1631 	case DISPLAY_ROW_ALIGN_4:
1632 	    align = 4;
1633 	    break;
1634 	case DISPLAY_ROW_ALIGN_8:
1635 	    align = 8;
1636 	    break;
1637 	case DISPLAY_ROW_ALIGN_16:
1638 	    align = 16;
1639 	    break;
1640 	case DISPLAY_ROW_ALIGN_32:
1641 	    align = 32;
1642 	    break;
1643 	case DISPLAY_ROW_ALIGN_64:
1644 	    align = 64;
1645 	    break;
1646 	default:
1647 	    align = 0;	/* not permitted */
1648     }
1649     if (align < ARCH_ALIGN_PTR_MOD)
1650 	return_error(gs_error_rangecheck);
1651 
1652     switch (ddev->nFormat & DISPLAY_ALPHA_MASK) {
1653 	case DISPLAY_ALPHA_FIRST:
1654 	case DISPLAY_ALPHA_LAST:
1655 	    /* Not implemented and unlikely to ever be implemented
1656  	     * because they would interact with linear_and_separable
1657 	     */
1658 	    return_error(gs_error_rangecheck);
1659     }
1660 
1661     switch (nFormat & DISPLAY_COLORS_MASK) {
1662 	case DISPLAY_COLORS_NATIVE:
1663 	    switch (nFormat & DISPLAY_DEPTH_MASK) {
1664 		case DISPLAY_DEPTH_1:
1665 		    /* 1bit/pixel, black is 1, white is 0 */
1666  	    	    set_color_info(&dci, DISPLAY_MODEL_GRAY, 1, 1, 1, 0);
1667                     dci.separable_and_linear = GX_CINFO_SEP_LIN_NONE;
1668 		    set_gray_color_procs(pdev, gx_b_w_gray_encode,
1669 		    				gx_default_b_w_map_color_rgb);
1670 		    break;
1671 		case DISPLAY_DEPTH_4:
1672 		    /* 4bit/pixel VGA color */
1673  	    	    set_color_info(&dci, DISPLAY_MODEL_RGB, 3, 4, 3, 2);
1674                     dci.separable_and_linear = GX_CINFO_SEP_LIN_NONE;
1675 		    set_rgb_color_procs(pdev, display_map_rgb_color_device4,
1676 		    				display_map_color_rgb_device4);
1677 		    break;
1678 		case DISPLAY_DEPTH_8:
1679 		    /* 8bit/pixel 96 color palette */
1680  	    	    set_color_info(&dci, DISPLAY_MODEL_RGBK, 4, 8, 31, 3);
1681                     dci.separable_and_linear = GX_CINFO_SEP_LIN_NONE;
1682 		    set_rgbk_color_procs(pdev, display_encode_color_device8,
1683 		    				display_decode_color_device8);
1684 		    break;
1685 		case DISPLAY_DEPTH_16:
1686 		    /* Windows 16-bit display */
1687 		    /* Is maxgray = maxcolor = 63 correct? */
1688 	            if ((ddev->nFormat & DISPLAY_555_MASK)
1689 			== DISPLAY_NATIVE_555)
1690  	    	        set_color_info(&dci, DISPLAY_MODEL_RGB, 3, 16, 31, 31);
1691 		    else
1692  	    	        set_color_info(&dci, DISPLAY_MODEL_RGB, 3, 16, 63, 63);
1693 		    set_rgb_color_procs(pdev, display_map_rgb_color_device16,
1694 		    				display_map_color_rgb_device16);
1695 		    break;
1696 		default:
1697 		    return_error(gs_error_rangecheck);
1698 	    }
1699 	    dci.gray_index = GX_CINFO_COMP_NO_INDEX;
1700 	    break;
1701 	case DISPLAY_COLORS_GRAY:
1702 	    set_color_info(&dci, DISPLAY_MODEL_GRAY, 1, bpc, maxvalue, 0);
1703 	    if (bpc == 1)
1704 	    	set_gray_color_procs(pdev, gx_default_gray_encode,
1705 						gx_default_w_b_map_color_rgb);
1706 	    else
1707 	    	set_gray_color_procs(pdev, gx_default_gray_encode,
1708 						gx_default_gray_map_color_rgb);
1709 	    break;
1710 	case DISPLAY_COLORS_RGB:
1711 	    if ((nFormat & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE)
1712 		bpp = bpc * 3;
1713 	    else
1714 		bpp = bpc * 4;
1715 	    set_color_info(&dci, DISPLAY_MODEL_RGB, 3, bpp, maxvalue, maxvalue);
1716 	    if (((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) &&
1717 	 	((nFormat & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE)) {
1718 		if ((nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN)
1719 	    	    set_rgb_color_procs(pdev, gx_default_rgb_map_rgb_color,
1720 		    				gx_default_rgb_map_color_rgb);
1721 		else
1722 	    	    set_rgb_color_procs(pdev, display_map_rgb_color_bgr24,
1723 		    				display_map_color_rgb_bgr24);
1724 	    }
1725 	    else {
1726 		/* slower flexible functions for alpha/unused component */
1727 	    	set_rgb_color_procs(pdev, display_map_rgb_color_rgb,
1728 						display_map_color_rgb_rgb);
1729 	    }
1730 	    break;
1731 	case DISPLAY_COLORS_CMYK:
1732 	    bpp = bpc * 4;
1733 	    set_color_info(&dci, DISPLAY_MODEL_CMYK, 4, bpp, maxvalue, maxvalue);
1734 	    if ((nFormat & DISPLAY_ALPHA_MASK) != DISPLAY_ALPHA_NONE)
1735 		return_error(gs_error_rangecheck);
1736 	    if ((nFormat & DISPLAY_ENDIAN_MASK) != DISPLAY_BIGENDIAN)
1737 		return_error(gs_error_rangecheck);
1738 
1739 	    if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_1)
1740 	    	set_cmyk_color_procs(pdev, cmyk_1bit_map_cmyk_color,
1741 						cmyk_1bit_map_color_cmyk);
1742 	    else if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8)
1743 	    	set_cmyk_color_procs(pdev, cmyk_8bit_map_cmyk_color,
1744 						cmyk_8bit_map_color_cmyk);
1745 	    else
1746 		return_error(gs_error_rangecheck);
1747 	    break;
1748 	case DISPLAY_COLORS_SEPARATION:
1749 	    if ((nFormat & DISPLAY_ENDIAN_MASK) != DISPLAY_BIGENDIAN)
1750 		return_error(gs_error_rangecheck);
1751 	    bpp = arch_sizeof_color_index * 8;
1752 	    set_color_info(&dci, DISPLAY_MODEL_SEP, bpp/bpc, bpp,
1753 		maxvalue, maxvalue);
1754 	    if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) {
1755 		ddev->devn_params.bitspercomponent = bpc;
1756 		set_color_procs(pdev,
1757 		    display_separation_encode_color,
1758 		    display_separation_decode_color,
1759 		    display_separation_get_color_mapping_procs,
1760 		    display_separation_get_color_comp_index);
1761 	    }
1762 	    else
1763 		return_error(gs_error_rangecheck);
1764 	    break;
1765 	default:
1766 	    return_error(gs_error_rangecheck);
1767     }
1768 
1769     /* restore old anti_alias info */
1770     dci.anti_alias = ddev->color_info.anti_alias;
1771     ddev->color_info = dci;
1772     check_device_separable(pdev);
1773     switch (nFormat & DISPLAY_COLORS_MASK) {
1774 	case DISPLAY_COLORS_NATIVE:
1775 	    ddev->color_info.gray_index = GX_CINFO_COMP_NO_INDEX;
1776 	    if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_1)
1777 	        ddev->color_info.gray_index = 0;
1778 	    else if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8)
1779 	        ddev->color_info.gray_index = 3;
1780 	    break;
1781 	case DISPLAY_COLORS_RGB:
1782 	    ddev->color_info.gray_index = GX_CINFO_COMP_NO_INDEX;
1783 	    break;
1784 	case DISPLAY_COLORS_GRAY:
1785 	    ddev->color_info.gray_index = 0;
1786 	    break;
1787 	case DISPLAY_COLORS_CMYK:
1788 	    ddev->color_info.gray_index = 3;
1789 	    break;
1790 	case DISPLAY_COLORS_SEPARATION:
1791 	    ddev->color_info.gray_index = GX_CINFO_COMP_NO_INDEX;
1792 	    break;
1793     }
1794     ddev->nFormat = nFormat;
1795 
1796     return 0;
1797 }
1798 
1799 /* ------ Begin Test Code ------ */
1800 
1801 /*********************************************************************
1802 typedef struct test_mode_s test_mode;
1803 struct test_mode_s {
1804     char *name;
1805     unsigned int format;
1806 };
1807 
1808 test_mode test_modes[] = {
1809     {"1bit/pixel native, black is 1, Windows",
1810      DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_1 |
1811      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST},
1812     {"4bit/pixel native, Windows VGA 16 color palette",
1813      DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_4 |
1814      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST},
1815     {"8bit/pixel native, Windows SVGA 96 color palette",
1816      DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
1817      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST},
1818     {"16bit/pixel native, Windows BGR555",
1819      DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_16 |
1820      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST | DISPLAY_NATIVE_555},
1821     {"16bit/pixel native, Windows BGR565",
1822      DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_16 |
1823      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST | DISPLAY_NATIVE_565},
1824     {"1bit/pixel gray, black is 0, topfirst",
1825      DISPLAY_COLORS_GRAY | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_1 |
1826      DISPLAY_BIGENDIAN | DISPLAY_TOPFIRST},
1827     {"4bit/pixel gray, bottom first",
1828      DISPLAY_COLORS_GRAY | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_4 |
1829      DISPLAY_BIGENDIAN | DISPLAY_BOTTOMFIRST},
1830     {"8bit/pixel gray, bottom first",
1831      DISPLAY_COLORS_GRAY | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
1832      DISPLAY_BIGENDIAN | DISPLAY_BOTTOMFIRST},
1833     {"24bit/pixel color, bottom first, Windows BGR24",
1834      DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
1835      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST},
1836     {"24bit/pixel color, bottom first, RGB24",
1837      DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
1838      DISPLAY_BIGENDIAN | DISPLAY_BOTTOMFIRST},
1839     {"24bit/pixel color, top first, GdkRgb RGB24",
1840      DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
1841      DISPLAY_BIGENDIAN | DISPLAY_TOPFIRST},
1842     {"32bit/pixel color, top first, Macintosh xRGB",
1843      DISPLAY_COLORS_RGB | DISPLAY_UNUSED_FIRST | DISPLAY_DEPTH_8 |
1844      DISPLAY_BIGENDIAN | DISPLAY_TOPFIRST},
1845     {"32bit/pixel color, bottom first, xBGR",
1846      DISPLAY_COLORS_RGB | DISPLAY_UNUSED_FIRST | DISPLAY_DEPTH_8 |
1847      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST},
1848     {"32bit/pixel color, bottom first, Windows BGRx",
1849      DISPLAY_COLORS_RGB | DISPLAY_UNUSED_LAST | DISPLAY_DEPTH_8 |
1850      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST},
1851     {"32bit/pixel color, bottom first, RGBx",
1852      DISPLAY_COLORS_RGB | DISPLAY_UNUSED_LAST | DISPLAY_DEPTH_8 |
1853      DISPLAY_BIGENDIAN | DISPLAY_BOTTOMFIRST},
1854     {"32bit/pixel CMYK, bottom first",
1855      DISPLAY_COLORS_CMYK | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
1856      DISPLAY_BIGENDIAN | DISPLAY_BOTTOMFIRST},
1857     {"64bit/pixel separations, bottom first",
1858      DISPLAY_COLORS_SEPARATIONS | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
1859      DISPLAY_BIGENDIAN | DISPLAY_BOTTOMFIRST},
1860     {"4bit/pixel CMYK, bottom first",
1861      DISPLAY_COLORS_CMYK | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_1 |
1862      DISPLAY_BIGENDIAN | DISPLAY_BOTTOMFIRST},
1863     {"1bit/pixel native, black is 1, 8 byte alignment",
1864      DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_1 |
1865      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST | DISPLAY_ROW_ALIGN_8},
1866     {"24bit/pixel color, bottom first, BGR24, 64 byte alignment",
1867      DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
1868      DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST | DISPLAY_ROW_ALIGN_64}
1869 };
1870 
1871 void
1872 test(int index)
1873 {
1874     char buf[1024];
1875     sprintf(buf, "gs -dDisplayFormat=16#%x examples/colorcir.ps -c quit", test_modes[index].format);
1876     system(buf);
1877 }
1878 
1879 int main(int argc, char *argv[])
1880 {
1881     int i;
1882     int dotest = 0;
1883     if (argc >=2) {
1884 	if (strcmp(argv[1], "-t") == 0)
1885 	    dotest = 1;
1886 	else {
1887 	    fprintf(stdout, "To show modes: disp\nTo run test: disp -t\n");
1888 	    return 1;
1889 	}
1890     }
1891     for (i=0; i < sizeof(test_modes)/sizeof(test_mode); i++) {
1892 	fprintf(stdout, "16#%x or %d: %s\n", test_modes[i].format,
1893 		test_modes[i].format, test_modes[i].name);
1894 	if (dotest)
1895 	    test(i);
1896     }
1897     return 0;
1898 }
1899 *********************************************************************/
1900 
1901 /* ------ End Test Code ------ */
1902