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