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