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