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