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