Ticket #87: 0004-Rewrite-cairo-os2-surface.c-to-remove-app-specific-c.patch

File 0004-Rewrite-cairo-os2-surface.c-to-remove-app-specific-c.patch, 107.9 KB (added by dmik, 8 years ago)
  • src/cairo-os2-private.h

    From 7d8090e2808cf0e1172fb80239978c97fea5d659 Mon Sep 17 00:00:00 2001
    From: Dave Yeo <dave.r.yeo@gmail.com>
    Date: Wed, 31 Aug 2011 20:41:18 -0700
    Subject: [PATCH 4/5] Rewrite cairo-os2-surface.c to remove app-specific code
     and add new features.
    
    Signed-off-by: Dave Yeo <dave.r.yeo@gmail.com>
    ---
     src/cairo-os2-private.h |  123 ++-
     src/cairo-os2-surface.c | 2494 ++++++++++++++++++++++++++---------------------
     src/cairo-os2.h         |   72 +-
     3 files changed, 1548 insertions(+), 1141 deletions(-)
    
    diff --git a/src/cairo-os2-private.h b/src/cairo-os2-private.h
    index 829dd3c..bc02db9 100644
    a b  
    22/* cairo - a vector graphics library with display and print output
    33 *
    44 * Copyright (c) 2005-2006 netlabs.org
     5 * Copyright (c) 2010-2011 Rich Walsh
    56 *
    67 * This library is free software; you can redistribute it and/or
    78 * modify it either under the terms of the GNU Lesser General Public
     
    3334 *
    3435 * Contributor(s):
    3536 *     Peter Weilbacher <mozilla@Weilbacher.org>
     37 *     Rich Walsh <rich@e-vertise.com>
    3638 */
    3739
    3840#ifndef CAIRO_OS2_PRIVATE_H
    3941#define CAIRO_OS2_PRIVATE_H
    4042
    41 #include "cairo-os2.h"
    4243#include "cairoint.h"
     44#include "cairo-os2.h"
     45
     46/**
     47 * Unpublished API:
     48 *   GpiEnableYInversion = PMGPI.723
     49 *   GpiQueryYInversion = PMGPI.726
     50 **/
     51
     52BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);
     53LONG APIENTRY GpiQueryYInversion (HPS hps);
     54
     55/**
     56 * Function declaration for GpiDrawBits () (missing from OpenWatcom headers)
     57 **/
     58#ifdef __WATCOMC__
     59LONG APIENTRY GpiDrawBits (HPS hps, PVOID pBits,
     60                           PBITMAPINFO2 pbmiInfoTable,
     61                           LONG lCount, PPOINTL aptlPoints,
     62                           LONG lRop, ULONG flOptions);
     63#endif
     64
     65/**
     66 * Support for dynamically loading dive.dll -
     67 * use to avoid both compile-time and run-time dependencies
     68 **/
     69
     70#ifdef OS2_DYNAMIC_DIVE
     71typedef ULONG (APIENTRY *DiveQuery_t)(void*, ULONG);
     72typedef ULONG (APIENTRY *DiveOpen_t)(ULONG*, BOOL, VOID*);
     73typedef ULONG (APIENTRY *DiveClose_t)(ULONG);
     74typedef ULONG (APIENTRY *DiveAcquire_t)(ULONG, RECTL*);
     75typedef ULONG (APIENTRY *DiveDeacquire_t)(ULONG);
     76
     77#define ORD_DIVEQUERYCAPS             1
     78#define ORD_DIVEOPEN                  2
     79#define ORD_DIVECLOSE                 3
     80#define ORD_DIVEACQUIREFRAMEBUFFER    6
     81#define ORD_DIVEDEACQUIREFRAMEBUFFER  8
     82#endif
     83
     84/**
     85 * OS/2 surface subtypes
     86 **/
     87
     88typedef enum _cairo_os2_subtype {
     89    CAIRO_OS2_SUBTYPE_NULL = 0,
     90    CAIRO_OS2_SUBTYPE_IMAGE
     91} cairo_os2_subtype_t;
     92
     93/**
     94 * MMIO bitmap formats defined here to avoid #including
     95 * multiple headers that aren't otherwise needed.
     96 **/
     97
     98#ifndef FOURCC_BGR4
     99#define FOURCC_BGR4 0x34524742
     100#endif
     101#ifndef FOURCC_BGR3
     102#define FOURCC_BGR3 0x33524742
     103#endif
     104
     105/**
     106 * cairo_os2_surface_t:
     107 *
     108 * @base: Standard #cairo_surface_t structure.
     109 * @subtype: This #cairo_os2_surface-specific value identifies whether the
     110 *   surface will be used for images or as a dummy with no image.
     111 * @width: Width of the surface in pixels.
     112 * @height: Height of the surface in pixels.
     113 * @hps: PM presentation space handle whose ownership is retained by the
     114 *   caller.  Required for printing surfaces, optional otherwise.
     115 * @format: Standard #cairo_format_t value.
     116 * @content: Standard #cairo_content_t value.
     117 * @hwnd: PM window handle whose ownership is retained by the caller.
     118 *   Required for surfaces associated with a window and ignored otherwise.
     119 * @stride: Distance in bytes from the start of one scan line to the next.
     120 * @data: Pointer to the memory #cairo_image_surface_t uses for its bitmap.
     121 *   It is allocated and freed by cairo_os2_surface_t and is not accessible
     122 *   outside this module.
     123 * @image: Pointer to the underlying image surface. It is only used for
     124 *   subtype %CAIRO_OS2_SUBTYPE_IMAGE.
     125 **/
     126
     127typedef struct _cairo_os2_surface {
     128    /* common data */
     129    cairo_surface_t         base;
     130    cairo_os2_subtype_t     subtype;
     131    int                     width;
     132    int                     height;
     133    HPS                     hps;
     134    cairo_format_t          format;
     135    cairo_content_t         content;
     136
     137    /* image surface data */
     138    HWND                    hwnd;
     139    int                     stride;
     140    unsigned char          *data;
     141    cairo_surface_t        *image;
    43142
    44 typedef struct _cairo_os2_surface
    45 {
    46     cairo_surface_t        base;
    47 
    48     /* Mutex semaphore to protect private fields from concurrent access */
    49     HMTX                   hmtx_use_private_fields;
    50     /* Private fields: */
    51     HPS                    hps_client_window;
    52     HWND                   hwnd_client_window;
    53     BITMAPINFO2            bitmap_info;
    54     unsigned char         *pixels;
    55     cairo_image_surface_t *image_surface;
    56     int                    pixel_array_lend_count;
    57     HEV                    hev_pixel_array_came_back;
    58 
    59     RECTL                  rcl_dirty_area;
    60     cairo_bool_t           dirty_area_present;
    61 
    62     /* General flags: */
    63     cairo_bool_t           blit_as_changes;
    64     cairo_bool_t           use_24bpp;
    65143} cairo_os2_surface_t;
    66144
    67145#endif /* CAIRO_OS2_PRIVATE_H */
     146
  • src/cairo-os2-surface.c

    diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
    index 74c0567..109eb44 100644
    a b  
    22/* cairo - a vector graphics library with display and print output
    33 *
    44 * Copyright (c) 2005-2006 netlabs.org
     5 * Copyright (c) 2010-2011 Rich Walsh
    56 *
    67 * This library is free software; you can redistribute it and/or
    78 * modify it either under the terms of the GNU Lesser General Public
     
    3334 *
    3435 * Contributor(s):
    3536 *     Peter Weilbacher <mozilla@Weilbacher.org>
    36  *     Rich Walsh <dragtext@e-vertise.com>
     37 *     Rich Walsh <rich@e-vertise.com>
    3738 */
    3839
    39 #include "cairoint.h"
    4040
     41/**
     42 * cairo_os2_surface:
     43 *
     44 * #cairo_os2_surface is a thin wrapper around #cairo_image_surface that
     45 * supports output to displays and native bitmaps.  It provides OS/2-specific
     46 * front-end functions and manages memory used by surface bitmaps.  Calls
     47 * to most backend functions are forwarded to the underlying image surface.
     48 **/
     49
     50#define INCL_DOS
     51#define INCL_WIN
     52#define INCL_GPI
     53#include <os2.h>
     54
     55#include <dive.h>
    4156#include "cairo-os2-private.h"
    4257#include "cairo-default-context-private.h"
    4358#include "cairo-error-private.h"
    4459
    45 /*
    46  * This function calls the allocation function depending on which
    47  * method was compiled into the library: it can be native allocation
    48  * (DosAllocMem/DosFreeMem) or C-Library based allocation (malloc/free).
    49  * Actually, for pixel buffers that we use this function for, cairo
    50  * uses _cairo_malloc_abc, so we use that here, too. And use the
    51  * change to check the size argument
    52  */
    53 void *_buffer_alloc (size_t a, size_t b, const unsigned int size)
    54 {
    55     size_t nbytes;
    56     void  *buffer = NULL;
    5760
    58     if (!a || !b || !size ||
    59         a >= INT32_MAX / b || a*b >= INT32_MAX / size) {
    60         return NULL;
    61     }
    62     nbytes = a * b * size;
     61/**
     62 *  Forward references to static helper functions
     63 **/
    6364
    64 #ifdef OS2_USE_PLATFORM_ALLOC
    65     /* Using OBJ_ANY on a machine that isn't configured for hi-mem
    66      * will cause ERROR_INVALID_PARAMETER.  If this occurs, or this
    67      * build doesn't have hi-mem enabled, fall back to using lo-mem.
    68      */
    69 #ifdef OS2_HIGH_MEMORY
    70     if (!DosAllocMem (&buffer, nbytes,
    71                       OBJ_ANY | PAG_READ | PAG_WRITE | PAG_COMMIT))
    72         return buffer;
    73 #endif
    74     if (DosAllocMem (&buffer, nbytes,
    75                      PAG_READ | PAG_WRITE | PAG_COMMIT))
    76         return NULL;
    77 #else
    78     /* Clear the malloc'd buffer the way DosAllocMem() does. */
    79     buffer = malloc (nbytes);
    80     if (buffer) {
    81         memset (buffer, 0, nbytes);
    82     }
    83 #endif
    84     return buffer;
    85 }
     65static cairo_status_t
     66_cairo_os2_surface_init_image (cairo_os2_surface_t *surface);
     67static unsigned char *
     68_cairo_os2_surface_alloc (unsigned int size);
     69static void
     70_cairo_os2_surface_free (void *buffer);
     71static cairo_status_t
     72_cairo_os2_surface_paint_32bpp (cairo_os2_surface_t *surface,
     73                                HPS                  hps,
     74                                RECTL               *src,
     75                                RECTL               *dst,
     76                                int                  count);
     77static cairo_status_t
     78_cairo_os2_surface_paint_24bpp (cairo_os2_surface_t *surface,
     79                                HPS                  hps,
     80                                RECTL               *src,
     81                                RECTL               *dst,
     82                                int                  count);
     83static cairo_status_t
     84_cairo_os2_surface_paint_dive (cairo_os2_surface_t *surface,
     85                               HPS                  hps,
     86                               RECTL               *rect,
     87                               int                  count);
     88static void
     89_cairo_os2_surface_dive_error (void);
    8690
    87 /*
    88  * This function selects the free function depending on which
    89  * allocation method was compiled into the library
    90  */
    91 void _buffer_free (void *buffer)
    92 {
    93 #ifdef OS2_USE_PLATFORM_ALLOC
    94     DosFreeMem (buffer);
    95 #else
    96     free (buffer);
    97 #endif
    98 }
    9991
    100 /*
    101  * The following part of the source file contains the code which might
    102  * be called the "core" of the OS/2 backend support. This contains the
    103  * OS/2 surface support functions and structures.
    104  */
     92/**
     93 * Module-level data
     94 **/
    10595
    106 /* Forward declaration */
    107 static const cairo_surface_backend_t cairo_os2_surface_backend;
     96static cairo_bool_t   display_use24bpp = FALSE;
     97static int            dive_status = 0;
     98static cairo_bool_t   dive_hideptr = TRUE;
     99static HDIVE          dive_handle = 0;
     100static int            dive_height;
     101static int            dive_stride;
     102static unsigned char *dive_scrnbuf;
    108103
    109 /* Unpublished API:
    110  *   GpiEnableYInversion = PMGPI.723
    111  *   GpiQueryYInversion = PMGPI.726
    112  *   BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);
    113  *   LONG APIENTRY GpiQueryYInversion (HPS hps);
    114  */
    115 BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);
    116 LONG APIENTRY GpiQueryYInversion (HPS hps);
    117 
    118 #ifdef __WATCOMC__
    119 /* Function declaration for GpiDrawBits () (missing from OpenWatcom headers) */
    120 LONG APIENTRY GpiDrawBits (HPS hps,
    121                            PVOID pBits,
    122                            PBITMAPINFO2 pbmiInfoTable,
    123                            LONG lCount,
    124                            PPOINTL aptlPoints,
    125                            LONG lRop,
    126                            ULONG flOptions);
    127 #endif
    128104
    129 static void
    130 _cairo_os2_surface_blit_pixels (cairo_os2_surface_t *surface,
    131                                 HPS                  hps_begin_paint,
    132                                 PRECTL               prcl_begin_paint_rect)
    133 {
    134     POINTL aptlPoints[4];
    135     LONG   lOldYInversion;
    136     LONG   rc = GPI_OK;
    137 
    138     /* Check the limits (may not be necessary) */
    139     if (prcl_begin_paint_rect->xLeft < 0)
    140         prcl_begin_paint_rect->xLeft = 0;
    141     if (prcl_begin_paint_rect->yBottom < 0)
    142         prcl_begin_paint_rect->yBottom = 0;
    143     if (prcl_begin_paint_rect->xRight > (LONG) surface->bitmap_info.cx)
    144         prcl_begin_paint_rect->xRight = (LONG) surface->bitmap_info.cx;
    145     if (prcl_begin_paint_rect->yTop > (LONG) surface->bitmap_info.cy)
    146         prcl_begin_paint_rect->yTop = (LONG) surface->bitmap_info.cy;
    147 
    148     /* Exit if the rectangle is empty */
    149     if (prcl_begin_paint_rect->xLeft   >= prcl_begin_paint_rect->xRight ||
    150         prcl_begin_paint_rect->yBottom >= prcl_begin_paint_rect->yTop)
    151         return;
    152 
    153     /* Set the Target & Source coordinates */
    154     *((PRECTL)&aptlPoints[0]) = *prcl_begin_paint_rect;
    155     *((PRECTL)&aptlPoints[2]) = *prcl_begin_paint_rect;
    156 
    157     /* Make the Target coordinates non-inclusive */
    158     aptlPoints[1].x -= 1;
    159     aptlPoints[1].y -= 1;
    160 
    161     /* Enable Y Inversion for the HPS, so  GpiDrawBits will
    162      * work with upside-top image, not with upside-down image!
    163      */
    164     lOldYInversion = GpiQueryYInversion (hps_begin_paint);
    165     GpiEnableYInversion (hps_begin_paint, surface->bitmap_info.cy-1);
    166 
    167     /* Debug code to draw rectangle limits */
    168 #if 0
    169     {
    170         int x, y;
    171         unsigned char *pixels;
    172 
    173         pixels = surface->pixels;
    174         for (x = 0; x < surface->bitmap_info.cx; x++) {
    175             for (y = 0; y < surface->bitmap_info.cy; y++) {
    176                 if ((x == 0) ||
    177                     (y == 0) ||
    178                     (x == y) ||
    179                     (x >= surface->bitmap_info.cx-1) ||
    180                     (y >= surface->bitmap_info.cy-1))
    181                 {
    182                     pixels[y*surface->bitmap_info.cx*4+x*4] = 255;
    183                 }
    184             }
    185         }
    186     }
    187 #endif
    188     if (!surface->use_24bpp) {
    189         rc = GpiDrawBits (hps_begin_paint,
    190                           surface->pixels,
    191                           &(surface->bitmap_info),
    192                           4,
    193                           aptlPoints,
    194                           ROP_SRCCOPY,
    195                           BBO_IGNORE);
    196         if (rc != GPI_OK)
    197             surface->use_24bpp = TRUE;
    198     }
     105/**
     106 * Support for dynamically loading dive.dll
     107 **/
    199108
    200     if (surface->use_24bpp) {
    201         /* If GpiDrawBits () failed then this is most likely because the
    202          * display driver could not handle a 32bit bitmap. So we need to
    203          * - create a buffer that only contains 3 bytes per pixel
    204          * - change the bitmap info header to contain 24bit
    205          * - pass the new buffer to GpiDrawBits () again
    206          * - clean up the new buffer
    207          */
    208         BITMAPINFO2       bmpinfo;
    209         unsigned char    *pchPixBuf;
    210         unsigned char    *pchTarget;
    211         ULONG            *pulSource;
    212         ULONG             ulX;
    213         ULONG             ulY;
    214         ULONG             ulPad;
    215 
    216         /* Set up the bitmap header, but this time for 24bit depth. */
    217         bmpinfo = surface->bitmap_info;
    218         bmpinfo.cBitCount = 24;
    219 
    220         /* The start of each row has to be DWORD aligned.  Calculate the
    221          * of number aligned bytes per row, the total size of the bitmap,
    222          * and the number of padding bytes at the end of each row.
    223          */
    224         ulX = (((bmpinfo.cx * bmpinfo.cBitCount) + 31) / 32) * 4;
    225         bmpinfo.cbImage = ulX * bmpinfo.cy;
    226         ulPad = ulX - bmpinfo.cx * 3;
    227 
    228         /* Allocate temporary pixel buffer.  If the rows don't need
    229          * padding, it has to be 1 byte larger than the size of the
    230          * bitmap  or else the high-order byte from the last source
    231          * row will end up in unallocated memory.
    232          */
    233         pchPixBuf = (unsigned char *)_buffer_alloc (1, 1,
    234                                         bmpinfo.cbImage + (ulPad ? 0 : 1));
    235 
    236         if (pchPixBuf) {
    237             /* Copy 4 bytes from the source but advance the target ptr only
    238              * 3 bytes, so the high-order alpha byte will be overwritten by
    239              * the next copy. At the end of each row, skip over the padding.
    240              */
    241             pchTarget = pchPixBuf;
    242             pulSource = (ULONG*)surface->pixels;
    243             for (ulY = bmpinfo.cy; ulY; ulY--) {
    244                 for (ulX = bmpinfo.cx; ulX; ulX--) {
    245                     *((ULONG*)pchTarget) = *pulSource++;
    246                     pchTarget += 3;
    247                 }
    248                 pchTarget += ulPad;
    249             }
     109#ifdef OS2_DYNAMIC_DIVE
     110static cairo_bool_t      dive_loaded = FALSE;
    250111
    251             rc = GpiDrawBits (hps_begin_paint,
    252                               pchPixBuf,
    253                               &bmpinfo,
    254                               4,
    255                               aptlPoints,
    256                               ROP_SRCCOPY,
    257                               BBO_IGNORE);
    258             if (rc != GPI_OK)
    259                 surface->use_24bpp = FALSE;
    260 
    261             _buffer_free (pchPixBuf);
    262         }
    263     }
     112static DiveQuery_t       pDiveQueryCaps = 0;
     113static DiveOpen_t        pDiveOpen = 0;
     114static DiveClose_t       pDiveClose = 0;
     115static DiveAcquire_t     pDiveAcquireFrameBuffer = 0;
     116static DiveDeacquire_t   pDiveDeacquireFrameBuffer = 0;
    264117
    265     /* Restore Y inversion */
    266     GpiEnableYInversion (hps_begin_paint, lOldYInversion);
    267 }
     118#define DiveQueryCaps             pDiveQueryCaps
     119#define DiveOpen                  pDiveOpen
     120#define DiveClose                 pDiveClose
     121#define DiveAcquireFrameBuffer    pDiveAcquireFrameBuffer
     122#define DiveDeacquireFrameBuffer  pDiveDeacquireFrameBuffer
    268123
    269 static void
    270 _cairo_os2_surface_get_pixels_from_screen (cairo_os2_surface_t *surface,
    271                                            HPS                  hps_begin_paint,
    272                                            PRECTL               prcl_begin_paint_rect)
    273 {
    274     HPS hps;
    275     HDC hdc;
    276     SIZEL sizlTemp;
    277     HBITMAP hbmpTemp;
    278     BITMAPINFO2 bmi2Temp;
    279     POINTL aptlPoints[4];
    280     int y;
    281     unsigned char *pchTemp;
    282 
    283     /* To copy pixels from screen to our buffer, we do the following steps:
    284      *
    285      * - Blit pixels from screen to a HBITMAP:
    286      *   -- Create Memory Device Context
    287      *   -- Create a PS into it
    288      *   -- Create a HBITMAP
    289      *   -- Select HBITMAP into memory PS
    290      *   -- Blit dirty pixels from screen to HBITMAP
    291      * - Copy HBITMAP lines (pixels) into our buffer
    292      * - Free resources
    293      */
     124static cairo_bool_t
     125_cairo_os2_surface_load_dive (void);
     126#endif
    294127
    295     /* Create a memory device context */
    296     hdc = DevOpenDC (0, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
    297     if (!hdc) {
    298         return;
    299     }
    300128
    301     /* Create a memory PS */
    302     sizlTemp.cx = prcl_begin_paint_rect->xRight - prcl_begin_paint_rect->xLeft;
    303     sizlTemp.cy = prcl_begin_paint_rect->yTop - prcl_begin_paint_rect->yBottom;
    304     hps = GpiCreatePS (0,
    305                        hdc,
    306                        &sizlTemp,
    307                        PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
    308     if (!hps) {
    309         DevCloseDC (hdc);
    310         return;
    311     }
     129/**
     130 * Forward reference to the backend structure
     131 **/
    312132
    313     /* Create an uninitialized bitmap. */
    314     /* Prepare BITMAPINFO2 structure for our buffer */
    315     memset (&bmi2Temp, 0, sizeof (bmi2Temp));
    316     bmi2Temp.cbFix = sizeof (BITMAPINFOHEADER2);
    317     bmi2Temp.cx = sizlTemp.cx;
    318     bmi2Temp.cy = sizlTemp.cy;
    319     bmi2Temp.cPlanes = 1;
    320     bmi2Temp.cBitCount = 32;
    321 
    322     hbmpTemp = GpiCreateBitmap (hps,
    323                                 (PBITMAPINFOHEADER2) &bmi2Temp,
    324                                 0,
    325                                 NULL,
    326                                 NULL);
    327 
    328     if (!hbmpTemp) {
    329         GpiDestroyPS (hps);
    330         DevCloseDC (hdc);
    331         return;
    332     }
     133static const
     134cairo_surface_backend_t cairo_os2_surface_backend;
    333135
    334     /* Select the bitmap into the memory device context. */
    335     GpiSetBitmap (hps, hbmpTemp);
    336 
    337     /* Target coordinates (Noninclusive) */
    338     aptlPoints[0].x = 0;
    339     aptlPoints[0].y = 0;
    340 
    341     aptlPoints[1].x = sizlTemp.cx;
    342     aptlPoints[1].y = sizlTemp.cy;
    343 
    344     /* Source coordinates (Inclusive) */
    345     aptlPoints[2].x = prcl_begin_paint_rect->xLeft;
    346     aptlPoints[2].y = surface->bitmap_info.cy - prcl_begin_paint_rect->yBottom;
    347 
    348     aptlPoints[3].x = prcl_begin_paint_rect->xRight;
    349     aptlPoints[3].y = surface->bitmap_info.cy - prcl_begin_paint_rect->yTop;
    350 
    351     /* Blit pixels from screen to bitmap */
    352     GpiBitBlt (hps,
    353                hps_begin_paint,
    354                4,
    355                aptlPoints,
    356                ROP_SRCCOPY,
    357                BBO_IGNORE);
    358 
    359     /* Now we have to extract the pixels from the bitmap. */
    360     pchTemp =
    361         surface->pixels +
    362         (prcl_begin_paint_rect->yBottom)*surface->bitmap_info.cx*4 +
    363         prcl_begin_paint_rect->xLeft*4;
    364     for (y = 0; y < sizlTemp.cy; y++) {
    365         /* Get one line of pixels */
    366         GpiQueryBitmapBits (hps,
    367                             sizlTemp.cy - y - 1, /* lScanStart */
    368                             1,                   /* lScans */
    369                             (PBYTE)pchTemp,
    370                             &bmi2Temp);
    371 
    372         /* Go for next line */
    373         pchTemp += surface->bitmap_info.cx*4;
    374     }
    375136
    376     /* Clean up resources */
    377     GpiSetBitmap (hps, (HBITMAP) NULL);
    378     GpiDeleteBitmap (hbmpTemp);
    379     GpiDestroyPS (hps);
    380     DevCloseDC (hdc);
    381 }
     137/**
     138 *
     139 * Surface Create functions
     140 *
     141 **/
    382142
    383 static cairo_status_t
    384 _cairo_os2_surface_acquire_source_image (void                   *abstract_surface,
    385                                          cairo_image_surface_t **image_out,
    386                                          void                  **image_extra)
    387 {
    388     cairo_os2_surface_t *local_os2_surface;
     143/**
     144 * cairo_os2_surface_create:
     145 * @format: a standard cairo_format_t value
     146 * @width: width of the surface in pixels
     147 * @height: height of the surface in pixels
     148 *
     149 * A generic image surface creation function.
     150 *
     151 * Returns: a cairo_os2_surface_t if successful, a nil surface if not.
     152 *
     153 * Since: 1.12
     154 **/
    389155
    390     local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
    391     if ((!local_os2_surface) ||
    392         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    393     {
    394         /* Invalid parameter (wrong surface)! */
    395         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    396     }
     156cairo_public cairo_surface_t *
     157cairo_os2_surface_create (cairo_format_t      format,
     158                          int                 width,
     159                          int                 height)
     160{
     161    cairo_status_t       status;
     162    cairo_os2_surface_t *surface;
    397163
    398     DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
     164    if (width < 0 || height < 0)
     165        return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
    399166
    400     /* Increase lend counter */
    401     local_os2_surface->pixel_array_lend_count++;
     167    if (!CAIRO_FORMAT_VALID(format))
     168        return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT);
    402169
    403     *image_out = local_os2_surface->image_surface;
    404     *image_extra = NULL;
     170    /*
     171     * Create an OS/2 wrapper for an image surface
     172     * whose bitmap will be allocated from system memory.
     173     */
     174    surface = malloc (sizeof (cairo_os2_surface_t));
     175    if (unlikely (surface == NULL))
     176        return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
     177
     178    memset (surface, 0, sizeof(cairo_os2_surface_t));
     179    surface->format  = format;
     180    surface->content = _cairo_content_from_format (surface->format);
     181    surface->subtype = CAIRO_OS2_SUBTYPE_IMAGE;
     182    surface->width   = width;
     183    surface->height  = height;
     184    surface->stride  = cairo_format_stride_for_width (format, width);
     185
     186    /*
     187     * allocate memory for a bitmap then create an image surface.
     188     */
     189    status = _cairo_os2_surface_init_image (surface);
     190    if (_cairo_status_is_error(status)) {
     191        if (surface->image)
     192            cairo_surface_destroy (surface->image);
     193        if (surface->data)
     194            _cairo_os2_surface_free (surface->data);
     195        free (surface);
     196        return _cairo_surface_create_in_error (status);
     197    }
    405198
    406     DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
     199    _cairo_surface_init (&surface->base, &cairo_os2_surface_backend,
     200                         NULL, surface->content);
    407201
    408     return CAIRO_STATUS_SUCCESS;
     202    return &surface->base;
    409203}
    410204
    411 static void
    412 _cairo_os2_surface_release_source_image (void                  *abstract_surface,
    413                                          cairo_image_surface_t *image,
    414                                          void                  *image_extra)
     205
     206/**
     207 * cairo_os2_surface_create_for_window:
     208 * @hwnd: window associated with this surface
     209 * @width: width of the surface in pixels
     210 * @height: height of the surface in pixels
     211 *
     212 * This creates a destination surface that maps to the entire area of
     213 * a native window.  Clients can call cairo_os2_surface_set_size() when
     214 * the window's size changes, and cairo_os2_surface_paint_window()
     215 * when they want to update the display with the surface's content.
     216 *
     217 * If @hwnd is not supplied with this call, it must be set using
     218 * cairo_os2_surface_set_hwnd() before attempting to display this surface.
     219 *
     220 * Returns: a cairo_os2_surface_t if successful, a nil surface if not.
     221 *
     222 * Since: 1.12
     223 **/
     224
     225cairo_public cairo_surface_t *
     226cairo_os2_surface_create_for_window (HWND  hwnd,
     227                                     int   width,
     228                                     int   height)
    415229{
    416     cairo_os2_surface_t *local_os2_surface;
    417 
    418     local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
    419     if ((!local_os2_surface) ||
    420         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    421     {
    422         /* Invalid parameter (wrong surface)! */
    423         return;
    424     }
     230    cairo_os2_surface_t *surface;
    425231
    426     /* Decrease Lend counter! */
    427     DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
     232    surface = (cairo_os2_surface_t *)
     233              cairo_os2_surface_create (CAIRO_FORMAT_ARGB32, width, height);
    428234
    429     if (local_os2_surface->pixel_array_lend_count > 0)
    430         local_os2_surface->pixel_array_lend_count--;
    431     DosPostEventSem (local_os2_surface->hev_pixel_array_came_back);
     235    if (!_cairo_status_is_error (surface->base.status))
     236        surface->hwnd = hwnd;
    432237
    433     DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
    434     return;
     238    return &surface->base;
    435239}
    436240
    437 static cairo_status_t
    438 _cairo_os2_surface_acquire_dest_image (void                     *abstract_surface,
    439                                        cairo_rectangle_int_t    *interest_rect,
    440                                        cairo_image_surface_t   **image_out,
    441                                        cairo_rectangle_int_t    *image_rect,
    442                                        void                    **image_extra)
    443 {
    444     cairo_os2_surface_t *local_os2_surface;
    445241
    446     local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
    447     if ((!local_os2_surface) ||
    448         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    449     {
    450         /* Invalid parameter (wrong surface)! */
    451         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    452     }
     242/**
     243 * cairo_os2_surface_create_null_surface:
     244 * @hps: presentation space handle, typically associated with a
     245 *   printer's device context
     246 * @width: width of the surface in pixels
     247 * @height: height of the surface in pixels
     248 *
     249 * This creates a a null surface that has no image surface associated
     250 * with it.  It is created when the client needs a surface that can be
     251 * queried for its attributes but won't actually be used.
     252 *
     253 * Returns: a cairo_os2_surface_t if successful, a nil surface if not.
     254 *
     255 * Since: 1.12
     256 **/
    453257
    454     DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
     258cairo_public cairo_surface_t *
     259cairo_os2_surface_create_null_surface (HPS  hps,
     260                                       int  width,
     261                                       int  height)
     262{
     263    cairo_os2_surface_t *surface;
    455264
    456     /* Increase lend counter */
    457     local_os2_surface->pixel_array_lend_count++;
     265    if (width < 0 || height < 0)
     266        return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
    458267
    459     *image_out = local_os2_surface->image_surface;
    460     *image_extra = NULL;
     268    surface = malloc (sizeof (cairo_os2_surface_t));
     269    if (unlikely (surface == NULL))
     270        return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
    461271
    462     image_rect->x = 0;
    463     image_rect->y = 0;
    464     image_rect->width = local_os2_surface->bitmap_info.cx;
    465     image_rect->height = local_os2_surface->bitmap_info.cy;
     272    memset (surface, 0, sizeof(cairo_os2_surface_t));
     273    surface->format  = CAIRO_FORMAT_ARGB32;
     274    surface->content = _cairo_content_from_format (surface->format);
     275    surface->subtype = CAIRO_OS2_SUBTYPE_NULL;
     276    surface->width   = width;
     277    surface->height  = height;
     278    surface->hps     = hps;
    466279
    467     DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
     280    _cairo_surface_init (&surface->base, &cairo_os2_surface_backend,
     281                         NULL, surface->content);
    468282
    469     return CAIRO_STATUS_SUCCESS;
     283    return &surface->base;
    470284}
    471285
    472 static void
    473 _cairo_os2_surface_release_dest_image (void                    *abstract_surface,
    474                                        cairo_rectangle_int_t   *interest_rect,
    475                                        cairo_image_surface_t   *image,
    476                                        cairo_rectangle_int_t   *image_rect,
    477                                        void                    *image_extra)
     286
     287/**
     288 *
     289 * OS/2-specific functions
     290 *
     291 **/
     292
     293/**
     294 * cairo_os2_surface_paint_window:
     295 * @surface: the cairo_os2_surface to display
     296 * @hps: presentation space handle associated with the target window
     297 * @rect: an array of native RECTL structure identifying the bottom-left
     298 *   and top-right corners of the areas to be displayed
     299 * @count: the number RECTLs in @rect's array
     300 *
     301 * This function paints the specified areas of a window using the supplied
     302 * surface. It is intended for surfaces whose dimensions have a 1-to-1
     303 * mapping to the dimensions of a native window (such as those created by
     304 * cairo_os2_surface_create_for_window()).  As such, each rectangle identifies
     305 * the coordinates for both the source bitmap and the destination window.  The
     306 * window's handle must already be associated with this surface, using either
     307 * cairo_os2_surface_create_for_window() or cairo_os2_surface_set_hwnd().
     308 *
     309 * It attempts to use the most efficient method available to move the image
     310 * to the screen.  If an attempt fails, it falls back to the next method.
     311 * If all attempts fail, the surface is marked as being in an error state.
     312 *
     313 * If @rect is %NULL, the entire window will be repainted.  @hps is
     314 * typically the presentation space handle returned by WinBeginPaint().
     315 * If it is null, cairo_os2_surface_paint_window() will use the HPS
     316 * that was previously associated with this surface.  If that too is null,
     317 * it will allocate (and later destroy) an HPS for the window handle
     318 * associated with this surface.
     319 *
     320 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     321 *          %CAIRO_STATUS_DEVICE_ERROR if a permanent fatal error occurs,
     322 *          or one of several errors if arguments are missing or invalid.
     323 *
     324 * Since: 1.12
     325 **/
     326
     327cairo_public cairo_status_t
     328cairo_os2_surface_paint_window (cairo_surface_t *surface,
     329                                HPS              hps,
     330                                RECTL           *rect,
     331                                int              count)
    478332{
    479     cairo_os2_surface_t *local_os2_surface;
    480     RECTL rclToBlit;
    481 
    482     local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
    483     if ((!local_os2_surface) ||
    484         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    485     {
    486         /* Invalid parameter (wrong surface)! */
    487         return;
    488     }
     333    cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface;
     334    cairo_status_t       status = CAIRO_STATUS_SUCCESS;
     335    HPS                  hpsTemp = 0;
     336    RECTL                rectTemp;
    489337
    490     /* So, we got back the image, and if all goes well, then
    491      * something has been changed inside the interest_rect.
    492      * So, we blit it to the screen!
    493      */
     338    if (unlikely (!surface || (rect && !count)))
     339        return _cairo_error (CAIRO_STATUS_NULL_POINTER);
    494340
    495     if (local_os2_surface->blit_as_changes) {
    496         /* Get mutex, we'll work with the pixel array! */
    497         if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)!=NO_ERROR) {
    498             /* Could not get mutex! */
    499             return;
    500         }
     341    if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2 ||
     342        os2surf->subtype != CAIRO_OS2_SUBTYPE_IMAGE || !os2surf->hwnd)
     343        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    501344
    502         if (local_os2_surface->hwnd_client_window) {
    503             /* We know the HWND, so let's invalidate the window region,
    504              * so the application will redraw itself, using the
    505              * cairo_os2_surface_refresh_window () API from its own PM thread.
    506              *
    507              * This is the safe method, which should be preferred every time.
    508              */
    509             rclToBlit.xLeft = interest_rect->x;
    510             rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */
    511             rclToBlit.yTop = local_os2_surface->bitmap_info.cy - (interest_rect->y);
    512             rclToBlit.yBottom = local_os2_surface->bitmap_info.cy - (interest_rect->y+interest_rect->height); /* Noninclusive */
    513 
    514             WinInvalidateRect (local_os2_surface->hwnd_client_window,
    515                                &rclToBlit,
    516                                FALSE);
    517         } else {
    518             /* We don't know the HWND, so try to blit the pixels from here!
    519              * Please note that it can be problematic if this is not the PM thread!
    520              *
    521              * It can cause internal PM stuffs to be scewed up, for some reason.
    522              * Please always tell the HWND to the surface using the
    523              * cairo_os2_surface_set_hwnd () API, and call cairo_os2_surface_refresh_window ()
    524              * from your WM_PAINT, if it's possible!
    525              */
    526             rclToBlit.xLeft = interest_rect->x;
    527             rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */
    528             rclToBlit.yBottom = interest_rect->y;
    529             rclToBlit.yTop = interest_rect->y+interest_rect->height; /* Noninclusive */
    530             /* Now blit there the stuffs! */
    531             _cairo_os2_surface_blit_pixels (local_os2_surface,
    532                                             local_os2_surface->hps_client_window,
    533                                             &rclToBlit);
     345    /* If an HPS wasn't provided, see if we can get one. */
     346    if (!hps) {
     347        hps = os2surf->hps;
     348        if (!hps) {
     349            if (os2surf->hwnd) {
     350                hpsTemp = WinGetPS(os2surf->hwnd);
     351                hps = hpsTemp;
     352            }
     353            /* No HPS & no way to get one, so exit */
     354            if (!hps)
     355                return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
    534356        }
     357    }
    535358
    536         DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
     359    /* If rect is null, paint the entire window. */
     360    if (!rect) {
     361        rectTemp.xLeft = 0;
     362        rectTemp.xRight = os2surf->width;
     363        rectTemp.yTop = os2surf->height;
     364        rectTemp.yBottom = 0;
     365        rect = &rectTemp;
     366        count = 1;
    537367    }
    538     /* Also decrease Lend counter! */
    539     DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
    540368
    541     if (local_os2_surface->pixel_array_lend_count > 0)
    542         local_os2_surface->pixel_array_lend_count--;
    543     DosPostEventSem (local_os2_surface->hev_pixel_array_came_back);
     369    if (dive_handle) {
     370        if (_cairo_os2_surface_paint_dive (os2surf, hps, rect, count) ==
     371                                                        CAIRO_STATUS_SUCCESS)
     372            goto done;
     373    }
     374    if (!display_use24bpp) {
     375        if (_cairo_os2_surface_paint_32bpp (os2surf, hps, rect, rect, count) ==
     376                                                        CAIRO_STATUS_SUCCESS)
     377            goto done;
     378        display_use24bpp = TRUE;
     379    }
     380    status = _cairo_os2_surface_paint_24bpp (os2surf, hps, rect, rect, count);
     381    if (status == CAIRO_STATUS_SUCCESS)
     382        goto done;
     383
     384    status = _cairo_surface_set_error (&os2surf->base, status);
    544385
    545     DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
     386done:
     387    if (hpsTemp)
     388        WinReleasePS (hpsTemp);
     389
     390    return status;
    546391}
    547392
    548 static cairo_bool_t
    549 _cairo_os2_surface_get_extents (void                    *abstract_surface,
    550                                 cairo_rectangle_int_t   *rectangle)
     393
     394/**
     395 * cairo_os2_surface_paint_bitmap:
     396 * @surface: the cairo_os2_surface to display
     397 * @hps: presentation space handle associated with the target device
     398 * @src: an array of native RECTL structure identifying those areas of
     399 *   the source surface which will be painted onto the destination
     400 * @dst: an array of native RECTL structure that identify where on the
     401 *   destination surface the corresponding @src rectangles will be painted
     402 * @count: the number of RECTLs in @src and @dst arrays
     403 * @use24bpp: if set, the surface's 32bpp bitmap is copied to a 24bpp
     404 *    bitmap before blitting to @hps
     405 *
     406 * This function paints the specified areas of a presentation space using
     407 * the supplied surface.  The target of the operation can be a PM bitmap
     408 * which the caller has previously created and selected into @hps, or it
     409 * can be an @hps associated with a window or printer.  Only GPI functions
     410 * will be used for blitting - DIVE is not available.
     411 *
     412 * Neither the origins nor dimensions of the @src and @dst rectangles need
     413 * be the same:  translation and scaling will occur as required.  Either
     414 * @src or @dst can be %NULL if there is a 1-to-1 mapping between the source
     415 * and destination's coordinates.  If both @src and @dst are %NULL, the
     416 * entire surface's contents will be painted into the presentation space.
     417 *
     418 * If the driver for the device context associated with @hps is known to
     419 * be unable to use 32-bit bitmap data as input (e.g. most native printer
     420 * drivers), the @use24bpp flag should be set.  Its use is very expensive
     421 * and should be avoided unless absolutely necessary.
     422 *
     423 * If cairo_os2_surface_set_hps() was used to associate an HPS with this
     424 * surface using, @hps may be %NULL;  otherwise, it must be supplied.
     425 *
     426 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     427 *          %CAIRO_STATUS_DEVICE_ERROR if the bit-blit fails,
     428 *          or one of several errors if arguments are missing or invalid.
     429 *
     430 * Since: 1.12
     431 **/
     432
     433cairo_public cairo_status_t
     434cairo_os2_surface_paint_bitmap (cairo_surface_t *surface,
     435                                HPS              hps,
     436                                RECTL           *src,
     437                                RECTL           *dst,
     438                                int              count,
     439                                BOOL             use24bpp)
    551440{
    552     cairo_os2_surface_t *local_os2_surface;
     441    cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface;
     442    cairo_status_t       status = CAIRO_STATUS_SUCCESS;
     443    RECTL                rectTemp;
     444
     445    if (unlikely (!surface || ((src || dst) && !count)))
     446        return _cairo_error (CAIRO_STATUS_NULL_POINTER);
    553447
    554     local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
    555     if ((!local_os2_surface) ||
    556         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    557     {
    558         /* Invalid parameter (wrong surface)! */
     448    if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2 ||
     449        os2surf->subtype != CAIRO_OS2_SUBTYPE_IMAGE)
    559450        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
     451
     452    if (!hps) {
     453        if (!os2surf->hps)
     454            return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
     455        hps = os2surf->hps;
    560456    }
    561457
    562     rectangle->x = 0;
    563     rectangle->y = 0;
    564     rectangle->width  = local_os2_surface->bitmap_info.cx;
    565     rectangle->height = local_os2_surface->bitmap_info.cy;
     458    /* If either src or dst is null, assume a 1 to 1 mapping of
     459     * coordinates;  if both are null, copy all of src to dst.
     460     */
     461    if (!src) {
     462        if (!dst) {
     463            rectTemp.xLeft = 0;
     464            rectTemp.xRight = os2surf->width;
     465            rectTemp.yTop = os2surf->height;
     466            rectTemp.yBottom = 0;
     467            src = dst = &rectTemp;
     468            count = 1;
     469        }
     470        else
     471            src = dst;
     472    }
     473    else
     474        if (!dst)
     475            dst = src;
    566476
    567     return TRUE;
     477    /* Perform either a 32-bit or 24-bit blit, depending on @use24bpp. */
     478    if (use24bpp)
     479        status = _cairo_os2_surface_paint_24bpp (os2surf, hps, src, dst, count);
     480    else
     481        status = _cairo_os2_surface_paint_32bpp (os2surf, hps, src, dst, count);
     482
     483    return status;
    568484}
    569485
     486
    570487/**
    571  * cairo_os2_surface_create:
    572  * @hps_client_window: the presentation handle to bind the surface to
    573  * @width: the width of the surface
    574  * @height: the height of the surface
    575  *
    576  * Create a Cairo surface which is bound to a given presentation space (HPS).
    577  * The caller retains ownership of the HPS and must dispose of it after the
    578  * the surface has been destroyed.  The surface will be created to have the
    579  * given size. By default every change to the surface will be made visible
    580  * immediately by blitting it into the window. This can be changed with
    581  * cairo_os2_surface_set_manual_window_refresh().
    582  * Note that the surface will contain garbage when created, so the pixels
    583  * have to be initialized by hand first. You can use the Cairo functions to
    584  * fill it with black, or use cairo_surface_mark_dirty() to fill the surface
    585  * with pixels from the window/HPS.
    586  *
    587  * Return value: the newly created surface
    588  *
    589  * Since: 1.4
     488 * cairo_os2_surface_get_hps:
     489 * @surface: the cairo_os2_surface to query
     490 * @hps: presentation space handle associated with this surface
     491 *
     492 * Retrieves the HPS associated with this surface, if any.
     493 *
     494 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     495 *          or one of several errors if arguments are missing or invalid.
     496 *
     497 * Since: 1.12
    590498 **/
    591 cairo_surface_t *
    592 cairo_os2_surface_create (HPS hps_client_window,
    593                           int width,
    594                           int height)
     499
     500cairo_public cairo_status_t
     501cairo_os2_surface_get_hps (cairo_surface_t *surface,
     502                           HPS             *hps)
    595503{
    596     cairo_os2_surface_t *local_os2_surface = 0;
    597     cairo_status_t status;
    598     int rc;
     504    cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface;
    599505
    600     /* Check the size of the window */
    601     if ((width <= 0) || (height <= 0)) {
    602         status = _cairo_error (CAIRO_STATUS_INVALID_SIZE);
    603         goto error_exit;
    604     }
     506    if (unlikely (!surface || !hps))
     507        return _cairo_error (CAIRO_STATUS_NULL_POINTER);
    605508
    606     /* Allocate an OS/2 surface structure. */
    607     local_os2_surface = (cairo_os2_surface_t *) malloc (sizeof (cairo_os2_surface_t));
    608     if (!local_os2_surface) {
    609         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    610         goto error_exit;
    611     }
     509    if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2)
     510        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    612511
    613     memset(local_os2_surface, 0, sizeof(cairo_os2_surface_t));
     512    *hps = os2surf->hps;
    614513
    615     /* Allocate resources:  mutex & event semaphores and the pixel buffer */
    616     if (DosCreateMutexSem (NULL,
    617                            &(local_os2_surface->hmtx_use_private_fields),
    618                            0,
    619                            FALSE))
    620     {
    621         status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
    622         goto error_exit;
    623     }
     514    return CAIRO_STATUS_SUCCESS;
     515}
    624516
    625     if (DosCreateEventSem (NULL,
    626                            &(local_os2_surface->hev_pixel_array_came_back),
    627                            0,
    628                            FALSE))
    629     {
    630         status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
    631         goto error_exit;
    632     }
    633517
    634     local_os2_surface->pixels = (unsigned char *) _buffer_alloc (height, width, 4);
    635     if (!local_os2_surface->pixels) {
    636         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    637         goto error_exit;
    638     }
     518/**
     519 * cairo_os2_surface_set_hps:
     520 * @surface: a cairo_os2_surface
     521 * @hps: presentation space handle to associate with this surface
     522 *
     523 * Associates an HPS with this surface or dissociates it if @hps is %NULL.
     524 * The caller retains ownership of @hps and must destroy it when it is no
     525 * longer needed.
     526 *
     527 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     528 *          or one of several errors if arguments are missing or invalid.
     529 *
     530 * Since: 1.12
     531 **/
    639532
    640     /* Create image surface from pixel array */
    641     local_os2_surface->image_surface = (cairo_image_surface_t *)
    642         cairo_image_surface_create_for_data (local_os2_surface->pixels,
    643                                              CAIRO_FORMAT_ARGB32,
    644                                              width,      /* Width */
    645                                              height,     /* Height */
    646                                              width * 4); /* Rowstride */
    647     status = local_os2_surface->image_surface->base.status;
    648     if (status)
    649         goto error_exit;
    650 
    651     /* Set values for OS/2-specific data that aren't zero/NULL/FALSE.
    652      * Note: hps_client_window may be null if this was called by
    653      * cairo_os2_surface_create_for_window().
    654      */
    655     local_os2_surface->hps_client_window = hps_client_window;
    656     local_os2_surface->blit_as_changes = TRUE;
    657 
    658     /* Prepare BITMAPINFO2 structure for our buffer */
    659     local_os2_surface->bitmap_info.cbFix = sizeof (BITMAPINFOHEADER2);
    660     local_os2_surface->bitmap_info.cx = width;
    661     local_os2_surface->bitmap_info.cy = height;
    662     local_os2_surface->bitmap_info.cPlanes = 1;
    663     local_os2_surface->bitmap_info.cBitCount = 32;
    664 
    665     /* Initialize base surface */
    666     _cairo_surface_init (&local_os2_surface->base,
    667                          &cairo_os2_surface_backend,
    668                          NULL, /* device */
    669                          _cairo_content_from_format (CAIRO_FORMAT_ARGB32));
    670 
    671     /* Successful exit */
    672     return (cairo_surface_t *)local_os2_surface;
    673 
    674  error_exit:
    675 
    676     /* This point will only be reached if an error occured */
    677 
    678     if (local_os2_surface) {
    679         if (local_os2_surface->pixels)
    680             _buffer_free (local_os2_surface->pixels);
    681         if (local_os2_surface->hev_pixel_array_came_back)
    682             DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
    683         if (local_os2_surface->hmtx_use_private_fields)
    684             DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
    685         free (local_os2_surface);
    686     }
     533cairo_public cairo_status_t
     534cairo_os2_surface_set_hps (cairo_surface_t *surface,
     535                           HPS              hps)
     536{
     537    cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface;
     538
     539    if (unlikely (!surface))
     540        return _cairo_error (CAIRO_STATUS_NULL_POINTER);
     541
     542    if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2)
     543        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    687544
    688     return _cairo_surface_create_in_error (status);
     545    os2surf->hps = hps;
     546
     547    return CAIRO_STATUS_SUCCESS;
    689548}
    690549
     550
    691551/**
    692  * cairo_os2_surface_create_for_window:
    693  * @hwnd_client_window: the window handle to bind the surface to
    694  * @width: the width of the surface
    695  * @height: the height of the surface
    696  *
    697  * Create a Cairo surface which is bound to a given window; the caller retains
    698  * ownership of the window.  This is a convenience function for use with
    699  * windows that will only be updated when cairo_os2_surface_refresh_window()
    700  * is called (usually in response to a WM_PAINT message).  It avoids the need
    701  * to create a persistent HPS for every window and assumes that one will be
    702  * supplied by the caller when a cairo function needs one.  If it isn't, an
    703  * HPS will be created on-the-fly and released before the function which needs
    704  * it returns.
    705  *
    706  * Return value: the newly created surface
    707  *
    708  * Since: 1.10
     552 * cairo_os2_surface_set_hwnd:
     553 * @surface: a cairo_os2_surface
     554 * @hwnd: window handle to associate with this surface
     555 *
     556 * Associates an HWND with this surface or dissociates it if @hwnd is %NULL.
     557 * The caller retains ownership of @hwnd.  If the surface was created without
     558 * supplying an HWND, this function must be called before attempting to use
     559 * cairo_os2_surface_paint_window().
     560 *
     561 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     562 *          or one of several errors if arguments are missing or invalid.
     563 *
     564 * Since: 1.12
    709565 **/
    710 cairo_surface_t *
    711 cairo_os2_surface_create_for_window (HWND hwnd_client_window,
    712                                      int width,
    713                                      int height)
     566
     567cairo_public cairo_status_t
     568cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
     569                            HWND             hwnd)
    714570{
    715     cairo_os2_surface_t *local_os2_surface;
     571    cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface;
    716572
    717     /* A window handle must be provided. */
    718     if (!hwnd_client_window) {
    719         return _cairo_surface_create_in_error (
    720                                 _cairo_error (CAIRO_STATUS_NO_MEMORY));
    721     }
     573    if (unlikely (!surface))
     574        return _cairo_error (CAIRO_STATUS_NULL_POINTER);
    722575
    723     /* Create the surface. */
    724     local_os2_surface = (cairo_os2_surface_t *)
    725         cairo_os2_surface_create (0, width, height);
     576    if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2)
     577        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    726578
    727     /* If successful, save the hwnd & turn off automatic repainting. */
    728     if (!local_os2_surface->image_surface->base.status) {
    729         local_os2_surface->hwnd_client_window = hwnd_client_window;
    730         local_os2_surface->blit_as_changes = FALSE;
    731     }
     579    os2surf->hwnd = hwnd;
    732580
    733     return (cairo_surface_t *)local_os2_surface;
     581    return CAIRO_STATUS_SUCCESS;
    734582}
    735583
     584
    736585/**
    737586 * cairo_os2_surface_set_size:
    738  * @surface: the cairo surface to resize
    739  * @new_width: the new width of the surface
    740  * @new_height: the new height of the surface
    741  * @timeout: timeout value in milliseconds
    742  *
    743  * When the client window is resized, call this API to set the new size in the
    744  * underlying surface accordingly. This function will reallocate everything,
    745  * so you'll have to redraw everything in the surface after this call.
    746  * The surface will contain garbage after the resizing. So the notes of
    747  * cairo_os2_surface_create() apply here, too.
    748  *
    749  * The timeout value specifies how long the function should wait on other parts
    750  * of the program to release the buffers. It is necessary, because it can happen
    751  * that Cairo is just drawing something into the surface while we want to
    752  * destroy and recreate it.
    753  *
    754  * Return value: %CAIRO_STATUS_SUCCESS if the surface could be resized,
    755  * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface,
    756  * %CAIRO_STATUS_INVALID_SIZE for invalid sizes
    757  * %CAIRO_STATUS_NO_MEMORY if the new size could not be allocated, or if the
    758  * timeout happened before all the buffers were released
    759  *
    760  * Since: 1.4
     587 * @surface: the cairo_os2_surface to resize
     588 * @width: the surface's new width
     589 * @height: the surface's new height
     590 * @copy: boolean indicating whether existing bitmap data should
     591 *   be copied to the resized surface
     592 *
     593 * This function resizes a cairo_os2_surface and its underlying image
     594 * surface. It is intended for surfaces whose dimensions have a 1-to-1
     595 * mapping to the dimensions of a native window (such as those created
     596 * by cairo_os2_surface_create_for_window()).
     597 *
     598 * If @copy is non-zero, bitmap data will be copied from the original
     599 * image surface to its replacement.  The bitmaps will be aligned at
     600 * their top-left corners.
     601 *
     602 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     603 *          or one of several errors if arguments are missing or invalid.
     604 *
     605 * Since: 1.12
    761606 **/
    762 int
     607
     608cairo_public cairo_status_t
    763609cairo_os2_surface_set_size (cairo_surface_t *surface,
    764                             int              new_width,
    765                             int              new_height,
    766                             int              timeout)
     610                            int              width,
     611                            int              height,
     612                            int              copy)
    767613{
    768     cairo_os2_surface_t *local_os2_surface;
    769     unsigned char *pchNewPixels;
    770     int rc;
    771     cairo_image_surface_t *pNewImageSurface;
    772 
    773     local_os2_surface = (cairo_os2_surface_t *) surface;
    774     if ((!local_os2_surface) ||
    775         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    776     {
    777         /* Invalid parameter (wrong surface)! */
     614    cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface;
     615    cairo_surface_t     *old_image;
     616    int                  old_width;
     617    int                  old_height;
     618    int                  old_stride;
     619    unsigned char       *old_data;
     620    cairo_status_t       status = CAIRO_STATUS_SUCCESS;
     621
     622    if (unlikely (!surface))
     623        return _cairo_error (CAIRO_STATUS_NULL_POINTER);
     624
     625    if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2)
    778626        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    779     }
    780627
    781     if ((new_width <= 0) ||
    782         (new_height <= 0))
    783     {
    784         /* Invalid size! */
     628    if (width < 0 || height < 0)
    785629        return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
     630
     631    old_image   = os2surf->image;
     632    old_width   = os2surf->width;
     633    old_height  = os2surf->height;
     634    old_stride  = os2surf->stride;
     635    old_data    = os2surf->data;
     636
     637    os2surf->image  = 0;
     638    os2surf->width  = width;
     639    os2surf->height = height;
     640    os2surf->stride = cairo_format_stride_for_width (os2surf->format, width);
     641    os2surf->data   = 0;
     642
     643    if (os2surf->subtype != CAIRO_OS2_SUBTYPE_NULL)
     644        status = _cairo_os2_surface_init_image (os2surf);
     645
     646    if (_cairo_status_is_error(status)) {
     647        if (os2surf->image)
     648            cairo_surface_destroy (os2surf->image);
     649        if (os2surf->data)
     650            _cairo_os2_surface_free (os2surf->data);
     651        os2surf->image  = old_image;
     652        os2surf->width  = old_width;
     653        os2surf->height = old_height;
     654        os2surf->stride = old_stride;
     655        os2surf->data   = old_data;
     656        return status;
    786657    }
    787658
    788     /* Allocate memory for new stuffs */
    789     pchNewPixels = (unsigned char *) _buffer_alloc (new_height, new_width, 4);
    790     if (!pchNewPixels) {
    791         /* Not enough memory for the pixels!
    792          * Everything remains the same!
    793          */
    794         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     659    if (copy) {
     660        unsigned char *src = old_data;
     661        unsigned char *dst = os2surf->data;
     662        int count  = (old_stride < os2surf->stride) ? old_stride : os2surf->stride;
     663        int height = (old_height < os2surf->height) ? old_height : os2surf->height;
     664
     665        while (height) {
     666            memcpy(dst, src, count);
     667            src += old_stride;
     668            dst += os2surf->stride;
     669            height--;
     670        }
    795671    }
    796672
    797     /* Create image surface from new pixel array */
    798     pNewImageSurface = (cairo_image_surface_t *)
    799         cairo_image_surface_create_for_data (pchNewPixels,
    800                                              CAIRO_FORMAT_ARGB32,
    801                                              new_width,      /* Width */
    802                                              new_height,     /* Height */
    803                                              new_width * 4); /* Rowstride */
    804 
    805     if (pNewImageSurface->base.status) {
    806         /* Could not create image surface!
    807          * Everything remains the same!
    808          */
    809         _buffer_free (pchNewPixels);
    810         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     673    if (old_image)
     674        cairo_surface_destroy (old_image);
     675    if (old_data)
     676        _cairo_os2_surface_free (old_data);
     677
     678    return status;
     679}
     680
     681
     682/**
     683 * cairo_os2_surface_enable_dive:
     684 *
     685 * @enable: boolean indicating whether DIVE should be enabled or disabled
     686 * @hide_pointer: boolean indicating whether the mouse pointer should be
     687 *   removed from the screen while writing to the frame buffer.
     688 *
     689 * This function enables or disables DIVE.  When enabled, image data is
     690 * written directly to the video framebuffer, bypassing OS/2's graphics
     691 * subsystem.  Only 32-bit (BGR4) and 24-bit (BGR3) color modes are
     692 * supported.  If any other video mode is in effect, or if any error
     693 * occurs while initializing or using DIVE, it will be disabled for
     694 * the remainder of the process.
     695 *
     696 * The @hide_pointer argument avoids screen corruption when DIVE is used
     697 * with less-capable video drivers that use a software-generated pointer.
     698 *
     699 * Returns: %TRUE if the desired state (enabled or disabled) can be
     700 *  achieved or is already in effect, and FALSE otherwise.
     701 *
     702 * Since: 1.12
     703 **/
     704
     705cairo_public cairo_bool_t
     706cairo_os2_surface_enable_dive (cairo_bool_t enable,
     707                               cairo_bool_t hide_pointer)
     708{
     709    unsigned int  rc;
     710    unsigned int  dive_fmts[64];
     711    DIVE_CAPS     dive_caps;
     712    char          msg[8];
     713
     714    /* If DIVE is disabled due to an earlier error, return false. */
     715    if (dive_status == -1)
     716        return FALSE;
     717
     718    /* Close DIVE if it is currently enabled and reset all values. */
     719    if (!enable) {
     720        if (dive_handle)
     721            DiveClose (dive_handle);
     722        dive_handle = 0;
     723        dive_scrnbuf = 0;
     724        dive_hideptr = TRUE;
     725        dive_status = 0;
     726        return TRUE;
    811727    }
    812728
    813     /* Okay, new memory allocated, so it's time to swap old buffers
    814      * to new ones!
    815      */
    816     if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)!=NO_ERROR) {
    817         /* Could not get mutex!
    818          * Everything remains the same!
    819          */
    820         cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
    821         _buffer_free (pchNewPixels);
    822         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     729    /* If DIVE is already enabled, do nothing. */
     730    if (dive_status)
     731        return TRUE;
     732
     733    /* Assume the worst. */
     734    dive_status = -1;
     735
     736#ifdef OS2_DYNAMIC_DIVE
     737    if (!dive_loaded) {
     738        dive_loaded = TRUE;
     739        if (!_cairo_os2_surface_load_dive ())
     740            return FALSE;
    823741    }
     742#endif
     743
     744    memset (&dive_caps, 0, sizeof(dive_caps));
     745    memset (dive_fmts, 0, sizeof(dive_fmts));
     746    dive_caps.ulStructLen = sizeof(dive_caps);
     747    dive_caps.ulFormatLength = sizeof(dive_fmts);
     748    dive_caps.pFormatData = dive_fmts;
     749
     750    /* Get the driver's DIVE capabilities. */
     751    rc = DiveQueryCaps (&dive_caps, DIVE_BUFFER_SCREEN);
     752    if (rc)
     753        return FALSE;
    824754
    825     /* We have to make sure that we won't destroy a surface which
    826      * is lent to some other code (Cairo is drawing into it)!
     755    /* Only 32-bit (BGR4) and 24-bit (BGR3) color modes
     756     * are supported.  If the mode is anything else, exit.
    827757     */
    828     while (local_os2_surface->pixel_array_lend_count > 0) {
    829         ULONG ulPostCount;
    830         DosResetEventSem (local_os2_surface->hev_pixel_array_came_back, &ulPostCount);
    831         DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
    832         /* Wait for somebody to return the pixels! */
    833         rc = DosWaitEventSem (local_os2_surface->hev_pixel_array_came_back, timeout);
    834         if (rc != NO_ERROR) {
    835             /* Either timeout or something wrong... Exit. */
    836             cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
    837             _buffer_free (pchNewPixels);
    838             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    839         }
    840         /* Okay, grab mutex and check counter again! */
    841         if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
    842             != NO_ERROR)
    843         {
    844             /* Could not get mutex!
    845              * Everything remains the same!
    846              */
    847             cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
    848             _buffer_free (pchNewPixels);
    849             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    850         }
     758    memcpy(msg, &dive_caps.fccColorEncoding, 4);
     759    msg[4] = 0;
     760    if (dive_caps.fccColorEncoding != FOURCC_BGR4) {
     761        if (dive_caps.fccColorEncoding == FOURCC_BGR3)
     762            display_use24bpp = TRUE;
     763        else
     764            return FALSE;
    851765    }
    852766
    853     /* Destroy old image surface */
    854     cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface));
    855     /* Destroy old pixel buffer */
    856     _buffer_free (local_os2_surface->pixels);
    857     /* Set new image surface */
    858     local_os2_surface->image_surface = pNewImageSurface;
    859     /* Set new pixel buffer */
    860     local_os2_surface->pixels = pchNewPixels;
    861     /* Change bitmap2 structure */
    862     local_os2_surface->bitmap_info.cx = new_width;
    863     local_os2_surface->bitmap_info.cy = new_height;
    864 
    865     DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
    866     return CAIRO_STATUS_SUCCESS;
     767    dive_height = dive_caps.ulVerticalResolution;
     768    dive_stride = dive_caps.ulScanLineBytes;
     769
     770    /* Open a DIVE instance and get the address of the frame buffer. */
     771    rc = DiveOpen(&dive_handle, FALSE, (void*)&dive_scrnbuf);
     772    if (rc)
     773        return FALSE;
     774
     775    /* Success. */
     776    dive_hideptr = hide_pointer;
     777    dive_status = 1;
     778
     779    return TRUE;
    867780}
    868781
     782
    869783/**
    870  * cairo_os2_surface_refresh_window:
    871  * @surface: the cairo surface to refresh
    872  * @hps_begin_paint: the presentation handle of the window to refresh
    873  * @prcl_begin_paint_rect: the rectangle to redraw
    874  *
    875  * This function can be used to force a repaint of a given area of the client
    876  * window. It should usually be called from the WM_PAINT processing of the
    877  * window procedure. However, it can be called any time a given part of the
    878  * window has to be updated.
    879  *
    880  * The HPS and RECTL to be passed can be taken from the usual WinBeginPaint call
    881  * of the window procedure, but you can also get the HPS using WinGetPS, and you
    882  * can assemble your own update rectangle by hand.
    883  * If hps_begin_paint is %NULL, the function will use the HPS passed into
    884  * cairo_os2_surface_create(). If @prcl_begin_paint_rect is %NULL, the function
    885  * will query the current window size and repaint the whole window.
    886  *
    887  * Cairo assumes that if you set the HWND to the surface using
    888  * cairo_os2_surface_set_hwnd(), this function will be called by the application
    889  * every time it gets a WM_PAINT for that HWND. If the HWND is set in the
    890  * surface, Cairo uses this function to handle dirty areas too.
    891  *
    892  * Since: 1.4
     784 *
     785 * Backend functions
     786 *
    893787 **/
    894 void
    895 cairo_os2_surface_refresh_window (cairo_surface_t *surface,
    896                                   HPS              hps_begin_paint,
    897                                   PRECTL           prcl_begin_paint_rect)
    898 {
    899     cairo_os2_surface_t *local_os2_surface;
    900     RECTL rclTemp;
    901     HPS hpsTemp = 0;
    902 
    903     local_os2_surface = (cairo_os2_surface_t *) surface;
    904     if ((!local_os2_surface) ||
    905         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    906     {
    907         /* Invalid parameter (wrong surface)! */
    908         return;
    909     }
    910788
    911     /* If an HPS wasn't provided, see if we can get one. */
    912     if (!hps_begin_paint) {
    913         hps_begin_paint = local_os2_surface->hps_client_window;
    914         if (!hps_begin_paint) {
    915             if (local_os2_surface->hwnd_client_window) {
    916                 hpsTemp = WinGetPS(local_os2_surface->hwnd_client_window);
    917                 hps_begin_paint = hpsTemp;
    918             }
    919             /* No HPS & no way to get one, so exit */
    920             if (!hps_begin_paint)
    921                 return;
    922         }
    923     }
     789static cairo_surface_t *
     790_cairo_os2_surface_create_similar (void             *abstract_other,
     791                                   cairo_content_t   content,
     792                                   int               width,
     793                                   int               height)
     794{
     795    cairo_os2_surface_t *other = abstract_other;
    924796
    925     if (prcl_begin_paint_rect == NULL) {
    926         /* Update the whole window! */
    927         rclTemp.xLeft = 0;
    928         rclTemp.xRight = local_os2_surface->bitmap_info.cx;
    929         rclTemp.yTop = local_os2_surface->bitmap_info.cy;
    930         rclTemp.yBottom = 0;
    931     } else {
    932         /* Use the rectangle we got passed as parameter! */
    933         rclTemp.xLeft = prcl_begin_paint_rect->xLeft;
    934         rclTemp.xRight = prcl_begin_paint_rect->xRight;
    935         rclTemp.yTop = local_os2_surface->bitmap_info.cy - prcl_begin_paint_rect->yBottom;
    936         rclTemp.yBottom = local_os2_surface->bitmap_info.cy - prcl_begin_paint_rect->yTop ;
    937     }
     797    if (unlikely (other->base.status))
     798        return _cairo_surface_create_in_error (other->base.status);
    938799
    939     /* Get mutex, we'll work with the pixel array! */
    940     if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
    941         != NO_ERROR)
    942     {
    943         /* Could not get mutex! */
    944         if (hpsTemp)
    945             WinReleasePS(hpsTemp);
    946         return;
    947     }
     800    if (unlikely (!CAIRO_CONTENT_VALID (content)))
     801        return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
    948802
    949     if ((local_os2_surface->dirty_area_present) &&
    950         (local_os2_surface->rcl_dirty_area.xLeft == rclTemp.xLeft) &&
    951         (local_os2_surface->rcl_dirty_area.xRight == rclTemp.xRight) &&
    952         (local_os2_surface->rcl_dirty_area.yTop == rclTemp.yTop) &&
    953         (local_os2_surface->rcl_dirty_area.yBottom == rclTemp.yBottom))
    954     {
    955         /* Aha, this call was because of a dirty area, so in this case we
    956          * have to blit the pixels from the screen to the surface!
    957          */
    958         local_os2_surface->dirty_area_present = FALSE;
    959         _cairo_os2_surface_get_pixels_from_screen (local_os2_surface,
    960                                                    hps_begin_paint,
    961                                                    &rclTemp);
    962     } else {
    963         /* Okay, we have the surface, have the HPS
    964          * (might be from WinBeginPaint () or from WinGetPS () )
    965          * Now blit there the stuffs!
    966          */
    967         _cairo_os2_surface_blit_pixels (local_os2_surface,
    968                                         hps_begin_paint,
    969                                         &rclTemp);
    970     }
     803    if (other->subtype == CAIRO_OS2_SUBTYPE_IMAGE)
     804        return cairo_os2_surface_create (_cairo_format_from_content (content),
     805                                         width, height);
    971806
    972     DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
     807    if (other->subtype == CAIRO_OS2_SUBTYPE_NULL)
     808        return cairo_os2_surface_create_null_surface (other->hps, width, height);
    973809
    974     if (hpsTemp)
    975         WinReleasePS(hpsTemp);
     810    return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT);
    976811}
    977812
     813
    978814static cairo_status_t
    979815_cairo_os2_surface_finish (void *abstract_surface)
    980816{
    981     cairo_os2_surface_t *local_os2_surface;
     817    cairo_os2_surface_t *surface = abstract_surface;
     818    if (surface->image)
     819        cairo_surface_destroy (surface->image);
     820    if (surface->data)
     821        _cairo_os2_surface_free (surface->data);
    982822
    983     local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
    984     if ((!local_os2_surface) ||
    985         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    986     {
    987         /* Invalid parameter (wrong surface)! */
    988         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    989     }
     823    return CAIRO_STATUS_SUCCESS;
     824}
    990825
    991     DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
    992826
    993     /* Destroy old image surface */
    994     cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface));
    995     /* Destroy old pixel buffer */
    996     _buffer_free (local_os2_surface->pixels);
    997     DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
    998     DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
     827static cairo_status_t
     828_cairo_os2_surface_acquire_source_image (void                    *abstract_surface,
     829                                         cairo_image_surface_t  **image_out,
     830                                         void                   **image_extra)
     831{
     832    cairo_os2_surface_t *surface = abstract_surface;
    999833
    1000     /* The memory itself will be free'd by the cairo_surface_destroy ()
    1001      * who called us.
    1002      */
     834    if (!surface->image)
     835        return CAIRO_STATUS_NULL_POINTER;
    1003836
    1004     return CAIRO_STATUS_SUCCESS;
     837    return _cairo_surface_acquire_source_image (surface->image,
     838                                                image_out, image_extra);
    1005839}
    1006840
    1007 /**
    1008  * cairo_os2_surface_set_hwnd:
    1009  * @surface: the cairo surface to associate with the window handle
    1010  * @hwnd_client_window: the window handle of the client window
    1011  *
    1012  * Sets window handle for surface; the caller retains ownership of the window.
    1013  * If Cairo wants to blit into the window because it is set to blit as the
    1014  * surface changes (see cairo_os2_surface_set_manual_window_refresh()), then
    1015  * there are two ways it can choose:
    1016  * If it knows the HWND of the surface, then it invalidates that area, so the
    1017  * application will get a WM_PAINT message and it can call
    1018  * cairo_os2_surface_refresh_window() to redraw that area. Otherwise cairo itself
    1019  * will use the HPS it got at surface creation time, and blit the pixels itself.
    1020  * It's also a solution, but experience shows that if this happens from a non-PM
    1021  * thread, then it can screw up PM internals.
    1022  *
    1023  * So, best solution is to set the HWND for the surface after the surface
    1024  * creation, so every blit will be done from application's message processing
    1025  * loop, which is the safest way to do.
    1026  *
    1027  * Since: 1.4
    1028  **/
    1029 void
    1030 cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
    1031                             HWND             hwnd_client_window)
     841
     842static void
     843_cairo_os2_surface_release_source_image (void                   *abstract_surface,
     844                                         cairo_image_surface_t  *image,
     845                                         void                   *image_extra)
    1032846{
    1033     cairo_os2_surface_t *local_os2_surface;
    1034 
    1035     local_os2_surface = (cairo_os2_surface_t *) surface;
    1036     if ((!local_os2_surface) ||
    1037         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    1038     {
    1039         /* Invalid parameter (wrong surface)! */
    1040         return;
    1041     }
     847}
    1042848
    1043     if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
    1044         != NO_ERROR)
    1045     {
    1046         /* Could not get mutex! */
    1047         return;
    1048     }
    1049849
    1050     local_os2_surface->hwnd_client_window = hwnd_client_window;
     850static cairo_status_t
     851_cairo_os2_surface_acquire_dest_image (void                    *abstract_surface,
     852                                       cairo_rectangle_int_t   *interest_rect,
     853                                       cairo_image_surface_t  **image_out,
     854                                       cairo_rectangle_int_t   *image_rect_out,
     855                                       void                   **image_extra)
     856{
     857    cairo_os2_surface_t *surface = abstract_surface;
     858
     859    if (!surface->image)
     860        return CAIRO_STATUS_NULL_POINTER;
    1051861
    1052     DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
     862    return _cairo_surface_acquire_dest_image (surface->image,
     863                                              interest_rect, image_out,
     864                                              image_rect_out, image_extra);
    1053865}
    1054866
    1055 /**
    1056  * cairo_os2_surface_set_manual_window_refresh:
    1057  * @surface: the cairo surface to set the refresh mode for
    1058  * @manual_refresh: the switch for manual surface refresh
    1059  *
    1060  * This API can tell Cairo if it should show every change to this surface
    1061  * immediately in the window or if it should be cached and will only be visible
    1062  * once the user calls cairo_os2_surface_refresh_window() explicitly. If the
    1063  * HWND was not set in the cairo surface, then the HPS will be used to blit the
    1064  * graphics. Otherwise it will invalidate the given window region so the user
    1065  * will get the WM_PAINT message to redraw that area of the window.
    1066  *
    1067  * So, if you're only interested in displaying the final result after several
    1068  * drawing operations, you might get better performance if you put the surface
    1069  * into manual refresh mode by passing a true value to this function. Then call
    1070  * cairo_os2_surface_refresh() whenever desired.
    1071  *
    1072  * Since: 1.4
    1073  **/
    1074 void
    1075 cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
    1076                                              cairo_bool_t     manual_refresh)
     867
     868static void
     869_cairo_os2_surface_release_dest_image (void                   *abstract_surface,
     870                                       cairo_rectangle_int_t  *interest_rect,
     871                                       cairo_image_surface_t  *image,
     872                                       cairo_rectangle_int_t  *image_rect,
     873                                       void                   *image_extra)
    1077874{
    1078     cairo_os2_surface_t *local_os2_surface;
    1079 
    1080     local_os2_surface = (cairo_os2_surface_t *) surface;
    1081     if ((!local_os2_surface) ||
    1082         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    1083     {
    1084         /* Invalid parameter (wrong surface)! */
    1085         return;
    1086     }
     875}
     876
    1087877
    1088     local_os2_surface->blit_as_changes = !manual_refresh;
     878static cairo_int_status_t
     879_cairo_os2_surface_composite (cairo_operator_t        op,
     880                              const cairo_pattern_t  *src_pattern,
     881                              const cairo_pattern_t  *mask_pattern,
     882                              void                   *abstract_dst,
     883                              int                     src_x,
     884                              int                     src_y,
     885                              int                     mask_x,
     886                              int                     mask_y,
     887                              int                     dst_x,
     888                              int                     dst_y,
     889                              unsigned int            width,
     890                              unsigned int            height,
     891                              cairo_region_t         *clip_region)
     892{
     893    cairo_os2_surface_t *surface = abstract_dst;
     894
     895    if (!surface->image)
     896        return CAIRO_STATUS_SUCCESS;
     897
     898    return _cairo_surface_composite (op, src_pattern, mask_pattern,
     899                                     surface->image, src_x, src_y,
     900                                     mask_x, mask_y, dst_x, dst_y,
     901                                     width, height, clip_region);
    1089902}
    1090903
    1091 /**
    1092  * cairo_os2_surface_get_manual_window_refresh:
    1093  * @surface: the cairo surface to query the refresh mode from
    1094  *
    1095  * This space left intentionally blank.
    1096  *
    1097  * Return value: current refresh mode of the surface (true by default)
    1098  *
    1099  * Since: 1.4
    1100  **/
    1101 cairo_bool_t
    1102 cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface)
     904
     905static cairo_int_status_t
     906_cairo_os2_surface_fill_rectangles (void                   *abstract_surface,
     907                                    cairo_operator_t        op,
     908                                    const cairo_color_t    *color,
     909                                    cairo_rectangle_int_t  *rects,
     910                                    int                     num_rects)
    1103911{
    1104     cairo_os2_surface_t *local_os2_surface;
     912    cairo_os2_surface_t *surface = abstract_surface;
    1105913
    1106     local_os2_surface = (cairo_os2_surface_t *) surface;
    1107     if ((!local_os2_surface) ||
    1108         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    1109     {
    1110         /* Invalid parameter (wrong surface)! */
    1111         return FALSE;
    1112     }
     914    if (!surface->image)
     915        return CAIRO_STATUS_SUCCESS;
    1113916
    1114     return !(local_os2_surface->blit_as_changes);
     917    return _cairo_surface_fill_rectangles (surface->image, op,
     918                                           color, rects, num_rects);
    1115919}
    1116920
    1117 /**
    1118  * cairo_os2_surface_get_hps:
    1119  * @surface: the cairo surface to be querued
    1120  * @hps: HPS currently associated with the surface (if any)
    1121  *
    1122  * This API retrieves the HPS associated with the surface.
    1123  *
    1124  * Return value: %CAIRO_STATUS_SUCCESS if the hps could be retrieved,
    1125  * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface,
    1126  * %CAIRO_STATUS_NULL_POINTER if the hps argument is null
    1127  *
    1128  * Since: 1.10
    1129  **/
    1130 cairo_status_t
    1131 cairo_os2_surface_get_hps (cairo_surface_t *surface,
    1132                            HPS             *hps)
     921
     922static cairo_int_status_t
     923_cairo_os2_surface_composite_trapezoids (cairo_operator_t        op,
     924                                         const cairo_pattern_t  *pattern,
     925                                         void                   *abstract_dst,
     926                                         cairo_antialias_t       antialias,
     927                                         int                     src_x,
     928                                         int                     src_y,
     929                                         int                     dst_x,
     930                                         int                     dst_y,
     931                                         unsigned int            width,
     932                                         unsigned int            height,
     933                                         cairo_trapezoid_t      *traps,
     934                                         int                     num_traps,
     935                                         cairo_region_t         *clip_region)
    1133936{
    1134     cairo_os2_surface_t *local_os2_surface;
     937    cairo_os2_surface_t *surface = abstract_dst;
    1135938
    1136     local_os2_surface = (cairo_os2_surface_t *) surface;
    1137     if ((!local_os2_surface) ||
    1138         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    1139     {
    1140         /* Invalid parameter (wrong surface)! */
    1141         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    1142     }
    1143     if (!hps)
    1144     {
    1145         return _cairo_error (CAIRO_STATUS_NULL_POINTER);
    1146     }
    1147     *hps = local_os2_surface->hps_client_window;
     939    if (!surface->image)
     940        return CAIRO_STATUS_SUCCESS;
    1148941
    1149     return CAIRO_STATUS_SUCCESS;
     942    return _cairo_surface_composite_trapezoids (op, pattern, surface->image,
     943                                                antialias, src_x, src_y,
     944                                                dst_x, dst_y, width, height,
     945                                                traps, num_traps, clip_region);
    1150946}
    1151947
    1152 /**
    1153  * cairo_os2_surface_set_hps:
    1154  * @surface: the cairo surface to associate with the HPS
    1155  * @hps: new HPS to be associated with the surface (the HPS may be null)
    1156  *
    1157  * This API replaces the HPS associated with the surface with a new one.
    1158  * The caller retains ownership of the HPS and must dispose of it after
    1159  * the surface has been destroyed or it has been replaced by another
    1160  * call to this function.
    1161  *
    1162  * Return value: %CAIRO_STATUS_SUCCESS if the hps could be replaced,
    1163  * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface,
    1164  *
    1165  * Since: 1.10
    1166  **/
    1167 cairo_status_t
    1168 cairo_os2_surface_set_hps (cairo_surface_t *surface,
    1169                            HPS              hps)
     948
     949static cairo_span_renderer_t *
     950_cairo_os2_surface_create_span_renderer (cairo_operator_t        op,
     951                                         const cairo_pattern_t  *pattern,
     952                                         void                   *abstract_dst,
     953                                         cairo_antialias_t       antialias,
     954                                         const cairo_composite_rectangles_t *rects,
     955                                         cairo_region_t         *clip_region)
    1170956{
    1171     cairo_os2_surface_t *local_os2_surface;
     957    cairo_os2_surface_t *surface = abstract_dst;
    1172958
    1173     local_os2_surface = (cairo_os2_surface_t *) surface;
    1174     if ((!local_os2_surface) ||
    1175         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    1176     {
    1177         /* Invalid parameter (wrong surface)! */
    1178         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    1179     }
    1180     local_os2_surface->hps_client_window = hps;
     959    if (!surface->image)
     960        return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NULL_POINTER);
    1181961
    1182     return CAIRO_STATUS_SUCCESS;
     962    return _cairo_surface_create_span_renderer (op, pattern, surface->image,
     963                                                antialias, rects, clip_region);
    1183964}
    1184965
    1185 static cairo_status_t
    1186 _cairo_os2_surface_mark_dirty_rectangle (void *surface,
    1187                                          int   x,
    1188                                          int   y,
    1189                                          int   width,
    1190                                          int   height)
     966
     967static cairo_bool_t
     968_cairo_os2_surface_check_span_renderer (cairo_operator_t        op,
     969                                        const cairo_pattern_t  *pattern,
     970                                        void                   *abstract_dst,
     971                                        cairo_antialias_t       antialias)
    1191972{
    1192     cairo_os2_surface_t *local_os2_surface;
    1193     RECTL rclToBlit;
    1194 
    1195     local_os2_surface = (cairo_os2_surface_t *) surface;
    1196     if ((!local_os2_surface) ||
    1197         (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    1198     {
    1199         /* Invalid parameter (wrong surface)! */
    1200         return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    1201     }
     973    cairo_os2_surface_t *surface = abstract_dst;
    1202974
    1203     /* Get mutex, we'll work with the pixel array! */
    1204     if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
    1205         != NO_ERROR)
    1206     {
    1207         /* Could not get mutex! */
    1208         return CAIRO_STATUS_NO_MEMORY;
    1209     }
     975    if (!surface->image)
     976        return FALSE;
    1210977
    1211     /* Check for defaults */
    1212     if (width < 0)
    1213         width = local_os2_surface->bitmap_info.cx;
    1214     if (height < 0)
    1215         height = local_os2_surface->bitmap_info.cy;
    1216 
    1217     if (local_os2_surface->hwnd_client_window) {
    1218         /* We know the HWND, so let's invalidate the window region,
    1219          * so the application will redraw itself, using the
    1220          * cairo_os2_surface_refresh_window () API from its own PM thread.
    1221          * From that function we'll note that it's not a redraw but a
    1222          * dirty-rectangle deal stuff, so we'll handle the things from
    1223          * there.
    1224          *
    1225          * This is the safe method, which should be preferred every time.
    1226          */
    1227         rclToBlit.xLeft = x;
    1228         rclToBlit.xRight = x + width; /* Noninclusive */
    1229         rclToBlit.yTop = local_os2_surface->bitmap_info.cy - (y);
    1230         rclToBlit.yBottom = local_os2_surface->bitmap_info.cy - (y + height); /* Noninclusive */
    1231 
    1232 #if 0
    1233         if (local_os2_surface->dirty_area_present) {
    1234             /* Yikes, there is already a dirty area which should be
    1235              * cleaned up, but we'll overwrite it. Sorry.
    1236              * TODO: Something clever should be done here.
    1237              */
    1238         }
    1239 #endif
     978    return _cairo_surface_check_span_renderer (op, pattern,
     979                                               surface->image,
     980                                               antialias);
     981}
    1240982
    1241         /* Set up dirty area reminder stuff */
    1242         memcpy (&(local_os2_surface->rcl_dirty_area), &rclToBlit, sizeof (RECTL));
    1243         local_os2_surface->dirty_area_present = TRUE;
    1244 
    1245         /* Invalidate window area */
    1246         WinInvalidateRect (local_os2_surface->hwnd_client_window,
    1247                            &rclToBlit,
    1248                            FALSE);
    1249     } else {
    1250         /* We don't know the HWND, so try to blit the pixels from here!
    1251          * Please note that it can be problematic if this is not the PM thread!
    1252          *
    1253          * It can cause internal PM stuffs to be scewed up, for some reason.
    1254          * Please always tell the HWND to the surface using the
    1255          * cairo_os2_surface_set_hwnd () API, and call cairo_os2_surface_refresh_window ()
    1256          * from your WM_PAINT, if it's possible!
    1257          */
    1258983
    1259         rclToBlit.xLeft = x;
    1260         rclToBlit.xRight = x + width; /* Noninclusive */
    1261         rclToBlit.yBottom = y;
    1262         rclToBlit.yTop = y + height; /* Noninclusive */
    1263         /* Now get the pixels from the screen! */
    1264         _cairo_os2_surface_get_pixels_from_screen (local_os2_surface,
    1265                                                    local_os2_surface->hps_client_window,
    1266                                                    &rclToBlit);
    1267     }
     984static cairo_bool_t
     985_cairo_os2_surface_get_extents (void                   *abstract_surface,
     986                                cairo_rectangle_int_t  *rectangle)
     987{
     988    cairo_os2_surface_t *surface = abstract_surface;
    1268989
    1269     DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
     990    rectangle->x = 0;
     991    rectangle->y = 0;
     992    rectangle->width  = surface->width;
     993    rectangle->height = surface->height;
    1270994
    1271     return CAIRO_STATUS_SUCCESS;
     995    return TRUE;
     996}
     997
     998
     999static void
     1000_cairo_os2_surface_get_font_options (void                  *abstract_surface,
     1001                                     cairo_font_options_t  *options)
     1002{
     1003    cairo_os2_surface_t *surface = abstract_surface;
     1004
     1005    if (surface->image)
     1006        cairo_surface_get_font_options (surface->image, options);
     1007    else
     1008        _cairo_font_options_init_default (options);
    12721009}
    12731010
     1011
    12741012static const cairo_surface_backend_t cairo_os2_surface_backend = {
    12751013    CAIRO_SURFACE_TYPE_OS2,
    12761014    _cairo_os2_surface_finish,
    12771015    _cairo_default_context_create,
    1278 
    1279     NULL, /* create_similar */
     1016    _cairo_os2_surface_create_similar,
    12801017    NULL, /* create_similar_image */
    12811018    NULL, /* map_to_image */
    12821019    NULL, /* unmap_image */
    1283 
    12841020    _cairo_os2_surface_acquire_source_image,
    12851021    _cairo_os2_surface_release_source_image,
    12861022    _cairo_os2_surface_acquire_dest_image,
    12871023    _cairo_os2_surface_release_dest_image,
    12881024    NULL, /* clone_similar */
    1289     NULL, /* composite */
    1290     NULL, /* fill_rectangles */
    1291     NULL, /* composite_trapezoids */
    1292     NULL, /* create_span_renderer */
    1293     NULL, /* check_span_renderer */
     1025    _cairo_os2_surface_composite,
     1026    _cairo_os2_surface_fill_rectangles,
     1027    _cairo_os2_surface_composite_trapezoids,
     1028    _cairo_os2_surface_create_span_renderer,
     1029    _cairo_os2_surface_check_span_renderer,
    12941030    NULL, /* copy_page */
    12951031    NULL, /* show_page */
    12961032    _cairo_os2_surface_get_extents,
    12971033    NULL, /* old_show_glyphs */
    1298     NULL, /* get_font_options */
     1034    _cairo_os2_surface_get_font_options,
    12991035    NULL, /* flush */
    1300     _cairo_os2_surface_mark_dirty_rectangle,
     1036    NULL, /* mark_dirty_rectangle */
    13011037    NULL, /* scaled_font_fini */
    13021038    NULL, /* scaled_glyph_fini */
    13031039    NULL, /* paint */
    static const cairo_surface_backend_t cairo_os2_surface_backend = { 
    13131049    NULL, /* has_show_text_glyphs */
    13141050    NULL  /* show_text_glyphs */
    13151051};
     1052
     1053
     1054/**
     1055 *
     1056 *  Static helper functions
     1057 *
     1058 **/
     1059
     1060/**
     1061 * _cairo_os2_surface_init_image:
     1062 * @surface: the cairo_os2_surface to associate with an cairo_image_surface
     1063 *
     1064 * Creates the image surface that underlies a cairo_os2_surface.
     1065 * If the surface's area is not empty, it allocates the memory the image
     1066 * surface will use for its bitmap.  The image surface is always created,
     1067 * regardless of whether its area is empty and is left in its default state
     1068 * of transparent black.
     1069 *
     1070 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     1071 *          %CAIRO_STATUS_NO_MEMORY if an image buffer can't be allocated,
     1072 *          or one of several errors if image_surface creation fails.
     1073 *
     1074 * Since: 1.12
     1075 **/
     1076
     1077static cairo_status_t
     1078_cairo_os2_surface_init_image (cairo_os2_surface_t *surface)
     1079{
     1080    cairo_status_t status;
     1081    int            size = surface->stride * surface->height;
     1082
     1083    if (size) {
     1084        surface->data = _cairo_os2_surface_alloc (size);
     1085        if (!surface->data)
     1086            return CAIRO_STATUS_NO_MEMORY;
     1087    }
     1088
     1089    surface->image = cairo_image_surface_create_for_data (surface->data,
     1090                                                          surface->format,
     1091                                                          surface->width,
     1092                                                          surface->height,
     1093                                                          surface->stride);
     1094
     1095    status = cairo_surface_status (surface->image);
     1096    if (_cairo_status_is_error(status))
     1097        return status;
     1098
     1099    return status;
     1100}
     1101
     1102
     1103/**
     1104 * _cairo_os2_surface_alloc:
     1105 * @size: the number of bytes to allocate
     1106 *
     1107 * Allocates the memory passed to cairo_image_surface_create_for_data()
     1108 * that will be used for its bitmap.
     1109 *
     1110 * Returns: a pointer to the newly allocated buffer if successful,
     1111 *          %NULL otherwise.
     1112 *
     1113 * Since: 1.12
     1114 **/
     1115
     1116static unsigned char *
     1117_cairo_os2_surface_alloc (unsigned int size)
     1118{
     1119    void  *buffer;
     1120
     1121#ifdef OS2_USE_PLATFORM_ALLOC
     1122# ifdef OS2_HIGH_MEMORY
     1123    if (!DosAllocMem (&buffer, size,
     1124                      OBJ_ANY | PAG_READ | PAG_WRITE | PAG_COMMIT))
     1125        return buffer;
     1126# endif
     1127    if (DosAllocMem (&buffer, size,
     1128                     PAG_READ | PAG_WRITE | PAG_COMMIT))
     1129        buffer = NULL;
     1130
     1131    return buffer;
     1132#else
     1133    buffer = malloc (size);
     1134    if (buffer)
     1135        memset (buffer, 0, size);
     1136
     1137    return buffer;
     1138#endif
     1139}
     1140
     1141
     1142/**
     1143 * _cairo_os2_surface_free:
     1144 * @buffer: the allocation to free
     1145 *
     1146 * Frees bitmap-data memory allocated by _cairo_os2_surface_alloc.
     1147 *
     1148 * Returns: no return value,
     1149 *
     1150 * Since: 1.12
     1151 **/
     1152
     1153static void
     1154_cairo_os2_surface_free (void *buffer)
     1155{
     1156#ifdef OS2_USE_PLATFORM_ALLOC
     1157    DosFreeMem (buffer);
     1158#else
     1159    free (buffer);
     1160#endif
     1161}
     1162
     1163
     1164/**
     1165 * _cairo_os2_surface_paint_32bpp:
     1166 * @surface: the cairo_os2_surface to display
     1167 * @hps: presentation space handle associated with the target device
     1168 * @src: an array of native RECTL structure identifying those areas of
     1169 *   the source surface which will be painted onto the destination
     1170 * @dst: an array of native RECTL structure that identify where on the
     1171 *   destination surface the corresponding @src rectangles will be painted
     1172 * @count: the number of RECTLs in @src and @dst arrays
     1173 *
     1174 * Uses standard GPI functions and structures to paint selected portions
     1175 * of the surface onto the presentation space identified by @hps.  If
     1176 * the @src and @dst rectangles are not the same size, GpiDrawBits() will
     1177 * expand or compress the image as needed.  Y-inversion is temporarily
     1178 * enabled for the presentation space so that Cairo's top-line-first
     1179 * bitmaps will be handled correctly.
     1180 *
     1181 * This function assumes the driver for the device context associated
     1182 * with @hps is able to handle 32-bit bitmap data as input and can
     1183 * convert it to an appropriate format/color-depth as needed.  If not,
     1184 * the function returns %CAIRO_STATUS_DEVICE_ERROR to signal that the
     1185 * 24-bit version of this function should be used instead.
     1186 *
     1187 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     1188 *          %CAIRO_STATUS_DEVICE_ERROR if the bit-blit fails.
     1189 *
     1190 * Since: 1.12
     1191 **/
     1192
     1193static cairo_status_t
     1194_cairo_os2_surface_paint_32bpp (cairo_os2_surface_t *surface,
     1195                                HPS                  hps,
     1196                                RECTL               *src,
     1197                                RECTL               *dst,
     1198                                int                  count)
     1199{
     1200    cairo_status_t status = CAIRO_STATUS_SUCCESS;
     1201    int            inversion;
     1202    int            ndx;
     1203    BITMAPINFO2    bmi;
     1204
     1205    /* Set up the bitmap header for 32bit depth. */
     1206    memset(&bmi, 0, sizeof (BITMAPINFO2));
     1207    bmi.cbFix = sizeof (BITMAPINFO2) - sizeof (bmi.argbColor[0]);
     1208    bmi.cx = surface->width;
     1209    bmi.cy = surface->height;
     1210    bmi.cPlanes = 1;
     1211    bmi.cBitCount = 32;
     1212
     1213    /* Enable Y Inversion for the HPS, so  GpiDrawBits will work with
     1214     * Cairo's top-line-first bitmap (vs OS/2's bottom-line-first bitmaps)
     1215     */
     1216    inversion = GpiQueryYInversion (hps);
     1217    GpiEnableYInversion (hps, surface->height - 1);
     1218
     1219    for (ndx = 0; ndx < count; ndx++) {
     1220        POINTL  aPtl[4];
     1221
     1222        /* Change y values from OS/2's coordinate system to Cairo's;
     1223         * swap top & bottom to accommodate Y-inversion setting;
     1224         * and make the destination coordinates non-inclusive.
     1225         */
     1226        aPtl[0].x = dst[ndx].xLeft;
     1227        aPtl[0].y = surface->height - dst[ndx].yTop;
     1228        aPtl[1].x = dst[ndx].xRight - 1;
     1229        aPtl[1].y = surface->height - dst[ndx].yBottom - 1;
     1230
     1231        aPtl[2].x = src[ndx].xLeft;
     1232        aPtl[2].y = surface->height - src[ndx].yTop;
     1233        aPtl[3].x = src[ndx].xRight;
     1234        aPtl[3].y = surface->height - src[ndx].yBottom;
     1235
     1236        /* paint */
     1237        if (GpiDrawBits (hps, surface->data, &bmi,
     1238                         4, aPtl, ROP_SRCCOPY, BBO_IGNORE) != GPI_OK) {
     1239            status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
     1240            break;
     1241        }
     1242    }
     1243
     1244    /* Restore Y inversion */
     1245    GpiEnableYInversion (hps, inversion);
     1246
     1247    return status;
     1248}
     1249
     1250
     1251/**
     1252 * _cairo_os2_surface_paint_24bpp:
     1253 * @surface: the cairo_os2_surface to display
     1254 * @hps: presentation space handle associated with the target device
     1255 * @src: an array of native RECTL structure identifying those areas of
     1256 *   the source surface which will be painted onto the destination
     1257 * @dst: an array of native RECTL structure that identify where on the
     1258 *   destination surface the corresponding @src rectangles will be painted
     1259 * @count: the number of RECTLs in @src and @dst arrays
     1260 *
     1261 * This is a fallback function used when the driver for the device context
     1262 * associated with @hps is unable to handle 32-bit bitmaps as input.  For
     1263 * each rectangle to be displayed, it copies that part of the surface to a
     1264 * temporary buffer, dropping the high-order byte to create a 24-bit bitmap.
     1265 *
     1266 * It temporarily enables Y-inversion for the presentation space so that
     1267 * Cairo's top-line-first bitmaps will be handled correctly.
     1268 *
     1269 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     1270 *          %CAIRO_STATUS_DEVICE_ERROR if the bit-blit fails,
     1271 *          CAIRO_STATUS_NO_MEMORY if a buffer allocation fails.
     1272 *
     1273 * Since: 1.12
     1274 **/
     1275
     1276static cairo_status_t
     1277_cairo_os2_surface_paint_24bpp (cairo_os2_surface_t *surface,
     1278                                HPS                  hps,
     1279                                RECTL               *src,
     1280                                RECTL               *dst,
     1281                                int                  count)
     1282{
     1283    cairo_status_t status = CAIRO_STATUS_SUCCESS;
     1284    int            inversion;
     1285    int            ndx;
     1286    int            bufSize = 0;
     1287    unsigned char *pchBuffer = 0;
     1288    BITMAPINFO2    bmi;
     1289
     1290    /* Set up the bitmap header for 24bit depth. */
     1291    memset(&bmi, 0, sizeof (BITMAPINFO2));
     1292    bmi.cbFix = sizeof (BITMAPINFO2) - sizeof (bmi.argbColor[0]);
     1293    bmi.cPlanes = 1;
     1294    bmi.cBitCount = 24;
     1295
     1296    /* Enable Y Inversion for the HPS, so  GpiDrawBits will work with
     1297     * Cairo's top-line-first bitmap (vs OS/2's bottom-line-first bitmaps)
     1298     */
     1299    inversion = GpiQueryYInversion (hps);
     1300    GpiEnableYInversion (hps, surface->height - 1);
     1301
     1302    for (ndx = 0; ndx < count; ndx++) {
     1303
     1304        int             tgt_stride;
     1305        int             tgt_pad;
     1306        int             src_advance;
     1307        int             x_ctr;
     1308        int             y_ctr;
     1309        unsigned char  *pchTarget;
     1310        unsigned int   *pulSource;
     1311        POINTL          aPtl[4];
     1312
     1313        /* For the destination, change y values from OS/2's coordinate
     1314         * system to Cairo's;  swap top & bottom to accommodate the
     1315         * Y-inversion setting;  and make its coordinates non-inclusive.
     1316         */
     1317        aPtl[0].x = dst[ndx].xLeft;
     1318        aPtl[0].y = surface->height - dst[ndx].yTop;
     1319        aPtl[1].x = dst[ndx].xRight - 1;
     1320        aPtl[1].y = surface->height - dst[ndx].yBottom - 1;
     1321
     1322        /* For the source, calc its size and map its coordinates to
     1323         * the origin of the buffer that will contain the 24-bit data.
     1324         */
     1325        bmi.cx = src[ndx].xRight - src[ndx].xLeft;
     1326        bmi.cy = src[ndx].yTop - src[ndx].yBottom;
     1327        aPtl[2].x = 0;
     1328        aPtl[2].y = 0;
     1329        aPtl[3].x = bmi.cx;
     1330        aPtl[3].y = bmi.cy;
     1331
     1332        /* The start of each row has to be DWORD aligned.  For the 24-bit
     1333         * target bitmap, calculate the of number aligned bytes per row
     1334         * and the number of padding bytes at the end of each row.  For
     1335         * the 32-bit source bitmap, calc the number of bytes to advance
     1336         * to the starting position on its next row.
     1337         */
     1338        tgt_stride = (((bmi.cx * bmi.cBitCount) + 31) / 32) * 4;
     1339        tgt_pad = tgt_stride - bmi.cx * 3;
     1340        src_advance = surface->stride - bmi.cx * 4;
     1341
     1342        /* If the existing temporary bitmap buffer is large enough,
     1343         * reuse it;  otherwise, allocate a new one.  If the rows
     1344         * don't need padding, it has to be 1 byte larger than the
     1345         * size of the bitmap or else the high-order byte from the
     1346         * last source row will end up in unallocated memory.
     1347         */
     1348        x_ctr = tgt_stride * bmi.cy + (tgt_pad ? 0 : 1);
     1349        if (x_ctr > bufSize) {
     1350            bufSize = x_ctr;
     1351            if (pchBuffer)
     1352                _cairo_os2_surface_free (pchBuffer);
     1353            pchBuffer = _cairo_os2_surface_alloc (bufSize);
     1354            if (!pchBuffer) {
     1355                status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     1356                break;
     1357            }
     1358        }
     1359
     1360        /* Calc the starting address in the source buffer. */
     1361        pulSource = (unsigned int*) (surface->data + (src[ndx].xLeft * 4) +
     1362                       ((surface->height - src[ndx].yTop) * surface->stride));
     1363
     1364        pchTarget = pchBuffer;
     1365
     1366        /* Copy 4 bytes from the source but advance the target ptr only
     1367         * 3 bytes, so the high-order alpha byte will be overwritten by
     1368         * the next copy. At the end of each row, skip over the padding.
     1369         */
     1370        for (y_ctr = bmi.cy; y_ctr; y_ctr--) {
     1371            for (x_ctr = bmi.cx; x_ctr; x_ctr--) {
     1372                *((unsigned int*)pchTarget) = *pulSource++;
     1373                pchTarget += 3;
     1374            }
     1375            pchTarget += tgt_pad;
     1376            pulSource  = (unsigned int*)((char*)pulSource + src_advance);
     1377        }
     1378
     1379        /* paint */
     1380        if (GpiDrawBits (hps, pchBuffer, &bmi,
     1381                         4, aPtl, ROP_SRCCOPY, BBO_IGNORE) != GPI_OK) {
     1382            status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
     1383            break;
     1384        }
     1385    }
     1386
     1387    /* Free the temp buffer */
     1388    if (pchBuffer)
     1389        _cairo_os2_surface_free (pchBuffer);
     1390
     1391    /* Restore Y inversion */
     1392    GpiEnableYInversion (hps, inversion);
     1393
     1394    return status;
     1395}
     1396
     1397
     1398/**
     1399 * _cairo_os2_surface_paint_dive:
     1400 * @surface: the cairo_os2_surface to display
     1401 * @hps: presentation space handle associated with the target window
     1402 * @rect: an array of native RECTL structure identifying the bottom-left
     1403 *   and top-right corners of the areas to be displayed
     1404 * @count: the number RECTLs in @rect's array
     1405 *
     1406 * This function uses DIVE to write those portions of the surface identified
     1407 * by @rect directly to the screen buffer.  It only supports 32- or 24-bit
     1408 * full-color video modes.  To avoid painting overlapping or child windows,
     1409 * it must perform all of the visible-region calculations that GPI normally
     1410 * handles.  Despite this, it provides a significant improvement in speed
     1411 * compared to using GPI functions.
     1412 *
     1413 * Returns: %CAIRO_STATUS_SUCCESS if successful,
     1414 *          %CAIRO_STATUS_DEVICE_ERROR if any native call fails.
     1415 *
     1416 * Since: 1.12
     1417 **/
     1418
     1419static cairo_status_t
     1420_cairo_os2_surface_paint_dive (cairo_os2_surface_t *surface,
     1421                               HPS                  hps,
     1422                               RECTL               *rect,
     1423                               int                  count)
     1424{
     1425    cairo_status_t status = CAIRO_STATUS_DEVICE_ERROR;
     1426    int            rc;
     1427    int            ndx;
     1428    HRGN           rgnVisible = 0;
     1429    HRGN           rgnPaint = 0;
     1430    RGNRECT        rgnrect;
     1431    RECTL          rectWnd;
     1432    RECTL         *rectPtr;
     1433    RECTL         *rectPaint = 0;
     1434
     1435    /* Get the visible region for this window;  if not visible, exit. */
     1436    rgnVisible = GpiCreateRegion (hps, 0, 0);
     1437    if (!rgnVisible)
     1438        goto done;
     1439
     1440    rc = WinQueryVisibleRegion (surface->hwnd, rgnVisible);
     1441    if (rc == RGN_ERROR)
     1442        goto done;
     1443
     1444    if (rc == RGN_NULL) {
     1445        status = CAIRO_STATUS_SUCCESS;
     1446        goto done;
     1447    }
     1448
     1449    /* Create a region from the update rectangles, then AND it against the
     1450     * visible region to produce the series of rects that will be painted.
     1451     */
     1452    rgnPaint = GpiCreateRegion (hps, count, rect);
     1453    if (!rgnPaint)
     1454        goto done;
     1455
     1456    rc = GpiCombineRegion (hps, rgnVisible, rgnPaint, rgnVisible, CRGN_AND);
     1457    if (rc == RGN_ERROR)
     1458        goto done;
     1459
     1460    if (rc == RGN_NULL) {
     1461        status = CAIRO_STATUS_SUCCESS;
     1462        goto done;
     1463    }
     1464
     1465    /* Determine the number of rectangles to paint,
     1466     * allocate memory to store them, then fetch them.
     1467     */
     1468    rgnrect.ircStart = 1;
     1469    rgnrect.crc = (unsigned int)-1;
     1470    rgnrect.crcReturned = 0;
     1471    rgnrect.ulDirection = RECTDIR_LFRT_TOPBOT;
     1472
     1473    if (!GpiQueryRegionRects (hps, rgnVisible, 0, &rgnrect, 0))
     1474        goto done;
     1475
     1476    rectPaint = (RECTL*)malloc (rgnrect.crcReturned * sizeof(RECTL));
     1477    if (!rectPaint)
     1478        goto done;
     1479
     1480    rgnrect.crc = rgnrect.crcReturned;
     1481    rgnrect.crcReturned = 0;
     1482    if (!GpiQueryRegionRects (hps, rgnVisible, 0, &rgnrect, rectPaint))
     1483        goto done;
     1484
     1485    /* Get the window's position in screen coordinates. */
     1486    WinQueryWindowRect (surface->hwnd, &rectWnd);
     1487    WinMapWindowPoints (surface->hwnd, HWND_DESKTOP, (POINTL*)&rectWnd, 2);
     1488
     1489    /* If required by the video driver, hide the mouse pointer. */
     1490    if (dive_hideptr)
     1491        WinShowPointer (HWND_DESKTOP, FALSE);
     1492
     1493    /* Get access to the frame buffer */
     1494    rc = DiveAcquireFrameBuffer (dive_handle, &rectWnd);
     1495    if (rc) {
     1496        _cairo_os2_surface_dive_error ();
     1497        goto done;
     1498    }
     1499
     1500    for (ndx = rgnrect.crcReturned, rectPtr = rectPaint; ndx; ndx--, rectPtr++) {
     1501        int            x;
     1502        int            y;
     1503        unsigned char *srcPtr;
     1504        unsigned char *dstPtr;
     1505
     1506        /* Get the starting point in the surface's buffer. */
     1507        x = rectPtr->xLeft;
     1508        y = surface->height - rectPtr->yTop;
     1509        srcPtr = surface->data + (y * surface->stride) + (x * 4);
     1510
     1511        /* Get the starting point in the frame buffer. */
     1512        x = rectPtr->xLeft + rectWnd.xLeft;
     1513        y = dive_height - (rectPtr->yTop + rectWnd.yBottom);
     1514        dstPtr = dive_scrnbuf + (y * dive_stride) +
     1515                 (x * (display_use24bpp ? 3 : 4));
     1516
     1517        x = (rectPtr->xRight - rectPtr->xLeft);
     1518        y = rectPtr->yTop - rectPtr->yBottom;
     1519
     1520        /* For 24-bit mode, copy 3 bytes at a time but move the source
     1521         * pointer 4 bytes to skip over the alpha byte.  when we reach
     1522         * the right edge of the rect, advance each ptr by the stride
     1523         * minus the distance they've already advanced.
     1524         */
     1525        if (unlikely (display_use24bpp)) {
     1526            int   ndx;
     1527            int   srcAdvance = surface->stride - (x * 4);
     1528            int   dstAdvance = dive_stride - (x * 3);
     1529
     1530            while (y) {
     1531                for (ndx = x; ndx; ndx--) {
     1532                    memcpy (dstPtr, srcPtr, 3);
     1533                    srcPtr += 4;
     1534                    dstPtr += 3;
     1535                }
     1536                srcPtr += srcAdvance;
     1537                dstPtr += dstAdvance;;
     1538                y--;
     1539            }
     1540        } else {
     1541            /* For 32-bit mode, copy an entire line at a time,
     1542             * then advance each pointer by its respective stride.
     1543             */
     1544            x *= 4;
     1545            while (y) {
     1546                memcpy (dstPtr, srcPtr, x);
     1547                srcPtr += surface->stride;
     1548                dstPtr += dive_stride;
     1549                y--;
     1550            }
     1551        }
     1552    }
     1553
     1554    /* Release the frame buffer */
     1555    rc = DiveDeacquireFrameBuffer (dive_handle);
     1556    if (rc) {
     1557        _cairo_os2_surface_dive_error ();
     1558        goto done;
     1559    }
     1560
     1561    status = CAIRO_STATUS_SUCCESS;
     1562
     1563done:
     1564    /* Cleanup */
     1565    if (dive_hideptr)
     1566        WinShowPointer (HWND_DESKTOP, TRUE);
     1567    if (rectPaint)
     1568        free (rectPaint);
     1569    if (rgnPaint)
     1570        GpiDestroyRegion (hps, rgnPaint);
     1571    if (rgnVisible)
     1572        GpiDestroyRegion (hps, rgnVisible);
     1573
     1574    return status;
     1575}
     1576
     1577
     1578/**
     1579 * _cairo_os2_surface_dive_error:
     1580 *
     1581 * Closes DIVE instance if open, resets values, and disables DIVE
     1582 * for this process.  Used when a DIVE function fails.
     1583 *
     1584 * Returns: no return value.
     1585 *
     1586 * Since: 1.12
     1587 **/
     1588
     1589static void
     1590_cairo_os2_surface_dive_error (void)
     1591{
     1592    if (dive_handle)
     1593        DiveClose (dive_handle);
     1594    dive_handle = 0;
     1595    dive_scrnbuf = 0;
     1596    dive_hideptr = TRUE;
     1597    dive_status = -1;
     1598    return;
     1599}
     1600
     1601
     1602/**
     1603 * _cairo_os2_surface_load_dive:
     1604 *
     1605 * Loads dive.dll and gets the entry point addresses used by this module.
     1606 *
     1607 * Returns: %TRUE if successful, %FALSE otherwise.
     1608 *
     1609 * Since: 1.12
     1610 **/
     1611
     1612#ifdef OS2_DYNAMIC_DIVE
     1613
     1614static cairo_bool_t
     1615_cairo_os2_surface_load_dive (void)
     1616{
     1617    HMODULE hmod;
     1618
     1619    if (DosLoadModule (0, 0, "DIVE", &hmod))
     1620        return FALSE;
     1621
     1622    if (DosQueryProcAddr (hmod, ORD_DIVEQUERYCAPS,
     1623                          0,    (PFN*)&pDiveQueryCaps) ||
     1624        DosQueryProcAddr (hmod, ORD_DIVEOPEN,
     1625                          0,    (PFN*)&pDiveOpen) ||
     1626        DosQueryProcAddr (hmod, ORD_DIVECLOSE,
     1627                          0,    (PFN*)&pDiveClose) ||
     1628        DosQueryProcAddr (hmod, ORD_DIVEACQUIREFRAMEBUFFER,
     1629                          0,    (PFN*)&pDiveAcquireFrameBuffer) ||
     1630        DosQueryProcAddr (hmod, ORD_DIVEDEACQUIREFRAMEBUFFER,
     1631                          0,    (PFN*)&pDiveDeacquireFrameBuffer)) {
     1632        DosFreeModule(hmod);
     1633        return FALSE;
     1634    }
     1635
     1636    return TRUE;
     1637}
     1638#endif
     1639
  • src/cairo-os2.h

    diff --git a/src/cairo-os2.h b/src/cairo-os2.h
    index d23f2de..4b84a60 100644
    a b  
    3333 *
    3434 * Contributor(s):
    3535 *     Peter Weilbacher <mozilla@Weilbacher.org>
    36  *     Rich Walsh <dragtext@e-vertise.com>
     36 *     Rich Walsh <rich@e-vertise.com>
    3737 */
    3838
    3939#ifndef _CAIRO_OS2_H_
    4040#define _CAIRO_OS2_H_
    4141
    42 #define INCL_DOS
    43 #define INCL_DOSSEMAPHORES
    44 #define INCL_DOSERRORS
    45 #define INCL_WIN
    46 #define INCL_GPI
    47 
    4842#include "cairo.h"
    4943
    50 #include <os2.h>
    51 
    5244CAIRO_BEGIN_DECLS
    5345
    5446/* The OS/2 Specific Cairo API */
    cairo_os2_fini (void); 
    6254#if CAIRO_HAS_OS2_SURFACE
    6355
    6456cairo_public cairo_surface_t *
    65 cairo_os2_surface_create (HPS hps_client_window,
    66                           int width,
    67                           int height);
     57cairo_os2_surface_create (cairo_format_t  format,
     58                          int             width,
     59                          int             height);
    6860
    6961cairo_public cairo_surface_t *
    70 cairo_os2_surface_create_for_window (HWND hwnd_client_window,
    71                                      int  width,
    72                                      int  height);
    73 
    74 cairo_public void
    75 cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
    76                             HWND             hwnd_client_window);
     62cairo_os2_surface_create_for_window (HWND  hwnd,
     63                                     int   width,
     64                                     int   height);
    7765
    78 cairo_public int
    79 cairo_os2_surface_set_size (cairo_surface_t *surface,
    80                             int              new_width,
    81                             int              new_height,
    82                             int              timeout);
    83 
    84 cairo_public void
    85 cairo_os2_surface_refresh_window (cairo_surface_t *surface,
    86                                   HPS              hps_begin_paint,
    87                                   PRECTL           prcl_begin_paint_rect);
     66cairo_public cairo_surface_t *
     67cairo_os2_surface_create_null_surface (HPS  hps,
     68                                       int  width,
     69                                       int  height);
    8870
    89 cairo_public void
    90 cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
    91                                              cairo_bool_t     manual_refresh);
     71cairo_public cairo_status_t
     72cairo_os2_surface_paint_window (cairo_surface_t *surface,
     73                                HPS              hps,
     74                                RECTL           *rect,
     75                                int              count);
    9276
    93 cairo_public cairo_bool_t
    94 cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface);
     77cairo_public cairo_status_t
     78cairo_os2_surface_paint_bitmap (cairo_surface_t *surface,
     79                                HPS              hps,
     80                                RECTL           *src,
     81                                RECTL           *dst,
     82                                int              count,
     83                                BOOL             use24bpp);
    9584
    9685cairo_public cairo_status_t
    9786cairo_os2_surface_get_hps (cairo_surface_t *surface,
    cairo_public cairo_status_t 
    10190cairo_os2_surface_set_hps (cairo_surface_t *surface,
    10291                           HPS              hps);
    10392
     93cairo_public cairo_status_t
     94cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
     95                            HWND             hwnd);
     96
     97cairo_public cairo_status_t
     98cairo_os2_surface_set_size (cairo_surface_t *surface,
     99                            int              width,
     100                            int              height,
     101                            int              copy);
     102
     103cairo_public cairo_bool_t
     104cairo_os2_surface_enable_dive (cairo_bool_t enable,
     105                               cairo_bool_t hide_pointer);
     106
    104107#else  /* CAIRO_HAS_OS2_SURFACE */
    105108# error Cairo was not compiled with support for the OS/2 backend
    106109#endif /* CAIRO_HAS_OS2_SURFACE */
    cairo_os2_surface_set_hps (cairo_surface_t *surface, 
    108111CAIRO_END_DECLS
    109112
    110113#endif /* _CAIRO_OS2_H_ */
     114