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