1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 /*
17  * Microsoft Windows 3.n driver for Ghostscript.
18  *
19  * Original version by Russell Lang and Maurice Castro with help from
20  * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
21  * created from gdevbgi.c and gnuplot/term/win.trm 5th June 1992.
22  * Extensively modified by L. Peter Deutsch, Aladdin Enterprises.
23  */
24 #include "gdevmswn.h"
25 #include "gp.h"
26 #include "gpcheck.h"
27 #include "gsparam.h"
28 #include "gdevpccm.h"
29 #include "gsdll.h"
30 
31 /* Forward references */
32 static int win_set_bits_per_pixel(gx_device_win *, int);
33 
34 #define TIMER_ID 1
35 
36 /* Open the win driver */
37 int
win_open(gx_device * dev)38 win_open(gx_device * dev)
39 {
40     HDC hdc;
41     int code;
42 
43     if (dev->width == INITIAL_WIDTH)
44         dev->width = (int)(8.5 * dev->x_pixels_per_inch);
45     if (dev->height == INITIAL_HEIGHT)
46         dev->height = (int)(11.0 * dev->y_pixels_per_inch);
47 
48     if (wdev->BitsPerPixel == 0) {
49         int depth;
50 
51         /* Set parameters that were unknown before opening device */
52         /* Find out if the device supports color */
53         /* We recognize 1, 4, 8, 16, 24 bit/pixel devices */
54         hdc = GetDC(NULL);	/* get hdc for desktop */
55         depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
56         if (depth > 16) {
57             wdev->BitsPerPixel = 24;
58         } else if (depth > 8) {
59             wdev->BitsPerPixel = 16;
60         } else if (depth >= 8) {
61             wdev->BitsPerPixel = 8;
62         } else if (depth >= 4) {
63             wdev->BitsPerPixel = 4;
64         } else {
65             wdev->BitsPerPixel = 1;
66         }
67         ReleaseDC(NULL, hdc);
68         wdev->mapped_color_flags = 0;
69     }
70     if ((code = win_set_bits_per_pixel(wdev, wdev->BitsPerPixel)) < 0)
71         return code;
72 
73     if (wdev->nColors > 0) {
74         /* create palette for display */
75         if ((wdev->limgpalette = win_makepalette(wdev))
76             == (LPLOGPALETTE) NULL)
77             return win_nomemory();
78         wdev->himgpalette = CreatePalette(wdev->limgpalette);
79     }
80     return 0;
81 }
82 
83 /* Make the output appear on the screen. */
84 int
win_sync_output(gx_device * dev)85 win_sync_output(gx_device * dev)
86 {
87     if (pgsdll_callback)
88         (*pgsdll_callback) (GSDLL_SYNC, (unsigned char *)wdev, 0);
89     return (0);
90 }
91 
92 /* Make the window visible, and display the output. */
93 int
win_output_page(gx_device * dev,int copies,int flush)94 win_output_page(gx_device * dev, int copies, int flush)
95 {
96     if (pgsdll_callback)
97         (*pgsdll_callback) (GSDLL_PAGE, (unsigned char *)wdev, 0);
98     return gx_finish_output_page(dev, copies, flush);;
99 }
100 
101 /* Close the win driver */
102 int
win_close(gx_device * dev)103 win_close(gx_device * dev)
104 {
105     /* Free resources */
106     if (wdev->nColors > 0) {
107         gs_free(dev->memory,
108                 wdev->mapped_color_flags, 4096, 1, "win_set_bits_per_pixel");
109         DeleteObject(wdev->himgpalette);
110         gs_free(dev->memory,
111                 (char *)(wdev->limgpalette), 1, sizeof(LOGPALETTE) +
112                 (1 << (wdev->color_info.depth)) * sizeof(PALETTEENTRY),
113                 "win_close");
114     }
115     return (0);
116 }
117 
118 /* Map a r-g-b color to the colors available under Windows */
119 gx_color_index
win_map_rgb_color(gx_device * dev,const gx_color_value cv[])120 win_map_rgb_color(gx_device * dev, const gx_color_value cv[])
121 {
122     gx_color_value r = cv[0];
123     gx_color_value g = cv[1];
124     gx_color_value b = cv[2];
125     switch (wdev->BitsPerPixel) {
126         case 24:
127             return (((unsigned long)b >> (gx_color_value_bits - 8)) << 16) +
128                 (((unsigned long)g >> (gx_color_value_bits - 8)) << 8) +
129                 (((unsigned long)r >> (gx_color_value_bits - 8)));
130         case 16:{
131                 gx_color_index color = ((r >> (gx_color_value_bits - 5)) << 11) +
132                                        ((g >> (gx_color_value_bits - 6)) << 5) +
133                                        (b >> (gx_color_value_bits - 5));
134 #if arch_is_big_endian
135                 ushort color16 = (ushort)color;
136 #else
137                 ushort color16 = (ushort)((color << 8) | (color >> 8));
138 #endif
139                 return color16;
140             }
141         case 15:{
142                 gx_color_index color = ((r >> (gx_color_value_bits - 5)) << 10) +
143                                        ((g >> (gx_color_value_bits - 5)) << 5) +
144                                        (b >> (gx_color_value_bits - 5));
145 #if arch_is_big_endian
146                 ushort color15 = (ushort)color;
147 #else
148                 ushort color15 = (ushort)((color << 8) | (color >> 8));
149 #endif
150                 return color15;
151             }
152         case 8:{
153                 int i;
154                 LPLOGPALETTE lpal = wdev->limgpalette;
155                 PALETTEENTRY *pep;
156                 byte cr, cg, cb;
157                 int mc_index;
158                 byte mc_mask;
159 
160                 /* Check for a color in the palette of 64. */
161                 {
162                     static const byte pal64[32] =
163                     {
164                         1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165                         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
166                         1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
167                         1
168                     };
169 
170                     if (pal64[r >> (gx_color_value_bits - 5)] &&
171                         pal64[g >> (gx_color_value_bits - 5)] &&
172                         pal64[b >> (gx_color_value_bits - 5)]
173                         )
174                         return (gx_color_index) (
175                                    ((r >> (gx_color_value_bits - 2)) << 4) +
176                                    ((g >> (gx_color_value_bits - 2)) << 2) +
177                                             (b >> (gx_color_value_bits - 2))
178                             );
179                 }
180 
181                 /* map colors to 0->255 in 32 steps */
182                 cr = win_color_value(r);
183                 cg = win_color_value(g);
184                 cb = win_color_value(b);
185 
186                 /* Search in palette, skipping the first 64. */
187                 mc_index = ((cr >> 3) << 7) + ((cg >> 3) << 2) + (cb >> 6);
188                 mc_mask = 0x80 >> ((cb >> 3) & 7);
189                 if (wdev->mapped_color_flags[mc_index] & mc_mask)
190                     for (i = wdev->nColors, pep = &lpal->palPalEntry[i];
191                          --pep, --i >= 64;
192                         ) {
193                         if (cr == pep->peRed &&
194                             cg == pep->peGreen &&
195                             cb == pep->peBlue
196                             )
197                             return ((gx_color_index) i);	/* found it */
198                     }
199                 /* next try adding it to palette */
200                 i = wdev->nColors;
201                 if (i < 220) {	/* allow 36 for windows and other apps */
202                     LPLOGPALETTE lipal = wdev->limgpalette;
203 
204                     wdev->nColors = i + 1;
205 
206                     DeleteObject(wdev->himgpalette);
207                     lipal->palPalEntry[i].peFlags = 0;
208                     lipal->palPalEntry[i].peRed = cr;
209                     lipal->palPalEntry[i].peGreen = cg;
210                     lipal->palPalEntry[i].peBlue = cb;
211                     lipal->palNumEntries = wdev->nColors;
212                     wdev->himgpalette = CreatePalette(lipal);
213 
214                     wdev->mapped_color_flags[mc_index] |= mc_mask;
215                     return ((gx_color_index) i);	/* return new palette index */
216                 }
217                 return (gx_no_color_index);	/* not found - dither instead */
218             }
219         case 4:
220             return pc_4bit_map_rgb_color(dev, cv);
221     }
222     return (gx_default_map_rgb_color(dev, cv));
223 }
224 
225 /* Map a color code to r-g-b. */
226 int
win_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])227 win_map_color_rgb(gx_device * dev, gx_color_index color,
228                   gx_color_value prgb[3])
229 {
230     gx_color_value one;
231     ushort value;
232 
233     switch (wdev->BitsPerPixel) {
234         case 24:
235             one = (gx_color_value) (gx_max_color_value / 255);
236             prgb[0] = ((color) & 255) * one;
237             prgb[1] = ((color >> 8) & 255) * one;
238             prgb[2] = ((color >> 16) & 255) * one;
239             break;
240         case 16:
241             value = (color >> 11) & 0x1f;
242             prgb[0] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
243             value = (color >> 5) & 0x3f;
244             prgb[1] = ((value << 10) + (value << 4) + (value >> 2)) >> (16 - gx_color_value_bits);
245             value = (color) & 0x1f;
246             prgb[2] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
247             break;
248         case 15:
249             value = (color >> 10) & 0x1f;
250             prgb[0] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
251             value = (color >> 5) & 0x1f;
252             prgb[1] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
253             value = (color) & 0x1f;
254             prgb[2] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
255             break;
256         case 8:
257             if (!dev->is_open)
258                 return -1;
259             one = (gx_color_value) (gx_max_color_value / 255);
260             prgb[0] = wdev->limgpalette->palPalEntry[(int)color].peRed * one;
261             prgb[1] = wdev->limgpalette->palPalEntry[(int)color].peGreen * one;
262             prgb[2] = wdev->limgpalette->palPalEntry[(int)color].peBlue * one;
263             break;
264         case 4:
265             pc_4bit_map_color_rgb(dev, color, prgb);
266             break;
267         default:
268             prgb[0] = prgb[1] = prgb[2] =
269                 (int)color ? gx_max_color_value : 0;
270     }
271     return 0;
272 }
273 
274 /* Get Win parameters */
275 int
win_get_params(gx_device * dev,gs_param_list * plist)276 win_get_params(gx_device * dev, gs_param_list * plist)
277 {
278     int code = gx_default_get_params(dev, plist);
279 
280     return code;
281 }
282 
283 /* Put parameters. */
284 /* Set window parameters -- size and resolution. */
285 /* We implement this ourselves so that we can do it without */
286 /* closing and opening the device. */
287 int
win_put_params(gx_device * dev,gs_param_list * plist)288 win_put_params(gx_device * dev, gs_param_list * plist)
289 {
290     int ecode = 0, code;
291     bool is_open = dev->is_open;
292     int width = dev->width;
293     int height = dev->height;
294     int old_bpp = dev->color_info.depth;
295     int bpp = old_bpp;
296     byte *old_flags = wdev->mapped_color_flags;
297 
298     /* Handle extra parameters */
299 
300     switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
301         case 0:
302             if (dev->is_open && bpp != old_bpp)
303                 ecode = gs_error_rangecheck;
304             else {		/* Don't release existing mapped_color_flags. */
305                 if (bpp != 8)
306                     wdev->mapped_color_flags = 0;
307                 code = win_set_bits_per_pixel(wdev, bpp);
308                 if (code < 0)
309                     ecode = code;
310                 else
311                     break;
312             }
313             goto bppe;
314         default:
315             ecode = code;
316           bppe:param_signal_error(plist, "BitsPerPixel", ecode);
317         case 1:
318             break;
319     }
320 
321     if (ecode >= 0) {		/* Prevent gx_default_put_params from closing the device. */
322         dev->is_open = false;
323         ecode = gx_default_put_params(dev, plist);
324         dev->is_open = is_open;
325     }
326     if (ecode < 0) {		/* If we allocated mapped_color_flags, release it. */
327         if (wdev->mapped_color_flags != 0 && old_flags == 0)
328             gs_free(wdev->memory,
329                     wdev->mapped_color_flags, 4096, 1,
330                     "win_put_params");
331         wdev->mapped_color_flags = old_flags;
332         if (bpp != old_bpp)
333             win_set_bits_per_pixel(wdev, old_bpp);
334         return ecode;
335     }
336     if (wdev->mapped_color_flags == 0 && old_flags != 0) {	/* Release old mapped_color_flags. */
337         gs_free(dev->memory,
338                 old_flags, 4096, 1, "win_put_params");
339     }
340     /* Hand off the change to the implementation. */
341     if (is_open && (bpp != old_bpp ||
342                     dev->width != width || dev->height != height)
343         ) {
344         int ccode;
345 
346         (*wdev->free_bitmap) (wdev);
347         ccode = (*wdev->alloc_bitmap) (wdev, (gx_device *) wdev);
348         if (ccode < 0) {	/* Bad news!  Some of the other device parameters */
349             /* may have changed.  We don't handle this. */
350             /* This is ****** WRONG ******. */
351             dev->width = width;
352             dev->height = height;
353             win_set_bits_per_pixel(wdev, old_bpp);
354             (*wdev->alloc_bitmap) (wdev, dev);
355             return ccode;
356         }
357     }
358     return 0;
359 }
360 
361 /* ------ Internal routines ------ */
362 
363 #undef wdev
364 
365 /* out of memory error message box */
366 int
win_nomemory(void)367 win_nomemory(void)
368 {
369     MessageBox((HWND) NULL, (LPSTR) "Not enough memory", (LPSTR) szAppName, MB_ICONSTOP);
370     return gs_error_limitcheck;
371 }
372 
373 LPLOGPALETTE
win_makepalette(gx_device_win * wdev)374 win_makepalette(gx_device_win * wdev)
375 {
376     int i, val;
377     LPLOGPALETTE logpalette;
378 
379     logpalette = (LPLOGPALETTE) gs_malloc(wdev->memory, 1, sizeof(LOGPALETTE) +
380                      (1 << (wdev->color_info.depth)) * sizeof(PALETTEENTRY),
381                                           "win_makepalette");
382     if (logpalette == (LPLOGPALETTE) NULL)
383         return (0);
384     logpalette->palVersion = 0x300;
385     logpalette->palNumEntries = wdev->nColors;
386     for (i = 0; i < wdev->nColors; i++) {
387         logpalette->palPalEntry[i].peFlags = 0;
388         switch (wdev->nColors) {
389             case 64:
390                 /* colors are rrggbb */
391                 logpalette->palPalEntry[i].peRed = ((i & 0x30) >> 4) * 85;
392                 logpalette->palPalEntry[i].peGreen = ((i & 0xC) >> 2) * 85;
393                 logpalette->palPalEntry[i].peBlue = (i & 3) * 85;
394                 break;
395             case 16:
396                 /* colors are irgb */
397                 val = (i & 8 ? 255 : 128);
398                 logpalette->palPalEntry[i].peRed = i & 4 ? val : 0;
399                 logpalette->palPalEntry[i].peGreen = i & 2 ? val : 0;
400                 logpalette->palPalEntry[i].peBlue = i & 1 ? val : 0;
401                 if (i == 8) {	/* light gray */
402                     logpalette->palPalEntry[i].peRed =
403                         logpalette->palPalEntry[i].peGreen =
404                         logpalette->palPalEntry[i].peBlue = 192;
405                 }
406                 break;
407             case 2:
408                 logpalette->palPalEntry[i].peRed =
409                     logpalette->palPalEntry[i].peGreen =
410                     logpalette->palPalEntry[i].peBlue = (i ? 255 : 0);
411                 break;
412         }
413     }
414     return (logpalette);
415 }
416 
417 static int
win_set_bits_per_pixel(gx_device_win * wdev,int bpp)418 win_set_bits_per_pixel(gx_device_win * wdev, int bpp)
419 {
420     static const gx_device_color_info win_24bit_color = dci_color(24, 255, 255);
421     static const gx_device_color_info win_16bit_color = dci_color(16, 255, 255);
422     static const gx_device_color_info win_8bit_color = dci_color(8, 31, 4);
423     static const gx_device_color_info win_ega_color = dci_pc_4bit;
424     static const gx_device_color_info win_vga_color = dci_pc_4bit;
425     static const gx_device_color_info win_mono_color = dci_black_and_white;
426     /* remember old anti_alias info */
427     gx_device_anti_alias_info anti_alias = wdev->color_info.anti_alias;
428     HDC hdc;
429 
430     switch (bpp) {
431         case 24:
432             wdev->color_info = win_24bit_color;
433             wdev->nColors = -1;
434             break;
435         case 16:
436         case 15:
437             wdev->color_info = win_16bit_color;
438             wdev->nColors = -1;
439             break;
440         case 8:
441             /* use 64 static colors and 166 dynamic colors from 8 planes */
442             wdev->color_info = win_8bit_color;
443             wdev->nColors = 64;
444             break;
445         case 4:
446             hdc = GetDC(NULL);
447             if (GetDeviceCaps(hdc, VERTRES) <= 350)
448                 wdev->color_info = win_ega_color;
449             else
450                 wdev->color_info = win_vga_color;
451             ReleaseDC(NULL, hdc);
452             wdev->nColors = 16;
453             break;
454         case 1:
455             wdev->color_info = win_mono_color;
456             wdev->nColors = 2;
457             break;
458         default:
459             return (gs_error_rangecheck);
460     }
461     wdev->BitsPerPixel = bpp;
462 
463     /* If necessary, allocate and clear the mapped color flags. */
464     if (bpp == 8) {
465         if (wdev->mapped_color_flags == 0) {
466             wdev->mapped_color_flags = gs_malloc(wdev->memory,
467                                                  4096, 1, "win_set_bits_per_pixel");
468             if (wdev->mapped_color_flags == 0)
469                 return_error(gs_error_VMerror);
470         }
471         memset(wdev->mapped_color_flags, 0, 4096);
472     } else {
473         gs_free(wdev->memory,
474                 wdev->mapped_color_flags, 4096, 1, "win_set_bits_per_pixel");
475         wdev->mapped_color_flags = 0;
476     }
477 
478     /* copy encode/decode procedures */
479     wdev->procs.encode_color = wdev->procs.map_rgb_color;
480     wdev->procs.decode_color = wdev->procs.map_color_rgb;
481     if (bpp == 1) {
482         wdev->procs.get_color_mapping_procs =
483             gx_default_DevGray_get_color_mapping_procs;
484         wdev->procs.get_color_comp_index =
485             gx_default_DevGray_get_color_comp_index;
486     }
487     else {
488         wdev->procs.get_color_mapping_procs =
489             gx_default_DevRGB_get_color_mapping_procs;
490         wdev->procs.get_color_comp_index =
491             gx_default_DevRGB_get_color_comp_index;
492     }
493 
494     /* restore old anti_alias info */
495     wdev->color_info.anti_alias = anti_alias;
496     return 0;
497 }
498