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