[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