1 /* Copyright (C) 1989, 1995, 1996, 1998, 1999, 2000, 2001 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gdevmswn.c,v 1.4.2.2.2.1 2003/01/17 00:49:01 giles Exp $ */
20 /*
21 * Microsoft Windows 3.n driver for Ghostscript.
22 *
23 * Original version by Russell Lang and Maurice Castro with help from
24 * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
25 * created from gdevbgi.c and gnuplot/term/win.trm 5th June 1992.
26 * Extensively modified by L. Peter Deutsch, Aladdin Enterprises.
27 */
28 #include "gdevmswn.h"
29 #include "gp.h"
30 #include "gpcheck.h"
31 #include "gsparam.h"
32 #include "gdevpccm.h"
33 #include "gsdll.h"
34
35 /* Forward references */
36 private int win_set_bits_per_pixel(P2(gx_device_win *, int));
37
38 #define TIMER_ID 1
39
40 /* Open the win driver */
41 int
win_open(gx_device * dev)42 win_open(gx_device * dev)
43 {
44 HDC hdc;
45 int code;
46
47 if (dev->width == INITIAL_WIDTH)
48 dev->width = (int)(8.5 * dev->x_pixels_per_inch);
49 if (dev->height == INITIAL_HEIGHT)
50 dev->height = (int)(11.0 * dev->y_pixels_per_inch);
51
52 if (wdev->BitsPerPixel == 0) {
53 int depth;
54
55 /* Set parameters that were unknown before opening device */
56 /* Find out if the device supports color */
57 /* We recognize 1, 4, 8, 16, 24 bit/pixel devices */
58 hdc = GetDC(NULL); /* get hdc for desktop */
59 depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
60 if (depth > 16) {
61 wdev->BitsPerPixel = 24;
62 } else if (depth > 8) {
63 wdev->BitsPerPixel = 16;
64 } else if (depth >= 8) {
65 wdev->BitsPerPixel = 8;
66 } else if (depth >= 4) {
67 wdev->BitsPerPixel = 4;
68 } else {
69 wdev->BitsPerPixel = 1;
70 }
71 ReleaseDC(NULL, hdc);
72 wdev->mapped_color_flags = 0;
73 }
74 if ((code = win_set_bits_per_pixel(wdev, wdev->BitsPerPixel)) < 0)
75 return code;
76
77 if (wdev->nColors > 0) {
78 /* create palette for display */
79 if ((wdev->limgpalette = win_makepalette(wdev))
80 == (LPLOGPALETTE) NULL)
81 return win_nomemory();
82 wdev->himgpalette = CreatePalette(wdev->limgpalette);
83 }
84 return 0;
85 }
86
87 /* Make the output appear on the screen. */
88 int
win_sync_output(gx_device * dev)89 win_sync_output(gx_device * dev)
90 {
91 if (pgsdll_callback)
92 (*pgsdll_callback) (GSDLL_SYNC, (unsigned char *)wdev, 0);
93 return (0);
94 }
95
96 /* Make the window visible, and display the output. */
97 int
win_output_page(gx_device * dev,int copies,int flush)98 win_output_page(gx_device * dev, int copies, int flush)
99 {
100 if (pgsdll_callback)
101 (*pgsdll_callback) (GSDLL_PAGE, (unsigned char *)wdev, 0);
102 return gx_finish_output_page(dev, copies, flush);;
103 }
104
105 /* Close the win driver */
106 int
win_close(gx_device * dev)107 win_close(gx_device * dev)
108 {
109 /* Free resources */
110 if (wdev->nColors > 0) {
111 gs_free(wdev->mapped_color_flags, 4096, 1, "win_set_bits_per_pixel");
112 DeleteObject(wdev->himgpalette);
113 gs_free((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,gx_color_value r,gx_color_value g,gx_color_value b)122 win_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
123 gx_color_value b)
124 {
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 if ((r == g) && (g == b) && (r >= gx_max_color_value / 3 * 2 - 1)
221 && (r < gx_max_color_value / 4 * 3))
222 return ((gx_color_index) 8); /* light gray */
223 return pc_4bit_map_rgb_color(dev, r, g, b);
224 }
225 return (gx_default_map_rgb_color(dev, r, g, b));
226 }
227
228 /* Map a color code to r-g-b. */
229 int
win_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])230 win_map_color_rgb(gx_device * dev, gx_color_index color,
231 gx_color_value prgb[3])
232 {
233 gx_color_value one;
234 ushort value;
235
236 switch (wdev->BitsPerPixel) {
237 case 24:
238 one = (gx_color_value) (gx_max_color_value / 255);
239 prgb[0] = ((color) & 255) * one;
240 prgb[1] = ((color >> 8) & 255) * one;
241 prgb[2] = ((color >> 16) & 255) * one;
242 break;
243 case 16:
244 value = (color >> 11) & 0x1f;
245 prgb[0] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
246 value = (color >> 5) & 0x3f;
247 prgb[1] = ((value << 10) + (value << 4) + (value >> 2)) >> (16 - gx_color_value_bits);
248 value = (color) & 0x1f;
249 prgb[2] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
250 break;
251 case 15:
252 value = (color >> 10) & 0x1f;
253 prgb[0] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
254 value = (color >> 5) & 0x1f;
255 prgb[1] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
256 value = (color) & 0x1f;
257 prgb[2] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits);
258 break;
259 case 8:
260 if (!dev->is_open)
261 return -1;
262 one = (gx_color_value) (gx_max_color_value / 255);
263 prgb[0] = wdev->limgpalette->palPalEntry[(int)color].peRed * one;
264 prgb[1] = wdev->limgpalette->palPalEntry[(int)color].peGreen * one;
265 prgb[2] = wdev->limgpalette->palPalEntry[(int)color].peBlue * one;
266 break;
267 case 4:
268 if (color == 8) /* VGA light gray */
269 prgb[0] = prgb[1] = prgb[2] = (gx_max_color_value / 4 * 3);
270 else
271 pc_4bit_map_color_rgb(dev, color, prgb);
272 break;
273 default:
274 prgb[0] = prgb[1] = prgb[2] =
275 (int)color ? gx_max_color_value : 0;
276 }
277 return 0;
278 }
279
280 /* Get Win parameters */
281 int
win_get_params(gx_device * dev,gs_param_list * plist)282 win_get_params(gx_device * dev, gs_param_list * plist)
283 {
284 int code = gx_default_get_params(dev, plist);
285
286 return code;
287 }
288
289 /* Put parameters. */
290 /* Set window parameters -- size and resolution. */
291 /* We implement this ourselves so that we can do it without */
292 /* closing and opening the device. */
293 int
win_put_params(gx_device * dev,gs_param_list * plist)294 win_put_params(gx_device * dev, gs_param_list * plist)
295 {
296 int ecode = 0, code;
297 bool is_open = dev->is_open;
298 int width = dev->width;
299 int height = dev->height;
300 int old_bpp = dev->color_info.depth;
301 int bpp = old_bpp;
302 byte *old_flags = wdev->mapped_color_flags;
303
304 /* Handle extra parameters */
305
306 switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
307 case 0:
308 if (dev->is_open && bpp != old_bpp)
309 ecode = gs_error_rangecheck;
310 else { /* Don't release existing mapped_color_flags. */
311 if (bpp != 8)
312 wdev->mapped_color_flags = 0;
313 code = win_set_bits_per_pixel(wdev, bpp);
314 if (code < 0)
315 ecode = code;
316 else
317 break;
318 }
319 goto bppe;
320 default:
321 ecode = code;
322 bppe:param_signal_error(plist, "BitsPerPixel", ecode);
323 case 1:
324 break;
325 }
326
327 if (ecode >= 0) { /* Prevent gx_default_put_params from closing the device. */
328 dev->is_open = false;
329 ecode = gx_default_put_params(dev, plist);
330 dev->is_open = is_open;
331 }
332 if (ecode < 0) { /* If we allocated mapped_color_flags, release it. */
333 if (wdev->mapped_color_flags != 0 && old_flags == 0)
334 gs_free(wdev->mapped_color_flags, 4096, 1,
335 "win_put_params");
336 wdev->mapped_color_flags = old_flags;
337 if (bpp != old_bpp)
338 win_set_bits_per_pixel(wdev, old_bpp);
339 return ecode;
340 }
341 if (wdev->mapped_color_flags == 0 && old_flags != 0) { /* Release old mapped_color_flags. */
342 gs_free(old_flags, 4096, 1, "win_put_params");
343 }
344 /* Hand off the change to the implementation. */
345 if (is_open && (bpp != old_bpp ||
346 dev->width != width || dev->height != height)
347 ) {
348 int ccode;
349
350 (*wdev->free_bitmap) (wdev);
351 ccode = (*wdev->alloc_bitmap) (wdev, (gx_device *) wdev);
352 if (ccode < 0) { /* Bad news! Some of the other device parameters */
353 /* may have changed. We don't handle this. */
354 /* This is ****** WRONG ******. */
355 dev->width = width;
356 dev->height = height;
357 win_set_bits_per_pixel(wdev, old_bpp);
358 (*wdev->alloc_bitmap) (wdev, dev);
359 return ccode;
360 }
361 }
362 return 0;
363 }
364
365 /* ------ Internal routines ------ */
366
367 #undef wdev
368
369
370
371 /* out of memory error message box */
372 int
win_nomemory(void)373 win_nomemory(void)
374 {
375 MessageBox((HWND) NULL, (LPSTR) "Not enough memory", (LPSTR) szAppName, MB_ICONSTOP);
376 return gs_error_limitcheck;
377 }
378
379
380 LPLOGPALETTE
win_makepalette(gx_device_win * wdev)381 win_makepalette(gx_device_win * wdev)
382 {
383 int i, val;
384 LPLOGPALETTE logpalette;
385
386 logpalette = (LPLOGPALETTE) gs_malloc(1, sizeof(LOGPALETTE) +
387 (1 << (wdev->color_info.depth)) * sizeof(PALETTEENTRY),
388 "win_makepalette");
389 if (logpalette == (LPLOGPALETTE) NULL)
390 return (0);
391 logpalette->palVersion = 0x300;
392 logpalette->palNumEntries = wdev->nColors;
393 for (i = 0; i < wdev->nColors; i++) {
394 logpalette->palPalEntry[i].peFlags = 0;
395 switch (wdev->nColors) {
396 case 64:
397 /* colors are rrggbb */
398 logpalette->palPalEntry[i].peRed = ((i & 0x30) >> 4) * 85;
399 logpalette->palPalEntry[i].peGreen = ((i & 0xC) >> 2) * 85;
400 logpalette->palPalEntry[i].peBlue = (i & 3) * 85;
401 break;
402 case 16:
403 /* colors are irgb */
404 val = (i & 8 ? 255 : 128);
405 logpalette->palPalEntry[i].peRed = i & 4 ? val : 0;
406 logpalette->palPalEntry[i].peGreen = i & 2 ? val : 0;
407 logpalette->palPalEntry[i].peBlue = i & 1 ? val : 0;
408 if (i == 8) { /* light gray */
409 logpalette->palPalEntry[i].peRed =
410 logpalette->palPalEntry[i].peGreen =
411 logpalette->palPalEntry[i].peBlue = 192;
412 }
413 break;
414 case 2:
415 logpalette->palPalEntry[i].peRed =
416 logpalette->palPalEntry[i].peGreen =
417 logpalette->palPalEntry[i].peBlue = (i ? 255 : 0);
418 break;
419 }
420 }
421 return (logpalette);
422 }
423
424
425 private int
win_set_bits_per_pixel(gx_device_win * wdev,int bpp)426 win_set_bits_per_pixel(gx_device_win * wdev, int bpp)
427 {
428 static const gx_device_color_info win_24bit_color = dci_color(24, 255, 255);
429 static const gx_device_color_info win_16bit_color = dci_color(16, 255, 255);
430 static const gx_device_color_info win_8bit_color = dci_color(8, 31, 4);
431 static const gx_device_color_info win_ega_color = dci_pc_4bit;
432 static const gx_device_color_info win_vga_color = dci_pc_4bit;
433 static const gx_device_color_info win_mono_color = dci_black_and_white;
434 /* remember old anti_alias info */
435 gx_device_anti_alias_info anti_alias = wdev->color_info.anti_alias;
436 HDC hdc;
437
438 switch (bpp) {
439 case 24:
440 wdev->color_info = win_24bit_color;
441 wdev->nColors = -1;
442 break;
443 case 16:
444 case 15:
445 wdev->color_info = win_16bit_color;
446 wdev->nColors = -1;
447 break;
448 case 8:
449 /* use 64 static colors and 166 dynamic colors from 8 planes */
450 wdev->color_info = win_8bit_color;
451 wdev->nColors = 64;
452 break;
453 case 4:
454 hdc = GetDC(NULL);
455 if (GetDeviceCaps(hdc, VERTRES) <= 350)
456 wdev->color_info = win_ega_color;
457 else
458 wdev->color_info = win_vga_color;
459 ReleaseDC(NULL, hdc);
460 wdev->nColors = 16;
461 break;
462 case 1:
463 wdev->color_info = win_mono_color;
464 wdev->nColors = 2;
465 break;
466 default:
467 return (gs_error_rangecheck);
468 }
469 wdev->BitsPerPixel = bpp;
470
471 /* If necessary, allocate and clear the mapped color flags. */
472 if (bpp == 8) {
473 if (wdev->mapped_color_flags == 0) {
474 wdev->mapped_color_flags = gs_malloc(4096, 1, "win_set_bits_per_pixel");
475 if (wdev->mapped_color_flags == 0)
476 return_error(gs_error_VMerror);
477 }
478 memset(wdev->mapped_color_flags, 0, 4096);
479 } else {
480 gs_free(wdev->mapped_color_flags, 4096, 1, "win_set_bits_per_pixel");
481 wdev->mapped_color_flags = 0;
482 }
483 /* restore old anti_alias info */
484 wdev->color_info.anti_alias = anti_alias;
485 return 0;
486 }
487