xref: /plan9/sys/src/cmd/gs/src/gdevmswn.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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