ShaderEffect subclasses from Effect, not DependencyObject
[moon.git] / cairo / src / cairo-os2-surface.c
blobbff649ae812d1d3f52f7d3f8e350dd319ad9d0cd
1 /* vim: set sw=4 sts=4 et cin: */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright (c) 2005-2006 netlabs.org
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is
32 * Doodle <doodle@scenergy.dfmk.hu>
34 * Contributor(s):
35 * Peter Weilbacher <mozilla@Weilbacher.org>
38 #include "cairoint.h"
40 #include "cairo-os2-private.h"
42 #include <fontconfig/fontconfig.h>
44 #include <float.h>
45 #ifdef BUILD_CAIRO_DLL
46 # define INCL_WIN
47 # define INCL_GPI
48 # define INCL_DOS
49 # define INCL_DOSERRORS
50 # include <os2emx.h>
51 # include "cairo-os2.h"
52 # ifndef __WATCOMC__
53 # include <emx/startup.h>
54 # endif
55 #endif
58 * Here comes the extra API for the OS/2 platform. Currently it consists
59 * of two extra functions, the cairo_os2_init() and the
60 * cairo_os2_fini(). Both of them are called automatically if
61 * Cairo is compiled to be a DLL file, but you have to call them before
62 * using the Cairo API if you link to Cairo statically!
64 * You'll also find the code in here which deals with DLL initialization
65 * and termination, if the code is built to be a DLL.
66 * (if BUILD_CAIRO_DLL is defined)
69 /* Initialization counter: */
70 static int cairo_os2_initialization_count = 0;
72 static void inline
73 DisableFPUException (void)
75 unsigned short usCW;
77 /* Some OS/2 PM API calls modify the FPU Control Word,
78 * but forget to restore it.
80 * This can result in XCPT_FLOAT_INVALID_OPCODE exceptions,
81 * so to be sure, we disable Invalid Opcode FPU exception
82 * before using FPU stuffs.
84 usCW = _control87 (0, 0);
85 usCW = usCW | EM_INVALID | 0x80;
86 _control87 (usCW, MCW_EM | 0x80);
89 /**
90 * cairo_os2_init:
92 * Initializes the Cairo library. This function is automatically called if
93 * Cairo was compiled to be a DLL (however it's not a problem if it's called
94 * multiple times). But if you link to Cairo statically, you have to call it
95 * once to set up Cairo's internal structures and mutexes.
97 * Since: 1.4
98 **/
99 cairo_public void
100 cairo_os2_init (void)
102 /* This may initialize some stuffs, like create mutex semaphores etc.. */
104 cairo_os2_initialization_count++;
105 if (cairo_os2_initialization_count > 1) return;
107 DisableFPUException ();
109 #if CAIRO_HAS_FT_FONT
110 /* Initialize FontConfig */
111 FcInit ();
112 #endif
114 CAIRO_MUTEX_INITIALIZE ();
118 * cairo_os2_fini:
120 * Uninitializes the Cairo library. This function is automatically called if
121 * Cairo was compiled to be a DLL (however it's not a problem if it's called
122 * multiple times). But if you link to Cairo statically, you have to call it
123 * once to shut down Cairo, to let it free all the resources it has allocated.
125 * Since: 1.4
127 cairo_public void
128 cairo_os2_fini (void)
130 /* This has to uninitialize some stuffs, like destroy mutex semaphores etc.. */
132 if (cairo_os2_initialization_count <= 0) return;
133 cairo_os2_initialization_count--;
134 if (cairo_os2_initialization_count > 0) return;
136 DisableFPUException ();
138 /* Free allocated memories! */
139 /* (Check cairo_debug_reset_static_data () for an example of this!) */
140 _cairo_font_face_reset_static_data ();
141 #if CAIRO_HAS_FT_FONT
142 _cairo_ft_font_reset_static_data ();
143 #endif
145 CAIRO_MUTEX_FINALIZE ();
147 #if CAIRO_HAS_FT_FONT
148 # if HAVE_FCFINI
149 /* Uninitialize FontConfig */
150 FcFini ();
151 # endif
152 #endif
154 #ifdef __WATCOMC__
155 /* It can happen that the libraries we use have memory leaks,
156 * so there are still memory chunks allocated at this point.
157 * In these cases, Watcom might still have a bigger memory chunk,
158 * called "the heap" allocated from the OS.
159 * As we want to minimize the memory we lose from the point of
160 * view of the OS, we call this function to shrink that heap
161 * as much as possible.
163 _heapshrink ();
164 #else
165 /* GCC has a heapmin function that approximately corresponds to
166 * what the Watcom function does
168 _heapmin ();
169 #endif
173 * This function calls the allocation function depending on which
174 * method was compiled into the library: it can be native allocation
175 * (DosAllocMem/DosFreeMem) or C-Library based allocation (malloc/free).
176 * Actually, for pixel buffers that we use this function for, cairo
177 * uses _cairo_malloc_abc, so we use that here, too. And use the
178 * change to check the size argument
180 void *_buffer_alloc (size_t a, size_t b, const unsigned int size)
182 /* check length like in the _cairo_malloc_abc macro, but we can leave
183 * away the unsigned casts as our arguments are unsigned already
185 size_t nbytes = b &&
186 a >= INT32_MAX / b ? 0 : size &&
187 a*b >= INT32_MAX / size ? 0 : a * b * size;
188 void *buffer = NULL;
189 #ifdef OS2_USE_PLATFORM_ALLOC
190 APIRET rc = NO_ERROR;
192 rc = DosAllocMem ((PPVOID)&buffer,
193 nbytes,
194 #ifdef OS2_HIGH_MEMORY /* only if compiled with high-memory support, */
195 OBJ_ANY | /* we can allocate anywhere! */
196 #endif
197 PAG_READ | PAG_WRITE | PAG_COMMIT);
198 if (rc != NO_ERROR) {
199 /* should there for some reason be another error, let's return
200 * a null surface and free the buffer again, because that's
201 * how a malloc failure would look like
203 if (rc != ERROR_NOT_ENOUGH_MEMORY && buffer) {
204 DosFreeMem (buffer);
206 return NULL;
208 #else
209 buffer = malloc (nbytes);
210 #endif
212 /* This does not seem to be needed, malloc'd space is usually
213 * already zero'd out!
216 * memset (buffer, 0x00, nbytes);
219 return buffer;
223 * This function selects the free function depending on which
224 * allocation method was compiled into the library
226 void _buffer_free (void *buffer)
228 #ifdef OS2_USE_PLATFORM_ALLOC
229 DosFreeMem (buffer);
230 #else
231 free (buffer);
232 #endif
235 /* XXX
236 * The cairo_os2_ini() and cairo_os2_fini() functions should be removed and
237 * the LibMain code moved to cairo-system.c. It should also call
238 * cairo_debug_reset_static_data() instead of duplicating its logic...
241 #ifdef BUILD_CAIRO_DLL
242 /* The main DLL entry for DLL initialization and uninitialization */
243 /* Only include this code if we're about to build a DLL. */
245 #ifdef __WATCOMC__
246 unsigned _System
247 LibMain (unsigned hmod,
248 unsigned termination)
249 #else
250 unsigned long _System
251 _DLL_InitTerm (unsigned long hModule,
252 unsigned long termination)
253 #endif
255 if (termination) {
256 /* Unloading the DLL */
257 cairo_os2_fini ();
259 #ifndef __WATCOMC__
260 /* Uninitialize RTL of GCC */
261 __ctordtorTerm ();
262 _CRT_term ();
263 #endif
264 return 1;
265 } else {
266 /* Loading the DLL */
267 #ifndef __WATCOMC__
268 /* Initialize RTL of GCC */
269 if (_CRT_init () != 0)
270 return 0;
271 __ctordtorInit ();
272 #endif
274 cairo_os2_init ();
275 return 1;
279 #endif /* BUILD_CAIRO_DLL */
282 * The following part of the source file contains the code which might
283 * be called the "core" of the OS/2 backend support. This contains the
284 * OS/2 surface support functions and structures.
287 /* Forward declaration */
288 static const cairo_surface_backend_t cairo_os2_surface_backend;
290 /* Unpublished API:
291 * GpiEnableYInversion = PMGPI.723
292 * GpiQueryYInversion = PMGPI.726
293 * BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);
294 * LONG APIENTRY GpiQueryYInversion (HPS hps);
296 BOOL APIENTRY GpiEnableYInversion (HPS hps, LONG lHeight);
297 LONG APIENTRY GpiQueryYInversion (HPS hps);
299 #ifdef __WATCOMC__
300 /* Function declaration for GpiDrawBits () (missing from OpenWatcom headers) */
301 LONG APIENTRY GpiDrawBits (HPS hps,
302 PVOID pBits,
303 PBITMAPINFO2 pbmiInfoTable,
304 LONG lCount,
305 PPOINTL aptlPoints,
306 LONG lRop,
307 ULONG flOptions);
308 #endif
310 static void
311 _cairo_os2_surface_blit_pixels (cairo_os2_surface_t *surface,
312 HPS hps_begin_paint,
313 PRECTL prcl_begin_paint_rect)
315 POINTL aptlPoints[4];
316 LONG lOldYInversion, rc = GPI_OK;
318 /* Enable Y Inversion for the HPS, so the
319 * GpiDrawBits will work with upside-top image, not with upside-down image!
321 lOldYInversion = GpiQueryYInversion (hps_begin_paint);
322 GpiEnableYInversion (hps_begin_paint, surface->bitmap_info.cy-1);
324 /* Target coordinates (Noninclusive) */
325 aptlPoints[0].x = prcl_begin_paint_rect->xLeft;
326 aptlPoints[0].y = prcl_begin_paint_rect->yBottom;
328 aptlPoints[1].x = prcl_begin_paint_rect->xRight-1;
329 aptlPoints[1].y = prcl_begin_paint_rect->yTop-1;
331 /* Source coordinates (Inclusive) */
332 aptlPoints[2].x = prcl_begin_paint_rect->xLeft;
333 aptlPoints[2].y = prcl_begin_paint_rect->yBottom;
335 aptlPoints[3].x = prcl_begin_paint_rect->xRight;
336 aptlPoints[3].y = (prcl_begin_paint_rect->yTop);
338 /* Some extra checking for limits
339 * (Dunno if really needed, but had some crashes sometimes without it,
340 * while developing the code...)
343 int i;
344 for (i = 0; i < 4; i++) {
345 if (aptlPoints[i].x < 0)
346 aptlPoints[i].x = 0;
347 if (aptlPoints[i].y < 0)
348 aptlPoints[i].y = 0;
349 if (aptlPoints[i].x > (LONG) surface->bitmap_info.cx)
350 aptlPoints[i].x = (LONG) surface->bitmap_info.cx;
351 if (aptlPoints[i].y > (LONG) surface->bitmap_info.cy)
352 aptlPoints[i].y = (LONG) surface->bitmap_info.cy;
356 /* Debug code to draw rectangle limits */
357 #if 0
359 int x, y;
360 unsigned char *pixels;
362 pixels = surface->pixels;
363 for (x = 0; x < surface->bitmap_info.cx; x++) {
364 for (y = 0; y < surface->bitmap_info.cy; y++) {
365 if ((x == 0) ||
366 (y == 0) ||
367 (x == y) ||
368 (x >= surface->bitmap_info.cx-1) ||
369 (y >= surface->bitmap_info.cy-1))
371 pixels[y*surface->bitmap_info.cx*4+x*4] = 255;
376 #endif
377 rc = GpiDrawBits (hps_begin_paint,
378 surface->pixels,
379 &(surface->bitmap_info),
381 aptlPoints,
382 ROP_SRCCOPY,
383 BBO_IGNORE);
385 if (rc != GPI_OK) {
386 /* if GpiDrawBits () failed then this is most likely because the
387 * display driver could not handle a 32bit bitmap. So we need to
388 * - create a buffer that only contains 3 bytes per pixel
389 * - change the bitmap info header to contain 24bit
390 * - pass the new buffer to GpiDrawBits () again
391 * - clean up the new buffer
393 BITMAPINFOHEADER2 bmpheader;
394 unsigned char *pchPixBuf, *pchPixSource;
395 void *pBufStart;
396 ULONG ulPixels;
398 /* allocate temporary pixel buffer */
399 pchPixBuf = (unsigned char *) _buffer_alloc (surface->bitmap_info.cy,
400 surface->bitmap_info.cx,
402 pchPixSource = surface->pixels; /* start at beginning of pixel buffer */
403 pBufStart = pchPixBuf; /* remember beginning of the new pixel buffer */
405 /* copy the first three bytes for each pixel but skip over the fourth */
406 for (ulPixels = 0; ulPixels < surface->bitmap_info.cx * surface->bitmap_info.cy; ulPixels++)
408 /* copy BGR from source buffer */
409 *pchPixBuf++ = *pchPixSource++;
410 *pchPixBuf++ = *pchPixSource++;
411 *pchPixBuf++ = *pchPixSource++;
412 pchPixSource++; /* jump over alpha channel in source buffer */
415 /* jump back to start of the buffer for display and cleanup */
416 pchPixBuf = pBufStart;
418 /* set up the bitmap header, but this time with 24bit depth only */
419 memset (&bmpheader, 0, sizeof (bmpheader));
420 bmpheader.cbFix = sizeof (BITMAPINFOHEADER2);
421 bmpheader.cx = surface->bitmap_info.cx;
422 bmpheader.cy = surface->bitmap_info.cy;
423 bmpheader.cPlanes = surface->bitmap_info.cPlanes;
424 bmpheader.cBitCount = 24;
425 rc = GpiDrawBits (hps_begin_paint,
426 pchPixBuf,
427 (PBITMAPINFO2)&bmpheader,
429 aptlPoints,
430 ROP_SRCCOPY,
431 BBO_IGNORE);
433 _buffer_free (pchPixBuf);
436 /* Restore Y inversion */
437 GpiEnableYInversion (hps_begin_paint, lOldYInversion);
440 static void
441 _cairo_os2_surface_get_pixels_from_screen (cairo_os2_surface_t *surface,
442 HPS hps_begin_paint,
443 PRECTL prcl_begin_paint_rect)
445 HPS hps;
446 HDC hdc;
447 HAB hab;
448 SIZEL sizlTemp;
449 HBITMAP hbmpTemp;
450 BITMAPINFO2 bmi2Temp;
451 POINTL aptlPoints[4];
452 int y;
453 unsigned char *pchTemp;
455 /* To copy pixels from screen to our buffer, we do the following steps:
457 * - Blit pixels from screen to a HBITMAP:
458 * -- Create Memory Device Context
459 * -- Create a PS into it
460 * -- Create a HBITMAP
461 * -- Select HBITMAP into memory PS
462 * -- Blit dirty pixels from screen to HBITMAP
463 * - Copy HBITMAP lines (pixels) into our buffer
464 * - Free resources
466 * These steps will require an Anchor Block (HAB). However,
467 * WinQUeryAnchorBlock () documentation says that HAB is not
468 * used in current OS/2 implementations, OS/2 deduces all information
469 * it needs from the TID. Anyway, we'd be in trouble if we'd have to
470 * get a HAB where we only know a HPS...
471 * So, we'll simply use a fake HAB.
474 hab = (HAB) 1; /* OS/2 doesn't really use HAB... */
476 /* Create a memory device context */
477 hdc = DevOpenDC (hab, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
478 if (!hdc) {
479 return;
482 /* Create a memory PS */
483 sizlTemp.cx = prcl_begin_paint_rect->xRight - prcl_begin_paint_rect->xLeft;
484 sizlTemp.cy = prcl_begin_paint_rect->yTop - prcl_begin_paint_rect->yBottom;
485 hps = GpiCreatePS (hab,
486 hdc,
487 &sizlTemp,
488 PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
489 if (!hps) {
490 DevCloseDC (hdc);
491 return;
494 /* Create an uninitialized bitmap. */
495 /* Prepare BITMAPINFO2 structure for our buffer */
496 memset (&bmi2Temp, 0, sizeof (bmi2Temp));
497 bmi2Temp.cbFix = sizeof (BITMAPINFOHEADER2);
498 bmi2Temp.cx = sizlTemp.cx;
499 bmi2Temp.cy = sizlTemp.cy;
500 bmi2Temp.cPlanes = 1;
501 bmi2Temp.cBitCount = 32;
503 hbmpTemp = GpiCreateBitmap (hps,
504 (PBITMAPINFOHEADER2) &bmi2Temp,
506 NULL,
507 NULL);
509 if (!hbmpTemp) {
510 GpiDestroyPS (hps);
511 DevCloseDC (hdc);
512 return;
515 /* Select the bitmap into the memory device context. */
516 GpiSetBitmap (hps, hbmpTemp);
518 /* Target coordinates (Noninclusive) */
519 aptlPoints[0].x = 0;
520 aptlPoints[0].y = 0;
522 aptlPoints[1].x = sizlTemp.cx;
523 aptlPoints[1].y = sizlTemp.cy;
525 /* Source coordinates (Inclusive) */
526 aptlPoints[2].x = prcl_begin_paint_rect->xLeft;
527 aptlPoints[2].y = surface->bitmap_info.cy - prcl_begin_paint_rect->yBottom;
529 aptlPoints[3].x = prcl_begin_paint_rect->xRight;
530 aptlPoints[3].y = surface->bitmap_info.cy - prcl_begin_paint_rect->yTop;
532 /* Blit pixels from screen to bitmap */
533 GpiBitBlt (hps,
534 hps_begin_paint,
536 aptlPoints,
537 ROP_SRCCOPY,
538 BBO_IGNORE);
540 /* Now we have to extract the pixels from the bitmap. */
541 pchTemp =
542 surface->pixels +
543 (prcl_begin_paint_rect->yBottom)*surface->bitmap_info.cx*4 +
544 prcl_begin_paint_rect->xLeft*4;
545 for (y = 0; y < sizlTemp.cy; y++) {
546 /* Get one line of pixels */
547 GpiQueryBitmapBits (hps,
548 sizlTemp.cy - y - 1, /* lScanStart */
549 1, /* lScans */
550 pchTemp,
551 &bmi2Temp);
553 /* Go for next line */
554 pchTemp += surface->bitmap_info.cx*4;
557 /* Clean up resources */
558 GpiSetBitmap (hps, (HBITMAP) NULL);
559 GpiDeleteBitmap (hbmpTemp);
560 GpiDestroyPS (hps);
561 DevCloseDC (hdc);
564 static cairo_status_t
565 _cairo_os2_surface_acquire_source_image (void *abstract_surface,
566 cairo_image_surface_t **image_out,
567 void **image_extra)
569 cairo_os2_surface_t *local_os2_surface;
571 local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
572 if ((!local_os2_surface) ||
573 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
575 /* Invalid parameter (wrong surface)! */
576 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
579 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
581 /* Increase lend counter */
582 local_os2_surface->pixel_array_lend_count++;
584 *image_out = local_os2_surface->image_surface;
585 *image_extra = NULL;
587 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
589 return CAIRO_STATUS_SUCCESS;
592 static void
593 _cairo_os2_surface_release_source_image (void *abstract_surface,
594 cairo_image_surface_t *image,
595 void *image_extra)
597 cairo_os2_surface_t *local_os2_surface;
599 local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
600 if ((!local_os2_surface) ||
601 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
603 /* Invalid parameter (wrong surface)! */
604 return;
607 /* Decrease Lend counter! */
608 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
610 if (local_os2_surface->pixel_array_lend_count > 0)
611 local_os2_surface->pixel_array_lend_count--;
612 DosPostEventSem (local_os2_surface->hev_pixel_array_came_back);
614 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
615 return;
618 static cairo_status_t
619 _cairo_os2_surface_acquire_dest_image (void *abstract_surface,
620 cairo_rectangle_int_t *interest_rect,
621 cairo_image_surface_t **image_out,
622 cairo_rectangle_int_t *image_rect,
623 void **image_extra)
625 cairo_os2_surface_t *local_os2_surface;
627 local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
628 if ((!local_os2_surface) ||
629 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
631 /* Invalid parameter (wrong surface)! */
632 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
635 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
637 /* Increase lend counter */
638 local_os2_surface->pixel_array_lend_count++;
640 *image_out = local_os2_surface->image_surface;
641 *image_extra = NULL;
643 image_rect->x = 0;
644 image_rect->y = 0;
645 image_rect->width = local_os2_surface->bitmap_info.cx;
646 image_rect->height = local_os2_surface->bitmap_info.cy;
648 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
650 return CAIRO_STATUS_SUCCESS;
653 static void
654 _cairo_os2_surface_release_dest_image (void *abstract_surface,
655 cairo_rectangle_int_t *interest_rect,
656 cairo_image_surface_t *image,
657 cairo_rectangle_int_t *image_rect,
658 void *image_extra)
660 cairo_os2_surface_t *local_os2_surface;
661 RECTL rclToBlit;
663 local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
664 if ((!local_os2_surface) ||
665 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
667 /* Invalid parameter (wrong surface)! */
668 return;
671 /* So, we got back the image, and if all goes well, then
672 * something has been changed inside the interest_rect.
673 * So, we blit it to the screen!
676 if (local_os2_surface->blit_as_changes) {
677 /* Get mutex, we'll work with the pixel array! */
678 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)!=NO_ERROR) {
679 /* Could not get mutex! */
680 return;
683 if (local_os2_surface->hwnd_client_window) {
684 /* We know the HWND, so let's invalidate the window region,
685 * so the application will redraw itself, using the
686 * cairo_os2_surface_refresh_window () API from its own PM thread.
688 * This is the safe method, which should be preferred every time.
690 rclToBlit.xLeft = interest_rect->x;
691 rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */
692 rclToBlit.yTop = local_os2_surface->bitmap_info.cy - (interest_rect->y);
693 rclToBlit.yBottom = local_os2_surface->bitmap_info.cy - (interest_rect->y+interest_rect->height); /* Noninclusive */
695 WinInvalidateRect (local_os2_surface->hwnd_client_window,
696 &rclToBlit,
697 FALSE);
698 } else {
699 /* We don't know the HWND, so try to blit the pixels from here!
700 * Please note that it can be problematic if this is not the PM thread!
702 * It can cause internal PM stuffs to be scewed up, for some reason.
703 * Please always tell the HWND to the surface using the
704 * cairo_os2_surface_set_hwnd () API, and call cairo_os2_surface_refresh_window ()
705 * from your WM_PAINT, if it's possible!
707 rclToBlit.xLeft = interest_rect->x;
708 rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */
709 rclToBlit.yBottom = interest_rect->y;
710 rclToBlit.yTop = interest_rect->y+interest_rect->height; /* Noninclusive */
711 /* Now blit there the stuffs! */
712 _cairo_os2_surface_blit_pixels (local_os2_surface,
713 local_os2_surface->hps_client_window,
714 &rclToBlit);
717 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
719 /* Also decrease Lend counter! */
720 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
722 if (local_os2_surface->pixel_array_lend_count > 0)
723 local_os2_surface->pixel_array_lend_count--;
724 DosPostEventSem (local_os2_surface->hev_pixel_array_came_back);
726 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
729 static cairo_int_status_t
730 _cairo_os2_surface_get_extents (void *abstract_surface,
731 cairo_rectangle_int_t *rectangle)
733 cairo_os2_surface_t *local_os2_surface;
735 local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
736 if ((!local_os2_surface) ||
737 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
739 /* Invalid parameter (wrong surface)! */
740 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
743 rectangle->x = 0;
744 rectangle->y = 0;
745 rectangle->width = local_os2_surface->bitmap_info.cx;
746 rectangle->height = local_os2_surface->bitmap_info.cy;
748 return CAIRO_STATUS_SUCCESS;
752 * cairo_os2_surface_create:
753 * @hps_client_window: the presentation handle to bind the surface to
754 * @width: the width of the surface
755 * @height: the height of the surface
757 * Create a Cairo surface which is bound to a given presentation space (HPS).
758 * The surface will be created to have the given size.
759 * By default every change to the surface will be made visible immediately by
760 * blitting it into the window. This can be changed with
761 * cairo_os2_surface_set_manual_window_refresh().
762 * Note that the surface will contain garbage when created, so the pixels have
763 * to be initialized by hand first. You can use the Cairo functions to fill it
764 * with black, or use cairo_surface_mark_dirty() to fill the surface with pixels
765 * from the window/HPS.
767 * Return value: the newly created surface
769 * Since: 1.4
771 cairo_surface_t *
772 cairo_os2_surface_create (HPS hps_client_window,
773 int width,
774 int height)
776 cairo_os2_surface_t *local_os2_surface;
777 cairo_status_t status;
778 int rc;
780 /* Check the size of the window */
781 if ((width <= 0) ||
782 (height <= 0))
784 /* Invalid window size! */
785 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
788 local_os2_surface = (cairo_os2_surface_t *) malloc (sizeof (cairo_os2_surface_t));
789 if (!local_os2_surface) {
790 /* Not enough memory! */
791 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
794 /* Initialize the OS/2 specific parts of the surface! */
796 /* Create mutex semaphore */
797 rc = DosCreateMutexSem (NULL,
798 &(local_os2_surface->hmtx_use_private_fields),
800 FALSE);
801 if (rc != NO_ERROR) {
802 /* Could not create mutex semaphore! */
803 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
806 /* Save PS handle */
807 local_os2_surface->hps_client_window = hps_client_window;
809 /* Defaults */
810 local_os2_surface->hwnd_client_window = NULLHANDLE;
811 local_os2_surface->blit_as_changes = TRUE;
812 local_os2_surface->pixel_array_lend_count = 0;
813 rc = DosCreateEventSem (NULL,
814 &(local_os2_surface->hev_pixel_array_came_back),
816 FALSE);
818 if (rc != NO_ERROR) {
819 /* Could not create event semaphore! */
820 DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
821 free (local_os2_surface);
822 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
825 /* Prepare BITMAPINFO2 structure for our buffer */
826 memset (&(local_os2_surface->bitmap_info), 0, sizeof (local_os2_surface->bitmap_info));
827 local_os2_surface->bitmap_info.cbFix = sizeof (BITMAPINFOHEADER2);
828 local_os2_surface->bitmap_info.cx = width;
829 local_os2_surface->bitmap_info.cy = height;
830 local_os2_surface->bitmap_info.cPlanes = 1;
831 local_os2_surface->bitmap_info.cBitCount = 32;
833 /* Allocate memory for pixels */
834 local_os2_surface->pixels = (unsigned char *) _buffer_alloc (height, width, 4);
835 if (!(local_os2_surface->pixels)) {
836 /* Not enough memory for the pixels! */
837 DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
838 DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
839 free (local_os2_surface);
840 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
843 /* Create image surface from pixel array */
844 local_os2_surface->image_surface = (cairo_image_surface_t *)
845 cairo_image_surface_create_for_data (local_os2_surface->pixels,
846 CAIRO_FORMAT_ARGB32,
847 width, /* Width */
848 height, /* Height */
849 width * 4); /* Rowstride */
851 status = local_os2_surface->image_surface->base.status;
852 if (status) {
853 /* Could not create image surface! */
854 _buffer_free (local_os2_surface->pixels);
855 DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
856 DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
857 free (local_os2_surface);
858 return _cairo_surface_create_in_error (status);
861 /* Initialize base surface */
862 _cairo_surface_init (&local_os2_surface->base,
863 &cairo_os2_surface_backend,
864 _cairo_content_from_format (CAIRO_FORMAT_ARGB32));
866 return (cairo_surface_t *)local_os2_surface;
870 * cairo_os2_surface_set_size:
871 * @surface: the cairo surface to resize
872 * @new_width: the new width of the surface
873 * @new_height: the new height of the surface
874 * @timeout: timeout value in milliseconds
876 * When the client window is resized, call this API to set the new size in the
877 * underlying surface accordingly. This function will reallocate everything,
878 * so you'll have to redraw everything in the surface after this call.
879 * The surface will contain garbage after the resizing. So the notes of
880 * cairo_os2_surface_create() apply here, too.
882 * The timeout value specifies how long the function should wait on other parts
883 * of the program to release the buffers. It is necessary, because it can happen
884 * that Cairo is just drawing something into the surface while we want to
885 * destroy and recreate it.
887 * Return value: %CAIRO_STATUS_SUCCESS if the surface could be resized,
888 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface,
889 * %CAIRO_STATUS_NO_MEMORY if the new size could not be allocated, for invalid
890 * sizes, or if the timeout happened before all the buffers were released
892 * Since: 1.4
895 cairo_os2_surface_set_size (cairo_surface_t *surface,
896 int new_width,
897 int new_height,
898 int timeout)
900 cairo_os2_surface_t *local_os2_surface;
901 unsigned char *pchNewPixels;
902 int rc;
903 cairo_image_surface_t *pNewImageSurface;
905 local_os2_surface = (cairo_os2_surface_t *) surface;
906 if ((!local_os2_surface) ||
907 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
909 /* Invalid parameter (wrong surface)! */
910 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
913 if ((new_width <= 0) ||
914 (new_height <= 0))
916 /* Invalid size! */
917 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
920 /* Allocate memory for new stuffs */
921 pchNewPixels = (unsigned char *) _buffer_alloc (new_height, new_width, 4);
922 if (!pchNewPixels) {
923 /* Not enough memory for the pixels!
924 * Everything remains the same!
926 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
929 /* Create image surface from new pixel array */
930 pNewImageSurface = (cairo_image_surface_t *)
931 cairo_image_surface_create_for_data (pchNewPixels,
932 CAIRO_FORMAT_ARGB32,
933 new_width, /* Width */
934 new_height, /* Height */
935 new_width * 4); /* Rowstride */
937 if (pNewImageSurface->base.status) {
938 /* Could not create image surface!
939 * Everything remains the same!
941 _buffer_free (pchNewPixels);
942 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
945 /* Okay, new memory allocated, so it's time to swap old buffers
946 * to new ones!
948 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)!=NO_ERROR) {
949 /* Could not get mutex!
950 * Everything remains the same!
952 cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
953 _buffer_free (pchNewPixels);
954 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
957 /* We have to make sure that we won't destroy a surface which
958 * is lent to some other code (Cairo is drawing into it)!
960 while (local_os2_surface->pixel_array_lend_count > 0) {
961 ULONG ulPostCount;
962 DosResetEventSem (local_os2_surface->hev_pixel_array_came_back, &ulPostCount);
963 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
964 /* Wait for somebody to return the pixels! */
965 rc = DosWaitEventSem (local_os2_surface->hev_pixel_array_came_back, timeout);
966 if (rc != NO_ERROR) {
967 /* Either timeout or something wrong... Exit. */
968 cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
969 _buffer_free (pchNewPixels);
970 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
972 /* Okay, grab mutex and check counter again! */
973 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
974 != NO_ERROR)
976 /* Could not get mutex!
977 * Everything remains the same!
979 cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
980 _buffer_free (pchNewPixels);
981 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
985 /* Destroy old image surface */
986 cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface));
987 /* Destroy old pixel buffer */
988 _buffer_free (local_os2_surface->pixels);
989 /* Set new image surface */
990 local_os2_surface->image_surface = pNewImageSurface;
991 /* Set new pixel buffer */
992 local_os2_surface->pixels = pchNewPixels;
993 /* Change bitmap2 structure */
994 local_os2_surface->bitmap_info.cx = new_width;
995 local_os2_surface->bitmap_info.cy = new_height;
997 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
998 return CAIRO_STATUS_SUCCESS;
1002 * cairo_os2_surface_refresh_window:
1003 * @surface: the cairo surface to refresh
1004 * @hps_begin_paint: the presentation handle of the window to refresh
1005 * @prcl_begin_paint_rect: the rectangle to redraw
1007 * This function can be used to force a repaint of a given area of the client
1008 * window. It should usually be called from the WM_PAINT processing of the
1009 * window procedure. However, it can be called any time a given part of the
1010 * window has to be updated.
1012 * The HPS and RECTL to be passed can be taken from the usual WinBeginPaint call
1013 * of the window procedure, but you can also get the HPS using WinGetPS, and you
1014 * can assemble your own update rectangle by hand.
1015 * If hps_begin_paint is %NULL, the function will use the HPS passed into
1016 * cairo_os2_surface_create(). If @prcl_begin_paint_rect is %NULL, the function
1017 * will query the current window size and repaint the whole window.
1019 * Cairo assumes that if you set the HWND to the surface using
1020 * cairo_os2_surface_set_hwnd(), this function will be called by the application
1021 * every time it gets a WM_PAINT for that HWND. If the HWND is set in the
1022 * surface, Cairo uses this function to handle dirty areas too.
1024 * Since: 1.4
1026 void
1027 cairo_os2_surface_refresh_window (cairo_surface_t *surface,
1028 HPS hps_begin_paint,
1029 PRECTL prcl_begin_paint_rect)
1031 cairo_os2_surface_t *local_os2_surface;
1032 RECTL rclTemp;
1034 local_os2_surface = (cairo_os2_surface_t *) surface;
1035 if ((!local_os2_surface) ||
1036 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
1038 /* Invalid parameter (wrong surface)! */
1039 return;
1042 /* Manage defaults (NULLs) */
1043 if (!hps_begin_paint)
1044 hps_begin_paint = local_os2_surface->hps_client_window;
1046 if (prcl_begin_paint_rect == NULL) {
1047 /* Update the whole window! */
1048 rclTemp.xLeft = 0;
1049 rclTemp.xRight = local_os2_surface->bitmap_info.cx;
1050 rclTemp.yTop = local_os2_surface->bitmap_info.cy;
1051 rclTemp.yBottom = 0;
1052 } else {
1053 /* Use the rectangle we got passed as parameter! */
1054 rclTemp.xLeft = prcl_begin_paint_rect->xLeft;
1055 rclTemp.xRight = prcl_begin_paint_rect->xRight;
1056 rclTemp.yTop = local_os2_surface->bitmap_info.cy - prcl_begin_paint_rect->yBottom;
1057 rclTemp.yBottom = local_os2_surface->bitmap_info.cy - prcl_begin_paint_rect->yTop ;
1060 /* Get mutex, we'll work with the pixel array! */
1061 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
1062 != NO_ERROR)
1064 /* Could not get mutex! */
1065 return;
1068 if ((local_os2_surface->dirty_area_present) &&
1069 (local_os2_surface->rcl_dirty_area.xLeft == rclTemp.xLeft) &&
1070 (local_os2_surface->rcl_dirty_area.xRight == rclTemp.xRight) &&
1071 (local_os2_surface->rcl_dirty_area.yTop == rclTemp.yTop) &&
1072 (local_os2_surface->rcl_dirty_area.yBottom == rclTemp.yBottom))
1074 /* Aha, this call was because of a dirty area, so in this case we
1075 * have to blit the pixels from the screen to the surface!
1077 local_os2_surface->dirty_area_present = FALSE;
1078 _cairo_os2_surface_get_pixels_from_screen (local_os2_surface,
1079 hps_begin_paint,
1080 &rclTemp);
1081 } else {
1082 /* Okay, we have the surface, have the HPS
1083 * (might be from WinBeginPaint () or from WinGetPS () )
1084 * Now blit there the stuffs!
1086 _cairo_os2_surface_blit_pixels (local_os2_surface,
1087 hps_begin_paint,
1088 &rclTemp);
1091 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
1094 static cairo_status_t
1095 _cairo_os2_surface_finish (void *abstract_surface)
1097 cairo_os2_surface_t *local_os2_surface;
1099 local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
1100 if ((!local_os2_surface) ||
1101 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
1103 /* Invalid parameter (wrong surface)! */
1104 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1107 DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
1109 /* Destroy old image surface */
1110 cairo_surface_destroy ((cairo_surface_t *) (local_os2_surface->image_surface));
1111 /* Destroy old pixel buffer */
1112 _buffer_free (local_os2_surface->pixels);
1113 DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
1114 DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
1116 /* The memory itself will be free'd by the cairo_surface_destroy ()
1117 * who called us.
1120 return CAIRO_STATUS_SUCCESS;
1124 * cairo_os2_surface_set_hwnd:
1125 * @surface: the cairo surface to associate with the window handle
1126 * @hwnd_client_window: the window handle of the client window
1128 * Sets window handle for surface. If Cairo wants to blit into the window
1129 * because it is set to blit as the surface changes (see
1130 * cairo_os2_surface_set_manual_window_refresh()), then there are two ways it
1131 * can choose:
1132 * If it knows the HWND of the surface, then it invalidates that area, so the
1133 * application will get a WM_PAINT message and it can call
1134 * cairo_os2_surface_refresh_window() to redraw that area. Otherwise cairo itself
1135 * will use the HPS it got at surface creation time, and blit the pixels itself.
1136 * It's also a solution, but experience shows that if this happens from a non-PM
1137 * thread, then it can screw up PM internals.
1139 * So, best solution is to set the HWND for the surface after the surface
1140 * creation, so every blit will be done from application's message processing
1141 * loop, which is the safest way to do.
1143 * Since: 1.4
1145 void
1146 cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
1147 HWND hwnd_client_window)
1149 cairo_os2_surface_t *local_os2_surface;
1151 local_os2_surface = (cairo_os2_surface_t *) surface;
1152 if ((!local_os2_surface) ||
1153 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
1155 /* Invalid parameter (wrong surface)! */
1156 return;
1159 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
1160 != NO_ERROR)
1162 /* Could not get mutex! */
1163 return;
1166 local_os2_surface->hwnd_client_window = hwnd_client_window;
1168 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
1172 * cairo_os2_surface_set_manual_window_refresh:
1173 * @surface: the cairo surface to set the refresh mode for
1174 * @manual_refresh: the switch for manual surface refresh
1176 * This API can tell Cairo if it should show every change to this surface
1177 * immediately in the window or if it should be cached and will only be visible
1178 * once the user calls cairo_os2_surface_refresh_window() explicitly. If the
1179 * HWND was not set in the cairo surface, then the HPS will be used to blit the
1180 * graphics. Otherwise it will invalidate the given window region so the user
1181 * will get the WM_PAINT message to redraw that area of the window.
1183 * So, if you're only interested in displaying the final result after several
1184 * drawing operations, you might get better performance if you put the surface
1185 * into manual refresh mode by passing a true value to this function. Then call
1186 * cairo_os2_surface_refresh() whenever desired.
1188 * Since: 1.4
1190 void
1191 cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
1192 cairo_bool_t manual_refresh)
1194 cairo_os2_surface_t *local_os2_surface;
1196 local_os2_surface = (cairo_os2_surface_t *) surface;
1197 if ((!local_os2_surface) ||
1198 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
1200 /* Invalid parameter (wrong surface)! */
1201 return;
1204 local_os2_surface->blit_as_changes = !manual_refresh;
1208 * cairo_os2_surface_get_manual_window_refresh:
1209 * @surface: the cairo surface to query the refresh mode from
1211 * This space left intentionally blank.
1213 * Return value: current refresh mode of the surface (true by default)
1215 * Since: 1.4
1217 cairo_bool_t
1218 cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface)
1220 cairo_os2_surface_t *local_os2_surface;
1222 local_os2_surface = (cairo_os2_surface_t *) surface;
1223 if ((!local_os2_surface) ||
1224 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
1226 /* Invalid parameter (wrong surface)! */
1227 return FALSE;
1230 return !(local_os2_surface->blit_as_changes);
1233 static cairo_status_t
1234 _cairo_os2_surface_mark_dirty_rectangle (void *surface,
1235 int x,
1236 int y,
1237 int width,
1238 int height)
1240 cairo_os2_surface_t *local_os2_surface;
1241 RECTL rclToBlit;
1243 local_os2_surface = (cairo_os2_surface_t *) surface;
1244 if ((!local_os2_surface) ||
1245 (local_os2_surface->base.backend != &cairo_os2_surface_backend))
1247 /* Invalid parameter (wrong surface)! */
1248 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1251 /* Get mutex, we'll work with the pixel array! */
1252 if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
1253 != NO_ERROR)
1255 /* Could not get mutex! */
1256 return CAIRO_STATUS_NO_MEMORY;
1259 /* Check for defaults */
1260 if (width < 0)
1261 width = local_os2_surface->bitmap_info.cx;
1262 if (height < 0)
1263 height = local_os2_surface->bitmap_info.cy;
1265 if (local_os2_surface->hwnd_client_window) {
1266 /* We know the HWND, so let's invalidate the window region,
1267 * so the application will redraw itself, using the
1268 * cairo_os2_surface_refresh_window () API from its own PM thread.
1269 * From that function we'll note that it's not a redraw but a
1270 * dirty-rectangle deal stuff, so we'll handle the things from
1271 * there.
1273 * This is the safe method, which should be preferred every time.
1275 rclToBlit.xLeft = x;
1276 rclToBlit.xRight = x + width; /* Noninclusive */
1277 rclToBlit.yTop = local_os2_surface->bitmap_info.cy - (y);
1278 rclToBlit.yBottom = local_os2_surface->bitmap_info.cy - (y + height); /* Noninclusive */
1280 #if 0
1281 if (local_os2_surface->dirty_area_present) {
1282 /* Yikes, there is already a dirty area which should be
1283 * cleaned up, but we'll overwrite it. Sorry.
1284 * TODO: Something clever should be done here.
1287 #endif
1289 /* Set up dirty area reminder stuff */
1290 memcpy (&(local_os2_surface->rcl_dirty_area), &rclToBlit, sizeof (RECTL));
1291 local_os2_surface->dirty_area_present = TRUE;
1293 /* Invalidate window area */
1294 WinInvalidateRect (local_os2_surface->hwnd_client_window,
1295 &rclToBlit,
1296 FALSE);
1297 } else {
1298 /* We don't know the HWND, so try to blit the pixels from here!
1299 * Please note that it can be problematic if this is not the PM thread!
1301 * It can cause internal PM stuffs to be scewed up, for some reason.
1302 * Please always tell the HWND to the surface using the
1303 * cairo_os2_surface_set_hwnd () API, and call cairo_os2_surface_refresh_window ()
1304 * from your WM_PAINT, if it's possible!
1307 rclToBlit.xLeft = x;
1308 rclToBlit.xRight = x + width; /* Noninclusive */
1309 rclToBlit.yBottom = y;
1310 rclToBlit.yTop = y + height; /* Noninclusive */
1311 /* Now get the pixels from the screen! */
1312 _cairo_os2_surface_get_pixels_from_screen (local_os2_surface,
1313 local_os2_surface->hps_client_window,
1314 &rclToBlit);
1317 DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
1319 return CAIRO_STATUS_SUCCESS;
1322 static const cairo_surface_backend_t cairo_os2_surface_backend = {
1323 CAIRO_SURFACE_TYPE_OS2,
1324 NULL, /* create_similar */
1325 _cairo_os2_surface_finish,
1326 _cairo_os2_surface_acquire_source_image,
1327 _cairo_os2_surface_release_source_image,
1328 _cairo_os2_surface_acquire_dest_image,
1329 _cairo_os2_surface_release_dest_image,
1330 NULL, /* clone_similar */
1331 NULL, /* composite */
1332 NULL, /* fill_rectangles */
1333 NULL, /* composite_trapezoids */
1334 NULL, /* copy_page */
1335 NULL, /* show_page */
1336 NULL, /* set_clip_region */
1337 NULL, /* intersect_clip_path */
1338 _cairo_os2_surface_get_extents,
1339 NULL, /* old_show_glyphs */
1340 NULL, /* get_font_options */
1341 NULL, /* flush */
1342 _cairo_os2_surface_mark_dirty_rectangle,
1343 NULL, /* scaled_font_fini */
1344 NULL, /* scaled_glyph_fini */
1345 NULL, /* paint */
1346 NULL, /* mask */
1347 NULL, /* stroke */
1348 NULL, /* fill */
1349 NULL, /* show_glyphs */
1350 NULL /* snapshot */