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