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