1 /* Copyright (C) 2001-2012 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,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* MS Windows 3.n driver for Ghostscript using a DIB for buffering. */
18 #include "gdevmswn.h"
19 #include "gxdevmem.h"
20 #include "gsdll.h"
21 #include "gsdllwin.h"
22
23 #ifdef __WIN32__
24 # define USE_SEGMENTS 0
25 #else
26 # define USE_SEGMENTS 1
27 #endif
28
29 /* Make sure we cast to the correct structure type. */
30 typedef struct gx_device_win_dib_s gx_device_win_dib;
31
32 #undef wdev
33 #define wdev ((gx_device_win_dib *)dev)
34
35 /* Device procedures */
36
37 /* See gxdevice.h for the definitions of the procedures. */
38 static dev_proc_open_device(win_dib_open);
39 static dev_proc_get_initial_matrix(win_dib_get_initial_matrix);
40 static dev_proc_close_device(win_dib_close);
41 static dev_proc_fill_rectangle(win_dib_fill_rectangle);
42 static dev_proc_copy_mono(win_dib_copy_mono);
43 static dev_proc_copy_color(win_dib_copy_color);
44 static dev_proc_get_bits(win_dib_get_bits);
45 static dev_proc_put_params(win_dib_put_params);
46
47 /* Windows-specific procedures */
48 static win_proc_repaint(win_dib_repaint);
49 static win_proc_alloc_bitmap(win_dib_alloc_bitmap);
50 static win_proc_free_bitmap(win_dib_free_bitmap);
51
52 /* The device descriptor */
53 struct gx_device_win_dib_s {
54 gx_device_common;
55 gx_device_win_common;
56
57 #if USE_SEGMENTS
58 /* The following help manage the division of the DIB */
59 /* into 64K segments. Each block of y_block scan lines */
60 /* starting at y_base mod 64K falls in a single segment. */
61 /* Since the raster is a power of 2, y_block is a power of 2. */
62
63 int y_block;
64 int y_base;
65 int y_mask; /* y_block - 1 */
66 #endif /* USE_SEGMENTS */
67
68 HGLOBAL hmdata;
69 #ifdef __WIN32__
70 HANDLE hmtx;
71 #endif
72 int lock_count;
73 gx_device_memory mdev;
74 };
75 static const gx_device_procs win_dib_procs =
76 {
77 win_dib_open,
78 win_dib_get_initial_matrix,
79 win_sync_output,
80 win_output_page,
81 win_dib_close,
82 win_map_rgb_color,
83 win_map_color_rgb,
84 win_dib_fill_rectangle,
85 NULL, /* tile_rectangle */
86 win_dib_copy_mono,
87 win_dib_copy_color,
88 NULL, /* draw_line */
89 win_dib_get_bits /* NULL */ , /* get_bits */
90 win_get_params,
91 win_dib_put_params,
92 NULL, /* map_cmyk_color */
93 win_get_xfont_procs,
94 NULL, /* get_xfont_device */
95 NULL, /* map_rgb_alpha_color */
96 gx_page_device_get_page_device
97 };
98 gx_device_win_dib far_data gs_mswindll_device =
99 {
100 std_device_std_body(gx_device_win_dib, &win_dib_procs, "mswindll",
101 INITIAL_WIDTH, INITIAL_HEIGHT,/* win_open() fills these in later */
102 INITIAL_RESOLUTION, INITIAL_RESOLUTION /* win_open() fills these in later */
103 ),
104 {0}, /* std_procs */
105 0, /* BitsPerPixel */
106 2, /* nColors */
107 0, /* mapped_color_flags */
108 win_dib_alloc_bitmap,
109 win_dib_free_bitmap
110 };
111
112 /* forward declarations */
113 static HGLOBAL win_dib_make_dib(gx_device_win * dev, int orgx, int orgy, int wx, int wy);
114 static int win_dib_lock_device(unsigned char *device, int flag);
115
116 /* Open the win_dib driver */
117 static int
win_dib_open(gx_device * dev)118 win_dib_open(gx_device * dev)
119 {
120 int code = win_open(dev);
121
122 if (code < 0)
123 return code;
124
125 #ifdef __WIN32__
126 if (!is_win32s)
127 wdev->hmtx = CreateMutex(NULL, FALSE, NULL); /* unnamed mutex, initially unowned */
128 #endif
129 if (gdev_mem_device_for_bits(dev->color_info.depth) == 0) {
130 win_close(dev);
131 return gs_error_rangecheck;
132 }
133 code = win_dib_alloc_bitmap((gx_device_win *) dev, dev);
134 if (code < 0) {
135 win_close(dev);
136 return code;
137 }
138 /* notify caller about new device */
139 if (pgsdll_callback) {
140 (*pgsdll_callback) (GSDLL_DEVICE, (unsigned char *)dev, 1);
141 (*pgsdll_callback) (GSDLL_SIZE, (unsigned char *)dev,
142 (dev->width & 0xffff) +
143 ((ulong) (dev->height & 0xffff) << 16));
144 }
145 return code;
146 }
147
148 /* Get the initial matrix. DIBs, unlike most displays, */
149 /* put (0,0) in the lower left corner. */
150 static void
win_dib_get_initial_matrix(gx_device * dev,gs_matrix * pmat)151 win_dib_get_initial_matrix(gx_device * dev, gs_matrix * pmat)
152 {
153 pmat->xx = dev->x_pixels_per_inch / 72.0;
154 pmat->xy = 0.0;
155 pmat->yx = 0.0;
156 pmat->yy = dev->y_pixels_per_inch / 72.0;
157 pmat->tx = 0.0;
158 pmat->ty = 0.0;
159 }
160
161 /* Close the win_dib driver */
162 static int
win_dib_close(gx_device * dev)163 win_dib_close(gx_device * dev)
164 {
165 int code;
166
167 /* wait until bitmap is not being used by caller */
168 win_dib_lock_device((unsigned char *)dev, 1);
169 if (pgsdll_callback)
170 (*pgsdll_callback) (GSDLL_DEVICE, (unsigned char *)dev, 0);
171 win_dib_lock_device((unsigned char *)dev, 0);
172 win_dib_free_bitmap((gx_device_win *) dev);
173 #ifdef __WIN32__
174 if (!is_win32s)
175 CloseHandle(wdev->hmtx);
176 #endif
177 code = win_close(dev);
178 return code;
179 }
180
181 #define wmdev ((gx_device *)&wdev->mdev)
182 #define wmproc(proc) (*dev_proc(&wdev->mdev, proc))
183
184 #if USE_SEGMENTS
185
186 /* The drawing routines must all be careful not to cross */
187 /* a segment boundary. */
188
189 #define single_block(y, h)\
190 !(((y - wdev->y_base) ^ (y - wdev->y_base + h - 1)) & ~wdev->y_mask)
191
192 #define BEGIN_BLOCKS\
193 { int by, bh, left = h;\
194 for ( by = y; left > 0; by += bh, left -= bh )\
195 { bh = wdev->y_block - (by & wdev->y_mask);\
196 if ( bh > left ) bh = left;
197 #define END_BLOCKS\
198 }\
199 }
200
201 #endif /* (!)USE_SEGMENTS */
202
203 /* Fill a rectangle. */
204 static int
win_dib_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)205 win_dib_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
206 gx_color_index color)
207 {
208 #if USE_SEGMENTS
209 if (single_block(y, h)) {
210 wmproc(fill_rectangle) (wmdev, x, y, w, h, color);
211 } else { /* Divide the transfer into blocks. */
212 BEGIN_BLOCKS
213 wmproc(fill_rectangle) (wmdev, x, by, w, bh, color);
214 END_BLOCKS
215 }
216 #else
217 wmproc(fill_rectangle) (wmdev, x, y, w, h, color);
218 #endif
219 return 0;
220 }
221
222 /* Copy a monochrome bitmap. The colors are given explicitly. */
223 /* Color = gx_no_color_index means transparent (no effect on the image). */
224 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)225 win_dib_copy_mono(gx_device * dev,
226 const byte * base, int sourcex, int raster, gx_bitmap_id id,
227 int x, int y, int w, int h,
228 gx_color_index zero, gx_color_index one)
229 {
230 #if USE_SEGMENTS
231 if (single_block(y, h)) {
232 wmproc(copy_mono) (wmdev, base, sourcex, raster, id,
233 x, y, w, h, zero, one);
234 } else { /* Divide the transfer into blocks. */
235 const byte *source = base;
236
237 BEGIN_BLOCKS
238 wmproc(copy_mono) (wmdev, source, sourcex, raster,
239 gx_no_bitmap_id, x, by, w, bh,
240 zero, one);
241 source += bh * raster;
242 END_BLOCKS
243 }
244 #else
245 wmproc(copy_mono) (wmdev, base, sourcex, raster, id,
246 x, y, w, h, zero, one);
247 #endif
248 return 0;
249 }
250
251 /* Copy a color pixel map. This is just like a bitmap, except that */
252 /* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
253 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)254 win_dib_copy_color(gx_device * dev,
255 const byte * base, int sourcex, int raster, gx_bitmap_id id,
256 int x, int y, int w, int h)
257 {
258 #if USE_SEGMENTS
259 if (single_block(y, h)) {
260 wmproc(copy_color) (wmdev, base, sourcex, raster, id,
261 x, y, w, h);
262 } else { /* Divide the transfer into blocks. */
263 const byte *source = base;
264
265 BEGIN_BLOCKS
266 wmproc(copy_color) (wmdev, source, sourcex, raster,
267 gx_no_bitmap_id, x, by, w, bh);
268 source += by * raster;
269 END_BLOCKS
270 }
271 #else
272 wmproc(copy_color) (wmdev, base, sourcex, raster, id,
273 x, y, w, h);
274 #endif
275 return 0;
276 }
277
278 int
win_dib_get_bits(gx_device * dev,int y,byte * str,byte ** actual_data)279 win_dib_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data)
280 {
281 return wmproc(get_bits) (wmdev, y, str, actual_data);
282 }
283
284 int
win_dib_put_params(gx_device * dev,gs_param_list * plist)285 win_dib_put_params(gx_device * dev, gs_param_list * plist)
286 {
287 int code;
288
289 win_dib_lock_device((unsigned char *)dev, 1);
290 code = win_put_params(dev, plist);
291 win_dib_lock_device((unsigned char *)dev, 0);
292 return code;
293 }
294
295 /* ------ DLL device procedures ------ */
296
297 /* make a copy of the device bitmap and return shared memory handle to it */
298 /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
299 HGLOBAL GSDLLAPI
gsdll_copy_dib(unsigned char * device)300 gsdll_copy_dib(unsigned char *device)
301 {
302 gx_device_win_dib *dev = (gx_device_win_dib *) device;
303
304 if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0)
305 return (HGLOBAL) NULL;
306 return win_dib_make_dib((gx_device_win *) dev, 0, 0, dev->width, dev->height);
307 }
308
309 /* make a copy of the device palette and return a handle to it */
310 /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
311 HPALETTE GSDLLAPI
gsdll_copy_palette(unsigned char * device)312 gsdll_copy_palette(unsigned char *device)
313 {
314 gx_device_win_dib *dev = (gx_device_win_dib *) device;
315
316 if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0)
317 return (HPALETTE) NULL;
318 if (wdev->nColors > 0)
319 return CreatePalette(dev->limgpalette);
320 return (HPALETTE) NULL;
321 }
322
323 /* copy the rectangle src from the device bitmap */
324 /* to the rectangle dest on the device given by hdc */
325 /* hdc must be a device context for a device (NOT a bitmap) */
326 /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
327 void GSDLLAPI
gsdll_draw(unsigned char * device,HDC hdc,LPRECT dest,LPRECT src)328 gsdll_draw(unsigned char *device, HDC hdc, LPRECT dest, LPRECT src)
329 {
330 gx_device_win_dib *dev = (gx_device_win_dib *) device;
331 HPALETTE oldpalette;
332
333 if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0)
334 return;
335 if (dev->nColors > 0) {
336 oldpalette = SelectPalette(hdc, dev->himgpalette, FALSE);
337 RealizePalette(hdc);
338 }
339 win_dib_repaint((gx_device_win *) dev, hdc, dest->left, dest->top,
340 dest->right - dest->left, dest->bottom - dest->top,
341 src->left, src->top);
342 if (dev->nColors > 0) {
343 SelectPalette(hdc, oldpalette, FALSE);
344 }
345 return;
346 }
347
348 /* ------ Windows-specific device procedures ------ */
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 /* Allocate the backing bitmap. */
533 static int
win_dib_alloc_bitmap(gx_device_win * dev,gx_device * param_dev)534 win_dib_alloc_bitmap(gx_device_win * dev, gx_device * param_dev)
535 {
536 int width;
537 gx_device_memory mdev;
538 HGLOBAL hmdata;
539 byte FAR *base;
540 uint ptr_size;
541 uint raster;
542 ulong data_size;
543
544 #if USE_SEGMENTS
545 byte FAR *ptr_base;
546 #endif
547
548 #ifdef __WIN32__
549 if (is_win32s) {
550 #endif
551 /* Round up the width so that the scan line size is a power of 2. */
552 if (dev->color_info.depth == 24) {
553 width = param_dev->width * 3 - 1;
554 while (width & (width + 1))
555 width |= width >> 1;
556 width = (width + 1) / 3;
557 } else {
558 width = param_dev->width - 1;
559 while (width & (width + 1))
560 width |= width >> 1;
561 width++;
562 }
563 #ifdef __WIN32__
564 } else { /* don't have to worry about segments so use less memory */
565 width = param_dev->width;
566 }
567 #endif
568
569 /* Finish initializing the DIB. */
570
571 gs_make_mem_device(&mdev, gdev_mem_device_for_bits(dev->color_info.depth), 0, 0, (gx_device *) dev);
572 mdev.width = width;
573 mdev.height = param_dev->height;
574 raster = gdev_mem_raster(&mdev);
575 data_size = (ulong) raster *mdev.height;
576
577 ptr_size = sizeof(byte **) * mdev.height;
578 hmdata = GlobalAlloc(0, raster + data_size + ptr_size * 2);
579 if (hmdata == 0) {
580 return win_nomemory();
581 }
582 /* Nothing can go wrong now.... */
583
584 wdev->hmdata = hmdata;
585 base = GlobalLock(hmdata);
586 #if USE_SEGMENTS
587 /* Adjust base so scan lines, and the pointer table, */
588 /* don't cross a segment boundary. */
589 base += (-PTR_OFF(base) & (raster - 1));
590 ptr_base = base + data_size;
591 if (PTR_OFF(ptr_base + ptr_size) < ptr_size)
592 base += (uint) - PTR_OFF(ptr_base);
593 wdev->y_block = 0x10000L / raster;
594 wdev->y_mask = wdev->y_block - 1;
595 if ((wdev->y_base = PTR_OFF(base)) != 0)
596 wdev->y_base = -(PTR_OFF(base) / raster);
597 #endif
598 wdev->mdev = mdev;
599 wdev->mdev.base = (byte *) base;
600 wmproc(open_device) ((gx_device *) & wdev->mdev);
601
602 if (wdev->is_open && pgsdll_callback)
603 (*pgsdll_callback) (GSDLL_SIZE, (unsigned char *)dev,
604 (dev->width & 0xffff) +
605 ((ulong) (dev->height & 0xffff) << 16));
606
607 return 0;
608 }
609
610 /* Free the backing bitmap. */
611 static void
win_dib_free_bitmap(gx_device_win * dev)612 win_dib_free_bitmap(gx_device_win * dev)
613 {
614 HGLOBAL hmdata = wdev->hmdata;
615
616 GlobalUnlock(hmdata);
617 GlobalFree(hmdata);
618 }
619
620 /* Lock the device (so it's size cannot be changed) if flag = TRUE */
621 /* or unlock the device if flag = FALSE */
622 /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
623 static int
win_dib_lock_device(unsigned char * device,int flag)624 win_dib_lock_device(unsigned char *device, int flag)
625 {
626 gx_device *dev = (gx_device *) device;
627
628 #ifdef __WIN32__
629 if (!is_win32s) {
630 if (flag) {
631 if (WaitForSingleObject(wdev->hmtx, 60000) == WAIT_TIMEOUT)
632 return 2;
633 return 1;
634 }
635 ReleaseMutex(wdev->hmtx);
636 return 0;
637 }
638 #endif
639 if (flag)
640 wdev->lock_count++;
641 else
642 wdev->lock_count--;
643 if (wdev->lock_count < 0)
644 wdev->lock_count = 0;
645 return wdev->lock_count;
646 }
647
648 int GSDLLAPI _export
gsdll_lock_device(unsigned char * device,int flag)649 gsdll_lock_device(unsigned char *device, int flag)
650 {
651 return win_dib_lock_device(device, flag);
652 }
653
654 /* Copy bitmap
655 * If pbmih nonzero, copy the BITMAPINFOHEADER.
656 * If prgbquad nonzero, copy the palette.
657 * number of entries copied is given by pbmih->biClrUsed
658 * If ppbyte nonzero, return pointer to row.
659 * pointer is only valid while device is locked
660 * GS can change the palette while the device is locked.
661 * Do not call this function while GS is busy.
662 * If all pbmih and prgbquad and ppbyte are all NULL,
663 * return value is byte count needed for BITMAPINFOHEADER
664 * and palette and one bitmap row.
665 * Otherwise return value is 0;
666 *
667 * This function exists to allow the bitmap to be copied to a file
668 * or structured storage, without the overhead of having two copies
669 * of the bitmap in memory at the same time.
670 */
671 int GSDLLAPI _export
gsdll_get_bitmap_row(unsigned char * device,LPBITMAPINFOHEADER pbmih,LPRGBQUAD prgbquad,LPBYTE * ppbyte,unsigned int row)672 gsdll_get_bitmap_row(unsigned char *device, LPBITMAPINFOHEADER pbmih,
673 LPRGBQUAD prgbquad, LPBYTE * ppbyte, unsigned int row)
674 {
675 int palcount;
676 gx_device_win_dib *dev = (gx_device_win_dib *) device;
677
678 palcount = (dev->color_info.depth == 24) ? 0 : dev->nColors;
679
680 if (pbmih) {
681 pbmih->biSize = sizeof(BITMAPINFOHEADER);
682 pbmih->biWidth = dev->width;
683 pbmih->biHeight = dev->mdev.height;
684 pbmih->biPlanes = 1;
685 pbmih->biBitCount = dev->color_info.depth;
686 if ((dev->BitsPerPixel == 15) || (dev->BitsPerPixel == 16))
687 pbmih->biCompression = BI_BITFIELDS;
688 else
689 pbmih->biCompression = 0;
690 pbmih->biSizeImage = 0; /* default */
691 pbmih->biXPelsPerMeter = (DWORD) (dev->x_pixels_per_inch / 25.4 * 1000);
692 pbmih->biYPelsPerMeter = (DWORD) (dev->y_pixels_per_inch / 25.4 * 1000);
693 pbmih->biClrUsed = palcount;
694 pbmih->biClrImportant = palcount;
695 }
696 if (prgbquad) {
697 int i;
698 gx_color_value prgb[3];
699
700 if (dev->BitsPerPixel == 15) { /* 5-5-5 RGB mode */
701 DWORD* bmi_colors = (DWORD*)(prgbquad);
702 pbmih->biCompression = BI_BITFIELDS;
703 bmi_colors[0] = 0x7c00;
704 bmi_colors[1] = 0x03e0;
705 bmi_colors[2] = 0x001f;
706 }
707 else if (dev->BitsPerPixel == 16) { /* 5-6-5 RGB mode */
708 DWORD* bmi_colors = (DWORD*)(prgbquad);
709 pbmih->biCompression = BI_BITFIELDS;
710 bmi_colors[0] = 0xf800;
711 bmi_colors[1] = 0x07e0;
712 bmi_colors[2] = 0x001f;
713 }
714 else {
715 for (i = 0; i < palcount; i++) {
716 win_map_color_rgb((gx_device *) wdev, (gx_color_index) i, prgb);
717 prgbquad[i].rgbRed = win_color_value(prgb[0]);
718 prgbquad[i].rgbGreen = win_color_value(prgb[1]);
719 prgbquad[i].rgbBlue = win_color_value(prgb[2]);
720 prgbquad[i].rgbReserved = 0;
721 }
722 }
723 }
724 if (ppbyte) {
725 if (row < dev->mdev.height)
726 *ppbyte = dev->mdev.line_ptrs[row];
727 else
728 *ppbyte = NULL;
729 }
730 if ((pbmih == NULL) && (prgbquad == NULL) && (ppbyte == NULL))
731 return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)
732 + gdev_mem_raster(&(dev->mdev));
733 return 0;
734 }
735