1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
3 * Copyright © 2004,2006 Red Hat, Inc.
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.
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.
24 * Author: Carl D. Worth <cworth@cworth.org>
27 #include "cairo-boilerplate-private.h"
28 #include "cairo-boilerplate-xlib.h"
30 #include <cairo-xlib.h>
31 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
32 #include <cairo-xlib-xrender.h>
35 #include <X11/Xutil.h> /* for XDestroyImage */
37 #if !CAIRO_HAS_XLIB_XRENDER_SURFACE
38 #define PolyModePrecise 0
41 static const cairo_user_data_key_t key;
43 typedef struct _xlib_target_closure {
46 cairo_bool_t drawable_is_pixmap;
47 } xlib_target_closure_t;
50 _cairo_boilerplate_xlib_cleanup (void *closure)
52 xlib_target_closure_t *xtc = closure;
55 if (xtc->drawable_is_pixmap)
56 XFreePixmap (xtc->dpy, xtc->drawable);
58 XDestroyWindow (xtc->dpy, xtc->drawable);
60 XCloseDisplay (xtc->dpy);
65 _cairo_boilerplate_xlib_synchronize (void *closure)
67 xlib_target_closure_t *xtc = closure;
70 ximage = XGetImage (xtc->dpy, xtc->drawable,
71 0, 0, 1, 1, AllPlanes, ZPixmap);
73 XDestroyImage (ximage);
77 _cairo_boilerplate_xlib_check_screen_size (Display *dpy,
82 Screen *scr = XScreenOfDisplay (dpy, screen);
83 return width <= WidthOfScreen (scr) && height <= HeightOfScreen (scr);
87 _cairo_boilerplate_xlib_setup_test_surface (cairo_surface_t *surface)
90 /* For testing purposes, tell the X server to strictly adhere to the
91 * Render specification.
93 cairo_xlib_device_debug_set_precision(cairo_surface_get_device(surface),
98 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
99 /* For the xlib backend we distinguish between TEST and PERF mode in a
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.
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.
110 static cairo_surface_t *
111 _cairo_boilerplate_xlib_test_create_surface (Display *dpy,
112 cairo_content_t content,
115 xlib_target_closure_t *xtc)
117 XRenderPictFormat *xrender_format;
118 cairo_surface_t *surface;
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);
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. */
134 case CAIRO_CONTENT_COLOR_ALPHA:
135 xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
137 case CAIRO_CONTENT_COLOR:
138 xrender_format = XRenderFindStandardFormat (dpy, PictStandardRGB24);
140 case CAIRO_CONTENT_ALPHA:
142 CAIRO_BOILERPLATE_DEBUG (("Invalid content for xlib test: %d\n", content));
145 if (xrender_format == NULL) {
146 CAIRO_BOILERPLATE_DEBUG (("X server does not have the Render extension.\n"));
150 xtc->drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy),
151 width, height, xrender_format->depth);
152 xtc->drawable_is_pixmap = TRUE;
154 surface = cairo_xlib_surface_create_with_xrender_format (dpy, xtc->drawable,
155 DefaultScreenOfDisplay (dpy),
159 _cairo_boilerplate_xlib_setup_test_surface(surface);
164 static cairo_surface_t *
165 _cairo_boilerplate_xlib_perf_create_surface (Display *dpy,
166 cairo_content_t content,
169 xlib_target_closure_t *xtc)
171 XSetWindowAttributes attr;
172 XRenderPictFormat *xrender_format;
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"));
183 xtc->drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy),
184 width, height, xrender_format->depth);
185 xtc->drawable_is_pixmap = TRUE;
188 case CAIRO_CONTENT_COLOR:
189 if (! _cairo_boilerplate_xlib_check_screen_size (dpy,
192 CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n"));
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"));
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;
211 case CAIRO_CONTENT_ALPHA:
213 CAIRO_BOILERPLATE_DEBUG (("Invalid content for xlib test: %d\n", content));
217 return cairo_xlib_surface_create_with_xrender_format (dpy, xtc->drawable,
218 DefaultScreenOfDisplay (dpy),
228 static void _destroy_similar (void *closure)
230 struct similar *similar = closure;
232 XFreePixmap (similar->dpy, similar->pixmap);
236 static cairo_surface_t *
237 _cairo_boilerplate_xlib_create_similar (cairo_surface_t *other,
238 cairo_content_t content,
242 XRenderPictFormat *xrender_format;
244 struct similar *similar;
245 cairo_surface_t *surface;
247 similar = malloc (sizeof (*similar));
248 similar->dpy = cairo_xlib_surface_get_display (other);
252 case CAIRO_CONTENT_COLOR_ALPHA: format = PictStandardARGB32; break;
253 case CAIRO_CONTENT_COLOR: format = PictStandardRGB24; break;
254 case CAIRO_CONTENT_ALPHA: format = PictStandardA8; break;
257 xrender_format = XRenderFindStandardFormat (similar->dpy, format);
258 similar->pixmap = XCreatePixmap (similar->dpy,
259 DefaultRootWindow (similar->dpy),
261 xrender_format->depth);
264 cairo_xlib_surface_create_with_xrender_format (similar->dpy,
266 DefaultScreenOfDisplay (similar->dpy),
270 cairo_surface_set_user_data (surface, &key, similar, _destroy_similar);
275 static cairo_surface_t *
276 _cairo_boilerplate_xlib_create_surface (const char *name,
277 cairo_content_t content,
282 cairo_boilerplate_mode_t mode,
285 xlib_target_closure_t *xtc;
287 cairo_surface_t *surface;
289 *closure = xtc = xcalloc (1, sizeof (xlib_target_closure_t));
291 width = ceil (width);
295 height = ceil (height);
299 xtc->dpy = dpy = XOpenDisplay (NULL);
300 if (xtc->dpy == NULL) {
302 CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
306 if (mode == CAIRO_BOILERPLATE_MODE_TEST)
307 surface = _cairo_boilerplate_xlib_test_create_surface (dpy, content, width, height, xtc);
308 else /* mode == CAIRO_BOILERPLATE_MODE_PERF */
309 surface = _cairo_boilerplate_xlib_perf_create_surface (dpy, content, width, height, xtc);
311 if (surface == NULL || cairo_surface_status (surface))
312 _cairo_boilerplate_xlib_cleanup (xtc);
317 static cairo_surface_t *
318 _cairo_boilerplate_xlib_render_0_0_create_surface (const char *name,
319 cairo_content_t content,
324 cairo_boilerplate_mode_t mode,
327 xlib_target_closure_t *xtc;
331 cairo_surface_t *surface, *dummy;
333 *closure = xtc = xcalloc (1, sizeof (xlib_target_closure_t));
335 width = ceil (width);
339 height = ceil (height);
343 xtc->dpy = dpy = XOpenDisplay (NULL);
344 if (xtc->dpy == NULL) {
346 CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
351 screen = DefaultScreen (dpy);
352 pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy), 1, 1,
353 DefaultDepth (dpy, screen));
354 dummy = cairo_xlib_surface_create (dpy, pixmap,
355 DefaultVisual (dpy, screen),
357 cairo_xlib_device_debug_cap_xrender_version (cairo_surface_get_device (dummy),
360 if (mode == CAIRO_BOILERPLATE_MODE_TEST)
361 surface = _cairo_boilerplate_xlib_test_create_surface (dpy, content, width, height, xtc);
362 else /* mode == CAIRO_BOILERPLATE_MODE_PERF */
363 surface = _cairo_boilerplate_xlib_perf_create_surface (dpy, content, width, height, xtc);
365 cairo_surface_destroy (dummy);
366 XFreePixmap (dpy, pixmap);
368 if (surface == NULL || cairo_surface_status (surface))
369 _cairo_boilerplate_xlib_cleanup (xtc);
374 static cairo_surface_t *
375 _cairo_boilerplate_xlib_window_create_surface (const char *name,
376 cairo_content_t content,
381 cairo_boilerplate_mode_t mode,
384 xlib_target_closure_t *xtc;
387 XSetWindowAttributes attr;
388 cairo_surface_t *surface;
390 /* We're not yet bothering to support perf mode for the
391 * xlib-fallback surface. */
392 if (mode == CAIRO_BOILERPLATE_MODE_PERF)
395 /* We also don't support drawing with destination-alpha in the
396 * xlib-fallback surface. */
397 if (content == CAIRO_CONTENT_COLOR_ALPHA)
400 *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
402 width = ceil (width);
406 height = ceil (height);
410 xtc->dpy = dpy = XOpenDisplay (NULL);
411 if (xtc->dpy == NULL) {
412 CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
417 /* This kills performance, but it makes debugging much
418 * easier. That's why we have it here only after explicitly not
419 * supporting PERF mode.*/
420 XSynchronize (dpy, 1);
422 screen = DefaultScreen (dpy);
423 if (! _cairo_boilerplate_xlib_check_screen_size (dpy, screen,
425 CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n"));
431 attr.override_redirect = True;
432 xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
435 DefaultDepth (dpy, screen),
437 DefaultVisual (dpy, screen),
438 CWOverrideRedirect, &attr);
439 XMapWindow (dpy, xtc->drawable);
440 xtc->drawable_is_pixmap = FALSE;
442 surface = cairo_xlib_surface_create (dpy, xtc->drawable,
443 DefaultVisual (dpy, screen),
445 if (cairo_surface_status (surface))
446 _cairo_boilerplate_xlib_cleanup (xtc);
448 _cairo_boilerplate_xlib_setup_test_surface(surface);
455 #if CAIRO_HAS_XLIB_SURFACE
456 /* The xlib-fallback target differs from the xlib target in two ways:
458 * 1. It creates its surfaces without relying on the Render extension
460 * 2. It disables use of the Render extension for its surfaces
462 * This provides testing of the non-Render fallback paths we have in
463 * cairo-xlib-surface.c
465 static cairo_surface_t *
466 _cairo_boilerplate_xlib_fallback_create_surface (const char *name,
467 cairo_content_t content,
472 cairo_boilerplate_mode_t mode,
475 xlib_target_closure_t *xtc;
478 XSetWindowAttributes attr;
479 cairo_surface_t *surface, *dummy;
481 /* We're not yet bothering to support perf mode for the
482 * xlib-fallback surface. */
483 if (mode == CAIRO_BOILERPLATE_MODE_PERF)
486 /* We also don't support drawing with destination-alpha in the
487 * xlib-fallback surface. */
488 if (content == CAIRO_CONTENT_COLOR_ALPHA)
491 *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
493 width = ceil (width);
497 height = ceil (height);
501 xtc->dpy = dpy = XOpenDisplay (NULL);
502 if (xtc->dpy == NULL) {
503 CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
508 /* This kills performance, but it makes debugging much
509 * easier. That's why we have it here only after explicitly not
510 * supporting PERF mode.*/
511 XSynchronize (dpy, 1);
513 screen = DefaultScreen (dpy);
514 if (! _cairo_boilerplate_xlib_check_screen_size (dpy, screen,
516 CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n"));
522 attr.override_redirect = True;
523 xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
526 DefaultDepth (dpy, screen),
528 DefaultVisual (dpy, screen),
529 CWOverrideRedirect, &attr);
530 XMapWindow (dpy, xtc->drawable);
531 xtc->drawable_is_pixmap = FALSE;
533 dummy = cairo_xlib_surface_create (dpy, xtc->drawable,
534 DefaultVisual (dpy, screen),
536 cairo_xlib_device_debug_cap_xrender_version (cairo_surface_get_device (dummy),
539 surface = cairo_xlib_surface_create (dpy, xtc->drawable,
540 DefaultVisual (dpy, screen),
542 cairo_surface_destroy (dummy);
543 if (cairo_surface_status (surface))
544 _cairo_boilerplate_xlib_cleanup (xtc);
546 _cairo_boilerplate_xlib_setup_test_surface(surface);
552 static const cairo_boilerplate_target_t targets[] = {
553 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
554 /* Acceleration architectures may make the results differ by a
555 * bit, so we set the error tolerance to 1. */
557 "xlib", "traps", NULL, "xlib-fallback",
558 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA, 1,
559 "cairo_xlib_surface_create_with_xrender_format",
560 _cairo_boilerplate_xlib_create_surface,
561 _cairo_boilerplate_xlib_create_similar,
563 _cairo_boilerplate_get_image_surface,
564 cairo_surface_write_to_png,
565 _cairo_boilerplate_xlib_cleanup,
566 _cairo_boilerplate_xlib_synchronize,
571 "xlib", "traps", NULL, "xlib-fallback",
572 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
573 "cairo_xlib_surface_create_with_xrender_format",
574 _cairo_boilerplate_xlib_create_surface,
575 _cairo_boilerplate_xlib_create_similar,
577 _cairo_boilerplate_get_image_surface,
578 cairo_surface_write_to_png,
579 _cairo_boilerplate_xlib_cleanup,
580 _cairo_boilerplate_xlib_synchronize,
585 "xlib-window", "traps", NULL, NULL,
586 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
587 "cairo_xlib_surface_create",
588 _cairo_boilerplate_xlib_window_create_surface,
589 cairo_surface_create_similar,
591 _cairo_boilerplate_get_image_surface,
592 cairo_surface_write_to_png,
593 _cairo_boilerplate_xlib_cleanup,
594 _cairo_boilerplate_xlib_synchronize,
599 "xlib-render-0_0", "mask", NULL, NULL,
600 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
601 "cairo_xlib_surface_create",
602 _cairo_boilerplate_xlib_render_0_0_create_surface,
603 cairo_surface_create_similar,
605 _cairo_boilerplate_get_image_surface,
606 cairo_surface_write_to_png,
607 _cairo_boilerplate_xlib_cleanup,
608 _cairo_boilerplate_xlib_synchronize,
613 #if CAIRO_HAS_XLIB_SURFACE
614 /* This is a fallback surface which uses xlib fallbacks instead of
615 * the Render extension. */
617 "xlib-fallback", "image", NULL, NULL,
618 CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
619 "cairo_xlib_surface_create",
620 _cairo_boilerplate_xlib_fallback_create_surface,
621 cairo_surface_create_similar,
623 _cairo_boilerplate_get_image_surface,
624 cairo_surface_write_to_png,
625 _cairo_boilerplate_xlib_cleanup,
626 _cairo_boilerplate_xlib_synchronize,
632 CAIRO_BOILERPLATE (xlib, targets)