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