1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gdevwddb.c 8250 2007-09-25 13:31:24Z giles $ */
16
* Microsoft Windows 3.n driver for Ghostscript,
17
* using device-dependent bitmap.
19
* Original version by Russell Lang and Maurice Castro with help from
20
* Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
21
* created from gdevbgi.c and gnuplot/term/win.trm 5th June 1992.
22
* Extensively modified by L. Peter Deutsch, Aladdin Enterprises.
26
/* Make sure we cast to the correct structure type. */
27
typedef struct gx_device_win_ddb_s gx_device_win_ddb;
30
#define wdev ((gx_device_win_ddb *)dev)
32
/* Forward references */
33
static void near win_addtool(gx_device_win_ddb *, int);
34
static void near win_maketools(gx_device_win_ddb *, HDC);
35
static void near win_destroytools(gx_device_win_ddb *);
37
/* Device procedures */
39
/* See gxdevice.h for the definitions of the procedures. */
40
static dev_proc_open_device(win_ddb_open);
41
static dev_proc_close_device(win_ddb_close);
42
static dev_proc_map_rgb_color(win_ddb_map_rgb_color);
43
static dev_proc_fill_rectangle(win_ddb_fill_rectangle);
44
static dev_proc_tile_rectangle(win_ddb_tile_rectangle);
45
static dev_proc_copy_mono(win_ddb_copy_mono);
46
static dev_proc_copy_color(win_ddb_copy_color);
48
/* Windows-specific procedures */
49
static win_proc_copy_to_clipboard(win_ddb_copy_to_clipboard);
50
static win_proc_repaint(win_ddb_repaint);
51
static win_proc_alloc_bitmap(win_ddb_alloc_bitmap);
52
static win_proc_free_bitmap(win_ddb_free_bitmap);
54
/* The device descriptor */
55
struct gx_device_win_ddb_s {
65
HBRUSH hbrush, *hbrushs;
67
#define select_brush(color)\
68
if (wdev->hbrush != wdev->hbrushs[color])\
69
{ wdev->hbrush = wdev->hbrushs[color];\
70
SelectObject(wdev->hdcbit,wdev->hbrush);\
73
LPLOGPALETTE lpalette;
75
/* A staging bitmap for copy_mono. */
76
/* We want one big enough to handle the standard 16x16 halftone; */
77
/* this is also big enough for ordinary-size characters. */
79
#define bmWidthBytes 4 /* must be even */
80
#define bmWidthBits (bmWidthBytes * 8)
86
static const gx_device_procs win_ddb_procs =
89
NULL, /* get_initial_matrix */
93
win_ddb_map_rgb_color,
95
win_ddb_fill_rectangle,
96
win_ddb_tile_rectangle,
103
NULL, /* map_cmyk_color */
106
gx_device_win_ddb far_data gs_mswin_device =
108
std_device_std_body(gx_device_win_ddb, &win_ddb_procs, "mswin",
109
INITIAL_WIDTH, INITIAL_HEIGHT, /* win_open() fills these in later */
110
INITIAL_RESOLUTION, INITIAL_RESOLUTION /* win_open() fills these in later */
113
0, /* BitsPerPixel - not used */
114
5000, /* UpdateInterval (in milliseconds) */
115
"\0", /* GSVIEW_STR */
116
0, /* not a DLL device */
118
0, /* mapped_color_flags */
119
win_ddb_copy_to_clipboard,
121
win_ddb_alloc_bitmap,
125
/* Open the win_ddb driver */
127
win_ddb_open(gx_device * dev)
129
int code = win_open(dev);
135
if (wdev->BitsPerPixel > 8)
136
return gs_error_limitcheck; /* don't support 24 bit/pixel */
138
/* Create the backing bitmap. */
139
code = win_ddb_alloc_bitmap((gx_device_win *) dev, dev);
143
/* Create the bitmap and DC for copy_mono. */
144
hdc = GetDC(wdev->hwndimg);
145
wdev->hbmmono = CreateBitmap(bmWidthBits, bmHeight, 1, 1, NULL);
146
wdev->hdcmono = CreateCompatibleDC(hdc);
147
if (wdev->hbmmono == NULL || wdev->hdcmono == NULL) {
148
win_ddb_free_bitmap((gx_device_win *) dev);
149
ReleaseDC(wdev->hwndimg, hdc);
150
return win_nomemory();
152
SetMapMode(wdev->hdcmono, GetMapMode(hdc));
153
SelectObject(wdev->hdcmono, wdev->hbmmono);
154
wdev->bm_id = gx_no_bitmap_id;
155
ReleaseDC(wdev->hwndimg, hdc);
157
/* create palette and tools for bitmap */
158
if ((wdev->lpalette = win_makepalette((gx_device_win *) dev))
159
== (LPLOGPALETTE) NULL)
160
return win_nomemory();
161
wdev->hpalette = CreatePalette(wdev->lpalette);
162
(void)SelectPalette(wdev->hdcbit, wdev->hpalette, NULL);
163
RealizePalette(wdev->hdcbit);
164
win_maketools(wdev, wdev->hdcbit);
166
wdev->hdctext = wdev->hdcbit; /* draw text here */
171
/* Close the win_ddb driver */
173
win_ddb_close(gx_device * dev)
177
win_destroytools(wdev);
178
DeleteDC(wdev->hdcmono);
179
win_ddb_free_bitmap((gx_device_win *) dev);
180
DeleteObject(wdev->hpalette);
181
DeleteObject(wdev->hbmmono);
182
gs_free((char *)(wdev->lpalette), 1, sizeof(LOGPALETTE) +
183
(1 << (wdev->color_info.depth)) * sizeof(PALETTEENTRY),
186
return win_close(dev);
189
/* Map a r-g-b color to the colors available under Windows */
190
static gx_color_index
191
win_ddb_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
194
int i = wdev->nColors;
195
gx_color_index color = win_map_rgb_color(dev, r, g, b);
196
LPLOGPALETTE lipal = wdev->limgpalette;
197
LPLOGPALETTE lpal = wdev->lpalette;
202
/* We just added a color to the window palette. */
203
/* Add it to the bitmap palette as well. */
205
DeleteObject(wdev->hpalette);
206
lpal->palPalEntry[i].peFlags = NULL;
207
lpal->palPalEntry[i].peRed = lipal->palPalEntry[i].peRed;
208
lpal->palPalEntry[i].peGreen = lipal->palPalEntry[i].peGreen;
209
lpal->palPalEntry[i].peBlue = lipal->palPalEntry[i].peBlue;
210
lpal->palNumEntries = i + 1;
211
wdev->hpalette = CreatePalette(lpal);
212
(void)SelectPalette(wdev->hdcbit, wdev->hpalette, NULL);
213
RealizePalette(wdev->hdcbit);
214
win_addtool(wdev, i);
219
/* Macro for filling a rectangle with a color. */
220
/* Note that it starts with a declaration. */
221
#define fill_rect(x, y, w, h, color)\
223
rect.left = x, rect.top = y;\
224
rect.right = x + w, rect.bottom = y + h;\
225
FillRect(wdev->hdcbit, &rect, wdev->hbrushs[(int)color])
228
/* Fill a rectangle. */
230
win_ddb_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
231
gx_color_index color)
233
fit_fill(dev, x, y, w, h);
234
/* Use PatBlt for filling. Special-case black. */
236
PatBlt(wdev->hdcbit, x, y, w, h, rop_write_0s);
238
select_brush((int)color);
239
PatBlt(wdev->hdcbit, x, y, w, h, rop_write_pattern);
241
win_update((gx_device_win *) dev);
246
/* Tile a rectangle. If neither color is transparent, */
247
/* pre-clear the rectangle to color0 and just tile with color1. */
248
/* This is faster because of how win_copy_mono is implemented. */
249
/* Note that this also does the right thing for colored tiles. */
251
win_ddb_tile_rectangle(gx_device * dev, const gx_tile_bitmap * tile,
252
int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
255
fit_fill(dev, x, y, w, h);
256
if (czero != gx_no_color_index && cone != gx_no_color_index) {
257
fill_rect(x, y, w, h, czero);
258
czero = gx_no_color_index;
260
if (tile->raster == bmWidthBytes && tile->size.y <= bmHeight &&
261
(px | py) == 0 && cone != gx_no_color_index
262
) { /* We can do this much more efficiently */
263
/* by using the internal algorithms of copy_mono */
264
/* and gx_default_tile_rectangle. */
265
int width = tile->size.x;
266
int height = tile->size.y;
267
int rwidth = tile->rep_width;
268
int irx = ((rwidth & (rwidth - 1)) == 0 ? /* power of 2 */
271
int ry = y % tile->rep_height;
272
int icw = width - irx;
273
int ch = height - ry;
274
int ex = x + w, ey = y + h;
275
int fex = ex - width, fey = ey - height;
278
select_brush((int)cone);
280
if (tile->id != wdev->bm_id || tile->id == gx_no_bitmap_id) {
281
wdev->bm_id = tile->id;
282
SetBitmapBits(wdev->hbmmono,
283
(DWORD) (bmWidthBytes * tile->size.y),
284
(BYTE *) tile->data);
286
#define copy_tile(srcx, srcy, tx, ty, tw, th)\
287
BitBlt(wdev->hdcbit, tx, ty, tw, th, wdev->hdcmono, srcx, srcy, rop_write_at_1s)
293
copy_tile(irx, ry, x, cy, w, ch);
295
copy_tile(irx, ry, x, cy, icw, ch);
298
copy_tile(0, ry, cx, cy, width, ch);
302
copy_tile(0, ry, cx, cy, ex - cx, ch);
305
if ((cy += ch) >= ey)
307
ch = (cy > fey ? ey - cy : height);
311
win_update((gx_device_win *) dev);
314
return gx_default_tile_rectangle(dev, tile, x, y, w, h, czero, cone, px, py);
318
/* Copy a monochrome bitmap. The colors are given explicitly. */
319
/* Color = gx_no_color_index means transparent (no effect on the image). */
321
win_ddb_copy_mono(gx_device * dev,
322
const byte * base, int sourcex, int raster, gx_bitmap_id id,
323
int x, int y, int w, int h,
324
gx_color_index zero, gx_color_index one)
327
const byte *ptr_line;
328
int width_bytes, height;
329
DWORD rop = rop_write_at_1s;
331
BYTE aBit[bmWidthBytes * bmHeight];
334
fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
337
base += sourcex >> 3;
340
/* Break up large transfers into smaller ones. */
341
while ((endx = sourcex + w) > bmWidthBits) {
342
int lastx = (endx - 1) & -bmWidthBits;
343
int subw = endx - lastx;
344
int code = win_ddb_copy_mono(dev, base, lastx,
345
raster, gx_no_bitmap_id,
346
x + lastx - sourcex, y,
353
while (h > bmHeight) {
357
code = win_ddb_copy_mono(dev, base + h * raster, sourcex,
358
raster, gx_no_bitmap_id,
359
x, y + h, w, bmHeight, zero, one);
364
width_bytes = (sourcex + w + 7) >> 3;
367
if (zero == gx_no_color_index) {
368
if (one == gx_no_color_index)
372
rop = rop_write_0_at_1s;
376
if (one == gx_no_color_index) {
378
rop = rop_write_at_0s;
379
} else { /* Pre-clear the rectangle to zero */
380
fill_rect(x, y, w, h, zero);
386
if (id != wdev->bm_id || id == gx_no_bitmap_id) {
388
if (raster == bmWidthBytes) { /* We can do the whole thing in a single transfer! */
389
SetBitmapBits(wdev->hbmmono,
390
(DWORD) (bmWidthBytes * h),
393
for (height = h; height--;
394
ptr_line += raster, aptr += bmWidthBytes
395
) { /* Pack the bits into the bitmap. */
396
switch (width_bytes) {
398
memcpy(aptr, ptr_line, width_bytes);
401
aptr[3] = ptr_line[3];
403
aptr[2] = ptr_line[2];
405
aptr[1] = ptr_line[1];
407
aptr[0] = ptr_line[0];
410
SetBitmapBits(wdev->hbmmono,
411
(DWORD) (bmWidthBytes * h),
415
BitBlt(wdev->hdcbit, x, y, w, h, wdev->hdcmono, sourcex, 0, rop);
416
win_update((gx_device_win *) dev);
421
/* Copy a color pixel map. This is just like a bitmap, except that */
422
/* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
424
win_ddb_copy_color(gx_device * dev,
425
const byte * base, int sourcex, int raster, gx_bitmap_id id,
426
int x, int y, int w, int h)
428
fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
430
if (gx_device_has_color(dev)) {
431
switch (dev->color_info.depth) {
435
int skip = raster - w;
436
const byte *sptr = base + sourcex;
440
if (x < 0 || x + w > dev->width)
441
return_error(gs_error_rangecheck);
442
for (yi = y; yi - y < h; yi++) {
443
for (xi = x; xi - x < w; xi++) {
446
SetPixel(wdev->hdcbit, xi, yi, PALETTEINDEX(color));
453
{ /* color device, four bits per pixel */
454
const byte *line = base + (sourcex >> 1);
455
int dest_y = y, end_x = x + w;
459
while (h--) { /* for each line */
460
const byte *source = line;
461
register int dest_x = x;
463
if (sourcex & 1) { /* odd nibble first */
464
int color = *source++ & 0xf;
466
SetPixel(wdev->hdcbit, dest_x, dest_y, PALETTEINDEX(color));
469
/* Now do full bytes */
470
while (dest_x < end_x) {
471
int color = *source >> 4;
473
SetPixel(wdev->hdcbit, dest_x, dest_y, PALETTEINDEX(color));
475
if (dest_x < end_x) {
476
color = *source++ & 0xf;
477
SetPixel(wdev->hdcbit, dest_x, dest_y, PALETTEINDEX(color));
487
return (-1); /* panic */
490
/* monochrome device: one bit per pixel */
491
{ /* bitmap is the same as win_copy_mono: one bit per pixel */
492
win_ddb_copy_mono(dev, base, sourcex, raster, id, x, y, w, h,
494
(gx_color_index) (dev->color_info.depth == 8 ? 63 : dev->color_info.max_gray));
496
win_update((gx_device_win *) dev);
500
/* ------ Windows-specific device procedures ------ */
503
/* Copy the bitmap to the clipboard. */
505
win_ddb_copy_to_clipboard(gx_device_win * dev)
506
{ /* make somewhere to put it and copy */
507
HDC hdcbit = wdev->hdcbit;
508
HBITMAP bitmap = CreateCompatibleBitmap(hdcbit, dev->width,
512
/* there is enough memory and the bitmaps OK */
513
HDC mem = CreateCompatibleDC(hdcbit);
515
SelectObject(mem, bitmap);
516
BitBlt(mem, 0, 0, dev->width, dev->height,
517
hdcbit, 0, 0, SRCCOPY);
519
/* copy it to the clipboard */
520
OpenClipboard(wdev->hwndimg);
522
SetClipboardData(CF_BITMAP, bitmap);
523
SetClipboardData(CF_PALETTE, CreatePalette(wdev->limgpalette));
529
/* Repaint a section of the window. */
531
win_ddb_repaint(gx_device_win * dev, HDC hdc, int dx, int dy, int wx, int wy,
534
BitBlt(hdc, dx, dy, wx, wy, wdev->hdcbit, sx, sy, SRCCOPY);
538
/* Allocate the backing bitmap. */
540
win_ddb_alloc_bitmap(gx_device_win * dev, gx_device * param_dev)
545
hdc = GetDC(wdev->hwndimg);
547
wdev->hbitmap = CreateCompatibleBitmap(hdc,
548
param_dev->width, param_dev->height);
549
if (wdev->hbitmap != (HBITMAP) NULL)
552
ReleaseDC(wdev->hwndimg, hdc);
553
return win_nomemory();
555
errprintf("\nNot enough memory for bitmap. Halving resolution... ");
556
param_dev->x_pixels_per_inch /= 2;
557
param_dev->y_pixels_per_inch /= 2;
558
param_dev->width /= 2;
559
param_dev->height /= 2;
562
wdev->hdcbit = CreateCompatibleDC(hdc); /* create Device Context for drawing */
563
SelectObject(wdev->hdcbit, wdev->hbitmap);
564
ReleaseDC(wdev->hwndimg, hdc);
569
/* Free the backing bitmap. */
571
win_ddb_free_bitmap(gx_device_win * dev)
573
DeleteDC(wdev->hdcbit); /* must do this first */
574
DeleteObject(wdev->hbitmap);
578
/* ------ Internal routines ------ */
584
win_addtool(gx_device_win_ddb * wdev, int i)
586
wdev->hpens[i] = CreatePen(PS_SOLID, 1, PALETTEINDEX(i));
587
wdev->hbrushs[i] = CreateSolidBrush(PALETTEINDEX(i));
592
win_maketools(gx_device_win_ddb * wdev, HDC hdc)
596
wdev->hpensize = (1 << (wdev->color_info.depth)) * sizeof(HPEN);
597
wdev->hpens = (HPEN *) gs_malloc(wdev->memory, 1, wdev->hpensize,
598
"win_maketools(pens)");
599
wdev->hbrushsize = (1 << (wdev->color_info.depth)) * sizeof(HBRUSH);
600
wdev->hbrushs = (HBRUSH *) gs_malloc(wdev->memory, 1, wdev->hbrushsize,
601
"win_maketools(brushes)");
602
if (wdev->hpens && wdev->hbrushs) {
603
for (i = 0; i < wdev->nColors; i++)
604
win_addtool(wdev, i);
606
wdev->hpen = wdev->hpens[0];
607
SelectObject(hdc, wdev->hpen);
609
wdev->hbrush = wdev->hbrushs[0];
610
SelectObject(hdc, wdev->hbrush);
616
win_destroytools(gx_device_win_ddb * wdev)
620
for (i = 0; i < wdev->nColors; i++) {
621
DeleteObject(wdev->hpens[i]);
622
DeleteObject(wdev->hbrushs[i]);
624
gs_free(wdev->memory, (char *)wdev->hbrushs, 1, wdev->hbrushsize,
625
"win_destroytools(brushes)");
626
gs_free(wdev->memory, (char *)wdev->hpens, 1, wdev->hpensize,
627
"win_destroytools(pens)");