[cairo][PATCH] OS/2 backend support files, v.2

Peter Weilbacher mozilla at Weilbacher.org
Mon Jul 31 10:08:36 PDT 2006


OK, over the weekend, Doodle and me have been hard at work and we hope
we have attended to all the comments from Carl. The new patches to make
the OS/2 backend work are attached.

Changes include:
- copyright changed to netlabs.org (which is the organisation that
  supports open source OS/2 programs, including Doodle's packages)
- the two nits to the build patch were done
- white space, comment, and brackets changed according to cairo coding
  style
- renamed variables that are exposed in the API and in the function
  calls as well as the cairo_os2_surface structure to the style with
  lower case + underscore as use in cairo
- merging of the three C files

No changes about:
- special OS/2 functions, Doodle hopefully convinced you that they
  are needed
- we left cairo-os2-private.h as a separate file. Most backends have
  such a file and we may want to implement a OS/2 font backend at some
  point which will then include this.

Let me know if I have overlooked something.
   Peter.

-------------- next part --------------
>From nobody Mon Sep 17 00:00:00 2001
From: Peter Weilbacher <pmw at schnurps.(none)>
Date: Mon Jul 31 18:44:08 2006 +0200
Subject: [PATCH] OS/2 build changes (v.2)

---

 configure.in    |   18 ++++++++++++++++++
 src/Makefile.am |   10 ++++++++++
 src/cairo.h     |    4 +++-
 src/cairoint.h  |   11 +++++++++++
 4 files changed, 42 insertions(+), 1 deletions(-)

6885807187ade5d0f8880034f38da4412058d1a0
diff --git a/configure.in b/configure.in
index 9e48511..a81379c 100644
--- a/configure.in
+++ b/configure.in
@@ -266,6 +266,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)
@@ -747,6 +760,7 @@ echo "  Xlib Xrender:  $use_xlib_xrender
 echo "  Quartz:        $use_quartz"
 echo "  XCB:           $use_xcb"
 echo "  Win32:         $use_win32"
+echo "  OS2:           $use_os2"
 echo "  PostScript:    $use_ps"
 echo "  PDF:           $use_pdf"
 echo "  SVG:           $use_svg"
@@ -807,6 +821,10 @@ if test x"$use_beos" = "xyes" ; then
    echo "$WARNING_MESSAGE" | sed 's/@BACKEND@/BeOS/'
 fi
 
+if test x"$use_os2" = "xyes" ; then
+   echo "$WARNING_MESSAGE" | sed 's, at BACKEND@,OS/2,'
+fi
+
 if test x"$use_directfb" = "xyes" ; then
      echo "$WARNING_MESSAGE" | sed 's/@BACKEND@/DirectFB/'
 fi
diff --git a/src/Makefile.am b/src/Makefile.am
index f490607..98001a2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -75,6 +75,14 @@ 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
+cairo_def_dependency = cairo.def
+export_symbols = -export-symbols $(cairo_def_dependency)
+endif
+
 libcairo_beos_sources =
 if CAIRO_HAS_BEOS_SURFACE
 libcairo_beos_headers = cairo-beos.h
@@ -130,6 +138,7 @@ cairo_headers =				\
 	$(libcairo_ps_headers)		\
 	$(libcairo_quartz_headers)	\
 	$(libcairo_win32_headers)	\
+	$(libcairo_os2_headers)		\
 	$(libcairo_beos_headers)	\
 	$(libcairo_xcb_headers)		\
 	$(libcairo_xlib_headers)	\
@@ -214,6 +223,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 7ec249f..e0960bb 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1239,6 +1239,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
@@ -1274,7 +1275,8 @@ typedef enum _cairo_surface_type {
     CAIRO_SURFACE_TYPE_WIN32,
     CAIRO_SURFACE_TYPE_BEOS,
     CAIRO_SURFACE_TYPE_DIRECTFB,
-    CAIRO_SURFACE_TYPE_SVG
+    CAIRO_SURFACE_TYPE_SVG,
+    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 4eb0c3c..4f6f166 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -159,6 +159,17 @@ cairo_private void _cairo_beos_unlock(vo
 # define CAIRO_MUTEX_UNLOCK(name) _cairo_beos_unlock (&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
+
 #ifndef CAIRO_MUTEX_DECLARE
 # error "No mutex declarations. Cairo will not work with multiple threads." \
 	"(Remove this #error directive to acknowledge & accept this limitation)."
-- 
1.2.4


-------------- next part --------------
From nobody Mon Sep 17 00:00:00 2001
From: Peter Weilbacher <pmw at schnurps.(none)>
Date: Mon Jul 31 18:45:00 2006 +0200
Subject: [PATCH] Files for OS/2 cairo backend (v.2)

---

 src/cairo-os2-private.h |   77 +++
 src/cairo-os2-surface.c | 1132 +++++++++++++++++++++++++++++++++++++++++++++++
 src/cairo-os2.h         |  195 ++++++++
 3 files changed, 1404 insertions(+), 0 deletions(-)
 create mode 100755 src/cairo-os2-private.h
 create mode 100755 src/cairo-os2-surface.c
 create mode 100755 src/cairo-os2.h

e83249c7b7309964e5246774b1483e936a8acae2
diff --git a/src/cairo-os2-private.h b/src/cairo-os2-private.h
new file mode 100755
index 0000000..1b71ce3
--- /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 100755
index 0000000..b296e03
--- /dev/null
+++ b/src/cairo-os2-surface.c
@@ -0,0 +1,1132 @@
+/* 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 CAIRO_OS2_BUILD_DLL
+# define INCL_WIN
+# include <os2.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_initialize () and the
+ * cairo_os2_uninitialize (). 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_initialize (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_uninitialize (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_uninitialize ();
+
+#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_initialize ();
+        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_repaint_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_repaint_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_repaint_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_blit_as_changes (cairo_surface_t *surface,
+                                       int              blit_as_changes)
+{
+    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 = blit_as_changes;
+}
+
+cairo_bool_t
+cairo_os2_surface_get_blit_as_changes (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_repaint_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_repaint_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 100755
index 0000000..c819d0f
--- /dev/null
+++ b/src/cairo-os2.h
@@ -0,0 +1,195 @@
+/* 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_initialize () :                                        */
+/*                                                                  */
+/* 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_initialize (void);
+
+/* cairo_os2_uninitialize () :                                      */
+/*                                                                  */
+/* 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_uninitialize (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_blit_as_changes () 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_blit_as_changes () 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_repaint_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_blit_as_changes () :                       */
+/*                                                                  */
+/* 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_repaint_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.                                                   */
+
+cairo_public void
+cairo_os2_surface_set_blit_as_changes (cairo_surface_t *surface,
+                                       cairo_bool_t     blit_as_changes);
+
+/* cairo_os2_surface_get_blit_as_changes () :                       */
+/*                                                                  */
+/* This API can return the current mode of the surface. It is       */
+/* TRUE by default.                                                 */
+
+cairo_public cairo_bool_t
+cairo_os2_surface_get_blit_as_changes (cairo_surface_t *surface);
+
+/* 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_repaint_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_repaint_window (cairo_surface_t *surface,
+                                  HPS              hps_begin_paint,
+                                  PRECTL           prcl_begin_paint_rect);
+
+#endif /* CAIRO_HAS_OS2_SURFACE */
+
+CAIRO_END_DECLS
+
+#endif /* _CAIRO_OS2_H_ */
-- 
1.2.4


More information about the cairo mailing list