Ticket #87: 0004-Rewrite-cairo-os2-surface.c-to-remove-app-specific-c.patch
File 0004-Rewrite-cairo-os2-surface.c-to-remove-app-specific-c.patch, 107.9 KB (added by , 9 years ago) |
---|
-
src/cairo-os2-private.h
From 7d8090e2808cf0e1172fb80239978c97fea5d659 Mon Sep 17 00:00:00 2001 From: Dave Yeo <dave.r.yeo@gmail.com> Date: Wed, 31 Aug 2011 20:41:18 -0700 Subject: [PATCH 4/5] Rewrite cairo-os2-surface.c to remove app-specific code and add new features. Signed-off-by: Dave Yeo <dave.r.yeo@gmail.com> --- src/cairo-os2-private.h | 123 ++- src/cairo-os2-surface.c | 2494 ++++++++++++++++++++++++++--------------------- src/cairo-os2.h | 72 +- 3 files changed, 1548 insertions(+), 1141 deletions(-) diff --git a/src/cairo-os2-private.h b/src/cairo-os2-private.h index 829dd3c..bc02db9 100644
a b 2 2 /* cairo - a vector graphics library with display and print output 3 3 * 4 4 * Copyright (c) 2005-2006 netlabs.org 5 * Copyright (c) 2010-2011 Rich Walsh 5 6 * 6 7 * This library is free software; you can redistribute it and/or 7 8 * modify it either under the terms of the GNU Lesser General Public … … 33 34 * 34 35 * Contributor(s): 35 36 * Peter Weilbacher <mozilla@Weilbacher.org> 37 * Rich Walsh <rich@e-vertise.com> 36 38 */ 37 39 38 40 #ifndef CAIRO_OS2_PRIVATE_H 39 41 #define CAIRO_OS2_PRIVATE_H 40 42 41 #include "cairo-os2.h"42 43 #include "cairoint.h" 44 #include "cairo-os2.h" 45 46 /** 47 * Unpublished API: 48 * GpiEnableYInversion = PMGPI.723 49 * GpiQueryYInversion = PMGPI.726 50 **/ 51 52 BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight); 53 LONG APIENTRY GpiQueryYInversion (HPS hps); 54 55 /** 56 * Function declaration for GpiDrawBits () (missing from OpenWatcom headers) 57 **/ 58 #ifdef __WATCOMC__ 59 LONG APIENTRY GpiDrawBits (HPS hps, PVOID pBits, 60 PBITMAPINFO2 pbmiInfoTable, 61 LONG lCount, PPOINTL aptlPoints, 62 LONG lRop, ULONG flOptions); 63 #endif 64 65 /** 66 * Support for dynamically loading dive.dll - 67 * use to avoid both compile-time and run-time dependencies 68 **/ 69 70 #ifdef OS2_DYNAMIC_DIVE 71 typedef ULONG (APIENTRY *DiveQuery_t)(void*, ULONG); 72 typedef ULONG (APIENTRY *DiveOpen_t)(ULONG*, BOOL, VOID*); 73 typedef ULONG (APIENTRY *DiveClose_t)(ULONG); 74 typedef ULONG (APIENTRY *DiveAcquire_t)(ULONG, RECTL*); 75 typedef ULONG (APIENTRY *DiveDeacquire_t)(ULONG); 76 77 #define ORD_DIVEQUERYCAPS 1 78 #define ORD_DIVEOPEN 2 79 #define ORD_DIVECLOSE 3 80 #define ORD_DIVEACQUIREFRAMEBUFFER 6 81 #define ORD_DIVEDEACQUIREFRAMEBUFFER 8 82 #endif 83 84 /** 85 * OS/2 surface subtypes 86 **/ 87 88 typedef enum _cairo_os2_subtype { 89 CAIRO_OS2_SUBTYPE_NULL = 0, 90 CAIRO_OS2_SUBTYPE_IMAGE 91 } cairo_os2_subtype_t; 92 93 /** 94 * MMIO bitmap formats defined here to avoid #including 95 * multiple headers that aren't otherwise needed. 96 **/ 97 98 #ifndef FOURCC_BGR4 99 #define FOURCC_BGR4 0x34524742 100 #endif 101 #ifndef FOURCC_BGR3 102 #define FOURCC_BGR3 0x33524742 103 #endif 104 105 /** 106 * cairo_os2_surface_t: 107 * 108 * @base: Standard #cairo_surface_t structure. 109 * @subtype: This #cairo_os2_surface-specific value identifies whether the 110 * surface will be used for images or as a dummy with no image. 111 * @width: Width of the surface in pixels. 112 * @height: Height of the surface in pixels. 113 * @hps: PM presentation space handle whose ownership is retained by the 114 * caller. Required for printing surfaces, optional otherwise. 115 * @format: Standard #cairo_format_t value. 116 * @content: Standard #cairo_content_t value. 117 * @hwnd: PM window handle whose ownership is retained by the caller. 118 * Required for surfaces associated with a window and ignored otherwise. 119 * @stride: Distance in bytes from the start of one scan line to the next. 120 * @data: Pointer to the memory #cairo_image_surface_t uses for its bitmap. 121 * It is allocated and freed by cairo_os2_surface_t and is not accessible 122 * outside this module. 123 * @image: Pointer to the underlying image surface. It is only used for 124 * subtype %CAIRO_OS2_SUBTYPE_IMAGE. 125 **/ 126 127 typedef struct _cairo_os2_surface { 128 /* common data */ 129 cairo_surface_t base; 130 cairo_os2_subtype_t subtype; 131 int width; 132 int height; 133 HPS hps; 134 cairo_format_t format; 135 cairo_content_t content; 136 137 /* image surface data */ 138 HWND hwnd; 139 int stride; 140 unsigned char *data; 141 cairo_surface_t *image; 43 142 44 typedef struct _cairo_os2_surface45 {46 cairo_surface_t base;47 48 /* Mutex semaphore to protect private fields from concurrent access */49 HMTX hmtx_use_private_fields;50 /* Private fields: */51 HPS hps_client_window;52 HWND hwnd_client_window;53 BITMAPINFO2 bitmap_info;54 unsigned char *pixels;55 cairo_image_surface_t *image_surface;56 int pixel_array_lend_count;57 HEV hev_pixel_array_came_back;58 59 RECTL rcl_dirty_area;60 cairo_bool_t dirty_area_present;61 62 /* General flags: */63 cairo_bool_t blit_as_changes;64 cairo_bool_t use_24bpp;65 143 } cairo_os2_surface_t; 66 144 67 145 #endif /* CAIRO_OS2_PRIVATE_H */ 146 -
src/cairo-os2-surface.c
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c index 74c0567..109eb44 100644
a b 2 2 /* cairo - a vector graphics library with display and print output 3 3 * 4 4 * Copyright (c) 2005-2006 netlabs.org 5 * Copyright (c) 2010-2011 Rich Walsh 5 6 * 6 7 * This library is free software; you can redistribute it and/or 7 8 * modify it either under the terms of the GNU Lesser General Public … … 33 34 * 34 35 * Contributor(s): 35 36 * Peter Weilbacher <mozilla@Weilbacher.org> 36 * Rich Walsh < dragtext@e-vertise.com>37 * Rich Walsh <rich@e-vertise.com> 37 38 */ 38 39 39 #include "cairoint.h"40 40 41 /** 42 * cairo_os2_surface: 43 * 44 * #cairo_os2_surface is a thin wrapper around #cairo_image_surface that 45 * supports output to displays and native bitmaps. It provides OS/2-specific 46 * front-end functions and manages memory used by surface bitmaps. Calls 47 * to most backend functions are forwarded to the underlying image surface. 48 **/ 49 50 #define INCL_DOS 51 #define INCL_WIN 52 #define INCL_GPI 53 #include <os2.h> 54 55 #include <dive.h> 41 56 #include "cairo-os2-private.h" 42 57 #include "cairo-default-context-private.h" 43 58 #include "cairo-error-private.h" 44 59 45 /*46 * This function calls the allocation function depending on which47 * method was compiled into the library: it can be native allocation48 * (DosAllocMem/DosFreeMem) or C-Library based allocation (malloc/free).49 * Actually, for pixel buffers that we use this function for, cairo50 * uses _cairo_malloc_abc, so we use that here, too. And use the51 * change to check the size argument52 */53 void *_buffer_alloc (size_t a, size_t b, const unsigned int size)54 {55 size_t nbytes;56 void *buffer = NULL;57 60 58 if (!a || !b || !size || 59 a >= INT32_MAX / b || a*b >= INT32_MAX / size) { 60 return NULL; 61 } 62 nbytes = a * b * size; 61 /** 62 * Forward references to static helper functions 63 **/ 63 64 64 #ifdef OS2_USE_PLATFORM_ALLOC 65 /* Using OBJ_ANY on a machine that isn't configured for hi-mem 66 * will cause ERROR_INVALID_PARAMETER. If this occurs, or this 67 * build doesn't have hi-mem enabled, fall back to using lo-mem. 68 */ 69 #ifdef OS2_HIGH_MEMORY 70 if (!DosAllocMem (&buffer, nbytes, 71 OBJ_ANY | PAG_READ | PAG_WRITE | PAG_COMMIT)) 72 return buffer; 73 #endif 74 if (DosAllocMem (&buffer, nbytes, 75 PAG_READ | PAG_WRITE | PAG_COMMIT)) 76 return NULL; 77 #else 78 /* Clear the malloc'd buffer the way DosAllocMem() does. */ 79 buffer = malloc (nbytes); 80 if (buffer) { 81 memset (buffer, 0, nbytes); 82 } 83 #endif 84 return buffer; 85 } 65 static cairo_status_t 66 _cairo_os2_surface_init_image (cairo_os2_surface_t *surface); 67 static unsigned char * 68 _cairo_os2_surface_alloc (unsigned int size); 69 static void 70 _cairo_os2_surface_free (void *buffer); 71 static cairo_status_t 72 _cairo_os2_surface_paint_32bpp (cairo_os2_surface_t *surface, 73 HPS hps, 74 RECTL *src, 75 RECTL *dst, 76 int count); 77 static cairo_status_t 78 _cairo_os2_surface_paint_24bpp (cairo_os2_surface_t *surface, 79 HPS hps, 80 RECTL *src, 81 RECTL *dst, 82 int count); 83 static cairo_status_t 84 _cairo_os2_surface_paint_dive (cairo_os2_surface_t *surface, 85 HPS hps, 86 RECTL *rect, 87 int count); 88 static void 89 _cairo_os2_surface_dive_error (void); 86 90 87 /*88 * This function selects the free function depending on which89 * allocation method was compiled into the library90 */91 void _buffer_free (void *buffer)92 {93 #ifdef OS2_USE_PLATFORM_ALLOC94 DosFreeMem (buffer);95 #else96 free (buffer);97 #endif98 }99 91 100 /* 101 * The following part of the source file contains the code which might 102 * be called the "core" of the OS/2 backend support. This contains the 103 * OS/2 surface support functions and structures. 104 */ 92 /** 93 * Module-level data 94 **/ 105 95 106 /* Forward declaration */ 107 static const cairo_surface_backend_t cairo_os2_surface_backend; 96 static cairo_bool_t display_use24bpp = FALSE; 97 static int dive_status = 0; 98 static cairo_bool_t dive_hideptr = TRUE; 99 static HDIVE dive_handle = 0; 100 static int dive_height; 101 static int dive_stride; 102 static unsigned char *dive_scrnbuf; 108 103 109 /* Unpublished API:110 * GpiEnableYInversion = PMGPI.723111 * GpiQueryYInversion = PMGPI.726112 * BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);113 * LONG APIENTRY GpiQueryYInversion (HPS hps);114 */115 BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);116 LONG APIENTRY GpiQueryYInversion (HPS hps);117 118 #ifdef __WATCOMC__119 /* Function declaration for GpiDrawBits () (missing from OpenWatcom headers) */120 LONG APIENTRY GpiDrawBits (HPS hps,121 PVOID pBits,122 PBITMAPINFO2 pbmiInfoTable,123 LONG lCount,124 PPOINTL aptlPoints,125 LONG lRop,126 ULONG flOptions);127 #endif128 104 129 static void 130 _cairo_os2_surface_blit_pixels (cairo_os2_surface_t *surface, 131 HPS hps_begin_paint, 132 PRECTL prcl_begin_paint_rect) 133 { 134 POINTL aptlPoints[4]; 135 LONG lOldYInversion; 136 LONG rc = GPI_OK; 137 138 /* Check the limits (may not be necessary) */ 139 if (prcl_begin_paint_rect->xLeft < 0) 140 prcl_begin_paint_rect->xLeft = 0; 141 if (prcl_begin_paint_rect->yBottom < 0) 142 prcl_begin_paint_rect->yBottom = 0; 143 if (prcl_begin_paint_rect->xRight > (LONG) surface->bitmap_info.cx) 144 prcl_begin_paint_rect->xRight = (LONG) surface->bitmap_info.cx; 145 if (prcl_begin_paint_rect->yTop > (LONG) surface->bitmap_info.cy) 146 prcl_begin_paint_rect->yTop = (LONG) surface->bitmap_info.cy; 147 148 /* Exit if the rectangle is empty */ 149 if (prcl_begin_paint_rect->xLeft >= prcl_begin_paint_rect->xRight || 150 prcl_begin_paint_rect->yBottom >= prcl_begin_paint_rect->yTop) 151 return; 152 153 /* Set the Target & Source coordinates */ 154 *((PRECTL)&aptlPoints[0]) = *prcl_begin_paint_rect; 155 *((PRECTL)&aptlPoints[2]) = *prcl_begin_paint_rect; 156 157 /* Make the Target coordinates non-inclusive */ 158 aptlPoints[1].x -= 1; 159 aptlPoints[1].y -= 1; 160 161 /* Enable Y Inversion for the HPS, so GpiDrawBits will 162 * work with upside-top image, not with upside-down image! 163 */ 164 lOldYInversion = GpiQueryYInversion (hps_begin_paint); 165 GpiEnableYInversion (hps_begin_paint, surface->bitmap_info.cy-1); 166 167 /* Debug code to draw rectangle limits */ 168 #if 0 169 { 170 int x, y; 171 unsigned char *pixels; 172 173 pixels = surface->pixels; 174 for (x = 0; x < surface->bitmap_info.cx; x++) { 175 for (y = 0; y < surface->bitmap_info.cy; y++) { 176 if ((x == 0) || 177 (y == 0) || 178 (x == y) || 179 (x >= surface->bitmap_info.cx-1) || 180 (y >= surface->bitmap_info.cy-1)) 181 { 182 pixels[y*surface->bitmap_info.cx*4+x*4] = 255; 183 } 184 } 185 } 186 } 187 #endif 188 if (!surface->use_24bpp) { 189 rc = GpiDrawBits (hps_begin_paint, 190 surface->pixels, 191 &(surface->bitmap_info), 192 4, 193 aptlPoints, 194 ROP_SRCCOPY, 195 BBO_IGNORE); 196 if (rc != GPI_OK) 197 surface->use_24bpp = TRUE; 198 } 105 /** 106 * Support for dynamically loading dive.dll 107 **/ 199 108 200 if (surface->use_24bpp) { 201 /* If GpiDrawBits () failed then this is most likely because the 202 * display driver could not handle a 32bit bitmap. So we need to 203 * - create a buffer that only contains 3 bytes per pixel 204 * - change the bitmap info header to contain 24bit 205 * - pass the new buffer to GpiDrawBits () again 206 * - clean up the new buffer 207 */ 208 BITMAPINFO2 bmpinfo; 209 unsigned char *pchPixBuf; 210 unsigned char *pchTarget; 211 ULONG *pulSource; 212 ULONG ulX; 213 ULONG ulY; 214 ULONG ulPad; 215 216 /* Set up the bitmap header, but this time for 24bit depth. */ 217 bmpinfo = surface->bitmap_info; 218 bmpinfo.cBitCount = 24; 219 220 /* The start of each row has to be DWORD aligned. Calculate the 221 * of number aligned bytes per row, the total size of the bitmap, 222 * and the number of padding bytes at the end of each row. 223 */ 224 ulX = (((bmpinfo.cx * bmpinfo.cBitCount) + 31) / 32) * 4; 225 bmpinfo.cbImage = ulX * bmpinfo.cy; 226 ulPad = ulX - bmpinfo.cx * 3; 227 228 /* Allocate temporary pixel buffer. If the rows don't need 229 * padding, it has to be 1 byte larger than the size of the 230 * bitmap or else the high-order byte from the last source 231 * row will end up in unallocated memory. 232 */ 233 pchPixBuf = (unsigned char *)_buffer_alloc (1, 1, 234 bmpinfo.cbImage + (ulPad ? 0 : 1)); 235 236 if (pchPixBuf) { 237 /* Copy 4 bytes from the source but advance the target ptr only 238 * 3 bytes, so the high-order alpha byte will be overwritten by 239 * the next copy. At the end of each row, skip over the padding. 240 */ 241 pchTarget = pchPixBuf; 242 pulSource = (ULONG*)surface->pixels; 243 for (ulY = bmpinfo.cy; ulY; ulY--) { 244 for (ulX = bmpinfo.cx; ulX; ulX--) { 245 *((ULONG*)pchTarget) = *pulSource++; 246 pchTarget += 3; 247 } 248 pchTarget += ulPad; 249 } 109 #ifdef OS2_DYNAMIC_DIVE 110 static cairo_bool_t dive_loaded = FALSE; 250 111 251 rc = GpiDrawBits (hps_begin_paint, 252 pchPixBuf, 253 &bmpinfo, 254 4, 255 aptlPoints, 256 ROP_SRCCOPY, 257 BBO_IGNORE); 258 if (rc != GPI_OK) 259 surface->use_24bpp = FALSE; 260 261 _buffer_free (pchPixBuf); 262 } 263 } 112 static DiveQuery_t pDiveQueryCaps = 0; 113 static DiveOpen_t pDiveOpen = 0; 114 static DiveClose_t pDiveClose = 0; 115 static DiveAcquire_t pDiveAcquireFrameBuffer = 0; 116 static DiveDeacquire_t pDiveDeacquireFrameBuffer = 0; 264 117 265 /* Restore Y inversion */ 266 GpiEnableYInversion (hps_begin_paint, lOldYInversion); 267 } 118 #define DiveQueryCaps pDiveQueryCaps 119 #define DiveOpen pDiveOpen 120 #define DiveClose pDiveClose 121 #define DiveAcquireFrameBuffer pDiveAcquireFrameBuffer 122 #define DiveDeacquireFrameBuffer pDiveDeacquireFrameBuffer 268 123 269 static void 270 _cairo_os2_surface_get_pixels_from_screen (cairo_os2_surface_t *surface, 271 HPS hps_begin_paint, 272 PRECTL prcl_begin_paint_rect) 273 { 274 HPS hps; 275 HDC hdc; 276 SIZEL sizlTemp; 277 HBITMAP hbmpTemp; 278 BITMAPINFO2 bmi2Temp; 279 POINTL aptlPoints[4]; 280 int y; 281 unsigned char *pchTemp; 282 283 /* To copy pixels from screen to our buffer, we do the following steps: 284 * 285 * - Blit pixels from screen to a HBITMAP: 286 * -- Create Memory Device Context 287 * -- Create a PS into it 288 * -- Create a HBITMAP 289 * -- Select HBITMAP into memory PS 290 * -- Blit dirty pixels from screen to HBITMAP 291 * - Copy HBITMAP lines (pixels) into our buffer 292 * - Free resources 293 */ 124 static cairo_bool_t 125 _cairo_os2_surface_load_dive (void); 126 #endif 294 127 295 /* Create a memory device context */296 hdc = DevOpenDC (0, OD_MEMORY,"*",0L, NULL, NULLHANDLE);297 if (!hdc) {298 return;299 }300 128 301 /* Create a memory PS */ 302 sizlTemp.cx = prcl_begin_paint_rect->xRight - prcl_begin_paint_rect->xLeft; 303 sizlTemp.cy = prcl_begin_paint_rect->yTop - prcl_begin_paint_rect->yBottom; 304 hps = GpiCreatePS (0, 305 hdc, 306 &sizlTemp, 307 PU_PELS | GPIT_NORMAL | GPIA_ASSOC); 308 if (!hps) { 309 DevCloseDC (hdc); 310 return; 311 } 129 /** 130 * Forward reference to the backend structure 131 **/ 312 132 313 /* Create an uninitialized bitmap. */ 314 /* Prepare BITMAPINFO2 structure for our buffer */ 315 memset (&bmi2Temp, 0, sizeof (bmi2Temp)); 316 bmi2Temp.cbFix = sizeof (BITMAPINFOHEADER2); 317 bmi2Temp.cx = sizlTemp.cx; 318 bmi2Temp.cy = sizlTemp.cy; 319 bmi2Temp.cPlanes = 1; 320 bmi2Temp.cBitCount = 32; 321 322 hbmpTemp = GpiCreateBitmap (hps, 323 (PBITMAPINFOHEADER2) &bmi2Temp, 324 0, 325 NULL, 326 NULL); 327 328 if (!hbmpTemp) { 329 GpiDestroyPS (hps); 330 DevCloseDC (hdc); 331 return; 332 } 133 static const 134 cairo_surface_backend_t cairo_os2_surface_backend; 333 135 334 /* Select the bitmap into the memory device context. */335 GpiSetBitmap (hps, hbmpTemp);336 337 /* Target coordinates (Noninclusive) */338 aptlPoints[0].x = 0;339 aptlPoints[0].y = 0;340 341 aptlPoints[1].x = sizlTemp.cx;342 aptlPoints[1].y = sizlTemp.cy;343 344 /* Source coordinates (Inclusive) */345 aptlPoints[2].x = prcl_begin_paint_rect->xLeft;346 aptlPoints[2].y = surface->bitmap_info.cy - prcl_begin_paint_rect->yBottom;347 348 aptlPoints[3].x = prcl_begin_paint_rect->xRight;349 aptlPoints[3].y = surface->bitmap_info.cy - prcl_begin_paint_rect->yTop;350 351 /* Blit pixels from screen to bitmap */352 GpiBitBlt (hps,353 hps_begin_paint,354 4,355 aptlPoints,356 ROP_SRCCOPY,357 BBO_IGNORE);358 359 /* Now we have to extract the pixels from the bitmap. */360 pchTemp =361 surface->pixels +362 (prcl_begin_paint_rect->yBottom)*surface->bitmap_info.cx*4 +363 prcl_begin_paint_rect->xLeft*4;364 for (y = 0; y < sizlTemp.cy; y++) {365 /* Get one line of pixels */366 GpiQueryBitmapBits (hps,367 sizlTemp.cy - y - 1, /* lScanStart */368 1, /* lScans */369 (PBYTE)pchTemp,370 &bmi2Temp);371 372 /* Go for next line */373 pchTemp += surface->bitmap_info.cx*4;374 }375 136 376 /* Clean up resources */ 377 GpiSetBitmap (hps, (HBITMAP) NULL); 378 GpiDeleteBitmap (hbmpTemp); 379 GpiDestroyPS (hps); 380 DevCloseDC (hdc); 381 } 137 /** 138 * 139 * Surface Create functions 140 * 141 **/ 382 142 383 static cairo_status_t 384 _cairo_os2_surface_acquire_source_image (void *abstract_surface, 385 cairo_image_surface_t **image_out, 386 void **image_extra) 387 { 388 cairo_os2_surface_t *local_os2_surface; 143 /** 144 * cairo_os2_surface_create: 145 * @format: a standard cairo_format_t value 146 * @width: width of the surface in pixels 147 * @height: height of the surface in pixels 148 * 149 * A generic image surface creation function. 150 * 151 * Returns: a cairo_os2_surface_t if successful, a nil surface if not. 152 * 153 * Since: 1.12 154 **/ 389 155 390 local_os2_surface = (cairo_os2_surface_t *) abstract_surface; 391 if ((!local_os2_surface) || 392 (local_os2_surface->base.backend != &cairo_os2_surface_backend))393 {394 /* Invalid parameter (wrong surface)! */ 395 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);396 }156 cairo_public cairo_surface_t * 157 cairo_os2_surface_create (cairo_format_t format, 158 int width, 159 int height) 160 { 161 cairo_status_t status; 162 cairo_os2_surface_t *surface; 397 163 398 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT); 164 if (width < 0 || height < 0) 165 return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); 399 166 400 /* Increase lend counter */401 local_os2_surface->pixel_array_lend_count++;167 if (!CAIRO_FORMAT_VALID(format)) 168 return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT); 402 169 403 *image_out = local_os2_surface->image_surface; 404 *image_extra = NULL; 170 /* 171 * Create an OS/2 wrapper for an image surface 172 * whose bitmap will be allocated from system memory. 173 */ 174 surface = malloc (sizeof (cairo_os2_surface_t)); 175 if (unlikely (surface == NULL)) 176 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); 177 178 memset (surface, 0, sizeof(cairo_os2_surface_t)); 179 surface->format = format; 180 surface->content = _cairo_content_from_format (surface->format); 181 surface->subtype = CAIRO_OS2_SUBTYPE_IMAGE; 182 surface->width = width; 183 surface->height = height; 184 surface->stride = cairo_format_stride_for_width (format, width); 185 186 /* 187 * allocate memory for a bitmap then create an image surface. 188 */ 189 status = _cairo_os2_surface_init_image (surface); 190 if (_cairo_status_is_error(status)) { 191 if (surface->image) 192 cairo_surface_destroy (surface->image); 193 if (surface->data) 194 _cairo_os2_surface_free (surface->data); 195 free (surface); 196 return _cairo_surface_create_in_error (status); 197 } 405 198 406 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 199 _cairo_surface_init (&surface->base, &cairo_os2_surface_backend, 200 NULL, surface->content); 407 201 408 return CAIRO_STATUS_SUCCESS;202 return &surface->base; 409 203 } 410 204 411 static void 412 _cairo_os2_surface_release_source_image (void *abstract_surface, 413 cairo_image_surface_t *image, 414 void *image_extra) 205 206 /** 207 * cairo_os2_surface_create_for_window: 208 * @hwnd: window associated with this surface 209 * @width: width of the surface in pixels 210 * @height: height of the surface in pixels 211 * 212 * This creates a destination surface that maps to the entire area of 213 * a native window. Clients can call cairo_os2_surface_set_size() when 214 * the window's size changes, and cairo_os2_surface_paint_window() 215 * when they want to update the display with the surface's content. 216 * 217 * If @hwnd is not supplied with this call, it must be set using 218 * cairo_os2_surface_set_hwnd() before attempting to display this surface. 219 * 220 * Returns: a cairo_os2_surface_t if successful, a nil surface if not. 221 * 222 * Since: 1.12 223 **/ 224 225 cairo_public cairo_surface_t * 226 cairo_os2_surface_create_for_window (HWND hwnd, 227 int width, 228 int height) 415 229 { 416 cairo_os2_surface_t *local_os2_surface; 417 418 local_os2_surface = (cairo_os2_surface_t *) abstract_surface; 419 if ((!local_os2_surface) || 420 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 421 { 422 /* Invalid parameter (wrong surface)! */ 423 return; 424 } 230 cairo_os2_surface_t *surface; 425 231 426 /* Decrease Lend counter! */427 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);232 surface = (cairo_os2_surface_t *) 233 cairo_os2_surface_create (CAIRO_FORMAT_ARGB32, width, height); 428 234 429 if (local_os2_surface->pixel_array_lend_count > 0) 430 local_os2_surface->pixel_array_lend_count--; 431 DosPostEventSem (local_os2_surface->hev_pixel_array_came_back); 235 if (!_cairo_status_is_error (surface->base.status)) 236 surface->hwnd = hwnd; 432 237 433 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 434 return; 238 return &surface->base; 435 239 } 436 240 437 static cairo_status_t438 _cairo_os2_surface_acquire_dest_image (void *abstract_surface,439 cairo_rectangle_int_t *interest_rect,440 cairo_image_surface_t **image_out,441 cairo_rectangle_int_t *image_rect,442 void **image_extra)443 {444 cairo_os2_surface_t *local_os2_surface;445 241 446 local_os2_surface = (cairo_os2_surface_t *) abstract_surface; 447 if ((!local_os2_surface) || 448 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 449 { 450 /* Invalid parameter (wrong surface)! */ 451 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 452 } 242 /** 243 * cairo_os2_surface_create_null_surface: 244 * @hps: presentation space handle, typically associated with a 245 * printer's device context 246 * @width: width of the surface in pixels 247 * @height: height of the surface in pixels 248 * 249 * This creates a a null surface that has no image surface associated 250 * with it. It is created when the client needs a surface that can be 251 * queried for its attributes but won't actually be used. 252 * 253 * Returns: a cairo_os2_surface_t if successful, a nil surface if not. 254 * 255 * Since: 1.12 256 **/ 453 257 454 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT); 258 cairo_public cairo_surface_t * 259 cairo_os2_surface_create_null_surface (HPS hps, 260 int width, 261 int height) 262 { 263 cairo_os2_surface_t *surface; 455 264 456 /* Increase lend counter */457 local_os2_surface->pixel_array_lend_count++;265 if (width < 0 || height < 0) 266 return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); 458 267 459 *image_out = local_os2_surface->image_surface; 460 *image_extra = NULL; 268 surface = malloc (sizeof (cairo_os2_surface_t)); 269 if (unlikely (surface == NULL)) 270 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); 461 271 462 image_rect->x = 0; 463 image_rect->y = 0; 464 image_rect->width = local_os2_surface->bitmap_info.cx; 465 image_rect->height = local_os2_surface->bitmap_info.cy; 272 memset (surface, 0, sizeof(cairo_os2_surface_t)); 273 surface->format = CAIRO_FORMAT_ARGB32; 274 surface->content = _cairo_content_from_format (surface->format); 275 surface->subtype = CAIRO_OS2_SUBTYPE_NULL; 276 surface->width = width; 277 surface->height = height; 278 surface->hps = hps; 466 279 467 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 280 _cairo_surface_init (&surface->base, &cairo_os2_surface_backend, 281 NULL, surface->content); 468 282 469 return CAIRO_STATUS_SUCCESS;283 return &surface->base; 470 284 } 471 285 472 static void 473 _cairo_os2_surface_release_dest_image (void *abstract_surface, 474 cairo_rectangle_int_t *interest_rect, 475 cairo_image_surface_t *image, 476 cairo_rectangle_int_t *image_rect, 477 void *image_extra) 286 287 /** 288 * 289 * OS/2-specific functions 290 * 291 **/ 292 293 /** 294 * cairo_os2_surface_paint_window: 295 * @surface: the cairo_os2_surface to display 296 * @hps: presentation space handle associated with the target window 297 * @rect: an array of native RECTL structure identifying the bottom-left 298 * and top-right corners of the areas to be displayed 299 * @count: the number RECTLs in @rect's array 300 * 301 * This function paints the specified areas of a window using the supplied 302 * surface. It is intended for surfaces whose dimensions have a 1-to-1 303 * mapping to the dimensions of a native window (such as those created by 304 * cairo_os2_surface_create_for_window()). As such, each rectangle identifies 305 * the coordinates for both the source bitmap and the destination window. The 306 * window's handle must already be associated with this surface, using either 307 * cairo_os2_surface_create_for_window() or cairo_os2_surface_set_hwnd(). 308 * 309 * It attempts to use the most efficient method available to move the image 310 * to the screen. If an attempt fails, it falls back to the next method. 311 * If all attempts fail, the surface is marked as being in an error state. 312 * 313 * If @rect is %NULL, the entire window will be repainted. @hps is 314 * typically the presentation space handle returned by WinBeginPaint(). 315 * If it is null, cairo_os2_surface_paint_window() will use the HPS 316 * that was previously associated with this surface. If that too is null, 317 * it will allocate (and later destroy) an HPS for the window handle 318 * associated with this surface. 319 * 320 * Returns: %CAIRO_STATUS_SUCCESS if successful, 321 * %CAIRO_STATUS_DEVICE_ERROR if a permanent fatal error occurs, 322 * or one of several errors if arguments are missing or invalid. 323 * 324 * Since: 1.12 325 **/ 326 327 cairo_public cairo_status_t 328 cairo_os2_surface_paint_window (cairo_surface_t *surface, 329 HPS hps, 330 RECTL *rect, 331 int count) 478 332 { 479 cairo_os2_surface_t *local_os2_surface; 480 RECTL rclToBlit; 481 482 local_os2_surface = (cairo_os2_surface_t *) abstract_surface; 483 if ((!local_os2_surface) || 484 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 485 { 486 /* Invalid parameter (wrong surface)! */ 487 return; 488 } 333 cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface; 334 cairo_status_t status = CAIRO_STATUS_SUCCESS; 335 HPS hpsTemp = 0; 336 RECTL rectTemp; 489 337 490 /* So, we got back the image, and if all goes well, then 491 * something has been changed inside the interest_rect. 492 * So, we blit it to the screen! 493 */ 338 if (unlikely (!surface || (rect && !count))) 339 return _cairo_error (CAIRO_STATUS_NULL_POINTER); 494 340 495 if (local_os2_surface->blit_as_changes) { 496 /* Get mutex, we'll work with the pixel array! */ 497 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)!=NO_ERROR) { 498 /* Could not get mutex! */ 499 return; 500 } 341 if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2 || 342 os2surf->subtype != CAIRO_OS2_SUBTYPE_IMAGE || !os2surf->hwnd) 343 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 501 344 502 if (local_os2_surface->hwnd_client_window) { 503 /* We know the HWND, so let's invalidate the window region, 504 * so the application will redraw itself, using the 505 * cairo_os2_surface_refresh_window () API from its own PM thread. 506 * 507 * This is the safe method, which should be preferred every time. 508 */ 509 rclToBlit.xLeft = interest_rect->x; 510 rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */ 511 rclToBlit.yTop = local_os2_surface->bitmap_info.cy - (interest_rect->y); 512 rclToBlit.yBottom = local_os2_surface->bitmap_info.cy - (interest_rect->y+interest_rect->height); /* Noninclusive */ 513 514 WinInvalidateRect (local_os2_surface->hwnd_client_window, 515 &rclToBlit, 516 FALSE); 517 } else { 518 /* We don't know the HWND, so try to blit the pixels from here! 519 * Please note that it can be problematic if this is not the PM thread! 520 * 521 * It can cause internal PM stuffs to be scewed up, for some reason. 522 * Please always tell the HWND to the surface using the 523 * cairo_os2_surface_set_hwnd () API, and call cairo_os2_surface_refresh_window () 524 * from your WM_PAINT, if it's possible! 525 */ 526 rclToBlit.xLeft = interest_rect->x; 527 rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */ 528 rclToBlit.yBottom = interest_rect->y; 529 rclToBlit.yTop = interest_rect->y+interest_rect->height; /* Noninclusive */ 530 /* Now blit there the stuffs! */ 531 _cairo_os2_surface_blit_pixels (local_os2_surface, 532 local_os2_surface->hps_client_window, 533 &rclToBlit); 345 /* If an HPS wasn't provided, see if we can get one. */ 346 if (!hps) { 347 hps = os2surf->hps; 348 if (!hps) { 349 if (os2surf->hwnd) { 350 hpsTemp = WinGetPS(os2surf->hwnd); 351 hps = hpsTemp; 352 } 353 /* No HPS & no way to get one, so exit */ 354 if (!hps) 355 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); 534 356 } 357 } 535 358 536 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 359 /* If rect is null, paint the entire window. */ 360 if (!rect) { 361 rectTemp.xLeft = 0; 362 rectTemp.xRight = os2surf->width; 363 rectTemp.yTop = os2surf->height; 364 rectTemp.yBottom = 0; 365 rect = &rectTemp; 366 count = 1; 537 367 } 538 /* Also decrease Lend counter! */539 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);540 368 541 if (local_os2_surface->pixel_array_lend_count > 0) 542 local_os2_surface->pixel_array_lend_count--; 543 DosPostEventSem (local_os2_surface->hev_pixel_array_came_back); 369 if (dive_handle) { 370 if (_cairo_os2_surface_paint_dive (os2surf, hps, rect, count) == 371 CAIRO_STATUS_SUCCESS) 372 goto done; 373 } 374 if (!display_use24bpp) { 375 if (_cairo_os2_surface_paint_32bpp (os2surf, hps, rect, rect, count) == 376 CAIRO_STATUS_SUCCESS) 377 goto done; 378 display_use24bpp = TRUE; 379 } 380 status = _cairo_os2_surface_paint_24bpp (os2surf, hps, rect, rect, count); 381 if (status == CAIRO_STATUS_SUCCESS) 382 goto done; 383 384 status = _cairo_surface_set_error (&os2surf->base, status); 544 385 545 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 386 done: 387 if (hpsTemp) 388 WinReleasePS (hpsTemp); 389 390 return status; 546 391 } 547 392 548 static cairo_bool_t 549 _cairo_os2_surface_get_extents (void *abstract_surface, 550 cairo_rectangle_int_t *rectangle) 393 394 /** 395 * cairo_os2_surface_paint_bitmap: 396 * @surface: the cairo_os2_surface to display 397 * @hps: presentation space handle associated with the target device 398 * @src: an array of native RECTL structure identifying those areas of 399 * the source surface which will be painted onto the destination 400 * @dst: an array of native RECTL structure that identify where on the 401 * destination surface the corresponding @src rectangles will be painted 402 * @count: the number of RECTLs in @src and @dst arrays 403 * @use24bpp: if set, the surface's 32bpp bitmap is copied to a 24bpp 404 * bitmap before blitting to @hps 405 * 406 * This function paints the specified areas of a presentation space using 407 * the supplied surface. The target of the operation can be a PM bitmap 408 * which the caller has previously created and selected into @hps, or it 409 * can be an @hps associated with a window or printer. Only GPI functions 410 * will be used for blitting - DIVE is not available. 411 * 412 * Neither the origins nor dimensions of the @src and @dst rectangles need 413 * be the same: translation and scaling will occur as required. Either 414 * @src or @dst can be %NULL if there is a 1-to-1 mapping between the source 415 * and destination's coordinates. If both @src and @dst are %NULL, the 416 * entire surface's contents will be painted into the presentation space. 417 * 418 * If the driver for the device context associated with @hps is known to 419 * be unable to use 32-bit bitmap data as input (e.g. most native printer 420 * drivers), the @use24bpp flag should be set. Its use is very expensive 421 * and should be avoided unless absolutely necessary. 422 * 423 * If cairo_os2_surface_set_hps() was used to associate an HPS with this 424 * surface using, @hps may be %NULL; otherwise, it must be supplied. 425 * 426 * Returns: %CAIRO_STATUS_SUCCESS if successful, 427 * %CAIRO_STATUS_DEVICE_ERROR if the bit-blit fails, 428 * or one of several errors if arguments are missing or invalid. 429 * 430 * Since: 1.12 431 **/ 432 433 cairo_public cairo_status_t 434 cairo_os2_surface_paint_bitmap (cairo_surface_t *surface, 435 HPS hps, 436 RECTL *src, 437 RECTL *dst, 438 int count, 439 BOOL use24bpp) 551 440 { 552 cairo_os2_surface_t *local_os2_surface; 441 cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface; 442 cairo_status_t status = CAIRO_STATUS_SUCCESS; 443 RECTL rectTemp; 444 445 if (unlikely (!surface || ((src || dst) && !count))) 446 return _cairo_error (CAIRO_STATUS_NULL_POINTER); 553 447 554 local_os2_surface = (cairo_os2_surface_t *) abstract_surface; 555 if ((!local_os2_surface) || 556 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 557 { 558 /* Invalid parameter (wrong surface)! */ 448 if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2 || 449 os2surf->subtype != CAIRO_OS2_SUBTYPE_IMAGE) 559 450 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 451 452 if (!hps) { 453 if (!os2surf->hps) 454 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); 455 hps = os2surf->hps; 560 456 } 561 457 562 rectangle->x = 0; 563 rectangle->y = 0; 564 rectangle->width = local_os2_surface->bitmap_info.cx; 565 rectangle->height = local_os2_surface->bitmap_info.cy; 458 /* If either src or dst is null, assume a 1 to 1 mapping of 459 * coordinates; if both are null, copy all of src to dst. 460 */ 461 if (!src) { 462 if (!dst) { 463 rectTemp.xLeft = 0; 464 rectTemp.xRight = os2surf->width; 465 rectTemp.yTop = os2surf->height; 466 rectTemp.yBottom = 0; 467 src = dst = &rectTemp; 468 count = 1; 469 } 470 else 471 src = dst; 472 } 473 else 474 if (!dst) 475 dst = src; 566 476 567 return TRUE; 477 /* Perform either a 32-bit or 24-bit blit, depending on @use24bpp. */ 478 if (use24bpp) 479 status = _cairo_os2_surface_paint_24bpp (os2surf, hps, src, dst, count); 480 else 481 status = _cairo_os2_surface_paint_32bpp (os2surf, hps, src, dst, count); 482 483 return status; 568 484 } 569 485 486 570 487 /** 571 * cairo_os2_surface_create: 572 * @hps_client_window: the presentation handle to bind the surface to 573 * @width: the width of the surface 574 * @height: the height of the surface 575 * 576 * Create a Cairo surface which is bound to a given presentation space (HPS). 577 * The caller retains ownership of the HPS and must dispose of it after the 578 * the surface has been destroyed. The surface will be created to have the 579 * given size. By default every change to the surface will be made visible 580 * immediately by blitting it into the window. This can be changed with 581 * cairo_os2_surface_set_manual_window_refresh(). 582 * Note that the surface will contain garbage when created, so the pixels 583 * have to be initialized by hand first. You can use the Cairo functions to 584 * fill it with black, or use cairo_surface_mark_dirty() to fill the surface 585 * with pixels from the window/HPS. 586 * 587 * Return value: the newly created surface 588 * 589 * Since: 1.4 488 * cairo_os2_surface_get_hps: 489 * @surface: the cairo_os2_surface to query 490 * @hps: presentation space handle associated with this surface 491 * 492 * Retrieves the HPS associated with this surface, if any. 493 * 494 * Returns: %CAIRO_STATUS_SUCCESS if successful, 495 * or one of several errors if arguments are missing or invalid. 496 * 497 * Since: 1.12 590 498 **/ 591 cairo_surface_t * 592 cairo_ os2_surface_create (HPS hps_client_window,593 int width,594 int height)499 500 cairo_public cairo_status_t 501 cairo_os2_surface_get_hps (cairo_surface_t *surface, 502 HPS *hps) 595 503 { 596 cairo_os2_surface_t *local_os2_surface = 0; 597 cairo_status_t status; 598 int rc; 504 cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface; 599 505 600 /* Check the size of the window */ 601 if ((width <= 0) || (height <= 0)) { 602 status = _cairo_error (CAIRO_STATUS_INVALID_SIZE); 603 goto error_exit; 604 } 506 if (unlikely (!surface || !hps)) 507 return _cairo_error (CAIRO_STATUS_NULL_POINTER); 605 508 606 /* Allocate an OS/2 surface structure. */ 607 local_os2_surface = (cairo_os2_surface_t *) malloc (sizeof (cairo_os2_surface_t)); 608 if (!local_os2_surface) { 609 status = _cairo_error (CAIRO_STATUS_NO_MEMORY); 610 goto error_exit; 611 } 509 if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2) 510 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 612 511 613 memset(local_os2_surface, 0, sizeof(cairo_os2_surface_t));512 *hps = os2surf->hps; 614 513 615 /* Allocate resources: mutex & event semaphores and the pixel buffer */ 616 if (DosCreateMutexSem (NULL, 617 &(local_os2_surface->hmtx_use_private_fields), 618 0, 619 FALSE)) 620 { 621 status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); 622 goto error_exit; 623 } 514 return CAIRO_STATUS_SUCCESS; 515 } 624 516 625 if (DosCreateEventSem (NULL,626 &(local_os2_surface->hev_pixel_array_came_back),627 0,628 FALSE))629 {630 status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);631 goto error_exit;632 }633 517 634 local_os2_surface->pixels = (unsigned char *) _buffer_alloc (height, width, 4); 635 if (!local_os2_surface->pixels) { 636 status = _cairo_error (CAIRO_STATUS_NO_MEMORY); 637 goto error_exit; 638 } 518 /** 519 * cairo_os2_surface_set_hps: 520 * @surface: a cairo_os2_surface 521 * @hps: presentation space handle to associate with this surface 522 * 523 * Associates an HPS with this surface or dissociates it if @hps is %NULL. 524 * The caller retains ownership of @hps and must destroy it when it is no 525 * longer needed. 526 * 527 * Returns: %CAIRO_STATUS_SUCCESS if successful, 528 * or one of several errors if arguments are missing or invalid. 529 * 530 * Since: 1.12 531 **/ 639 532 640 /* Create image surface from pixel array */ 641 local_os2_surface->image_surface = (cairo_image_surface_t *) 642 cairo_image_surface_create_for_data (local_os2_surface->pixels, 643 CAIRO_FORMAT_ARGB32, 644 width, /* Width */ 645 height, /* Height */ 646 width * 4); /* Rowstride */ 647 status = local_os2_surface->image_surface->base.status; 648 if (status) 649 goto error_exit; 650 651 /* Set values for OS/2-specific data that aren't zero/NULL/FALSE. 652 * Note: hps_client_window may be null if this was called by 653 * cairo_os2_surface_create_for_window(). 654 */ 655 local_os2_surface->hps_client_window = hps_client_window; 656 local_os2_surface->blit_as_changes = TRUE; 657 658 /* Prepare BITMAPINFO2 structure for our buffer */ 659 local_os2_surface->bitmap_info.cbFix = sizeof (BITMAPINFOHEADER2); 660 local_os2_surface->bitmap_info.cx = width; 661 local_os2_surface->bitmap_info.cy = height; 662 local_os2_surface->bitmap_info.cPlanes = 1; 663 local_os2_surface->bitmap_info.cBitCount = 32; 664 665 /* Initialize base surface */ 666 _cairo_surface_init (&local_os2_surface->base, 667 &cairo_os2_surface_backend, 668 NULL, /* device */ 669 _cairo_content_from_format (CAIRO_FORMAT_ARGB32)); 670 671 /* Successful exit */ 672 return (cairo_surface_t *)local_os2_surface; 673 674 error_exit: 675 676 /* This point will only be reached if an error occured */ 677 678 if (local_os2_surface) { 679 if (local_os2_surface->pixels) 680 _buffer_free (local_os2_surface->pixels); 681 if (local_os2_surface->hev_pixel_array_came_back) 682 DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back); 683 if (local_os2_surface->hmtx_use_private_fields) 684 DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields); 685 free (local_os2_surface); 686 } 533 cairo_public cairo_status_t 534 cairo_os2_surface_set_hps (cairo_surface_t *surface, 535 HPS hps) 536 { 537 cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface; 538 539 if (unlikely (!surface)) 540 return _cairo_error (CAIRO_STATUS_NULL_POINTER); 541 542 if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2) 543 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 687 544 688 return _cairo_surface_create_in_error (status); 545 os2surf->hps = hps; 546 547 return CAIRO_STATUS_SUCCESS; 689 548 } 690 549 550 691 551 /** 692 * cairo_os2_surface_create_for_window: 693 * @hwnd_client_window: the window handle to bind the surface to 694 * @width: the width of the surface 695 * @height: the height of the surface 696 * 697 * Create a Cairo surface which is bound to a given window; the caller retains 698 * ownership of the window. This is a convenience function for use with 699 * windows that will only be updated when cairo_os2_surface_refresh_window() 700 * is called (usually in response to a WM_PAINT message). It avoids the need 701 * to create a persistent HPS for every window and assumes that one will be 702 * supplied by the caller when a cairo function needs one. If it isn't, an 703 * HPS will be created on-the-fly and released before the function which needs 704 * it returns. 705 * 706 * Return value: the newly created surface 707 * 708 * Since: 1.10 552 * cairo_os2_surface_set_hwnd: 553 * @surface: a cairo_os2_surface 554 * @hwnd: window handle to associate with this surface 555 * 556 * Associates an HWND with this surface or dissociates it if @hwnd is %NULL. 557 * The caller retains ownership of @hwnd. If the surface was created without 558 * supplying an HWND, this function must be called before attempting to use 559 * cairo_os2_surface_paint_window(). 560 * 561 * Returns: %CAIRO_STATUS_SUCCESS if successful, 562 * or one of several errors if arguments are missing or invalid. 563 * 564 * Since: 1.12 709 565 **/ 710 cairo_surface_t * 711 cairo_ os2_surface_create_for_window (HWND hwnd_client_window,712 int width,713 int height)566 567 cairo_public cairo_status_t 568 cairo_os2_surface_set_hwnd (cairo_surface_t *surface, 569 HWND hwnd) 714 570 { 715 cairo_os2_surface_t * local_os2_surface;571 cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface; 716 572 717 /* A window handle must be provided. */ 718 if (!hwnd_client_window) { 719 return _cairo_surface_create_in_error ( 720 _cairo_error (CAIRO_STATUS_NO_MEMORY)); 721 } 573 if (unlikely (!surface)) 574 return _cairo_error (CAIRO_STATUS_NULL_POINTER); 722 575 723 /* Create the surface. */ 724 local_os2_surface = (cairo_os2_surface_t *) 725 cairo_os2_surface_create (0, width, height); 576 if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2) 577 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 726 578 727 /* If successful, save the hwnd & turn off automatic repainting. */ 728 if (!local_os2_surface->image_surface->base.status) { 729 local_os2_surface->hwnd_client_window = hwnd_client_window; 730 local_os2_surface->blit_as_changes = FALSE; 731 } 579 os2surf->hwnd = hwnd; 732 580 733 return (cairo_surface_t *)local_os2_surface;581 return CAIRO_STATUS_SUCCESS; 734 582 } 735 583 584 736 585 /** 737 586 * cairo_os2_surface_set_size: 738 * @surface: the cairo surface to resize 739 * @new_width: the new width of the surface 740 * @new_height: the new height of the surface 741 * @timeout: timeout value in milliseconds 742 * 743 * When the client window is resized, call this API to set the new size in the 744 * underlying surface accordingly. This function will reallocate everything, 745 * so you'll have to redraw everything in the surface after this call. 746 * The surface will contain garbage after the resizing. So the notes of 747 * cairo_os2_surface_create() apply here, too. 748 * 749 * The timeout value specifies how long the function should wait on other parts 750 * of the program to release the buffers. It is necessary, because it can happen 751 * that Cairo is just drawing something into the surface while we want to 752 * destroy and recreate it. 753 * 754 * Return value: %CAIRO_STATUS_SUCCESS if the surface could be resized, 755 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface, 756 * %CAIRO_STATUS_INVALID_SIZE for invalid sizes 757 * %CAIRO_STATUS_NO_MEMORY if the new size could not be allocated, or if the 758 * timeout happened before all the buffers were released 759 * 760 * Since: 1.4 587 * @surface: the cairo_os2_surface to resize 588 * @width: the surface's new width 589 * @height: the surface's new height 590 * @copy: boolean indicating whether existing bitmap data should 591 * be copied to the resized surface 592 * 593 * This function resizes a cairo_os2_surface and its underlying image 594 * surface. It is intended for surfaces whose dimensions have a 1-to-1 595 * mapping to the dimensions of a native window (such as those created 596 * by cairo_os2_surface_create_for_window()). 597 * 598 * If @copy is non-zero, bitmap data will be copied from the original 599 * image surface to its replacement. The bitmaps will be aligned at 600 * their top-left corners. 601 * 602 * Returns: %CAIRO_STATUS_SUCCESS if successful, 603 * or one of several errors if arguments are missing or invalid. 604 * 605 * Since: 1.12 761 606 **/ 762 int 607 608 cairo_public cairo_status_t 763 609 cairo_os2_surface_set_size (cairo_surface_t *surface, 764 int new_width,765 int new_height,766 int timeout)610 int width, 611 int height, 612 int copy) 767 613 { 768 cairo_os2_surface_t *local_os2_surface; 769 unsigned char *pchNewPixels; 770 int rc; 771 cairo_image_surface_t *pNewImageSurface; 772 773 local_os2_surface = (cairo_os2_surface_t *) surface; 774 if ((!local_os2_surface) || 775 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 776 { 777 /* Invalid parameter (wrong surface)! */ 614 cairo_os2_surface_t *os2surf = (cairo_os2_surface_t *) surface; 615 cairo_surface_t *old_image; 616 int old_width; 617 int old_height; 618 int old_stride; 619 unsigned char *old_data; 620 cairo_status_t status = CAIRO_STATUS_SUCCESS; 621 622 if (unlikely (!surface)) 623 return _cairo_error (CAIRO_STATUS_NULL_POINTER); 624 625 if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_OS2) 778 626 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 779 }780 627 781 if ((new_width <= 0) || 782 (new_height <= 0)) 783 { 784 /* Invalid size! */ 628 if (width < 0 || height < 0) 785 629 return _cairo_error (CAIRO_STATUS_INVALID_SIZE); 630 631 old_image = os2surf->image; 632 old_width = os2surf->width; 633 old_height = os2surf->height; 634 old_stride = os2surf->stride; 635 old_data = os2surf->data; 636 637 os2surf->image = 0; 638 os2surf->width = width; 639 os2surf->height = height; 640 os2surf->stride = cairo_format_stride_for_width (os2surf->format, width); 641 os2surf->data = 0; 642 643 if (os2surf->subtype != CAIRO_OS2_SUBTYPE_NULL) 644 status = _cairo_os2_surface_init_image (os2surf); 645 646 if (_cairo_status_is_error(status)) { 647 if (os2surf->image) 648 cairo_surface_destroy (os2surf->image); 649 if (os2surf->data) 650 _cairo_os2_surface_free (os2surf->data); 651 os2surf->image = old_image; 652 os2surf->width = old_width; 653 os2surf->height = old_height; 654 os2surf->stride = old_stride; 655 os2surf->data = old_data; 656 return status; 786 657 } 787 658 788 /* Allocate memory for new stuffs */ 789 pchNewPixels = (unsigned char *) _buffer_alloc (new_height, new_width, 4); 790 if (!pchNewPixels) { 791 /* Not enough memory for the pixels! 792 * Everything remains the same! 793 */ 794 return _cairo_error (CAIRO_STATUS_NO_MEMORY); 659 if (copy) { 660 unsigned char *src = old_data; 661 unsigned char *dst = os2surf->data; 662 int count = (old_stride < os2surf->stride) ? old_stride : os2surf->stride; 663 int height = (old_height < os2surf->height) ? old_height : os2surf->height; 664 665 while (height) { 666 memcpy(dst, src, count); 667 src += old_stride; 668 dst += os2surf->stride; 669 height--; 670 } 795 671 } 796 672 797 /* Create image surface from new pixel array */ 798 pNewImageSurface = (cairo_image_surface_t *) 799 cairo_image_surface_create_for_data (pchNewPixels, 800 CAIRO_FORMAT_ARGB32, 801 new_width, /* Width */ 802 new_height, /* Height */ 803 new_width * 4); /* Rowstride */ 804 805 if (pNewImageSurface->base.status) { 806 /* Could not create image surface! 807 * Everything remains the same! 808 */ 809 _buffer_free (pchNewPixels); 810 return _cairo_error (CAIRO_STATUS_NO_MEMORY); 673 if (old_image) 674 cairo_surface_destroy (old_image); 675 if (old_data) 676 _cairo_os2_surface_free (old_data); 677 678 return status; 679 } 680 681 682 /** 683 * cairo_os2_surface_enable_dive: 684 * 685 * @enable: boolean indicating whether DIVE should be enabled or disabled 686 * @hide_pointer: boolean indicating whether the mouse pointer should be 687 * removed from the screen while writing to the frame buffer. 688 * 689 * This function enables or disables DIVE. When enabled, image data is 690 * written directly to the video framebuffer, bypassing OS/2's graphics 691 * subsystem. Only 32-bit (BGR4) and 24-bit (BGR3) color modes are 692 * supported. If any other video mode is in effect, or if any error 693 * occurs while initializing or using DIVE, it will be disabled for 694 * the remainder of the process. 695 * 696 * The @hide_pointer argument avoids screen corruption when DIVE is used 697 * with less-capable video drivers that use a software-generated pointer. 698 * 699 * Returns: %TRUE if the desired state (enabled or disabled) can be 700 * achieved or is already in effect, and FALSE otherwise. 701 * 702 * Since: 1.12 703 **/ 704 705 cairo_public cairo_bool_t 706 cairo_os2_surface_enable_dive (cairo_bool_t enable, 707 cairo_bool_t hide_pointer) 708 { 709 unsigned int rc; 710 unsigned int dive_fmts[64]; 711 DIVE_CAPS dive_caps; 712 char msg[8]; 713 714 /* If DIVE is disabled due to an earlier error, return false. */ 715 if (dive_status == -1) 716 return FALSE; 717 718 /* Close DIVE if it is currently enabled and reset all values. */ 719 if (!enable) { 720 if (dive_handle) 721 DiveClose (dive_handle); 722 dive_handle = 0; 723 dive_scrnbuf = 0; 724 dive_hideptr = TRUE; 725 dive_status = 0; 726 return TRUE; 811 727 } 812 728 813 /* Okay, new memory allocated, so it's time to swap old buffers 814 * to new ones! 815 */ 816 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)!=NO_ERROR) { 817 /* Could not get mutex! 818 * Everything remains the same! 819 */ 820 cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface); 821 _buffer_free (pchNewPixels); 822 return _cairo_error (CAIRO_STATUS_NO_MEMORY); 729 /* If DIVE is already enabled, do nothing. */ 730 if (dive_status) 731 return TRUE; 732 733 /* Assume the worst. */ 734 dive_status = -1; 735 736 #ifdef OS2_DYNAMIC_DIVE 737 if (!dive_loaded) { 738 dive_loaded = TRUE; 739 if (!_cairo_os2_surface_load_dive ()) 740 return FALSE; 823 741 } 742 #endif 743 744 memset (&dive_caps, 0, sizeof(dive_caps)); 745 memset (dive_fmts, 0, sizeof(dive_fmts)); 746 dive_caps.ulStructLen = sizeof(dive_caps); 747 dive_caps.ulFormatLength = sizeof(dive_fmts); 748 dive_caps.pFormatData = dive_fmts; 749 750 /* Get the driver's DIVE capabilities. */ 751 rc = DiveQueryCaps (&dive_caps, DIVE_BUFFER_SCREEN); 752 if (rc) 753 return FALSE; 824 754 825 /* We have to make sure that we won't destroy a surface which826 * is lent to some other code (Cairo is drawing into it)!755 /* Only 32-bit (BGR4) and 24-bit (BGR3) color modes 756 * are supported. If the mode is anything else, exit. 827 757 */ 828 while (local_os2_surface->pixel_array_lend_count > 0) { 829 ULONG ulPostCount; 830 DosResetEventSem (local_os2_surface->hev_pixel_array_came_back, &ulPostCount); 831 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 832 /* Wait for somebody to return the pixels! */ 833 rc = DosWaitEventSem (local_os2_surface->hev_pixel_array_came_back, timeout); 834 if (rc != NO_ERROR) { 835 /* Either timeout or something wrong... Exit. */ 836 cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface); 837 _buffer_free (pchNewPixels); 838 return _cairo_error (CAIRO_STATUS_NO_MEMORY); 839 } 840 /* Okay, grab mutex and check counter again! */ 841 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT) 842 != NO_ERROR) 843 { 844 /* Could not get mutex! 845 * Everything remains the same! 846 */ 847 cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface); 848 _buffer_free (pchNewPixels); 849 return _cairo_error (CAIRO_STATUS_NO_MEMORY); 850 } 758 memcpy(msg, &dive_caps.fccColorEncoding, 4); 759 msg[4] = 0; 760 if (dive_caps.fccColorEncoding != FOURCC_BGR4) { 761 if (dive_caps.fccColorEncoding == FOURCC_BGR3) 762 display_use24bpp = TRUE; 763 else 764 return FALSE; 851 765 } 852 766 853 /* Destroy old image surface */ 854 cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface)); 855 /* Destroy old pixel buffer */ 856 _buffer_free (local_os2_surface->pixels); 857 /* Set new image surface */ 858 local_os2_surface->image_surface = pNewImageSurface; 859 /* Set new pixel buffer */ 860 local_os2_surface->pixels = pchNewPixels; 861 /* Change bitmap2 structure */ 862 local_os2_surface->bitmap_info.cx = new_width; 863 local_os2_surface->bitmap_info.cy = new_height; 864 865 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 866 return CAIRO_STATUS_SUCCESS; 767 dive_height = dive_caps.ulVerticalResolution; 768 dive_stride = dive_caps.ulScanLineBytes; 769 770 /* Open a DIVE instance and get the address of the frame buffer. */ 771 rc = DiveOpen(&dive_handle, FALSE, (void*)&dive_scrnbuf); 772 if (rc) 773 return FALSE; 774 775 /* Success. */ 776 dive_hideptr = hide_pointer; 777 dive_status = 1; 778 779 return TRUE; 867 780 } 868 781 782 869 783 /** 870 * cairo_os2_surface_refresh_window: 871 * @surface: the cairo surface to refresh 872 * @hps_begin_paint: the presentation handle of the window to refresh 873 * @prcl_begin_paint_rect: the rectangle to redraw 874 * 875 * This function can be used to force a repaint of a given area of the client 876 * window. It should usually be called from the WM_PAINT processing of the 877 * window procedure. However, it can be called any time a given part of the 878 * window has to be updated. 879 * 880 * The HPS and RECTL to be passed can be taken from the usual WinBeginPaint call 881 * of the window procedure, but you can also get the HPS using WinGetPS, and you 882 * can assemble your own update rectangle by hand. 883 * If hps_begin_paint is %NULL, the function will use the HPS passed into 884 * cairo_os2_surface_create(). If @prcl_begin_paint_rect is %NULL, the function 885 * will query the current window size and repaint the whole window. 886 * 887 * Cairo assumes that if you set the HWND to the surface using 888 * cairo_os2_surface_set_hwnd(), this function will be called by the application 889 * every time it gets a WM_PAINT for that HWND. If the HWND is set in the 890 * surface, Cairo uses this function to handle dirty areas too. 891 * 892 * Since: 1.4 784 * 785 * Backend functions 786 * 893 787 **/ 894 void895 cairo_os2_surface_refresh_window (cairo_surface_t *surface,896 HPS hps_begin_paint,897 PRECTL prcl_begin_paint_rect)898 {899 cairo_os2_surface_t *local_os2_surface;900 RECTL rclTemp;901 HPS hpsTemp = 0;902 903 local_os2_surface = (cairo_os2_surface_t *) surface;904 if ((!local_os2_surface) ||905 (local_os2_surface->base.backend != &cairo_os2_surface_backend))906 {907 /* Invalid parameter (wrong surface)! */908 return;909 }910 788 911 /* If an HPS wasn't provided, see if we can get one. */ 912 if (!hps_begin_paint) { 913 hps_begin_paint = local_os2_surface->hps_client_window; 914 if (!hps_begin_paint) { 915 if (local_os2_surface->hwnd_client_window) { 916 hpsTemp = WinGetPS(local_os2_surface->hwnd_client_window); 917 hps_begin_paint = hpsTemp; 918 } 919 /* No HPS & no way to get one, so exit */ 920 if (!hps_begin_paint) 921 return; 922 } 923 } 789 static cairo_surface_t * 790 _cairo_os2_surface_create_similar (void *abstract_other, 791 cairo_content_t content, 792 int width, 793 int height) 794 { 795 cairo_os2_surface_t *other = abstract_other; 924 796 925 if (prcl_begin_paint_rect == NULL) { 926 /* Update the whole window! */ 927 rclTemp.xLeft = 0; 928 rclTemp.xRight = local_os2_surface->bitmap_info.cx; 929 rclTemp.yTop = local_os2_surface->bitmap_info.cy; 930 rclTemp.yBottom = 0; 931 } else { 932 /* Use the rectangle we got passed as parameter! */ 933 rclTemp.xLeft = prcl_begin_paint_rect->xLeft; 934 rclTemp.xRight = prcl_begin_paint_rect->xRight; 935 rclTemp.yTop = local_os2_surface->bitmap_info.cy - prcl_begin_paint_rect->yBottom; 936 rclTemp.yBottom = local_os2_surface->bitmap_info.cy - prcl_begin_paint_rect->yTop ; 937 } 797 if (unlikely (other->base.status)) 798 return _cairo_surface_create_in_error (other->base.status); 938 799 939 /* Get mutex, we'll work with the pixel array! */ 940 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT) 941 != NO_ERROR) 942 { 943 /* Could not get mutex! */ 944 if (hpsTemp) 945 WinReleasePS(hpsTemp); 946 return; 947 } 800 if (unlikely (!CAIRO_CONTENT_VALID (content))) 801 return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT); 948 802 949 if ((local_os2_surface->dirty_area_present) && 950 (local_os2_surface->rcl_dirty_area.xLeft == rclTemp.xLeft) && 951 (local_os2_surface->rcl_dirty_area.xRight == rclTemp.xRight) && 952 (local_os2_surface->rcl_dirty_area.yTop == rclTemp.yTop) && 953 (local_os2_surface->rcl_dirty_area.yBottom == rclTemp.yBottom)) 954 { 955 /* Aha, this call was because of a dirty area, so in this case we 956 * have to blit the pixels from the screen to the surface! 957 */ 958 local_os2_surface->dirty_area_present = FALSE; 959 _cairo_os2_surface_get_pixels_from_screen (local_os2_surface, 960 hps_begin_paint, 961 &rclTemp); 962 } else { 963 /* Okay, we have the surface, have the HPS 964 * (might be from WinBeginPaint () or from WinGetPS () ) 965 * Now blit there the stuffs! 966 */ 967 _cairo_os2_surface_blit_pixels (local_os2_surface, 968 hps_begin_paint, 969 &rclTemp); 970 } 803 if (other->subtype == CAIRO_OS2_SUBTYPE_IMAGE) 804 return cairo_os2_surface_create (_cairo_format_from_content (content), 805 width, height); 971 806 972 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 807 if (other->subtype == CAIRO_OS2_SUBTYPE_NULL) 808 return cairo_os2_surface_create_null_surface (other->hps, width, height); 973 809 974 if (hpsTemp) 975 WinReleasePS(hpsTemp); 810 return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT); 976 811 } 977 812 813 978 814 static cairo_status_t 979 815 _cairo_os2_surface_finish (void *abstract_surface) 980 816 { 981 cairo_os2_surface_t *local_os2_surface; 817 cairo_os2_surface_t *surface = abstract_surface; 818 if (surface->image) 819 cairo_surface_destroy (surface->image); 820 if (surface->data) 821 _cairo_os2_surface_free (surface->data); 982 822 983 local_os2_surface = (cairo_os2_surface_t *) abstract_surface; 984 if ((!local_os2_surface) || 985 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 986 { 987 /* Invalid parameter (wrong surface)! */ 988 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 989 } 823 return CAIRO_STATUS_SUCCESS; 824 } 990 825 991 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);992 826 993 /* Destroy old image surface */ 994 cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface)); 995 /* Destroy old pixel buffer */996 _buffer_free (local_os2_surface->pixels);997 DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields); 998 DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);827 static cairo_status_t 828 _cairo_os2_surface_acquire_source_image (void *abstract_surface, 829 cairo_image_surface_t **image_out, 830 void **image_extra) 831 { 832 cairo_os2_surface_t *surface = abstract_surface; 999 833 1000 /* The memory itself will be free'd by the cairo_surface_destroy () 1001 * who called us. 1002 */ 834 if (!surface->image) 835 return CAIRO_STATUS_NULL_POINTER; 1003 836 1004 return CAIRO_STATUS_SUCCESS; 837 return _cairo_surface_acquire_source_image (surface->image, 838 image_out, image_extra); 1005 839 } 1006 840 1007 /** 1008 * cairo_os2_surface_set_hwnd: 1009 * @surface: the cairo surface to associate with the window handle 1010 * @hwnd_client_window: the window handle of the client window 1011 * 1012 * Sets window handle for surface; the caller retains ownership of the window. 1013 * If Cairo wants to blit into the window because it is set to blit as the 1014 * surface changes (see cairo_os2_surface_set_manual_window_refresh()), then 1015 * there are two ways it can choose: 1016 * If it knows the HWND of the surface, then it invalidates that area, so the 1017 * application will get a WM_PAINT message and it can call 1018 * cairo_os2_surface_refresh_window() to redraw that area. Otherwise cairo itself 1019 * will use the HPS it got at surface creation time, and blit the pixels itself. 1020 * It's also a solution, but experience shows that if this happens from a non-PM 1021 * thread, then it can screw up PM internals. 1022 * 1023 * So, best solution is to set the HWND for the surface after the surface 1024 * creation, so every blit will be done from application's message processing 1025 * loop, which is the safest way to do. 1026 * 1027 * Since: 1.4 1028 **/ 1029 void 1030 cairo_os2_surface_set_hwnd (cairo_surface_t *surface, 1031 HWND hwnd_client_window) 841 842 static void 843 _cairo_os2_surface_release_source_image (void *abstract_surface, 844 cairo_image_surface_t *image, 845 void *image_extra) 1032 846 { 1033 cairo_os2_surface_t *local_os2_surface; 1034 1035 local_os2_surface = (cairo_os2_surface_t *) surface; 1036 if ((!local_os2_surface) || 1037 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 1038 { 1039 /* Invalid parameter (wrong surface)! */ 1040 return; 1041 } 847 } 1042 848 1043 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)1044 != NO_ERROR)1045 {1046 /* Could not get mutex! */1047 return;1048 }1049 849 1050 local_os2_surface->hwnd_client_window = hwnd_client_window; 850 static cairo_status_t 851 _cairo_os2_surface_acquire_dest_image (void *abstract_surface, 852 cairo_rectangle_int_t *interest_rect, 853 cairo_image_surface_t **image_out, 854 cairo_rectangle_int_t *image_rect_out, 855 void **image_extra) 856 { 857 cairo_os2_surface_t *surface = abstract_surface; 858 859 if (!surface->image) 860 return CAIRO_STATUS_NULL_POINTER; 1051 861 1052 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 862 return _cairo_surface_acquire_dest_image (surface->image, 863 interest_rect, image_out, 864 image_rect_out, image_extra); 1053 865 } 1054 866 1055 /** 1056 * cairo_os2_surface_set_manual_window_refresh: 1057 * @surface: the cairo surface to set the refresh mode for 1058 * @manual_refresh: the switch for manual surface refresh 1059 * 1060 * This API can tell Cairo if it should show every change to this surface 1061 * immediately in the window or if it should be cached and will only be visible 1062 * once the user calls cairo_os2_surface_refresh_window() explicitly. If the 1063 * HWND was not set in the cairo surface, then the HPS will be used to blit the 1064 * graphics. Otherwise it will invalidate the given window region so the user 1065 * will get the WM_PAINT message to redraw that area of the window. 1066 * 1067 * So, if you're only interested in displaying the final result after several 1068 * drawing operations, you might get better performance if you put the surface 1069 * into manual refresh mode by passing a true value to this function. Then call 1070 * cairo_os2_surface_refresh() whenever desired. 1071 * 1072 * Since: 1.4 1073 **/ 1074 void 1075 cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface, 1076 cairo_bool_t manual_refresh) 867 868 static void 869 _cairo_os2_surface_release_dest_image (void *abstract_surface, 870 cairo_rectangle_int_t *interest_rect, 871 cairo_image_surface_t *image, 872 cairo_rectangle_int_t *image_rect, 873 void *image_extra) 1077 874 { 1078 cairo_os2_surface_t *local_os2_surface; 1079 1080 local_os2_surface = (cairo_os2_surface_t *) surface; 1081 if ((!local_os2_surface) || 1082 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 1083 { 1084 /* Invalid parameter (wrong surface)! */ 1085 return; 1086 } 875 } 876 1087 877 1088 local_os2_surface->blit_as_changes = !manual_refresh; 878 static cairo_int_status_t 879 _cairo_os2_surface_composite (cairo_operator_t op, 880 const cairo_pattern_t *src_pattern, 881 const cairo_pattern_t *mask_pattern, 882 void *abstract_dst, 883 int src_x, 884 int src_y, 885 int mask_x, 886 int mask_y, 887 int dst_x, 888 int dst_y, 889 unsigned int width, 890 unsigned int height, 891 cairo_region_t *clip_region) 892 { 893 cairo_os2_surface_t *surface = abstract_dst; 894 895 if (!surface->image) 896 return CAIRO_STATUS_SUCCESS; 897 898 return _cairo_surface_composite (op, src_pattern, mask_pattern, 899 surface->image, src_x, src_y, 900 mask_x, mask_y, dst_x, dst_y, 901 width, height, clip_region); 1089 902 } 1090 903 1091 /** 1092 * cairo_os2_surface_get_manual_window_refresh: 1093 * @surface: the cairo surface to query the refresh mode from 1094 * 1095 * This space left intentionally blank. 1096 * 1097 * Return value: current refresh mode of the surface (true by default) 1098 * 1099 * Since: 1.4 1100 **/ 1101 cairo_bool_t 1102 cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface) 904 905 static cairo_int_status_t 906 _cairo_os2_surface_fill_rectangles (void *abstract_surface, 907 cairo_operator_t op, 908 const cairo_color_t *color, 909 cairo_rectangle_int_t *rects, 910 int num_rects) 1103 911 { 1104 cairo_os2_surface_t * local_os2_surface;912 cairo_os2_surface_t *surface = abstract_surface; 1105 913 1106 local_os2_surface = (cairo_os2_surface_t *) surface; 1107 if ((!local_os2_surface) || 1108 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 1109 { 1110 /* Invalid parameter (wrong surface)! */ 1111 return FALSE; 1112 } 914 if (!surface->image) 915 return CAIRO_STATUS_SUCCESS; 1113 916 1114 return !(local_os2_surface->blit_as_changes); 917 return _cairo_surface_fill_rectangles (surface->image, op, 918 color, rects, num_rects); 1115 919 } 1116 920 1117 /** 1118 * cairo_os2_surface_get_hps: 1119 * @surface: the cairo surface to be querued 1120 * @hps: HPS currently associated with the surface (if any) 1121 * 1122 * This API retrieves the HPS associated with the surface. 1123 * 1124 * Return value: %CAIRO_STATUS_SUCCESS if the hps could be retrieved, 1125 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface, 1126 * %CAIRO_STATUS_NULL_POINTER if the hps argument is null 1127 * 1128 * Since: 1.10 1129 **/ 1130 cairo_status_t 1131 cairo_os2_surface_get_hps (cairo_surface_t *surface, 1132 HPS *hps) 921 922 static cairo_int_status_t 923 _cairo_os2_surface_composite_trapezoids (cairo_operator_t op, 924 const cairo_pattern_t *pattern, 925 void *abstract_dst, 926 cairo_antialias_t antialias, 927 int src_x, 928 int src_y, 929 int dst_x, 930 int dst_y, 931 unsigned int width, 932 unsigned int height, 933 cairo_trapezoid_t *traps, 934 int num_traps, 935 cairo_region_t *clip_region) 1133 936 { 1134 cairo_os2_surface_t * local_os2_surface;937 cairo_os2_surface_t *surface = abstract_dst; 1135 938 1136 local_os2_surface = (cairo_os2_surface_t *) surface; 1137 if ((!local_os2_surface) || 1138 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 1139 { 1140 /* Invalid parameter (wrong surface)! */ 1141 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 1142 } 1143 if (!hps) 1144 { 1145 return _cairo_error (CAIRO_STATUS_NULL_POINTER); 1146 } 1147 *hps = local_os2_surface->hps_client_window; 939 if (!surface->image) 940 return CAIRO_STATUS_SUCCESS; 1148 941 1149 return CAIRO_STATUS_SUCCESS; 942 return _cairo_surface_composite_trapezoids (op, pattern, surface->image, 943 antialias, src_x, src_y, 944 dst_x, dst_y, width, height, 945 traps, num_traps, clip_region); 1150 946 } 1151 947 1152 /** 1153 * cairo_os2_surface_set_hps: 1154 * @surface: the cairo surface to associate with the HPS 1155 * @hps: new HPS to be associated with the surface (the HPS may be null) 1156 * 1157 * This API replaces the HPS associated with the surface with a new one. 1158 * The caller retains ownership of the HPS and must dispose of it after 1159 * the surface has been destroyed or it has been replaced by another 1160 * call to this function. 1161 * 1162 * Return value: %CAIRO_STATUS_SUCCESS if the hps could be replaced, 1163 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface, 1164 * 1165 * Since: 1.10 1166 **/ 1167 cairo_status_t 1168 cairo_os2_surface_set_hps (cairo_surface_t *surface, 1169 HPS hps) 948 949 static cairo_span_renderer_t * 950 _cairo_os2_surface_create_span_renderer (cairo_operator_t op, 951 const cairo_pattern_t *pattern, 952 void *abstract_dst, 953 cairo_antialias_t antialias, 954 const cairo_composite_rectangles_t *rects, 955 cairo_region_t *clip_region) 1170 956 { 1171 cairo_os2_surface_t * local_os2_surface;957 cairo_os2_surface_t *surface = abstract_dst; 1172 958 1173 local_os2_surface = (cairo_os2_surface_t *) surface; 1174 if ((!local_os2_surface) || 1175 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 1176 { 1177 /* Invalid parameter (wrong surface)! */ 1178 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 1179 } 1180 local_os2_surface->hps_client_window = hps; 959 if (!surface->image) 960 return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NULL_POINTER); 1181 961 1182 return CAIRO_STATUS_SUCCESS; 962 return _cairo_surface_create_span_renderer (op, pattern, surface->image, 963 antialias, rects, clip_region); 1183 964 } 1184 965 1185 static cairo_status_t 1186 _cairo_os2_surface_mark_dirty_rectangle (void *surface, 1187 int x,1188 int y,1189 int width,1190 int height)966 967 static cairo_bool_t 968 _cairo_os2_surface_check_span_renderer (cairo_operator_t op, 969 const cairo_pattern_t *pattern, 970 void *abstract_dst, 971 cairo_antialias_t antialias) 1191 972 { 1192 cairo_os2_surface_t *local_os2_surface; 1193 RECTL rclToBlit; 1194 1195 local_os2_surface = (cairo_os2_surface_t *) surface; 1196 if ((!local_os2_surface) || 1197 (local_os2_surface->base.backend != &cairo_os2_surface_backend)) 1198 { 1199 /* Invalid parameter (wrong surface)! */ 1200 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); 1201 } 973 cairo_os2_surface_t *surface = abstract_dst; 1202 974 1203 /* Get mutex, we'll work with the pixel array! */ 1204 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT) 1205 != NO_ERROR) 1206 { 1207 /* Could not get mutex! */ 1208 return CAIRO_STATUS_NO_MEMORY; 1209 } 975 if (!surface->image) 976 return FALSE; 1210 977 1211 /* Check for defaults */ 1212 if (width < 0) 1213 width = local_os2_surface->bitmap_info.cx; 1214 if (height < 0) 1215 height = local_os2_surface->bitmap_info.cy; 1216 1217 if (local_os2_surface->hwnd_client_window) { 1218 /* We know the HWND, so let's invalidate the window region, 1219 * so the application will redraw itself, using the 1220 * cairo_os2_surface_refresh_window () API from its own PM thread. 1221 * From that function we'll note that it's not a redraw but a 1222 * dirty-rectangle deal stuff, so we'll handle the things from 1223 * there. 1224 * 1225 * This is the safe method, which should be preferred every time. 1226 */ 1227 rclToBlit.xLeft = x; 1228 rclToBlit.xRight = x + width; /* Noninclusive */ 1229 rclToBlit.yTop = local_os2_surface->bitmap_info.cy - (y); 1230 rclToBlit.yBottom = local_os2_surface->bitmap_info.cy - (y + height); /* Noninclusive */ 1231 1232 #if 0 1233 if (local_os2_surface->dirty_area_present) { 1234 /* Yikes, there is already a dirty area which should be 1235 * cleaned up, but we'll overwrite it. Sorry. 1236 * TODO: Something clever should be done here. 1237 */ 1238 } 1239 #endif 978 return _cairo_surface_check_span_renderer (op, pattern, 979 surface->image, 980 antialias); 981 } 1240 982 1241 /* Set up dirty area reminder stuff */1242 memcpy (&(local_os2_surface->rcl_dirty_area), &rclToBlit, sizeof (RECTL));1243 local_os2_surface->dirty_area_present = TRUE;1244 1245 /* Invalidate window area */1246 WinInvalidateRect (local_os2_surface->hwnd_client_window,1247 &rclToBlit,1248 FALSE);1249 } else {1250 /* We don't know the HWND, so try to blit the pixels from here!1251 * Please note that it can be problematic if this is not the PM thread!1252 *1253 * It can cause internal PM stuffs to be scewed up, for some reason.1254 * Please always tell the HWND to the surface using the1255 * cairo_os2_surface_set_hwnd () API, and call cairo_os2_surface_refresh_window ()1256 * from your WM_PAINT, if it's possible!1257 */1258 983 1259 rclToBlit.xLeft = x; 1260 rclToBlit.xRight = x + width; /* Noninclusive */ 1261 rclToBlit.yBottom = y; 1262 rclToBlit.yTop = y + height; /* Noninclusive */ 1263 /* Now get the pixels from the screen! */ 1264 _cairo_os2_surface_get_pixels_from_screen (local_os2_surface, 1265 local_os2_surface->hps_client_window, 1266 &rclToBlit); 1267 } 984 static cairo_bool_t 985 _cairo_os2_surface_get_extents (void *abstract_surface, 986 cairo_rectangle_int_t *rectangle) 987 { 988 cairo_os2_surface_t *surface = abstract_surface; 1268 989 1269 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); 990 rectangle->x = 0; 991 rectangle->y = 0; 992 rectangle->width = surface->width; 993 rectangle->height = surface->height; 1270 994 1271 return CAIRO_STATUS_SUCCESS; 995 return TRUE; 996 } 997 998 999 static void 1000 _cairo_os2_surface_get_font_options (void *abstract_surface, 1001 cairo_font_options_t *options) 1002 { 1003 cairo_os2_surface_t *surface = abstract_surface; 1004 1005 if (surface->image) 1006 cairo_surface_get_font_options (surface->image, options); 1007 else 1008 _cairo_font_options_init_default (options); 1272 1009 } 1273 1010 1011 1274 1012 static const cairo_surface_backend_t cairo_os2_surface_backend = { 1275 1013 CAIRO_SURFACE_TYPE_OS2, 1276 1014 _cairo_os2_surface_finish, 1277 1015 _cairo_default_context_create, 1278 1279 NULL, /* create_similar */ 1016 _cairo_os2_surface_create_similar, 1280 1017 NULL, /* create_similar_image */ 1281 1018 NULL, /* map_to_image */ 1282 1019 NULL, /* unmap_image */ 1283 1284 1020 _cairo_os2_surface_acquire_source_image, 1285 1021 _cairo_os2_surface_release_source_image, 1286 1022 _cairo_os2_surface_acquire_dest_image, 1287 1023 _cairo_os2_surface_release_dest_image, 1288 1024 NULL, /* clone_similar */ 1289 NULL, /* composite */1290 NULL, /* fill_rectangles */1291 NULL, /* composite_trapezoids */1292 NULL, /* create_span_renderer */1293 NULL, /* check_span_renderer */1025 _cairo_os2_surface_composite, 1026 _cairo_os2_surface_fill_rectangles, 1027 _cairo_os2_surface_composite_trapezoids, 1028 _cairo_os2_surface_create_span_renderer, 1029 _cairo_os2_surface_check_span_renderer, 1294 1030 NULL, /* copy_page */ 1295 1031 NULL, /* show_page */ 1296 1032 _cairo_os2_surface_get_extents, 1297 1033 NULL, /* old_show_glyphs */ 1298 NULL, /* get_font_options */1034 _cairo_os2_surface_get_font_options, 1299 1035 NULL, /* flush */ 1300 _cairo_os2_surface_mark_dirty_rectangle,1036 NULL, /* mark_dirty_rectangle */ 1301 1037 NULL, /* scaled_font_fini */ 1302 1038 NULL, /* scaled_glyph_fini */ 1303 1039 NULL, /* paint */ … … static const cairo_surface_backend_t cairo_os2_surface_backend = { 1313 1049 NULL, /* has_show_text_glyphs */ 1314 1050 NULL /* show_text_glyphs */ 1315 1051 }; 1052 1053 1054 /** 1055 * 1056 * Static helper functions 1057 * 1058 **/ 1059 1060 /** 1061 * _cairo_os2_surface_init_image: 1062 * @surface: the cairo_os2_surface to associate with an cairo_image_surface 1063 * 1064 * Creates the image surface that underlies a cairo_os2_surface. 1065 * If the surface's area is not empty, it allocates the memory the image 1066 * surface will use for its bitmap. The image surface is always created, 1067 * regardless of whether its area is empty and is left in its default state 1068 * of transparent black. 1069 * 1070 * Returns: %CAIRO_STATUS_SUCCESS if successful, 1071 * %CAIRO_STATUS_NO_MEMORY if an image buffer can't be allocated, 1072 * or one of several errors if image_surface creation fails. 1073 * 1074 * Since: 1.12 1075 **/ 1076 1077 static cairo_status_t 1078 _cairo_os2_surface_init_image (cairo_os2_surface_t *surface) 1079 { 1080 cairo_status_t status; 1081 int size = surface->stride * surface->height; 1082 1083 if (size) { 1084 surface->data = _cairo_os2_surface_alloc (size); 1085 if (!surface->data) 1086 return CAIRO_STATUS_NO_MEMORY; 1087 } 1088 1089 surface->image = cairo_image_surface_create_for_data (surface->data, 1090 surface->format, 1091 surface->width, 1092 surface->height, 1093 surface->stride); 1094 1095 status = cairo_surface_status (surface->image); 1096 if (_cairo_status_is_error(status)) 1097 return status; 1098 1099 return status; 1100 } 1101 1102 1103 /** 1104 * _cairo_os2_surface_alloc: 1105 * @size: the number of bytes to allocate 1106 * 1107 * Allocates the memory passed to cairo_image_surface_create_for_data() 1108 * that will be used for its bitmap. 1109 * 1110 * Returns: a pointer to the newly allocated buffer if successful, 1111 * %NULL otherwise. 1112 * 1113 * Since: 1.12 1114 **/ 1115 1116 static unsigned char * 1117 _cairo_os2_surface_alloc (unsigned int size) 1118 { 1119 void *buffer; 1120 1121 #ifdef OS2_USE_PLATFORM_ALLOC 1122 # ifdef OS2_HIGH_MEMORY 1123 if (!DosAllocMem (&buffer, size, 1124 OBJ_ANY | PAG_READ | PAG_WRITE | PAG_COMMIT)) 1125 return buffer; 1126 # endif 1127 if (DosAllocMem (&buffer, size, 1128 PAG_READ | PAG_WRITE | PAG_COMMIT)) 1129 buffer = NULL; 1130 1131 return buffer; 1132 #else 1133 buffer = malloc (size); 1134 if (buffer) 1135 memset (buffer, 0, size); 1136 1137 return buffer; 1138 #endif 1139 } 1140 1141 1142 /** 1143 * _cairo_os2_surface_free: 1144 * @buffer: the allocation to free 1145 * 1146 * Frees bitmap-data memory allocated by _cairo_os2_surface_alloc. 1147 * 1148 * Returns: no return value, 1149 * 1150 * Since: 1.12 1151 **/ 1152 1153 static void 1154 _cairo_os2_surface_free (void *buffer) 1155 { 1156 #ifdef OS2_USE_PLATFORM_ALLOC 1157 DosFreeMem (buffer); 1158 #else 1159 free (buffer); 1160 #endif 1161 } 1162 1163 1164 /** 1165 * _cairo_os2_surface_paint_32bpp: 1166 * @surface: the cairo_os2_surface to display 1167 * @hps: presentation space handle associated with the target device 1168 * @src: an array of native RECTL structure identifying those areas of 1169 * the source surface which will be painted onto the destination 1170 * @dst: an array of native RECTL structure that identify where on the 1171 * destination surface the corresponding @src rectangles will be painted 1172 * @count: the number of RECTLs in @src and @dst arrays 1173 * 1174 * Uses standard GPI functions and structures to paint selected portions 1175 * of the surface onto the presentation space identified by @hps. If 1176 * the @src and @dst rectangles are not the same size, GpiDrawBits() will 1177 * expand or compress the image as needed. Y-inversion is temporarily 1178 * enabled for the presentation space so that Cairo's top-line-first 1179 * bitmaps will be handled correctly. 1180 * 1181 * This function assumes the driver for the device context associated 1182 * with @hps is able to handle 32-bit bitmap data as input and can 1183 * convert it to an appropriate format/color-depth as needed. If not, 1184 * the function returns %CAIRO_STATUS_DEVICE_ERROR to signal that the 1185 * 24-bit version of this function should be used instead. 1186 * 1187 * Returns: %CAIRO_STATUS_SUCCESS if successful, 1188 * %CAIRO_STATUS_DEVICE_ERROR if the bit-blit fails. 1189 * 1190 * Since: 1.12 1191 **/ 1192 1193 static cairo_status_t 1194 _cairo_os2_surface_paint_32bpp (cairo_os2_surface_t *surface, 1195 HPS hps, 1196 RECTL *src, 1197 RECTL *dst, 1198 int count) 1199 { 1200 cairo_status_t status = CAIRO_STATUS_SUCCESS; 1201 int inversion; 1202 int ndx; 1203 BITMAPINFO2 bmi; 1204 1205 /* Set up the bitmap header for 32bit depth. */ 1206 memset(&bmi, 0, sizeof (BITMAPINFO2)); 1207 bmi.cbFix = sizeof (BITMAPINFO2) - sizeof (bmi.argbColor[0]); 1208 bmi.cx = surface->width; 1209 bmi.cy = surface->height; 1210 bmi.cPlanes = 1; 1211 bmi.cBitCount = 32; 1212 1213 /* Enable Y Inversion for the HPS, so GpiDrawBits will work with 1214 * Cairo's top-line-first bitmap (vs OS/2's bottom-line-first bitmaps) 1215 */ 1216 inversion = GpiQueryYInversion (hps); 1217 GpiEnableYInversion (hps, surface->height - 1); 1218 1219 for (ndx = 0; ndx < count; ndx++) { 1220 POINTL aPtl[4]; 1221 1222 /* Change y values from OS/2's coordinate system to Cairo's; 1223 * swap top & bottom to accommodate Y-inversion setting; 1224 * and make the destination coordinates non-inclusive. 1225 */ 1226 aPtl[0].x = dst[ndx].xLeft; 1227 aPtl[0].y = surface->height - dst[ndx].yTop; 1228 aPtl[1].x = dst[ndx].xRight - 1; 1229 aPtl[1].y = surface->height - dst[ndx].yBottom - 1; 1230 1231 aPtl[2].x = src[ndx].xLeft; 1232 aPtl[2].y = surface->height - src[ndx].yTop; 1233 aPtl[3].x = src[ndx].xRight; 1234 aPtl[3].y = surface->height - src[ndx].yBottom; 1235 1236 /* paint */ 1237 if (GpiDrawBits (hps, surface->data, &bmi, 1238 4, aPtl, ROP_SRCCOPY, BBO_IGNORE) != GPI_OK) { 1239 status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); 1240 break; 1241 } 1242 } 1243 1244 /* Restore Y inversion */ 1245 GpiEnableYInversion (hps, inversion); 1246 1247 return status; 1248 } 1249 1250 1251 /** 1252 * _cairo_os2_surface_paint_24bpp: 1253 * @surface: the cairo_os2_surface to display 1254 * @hps: presentation space handle associated with the target device 1255 * @src: an array of native RECTL structure identifying those areas of 1256 * the source surface which will be painted onto the destination 1257 * @dst: an array of native RECTL structure that identify where on the 1258 * destination surface the corresponding @src rectangles will be painted 1259 * @count: the number of RECTLs in @src and @dst arrays 1260 * 1261 * This is a fallback function used when the driver for the device context 1262 * associated with @hps is unable to handle 32-bit bitmaps as input. For 1263 * each rectangle to be displayed, it copies that part of the surface to a 1264 * temporary buffer, dropping the high-order byte to create a 24-bit bitmap. 1265 * 1266 * It temporarily enables Y-inversion for the presentation space so that 1267 * Cairo's top-line-first bitmaps will be handled correctly. 1268 * 1269 * Returns: %CAIRO_STATUS_SUCCESS if successful, 1270 * %CAIRO_STATUS_DEVICE_ERROR if the bit-blit fails, 1271 * CAIRO_STATUS_NO_MEMORY if a buffer allocation fails. 1272 * 1273 * Since: 1.12 1274 **/ 1275 1276 static cairo_status_t 1277 _cairo_os2_surface_paint_24bpp (cairo_os2_surface_t *surface, 1278 HPS hps, 1279 RECTL *src, 1280 RECTL *dst, 1281 int count) 1282 { 1283 cairo_status_t status = CAIRO_STATUS_SUCCESS; 1284 int inversion; 1285 int ndx; 1286 int bufSize = 0; 1287 unsigned char *pchBuffer = 0; 1288 BITMAPINFO2 bmi; 1289 1290 /* Set up the bitmap header for 24bit depth. */ 1291 memset(&bmi, 0, sizeof (BITMAPINFO2)); 1292 bmi.cbFix = sizeof (BITMAPINFO2) - sizeof (bmi.argbColor[0]); 1293 bmi.cPlanes = 1; 1294 bmi.cBitCount = 24; 1295 1296 /* Enable Y Inversion for the HPS, so GpiDrawBits will work with 1297 * Cairo's top-line-first bitmap (vs OS/2's bottom-line-first bitmaps) 1298 */ 1299 inversion = GpiQueryYInversion (hps); 1300 GpiEnableYInversion (hps, surface->height - 1); 1301 1302 for (ndx = 0; ndx < count; ndx++) { 1303 1304 int tgt_stride; 1305 int tgt_pad; 1306 int src_advance; 1307 int x_ctr; 1308 int y_ctr; 1309 unsigned char *pchTarget; 1310 unsigned int *pulSource; 1311 POINTL aPtl[4]; 1312 1313 /* For the destination, change y values from OS/2's coordinate 1314 * system to Cairo's; swap top & bottom to accommodate the 1315 * Y-inversion setting; and make its coordinates non-inclusive. 1316 */ 1317 aPtl[0].x = dst[ndx].xLeft; 1318 aPtl[0].y = surface->height - dst[ndx].yTop; 1319 aPtl[1].x = dst[ndx].xRight - 1; 1320 aPtl[1].y = surface->height - dst[ndx].yBottom - 1; 1321 1322 /* For the source, calc its size and map its coordinates to 1323 * the origin of the buffer that will contain the 24-bit data. 1324 */ 1325 bmi.cx = src[ndx].xRight - src[ndx].xLeft; 1326 bmi.cy = src[ndx].yTop - src[ndx].yBottom; 1327 aPtl[2].x = 0; 1328 aPtl[2].y = 0; 1329 aPtl[3].x = bmi.cx; 1330 aPtl[3].y = bmi.cy; 1331 1332 /* The start of each row has to be DWORD aligned. For the 24-bit 1333 * target bitmap, calculate the of number aligned bytes per row 1334 * and the number of padding bytes at the end of each row. For 1335 * the 32-bit source bitmap, calc the number of bytes to advance 1336 * to the starting position on its next row. 1337 */ 1338 tgt_stride = (((bmi.cx * bmi.cBitCount) + 31) / 32) * 4; 1339 tgt_pad = tgt_stride - bmi.cx * 3; 1340 src_advance = surface->stride - bmi.cx * 4; 1341 1342 /* If the existing temporary bitmap buffer is large enough, 1343 * reuse it; otherwise, allocate a new one. If the rows 1344 * don't need padding, it has to be 1 byte larger than the 1345 * size of the bitmap or else the high-order byte from the 1346 * last source row will end up in unallocated memory. 1347 */ 1348 x_ctr = tgt_stride * bmi.cy + (tgt_pad ? 0 : 1); 1349 if (x_ctr > bufSize) { 1350 bufSize = x_ctr; 1351 if (pchBuffer) 1352 _cairo_os2_surface_free (pchBuffer); 1353 pchBuffer = _cairo_os2_surface_alloc (bufSize); 1354 if (!pchBuffer) { 1355 status = _cairo_error (CAIRO_STATUS_NO_MEMORY); 1356 break; 1357 } 1358 } 1359 1360 /* Calc the starting address in the source buffer. */ 1361 pulSource = (unsigned int*) (surface->data + (src[ndx].xLeft * 4) + 1362 ((surface->height - src[ndx].yTop) * surface->stride)); 1363 1364 pchTarget = pchBuffer; 1365 1366 /* Copy 4 bytes from the source but advance the target ptr only 1367 * 3 bytes, so the high-order alpha byte will be overwritten by 1368 * the next copy. At the end of each row, skip over the padding. 1369 */ 1370 for (y_ctr = bmi.cy; y_ctr; y_ctr--) { 1371 for (x_ctr = bmi.cx; x_ctr; x_ctr--) { 1372 *((unsigned int*)pchTarget) = *pulSource++; 1373 pchTarget += 3; 1374 } 1375 pchTarget += tgt_pad; 1376 pulSource = (unsigned int*)((char*)pulSource + src_advance); 1377 } 1378 1379 /* paint */ 1380 if (GpiDrawBits (hps, pchBuffer, &bmi, 1381 4, aPtl, ROP_SRCCOPY, BBO_IGNORE) != GPI_OK) { 1382 status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); 1383 break; 1384 } 1385 } 1386 1387 /* Free the temp buffer */ 1388 if (pchBuffer) 1389 _cairo_os2_surface_free (pchBuffer); 1390 1391 /* Restore Y inversion */ 1392 GpiEnableYInversion (hps, inversion); 1393 1394 return status; 1395 } 1396 1397 1398 /** 1399 * _cairo_os2_surface_paint_dive: 1400 * @surface: the cairo_os2_surface to display 1401 * @hps: presentation space handle associated with the target window 1402 * @rect: an array of native RECTL structure identifying the bottom-left 1403 * and top-right corners of the areas to be displayed 1404 * @count: the number RECTLs in @rect's array 1405 * 1406 * This function uses DIVE to write those portions of the surface identified 1407 * by @rect directly to the screen buffer. It only supports 32- or 24-bit 1408 * full-color video modes. To avoid painting overlapping or child windows, 1409 * it must perform all of the visible-region calculations that GPI normally 1410 * handles. Despite this, it provides a significant improvement in speed 1411 * compared to using GPI functions. 1412 * 1413 * Returns: %CAIRO_STATUS_SUCCESS if successful, 1414 * %CAIRO_STATUS_DEVICE_ERROR if any native call fails. 1415 * 1416 * Since: 1.12 1417 **/ 1418 1419 static cairo_status_t 1420 _cairo_os2_surface_paint_dive (cairo_os2_surface_t *surface, 1421 HPS hps, 1422 RECTL *rect, 1423 int count) 1424 { 1425 cairo_status_t status = CAIRO_STATUS_DEVICE_ERROR; 1426 int rc; 1427 int ndx; 1428 HRGN rgnVisible = 0; 1429 HRGN rgnPaint = 0; 1430 RGNRECT rgnrect; 1431 RECTL rectWnd; 1432 RECTL *rectPtr; 1433 RECTL *rectPaint = 0; 1434 1435 /* Get the visible region for this window; if not visible, exit. */ 1436 rgnVisible = GpiCreateRegion (hps, 0, 0); 1437 if (!rgnVisible) 1438 goto done; 1439 1440 rc = WinQueryVisibleRegion (surface->hwnd, rgnVisible); 1441 if (rc == RGN_ERROR) 1442 goto done; 1443 1444 if (rc == RGN_NULL) { 1445 status = CAIRO_STATUS_SUCCESS; 1446 goto done; 1447 } 1448 1449 /* Create a region from the update rectangles, then AND it against the 1450 * visible region to produce the series of rects that will be painted. 1451 */ 1452 rgnPaint = GpiCreateRegion (hps, count, rect); 1453 if (!rgnPaint) 1454 goto done; 1455 1456 rc = GpiCombineRegion (hps, rgnVisible, rgnPaint, rgnVisible, CRGN_AND); 1457 if (rc == RGN_ERROR) 1458 goto done; 1459 1460 if (rc == RGN_NULL) { 1461 status = CAIRO_STATUS_SUCCESS; 1462 goto done; 1463 } 1464 1465 /* Determine the number of rectangles to paint, 1466 * allocate memory to store them, then fetch them. 1467 */ 1468 rgnrect.ircStart = 1; 1469 rgnrect.crc = (unsigned int)-1; 1470 rgnrect.crcReturned = 0; 1471 rgnrect.ulDirection = RECTDIR_LFRT_TOPBOT; 1472 1473 if (!GpiQueryRegionRects (hps, rgnVisible, 0, &rgnrect, 0)) 1474 goto done; 1475 1476 rectPaint = (RECTL*)malloc (rgnrect.crcReturned * sizeof(RECTL)); 1477 if (!rectPaint) 1478 goto done; 1479 1480 rgnrect.crc = rgnrect.crcReturned; 1481 rgnrect.crcReturned = 0; 1482 if (!GpiQueryRegionRects (hps, rgnVisible, 0, &rgnrect, rectPaint)) 1483 goto done; 1484 1485 /* Get the window's position in screen coordinates. */ 1486 WinQueryWindowRect (surface->hwnd, &rectWnd); 1487 WinMapWindowPoints (surface->hwnd, HWND_DESKTOP, (POINTL*)&rectWnd, 2); 1488 1489 /* If required by the video driver, hide the mouse pointer. */ 1490 if (dive_hideptr) 1491 WinShowPointer (HWND_DESKTOP, FALSE); 1492 1493 /* Get access to the frame buffer */ 1494 rc = DiveAcquireFrameBuffer (dive_handle, &rectWnd); 1495 if (rc) { 1496 _cairo_os2_surface_dive_error (); 1497 goto done; 1498 } 1499 1500 for (ndx = rgnrect.crcReturned, rectPtr = rectPaint; ndx; ndx--, rectPtr++) { 1501 int x; 1502 int y; 1503 unsigned char *srcPtr; 1504 unsigned char *dstPtr; 1505 1506 /* Get the starting point in the surface's buffer. */ 1507 x = rectPtr->xLeft; 1508 y = surface->height - rectPtr->yTop; 1509 srcPtr = surface->data + (y * surface->stride) + (x * 4); 1510 1511 /* Get the starting point in the frame buffer. */ 1512 x = rectPtr->xLeft + rectWnd.xLeft; 1513 y = dive_height - (rectPtr->yTop + rectWnd.yBottom); 1514 dstPtr = dive_scrnbuf + (y * dive_stride) + 1515 (x * (display_use24bpp ? 3 : 4)); 1516 1517 x = (rectPtr->xRight - rectPtr->xLeft); 1518 y = rectPtr->yTop - rectPtr->yBottom; 1519 1520 /* For 24-bit mode, copy 3 bytes at a time but move the source 1521 * pointer 4 bytes to skip over the alpha byte. when we reach 1522 * the right edge of the rect, advance each ptr by the stride 1523 * minus the distance they've already advanced. 1524 */ 1525 if (unlikely (display_use24bpp)) { 1526 int ndx; 1527 int srcAdvance = surface->stride - (x * 4); 1528 int dstAdvance = dive_stride - (x * 3); 1529 1530 while (y) { 1531 for (ndx = x; ndx; ndx--) { 1532 memcpy (dstPtr, srcPtr, 3); 1533 srcPtr += 4; 1534 dstPtr += 3; 1535 } 1536 srcPtr += srcAdvance; 1537 dstPtr += dstAdvance;; 1538 y--; 1539 } 1540 } else { 1541 /* For 32-bit mode, copy an entire line at a time, 1542 * then advance each pointer by its respective stride. 1543 */ 1544 x *= 4; 1545 while (y) { 1546 memcpy (dstPtr, srcPtr, x); 1547 srcPtr += surface->stride; 1548 dstPtr += dive_stride; 1549 y--; 1550 } 1551 } 1552 } 1553 1554 /* Release the frame buffer */ 1555 rc = DiveDeacquireFrameBuffer (dive_handle); 1556 if (rc) { 1557 _cairo_os2_surface_dive_error (); 1558 goto done; 1559 } 1560 1561 status = CAIRO_STATUS_SUCCESS; 1562 1563 done: 1564 /* Cleanup */ 1565 if (dive_hideptr) 1566 WinShowPointer (HWND_DESKTOP, TRUE); 1567 if (rectPaint) 1568 free (rectPaint); 1569 if (rgnPaint) 1570 GpiDestroyRegion (hps, rgnPaint); 1571 if (rgnVisible) 1572 GpiDestroyRegion (hps, rgnVisible); 1573 1574 return status; 1575 } 1576 1577 1578 /** 1579 * _cairo_os2_surface_dive_error: 1580 * 1581 * Closes DIVE instance if open, resets values, and disables DIVE 1582 * for this process. Used when a DIVE function fails. 1583 * 1584 * Returns: no return value. 1585 * 1586 * Since: 1.12 1587 **/ 1588 1589 static void 1590 _cairo_os2_surface_dive_error (void) 1591 { 1592 if (dive_handle) 1593 DiveClose (dive_handle); 1594 dive_handle = 0; 1595 dive_scrnbuf = 0; 1596 dive_hideptr = TRUE; 1597 dive_status = -1; 1598 return; 1599 } 1600 1601 1602 /** 1603 * _cairo_os2_surface_load_dive: 1604 * 1605 * Loads dive.dll and gets the entry point addresses used by this module. 1606 * 1607 * Returns: %TRUE if successful, %FALSE otherwise. 1608 * 1609 * Since: 1.12 1610 **/ 1611 1612 #ifdef OS2_DYNAMIC_DIVE 1613 1614 static cairo_bool_t 1615 _cairo_os2_surface_load_dive (void) 1616 { 1617 HMODULE hmod; 1618 1619 if (DosLoadModule (0, 0, "DIVE", &hmod)) 1620 return FALSE; 1621 1622 if (DosQueryProcAddr (hmod, ORD_DIVEQUERYCAPS, 1623 0, (PFN*)&pDiveQueryCaps) || 1624 DosQueryProcAddr (hmod, ORD_DIVEOPEN, 1625 0, (PFN*)&pDiveOpen) || 1626 DosQueryProcAddr (hmod, ORD_DIVECLOSE, 1627 0, (PFN*)&pDiveClose) || 1628 DosQueryProcAddr (hmod, ORD_DIVEACQUIREFRAMEBUFFER, 1629 0, (PFN*)&pDiveAcquireFrameBuffer) || 1630 DosQueryProcAddr (hmod, ORD_DIVEDEACQUIREFRAMEBUFFER, 1631 0, (PFN*)&pDiveDeacquireFrameBuffer)) { 1632 DosFreeModule(hmod); 1633 return FALSE; 1634 } 1635 1636 return TRUE; 1637 } 1638 #endif 1639 -
src/cairo-os2.h
diff --git a/src/cairo-os2.h b/src/cairo-os2.h index d23f2de..4b84a60 100644
a b 33 33 * 34 34 * Contributor(s): 35 35 * Peter Weilbacher <mozilla@Weilbacher.org> 36 * Rich Walsh < dragtext@e-vertise.com>36 * Rich Walsh <rich@e-vertise.com> 37 37 */ 38 38 39 39 #ifndef _CAIRO_OS2_H_ 40 40 #define _CAIRO_OS2_H_ 41 41 42 #define INCL_DOS43 #define INCL_DOSSEMAPHORES44 #define INCL_DOSERRORS45 #define INCL_WIN46 #define INCL_GPI47 48 42 #include "cairo.h" 49 43 50 #include <os2.h>51 52 44 CAIRO_BEGIN_DECLS 53 45 54 46 /* The OS/2 Specific Cairo API */ … … cairo_os2_fini (void); 62 54 #if CAIRO_HAS_OS2_SURFACE 63 55 64 56 cairo_public cairo_surface_t * 65 cairo_os2_surface_create ( HPS hps_client_window,66 int width,67 int height);57 cairo_os2_surface_create (cairo_format_t format, 58 int width, 59 int height); 68 60 69 61 cairo_public cairo_surface_t * 70 cairo_os2_surface_create_for_window (HWND hwnd_client_window, 71 int width, 72 int height); 73 74 cairo_public void 75 cairo_os2_surface_set_hwnd (cairo_surface_t *surface, 76 HWND hwnd_client_window); 62 cairo_os2_surface_create_for_window (HWND hwnd, 63 int width, 64 int height); 77 65 78 cairo_public int 79 cairo_os2_surface_set_size (cairo_surface_t *surface, 80 int new_width, 81 int new_height, 82 int timeout); 83 84 cairo_public void 85 cairo_os2_surface_refresh_window (cairo_surface_t *surface, 86 HPS hps_begin_paint, 87 PRECTL prcl_begin_paint_rect); 66 cairo_public cairo_surface_t * 67 cairo_os2_surface_create_null_surface (HPS hps, 68 int width, 69 int height); 88 70 89 cairo_public void 90 cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface, 91 cairo_bool_t manual_refresh); 71 cairo_public cairo_status_t 72 cairo_os2_surface_paint_window (cairo_surface_t *surface, 73 HPS hps, 74 RECTL *rect, 75 int count); 92 76 93 cairo_public cairo_bool_t 94 cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface); 77 cairo_public cairo_status_t 78 cairo_os2_surface_paint_bitmap (cairo_surface_t *surface, 79 HPS hps, 80 RECTL *src, 81 RECTL *dst, 82 int count, 83 BOOL use24bpp); 95 84 96 85 cairo_public cairo_status_t 97 86 cairo_os2_surface_get_hps (cairo_surface_t *surface, … … cairo_public cairo_status_t 101 90 cairo_os2_surface_set_hps (cairo_surface_t *surface, 102 91 HPS hps); 103 92 93 cairo_public cairo_status_t 94 cairo_os2_surface_set_hwnd (cairo_surface_t *surface, 95 HWND hwnd); 96 97 cairo_public cairo_status_t 98 cairo_os2_surface_set_size (cairo_surface_t *surface, 99 int width, 100 int height, 101 int copy); 102 103 cairo_public cairo_bool_t 104 cairo_os2_surface_enable_dive (cairo_bool_t enable, 105 cairo_bool_t hide_pointer); 106 104 107 #else /* CAIRO_HAS_OS2_SURFACE */ 105 108 # error Cairo was not compiled with support for the OS/2 backend 106 109 #endif /* CAIRO_HAS_OS2_SURFACE */ … … cairo_os2_surface_set_hps (cairo_surface_t *surface, 108 111 CAIRO_END_DECLS 109 112 110 113 #endif /* _CAIRO_OS2_H_ */ 114