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