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