xref: /plan9/sys/src/cmd/gs/src/gdevwdib.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 1995, 1996, 1997, 1999 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: gdevwdib.c,v 1.9 2004/09/15 19:41:01 ray Exp $ */
18 /* MS Windows 3.n driver for Ghostscript using a DIB for buffering. */
19 #include "gdevmswn.h"
20 #include "gxdevmem.h"
21 #include "gsdll.h"
22 #include "gsdllwin.h"
23 
24 #ifdef __WIN32__
25 #  define USE_SEGMENTS 0
26 #else
27 #  define USE_SEGMENTS 1
28 #endif
29 
30 /* Make sure we cast to the correct structure type. */
31 typedef struct gx_device_win_dib_s gx_device_win_dib;
32 
33 #undef wdev
34 #define wdev ((gx_device_win_dib *)dev)
35 
36 /* Device procedures */
37 
38 /* See gxdevice.h for the definitions of the procedures. */
39 private dev_proc_open_device(win_dib_open);
40 private dev_proc_get_initial_matrix(win_dib_get_initial_matrix);
41 private dev_proc_close_device(win_dib_close);
42 private dev_proc_fill_rectangle(win_dib_fill_rectangle);
43 private dev_proc_copy_mono(win_dib_copy_mono);
44 private dev_proc_copy_color(win_dib_copy_color);
45 private dev_proc_get_bits(win_dib_get_bits);
46 private dev_proc_put_params(win_dib_put_params);
47 
48 /* Windows-specific procedures */
49 private win_proc_repaint(win_dib_repaint);
50 private win_proc_alloc_bitmap(win_dib_alloc_bitmap);
51 private win_proc_free_bitmap(win_dib_free_bitmap);
52 
53 /* The device descriptor */
54 struct gx_device_win_dib_s {
55     gx_device_common;
56     gx_device_win_common;
57 
58 #if USE_SEGMENTS
59     /* The following help manage the division of the DIB */
60     /* into 64K segments.  Each block of y_block scan lines */
61     /* starting at y_base mod 64K falls in a single segment. */
62     /* Since the raster is a power of 2, y_block is a power of 2. */
63 
64     int y_block;
65     int y_base;
66     int y_mask;			/* y_block - 1 */
67 #endif				/* USE_SEGMENTS */
68 
69     HGLOBAL hmdata;
70 #ifdef __WIN32__
71     HANDLE hmtx;
72 #endif
73     int lock_count;
74     gx_device_memory mdev;
75 };
76 private const gx_device_procs win_dib_procs =
77 {
78     win_dib_open,
79     win_dib_get_initial_matrix,
80     win_sync_output,
81     win_output_page,
82     win_dib_close,
83     win_map_rgb_color,
84     win_map_color_rgb,
85     win_dib_fill_rectangle,
86     NULL,			/* tile_rectangle */
87     win_dib_copy_mono,
88     win_dib_copy_color,
89     NULL,			/* draw_line */
90     win_dib_get_bits /* NULL */ ,	/* get_bits */
91     win_get_params,
92     win_dib_put_params,
93     NULL,			/* map_cmyk_color */
94     win_get_xfont_procs,
95     NULL,			/* get_xfont_device */
96     NULL,			/* map_rgb_alpha_color */
97     gx_page_device_get_page_device
98 };
99 gx_device_win_dib far_data gs_mswindll_device =
100 {
101     std_device_std_body(gx_device_win_dib, &win_dib_procs, "mswindll",
102 			INITIAL_WIDTH, INITIAL_HEIGHT,/* win_open() fills these in later */
103 			INITIAL_RESOLUTION, INITIAL_RESOLUTION	/* win_open() fills these in later */
104     ),
105     {0},			/* std_procs */
106     0,				/* BitsPerPixel */
107     2,				/* nColors */
108     0,				/* mapped_color_flags */
109     win_dib_alloc_bitmap,
110     win_dib_free_bitmap
111 };
112 
113 /* forward declarations */
114 private HGLOBAL win_dib_make_dib(gx_device_win * dev, int orgx, int orgy, int wx, int wy);
115 private int win_dib_lock_device(unsigned char *device, int flag);
116 
117 
118 /* Open the win_dib driver */
119 private int
win_dib_open(gx_device * dev)120 win_dib_open(gx_device * dev)
121 {
122     int code = win_open(dev);
123 
124     if (code < 0)
125 	return code;
126 
127 #ifdef __WIN32__
128     if (!is_win32s)
129 	wdev->hmtx = CreateMutex(NULL, FALSE, NULL);	/* unnamed mutex, initially unowned */
130 #endif
131     if (gdev_mem_device_for_bits(dev->color_info.depth) == 0) {
132 	win_close(dev);
133 	return gs_error_rangecheck;
134     }
135     code = win_dib_alloc_bitmap((gx_device_win *) dev, dev);
136     if (code < 0) {
137 	win_close(dev);
138 	return code;
139     }
140     /* notify caller about new device */
141     if (pgsdll_callback) {
142 	(*pgsdll_callback) (GSDLL_DEVICE, (unsigned char *)dev, 1);
143 	(*pgsdll_callback) (GSDLL_SIZE, (unsigned char *)dev,
144 			(dev->width & 0xffff) +
145 			((ulong) (dev->height & 0xffff) << 16));
146     }
147     return code;
148 }
149 
150 /* Get the initial matrix.  DIBs, unlike most displays, */
151 /* put (0,0) in the lower left corner. */
152 private void
win_dib_get_initial_matrix(gx_device * dev,gs_matrix * pmat)153 win_dib_get_initial_matrix(gx_device * dev, gs_matrix * pmat)
154 {
155     pmat->xx = dev->x_pixels_per_inch / 72.0;
156     pmat->xy = 0.0;
157     pmat->yx = 0.0;
158     pmat->yy = dev->y_pixels_per_inch / 72.0;
159     pmat->tx = 0.0;
160     pmat->ty = 0.0;
161 }
162 
163 /* Close the win_dib driver */
164 private int
win_dib_close(gx_device * dev)165 win_dib_close(gx_device * dev)
166 {
167     int code;
168 
169     /* wait until bitmap is not being used by caller */
170     win_dib_lock_device((unsigned char *)dev, 1);
171     if (pgsdll_callback)
172 	(*pgsdll_callback) (GSDLL_DEVICE, (unsigned char *)dev, 0);
173     win_dib_lock_device((unsigned char *)dev, 0);
174     win_dib_free_bitmap((gx_device_win *) dev);
175 #ifdef __WIN32__
176     if (!is_win32s)
177 	CloseHandle(wdev->hmtx);
178 #endif
179     code = win_close(dev);
180     return code;
181 }
182 
183 #define wmdev ((gx_device *)&wdev->mdev)
184 #define wmproc(proc) (*dev_proc(&wdev->mdev, proc))
185 
186 #if USE_SEGMENTS
187 
188 /* The drawing routines must all be careful not to cross */
189 /* a segment boundary. */
190 
191 #define single_block(y, h)\
192   !(((y - wdev->y_base) ^ (y - wdev->y_base + h - 1)) & ~wdev->y_mask)
193 
194 #define BEGIN_BLOCKS\
195 {	int by, bh, left = h;\
196 	for ( by = y; left > 0; by += bh, left -= bh )\
197 	{	bh = wdev->y_block - (by & wdev->y_mask);\
198 		if ( bh > left ) bh = left;
199 #define END_BLOCKS\
200 	}\
201 }
202 
203 #endif /* (!)USE_SEGMENTS */
204 
205 /* Fill a rectangle. */
206 private int
win_dib_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)207 win_dib_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
208 		       gx_color_index color)
209 {
210 #if USE_SEGMENTS
211     if (single_block(y, h)) {
212 	wmproc(fill_rectangle) (wmdev, x, y, w, h, color);
213     } else {			/* Divide the transfer into blocks. */
214 	BEGIN_BLOCKS
215 	    wmproc(fill_rectangle) (wmdev, x, by, w, bh, color);
216 	END_BLOCKS
217     }
218 #else
219     wmproc(fill_rectangle) (wmdev, x, y, w, h, color);
220 #endif
221     return 0;
222 }
223 
224 /* Copy a monochrome bitmap.  The colors are given explicitly. */
225 /* Color = gx_no_color_index means transparent (no effect on the image). */
226 private int
win_dib_copy_mono(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)227 win_dib_copy_mono(gx_device * dev,
228 		const byte * base, int sourcex, int raster, gx_bitmap_id id,
229 		  int x, int y, int w, int h,
230 		  gx_color_index zero, gx_color_index one)
231 {
232 #if USE_SEGMENTS
233     if (single_block(y, h)) {
234 	wmproc(copy_mono) (wmdev, base, sourcex, raster, id,
235 			   x, y, w, h, zero, one);
236     } else {			/* Divide the transfer into blocks. */
237 	const byte *source = base;
238 
239 	BEGIN_BLOCKS
240 	    wmproc(copy_mono) (wmdev, source, sourcex, raster,
241 			       gx_no_bitmap_id, x, by, w, bh,
242 			       zero, one);
243 	source += bh * raster;
244 	END_BLOCKS
245     }
246 #else
247     wmproc(copy_mono) (wmdev, base, sourcex, raster, id,
248 		       x, y, w, h, zero, one);
249 #endif
250     return 0;
251 }
252 
253 /* Copy a color pixel map.  This is just like a bitmap, except that */
254 /* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
255 private int
win_dib_copy_color(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)256 win_dib_copy_color(gx_device * dev,
257 		const byte * base, int sourcex, int raster, gx_bitmap_id id,
258 		   int x, int y, int w, int h)
259 {
260 #if USE_SEGMENTS
261     if (single_block(y, h)) {
262 	wmproc(copy_color) (wmdev, base, sourcex, raster, id,
263 			    x, y, w, h);
264     } else {			/* Divide the transfer into blocks. */
265 	const byte *source = base;
266 
267 	BEGIN_BLOCKS
268 	    wmproc(copy_color) (wmdev, source, sourcex, raster,
269 				gx_no_bitmap_id, x, by, w, bh);
270 	source += by * raster;
271 	END_BLOCKS
272     }
273 #else
274     wmproc(copy_color) (wmdev, base, sourcex, raster, id,
275 			x, y, w, h);
276 #endif
277     return 0;
278 }
279 
280 int
win_dib_get_bits(gx_device * dev,int y,byte * str,byte ** actual_data)281 win_dib_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data)
282 {
283     return wmproc(get_bits) (wmdev, y, str, actual_data);
284 }
285 
286 int
win_dib_put_params(gx_device * dev,gs_param_list * plist)287 win_dib_put_params(gx_device * dev, gs_param_list * plist)
288 {
289     int code;
290 
291     win_dib_lock_device((unsigned char *)dev, 1);
292     code = win_put_params(dev, plist);
293     win_dib_lock_device((unsigned char *)dev, 0);
294     return code;
295 }
296 
297 /* ------ DLL device procedures ------ */
298 
299 /* make a copy of the device bitmap and return shared memory handle to it */
300 /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
301 HGLOBAL GSDLLAPI
gsdll_copy_dib(unsigned char * device)302 gsdll_copy_dib(unsigned char *device)
303 {
304     gx_device_win_dib *dev = (gx_device_win_dib *) device;
305 
306     if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0)
307 	return (HGLOBAL) NULL;
308     return win_dib_make_dib((gx_device_win *) dev, 0, 0, dev->width, dev->height);
309 }
310 
311 /* make a copy of the device palette and return a handle to it */
312 /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
313 HPALETTE GSDLLAPI
gsdll_copy_palette(unsigned char * device)314 gsdll_copy_palette(unsigned char *device)
315 {
316     gx_device_win_dib *dev = (gx_device_win_dib *) device;
317 
318     if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0)
319 	return (HPALETTE) NULL;
320     if (wdev->nColors > 0)
321 	return CreatePalette(dev->limgpalette);
322     return (HPALETTE) NULL;
323 }
324 
325 /* copy the rectangle src from the device bitmap */
326 /* to the rectangle dest on the device given by hdc */
327 /* hdc must be a device context for a device (NOT a bitmap) */
328 /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
329 void GSDLLAPI
gsdll_draw(unsigned char * device,HDC hdc,LPRECT dest,LPRECT src)330 gsdll_draw(unsigned char *device, HDC hdc, LPRECT dest, LPRECT src)
331 {
332     gx_device_win_dib *dev = (gx_device_win_dib *) device;
333     HPALETTE oldpalette;
334 
335     if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0)
336 	return;
337     if (dev->nColors > 0) {
338 	oldpalette = SelectPalette(hdc, dev->himgpalette, FALSE);
339 	RealizePalette(hdc);
340     }
341     win_dib_repaint((gx_device_win *) dev, hdc, dest->left, dest->top,
342 		    dest->right - dest->left, dest->bottom - dest->top,
343 		    src->left, src->top);
344     if (dev->nColors > 0) {
345 	SelectPalette(hdc, oldpalette, FALSE);
346     }
347     return;
348 }
349 
350 /* ------ Windows-specific device procedures ------ */
351 
352 
353 /* Repaint a section of the window. */
354 private void
win_dib_repaint(gx_device_win * dev,HDC hdc,int dx,int dy,int wx,int wy,int sx,int sy)355 win_dib_repaint(gx_device_win * dev, HDC hdc, int dx, int dy, int wx, int wy,
356 		int sx, int sy)
357 {
358     struct bmi_s {
359 	BITMAPINFOHEADER h;
360 	ushort pal_index[256];
361     } bmi;
362     int i;
363     UINT which_colors;
364 
365     memset(&bmi.h, 0, sizeof(bmi.h));
366 
367     bmi.h.biSize = sizeof(bmi.h);
368     bmi.h.biWidth = wdev->mdev.width;
369     bmi.h.biHeight = wy;
370     bmi.h.biPlanes = 1;
371     bmi.h.biBitCount = dev->color_info.depth;
372     bmi.h.biCompression = 0;
373     bmi.h.biSizeImage = 0;	/* default */
374     bmi.h.biXPelsPerMeter = 0;	/* default */
375     bmi.h.biYPelsPerMeter = 0;	/* default */
376 
377     if (dev->BitsPerPixel <= 8) {
378 	bmi.h.biClrUsed = wdev->nColors;
379 	bmi.h.biClrImportant = wdev->nColors;
380 	for (i = 0; i < wdev->nColors; i++)
381 	    bmi.pal_index[i] = i;
382 	which_colors = DIB_PAL_COLORS;
383     } else if (dev->BitsPerPixel == 15) { /* 5-5-5 RGB mode */
384 	DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]);
385 	bmi.h.biCompression = BI_BITFIELDS;
386 	bmi_colors[0] = 0x7c00;
387 	bmi_colors[1] = 0x03e0;
388 	bmi_colors[2] = 0x001f;
389 	which_colors = DIB_RGB_COLORS;
390     } else if (dev->BitsPerPixel == 16) { /* 5-6-5 RGB mode */
391 	DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]);
392 	bmi.h.biCompression = BI_BITFIELDS;
393 	bmi_colors[0] = 0xf800;
394 	bmi_colors[1] = 0x07e0;
395 	bmi_colors[2] = 0x001f;
396 	which_colors = DIB_RGB_COLORS;
397     } else {
398 	bmi.h.biClrUsed = 0;
399 	bmi.h.biClrImportant = 0;
400 	which_colors = DIB_RGB_COLORS;
401     }
402     /*
403      * Windows apparently limits the size of a single transfer
404      * to 2 Mb, which can be exceeded on 24-bit displays.
405      * Deal with this here.
406      */
407 #define max_transfer 2000000
408     if (wdev->mdev.raster > 0) {	/* just in case! */
409 	long ny = max_transfer / wdev->mdev.raster;
410 
411 	for (; wy > ny; dy += ny, wy -= ny, sy += ny)
412 	    SetDIBitsToDevice(hdc, dx, dy, wx, ny,
413 			      sx, 0, 0, ny,
414 			      wdev->mdev.line_ptrs[wdev->height - (sy + ny)],
415 			      (BITMAPINFO FAR *) & bmi, which_colors);
416     }
417 #undef max_transfer
418     SetDIBitsToDevice(hdc, dx, dy, wx, wy,
419 		      sx, 0, 0, wy,
420 		      wdev->mdev.line_ptrs[wdev->height - (sy + wy)],
421 		      (BITMAPINFO FAR *) & bmi, which_colors);
422 }
423 
424 /* This makes a DIB that contains all or part of the bitmap. */
425 /* The bitmap pixel orgx must start on a byte boundary. */
426 private HGLOBAL
win_dib_make_dib(gx_device_win * dev,int orgx,int orgy,int wx,int wy)427 win_dib_make_dib(gx_device_win * dev, int orgx, int orgy, int wx, int wy)
428 {
429 #define xwdev ((gx_device_win_dib *)dev)
430     gx_color_value prgb[3];
431     HGLOBAL hglobal;
432     BYTE FAR *pDIB;
433     BITMAPINFOHEADER FAR *pbmih;
434     RGBQUAD FAR *pColors;
435     BYTE FAR *pBits;
436     BYTE FAR *pLine;
437     ulong bitmapsize;
438     int palcount;
439     int i;
440     UINT lwidth;		/* line width in bytes rounded up to multiple of 4 bytes */
441     int loffset;		/* byte offset to start of line */
442 
443 #if USE_SEGMENTS
444     UINT lseg;			/* bytes remaining in this segment */
445 #endif
446 
447     if (orgx + wx > wdev->width)
448 	wx = wdev->width - orgx;
449     if (orgy + wy > wdev->height)
450 	wy = wdev->height - orgy;
451 
452     loffset = orgx * wdev->color_info.depth / 8;
453     lwidth = ((wx * wdev->color_info.depth + 31) & ~31) >> 3;
454     bitmapsize = (long)lwidth *wy;
455 
456     if (wdev->color_info.depth > 16)
457 	palcount = 0;
458     else if (wdev->color_info.depth > 8)
459 	palcount = 3;		/* 16-bit BI_BITFIELDS */
460     else
461 	palcount = wdev->nColors;
462 
463     hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER)
464 			  + sizeof(RGBQUAD) * palcount + bitmapsize);
465     if (hglobal == (HGLOBAL) NULL) {
466 	MessageBeep(-1);
467 	return (HGLOBAL) NULL;
468     }
469     pDIB = (BYTE FAR *) GlobalLock(hglobal);
470     if (pDIB == (BYTE FAR *) NULL) {
471 	MessageBeep(-1);
472 	return (HGLOBAL) NULL;
473     }
474     pbmih = (BITMAPINFOHEADER FAR *) (pDIB);
475     pColors = (RGBQUAD FAR *) (pDIB + sizeof(BITMAPINFOHEADER));
476     pBits = (BYTE FAR *) (pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palcount);
477 
478     pbmih->biSize = sizeof(BITMAPINFOHEADER);
479     pbmih->biWidth = wx;
480     pbmih->biHeight = wy;
481     pbmih->biPlanes = 1;
482     pbmih->biBitCount = wdev->color_info.depth;
483     pbmih->biCompression = 0;
484     pbmih->biSizeImage = 0;	/* default */
485     pbmih->biXPelsPerMeter = (DWORD) (dev->x_pixels_per_inch / 25.4 * 1000);
486     pbmih->biYPelsPerMeter = (DWORD) (dev->y_pixels_per_inch / 25.4 * 1000);
487     pbmih->biClrUsed = palcount;
488     pbmih->biClrImportant = palcount;
489 
490     if (dev->BitsPerPixel == 15) { /* 5-5-5 RGB mode */
491 	DWORD* bmi_colors = (DWORD*)(pColors);
492         pbmih->biCompression = BI_BITFIELDS;
493 	bmi_colors[0] = 0x7c00;
494 	bmi_colors[1] = 0x03e0;
495 	bmi_colors[2] = 0x001f;
496     }
497     else if (dev->BitsPerPixel == 16) { /* 5-6-5 RGB mode */
498 	DWORD* bmi_colors = (DWORD*)(pColors);
499         pbmih->biCompression = BI_BITFIELDS;
500 	bmi_colors[0] = 0xf800;
501 	bmi_colors[1] = 0x07e0;
502 	bmi_colors[2] = 0x001f;
503     }
504     else {
505     for (i = 0; i < palcount; i++) {
506 	win_map_color_rgb((gx_device *) wdev, (gx_color_index) i, prgb);
507 	pColors[i].rgbRed = win_color_value(prgb[0]);
508 	pColors[i].rgbGreen = win_color_value(prgb[1]);
509 	pColors[i].rgbBlue = win_color_value(prgb[2]);
510 	pColors[i].rgbReserved = 0;
511     }
512     }
513 
514     pLine = pBits;
515     for (i = orgy; i < orgy + wy; i++) {
516 #if USE_SEGMENTS
517 	/* Window 3.1 has hmemcpy, but 3.0 doesn't */
518 	lseg = (UINT) (-OFFSETOF(pLine));	/* remaining bytes in this segment */
519 	if (lseg >= lwidth) {
520 	    _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lwidth);
521 	} else {		/* break up transfer to avoid crossing segment boundary */
522 	    _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lseg);
523 	    _fmemcpy(pLine + lseg, xwdev->mdev.line_ptrs[i] + loffset + lseg, lwidth - lseg);
524 	}
525 #else
526 	memcpy(pLine, xwdev->mdev.line_ptrs[i], lwidth);
527 #endif
528 	pLine += lwidth;
529     }
530 
531     GlobalUnlock(hglobal);
532     return hglobal;
533 }
534 
535 
536 /* Allocate the backing bitmap. */
537 private int
win_dib_alloc_bitmap(gx_device_win * dev,gx_device * param_dev)538 win_dib_alloc_bitmap(gx_device_win * dev, gx_device * param_dev)
539 {
540     int width;
541     gx_device_memory mdev;
542     HGLOBAL hmdata;
543     byte FAR *base;
544     uint ptr_size;
545     uint raster;
546     ulong data_size;
547 
548 #if USE_SEGMENTS
549    byte FAR *ptr_base;
550 #endif
551 
552 #ifdef __WIN32__
553     if (is_win32s) {
554 #endif
555 	/* Round up the width so that the scan line size is a power of 2. */
556 	if (dev->color_info.depth == 24) {
557 	    width = param_dev->width * 3 - 1;
558 	    while (width & (width + 1))
559 		width |= width >> 1;
560 	    width = (width + 1) / 3;
561 	} else {
562 	    width = param_dev->width - 1;
563 	    while (width & (width + 1))
564 		width |= width >> 1;
565 	    width++;
566 	}
567 #ifdef __WIN32__
568     } else {			/* don't have to worry about segments so use less memory */
569 	width = param_dev->width;
570     }
571 #endif
572 
573     /* Finish initializing the DIB. */
574 
575     gs_make_mem_device(&mdev, gdev_mem_device_for_bits(dev->color_info.depth), 0, 0, (gx_device *) dev);
576     mdev.width = width;
577     mdev.height = param_dev->height;
578     raster = gdev_mem_raster(&mdev);
579     data_size = (ulong) raster *mdev.height;
580 
581     ptr_size = sizeof(byte **) * mdev.height;
582     hmdata = GlobalAlloc(0, raster + data_size + ptr_size * 2);
583     if (hmdata == 0) {
584 	return win_nomemory();
585     }
586     /* Nothing can go wrong now.... */
587 
588     wdev->hmdata = hmdata;
589     base = GlobalLock(hmdata);
590 #if USE_SEGMENTS
591     /* Adjust base so scan lines, and the pointer table, */
592     /* don't cross a segment boundary. */
593     base += (-PTR_OFF(base) & (raster - 1));
594     ptr_base = base + data_size;
595     if (PTR_OFF(ptr_base + ptr_size) < ptr_size)
596 	base += (uint) - PTR_OFF(ptr_base);
597     wdev->y_block = 0x10000L / raster;
598     wdev->y_mask = wdev->y_block - 1;
599     if ((wdev->y_base = PTR_OFF(base)) != 0)
600 	wdev->y_base = -(PTR_OFF(base) / raster);
601 #endif
602     wdev->mdev = mdev;
603     wdev->mdev.base = (byte *) base;
604     wmproc(open_device) ((gx_device *) & wdev->mdev);
605 
606     if (wdev->is_open && pgsdll_callback)
607 	(*pgsdll_callback) (GSDLL_SIZE, (unsigned char *)dev,
608 			    (dev->width & 0xffff) +
609 			    ((ulong) (dev->height & 0xffff) << 16));
610 
611     return 0;
612 }
613 
614 
615 /* Free the backing bitmap. */
616 private void
win_dib_free_bitmap(gx_device_win * dev)617 win_dib_free_bitmap(gx_device_win * dev)
618 {
619     HGLOBAL hmdata = wdev->hmdata;
620 
621     GlobalUnlock(hmdata);
622     GlobalFree(hmdata);
623 }
624 
625 /* Lock the device (so it's size cannot be changed) if flag = TRUE */
626 /* or unlock the device if flag = FALSE */
627 /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
628 private int
win_dib_lock_device(unsigned char * device,int flag)629 win_dib_lock_device(unsigned char *device, int flag)
630 {
631     gx_device *dev = (gx_device *) device;
632 
633 #ifdef __WIN32__
634     if (!is_win32s) {
635 	if (flag) {
636 	    if (WaitForSingleObject(wdev->hmtx, 60000) == WAIT_TIMEOUT)
637 		return 2;
638 	    return 1;
639 	}
640 	ReleaseMutex(wdev->hmtx);
641 	return 0;
642     }
643 #endif
644     if (flag)
645 	wdev->lock_count++;
646     else
647 	wdev->lock_count--;
648     if (wdev->lock_count < 0)
649 	wdev->lock_count = 0;
650     return wdev->lock_count;
651 }
652 
653 int GSDLLAPI _export
gsdll_lock_device(unsigned char * device,int flag)654 gsdll_lock_device(unsigned char *device, int flag)
655 {
656     return win_dib_lock_device(device, flag);
657 }
658 
659 
660 /* Copy bitmap
661  * If pbmih nonzero, copy the BITMAPINFOHEADER.
662  * If prgbquad nonzero, copy the palette.
663  *   number of entries copied is given by pbmih->biClrUsed
664  * If ppbyte nonzero, return pointer to row.
665  *   pointer is only valid while device is locked
666  * GS can change the palette while the device is locked.
667  * Do not call this function while GS is busy.
668  * If all pbmih and prgbquad and ppbyte are all NULL,
669  * return value is byte count needed for BITMAPINFOHEADER
670  * and palette and one bitmap row.
671  * Otherwise return value is 0;
672  *
673  * This function exists to allow the bitmap to be copied to a file
674  * or structured storage, without the overhead of having two copies
675  * of the bitmap in memory at the same time.
676  */
677 int GSDLLAPI _export
gsdll_get_bitmap_row(unsigned char * device,LPBITMAPINFOHEADER pbmih,LPRGBQUAD prgbquad,LPBYTE * ppbyte,unsigned int row)678 gsdll_get_bitmap_row(unsigned char *device, LPBITMAPINFOHEADER pbmih,
679 		     LPRGBQUAD prgbquad, LPBYTE * ppbyte, unsigned int row)
680 {
681     int palcount;
682     gx_device_win_dib *dev = (gx_device_win_dib *) device;
683 
684     palcount = (dev->color_info.depth == 24) ? 0 : dev->nColors;
685 
686     if (pbmih) {
687 	pbmih->biSize = sizeof(BITMAPINFOHEADER);
688 	pbmih->biWidth = dev->width;
689 	pbmih->biHeight = dev->mdev.height;
690 	pbmih->biPlanes = 1;
691 	pbmih->biBitCount = dev->color_info.depth;
692 	if ((dev->BitsPerPixel == 15) || (dev->BitsPerPixel == 16))
693             pbmih->biCompression = BI_BITFIELDS;
694 	else
695 	pbmih->biCompression = 0;
696 	pbmih->biSizeImage = 0;	/* default */
697 	pbmih->biXPelsPerMeter = (DWORD) (dev->x_pixels_per_inch / 25.4 * 1000);
698 	pbmih->biYPelsPerMeter = (DWORD) (dev->y_pixels_per_inch / 25.4 * 1000);
699 	pbmih->biClrUsed = palcount;
700 	pbmih->biClrImportant = palcount;
701     }
702     if (prgbquad) {
703 	int i;
704 	gx_color_value prgb[3];
705 
706 	if (dev->BitsPerPixel == 15) { /* 5-5-5 RGB mode */
707 	    DWORD* bmi_colors = (DWORD*)(prgbquad);
708 	    pbmih->biCompression = BI_BITFIELDS;
709 	    bmi_colors[0] = 0x7c00;
710 	    bmi_colors[1] = 0x03e0;
711 	    bmi_colors[2] = 0x001f;
712 	}
713 	else if (dev->BitsPerPixel == 16) { /* 5-6-5 RGB mode */
714 	    DWORD* bmi_colors = (DWORD*)(prgbquad);
715 	    pbmih->biCompression = BI_BITFIELDS;
716 	    bmi_colors[0] = 0xf800;
717 	    bmi_colors[1] = 0x07e0;
718 	    bmi_colors[2] = 0x001f;
719 	}
720 	else {
721 	for (i = 0; i < palcount; i++) {
722 	    win_map_color_rgb((gx_device *) wdev, (gx_color_index) i, prgb);
723 	    prgbquad[i].rgbRed = win_color_value(prgb[0]);
724 	    prgbquad[i].rgbGreen = win_color_value(prgb[1]);
725 	    prgbquad[i].rgbBlue = win_color_value(prgb[2]);
726 	    prgbquad[i].rgbReserved = 0;
727 	    }
728 	}
729     }
730     if (ppbyte) {
731 	if (row < dev->mdev.height)
732 	    *ppbyte = dev->mdev.line_ptrs[row];
733 	else
734 	    *ppbyte = NULL;
735     }
736     if ((pbmih == NULL) && (prgbquad == NULL) && (ppbyte == NULL))
737 	return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)
738 	    + gdev_mem_raster(&(dev->mdev));
739     return 0;
740 }
741