home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / sharewar / dos / program / gs300sr1 / gs300sr1.exe / GDEVWDIB.C < prev    next >
C/C++ Source or Header  |  1994-08-01  |  17KB  |  566 lines

  1. /* Copyright (C) 1992, 1993, 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevwdib.c */
  20. /* MS Windows 3.n driver for Ghostscript using a DIB for buffering. */
  21. #include "gdevmswn.h"
  22. #include "gxdevmem.h"
  23. #ifdef __DLL__
  24. #include "gsdll.h"
  25. #endif
  26.  
  27. #ifdef __WIN32__
  28. #  define USE_SEGMENTS 0
  29. #else
  30. #  define USE_SEGMENTS 1
  31. #endif
  32.  
  33. /* Make sure we cast to the correct structure type. */
  34. typedef struct gx_device_win_dib_s gx_device_win_dib;
  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_map_rgb_color(win_dib_map_rgb_color);
  45. private dev_proc_fill_rectangle(win_dib_fill_rectangle);
  46. private dev_proc_copy_mono(win_dib_copy_mono);
  47. private dev_proc_copy_color(win_dib_copy_color);
  48. /* Windows-specific procedures */
  49. private win_proc_copy_to_clipboard(win_dib_copy_to_clipboard);
  50. private win_proc_repaint(win_dib_repaint);
  51. private win_proc_alloc_bitmap(win_dib_alloc_bitmap);
  52. private win_proc_free_bitmap(win_dib_free_bitmap);
  53.  
  54. /* The device descriptor */
  55. struct gx_device_win_dib_s {
  56.     gx_device_common;
  57.     gx_device_win_common;
  58.  
  59. #if USE_SEGMENTS
  60.     /* The following help manage the division of the DIB */
  61.     /* into 64K segments.  Each block of y_block scan lines */
  62.     /* starting at y_base mod 64K falls in a single segment. */
  63.     /* Since the raster is a power of 2, y_block is a power of 2. */
  64.  
  65.     int y_block;
  66.     int y_base;
  67.     int y_mask;        /* y_block - 1 */
  68. #endif        /* USE_SEGMENTS */
  69.  
  70.     HGLOBAL hmdata;
  71.     gx_device_memory mdev;
  72. };
  73. private gx_device_procs win_dib_procs = {
  74.     win_dib_open,
  75.     win_dib_get_initial_matrix,
  76.     win_sync_output,
  77.     win_output_page,
  78.     win_dib_close,
  79.     win_dib_map_rgb_color,
  80.     win_map_color_rgb,
  81.     win_dib_fill_rectangle,
  82.     NULL,            /* tile_rectangle */
  83.     win_dib_copy_mono,
  84.     win_dib_copy_color,
  85.     NULL,            /* draw_line */
  86.     NULL,            /* get_bits */
  87.     win_get_params,
  88.     win_put_params,
  89.     NULL,            /* map_cmyk_color */
  90.     win_get_xfont_procs
  91. };
  92. #ifdef __DLL__
  93. gx_device_win_dib gs_mswindll_device = {
  94.     sizeof(gx_device_win_dib),
  95.     &win_dib_procs,
  96.     "mswindll",
  97.     INITIAL_WIDTH, INITIAL_HEIGHT,     /* win_open() fills these in later */
  98.     INITIAL_RESOLUTION, INITIAL_RESOLUTION,    /* win_open() fills these in later */
  99.     no_margins,
  100.     dci_black_and_white,
  101.     dev_init_misc, { 0 },        /* not open yet */
  102.     0,                /* BitsPerPixel */
  103.     5000,                /* UpdateInterval (in milliseconds) */
  104.     "\0",                /* GSVIEW_STR */
  105.     1,                /* This is a DLL device */
  106.     2,                /* nColors */
  107.     win_dib_copy_to_clipboard,
  108.     win_dib_repaint,
  109.     win_dib_alloc_bitmap,
  110.     win_dib_free_bitmap
  111. };
  112. #endif
  113. gx_device_win_dib gs_mswin_device = {
  114.     sizeof(gx_device_win_dib),
  115.     &win_dib_procs,
  116.     "mswin",
  117.     INITIAL_WIDTH, INITIAL_HEIGHT,     /* win_open() fills these in later */
  118.     INITIAL_RESOLUTION, INITIAL_RESOLUTION,    /* win_open() fills these in later */
  119.     no_margins,
  120.     dci_black_and_white,
  121.     dev_init_misc, { 0 },        /* not open yet */
  122.     0,                /* BitsPerPixel */
  123.     5000,                /* UpdateInterval (in milliseconds) */
  124.     "\0",                /* GSVIEW_STR */
  125.     0,                /* not a DLL device */
  126.     2,                /* nColors */
  127.     win_dib_copy_to_clipboard,
  128.     win_dib_repaint,
  129.     win_dib_alloc_bitmap,
  130.     win_dib_free_bitmap
  131. };
  132.  
  133. /* forward declarations */
  134. private HGLOBAL win_dib_make_dib(gx_device_win *dev, int orgx, int orgy, int wx, int wy);
  135.  
  136.  
  137. /* Open the win_dib driver */
  138. private int
  139. win_dib_open(gx_device *dev)
  140. {
  141.     int code = win_open(dev);
  142.     if ( code < 0 ) return code;
  143.  
  144.     if ( gdev_mem_device_for_bits(dev->color_info.depth) == 0 )
  145.     {    win_close(dev);
  146.         return gs_error_rangecheck;
  147.     }
  148.     code = win_dib_alloc_bitmap((gx_device_win *)dev, dev);
  149. #ifdef __DLL__
  150.     if ( code < 0 ) return code;
  151.     if (wdev->dll) {
  152.         /* notify caller about new device */
  153.         (*pgsdll_callback)(GSDLL_DEVICE, (unsigned char *)dev, 1);
  154.         return 0;    /* caller will handle displaying */
  155.     }
  156. #endif
  157.     return code;
  158. }
  159.  
  160. /* Get the initial matrix.  DIBs, unlike most displays, */
  161. /* put (0,0) in the lower left corner. */
  162. private void
  163. win_dib_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
  164. {    pmat->xx = dev->x_pixels_per_inch / 72.0;
  165.     pmat->xy = 0;
  166.     pmat->yx = 0;
  167.     pmat->yy = dev->y_pixels_per_inch / 72.0;
  168.     pmat->tx = 0;
  169.     pmat->ty = 0;
  170. }
  171.  
  172. /* Close the win_dib driver */
  173. private int
  174. win_dib_close(gx_device *dev)
  175. {int code;
  176.     win_dib_free_bitmap((gx_device_win *)dev);
  177.     code = win_close(dev);
  178. #ifdef __DLL__
  179.         if (wdev->dll) {
  180.             (*pgsdll_callback)(GSDLL_DEVICE, (unsigned char *)dev, 0);
  181.         }
  182. #endif
  183.     return code;
  184. }
  185.  
  186. /* Map a r-g-b color to the colors available under Windows */
  187. private gx_color_index
  188. win_dib_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
  189.   gx_color_value b)
  190. {    int i = wdev->nColors;
  191.     gx_color_index color = win_map_rgb_color(dev, r, g, b);
  192.     if ( color != i ) return color;
  193.  
  194.     return color;
  195. }
  196.  
  197. #define wmdev ((gx_device *)&wdev->mdev)
  198. #define wmproc(proc) (*dev_proc(&wdev->mdev, proc))
  199.  
  200. #if USE_SEGMENTS
  201.  
  202. /* The drawing routines must all be careful not to cross */
  203. /* a segment boundary. */
  204.  
  205. #define single_block(y, h)\
  206.   !(((y - wdev->y_base) ^ (y - wdev->y_base + h - 1)) & ~wdev->y_mask)
  207.  
  208. #define BEGIN_BLOCKS\
  209. {    int by, bh, left = h;\
  210.     for ( by = y; left > 0; by += bh, left -= bh )\
  211.     {    bh = wdev->y_block - (by & wdev->y_mask);\
  212.         if ( bh > left ) bh = left;
  213. #define END_BLOCKS\
  214.     }\
  215. }
  216.  
  217. #endif        /* (!)USE_SEGMENTS */
  218.  
  219. /* Fill a rectangle. */
  220. private int
  221. win_dib_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  222.   gx_color_index color)
  223. {
  224. #if USE_SEGMENTS
  225.     if ( single_block(y, h) )
  226.     {    wmproc(fill_rectangle)(wmdev, x, y, w, h, color);
  227.     }
  228.     else
  229.     {    /* Divide the transfer into blocks. */
  230.         BEGIN_BLOCKS
  231.             wmproc(fill_rectangle)(wmdev, x, by, w, bh, color);
  232.         END_BLOCKS
  233.     }
  234. #else
  235.     wmproc(fill_rectangle)(wmdev, x, y, w, h, color);
  236. #endif
  237.     win_update((gx_device_win *)dev);
  238.     return 0;
  239. }
  240.  
  241. /* Copy a monochrome bitmap.  The colors are given explicitly. */
  242. /* Color = gx_no_color_index means transparent (no effect on the image). */
  243. private int
  244. win_dib_copy_mono(gx_device *dev,
  245.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  246.   int x, int y, int w, int h,
  247.   gx_color_index zero, gx_color_index one)
  248. {
  249. #if USE_SEGMENTS
  250.     if ( single_block(y, h) )
  251.     {    wmproc(copy_mono)(wmdev, base, sourcex, raster, id,
  252.                      x, y, w, h, zero, one);
  253.     }
  254.     else
  255.     {    /* Divide the transfer into blocks. */
  256.         const byte *source = base;
  257.         BEGIN_BLOCKS
  258.             wmproc(copy_mono)(wmdev, source, sourcex, raster,
  259.                       gx_no_bitmap_id, x, by, w, bh,
  260.                       zero, one);
  261.             source += bh * raster;
  262.         END_BLOCKS
  263.     }
  264. #else
  265.     wmproc(copy_mono)(wmdev, base, sourcex, raster, id,
  266.               x, y, w, h, zero, one);
  267. #endif
  268.     win_update((gx_device_win *)dev);
  269.     return 0;
  270. }
  271.  
  272. /* Copy a color pixel map.  This is just like a bitmap, except that */
  273. /* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
  274. private int
  275. win_dib_copy_color(gx_device *dev,
  276.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  277.   int x, int y, int w, int h)
  278. {
  279. #if USE_SEGMENTS
  280.     if ( single_block(y, h) )
  281.     {    wmproc(copy_color)(wmdev, base, sourcex, raster, id,
  282.                    x, y, w, h);
  283.     }
  284.     else
  285.     {    /* Divide the transfer into blocks. */
  286.         const byte *source = base;
  287.         BEGIN_BLOCKS
  288.             wmproc(copy_color)(wmdev, source, sourcex, raster,
  289.                        gx_no_bitmap_id, x, by, w, bh);
  290.             source += by * raster;
  291.         END_BLOCKS
  292.     }
  293. #else
  294.     wmproc(copy_color)(wmdev, base, sourcex, raster, id,
  295.                x, y, w, h);
  296. #endif
  297.     win_update((gx_device_win *)dev);
  298.     return 0;
  299. }
  300.  
  301. /* ------ DLL device procedures ------ */
  302. #ifdef __DLL__
  303. /* make a copy of the device bitmap and return shared memory handle to it */
  304. /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
  305. HGLOBAL WINAPI
  306. gsdll_copy_dib(unsigned char *device)
  307. {
  308. gx_device_win *dev = (gx_device_win *)device;
  309.     return win_dib_make_dib(dev, 0, 0, wdev->width, wdev->height);
  310. }
  311.  
  312. /* make a copy of the device palette and return a handle to it */
  313. /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
  314. HPALETTE WINAPI
  315. gsdll_copy_palette(unsigned char *device)
  316. {
  317. gx_device_win *dev = (gx_device_win *)device;
  318.     return CreatePalette(wdev->limgpalette);
  319. }
  320.  
  321. /* copy the rectangle src from the device bitmap */
  322. /* to the rectangle dest on the device given by hdc */
  323. /* hdc must be a device context for a device (NOT a bitmap) */
  324. /* device is a pointer to Ghostscript device from GSDLL_DEVICE message */
  325. void WINAPI
  326. gsdll_draw(unsigned char *device, HDC hdc, LPRECT dest, LPRECT src)
  327. {
  328. gx_device_win *dev = (gx_device_win *)device;
  329. HPALETTE oldpalette;
  330.     if (wdev->nColors > 0) {
  331.         oldpalette = SelectPalette(hdc,wdev->himgpalette,NULL);
  332.         RealizePalette(hdc);
  333.     }
  334.     win_dib_repaint(wdev,hdc, src->left, src->top,
  335.         src->right-src->left, src->bottom-src->top,  
  336.         dest->left, dest->top);
  337.     if (wdev->nColors > 0) {
  338.         SelectPalette(hdc,oldpalette,NULL);
  339.     }
  340.     return;
  341. }
  342. #endif /* __DLL__ */
  343.  
  344. /* ------ Windows-specific device procedures ------ */
  345.  
  346.  
  347. /* Repaint a section of the window. */
  348. private void
  349. win_dib_repaint(gx_device_win *dev, HDC hdc, int dx, int dy, int wx, int wy,
  350.   int sx, int sy)
  351. {    struct bmi_s {
  352.         BITMAPINFOHEADER h;
  353.         ushort pal_index[256];
  354.     } bmi;
  355.     int i;
  356.  
  357.     bmi.h.biSize = sizeof(bmi.h);
  358.     bmi.h.biWidth = wdev->mdev.width;
  359.     bmi.h.biHeight = wy;
  360.     bmi.h.biPlanes = 1;
  361.     bmi.h.biBitCount = dev->color_info.depth;
  362.     bmi.h.biCompression = 0;
  363.     bmi.h.biSizeImage = 0;            /* default */
  364.     bmi.h.biXPelsPerMeter = 0;        /* default */
  365.     bmi.h.biYPelsPerMeter = 0;        /* default */
  366.     if (dev->BitsPerPixel <= 8) {
  367.         bmi.h.biClrUsed = wdev->nColors;
  368.         bmi.h.biClrImportant = wdev->nColors;
  369.         for ( i = 0; i < wdev->nColors; i++ )
  370.         bmi.pal_index[i] = i;
  371.         SetDIBitsToDevice(hdc, dx, dy, wx, wy,
  372.         sx, 0, 0, wy,
  373.         wdev->mdev.line_ptrs[wdev->height - (sy + wy)],
  374.         (BITMAPINFO FAR *)&bmi, DIB_PAL_COLORS);
  375.     }
  376.     else {
  377.         bmi.h.biClrUsed = 0;
  378.         bmi.h.biClrImportant = 0;
  379.         SetDIBitsToDevice(hdc, dx, dy, wx, wy,
  380.         sx, 0, 0, wy,
  381.         wdev->mdev.line_ptrs[wdev->height - (sy + wy)],
  382.         (BITMAPINFO FAR *)&bmi, DIB_RGB_COLORS);
  383.     }
  384. }
  385.  
  386.  
  387. /* This makes a DIB that contains all or part of the bitmap. */
  388. /* The bitmap pixel orgx must start on a byte boundary. */
  389. private HGLOBAL
  390. win_dib_make_dib(gx_device_win *dev, int orgx, int orgy, int wx, int wy)
  391. {
  392. #define xwdev ((gx_device_win_dib *)dev)
  393.     gx_color_value prgb[3];
  394.     HGLOBAL hglobal;
  395.     BYTE FAR *pDIB;
  396.     BITMAPINFOHEADER FAR *pbmih;
  397.     RGBQUAD FAR *pColors;
  398.     BYTE huge *pBits;
  399.     BYTE huge *pLine;
  400.     ulong bitmapsize;
  401.     int i;
  402.     int loffset;         /* byte offset to start of line */
  403.     UINT lwidth;        /* line width in bytes rounded up to multiple of 4 bytes */
  404.     UINT lseg;        /* bytes remaining in this segment */
  405.     int palcount;
  406.  
  407.     if (orgx + wx > wdev->width)
  408.         wx = wdev->width - orgx;
  409.     if (orgy + wy > wdev->height)
  410.         wy = wdev->height - orgy;
  411.  
  412.     loffset = orgx * wdev->color_info.depth / 8;
  413.     lwidth =  ((wx * wdev->color_info.depth + 31) & ~31) >> 3;
  414.     bitmapsize = (long)lwidth * wy;
  415.  
  416.     if (wdev->color_info.depth == 24)
  417.         palcount = 0;
  418.     else
  419.         palcount = wdev->nColors;
  420.  
  421.     hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER) 
  422.         + sizeof(RGBQUAD) * palcount + bitmapsize);
  423.     if (hglobal == (HGLOBAL)NULL) {
  424.         MessageBeep(-1);
  425.         return(HGLOBAL)NULL;
  426.     }
  427.     pDIB = (BYTE FAR *)GlobalLock(hglobal);
  428.     if (pDIB == (BYTE FAR *)NULL) {
  429.         MessageBeep(-1);
  430.         return(HGLOBAL)NULL;
  431.     }
  432.     pbmih = (BITMAPINFOHEADER FAR *)(pDIB); 
  433.     pColors = (RGBQUAD FAR *)(pDIB + sizeof(BITMAPINFOHEADER));
  434.     pBits = (BYTE huge *)(pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palcount);
  435.  
  436.     pbmih->biSize = sizeof(BITMAPINFOHEADER);
  437.     pbmih->biWidth = wx;
  438.     pbmih->biHeight = wy;
  439.     pbmih->biPlanes = 1;
  440.     pbmih->biBitCount = wdev->color_info.depth;
  441.     pbmih->biCompression = 0;
  442.     pbmih->biSizeImage = 0;            /* default */
  443.     pbmih->biXPelsPerMeter = (DWORD)(dev->x_pixels_per_inch / 25.4 * 1000);
  444.     pbmih->biYPelsPerMeter = (DWORD)(dev->y_pixels_per_inch / 25.4 * 1000);
  445.     pbmih->biClrUsed = palcount;
  446.     pbmih->biClrImportant = palcount;
  447.     for ( i = 0; i < palcount; i++ ) {
  448.         win_map_color_rgb((gx_device *)wdev, (gx_color_index)i, prgb);
  449.         pColors[i].rgbRed   = win_color_value(prgb[0]);
  450.         pColors[i].rgbGreen = win_color_value(prgb[1]);
  451.         pColors[i].rgbBlue  = win_color_value(prgb[2]);
  452.         pColors[i].rgbReserved = 0;
  453.     }
  454.  
  455.     pLine = pBits;
  456.     for ( i = orgy; i < orgy + wy; i++ ) {
  457. #if USE_SEGMENTS
  458.         /* Window 3.1 has hmemcpy, but 3.0 doesn't */
  459.         lseg = (UINT)(-OFFSETOF(pLine));   /* remaining bytes in this segment */
  460.         if (lseg >= lwidth) { 
  461.            _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lwidth);
  462.         }
  463.         else { /* break up transfer to avoid crossing segment boundary */
  464.            _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lseg);
  465.            _fmemcpy(pLine+lseg, xwdev->mdev.line_ptrs[i] + loffset + lseg, lwidth - lseg);
  466.         }
  467. #else
  468.         memcpy(pLine, xwdev->mdev.line_ptrs[i], lwidth);
  469. #endif
  470.         pLine += lwidth;
  471.     }
  472.  
  473.     GlobalUnlock(hglobal);
  474.     return hglobal;
  475. }
  476.  
  477.  
  478. /* Copy the bitmap to the clipboard. */
  479. private void
  480. win_dib_copy_to_clipboard(gx_device_win *dev)
  481. {
  482.     HGLOBAL hglobal;
  483.     hglobal = win_dib_make_dib(dev, 0, 0, wdev->width, wdev->height);
  484.     if (hglobal == (HGLOBAL)NULL) {
  485.         MessageBox(wdev->hwndimg, "Not enough memory to Copy to Clipboard", 
  486.         szAppName, MB_OK | MB_ICONEXCLAMATION);
  487.         return;
  488.     }
  489.     OpenClipboard(dev->hwndimg);
  490.     EmptyClipboard();
  491.     SetClipboardData(CF_DIB, hglobal);
  492.     if (wdev->nColors > 0)
  493.         SetClipboardData(CF_PALETTE, CreatePalette(wdev->limgpalette));
  494.     CloseClipboard();
  495. }
  496.  
  497.  
  498. /* Allocate the backing bitmap. */
  499. private int
  500. win_dib_alloc_bitmap(gx_device_win *dev, gx_device *param_dev)
  501. {
  502.     int width;
  503.     gx_device_memory mdev;
  504.     HGLOBAL hmdata;
  505.     byte huge *base;
  506.     byte huge *ptr_base;
  507.     ulong data_size;
  508.     uint ptr_size;
  509.     uint raster;
  510.  
  511.     /* Round up the width so that the scan line size is a power of 2. */
  512.     if (dev->color_info.depth == 24) {
  513.         width = param_dev->width * 3 - 1;
  514.         while ( width & (width + 1) ) width |= width >> 1;
  515.         width = (width + 1) / 3;
  516.     }
  517.     else {
  518.         width = param_dev->width - 1;
  519.         while ( width & (width + 1) ) width |= width >> 1;
  520.         width++;
  521.     }
  522.  
  523.     /* Finish initializing the DIB. */
  524.  
  525.     gs_make_mem_device(&mdev, gdev_mem_device_for_bits(dev->color_info.depth), 0, 0);
  526.     mdev.width = width;
  527.     mdev.height = param_dev->height;
  528.     mdev.target = (gx_device *)dev;
  529.     raster = gdev_mem_raster(&mdev);
  530.     data_size = (ulong)raster * mdev.height;
  531.     ptr_size = sizeof(byte **) * mdev.height;
  532.     hmdata = GlobalAlloc(0, raster + data_size + ptr_size * 2);
  533.     if ( hmdata == 0 )
  534.         return win_nomemory();
  535.  
  536.     /* Nothing can go wrong now.... */
  537.  
  538.     wdev->hmdata = hmdata;
  539.     base = GlobalLock(hmdata);
  540. #if USE_SEGMENTS
  541.     /* Adjust base so scan lines, and the pointer table, */
  542.     /* don't cross a segment boundary. */
  543.     base += (-PTR_OFF(base) & (raster - 1));
  544.     ptr_base = base + data_size;
  545.     if ( PTR_OFF(ptr_base + ptr_size) < ptr_size )
  546.         base += (uint)-PTR_OFF(ptr_base);
  547.     wdev->y_block = 0x10000L / raster;
  548.     wdev->y_mask = wdev->y_block - 1;
  549.     if ( (wdev->y_base = PTR_OFF(base)) != 0 )
  550.         wdev->y_base = -(PTR_OFF(base) / raster);
  551. #endif
  552.     wdev->mdev = mdev;
  553.     wdev->mdev.base = (byte *)base;
  554.     wmproc(open_device)((gx_device *)&wdev->mdev);
  555.     return 0;
  556. }
  557.  
  558.  
  559. /* Free the backing bitmap. */
  560. private void
  561. win_dib_free_bitmap(gx_device_win *dev)
  562. {    HGLOBAL hmdata = wdev->hmdata;
  563.     GlobalUnlock(hmdata);
  564.     GlobalFree(hmdata);
  565. }
  566.