Changeset 1273 for cairo


Ignore:
Timestamp:
Jan 24, 2016, 11:23:30 PM (9 years ago)
Author:
dmik
Message:

cairo: Rewrite cairo-os2-surface.c to remove app-specific code and add new features.

Based on a patch by Rich Walsh with some adaptions to the newer upstream version
(see #87 for details).

Location:
cairo/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified cairo/trunk/src/cairo-os2-private.h

    r1239 r1273  
    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
     
    3435 * Contributor(s):
    3536 *     Peter Weilbacher <mozilla@Weilbacher.org>
     37 *     Rich Walsh <rich@e-vertise.com>
    3638 */
    3739
     
    3941#define CAIRO_OS2_PRIVATE_H
    4042
     43#include "cairoint.h"
    4144#include "cairo-os2.h"
    42 #include "cairoint.h"
    4345
    44 typedef struct _cairo_os2_surface
    45 {
    46     cairo_surface_t        base;
     46/**
     47 * Unpublished API:
     48 *   GpiEnableYInversion = PMGPI.723
     49 *   GpiQueryYInversion = PMGPI.726
     50 **/
    4751
    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;
     52BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);
     53LONG APIENTRY GpiQueryYInversion (HPS hps);
    5854
    59     RECTL                  rcl_dirty_area;
    60     cairo_bool_t           dirty_area_present;
     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
    6164
    62     /* General flags: */
    63     cairo_bool_t           blit_as_changes;
    64     cairo_bool_t           use_24bpp;
     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;
     142
    65143} cairo_os2_surface_t;
    66144
  • TabularUnified cairo/trunk/src/cairo-os2-surface.c

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

    r1239 r1273  
    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
     
    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
     42#include <os2.h>
    4743
    4844#include "cairo.h"
    49 
    50 #include <os2.h>
    5145
    5246CAIRO_BEGIN_DECLS
     
    6357
    6458cairo_public cairo_surface_t *
    65 cairo_os2_surface_create (HPS hps_client_window,
    66                           int width,
    67                           int height);
     59cairo_os2_surface_create (cairo_format_t  format,
     60                          int             width,
     61                          int             height);
    6862
    6963cairo_public cairo_surface_t *
    70 cairo_os2_surface_create_for_window (HWND hwnd_client_window,
    71                                      int  width,
    72                                      int  height);
     64cairo_os2_surface_create_for_window (HWND  hwnd,
     65                                     int   width,
     66                                     int   height);
    7367
    74 cairo_public void
    75 cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
    76                             HWND             hwnd_client_window);
     68cairo_public cairo_surface_t *
     69cairo_os2_surface_create_null_surface (HPS  hps,
     70                                       int  width,
     71                                       int  height);
    7772
    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);
     73cairo_public cairo_status_t
     74cairo_os2_surface_paint_window (cairo_surface_t *surface,
     75                                HPS              hps,
     76                                RECTL           *rect,
     77                                int              count);
    8378
    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);
    88 
    89 cairo_public void
    90 cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
    91                                              cairo_bool_t     manual_refresh);
    92 
    93 cairo_public cairo_bool_t
    94 cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface);
     79cairo_public cairo_status_t
     80cairo_os2_surface_paint_bitmap (cairo_surface_t *surface,
     81                                HPS              hps,
     82                                RECTL           *src,
     83                                RECTL           *dst,
     84                                int              count,
     85                                BOOL             use24bpp);
    9586
    9687cairo_public cairo_status_t
     
    10293                           HPS              hps);
    10394
     95cairo_public cairo_status_t
     96cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
     97                            HWND             hwnd);
     98
     99cairo_public cairo_status_t
     100cairo_os2_surface_set_size (cairo_surface_t *surface,
     101                            int              width,
     102                            int              height,
     103                            int              copy);
     104
     105cairo_public cairo_bool_t
     106cairo_os2_surface_enable_dive (cairo_bool_t enable,
     107                               cairo_bool_t hide_pointer);
     108
    104109#else  /* CAIRO_HAS_OS2_SURFACE */
    105110# error Cairo was not compiled with support for the OS/2 backend
  • TabularUnified cairo/trunk/test/error-setters.c

    r1239 r1273  
    6767    cairo_os2_surface_set_hwnd (surface, 0);
    6868    cairo_os2_surface_set_size (surface, 0, 0, 0);
    69     cairo_os2_surface_set_manual_window_refresh (surface, FALSE);
    7069#endif
    7170
Note: See TracChangeset for help on using the changeset viewer.