[cairo] OS/2 backend support files

Peter Weilbacher (Mozilla) mozilla at weilbacher.org
Sat Jul 22 07:47:30 PDT 2006


Doodle wrote:

> Following my conversation with Carl in public, here is a zip
> file containing the OS/2 specific files for Cairo v1.2.0.
> 
> http://scenergy.dfmk.hu/doodle/cairo_120_os2_files.zip
> 
> This contains the OS/2 surface support files, and some small
> modifications in the common header files.

Thanks a lot for sending the files. As promised I have fiddled around
with the build system and gotten it to work on OS/2 for the most part.
>From Doodle's files I made two "git format-patch origin" patches from
the current HEAD (or trunk or whatever that is called in cairo/git
speak) which I attach to this email.

Some points:
- I had to make a few small changes to the files Doodle sent:
  + add "@CAIRO_SURFACE_TYPE_OS2: The surface is of type os2" to
    cairo.h.
  + add
    #ifndef __WATCOMC__
    #include <emx/startup.h>
    #endif
    at the top of cairo-os2-dll.c to circumvent warnings about the DLL
    startup functions.
  + include cairo-os2.h at the top of cairo-os2-extra.c and add void in
    the functions without arguments in both these files (to get rid of
    GCC compile warnings).
  + add spaces in front of the function brackes in cairo-os2.h to have
    them end up in the .def file

- Doodle: I was wondering why you set (c) and initial developer as
  RedHat in your files? Last time we met you were not working for them.

- OS/2 does not allow to set png_CFLAGS in the environment (every
  variable is automatically uppercased). I don't know how to dead with
  this, so the OS/2ers either have to set CFLAGS including PNG specific
  flags

- Is it intentional that pixman.lib (lib for static linking) does not
  get copied to $prefix/lib make install or am I doing something wrong
  so that the cairo.lib does not contain the pixman functions?

- The biggest point so far is that I didn't find a version of libtool
  for OS/2 that can actually compile a DLL, but I think that this has
  nothing to do with these patches and has to be solved in libtool.

OK, that's it for now. Let me know if I need to do anything more before
this can get into the main repository. Any more requirements to get this
into the 1.2 branch?

Cheers,
   Peter.
-------------- next part --------------
>From nobody Mon Sep 17 00:00:00 2001
From: Peter Weilbacher <pmw at schnurps.(none)>
Date: Sat Jul 22 16:16:27 2006 +0200
Subject: [PATCH] OS/2 build changes

---

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

08e9832c85f7102f915f5a4f5ababeb0235b79cc
diff --git a/configure.in b/configure.in
index 9e48511..2d69292 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, auto, [
+  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..dd3ced2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -75,6 +75,15 @@ 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-os2-dll.c cairo-os2-extra.c
+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 +139,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 +224,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 e5349c9..c6b9eea 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 9ecb072..a243d0d 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -159,6 +159,18 @@ 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: Sat Jul 22 16:17:18 2006 +0200
Subject: [PATCH] Files for OS/2 cairo backend

---

 src/cairo-os2-dll.c     |   78 ++++
 src/cairo-os2-extra.c   |  161 ++++++++
 src/cairo-os2-private.h |   76 ++++
 src/cairo-os2-surface.c |  995 +++++++++++++++++++++++++++++++++++++++++++++++
 src/cairo-os2.h         |  191 +++++++++
 5 files changed, 1501 insertions(+), 0 deletions(-)
 create mode 100644 src/cairo-os2-dll.c
 create mode 100644 src/cairo-os2-extra.c
 create mode 100644 src/cairo-os2-private.h
 create mode 100644 src/cairo-os2-surface.c
 create mode 100644 src/cairo-os2.h

e1762f5c84f038226d342569390d2b6ecaca092c
diff --git a/src/cairo-os2-dll.c b/src/cairo-os2-dll.c
new file mode 100644
index 0000000..f3a816c
--- /dev/null
+++ b/src/cairo-os2-dll.c
@@ -0,0 +1,78 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Doodle <doodle at scenergy.dfmk.hu>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define INCL_WIN
+#include <os2.h>
+#include "cairo-os2.h"
+#ifndef __WATCOMC__
+#include <emx/startup.h>
+#endif
+
+/* The main DLL entry for DLL initialization and uninitialization */
+#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;
+  }
+}
diff --git a/src/cairo-os2-extra.c b/src/cairo-os2-extra.c
new file mode 100644
index 0000000..d935f29
--- /dev/null
+++ b/src/cairo-os2-extra.c
@@ -0,0 +1,161 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Doodle <doodle at scenergy.dfmk.hu>
+ */
+
+/*
+ * This file contains the extra API for the OS/2 platform. Currently it
+ * contains two extra functions, the cairo_os2_initialize() and the
+ * cairo_os2_uninitialize(). Both of them are called automatically if
+ * cairo is compiled to a DLL file, but you have to call them before
+ * using cairo if you link to cairo statically!
+ */
+
+#include "cairoint.h"
+#include "cairo-os2.h"
+#include "fontconfig/fontconfig.h"
+#include <float.h>
+
+static int iCairoIsInitialized = 0;
+
+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
+
+extern void AddLog(char *pchMsg);
+
+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.. */
+
+  iCairoIsInitialized++;
+  if (iCairoIsInitialized>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 (iCairoIsInitialized<=0) return;
+  iCairoIsInitialized--;
+  if (iCairoIsInitialized>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
+}
diff --git a/src/cairo-os2-private.h b/src/cairo-os2-private.h
new file mode 100644
index 0000000..f5083fa
--- /dev/null
+++ b/src/cairo-os2-private.h
@@ -0,0 +1,76 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Doodle <doodle at scenergy.dfmk.hu>
+ */
+
+#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                   hmtxUsePrivateFields;
+  /* Private fields: */
+  HPS                    hpsClientWindow;
+  HWND                   hwndClientWindow;
+  BITMAPINFO2            bmi2BitmapInfo;
+  unsigned char         *pchPixels;
+  cairo_image_surface_t *pImageSurface;
+  int                    iPixelArrayLendCounter;
+  HEV                    hevPixelArrayCameBack;
+
+  RECTL                  rclDirtyArea;
+  int                    bDirtyAreaPresent;
+
+  /* General flags: */
+  int                    bBlitAsChanges;
+
+} 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..3d4333a
--- /dev/null
+++ b/src/cairo-os2-surface.c
@@ -0,0 +1,995 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Doodle <doodle at scenergy.dfmk.hu>
+ */
+
+#include <stdio.h>
+#include "cairoint.h"
+#include "cairo-os2-private.h"
+
+/* 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 *pOS2Surface,
+                                           HPS hpsBeginPaint,
+                                           PRECTL prclBeginPaintRect)
+{
+  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(hpsBeginPaint);
+  GpiEnableYInversion(hpsBeginPaint, pOS2Surface->bmi2BitmapInfo.cy-1);
+
+  /* Target coordinates (Noninclusive) */
+  aptlPoints[0].x = prclBeginPaintRect->xLeft;
+  aptlPoints[0].y = prclBeginPaintRect->yBottom;
+  
+  aptlPoints[1].x = prclBeginPaintRect->xRight-1;
+  aptlPoints[1].y = prclBeginPaintRect->yTop-1;
+
+  /* Source coordinates (Inclusive) */
+  aptlPoints[2].x = prclBeginPaintRect->xLeft;
+  aptlPoints[2].y = prclBeginPaintRect->yBottom;
+
+  aptlPoints[3].x = prclBeginPaintRect->xRight;
+  aptlPoints[3].y = (prclBeginPaintRect->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>pOS2Surface->bmi2BitmapInfo.cx)
+        aptlPoints[i].x = pOS2Surface->bmi2BitmapInfo.cx;
+      if (aptlPoints[i].y>pOS2Surface->bmi2BitmapInfo.cy)
+        aptlPoints[i].y = pOS2Surface->bmi2BitmapInfo.cy;
+    }
+  }
+  
+
+  /* Debug code to draw rectangle limits */
+  /*
+  {
+    int x, y;
+    unsigned char *pchPixels;
+
+    pchPixels = pOS2Surface->pchPixels;
+    for (x=0; x<pOS2Surface->bmi2BitmapInfo.cx; x++)
+      for (y=0; y<pOS2Surface->bmi2BitmapInfo.cy; y++)
+      {
+        if ((x==0) ||
+            (y==0) ||
+            (x==y) ||
+            (x>=pOS2Surface->bmi2BitmapInfo.cx-1) ||
+            (y>=pOS2Surface->bmi2BitmapInfo.cy-1)
+            )
+          pchPixels[y*pOS2Surface->bmi2BitmapInfo.cx*4+x*4] = 255;
+      }
+  }
+  */
+  GpiDrawBits(hpsBeginPaint,
+              pOS2Surface->pchPixels,
+              &(pOS2Surface->bmi2BitmapInfo),
+              4,
+              aptlPoints,
+              ROP_SRCCOPY,
+              BBO_IGNORE);
+
+  /* Restore Y inversion */
+  GpiEnableYInversion(hpsBeginPaint, lOldYInversion);
+}
+
+static void _cairo_os2_surface_get_pixels_from_screen(cairo_os2_surface_t *pOS2Surface,
+                                                      HPS hpsBeginPaint,
+                                                      PRECTL prclBeginPaintRect)
+{
+  HPS hps;
+  HDC hdc;
+  HAB hab;
+  SIZEL sizlTemp;
+  HBITMAP hbmpTemp;
+  BITMAPINFO2 bmi2Temp;
+  POINTL aptlPoints[4];
+  int y;
+  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)
+  {
+    /* printf("Could not create DC!\n"); */
+    return;
+  }
+
+  /* Create a memory PS */
+  sizlTemp.cx = prclBeginPaintRect->xRight - prclBeginPaintRect->xLeft;
+  sizlTemp.cy = prclBeginPaintRect->yTop - prclBeginPaintRect->yBottom;
+  /* printf("Creating PS: %dx%d\n", sizlTemp.cx, sizlTemp.cy);*/
+  hps = GpiCreatePS (hab,
+                     hdc,
+                     &sizlTemp,
+                     PU_PELS | GPIT_NORMAL | GPIA_ASSOC );
+  if (!hps)
+  {
+    /* printf("Could not create PS!\n"); */
+    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)
+  {
+    /* printf("Could not create Bitmap!\n"); */
+    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 = prclBeginPaintRect->xLeft;
+  aptlPoints[2].y = pOS2Surface->bmi2BitmapInfo.cy - prclBeginPaintRect->yBottom;
+
+  aptlPoints[3].x = prclBeginPaintRect->xRight;
+  aptlPoints[3].y = pOS2Surface->bmi2BitmapInfo.cy - prclBeginPaintRect->yTop;
+
+  /*
+  printf("BitBlt... Surface: (%d x %d)\n",
+         pOS2Surface->bmi2BitmapInfo.cx,
+         pOS2Surface->bmi2BitmapInfo.cy);
+
+  printf("BitBlt... Target: (%d x %d) -> (%d x %d)\n",
+         aptlPoints[0].x, aptlPoints[0].y,
+         aptlPoints[1].x, aptlPoints[1].y);
+  printf("BitBlt... Source: (%d x %d) -> (%d x %d)\n",
+         aptlPoints[2].x, aptlPoints[2].y,
+         aptlPoints[3].x, aptlPoints[3].y);
+         */
+
+  /* Blit pixels from screen to bitmap */
+  GpiBitBlt(hps, hpsBeginPaint,
+            4,
+            aptlPoints,
+            ROP_SRCCOPY,
+            BBO_IGNORE);
+
+  /* Now we have to extract the pixels from the bitmap. */
+  /* printf("Getting pixels from bitmap...\n"); */
+
+  pchTemp =
+    pOS2Surface->pchPixels +
+    (prclBeginPaintRect->yBottom)*pOS2Surface->bmi2BitmapInfo.cx*4 +
+    prclBeginPaintRect->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 += pOS2Surface->bmi2BitmapInfo.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 *pOS2Surface;
+
+  pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+  }
+
+  DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
+
+  /* Increase lend counter */
+  pOS2Surface->iPixelArrayLendCounter++;
+
+  *image_out = pOS2Surface->pImageSurface;
+  *image_extra = NULL;
+
+  DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+
+  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 *pOS2Surface;
+
+  pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return;
+  }
+
+  /* Decrease Lend counter! */
+  DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
+
+  if (pOS2Surface->iPixelArrayLendCounter>0)
+    pOS2Surface->iPixelArrayLendCounter--;
+  DosPostEventSem(pOS2Surface->hevPixelArrayCameBack);
+
+  DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+  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 *pOS2Surface;
+
+  pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+  }
+
+  DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
+
+  /* Increase lend counter */
+  pOS2Surface->iPixelArrayLendCounter++;
+
+  *image_out = pOS2Surface->pImageSurface;
+  *image_extra = NULL;
+
+  image_rect->x = 0;
+  image_rect->y = 0;
+  image_rect->width = pOS2Surface->bmi2BitmapInfo.cx;
+  image_rect->height = pOS2Surface->bmi2BitmapInfo.cy;
+
+  DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+
+  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 *pOS2Surface;
+  RECTL rclToBlit;
+
+  pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
+  if ((!pOS2Surface) || (pOS2Surface->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 (pOS2Surface->bBlitAsChanges)
+  {
+    /* Get mutex, we'll work with the pixel array! */
+    if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
+    {
+      /* Could not get mutex! */
+      return;
+    }
+
+    if (pOS2Surface->hwndClientWindow)
+    {
+      /* 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 = pOS2Surface->bmi2BitmapInfo.cy - (interest_rect->y);
+      rclToBlit.yBottom = pOS2Surface->bmi2BitmapInfo.cy - (interest_rect->y+interest_rect->height); /* Noninclusive */
+
+      WinInvalidateRect(pOS2Surface->hwndClientWindow,
+                        &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(pOS2Surface,
+                                     pOS2Surface->hpsClientWindow,
+                                     &rclToBlit);
+    }
+
+    /* Done! */
+    DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+  }
+  /* Also decrease Lend counter! */
+  DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
+
+  if (pOS2Surface->iPixelArrayLendCounter>0)
+    pOS2Surface->iPixelArrayLendCounter--;
+  DosPostEventSem(pOS2Surface->hevPixelArrayCameBack);
+
+  DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+}
+
+static cairo_int_status_t _cairo_os2_surface_get_extents(void *abstract_surface,
+                                                         cairo_rectangle_int16_t *rectangle)
+{
+  cairo_os2_surface_t *pOS2Surface;
+
+  pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+  }
+
+  rectangle->x = 0;
+  rectangle->y = 0;
+  rectangle->width  = pOS2Surface->bmi2BitmapInfo.cx;
+  rectangle->height = pOS2Surface->bmi2BitmapInfo.cy;
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *cairo_os2_surface_create(HPS hpsClientWindow,
+                                          int iWidth, int iHeight)
+{
+  cairo_os2_surface_t *pOS2Surface;
+  int rc;
+
+  /* Check the size of the window */
+  if (
+      (iWidth<=0) ||
+      (iHeight<=0)
+     )
+  {
+    /* Invalid window size! */
+    _cairo_error(CAIRO_STATUS_NO_MEMORY);
+    return (cairo_surface_t *) &_cairo_surface_nil;
+  }
+
+
+  pOS2Surface = (cairo_os2_surface_t *) malloc(sizeof(cairo_os2_surface_t));
+  if (!pOS2Surface)
+  {
+    /* 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,
+                         &(pOS2Surface->hmtxUsePrivateFields),
+                         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 */
+  pOS2Surface->hpsClientWindow = hpsClientWindow;
+
+  /* Defaults */
+  pOS2Surface->hwndClientWindow = NULLHANDLE;
+  pOS2Surface->bBlitAsChanges = TRUE;
+  pOS2Surface->iPixelArrayLendCounter = 0;
+  rc = DosCreateEventSem(NULL,
+                         &(pOS2Surface->hevPixelArrayCameBack),
+                         0,
+                         FALSE);
+
+  if (rc!=NO_ERROR)
+  {
+    /* Could not create event semaphore! */
+    DosCloseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+    free(pOS2Surface);
+    _cairo_error(CAIRO_STATUS_NO_MEMORY);
+    return (cairo_surface_t *) &_cairo_surface_nil;
+  }
+
+  /* Prepare BITMAPINFO2 structure for our buffer */
+  memset(&(pOS2Surface->bmi2BitmapInfo), 0, sizeof(pOS2Surface->bmi2BitmapInfo));
+  pOS2Surface->bmi2BitmapInfo.cbFix = sizeof(BITMAPINFOHEADER2);
+  pOS2Surface->bmi2BitmapInfo.cx = iWidth;
+  pOS2Surface->bmi2BitmapInfo.cy = iHeight;
+  pOS2Surface->bmi2BitmapInfo.cPlanes = 1;
+  pOS2Surface->bmi2BitmapInfo.cBitCount = 32;
+
+  /*
+  pOS2Surface->bmi2BitmapInfo.ulCompression = BCA_UNCOMP;
+  pOS2Surface->bmi2BitmapInfo.cbImage = 0;
+  pOS2Surface->bmi2BitmapInfo.cxResolution = 70;
+  pOS2Surface->bmi2BitmapInfo.cyResolution = 70;
+  pOS2Surface->bmi2BitmapInfo.cclrUsed = 0;
+  pOS2Surface->bmi2BitmapInfo.cclrImportant = 0;
+  pOS2Surface->bmi2BitmapInfo.usUnits = BRU_METRIC;
+  pOS2Surface->bmi2BitmapInfo.usReserved = 0;
+  pOS2Surface->bmi2BitmapInfo.usRecording = BRA_BOTTOMUP;
+  pOS2Surface->bmi2BitmapInfo.usRendering = BRH_NOTHALFTONED;
+  pOS2Surface->bmi2BitmapInfo.cSize1 = 0;
+  pOS2Surface->bmi2BitmapInfo.cSize2 = 0;
+  pOS2Surface->bmi2BitmapInfo.ulColorEncoding = BCE_RGB;
+  pOS2Surface->bmi2BitmapInfo.ulIdentifier = 0;
+  */
+
+  /* Allocate memory for pixels */
+  pOS2Surface->pchPixels = (unsigned char *) malloc(iWidth * iHeight * 4);
+  if (!(pOS2Surface->pchPixels))
+  {
+    /* Not enough memory for the pixels! */
+    DosCloseEventSem(pOS2Surface->hevPixelArrayCameBack);
+    DosCloseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+    free(pOS2Surface);
+    _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(pOS2Surface->pchPixels, 0x00, swpTemp.cx * swpTemp.cy * 4);
+   */
+
+  /* Create image surface from pixel array */
+  pOS2Surface->pImageSurface = (cairo_image_surface_t *)
+    cairo_image_surface_create_for_data(pOS2Surface->pchPixels,
+                                        CAIRO_FORMAT_RGB24,
+                                        iWidth,      /* Width */
+                                        iHeight,     /* Height */
+                                        iWidth * 4); /* Rowstride */
+
+  if (pOS2Surface->pImageSurface->base.status)
+  {
+    /* Could not create image surface! */
+    free(pOS2Surface->pchPixels);
+    DosCloseEventSem(pOS2Surface->hevPixelArrayCameBack);
+    DosCloseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+    free(pOS2Surface);
+    _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    return (cairo_surface_t *) &_cairo_surface_nil;
+  }
+
+  /* Initialize base surface */
+  _cairo_surface_init(&pOS2Surface->base,
+                      &cairo_os2_surface_backend,
+                      _cairo_content_from_format(CAIRO_FORMAT_ARGB32));
+
+  /* All done! */
+  return (cairo_surface_t *)pOS2Surface;
+}
+
+
+int  cairo_os2_surface_window_resized(cairo_surface_t *pSurface,
+                                      int iNewWidth, int iNewHeight,
+                                      int iTimeOut)
+{
+  cairo_os2_surface_t *pOS2Surface;
+  unsigned char *pchNewPixels;
+  int rc;
+  cairo_image_surface_t *pNewImageSurface;
+
+  pOS2Surface = (cairo_os2_surface_t *) pSurface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+  }
+
+  if ((iNewWidth<=0) || (iNewHeight<=0))
+  {
+    /* Invalid size! */
+    return CAIRO_STATUS_NO_MEMORY;
+  }
+
+  /* Allocate memory for new stuffs */
+  pchNewPixels = (unsigned char *) malloc(iNewWidth * iNewHeight * 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, iNewWidth * iNewHeight * 4);
+   */
+
+  /* Create image surface from new pixel array */
+  pNewImageSurface = (cairo_image_surface_t *)
+    cairo_image_surface_create_for_data(pchNewPixels,
+                                        CAIRO_FORMAT_RGB24,
+                                        iNewWidth,      /* Width */
+                                        iNewHeight,     /* Height */
+                                        iNewWidth * 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(pOS2Surface->hmtxUsePrivateFields, 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 (pOS2Surface->iPixelArrayLendCounter>0)
+  {
+    ULONG ulPostCount;
+    DosResetEventSem(pOS2Surface->hevPixelArrayCameBack, &ulPostCount);
+    DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+    /* Wait for somebody to return the pixels! */
+    rc = DosWaitEventSem(pOS2Surface->hevPixelArrayCameBack, iTimeOut);
+    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(pOS2Surface->hmtxUsePrivateFields, 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 *) (pOS2Surface->pImageSurface));
+  /* Destroy old pixel buffer */
+  free(pOS2Surface->pchPixels);
+  /* Set new image surface */
+  pOS2Surface->pImageSurface = pNewImageSurface;
+  /* Set new pixel buffer */
+  pOS2Surface->pchPixels = pchNewPixels;
+  /* Change bitmap2 structure */
+  pOS2Surface->bmi2BitmapInfo.cx = iNewWidth;
+  pOS2Surface->bmi2BitmapInfo.cy = iNewHeight;
+
+  /* Okay, things have been changed successfully! */
+  DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+  return CAIRO_STATUS_SUCCESS;
+}
+
+void cairo_os2_surface_repaint_window(cairo_surface_t *pSurface,
+                                      HPS hpsBeginPaint,
+                                      PRECTL prclBeginPaintRect)
+{
+  cairo_os2_surface_t *pOS2Surface;
+  RECTL rclTemp;
+
+  pOS2Surface = (cairo_os2_surface_t *) pSurface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return;
+  }
+
+  /* Manage defaults (NULLs) */
+  if (hpsBeginPaint == NULL)
+      hpsBeginPaint = pOS2Surface->hpsClientWindow;
+
+  if (prclBeginPaintRect == NULL)
+  {
+    /* Update the whole window! */
+    rclTemp.xLeft = 0;
+    rclTemp.xRight = pOS2Surface->bmi2BitmapInfo.cx;
+    rclTemp.yTop = pOS2Surface->bmi2BitmapInfo.cy;
+    rclTemp.yBottom = 0;
+  } else
+  {
+    /* Use the rectangle we got passed as parameter! */
+    rclTemp.xLeft = prclBeginPaintRect->xLeft;
+    rclTemp.xRight = prclBeginPaintRect->xRight;
+    rclTemp.yTop = pOS2Surface->bmi2BitmapInfo.cy - prclBeginPaintRect->yBottom;
+    rclTemp.yBottom = pOS2Surface->bmi2BitmapInfo.cy - prclBeginPaintRect->yTop ;
+  }
+
+  /* Get mutex, we'll work with the pixel array! */
+  if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
+  {
+    /* Could not get mutex! */
+    return;
+  }
+
+  if ((pOS2Surface->bDirtyAreaPresent) &&
+      (pOS2Surface->rclDirtyArea.xLeft == rclTemp.xLeft) &&
+      (pOS2Surface->rclDirtyArea.xRight == rclTemp.xRight) &&
+      (pOS2Surface->rclDirtyArea.yTop == rclTemp.yTop) &&
+      (pOS2Surface->rclDirtyArea.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!
+     */
+    pOS2Surface->bDirtyAreaPresent = 0;
+    _cairo_os2_surface_get_pixels_from_screen(pOS2Surface,
+                                              hpsBeginPaint,
+                                              &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(pOS2Surface,
+                                   hpsBeginPaint,
+                                   &rclTemp);
+  }
+  /* Done! */
+  DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+}
+
+static cairo_status_t _cairo_os2_surface_finish(void *abstract_surface)
+{
+  cairo_os2_surface_t *pOS2Surface;
+
+  pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+  }
+
+  DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
+
+  /* Destroy old image surface */
+  cairo_surface_destroy((cairo_surface_t *) (pOS2Surface->pImageSurface));
+  /* Destroy old pixel buffer */
+  free(pOS2Surface->pchPixels);
+  DosCloseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+  DosCloseEventSem(pOS2Surface->hevPixelArrayCameBack);
+
+  /* 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 *pSurface,
+                                HWND hwndClientWindow)
+{
+  cairo_os2_surface_t *pOS2Surface;
+
+  pOS2Surface = (cairo_os2_surface_t *) pSurface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return;
+  }
+
+  if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
+  {
+    /* Could not get mutex! */
+    return;
+  }
+
+  pOS2Surface->hwndClientWindow = hwndClientWindow;
+
+  DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+}
+
+void cairo_os2_surface_set_blit_as_changes(cairo_surface_t *pSurface,
+                                           int bBlitAsChanges)
+{
+  cairo_os2_surface_t *pOS2Surface;
+
+  pOS2Surface = (cairo_os2_surface_t *) pSurface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return;
+  }
+
+  pOS2Surface->bBlitAsChanges = bBlitAsChanges;
+}
+
+int cairo_os2_surface_get_blit_as_changes(cairo_surface_t *pSurface)
+{
+  cairo_os2_surface_t *pOS2Surface;
+
+  pOS2Surface = (cairo_os2_surface_t *) pSurface;
+  if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
+  {
+    /* Invalid parameter (wrong surface)! */
+    return 0;
+  }
+
+  return pOS2Surface->bBlitAsChanges;
+}
+
+static cairo_status_t _cairo_os2_surface_mark_dirty_rectangle(void *surface,
+                                                              int   x,
+                                                              int   y,
+                                                              int   width,
+                                                              int   height)
+{
+  cairo_os2_surface_t *pOS2Surface;
+  RECTL rclToBlit;
+
+  pOS2Surface = (cairo_os2_surface_t *) surface;
+  if ((!pOS2Surface) || (pOS2Surface->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(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
+  {
+    /* Could not get mutex! */
+    return CAIRO_STATUS_NO_MEMORY;
+  }
+
+  /* Check for defaults */
+  if (width<0)
+    width = pOS2Surface->bmi2BitmapInfo.cx;
+  if (height<0)
+    height = pOS2Surface->bmi2BitmapInfo.cy;
+
+  if (pOS2Surface->hwndClientWindow)
+  {
+    /* 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 = pOS2Surface->bmi2BitmapInfo.cy - (y);
+    rclToBlit.yBottom = pOS2Surface->bmi2BitmapInfo.cy - (y + height); /* Noninclusive */
+
+#if 0
+    if (pOS2Surface->bDirtyAreaPresent)
+    {
+      /* 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(&(pOS2Surface->rclDirtyArea), &rclToBlit, sizeof(RECTL));
+    pOS2Surface->bDirtyAreaPresent = 1;
+
+    /* Invalidate window area */
+    WinInvalidateRect(pOS2Surface->hwndClientWindow,
+                      &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(pOS2Surface,
+                                              pOS2Surface->hpsClientWindow,
+                                              &rclToBlit);
+  }
+
+  /* Done! */
+  DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
+
+  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..ad5ec83
--- /dev/null
+++ b/src/cairo-os2.h
@@ -0,0 +1,191 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Doodle <doodle at scenergy.dfmk.hu>
+ */
+
+#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 hpsClientWindow,
+                          int iWidth, int iHeight);
+
+/* 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 *pSurface,
+                            HWND hwndClientWindow);
+
+/* 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 *pSurface,
+                                       int bBlitAsChanges);
+
+/* cairo_os2_surface_get_blit_as_changes() :                      */
+/*                                                                */
+/* This API can return the current mode of the surface. It is     */
+/* TRUE by default.                                               */
+
+cairo_public int
+cairo_os2_surface_get_blit_as_changes (cairo_surface_t *pSurface);
+
+/* cairo_os2_surface_window_resized() :                           */
+/*                                                                */
+/* 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_window_resized (cairo_surface_t *pSurface,
+                                  int iNewWidth, int iNewHeight,
+                                  int iTimeOut);
+
+/* 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 hpsBeginPaint parameter is NULL, the function will use  */
+/* the HPS you passed in to cairo_os2_surface_create(). If the    */
+/* prclBeginPaintRect 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 *pSurface,
+                                  HPS hpsBeginPaint,
+                                  PRECTL prclBeginPaintRect);
+
+#endif /* CAIRO_HAS_OS2_SURFACE */
+
+CAIRO_END_DECLS
+
+#endif /* _CAIRO_OS2_H_ */
-- 
1.2.4



More information about the cairo mailing list