static cairo_status_t
_cairo_os2_surface_finish (void *abstract_surface)
{
    cairo_os2_surface_t *local_os2_surface;

    local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
    if ((!local_os2_surface) ||
        (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    {
        /* Invalid parameter (wrong surface)! */
        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    }

    DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);

    /* Destroy old image surface */
    cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface));
    /* Destroy old pixel buffer */
    _buffer_free (local_os2_surface->pixels);
    DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
    DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);

    /* The memory itself will be free'd by the cairo_surface_destroy ()
     * who called us.
     */

    return CAIRO_STATUS_SUCCESS;
}
/**
 * cairo_os2_surface_set_size:
 * @surface: the cairo surface to resize
 * @new_width: the new width of the surface
 * @new_height: the new height of the surface
 * @timeout: timeout value in milliseconds
 *
 * When the client window is resized, call this API to set the new size in the
 * underlying surface accordingly. This function will reallocate everything,
 * so you'll have to redraw everything in the surface after this call.
 * The surface will contain garbage after the resizing. So the notes of
 * cairo_os2_surface_create() apply here, too.
 *
 * The timeout value specifies how long the function should wait on other parts
 * of the program to release the buffers. It is necessary, because it can happen
 * that Cairo is just drawing something into the surface while we want to
 * destroy and recreate it.
 *
 * Return value: %CAIRO_STATUS_SUCCESS if the surface could be resized,
 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface,
 * %CAIRO_STATUS_INVALID_SIZE for invalid sizes
 * %CAIRO_STATUS_NO_MEMORY if the new size could not be allocated, or if the
 * timeout happened before all the buffers were released
 *
 * Since: 1.4
 **/
int
cairo_os2_surface_set_size (cairo_surface_t *surface,
                            int              new_width,
                            int              new_height,
                            int              timeout)
{
    cairo_os2_surface_t *local_os2_surface;
    unsigned char *pchNewPixels;
    int rc;
    cairo_image_surface_t *pNewImageSurface;

    local_os2_surface = (cairo_os2_surface_t *) surface;
    if ((!local_os2_surface) ||
        (local_os2_surface->base.backend != &cairo_os2_surface_backend))
    {
        /* Invalid parameter (wrong surface)! */
        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    }

    if ((new_width <= 0) ||
        (new_height <= 0))
    {
        /* Invalid size! */
        return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
    }

    /* Allocate memory for new stuffs */
    pchNewPixels = (unsigned char *) _buffer_alloc (new_height, new_width, 4);
    if (!pchNewPixels) {
        /* Not enough memory for the pixels!
         * Everything remains the same!
         */
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    /* Create image surface from new pixel array */
    pNewImageSurface = (cairo_image_surface_t *)
        cairo_image_surface_create_for_data (pchNewPixels,
                                             CAIRO_FORMAT_ARGB32,
                                             new_width,      /* Width */
                                             new_height,     /* Height */
                                             new_width * 4); /* Rowstride */

    if (pNewImageSurface->base.status) {
        /* Could not create image surface!
         * Everything remains the same!
         */
        _buffer_free (pchNewPixels);
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    /* Okay, new memory allocated, so it's time to swap old buffers
     * to new ones!
     */
    if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)!=NO_ERROR) {
        /* Could not get mutex!
         * Everything remains the same!
         */
        cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
        _buffer_free (pchNewPixels);
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    /* We have to make sure that we won't destroy a surface which
     * is lent to some other code (Cairo is drawing into it)!
     */
    while (local_os2_surface->pixel_array_lend_count > 0) {
        ULONG ulPostCount;
        DosResetEventSem (local_os2_surface->hev_pixel_array_came_back, &ulPostCount);
        DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
        /* Wait for somebody to return the pixels! */
        rc = DosWaitEventSem (local_os2_surface->hev_pixel_array_came_back, timeout);
        if (rc != NO_ERROR) {
            /* Either timeout or something wrong... Exit. */
            cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
            _buffer_free (pchNewPixels);
            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        }
        /* Okay, grab mutex and check counter again! */
        if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
            != NO_ERROR)
        {
            /* Could not get mutex!
             * Everything remains the same!
             */
            cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
            _buffer_free (pchNewPixels);
            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        }
    }

    /* Destroy old image surface */
    cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface));
    /* Destroy old pixel buffer */
    _buffer_free (local_os2_surface->pixels);
    /* Set new image surface */
    local_os2_surface->image_surface = pNewImageSurface;
    /* Set new pixel buffer */
    local_os2_surface->pixels = pchNewPixels;
    /* Change bitmap2 structure */
    local_os2_surface->bitmap_info.cx = new_width;
    local_os2_surface->bitmap_info.cy = new_height;

    DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
    return CAIRO_STATUS_SUCCESS;
}
/**
 * cairo_os2_surface_create:
 * @hps_client_window: the presentation handle to bind the surface to
 * @width: the width of the surface
 * @height: the height of the surface
 *
 * Create a Cairo surface which is bound to a given presentation space (HPS).
 * The surface will be created to have the given size.
 * By default every change to the surface will be made visible immediately by
 * blitting it into the window. This can be changed with
 * cairo_os2_surface_set_manual_window_refresh().
 * Note that the surface will contain garbage when created, so the pixels have
 * to be initialized by hand first. You can use the Cairo functions to fill it
 * with black, or use cairo_surface_mark_dirty() to fill the surface with pixels
 * from the window/HPS.
 *
 * Return value: the newly created surface
 *
 * Since: 1.4
 **/
cairo_surface_t *
cairo_os2_surface_create (HPS hps_client_window,
                          int width,
                          int height)
{
    cairo_os2_surface_t *local_os2_surface;
    cairo_status_t status;
    int rc;

    /* Check the size of the window */
    if ((width <= 0) ||
        (height <= 0))
    {
        /* Invalid window size! */
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
    }

    local_os2_surface = (cairo_os2_surface_t *) malloc (sizeof (cairo_os2_surface_t));
    if (!local_os2_surface) {
        /* Not enough memory! */
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
    }

    /* Initialize the OS/2 specific parts of the surface! */

    /* Create mutex semaphore */
    rc = DosCreateMutexSem (NULL,
                            &(local_os2_surface->hmtx_use_private_fields),
                            0,
                            FALSE);
    if (rc != NO_ERROR) {
        /* Could not create mutex semaphore! */
        free (local_os2_surface);
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
    }

    /* Save PS handle */
    local_os2_surface->hps_client_window = hps_client_window;

    /* Defaults */
    local_os2_surface->hwnd_client_window = NULLHANDLE;
    local_os2_surface->blit_as_changes = TRUE;
    local_os2_surface->pixel_array_lend_count = 0;
    rc = DosCreateEventSem (NULL,
                            &(local_os2_surface->hev_pixel_array_came_back),
                            0,
                            FALSE);

    if (rc != NO_ERROR) {
        /* Could not create event semaphore! */
        DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
        free (local_os2_surface);
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
    }

    /* Prepare BITMAPINFO2 structure for our buffer */
    memset (&(local_os2_surface->bitmap_info), 0, sizeof (local_os2_surface->bitmap_info));
    local_os2_surface->bitmap_info.cbFix = sizeof (BITMAPINFOHEADER2);
    local_os2_surface->bitmap_info.cx = width;
    local_os2_surface->bitmap_info.cy = height;
    local_os2_surface->bitmap_info.cPlanes = 1;
    local_os2_surface->bitmap_info.cBitCount = 32;

    /* Allocate memory for pixels */
    local_os2_surface->pixels = (unsigned char *) _buffer_alloc (height, width, 4);
    if (!(local_os2_surface->pixels)) {
        /* Not enough memory for the pixels! */
        DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
        DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
        free (local_os2_surface);
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
    }

    /* Create image surface from pixel array */
    local_os2_surface->image_surface = (cairo_image_surface_t *)
        cairo_image_surface_create_for_data (local_os2_surface->pixels,
                                             CAIRO_FORMAT_ARGB32,
                                             width,      /* Width */
                                             height,     /* Height */
                                             width * 4); /* Rowstride */

    status = local_os2_surface->image_surface->base.status;
    if (status) {
        /* Could not create image surface! */
        _buffer_free (local_os2_surface->pixels);
        DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
        DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
        free (local_os2_surface);
        return _cairo_surface_create_in_error (status);
    }

    /* Initialize base surface */
    _cairo_surface_init (&local_os2_surface->base,
                         &cairo_os2_surface_backend,
                         _cairo_content_from_format (CAIRO_FORMAT_ARGB32));

    return (cairo_surface_t *)local_os2_surface;
}
static void
_cairo_os2_surface_blit_pixels (cairo_os2_surface_t *surface,
                                HPS                  hps_begin_paint,
                                PRECTL               prcl_begin_paint_rect)
{
    POINTL aptlPoints[4];
    LONG lOldYInversion, rc = GPI_OK;

    /* Enable Y Inversion for the HPS, so the
     * GpiDrawBits will work with upside-top image, not with upside-down image!
     */
    lOldYInversion = GpiQueryYInversion (hps_begin_paint);
    GpiEnableYInversion (hps_begin_paint, surface->bitmap_info.cy-1);

    /* Target coordinates (Noninclusive) */
    aptlPoints[0].x = prcl_begin_paint_rect->xLeft;
    aptlPoints[0].y = prcl_begin_paint_rect->yBottom;

    aptlPoints[1].x = prcl_begin_paint_rect->xRight-1;
    aptlPoints[1].y = prcl_begin_paint_rect->yTop-1;

    /* Source coordinates (Inclusive) */
    aptlPoints[2].x = prcl_begin_paint_rect->xLeft;
    aptlPoints[2].y = prcl_begin_paint_rect->yBottom;

    aptlPoints[3].x = prcl_begin_paint_rect->xRight;
    aptlPoints[3].y = (prcl_begin_paint_rect->yTop);

    /* Some extra checking for limits
     * (Dunno if really needed, but had some crashes sometimes without it,
     *  while developing the code...)
     */
    {
        int i;
        for (i = 0; i < 4; i++) {
            if (aptlPoints[i].x < 0)
                aptlPoints[i].x = 0;
            if (aptlPoints[i].y < 0)
                aptlPoints[i].y = 0;
            if (aptlPoints[i].x > (LONG) surface->bitmap_info.cx)
                aptlPoints[i].x = (LONG) surface->bitmap_info.cx;
            if (aptlPoints[i].y > (LONG) surface->bitmap_info.cy)
                aptlPoints[i].y = (LONG) surface->bitmap_info.cy;
        }
    }

    /* Debug code to draw rectangle limits */
#if 0
    {
        int x, y;
        unsigned char *pixels;

        pixels = surface->pixels;
        for (x = 0; x < surface->bitmap_info.cx; x++) {
            for (y = 0; y < surface->bitmap_info.cy; y++) {
                if ((x == 0) ||
                    (y == 0) ||
                    (x == y) ||
                    (x >= surface->bitmap_info.cx-1) ||
                    (y >= surface->bitmap_info.cy-1))
                {
                    pixels[y*surface->bitmap_info.cx*4+x*4] = 255;
                }
            }
        }
    }
#endif
    rc = GpiDrawBits (hps_begin_paint,
                      surface->pixels,
                      &(surface->bitmap_info),
                      4,
                      aptlPoints,
                      ROP_SRCCOPY,
                      BBO_IGNORE);

    if (rc != GPI_OK) {
        /* if GpiDrawBits () failed then this is most likely because the
         * display driver could not handle a 32bit bitmap. So we need to
         * - create a buffer that only contains 3 bytes per pixel
         * - change the bitmap info header to contain 24bit
         * - pass the new buffer to GpiDrawBits () again
         * - clean up the new buffer
         */
        BITMAPINFOHEADER2 bmpheader;
        unsigned char *pchPixBuf, *pchPixSource;
        void *pBufStart;
        ULONG ulPixels;

        /* allocate temporary pixel buffer */
        pchPixBuf = (unsigned char *) _buffer_alloc (surface->bitmap_info.cy,
                                                     surface->bitmap_info.cx,
                                                     3);
        pchPixSource = surface->pixels; /* start at beginning of pixel buffer */
        pBufStart = pchPixBuf; /* remember beginning of the new pixel buffer */

        /* copy the first three bytes for each pixel but skip over the fourth */
        for (ulPixels = 0; ulPixels < surface->bitmap_info.cx * surface->bitmap_info.cy; ulPixels++)
        {
            /* copy BGR from source buffer */
            *pchPixBuf++ = *pchPixSource++;
            *pchPixBuf++ = *pchPixSource++;
            *pchPixBuf++ = *pchPixSource++;
            pchPixSource++; /* jump over alpha channel in source buffer */
        }

        /* jump back to start of the buffer for display and cleanup */
        pchPixBuf = pBufStart;

        /* set up the bitmap header, but this time with 24bit depth only */
        memset (&bmpheader, 0, sizeof (bmpheader));
        bmpheader.cbFix = sizeof (BITMAPINFOHEADER2);
        bmpheader.cx = surface->bitmap_info.cx;
        bmpheader.cy = surface->bitmap_info.cy;
        bmpheader.cPlanes = surface->bitmap_info.cPlanes;
        bmpheader.cBitCount = 24;
        rc = GpiDrawBits (hps_begin_paint,
                          pchPixBuf,
                          (PBITMAPINFO2)&bmpheader,
                          4,
                          aptlPoints,
                          ROP_SRCCOPY,
                          BBO_IGNORE);

        _buffer_free (pchPixBuf);
    }

    /* Restore Y inversion */
    GpiEnableYInversion (hps_begin_paint, lOldYInversion);
}
/**
 * cairo_os2_surface_create:
 * @hps_client_window: the presentation handle to bind the surface to
 * @width: the width of the surface
 * @height: the height of the surface
 *
 * Create a Cairo surface which is bound to a given presentation space (HPS).
 * The caller retains ownership of the HPS and must dispose of it after the
 * the surface has been destroyed.  The surface will be created to have the
 * given size. By default every change to the surface will be made visible
 * immediately by blitting it into the window. This can be changed with
 * cairo_os2_surface_set_manual_window_refresh().
 * Note that the surface will contain garbage when created, so the pixels
 * have to be initialized by hand first. You can use the Cairo functions to
 * fill it with black, or use cairo_surface_mark_dirty() to fill the surface
 * with pixels from the window/HPS.
 *
 * Return value: the newly created surface
 *
 * Since: 1.4
 **/
cairo_surface_t *
cairo_os2_surface_create (HPS hps_client_window,
                          int width,
                          int height)
{
    cairo_os2_surface_t *local_os2_surface = 0;
    cairo_status_t status;
    int rc;

    /* Check the size of the window */
    if ((width <= 0) || (height <= 0)) {
        status = _cairo_error (CAIRO_STATUS_INVALID_SIZE);
        goto error_exit;
    }

    /* Allocate an OS/2 surface structure. */
    local_os2_surface = (cairo_os2_surface_t *) malloc (sizeof (cairo_os2_surface_t));
    if (!local_os2_surface) {
        status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        goto error_exit;
    }

    memset(local_os2_surface, 0, sizeof(cairo_os2_surface_t));

    /* Allocate resources:  mutex & event semaphores and the pixel buffer */
    if (DosCreateMutexSem (NULL,
                           &(local_os2_surface->hmtx_use_private_fields),
                           0,
                           FALSE))
    {
        status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
        goto error_exit;
    }

    if (DosCreateEventSem (NULL,
                           &(local_os2_surface->hev_pixel_array_came_back),
                           0,
                           FALSE))
    {
        status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
        goto error_exit;
    }

    local_os2_surface->pixels = (unsigned char *) _buffer_alloc (height, width, 4);
    if (!local_os2_surface->pixels) {
        status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        goto error_exit;
    }

    /* Create image surface from pixel array */
    local_os2_surface->image_surface = (cairo_image_surface_t *)
        cairo_image_surface_create_for_data (local_os2_surface->pixels,
                                             CAIRO_FORMAT_ARGB32,
                                             width,      /* Width */
                                             height,     /* Height */
                                             width * 4); /* Rowstride */
    status = local_os2_surface->image_surface->base.status;
    if (status)
        goto error_exit;

    /* Set values for OS/2-specific data that aren't zero/NULL/FALSE.
     * Note: hps_client_window may be null if this was called by
     * cairo_os2_surface_create_for_window().
     */
    local_os2_surface->hps_client_window = hps_client_window;
    local_os2_surface->blit_as_changes = TRUE;

    /* Prepare BITMAPINFO2 structure for our buffer */
    local_os2_surface->bitmap_info.cbFix = sizeof (BITMAPINFOHEADER2);
    local_os2_surface->bitmap_info.cx = width;
    local_os2_surface->bitmap_info.cy = height;
    local_os2_surface->bitmap_info.cPlanes = 1;
    local_os2_surface->bitmap_info.cBitCount = 32;

    /* Initialize base surface */
    _cairo_surface_init (&local_os2_surface->base,
                         &cairo_os2_surface_backend,
                         NULL, /* device */
                         _cairo_content_from_format (CAIRO_FORMAT_ARGB32));

    /* Successful exit */
    return (cairo_surface_t *)local_os2_surface;

 error_exit:

    /* This point will only be reached if an error occurred */

    if (local_os2_surface) {
        if (local_os2_surface->pixels)
            _buffer_free (local_os2_surface->pixels);
        if (local_os2_surface->hev_pixel_array_came_back)
            DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
        if (local_os2_surface->hmtx_use_private_fields)
            DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
        free (local_os2_surface);
    }

    return _cairo_surface_create_in_error (status);
}
static void
_cairo_os2_surface_blit_pixels (cairo_os2_surface_t *surface,
                                HPS                  hps_begin_paint,
                                PRECTL               prcl_begin_paint_rect)
{
    POINTL aptlPoints[4];
    LONG   lOldYInversion;
    LONG   rc = GPI_OK;

    /* Check the limits (may not be necessary) */
    if (prcl_begin_paint_rect->xLeft < 0)
        prcl_begin_paint_rect->xLeft = 0;
    if (prcl_begin_paint_rect->yBottom < 0)
        prcl_begin_paint_rect->yBottom = 0;
    if (prcl_begin_paint_rect->xRight > (LONG) surface->bitmap_info.cx)
        prcl_begin_paint_rect->xRight = (LONG) surface->bitmap_info.cx;
    if (prcl_begin_paint_rect->yTop > (LONG) surface->bitmap_info.cy)
        prcl_begin_paint_rect->yTop = (LONG) surface->bitmap_info.cy;

    /* Exit if the rectangle is empty */
    if (prcl_begin_paint_rect->xLeft   >= prcl_begin_paint_rect->xRight ||
        prcl_begin_paint_rect->yBottom >= prcl_begin_paint_rect->yTop)
        return;

    /* Set the Target & Source coordinates */
    *((PRECTL)&aptlPoints[0]) = *prcl_begin_paint_rect;
    *((PRECTL)&aptlPoints[2]) = *prcl_begin_paint_rect;

    /* Make the Target coordinates non-inclusive */
    aptlPoints[1].x -= 1;
    aptlPoints[1].y -= 1;

    /* Enable Y Inversion for the HPS, so  GpiDrawBits will
     * work with upside-top image, not with upside-down image!
     */
    lOldYInversion = GpiQueryYInversion (hps_begin_paint);
    GpiEnableYInversion (hps_begin_paint, surface->bitmap_info.cy-1);

    /* Debug code to draw rectangle limits */
#if 0
    {
        int x, y;
        unsigned char *pixels;

        pixels = surface->pixels;
        for (x = 0; x < surface->bitmap_info.cx; x++) {
            for (y = 0; y < surface->bitmap_info.cy; y++) {
                if ((x == 0) ||
                    (y == 0) ||
                    (x == y) ||
                    (x >= surface->bitmap_info.cx-1) ||
                    (y >= surface->bitmap_info.cy-1))
                {
                    pixels[y*surface->bitmap_info.cx*4+x*4] = 255;
                }
            }
        }
    }
#endif
    if (!surface->use_24bpp) {
        rc = GpiDrawBits (hps_begin_paint,
                          surface->pixels,
                          &(surface->bitmap_info),
                          4,
                          aptlPoints,
                          ROP_SRCCOPY,
                          BBO_IGNORE);
        if (rc != GPI_OK)
            surface->use_24bpp = TRUE;
    }

    if (surface->use_24bpp) {
        /* If GpiDrawBits () failed then this is most likely because the
         * display driver could not handle a 32bit bitmap. So we need to
         * - create a buffer that only contains 3 bytes per pixel
         * - change the bitmap info header to contain 24bit
         * - pass the new buffer to GpiDrawBits () again
         * - clean up the new buffer
         */
        BITMAPINFO2       bmpinfo;
        unsigned char    *pchPixBuf;
        unsigned char    *pchTarget;
        ULONG            *pulSource;
        ULONG             ulX;
        ULONG             ulY;
        ULONG             ulPad;

        /* Set up the bitmap header, but this time for 24bit depth. */
        bmpinfo = surface->bitmap_info;
        bmpinfo.cBitCount = 24;

        /* The start of each row has to be DWORD aligned.  Calculate the
         * of number aligned bytes per row, the total size of the bitmap,
         * and the number of padding bytes at the end of each row.
         */
        ulX = (((bmpinfo.cx * bmpinfo.cBitCount) + 31) / 32) * 4;
        bmpinfo.cbImage = ulX * bmpinfo.cy;
        ulPad = ulX - bmpinfo.cx * 3;

        /* Allocate temporary pixel buffer.  If the rows don't need
         * padding, it has to be 1 byte larger than the size of the
         * bitmap  or else the high-order byte from the last source
         * row will end up in unallocated memory.
         */
        pchPixBuf = (unsigned char *)_buffer_alloc (1, 1,
                                        bmpinfo.cbImage + (ulPad ? 0 : 1));

        if (pchPixBuf) {
            /* Copy 4 bytes from the source but advance the target ptr only
             * 3 bytes, so the high-order alpha byte will be overwritten by
             * the next copy. At the end of each row, skip over the padding.
             */
            pchTarget = pchPixBuf;
            pulSource = (ULONG*)surface->pixels;
            for (ulY = bmpinfo.cy; ulY; ulY--) {
                for (ulX = bmpinfo.cx; ulX; ulX--) {
                    *((ULONG*)pchTarget) = *pulSource++;
                    pchTarget += 3;
                }
                pchTarget += ulPad;
            }

            rc = GpiDrawBits (hps_begin_paint,
                              pchPixBuf,
                              &bmpinfo,
                              4,
                              aptlPoints,
                              ROP_SRCCOPY,
                              BBO_IGNORE);
            if (rc != GPI_OK)
                surface->use_24bpp = FALSE;

            _buffer_free (pchPixBuf);
        }
    }

    /* Restore Y inversion */
    GpiEnableYInversion (hps_begin_paint, lOldYInversion);
}