1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /*
3 * Copyright © 2004,2006 Red Hat, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of
10 * Red Hat, Inc. not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior
12 * permission. Red Hat, Inc. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
15 *
16 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
22 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Author: Carl D. Worth <cworth@cworth.org>
25 */
26
27 #include "cairo-boilerplate-private.h"
28 #include "cairo-boilerplate-xlib.h"
29
30 #include <cairo-xlib.h>
31 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
32 #include <cairo-xlib-xrender.h>
33 #endif
34
35 #include <X11/Xutil.h> /* for XDestroyImage */
36
37 #if !CAIRO_HAS_XLIB_XRENDER_SURFACE
38 #define PolyModePrecise 0
39 #endif
40
41 static const cairo_user_data_key_t key;
42
43 typedef struct _xlib_target_closure {
44 Display *dpy;
45 Drawable drawable;
46 cairo_bool_t drawable_is_pixmap;
47 } xlib_target_closure_t;
48
49 static void
_cairo_boilerplate_xlib_cleanup(void * closure)50 _cairo_boilerplate_xlib_cleanup (void *closure)
51 {
52 xlib_target_closure_t *xtc = closure;
53
54 if (xtc->drawable) {
55 if (xtc->drawable_is_pixmap)
56 XFreePixmap (xtc->dpy, xtc->drawable);
57 else
58 XDestroyWindow (xtc->dpy, xtc->drawable);
59 }
60 XCloseDisplay (xtc->dpy);
61 free (xtc);
62 }
63
64 static void
_cairo_boilerplate_xlib_synchronize(void * closure)65 _cairo_boilerplate_xlib_synchronize (void *closure)
66 {
67 xlib_target_closure_t *xtc = closure;
68 XImage *ximage;
69
70 ximage = XGetImage (xtc->dpy, xtc->drawable,
71 0, 0, 1, 1, AllPlanes, ZPixmap);
72 if (ximage != NULL)
73 XDestroyImage (ximage);
74 }
75
76 static cairo_bool_t
_cairo_boilerplate_xlib_check_screen_size(Display * dpy,int screen,int width,int height)77 _cairo_boilerplate_xlib_check_screen_size (Display *dpy,
78 int screen,
79 int width,
80 int height)
81 {
82 Screen *scr = XScreenOfDisplay (dpy, screen);
83 return width <= WidthOfScreen (scr) && height <= HeightOfScreen (scr);
84 }
85
86 static void
_cairo_boilerplate_xlib_setup_test_surface(cairo_surface_t * surface)87 _cairo_boilerplate_xlib_setup_test_surface (cairo_surface_t *surface)
88 {
89
90 /* For testing purposes, tell the X server to strictly adhere to the
91 * Render specification.
92 */
93 cairo_xlib_device_debug_set_precision(cairo_surface_get_device(surface),
94 PolyModePrecise);
95 }
96
97
98 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
99 /* For the xlib backend we distinguish between TEST and PERF mode in a
100 * couple of ways.
101 *
102 * For TEST, we always test against pixmaps of depth 32 (for
103 * COLOR_ALPHA) or 24 (for COLOR) and we use XSynchronize to make it
104 * easier to debug problems.
105 *
106 * For PERF, we test against 32-bit pixmaps for COLOR_ALPHA, but for
107 * COLOR we test against _windows_ at the depth of the default visual.
108 * For obvious reasons, we don't use XSynchronize.
109 */
110 static cairo_surface_t *
_cairo_boilerplate_xlib_test_create_surface(Display * dpy,cairo_content_t content,int width,int height,xlib_target_closure_t * xtc)111 _cairo_boilerplate_xlib_test_create_surface (Display *dpy,
112 cairo_content_t content,
113 int width,
114 int height,
115 xlib_target_closure_t *xtc)
116 {
117 XRenderPictFormat *xrender_format;
118 cairo_surface_t *surface;
119
120 /* This kills performance, but it makes debugging much
121 * easier. That's why we have it here when in TEST mode, but not
122 * over in PERF mode. */
123 XSynchronize (xtc->dpy, 1);
124
125 /* XXX: Currently we don't do any xlib testing when the X server
126 * doesn't have the Render extension. We could do better here,
127 * (perhaps by converting the tests from ARGB32 to RGB24). One
128 * step better would be to always test the non-Render fallbacks
129 * for each test even if the server does have the Render
130 * extension. That would probably be through another
131 * cairo_boilerplate_target which would use an extended version of
132 * cairo_test_xlib_disable_render. */
133 switch (content) {
134 case CAIRO_CONTENT_COLOR_ALPHA:
135 xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
136 break;
137 case CAIRO_CONTENT_COLOR:
138 xrender_format = XRenderFindStandardFormat (dpy, PictStandardRGB24);
139 break;
140 case CAIRO_CONTENT_ALPHA:
141 default:
142 CAIRO_BOILERPLATE_DEBUG (("Invalid content for xlib test: %d\n", content));
143 return NULL;
144 }
145 if (xrender_format == NULL) {
146 CAIRO_BOILERPLATE_DEBUG (("X server does not have the Render extension.\n"));
147 return NULL;
148 }
149
150 xtc->drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy),
151 width, height, xrender_format->depth);
152 xtc->drawable_is_pixmap = TRUE;
153
154 surface = cairo_xlib_surface_create_with_xrender_format (dpy, xtc->drawable,
155 DefaultScreenOfDisplay (dpy),
156 xrender_format,
157 width, height);
158
159 _cairo_boilerplate_xlib_setup_test_surface(surface);
160
161 return surface;
162 }
163
164 static cairo_surface_t *
_cairo_boilerplate_xlib_perf_create_surface(Display * dpy,cairo_content_t content,int width,int height,xlib_target_closure_t * xtc)165 _cairo_boilerplate_xlib_perf_create_surface (Display *dpy,
166 cairo_content_t content,
167 int width,
168 int height,
169 xlib_target_closure_t *xtc)
170 {
171 XSetWindowAttributes attr;
172 XRenderPictFormat *xrender_format;
173 Visual *visual;
174
175 switch (content) {
176 case CAIRO_CONTENT_COLOR_ALPHA:
177 xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
178 if (xrender_format == NULL) {
179 CAIRO_BOILERPLATE_DEBUG (("X server does not have the Render extension.\n"));
180 return NULL;
181 }
182
183 xtc->drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy),
184 width, height, xrender_format->depth);
185 xtc->drawable_is_pixmap = TRUE;
186 break;
187
188 case CAIRO_CONTENT_COLOR:
189 if (! _cairo_boilerplate_xlib_check_screen_size (dpy,
190 DefaultScreen (dpy),
191 width, height)) {
192 CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n"));
193 return NULL;
194 }
195
196 visual = DefaultVisual (dpy, DefaultScreen (dpy));
197 xrender_format = XRenderFindVisualFormat (dpy, visual);
198 if (xrender_format == NULL) {
199 CAIRO_BOILERPLATE_DEBUG (("X server does not have the Render extension.\n"));
200 return NULL;
201 }
202
203 attr.override_redirect = True;
204 xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0,
205 width, height, 0, xrender_format->depth,
206 InputOutput, visual, CWOverrideRedirect, &attr);
207 XMapWindow (dpy, xtc->drawable);
208 xtc->drawable_is_pixmap = FALSE;
209 break;
210
211 case CAIRO_CONTENT_ALPHA:
212 default:
213 CAIRO_BOILERPLATE_DEBUG (("Invalid content for xlib test: %d\n", content));
214 return NULL;
215 }
216
217 return cairo_xlib_surface_create_with_xrender_format (dpy, xtc->drawable,
218 DefaultScreenOfDisplay (dpy),
219 xrender_format,
220 width, height);
221 }
222
223 struct similar {
224 Display *dpy;
225 Pixmap pixmap;
226 };
227
_destroy_similar(void * closure)228 static void _destroy_similar (void *closure)
229 {
230 struct similar *similar = closure;
231
232 XFreePixmap (similar->dpy, similar->pixmap);
233 free (similar);
234 }
235
236 static cairo_surface_t *
_cairo_boilerplate_xlib_create_similar(cairo_surface_t * other,cairo_content_t content,int width,int height)237 _cairo_boilerplate_xlib_create_similar (cairo_surface_t *other,
238 cairo_content_t content,
239 int width,
240 int height)
241 {
242 XRenderPictFormat *xrender_format;
243 uint32_t format;
244 struct similar *similar;
245 cairo_surface_t *surface;
246
247 similar = malloc (sizeof (*similar));
248 similar->dpy = cairo_xlib_surface_get_display (other);
249
250 switch (content) {
251 case CAIRO_CONTENT_COLOR:
252 format = PictStandardRGB24;
253 break;
254 case CAIRO_CONTENT_ALPHA:
255 format = PictStandardA8;
256 break;
257 case CAIRO_CONTENT_COLOR_ALPHA:
258 default:
259 format = PictStandardARGB32;
260 break;
261 }
262
263 xrender_format = XRenderFindStandardFormat (similar->dpy, format);
264 similar->pixmap = XCreatePixmap (similar->dpy,
265 DefaultRootWindow (similar->dpy),
266 width, height,
267 xrender_format->depth);
268
269 surface =
270 cairo_xlib_surface_create_with_xrender_format (similar->dpy,
271 similar->pixmap,
272 DefaultScreenOfDisplay (similar->dpy),
273 xrender_format,
274 width, height);
275
276 cairo_surface_set_user_data (surface, &key, similar, _destroy_similar);
277
278 return surface;
279 }
280
281 static cairo_surface_t *
_cairo_boilerplate_xlib_create_surface(const char * name,cairo_content_t content,double width,double height,double max_width,double max_height,cairo_boilerplate_mode_t mode,void ** closure)282 _cairo_boilerplate_xlib_create_surface (const char *name,
283 cairo_content_t content,
284 double width,
285 double height,
286 double max_width,
287 double max_height,
288 cairo_boilerplate_mode_t mode,
289 void **closure)
290 {
291 xlib_target_closure_t *xtc;
292 Display *dpy;
293 cairo_surface_t *surface;
294
295 *closure = xtc = xcalloc (1, sizeof (xlib_target_closure_t));
296
297 width = ceil (width);
298 if (width < 1)
299 width = 1;
300
301 height = ceil (height);
302 if (height < 1)
303 height = 1;
304
305 xtc->dpy = dpy = XOpenDisplay (NULL);
306 if (xtc->dpy == NULL) {
307 free (xtc);
308 CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
309 return NULL;
310 }
311
312 if (mode == CAIRO_BOILERPLATE_MODE_TEST)
313 surface = _cairo_boilerplate_xlib_test_create_surface (dpy, content, width, height, xtc);
314 else /* mode == CAIRO_BOILERPLATE_MODE_PERF */
315 surface = _cairo_boilerplate_xlib_perf_create_surface (dpy, content, width, height, xtc);
316
317 if (surface == NULL || cairo_surface_status (surface))
318 _cairo_boilerplate_xlib_cleanup (xtc);
319
320 return surface;
321 }
322
323 static cairo_surface_t *
_cairo_boilerplate_xlib_render_0_0_create_surface(const char * name,cairo_content_t content,double width,double height,double max_width,double max_height,cairo_boilerplate_mode_t mode,void ** closure)324 _cairo_boilerplate_xlib_render_0_0_create_surface (const char *name,
325 cairo_content_t content,
326 double width,
327 double height,
328 double max_width,
329 double max_height,
330 cairo_boilerplate_mode_t mode,
331 void **closure)
332 {
333 xlib_target_closure_t *xtc;
334 Display *dpy;
335 int screen;
336 Pixmap pixmap;
337 cairo_surface_t *surface, *dummy;
338
339 *closure = xtc = xcalloc (1, sizeof (xlib_target_closure_t));
340
341 width = ceil (width);
342 if (width < 1)
343 width = 1;
344
345 height = ceil (height);
346 if (height < 1)
347 height = 1;
348
349 xtc->dpy = dpy = XOpenDisplay (NULL);
350 if (xtc->dpy == NULL) {
351 free (xtc);
352 CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
353 return NULL;
354 }
355
356
357 screen = DefaultScreen (dpy);
358 pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy), 1, 1,
359 DefaultDepth (dpy, screen));
360 dummy = cairo_xlib_surface_create (dpy, pixmap,
361 DefaultVisual (dpy, screen),
362 1, 1);
363 cairo_xlib_device_debug_cap_xrender_version (cairo_surface_get_device (dummy),
364 0, 0);
365
366 if (mode == CAIRO_BOILERPLATE_MODE_TEST)
367 surface = _cairo_boilerplate_xlib_test_create_surface (dpy, content, width, height, xtc);
368 else /* mode == CAIRO_BOILERPLATE_MODE_PERF */
369 surface = _cairo_boilerplate_xlib_perf_create_surface (dpy, content, width, height, xtc);
370
371 cairo_surface_destroy (dummy);
372 XFreePixmap (dpy, pixmap);
373
374 if (surface == NULL || cairo_surface_status (surface))
375 _cairo_boilerplate_xlib_cleanup (xtc);
376
377 return surface;
378 }
379
380 static cairo_surface_t *
_cairo_boilerplate_xlib_window_create_surface(const char * name,cairo_content_t content,double width,double height,double max_width,double max_height,cairo_boilerplate_mode_t mode,void ** closure)381 _cairo_boilerplate_xlib_window_create_surface (const char *name,
382 cairo_content_t content,
383 double width,
384 double height,
385 double max_width,
386 double max_height,
387 cairo_boilerplate_mode_t mode,
388 void **closure)
389 {
390 xlib_target_closure_t *xtc;
391 Display *dpy;
392 int screen;
393 XSetWindowAttributes attr;
394 cairo_surface_t *surface;
395
396 /* We're not yet bothering to support perf mode for the
397 * xlib-fallback surface. */
398 if (mode == CAIRO_BOILERPLATE_MODE_PERF)
399 return NULL;
400
401 /* We also don't support drawing with destination-alpha in the
402 * xlib-fallback surface. */
403 if (content == CAIRO_CONTENT_COLOR_ALPHA)
404 return NULL;
405
406 *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
407
408 width = ceil (width);
409 if (width < 1)
410 width = 1;
411
412 height = ceil (height);
413 if (height < 1)
414 height = 1;
415
416 xtc->dpy = dpy = XOpenDisplay (NULL);
417 if (xtc->dpy == NULL) {
418 CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
419 free (xtc);
420 return NULL;
421 }
422
423 /* This kills performance, but it makes debugging much
424 * easier. That's why we have it here only after explicitly not
425 * supporting PERF mode.*/
426 XSynchronize (dpy, 1);
427
428 screen = DefaultScreen (dpy);
429 if (! _cairo_boilerplate_xlib_check_screen_size (dpy, screen,
430 width, height)) {
431 CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n"));
432 XCloseDisplay (dpy);
433 free (xtc);
434 return NULL;
435 }
436
437 attr.override_redirect = True;
438 xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
439 0, 0,
440 width, height, 0,
441 DefaultDepth (dpy, screen),
442 InputOutput,
443 DefaultVisual (dpy, screen),
444 CWOverrideRedirect, &attr);
445 XMapWindow (dpy, xtc->drawable);
446 xtc->drawable_is_pixmap = FALSE;
447
448 surface = cairo_xlib_surface_create (dpy, xtc->drawable,
449 DefaultVisual (dpy, screen),
450 width, height);
451 if (cairo_surface_status (surface))
452 _cairo_boilerplate_xlib_cleanup (xtc);
453
454 _cairo_boilerplate_xlib_setup_test_surface(surface);
455
456 return surface;
457 }
458 #endif
459
460
461 #if CAIRO_HAS_XLIB_SURFACE
462 /* The xlib-fallback target differs from the xlib target in two ways:
463 *
464 * 1. It creates its surfaces without relying on the Render extension
465 *
466 * 2. It disables use of the Render extension for its surfaces
467 *
468 * This provides testing of the non-Render fallback paths we have in
469 * cairo-xlib-surface.c
470 */
471 static cairo_surface_t *
_cairo_boilerplate_xlib_fallback_create_surface(const char * name,cairo_content_t content,double width,double height,double max_width,double max_height,cairo_boilerplate_mode_t mode,void ** closure)472 _cairo_boilerplate_xlib_fallback_create_surface (const char *name,
473 cairo_content_t content,
474 double width,
475 double height,
476 double max_width,
477 double max_height,
478 cairo_boilerplate_mode_t mode,
479 void **closure)
480 {
481 xlib_target_closure_t *xtc;
482 Display *dpy;
483 int screen;
484 XSetWindowAttributes attr;
485 cairo_surface_t *surface, *dummy;
486
487 /* We're not yet bothering to support perf mode for the
488 * xlib-fallback surface. */
489 if (mode == CAIRO_BOILERPLATE_MODE_PERF)
490 return NULL;
491
492 /* We also don't support drawing with destination-alpha in the
493 * xlib-fallback surface. */
494 if (content == CAIRO_CONTENT_COLOR_ALPHA)
495 return NULL;
496
497 *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
498
499 width = ceil (width);
500 if (width < 1)
501 width = 1;
502
503 height = ceil (height);
504 if (height < 1)
505 height = 1;
506
507 xtc->dpy = dpy = XOpenDisplay (NULL);
508 if (xtc->dpy == NULL) {
509 CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
510 free (xtc);
511 return NULL;
512 }
513
514 /* This kills performance, but it makes debugging much
515 * easier. That's why we have it here only after explicitly not
516 * supporting PERF mode.*/
517 XSynchronize (dpy, 1);
518
519 screen = DefaultScreen (dpy);
520 if (! _cairo_boilerplate_xlib_check_screen_size (dpy, screen,
521 width, height)) {
522 CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n"));
523 XCloseDisplay (dpy);
524 free (xtc);
525 return NULL;
526 }
527
528 attr.override_redirect = True;
529 xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
530 0, 0,
531 width, height, 0,
532 DefaultDepth (dpy, screen),
533 InputOutput,
534 DefaultVisual (dpy, screen),
535 CWOverrideRedirect, &attr);
536 XMapWindow (dpy, xtc->drawable);
537 xtc->drawable_is_pixmap = FALSE;
538
539 dummy = cairo_xlib_surface_create (dpy, xtc->drawable,
540 DefaultVisual (dpy, screen),
541 width, height);
542 cairo_xlib_device_debug_cap_xrender_version (cairo_surface_get_device (dummy),
543 -1, -1);
544
545 surface = cairo_xlib_surface_create (dpy, xtc->drawable,
546 DefaultVisual (dpy, screen),
547 width, height);
548 cairo_surface_destroy (dummy);
549 if (cairo_surface_status (surface))
550 _cairo_boilerplate_xlib_cleanup (xtc);
551
552 _cairo_boilerplate_xlib_setup_test_surface(surface);
553
554 return surface;
555 }
556 #endif
557
558 static const cairo_boilerplate_target_t targets[] = {
559 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
560 /* Acceleration architectures may make the results differ by a
561 * bit, so we set the error tolerance to 1. */
562 {
563 "xlib", "traps", NULL, "xlib-fallback",
564 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA, 1,
565 "cairo_xlib_surface_create_with_xrender_format",
566 _cairo_boilerplate_xlib_create_surface,
567 _cairo_boilerplate_xlib_create_similar,
568 NULL, NULL,
569 _cairo_boilerplate_get_image_surface,
570 cairo_surface_write_to_png,
571 _cairo_boilerplate_xlib_cleanup,
572 _cairo_boilerplate_xlib_synchronize,
573 NULL,
574 TRUE, FALSE, FALSE
575 },
576 {
577 "xlib", "traps", NULL, "xlib-fallback",
578 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
579 "cairo_xlib_surface_create_with_xrender_format",
580 _cairo_boilerplate_xlib_create_surface,
581 _cairo_boilerplate_xlib_create_similar,
582 NULL, NULL,
583 _cairo_boilerplate_get_image_surface,
584 cairo_surface_write_to_png,
585 _cairo_boilerplate_xlib_cleanup,
586 _cairo_boilerplate_xlib_synchronize,
587 NULL,
588 FALSE, FALSE, FALSE
589 },
590 {
591 "xlib-window", "traps", NULL, NULL,
592 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
593 "cairo_xlib_surface_create",
594 _cairo_boilerplate_xlib_window_create_surface,
595 cairo_surface_create_similar,
596 NULL, NULL,
597 _cairo_boilerplate_get_image_surface,
598 cairo_surface_write_to_png,
599 _cairo_boilerplate_xlib_cleanup,
600 _cairo_boilerplate_xlib_synchronize,
601 NULL,
602 FALSE, FALSE, FALSE
603 },
604 {
605 "xlib-render-0_0", "mask", NULL, NULL,
606 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
607 "cairo_xlib_surface_create",
608 _cairo_boilerplate_xlib_render_0_0_create_surface,
609 cairo_surface_create_similar,
610 NULL, NULL,
611 _cairo_boilerplate_get_image_surface,
612 cairo_surface_write_to_png,
613 _cairo_boilerplate_xlib_cleanup,
614 _cairo_boilerplate_xlib_synchronize,
615 NULL,
616 FALSE, FALSE, FALSE
617 },
618 #endif
619 #if CAIRO_HAS_XLIB_SURFACE
620 /* This is a fallback surface which uses xlib fallbacks instead of
621 * the Render extension. */
622 {
623 "xlib-fallback", "image", NULL, NULL,
624 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
625 "cairo_xlib_surface_create",
626 _cairo_boilerplate_xlib_fallback_create_surface,
627 cairo_surface_create_similar,
628 NULL, NULL,
629 _cairo_boilerplate_get_image_surface,
630 cairo_surface_write_to_png,
631 _cairo_boilerplate_xlib_cleanup,
632 _cairo_boilerplate_xlib_synchronize,
633 NULL,
634 FALSE, FALSE, FALSE
635 },
636 #endif
637 };
638 CAIRO_BOILERPLATE (xlib, targets)
639