[cairo-commit] 2 commits - configure.in src/cairo.h src/cairoint.h src/cairo-os2.h src/cairo-os2-private.h src/cairo-os2-surface.c src/Makefile.am

Peter Weilbacher pmw at kemper.freedesktop.org
Fri Sep 15 02:47:00 PDT 2006


 configure.in            |   18 
 src/Makefile.am         |    8 
 src/cairo-os2-private.h |   77 +++
 src/cairo-os2-surface.c | 1135 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/cairo-os2.h         |  201 ++++++++
 src/cairo.h             |    4 
 src/cairoint.h          |   11 
 7 files changed, 1453 insertions(+), 1 deletion(-)

New commits:
diff-tree 2fd0ad948931f4be43c81d2c4c56d264605bd737 (from 8c6baacefacbfb9e826d05ae253ead60d4e8e146)
Author: Peter Weilbacher <pmw at schnurps.(none)>
Date:   Fri Sep 15 11:18:47 2006 +0200

    OS/2 build changes

diff --git a/configure.in b/configure.in
index 50c74a1..edffd4f 100644
--- a/configure.in
+++ b/configure.in
@@ -294,6 +294,19 @@ CAIRO_BACKEND_ENABLE(win32_font, Microso
 
 dnl ===========================================================================
 
+CAIRO_BACKEND_ENABLE(os2, OS/2, os2, OS2_SURFACE, no, [
+  case "$host" in
+    *-*-os2*)
+      :
+      ;;
+    *)
+      use_os2="no (requires an OS/2 platform)"
+      ;;
+  esac
+])
+
+dnl ===========================================================================
+
 CAIRO_BACKEND_ENABLE(beos, BeOS/Zeta, beos, BEOS_SURFACE, no, [
   case "$host" in
     *-*-beos)
@@ -826,6 +839,7 @@ echo "  Quartz:        $use_quartz"
 echo "  Native Quartz: $use_nquartz"
 echo "  XCB:           $use_xcb"
 echo "  Win32:         $use_win32"
+echo "  OS2:           $use_os2"
 echo "  PostScript:    $use_ps"
 echo "  PDF:           $use_pdf"
 echo "  SVG:           $use_svg"
@@ -882,6 +896,10 @@ if test x"$use_quartz" = "xyes" ; then
    echo "$WARNING_MESSAGE" | sed 's/@BACKEND@/ATSUI/'
 fi
 
+if test x"$use_os2" = "xyes" ; then
+   echo "$WARNING_MESSAGE" | sed 's, at BACKEND@,OS/2,'
+fi
+
 if test x"$use_beos" = "xyes" ; then
    echo "$WARNING_MESSAGE" | sed 's/@BACKEND@/BeOS/'
 fi
diff --git a/src/Makefile.am b/src/Makefile.am
index 23516c1..b61d291 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -84,6 +84,12 @@ if CAIRO_HAS_WIN32_FONT
 libcairo_win32_sources += cairo-win32-font.c
 endif
 
+libcairo_os2_sources =
+if CAIRO_HAS_OS2_SURFACE
+libcairo_os2_headers = cairo-os2.h
+libcairo_os2_sources += cairo-os2-surface.c cairo-os2-private.h
+endif
+
 libcairo_beos_sources =
 if CAIRO_HAS_BEOS_SURFACE
 libcairo_beos_headers = cairo-beos.h
@@ -140,6 +146,7 @@ cairo_headers =				\
 	$(libcairo_quartz_headers)	\
 	$(libcairo_nquartz_headers)	\
 	$(libcairo_win32_headers)	\
+	$(libcairo_os2_headers)		\
 	$(libcairo_beos_headers)	\
 	$(libcairo_xcb_headers)		\
 	$(libcairo_xlib_headers)	\
@@ -226,6 +233,7 @@ libcairo_la_SOURCES =				\
 	$(libcairo_xcb_sources)			\
 	$(libcairo_glitz_sources)		\
 	$(libcairo_win32_sources)		\
+	$(libcairo_os2_sources)			\
 	$(libcairo_directfb_sources)		\
 	cairoint.h
 
diff --git a/src/cairo.h b/src/cairo.h
index 0325138..661a24e 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1240,6 +1240,7 @@ cairo_surface_status (cairo_surface_t *s
  * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos
  * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb
  * @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg
+ * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2
  *
  * #cairo_surface_type_t is used to describe the type of a given
  * surface. The surface types are also known as "backends" or "surface
@@ -1276,7 +1277,8 @@ typedef enum _cairo_surface_type {
     CAIRO_SURFACE_TYPE_BEOS,
     CAIRO_SURFACE_TYPE_DIRECTFB,
     CAIRO_SURFACE_TYPE_SVG,
-    CAIRO_SURFACE_TYPE_NQUARTZ
+    CAIRO_SURFACE_TYPE_NQUARTZ,
+    CAIRO_SURFACE_TYPE_OS2
 } cairo_surface_type_t;
 
 cairo_public cairo_surface_type_t
diff --git a/src/cairoint.h b/src/cairoint.h
index 53a1130..2d1d455 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -160,6 +160,17 @@ CAIRO_BEGIN_DECLS
 # define CAIRO_MUTEX_UNLOCK(name) LeaveCriticalSection (&name)
 #endif
 
+#if defined(__OS2__) && !defined(CAIRO_MUTEX_DECLARE)
+# define INCL_BASE
+# define INCL_PM
+# include <os2.h>
+
+# define CAIRO_MUTEX_DECLARE(name) extern HMTX name
+# define CAIRO_MUTEX_DECLARE_GLOBAL(name) extern HMTX name
+# define CAIRO_MUTEX_LOCK(name) DosRequestMutexSem(name, SEM_INDEFINITE_WAIT)
+# define CAIRO_MUTEX_UNLOCK(name) DosReleaseMutexSem(name)
+#endif
+
 #if !defined(CAIRO_MUTEX_DECLARE) && defined CAIRO_HAS_BEOS_SURFACE
 cairo_private void _cairo_beos_lock(void*);
 cairo_private void _cairo_beos_unlock(void*);
diff-tree 8c6baacefacbfb9e826d05ae253ead60d4e8e146 (from edfceea853dd6ae189843f138478c7d43fb98367)
Author: Peter Weilbacher <pmw at schnurps.(none)>
Date:   Fri Sep 15 11:18:14 2006 +0200

    OS/2 backend files

diff --git a/src/cairo-os2-private.h b/src/cairo-os2-private.h
new file mode 100644
index 0000000..9ed0c7c
--- /dev/null
+++ b/src/cairo-os2-private.h
@@ -0,0 +1,77 @@
+/* vim: set sw=4 sts=4 et cin: */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright (c) 2005-2006 netlabs.org
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is
+ *     Doodle <doodle at scenergy.dfmk.hu>
+ *
+ * Contributor(s):
+ *     Peter Weilbacher <mozilla at Weilbacher.org>
+ */
+
+#ifndef CAIRO_OS2_PRIVATE_H
+#define CAIRO_OS2_PRIVATE_H
+
+#define INCL_DOS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSERRORS
+#define INCL_WIN
+#define INCL_GPI
+#ifdef __WATCOMC__
+# include <os2.h>
+#else
+# include <os2emx.h>
+#endif
+
+#include <cairo-os2.h>
+#include <cairoint.h>
+
+typedef struct _cairo_os2_surface
+{
+    cairo_surface_t        base;
+
+    /* Mutex semaphore to protect private fields from concurrent access */
+    HMTX                   hmtx_use_private_fields;
+    /* Private fields: */
+    HPS                    hps_client_window;
+    HWND                   hwnd_client_window;
+    BITMAPINFO2            bitmap_info;
+    unsigned char         *pixels;
+    cairo_image_surface_t *image_surface;
+    int                    pixel_array_lend_count;
+    HEV                    hev_pixel_array_came_back;
+
+    RECTL                  rcl_dirty_area;
+    cairo_bool_t           dirty_area_present;
+
+    /* General flags: */
+    cairo_bool_t           blit_as_changes;
+} cairo_os2_surface_t;
+
+#endif /* CAIRO_OS2_PRIVATE_H */
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
new file mode 100644
index 0000000..59718bb
--- /dev/null
+++ b/src/cairo-os2-surface.c
@@ -0,0 +1,1135 @@
+/* vim: set sw=4 sts=4 et cin: */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright (c) 2005-2006 netlabs.org
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is
+ *     Doodle <doodle at scenergy.dfmk.hu>
+ *
+ * Contributor(s):
+ *     Peter Weilbacher <mozilla at Weilbacher.org>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <float.h>
+#ifdef BUILD_CAIRO_DLL
+# define INCL_WIN
+# define INCL_GPI
+# define INCL_DOS
+# define INCL_DOSERRORS
+# include <os2emx.h>
+# include "cairo-os2.h"
+# ifndef __WATCOMC__
+#  include <emx/startup.h>
+# endif
+#endif
+#include "cairoint.h"
+#include "cairo-os2-private.h"
+#include "fontconfig/fontconfig.h"
+
+/*
+ * Here comes the extra API for the OS/2 platform. Currently it consists
+ * of two extra functions, the cairo_os2_init () and the
+ * cairo_os2_fini (). Both of them are called automatically if
+ * Cairo is compiled to be a DLL file, but you have to call them before
+ * using the Cairo API if you link to Cairo statically!
+ *
+ * You'll also find the code in here which deals with DLL initialization
+ * and termination, if the code is built to be a DLL.
+ * (if BUILD_CAIRO_DLL is defined)
+ */
+
+/* Initialization counter: */
+static int cairo_os2_initialization_count = 0;
+
+/* The mutex semaphores Cairo uses all around: */
+HMTX cairo_toy_font_face_hash_table_mutex = 0;
+HMTX cairo_scaled_font_map_mutex = 0;
+HMTX _global_image_glyph_cache_mutex = 0;
+#ifdef CAIRO_HAS_FT_FONT
+HMTX cairo_ft_unscaled_font_map_mutex = 0;
+#endif
+
+static void inline
+DisableFPUException (void)
+{
+    unsigned short usCW;
+
+    /* Some OS/2 PM API calls modify the FPU Control Word,
+     * but forget to restore it.
+     *
+     * This can result in XCPT_FLOAT_INVALID_OPCODE exceptions,
+     * so to be sure, we disable Invalid Opcode FPU exception
+     * before using FPU stuffs.
+     */
+    usCW = _control87 (0, 0);
+    usCW = usCW | EM_INVALID | 0x80;
+    _control87 (usCW, MCW_EM | 0x80);
+}
+
+cairo_public void
+cairo_os2_init (void)
+{
+    /* This may initialize some stuffs, like create mutex semaphores etc.. */
+
+    cairo_os2_initialization_count++;
+    if (cairo_os2_initialization_count > 1) return;
+
+    DisableFPUException ();
+
+    /* Create the mutex semaphores we'll use! */
+
+    /* cairo-font.c: */
+    DosCreateMutexSem (NULL, &cairo_toy_font_face_hash_table_mutex, 0, FALSE);
+    DosCreateMutexSem (NULL, &cairo_scaled_font_map_mutex, 0, FALSE);
+    DosCreateMutexSem (NULL, &_global_image_glyph_cache_mutex, 0, FALSE);
+
+#ifdef CAIRO_HAS_FT_FONT
+    /* cairo-ft-font.c: */
+    DosCreateMutexSem (NULL, &cairo_ft_unscaled_font_map_mutex, 0, FALSE);
+#endif
+
+    /* Initialize FontConfig */
+    FcInit ();
+}
+
+cairo_public void
+cairo_os2_fini (void)
+{
+    /* This has to uninitialize some stuffs, like destroy mutex semaphores etc.. */
+
+    if (cairo_os2_initialization_count <= 0) return;
+    cairo_os2_initialization_count--;
+    if (cairo_os2_initialization_count > 0) return;
+
+    DisableFPUException ();
+
+    /* Free allocated memories! */
+    /* (Check cairo_debug_reset_static_date () for an example of this!) */
+    _cairo_font_reset_static_data ();
+#ifdef CAIRO_HAS_FT_FONT
+    _cairo_ft_font_reset_static_data ();
+#endif
+
+    /* Destroy the mutex semaphores we've created! */
+    /* cairo-font.c: */
+    if (cairo_toy_font_face_hash_table_mutex) {
+        DosCloseMutexSem (cairo_toy_font_face_hash_table_mutex);
+        cairo_toy_font_face_hash_table_mutex = 0;
+    }
+    if (cairo_scaled_font_map_mutex) {
+        DosCloseMutexSem (cairo_scaled_font_map_mutex);
+        cairo_scaled_font_map_mutex = 0;
+    }
+    if (_global_image_glyph_cache_mutex) {
+        DosCloseMutexSem (_global_image_glyph_cache_mutex);
+        _global_image_glyph_cache_mutex = 0;
+    }
+
+#ifdef CAIRO_HAS_FT_FONT
+    /* cairo-ft-font.c: */
+    if (cairo_ft_unscaled_font_map_mutex) {
+        DosCloseMutexSem (cairo_ft_unscaled_font_map_mutex);
+        cairo_ft_unscaled_font_map_mutex = 0;
+    }
+#endif
+
+    /* Uninitialize FontConfig */
+    FcFini ();
+
+#ifdef __WATCOMC__
+    /* It can happen that the libraries we use have memory leaks,
+     * so there are still memory chunks allocated at this point.
+     * In these cases, Watcom might still have a bigger memory chunk,
+     * called "the heap" allocated from the OS.
+     * As we want to minimize the memory we lose from the point of
+     * view of the OS, we call this function to shrink that heap
+     * as much as possible.
+     */
+    _heapshrink ();
+#endif
+}
+
+#ifdef BUILD_CAIRO_DLL
+/* The main DLL entry for DLL initialization and uninitialization */
+/* Only include this code if we're about to build a DLL.          */
+
+#ifdef __WATCOMC__
+unsigned _System
+LibMain (unsigned hmod,
+         unsigned termination)
+#else
+unsigned long _System
+_DLL_InitTerm (unsigned long hModule,
+               unsigned long termination)
+#endif
+{
+    if (termination) {
+        /* Unloading the DLL */
+        cairo_os2_fini ();
+
+#ifndef __WATCOMC__
+        /* Uninitialize RTL of GCC */
+        __ctordtorTerm ();
+        _CRT_term ();
+#endif
+        return 1;
+    } else {
+        /* Loading the DLL */
+#ifndef __WATCOMC__
+        /* Initialize RTL of GCC */
+        if (_CRT_init () != 0)
+            return 0;
+        __ctordtorInit ();
+#endif
+
+        cairo_os2_init ();
+        return 1;
+    }
+}
+
+#endif /* BUILD_CAIRO_DLL */
+
+/*
+ * The following part of the source file contains the code which might
+ * be called the "core" of the OS/2 backend support. This contains the
+ * OS/2 surface support functions and structures.
+ */
+
+/* Forward declaration */
+static const cairo_surface_backend_t cairo_os2_surface_backend;
+
+/* Unpublished API:
+ *   GpiEnableYInversion = PMGPI.723
+ *   GpiQueryYInversion = PMGPI.726
+ *   BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);
+ *   LONG APIENTRY GpiQueryYInversion (HPS hps);
+ */
+BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);
+LONG APIENTRY GpiQueryYInversion (HPS hps);
+
+#ifdef __WATCOMC__
+/* Function declaration for GpiDrawBits () (missing from OpenWatcom headers) */
+LONG APIENTRY GpiDrawBits (HPS hps,
+                           PVOID pBits,
+                           PBITMAPINFO2 pbmiInfoTable,
+                           LONG lCount,
+                           PPOINTL aptlPoints,
+                           LONG lRop,
+                           ULONG flOptions);
+#endif
+
+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;
+
+    /* 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
+    GpiDrawBits (hps_begin_paint,
+                 surface->pixels,
+                 &(surface->bitmap_info),
+                 4,
+                 aptlPoints,
+                 ROP_SRCCOPY,
+                 BBO_IGNORE);
+
+    /* Restore Y inversion */
+    GpiEnableYInversion (hps_begin_paint, lOldYInversion);
+}
+
+static void
+_cairo_os2_surface_get_pixels_from_screen (cairo_os2_surface_t *surface,
+                                           HPS                  hps_begin_paint,
+                                           PRECTL               prcl_begin_paint_rect)
+{
+    HPS hps;
+    HDC hdc;
+    HAB hab;
+    SIZEL sizlTemp;
+    HBITMAP hbmpTemp;
+    BITMAPINFO2 bmi2Temp;
+    POINTL aptlPoints[4];
+    int y;
+    unsigned char *pchTemp;
+
+    /* To copy pixels from screen to our buffer, we do the following steps:
+     *
+     * - Blit pixels from screen to a HBITMAP:
+     *   -- Create Memory Device Context
+     *   -- Create a PS into it
+     *   -- Create a HBITMAP
+     *   -- Select HBITMAP into memory PS
+     *   -- Blit dirty pixels from screen to HBITMAP
+     * - Copy HBITMAP lines (pixels) into our buffer
+     * - Free resources
+     *
+     * These steps will require an Anchor Block (HAB). However,
+     * WinQUeryAnchorBlock () documentation says that HAB is not
+     * used in current OS/2 implementations, OS/2 deduces all information
+     * it needs from the TID. Anyway, we'd be in trouble if we'd have to
+     * get a HAB where we only know a HPS...
+     * So, we'll simply use a fake HAB.
+     */
+
+    hab = (HAB) 1; /* OS/2 doesn't really use HAB... */
+
+    /* Create a memory device context */
+    hdc = DevOpenDC (hab, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
+    if (!hdc) {
+        return;
+    }
+
+    /* Create a memory PS */
+    sizlTemp.cx = prcl_begin_paint_rect->xRight - prcl_begin_paint_rect->xLeft;
+    sizlTemp.cy = prcl_begin_paint_rect->yTop - prcl_begin_paint_rect->yBottom;
+    hps = GpiCreatePS (hab,
+                       hdc,
+                       &sizlTemp,
+                       PU_PELS | GPIT_NORMAL | GPIA_ASSOC );
+    if (!hps) {
+        DevCloseDC (hdc);
+        return;
+    }
+
+    /* Create an uninitialized bitmap. */
+    /* Prepare BITMAPINFO2 structure for our buffer */
+    memset (&bmi2Temp, 0, sizeof (bmi2Temp));
+    bmi2Temp.cbFix = sizeof (BITMAPINFOHEADER2);
+    bmi2Temp.cx = sizlTemp.cx;
+    bmi2Temp.cy = sizlTemp.cy;
+    bmi2Temp.cPlanes = 1;
+    bmi2Temp.cBitCount = 32;
+
+    hbmpTemp = GpiCreateBitmap (hps,
+                                (PBITMAPINFOHEADER2) &bmi2Temp,
+                                0,
+                                NULL,
+                                NULL);
+
+    if (!hbmpTemp) {
+        GpiDestroyPS (hps);
+        DevCloseDC (hdc);
+        return;
+    }
+
+    /* Select the bitmap into the memory device context. */
+    GpiSetBitmap (hps, hbmpTemp);
+
+    /* Target coordinates (Noninclusive) */
+    aptlPoints[0].x = 0;
+    aptlPoints[0].y = 0;
+    
+    aptlPoints[1].x = sizlTemp.cx;
+    aptlPoints[1].y = sizlTemp.cy;
+
+    /* Source coordinates (Inclusive) */
+    aptlPoints[2].x = prcl_begin_paint_rect->xLeft;
+    aptlPoints[2].y = surface->bitmap_info.cy - prcl_begin_paint_rect->yBottom;
+
+    aptlPoints[3].x = prcl_begin_paint_rect->xRight;
+    aptlPoints[3].y = surface->bitmap_info.cy - prcl_begin_paint_rect->yTop;
+
+    /* Blit pixels from screen to bitmap */
+    GpiBitBlt (hps,
+               hps_begin_paint,
+               4,
+               aptlPoints,
+               ROP_SRCCOPY,
+               BBO_IGNORE);
+
+    /* Now we have to extract the pixels from the bitmap. */
+    pchTemp =
+        surface->pixels +
+        (prcl_begin_paint_rect->yBottom)*surface->bitmap_info.cx*4 +
+        prcl_begin_paint_rect->xLeft*4;
+    for (y = 0; y < sizlTemp.cy; y++) {
+        /* Get one line of pixels */
+        GpiQueryBitmapBits (hps,
+                            sizlTemp.cy - y - 1, /* lScanStart */
+                            1,                   /* lScans */
+                            pchTemp,
+                            &bmi2Temp);
+
+        /* Go for next line */
+        pchTemp += surface->bitmap_info.cx*4;
+    }
+
+    /* Clean up resources */
+    GpiSetBitmap (hps, (HBITMAP) NULL);
+    GpiDeleteBitmap (hbmpTemp);
+    GpiDestroyPS (hps);
+    DevCloseDC (hdc);
+}
+
+static cairo_status_t
+_cairo_os2_surface_acquire_source_image (void                   *abstract_surface,
+                                         cairo_image_surface_t **image_out,
+                                         void                  **image_extra)
+{
+    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_STATUS_SURFACE_TYPE_MISMATCH;
+    }
+
+    DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
+
+    /* Increase lend counter */
+    local_os2_surface->pixel_array_lend_count++;
+
+    *image_out = local_os2_surface->image_surface;
+    *image_extra = NULL;
+
+    DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_os2_surface_release_source_image (void                  *abstract_surface,
+                                         cairo_image_surface_t *image,
+                                         void                  *image_extra)
+{
+    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;
+    }
+
+    /* Decrease Lend counter! */
+    DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
+
+    if (local_os2_surface->pixel_array_lend_count > 0)
+        local_os2_surface->pixel_array_lend_count--;
+    DosPostEventSem (local_os2_surface->hev_pixel_array_came_back);
+
+    DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
+    return;
+}
+
+static cairo_status_t
+_cairo_os2_surface_acquire_dest_image (void                     *abstract_surface,
+                                       cairo_rectangle_int16_t  *interest_rect,
+                                       cairo_image_surface_t   **image_out,
+                                       cairo_rectangle_int16_t  *image_rect,
+                                       void                    **image_extra)
+{
+    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_STATUS_SURFACE_TYPE_MISMATCH;
+    }
+
+    DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
+
+    /* Increase lend counter */
+    local_os2_surface->pixel_array_lend_count++;
+
+    *image_out = local_os2_surface->image_surface;
+    *image_extra = NULL;
+
+    image_rect->x = 0;
+    image_rect->y = 0;
+    image_rect->width = local_os2_surface->bitmap_info.cx;
+    image_rect->height = local_os2_surface->bitmap_info.cy;
+
+    DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_os2_surface_release_dest_image (void                    *abstract_surface,
+                                       cairo_rectangle_int16_t *interest_rect,
+                                       cairo_image_surface_t   *image,
+                                       cairo_rectangle_int16_t *image_rect,
+                                       void                    *image_extra)
+{
+    cairo_os2_surface_t *local_os2_surface;
+    RECTL rclToBlit;
+
+    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;
+    }
+
+    /* So, we got back the image, and if all goes well, then
+     * something has been changed inside the interest_rect.
+     * So, we blit it to the screen!
+     */
+
+    if (local_os2_surface->blit_as_changes) {
+        /* Get mutex, we'll work with the pixel array! */
+        if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)!=NO_ERROR) {
+            /* Could not get mutex! */
+            return;
+        }
+
+        if (local_os2_surface->hwnd_client_window) {
+            /* We know the HWND, so let's invalidate the window region,
+             * so the application will redraw itself, using the
+             * cairo_os2_surface_refresh_window () API from its own PM thread.
+             *
+             * This is the safe method, which should be preferred every time.
+             */
+            rclToBlit.xLeft = interest_rect->x;
+            rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */
+            rclToBlit.yTop = local_os2_surface->bitmap_info.cy - (interest_rect->y);
+            rclToBlit.yBottom = local_os2_surface->bitmap_info.cy - (interest_rect->y+interest_rect->height); /* Noninclusive */
+
+            WinInvalidateRect (local_os2_surface->hwnd_client_window,
+                               &rclToBlit,
+                               FALSE);
+        } else {
+            /* We don't know the HWND, so try to blit the pixels from here!
+             * Please note that it can be problematic if this is not the PM thread!
+             *
+             * It can cause internal PM stuffs to be scewed up, for some reason.
+             * Please always tell the HWND to the surface using the
+             * cairo_os2_surface_set_hwnd () API, and call cairo_os2_surface_refresh_window ()
+             * from your WM_PAINT, if it's possible!
+             */
+            rclToBlit.xLeft = interest_rect->x;
+            rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */
+            rclToBlit.yBottom = interest_rect->y;
+            rclToBlit.yTop = interest_rect->y+interest_rect->height; /* Noninclusive */
+            /* Now blit there the stuffs! */
+            _cairo_os2_surface_blit_pixels (local_os2_surface,
+                                            local_os2_surface->hps_client_window,
+                                            &rclToBlit);
+        }
+
+        DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
+    }
+    /* Also decrease Lend counter! */
+    DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
+
+    if (local_os2_surface->pixel_array_lend_count > 0)
+        local_os2_surface->pixel_array_lend_count--;
+    DosPostEventSem (local_os2_surface->hev_pixel_array_came_back);
+
+    DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
+}
+
+static cairo_int_status_t
+_cairo_os2_surface_get_extents (void                    *abstract_surface,
+                                cairo_rectangle_int16_t *rectangle)
+{
+    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_STATUS_SURFACE_TYPE_MISMATCH;
+    }
+
+    rectangle->x = 0;
+    rectangle->y = 0;
+    rectangle->width  = local_os2_surface->bitmap_info.cx;
+    rectangle->height = local_os2_surface->bitmap_info.cy;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+cairo_os2_surface_create (HPS hps_client_window,
+                          int width,
+                          int height)
+{
+    cairo_os2_surface_t *local_os2_surface;
+    int rc;
+
+    /* Check the size of the window */
+    if ((width <= 0) ||
+        (height <= 0))
+    {
+        /* Invalid window size! */
+        _cairo_error (CAIRO_STATUS_NO_MEMORY);
+        return (cairo_surface_t *) &_cairo_surface_nil;
+    }
+
+    local_os2_surface = (cairo_os2_surface_t *) malloc (sizeof (cairo_os2_surface_t));
+    if (!local_os2_surface) {
+        /* Not enough memory! */
+        _cairo_error (CAIRO_STATUS_NO_MEMORY);
+        return (cairo_surface_t *) &_cairo_surface_nil;
+    }
+
+    /* 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! */
+        _cairo_error (CAIRO_STATUS_NO_MEMORY);
+        return (cairo_surface_t *) &_cairo_surface_nil;
+    }
+
+    /* 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);
+        _cairo_error (CAIRO_STATUS_NO_MEMORY);
+        return (cairo_surface_t *) &_cairo_surface_nil;
+    }
+
+    /* 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 *) malloc (width * height * 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);
+        _cairo_error (CAIRO_STATUS_NO_MEMORY);
+        return (cairo_surface_t *) &_cairo_surface_nil;
+    }
+
+    /* This is possibly not needed, malloc'd space is
+     * usually zero'd out!
+     */
+    /*
+     memset (local_os2_surface->pixels, 0x00, swpTemp.cx * swpTemp.cy * 4);
+     */
+
+    /* 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 */
+
+    if (local_os2_surface->image_surface->base.status) {
+        /* Could not create image surface! */
+        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);
+        _cairo_error (CAIRO_STATUS_NO_MEMORY);
+        return (cairo_surface_t *) &_cairo_surface_nil;
+    }
+
+    /* 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;
+}
+
+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_STATUS_SURFACE_TYPE_MISMATCH;
+    }
+
+    if ((new_width <= 0) ||
+        (new_height <= 0))
+    {
+        /* Invalid size! */
+        return CAIRO_STATUS_NO_MEMORY;
+    }
+
+    /* Allocate memory for new stuffs */
+    pchNewPixels = (unsigned char *) malloc (new_width * new_height * 4);
+    if (!pchNewPixels) {
+        /* Not enough memory for the pixels!
+         * Everything remains the same!
+         */
+        return CAIRO_STATUS_NO_MEMORY;
+    }
+
+    /* This is possibly not needed, malloc'd space is usually
+     * already zero'd out!
+     */
+    /*
+     memset (pchNewPixels, 0x00, new_width * new_height * 4);
+     */
+
+    /* 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!
+         */
+        free (pchNewPixels);
+        return 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);
+        free (pchNewPixels);
+        return 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);
+            free (pchNewPixels);
+            return 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);
+            free (pchNewPixels);
+            return CAIRO_STATUS_NO_MEMORY;
+        }
+    }
+
+    /* Destroy old image surface */
+    cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface));
+    /* Destroy old pixel 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;
+}
+
+void
+cairo_os2_surface_refresh_window (cairo_surface_t *surface,
+                                  HPS              hps_begin_paint,
+                                  PRECTL           prcl_begin_paint_rect)
+{
+    cairo_os2_surface_t *local_os2_surface;
+    RECTL rclTemp;
+
+    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;
+    }
+
+    /* Manage defaults (NULLs) */
+    if (!hps_begin_paint)
+        hps_begin_paint = local_os2_surface->hps_client_window;
+
+    if (prcl_begin_paint_rect == NULL) {
+        /* Update the whole window! */
+        rclTemp.xLeft = 0;
+        rclTemp.xRight = local_os2_surface->bitmap_info.cx;
+        rclTemp.yTop = local_os2_surface->bitmap_info.cy;
+        rclTemp.yBottom = 0;
+    } else {
+        /* Use the rectangle we got passed as parameter! */
+        rclTemp.xLeft = prcl_begin_paint_rect->xLeft;
+        rclTemp.xRight = prcl_begin_paint_rect->xRight;
+        rclTemp.yTop = local_os2_surface->bitmap_info.cy - prcl_begin_paint_rect->yBottom;
+        rclTemp.yBottom = local_os2_surface->bitmap_info.cy - prcl_begin_paint_rect->yTop ;
+    }
+
+    /* Get mutex, we'll work with the pixel array! */
+    if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
+        != NO_ERROR)
+    {
+        /* Could not get mutex! */
+        return;
+    }
+
+    if ((local_os2_surface->dirty_area_present) &&
+        (local_os2_surface->rcl_dirty_area.xLeft == rclTemp.xLeft) &&
+        (local_os2_surface->rcl_dirty_area.xRight == rclTemp.xRight) &&
+        (local_os2_surface->rcl_dirty_area.yTop == rclTemp.yTop) &&
+        (local_os2_surface->rcl_dirty_area.yBottom == rclTemp.yBottom))
+    {
+        /* Aha, this call was because of a dirty area, so in this case we
+         * have to blit the pixels from the screen to the surface!
+         */
+        local_os2_surface->dirty_area_present = FALSE;
+        _cairo_os2_surface_get_pixels_from_screen (local_os2_surface,
+                                                   hps_begin_paint,
+                                                   &rclTemp);
+    } else {
+        /* Okay, we have the surface, have the HPS
+         * (might be from WinBeginPaint () or from WinGetPS () )
+         * Now blit there the stuffs!
+         */
+        _cairo_os2_surface_blit_pixels (local_os2_surface,
+                                        hps_begin_paint,
+                                        &rclTemp);
+    }
+
+    DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
+}
+
+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_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 */
+    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;
+}
+
+void
+cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
+                            HWND             hwnd_client_window)
+{
+    cairo_os2_surface_t *local_os2_surface;
+
+    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;
+    }
+
+    if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
+        != NO_ERROR)
+    {
+        /* Could not get mutex! */
+        return;
+    }
+
+    local_os2_surface->hwnd_client_window = hwnd_client_window;
+
+    DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
+}
+
+void
+cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
+                                             cairo_bool_t     manual_refresh)
+{
+    cairo_os2_surface_t *local_os2_surface;
+
+    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;
+    }
+
+    local_os2_surface->blit_as_changes = !manual_refresh;
+}
+
+cairo_bool_t
+cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface)
+{
+    cairo_os2_surface_t *local_os2_surface;
+
+    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 FALSE;
+    }
+
+    return !(local_os2_surface->blit_as_changes);
+}
+
+static cairo_status_t
+_cairo_os2_surface_mark_dirty_rectangle (void *surface,
+                                         int   x,
+                                         int   y,
+                                         int   width,
+                                         int   height)
+{
+    cairo_os2_surface_t *local_os2_surface;
+    RECTL rclToBlit;
+
+    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_STATUS_SURFACE_TYPE_MISMATCH;
+    }
+
+    /* Get mutex, we'll work with the pixel array! */
+    if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
+        != NO_ERROR)
+    {
+        /* Could not get mutex! */
+        return CAIRO_STATUS_NO_MEMORY;
+    }
+
+    /* Check for defaults */
+    if (width < 0)
+        width = local_os2_surface->bitmap_info.cx;
+    if (height < 0)
+        height = local_os2_surface->bitmap_info.cy;
+
+    if (local_os2_surface->hwnd_client_window) {
+        /* We know the HWND, so let's invalidate the window region,
+         * so the application will redraw itself, using the
+         * cairo_os2_surface_refresh_window () API from its own PM thread.
+         * From that function we'll note that it's not a redraw but a
+         * dirty-rectangle deal stuff, so we'll handle the things from
+         * there.
+         *
+         * This is the safe method, which should be preferred every time.
+         */
+        rclToBlit.xLeft = x;
+        rclToBlit.xRight = x + width; /* Noninclusive */
+        rclToBlit.yTop = local_os2_surface->bitmap_info.cy - (y);
+        rclToBlit.yBottom = local_os2_surface->bitmap_info.cy - (y + height); /* Noninclusive */
+
+#if 0
+        if (local_os2_surface->dirty_area_present) {
+            /* Yikes, there is already a dirty area which should be
+             * cleaned up, but we'll overwrite it. Sorry.
+             * TODO: Something clever should be done here.
+             */
+        }
+#endif
+
+        /* Set up dirty area reminder stuff */
+        memcpy (&(local_os2_surface->rcl_dirty_area), &rclToBlit, sizeof (RECTL));
+        local_os2_surface->dirty_area_present = TRUE;
+
+        /* Invalidate window area */
+        WinInvalidateRect (local_os2_surface->hwnd_client_window,
+                           &rclToBlit,
+                           FALSE);
+    } else {
+        /* We don't know the HWND, so try to blit the pixels from here!
+         * Please note that it can be problematic if this is not the PM thread!
+         *
+         * It can cause internal PM stuffs to be scewed up, for some reason.
+         * Please always tell the HWND to the surface using the
+         * cairo_os2_surface_set_hwnd () API, and call cairo_os2_surface_refresh_window ()
+         * from your WM_PAINT, if it's possible!
+         */
+
+        rclToBlit.xLeft = x;
+        rclToBlit.xRight = x + width; /* Noninclusive */
+        rclToBlit.yBottom = y;
+        rclToBlit.yTop = y + height; /* Noninclusive */
+        /* Now get the pixels from the screen! */
+        _cairo_os2_surface_get_pixels_from_screen (local_os2_surface,
+                                                   local_os2_surface->hps_client_window,
+                                                   &rclToBlit);
+    }
+
+    DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_os2_surface_backend = {
+    CAIRO_SURFACE_TYPE_OS2,
+    NULL, /* create_similar */
+    _cairo_os2_surface_finish,
+    _cairo_os2_surface_acquire_source_image,
+    _cairo_os2_surface_release_source_image,
+    _cairo_os2_surface_acquire_dest_image,
+    _cairo_os2_surface_release_dest_image,
+    NULL, /* clone_similar */
+    NULL, /* composite */
+    NULL, /* fill_rectangles */
+    NULL, /* composite_trapezoids */
+    NULL, /* copy_page */
+    NULL, /* show_page */
+    NULL, /* set_clip_region */
+    NULL, /* intersect_clip_path */
+    _cairo_os2_surface_get_extents,
+    NULL, /* old_show_glyphs */
+    NULL, /* get_font_options */
+    NULL, /* flush */
+    _cairo_os2_surface_mark_dirty_rectangle,
+    NULL, /* scaled_font_fini */
+    NULL, /* scaled_glyph_fini */
+    NULL, /* paint */
+    NULL, /* mask */
+    NULL, /* stroke */
+    NULL, /* fill */
+    NULL, /* show_glyphs */
+    NULL  /* snapshot */
+};
diff --git a/src/cairo-os2.h b/src/cairo-os2.h
new file mode 100644
index 0000000..3e1b4aa
--- /dev/null
+++ b/src/cairo-os2.h
@@ -0,0 +1,201 @@
+/* vim: set sw=4 sts=4 et cin: */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright (c) 2005-2006 netlabs.org
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is
+ *     Doodle <doodle at scenergy.dfmk.hu>
+ *
+ * Contributor(s):
+ *     Peter Weilbacher <mozilla at Weilbacher.org>
+ */
+
+#ifndef _CAIRO_OS2_H_
+#define _CAIRO_OS2_H_
+
+#include <cairo.h>
+
+CAIRO_BEGIN_DECLS
+
+/* The OS/2 Specific Cairo API */
+
+/* cairo_os2_init () :                                              */
+/*                                                                  */
+/* Initializes the Cairo library. This function is automatically    */
+/* called if Cairo was compiled to be a DLL (however it's not a     */
+/* problem if it's called multiple times), but if you link to       */
+/* Cairo statically, you have to call it once to set up Cairo's     */
+/* internal structures and mutexes.                                 */
+
+cairo_public void
+cairo_os2_init (void);
+
+/* cairo_os2_fini () :                                              */
+/*                                                                  */
+/* Uninitializes the Cairo library. This function is automatically  */
+/* called if Cairo was compiled to be a DLL (however it's not a     */
+/* problem if it's called multiple times), but if you link to       */
+/* Cairo statically, you have to call it once to shut down Cairo,   */
+/* to let it free all the resources it has allocated.               */
+
+cairo_public void
+cairo_os2_fini (void);
+
+#if CAIRO_HAS_OS2_SURFACE
+
+/* cairo_os2_surface_create () :                                    */
+/*                                                                  */
+/* Create a Cairo surface which is bounded 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 the                              */
+/*             cairo_os2_surface_set_manual_window_refresh () API.  */
+/* 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 the                */
+/* cairo_surface_mark_dirty () API to fill the surface with pixels  */
+/* from the window/HPS.                                             */
+
+cairo_public cairo_surface_t *
+cairo_os2_surface_create (HPS hps_client_window,
+                          int width,
+                          int height);
+
+/* cairo_os2_surface_set_hwnd () :                                  */
+/*                                                                  */
+/* Sets window handle for surface. If Cairo wants to blit into the  */
+/* window because it's set that it should blit as the surface       */
+/* changes (see cairo_os2_surface_set_manual_window_refresh () API),*/
+/* then there are two ways it can choose:                           */
+/* If it knows the HWND of the surface, then it invalidates that    */
+/* area, so the application will get a WM_PAINT message and it can  */
+/* call cairo_os2_surface_refresh_window () to redraw that area.    */
+/* Otherwise cairo itself will use the HPS it got at surface        */
+/* creation time, and blit the pixels itself.                       */
+/* It's also a solution, but experience shows that if this happens  */
+/* from a non-PM thread, then it can screw up PM internals.         */
+/*                                                                  */
+/* So, best solution is to set the HWND for the surface after the   */
+/* surface creation, so every blit will be done from application's  */
+/* message processing loop, which is the safest way to do.          */
+
+cairo_public void
+cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
+                            HWND             hwnd_client_window);
+
+/* cairo_os2_surface_set_size () :                                  */
+/*                                                                  */
+/* When the client window is resized, call this API so the          */
+/* underlaying surface will also be resized. 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, just like   */
+/* after cairo_os2_surface_create (), so all those notes also apply */
+/* here, please read that!                                          */
+/*                                                                  */
+/* The timeout value is in milliseconds, and tells how much the     */
+/* function should wait on other parts of the program to release    */
+/* the buffers. It is necessary, because it can be that Cairo is    */
+/* just drawing something into the surface while we want to         */
+/* destroy and recreate it.                                         */
+/* Returns CAIRO_STATUS_SUCCESS if the surface could be resized,    */
+/* or returns other error code if                                   */
+/*  - the surface is not a real OS/2 Surface                        */
+/*  - there is not enough memory to resize the surface              */
+/*  - waiting for all the buffers to be released timed out          */
+
+cairo_public int
+cairo_os2_surface_set_size (cairo_surface_t *surface,
+                            int              new_width,
+                            int              new_height,
+                            int              timeout);
+
+/* cairo_os2_surface_refresh_window () :                            */
+/*                                                                  */
+/* This function can be used to force a repaint of a given area     */
+/* of the client window. Most of the time it is called from the     */
+/* WM_PAINT processing of the window proc. However, it can be       */
+/* called anytime if a given part of the window has to be updated.  */
+/*                                                                  */
+/* The function expects a HPS of the window, and a RECTL to tell    */
+/* which part of the window should be redrawn.                      */
+/* The returned values of WinBeginPaint () is just perfect here,    */
+/* but you can also get the HPS by using the WinGetPS () function,  */
+/* and you can assemble your own update rect by hand.               */
+/* If the hps_begin_paint parameter is NULL, the function will use  */
+/* the HPS you passed in to cairo_os2_surface_create (). If the     */
+/* prcl_begin_paint_rect parameter is NULL, the function will query */
+/* the current window size and repaint the whole window.            */
+/*                                                                  */
+/* Cairo/2 assumes that if you told the HWND to the surface using   */
+/* the cairo_os2_surface_set_hwnd () API, then this function will   */
+/* be called by the application every time it gets a WM_PAINT for   */
+/* that HWND. If the HWND is told to the surface, Cairo uses this   */
+/* function to handle dirty areas too, so you were warned. :)       */
+
+cairo_public void
+cairo_os2_surface_refresh_window (cairo_surface_t *surface,
+                                  HPS              hps_begin_paint,
+                                  PRECTL           prcl_begin_paint_rect);
+
+/* cairo_os2_surface_set_manual_window_refresh () :                 */
+/*                                                                  */
+/* This API can tell Cairo if it should show every change to this   */
+/* surface immediately in the window, or if it should be cached     */
+/* and will only be visible if the user calls the                   */
+/* cairo_os2_surface_refresh_window () API explicitly.              */
+/* If the HWND was not told to Cairo, then it will use the HPS to   */
+/* blit the graphics. Otherwise it will invalidate the given        */
+/* window region so the user will get WM_PAINT to redraw that area  */
+/* of the window.                                                   */
+/*                                                                  */
+/* So, if you're only interested in displaying the final result     */
+/* after several drawing operations, you might get better           */
+/* performance if you  put the surface into a manual refresh mode   */
+/* by passing a true value to cairo_os2_surface_set_manual_refresh()*/
+/* and then calling cairo_os2_surface_refresh() whenever desired.   */
+
+cairo_public void
+cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
+                                             cairo_bool_t     manual_refresh);
+
+/* cairo_os2_surface_get_manual_window_refresh () :                 */
+/*                                                                  */
+/* This API can return the current mode of the surface. It is       */
+/* TRUE by default.                                                 */
+
+cairo_public cairo_bool_t
+cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface);
+
+#endif /* CAIRO_HAS_OS2_SURFACE */
+
+CAIRO_END_DECLS
+
+#endif /* _CAIRO_OS2_H_ */


More information about the cairo-commit mailing list