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