Update change log.
[platform/upstream/cairo.git] / boilerplate / cairo-boilerplate-xlib.c
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
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
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
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
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 *
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 *
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
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 *
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     default:
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;
255     }
256
257     xrender_format = XRenderFindStandardFormat (similar->dpy, format);
258     similar->pixmap = XCreatePixmap (similar->dpy,
259                                      DefaultRootWindow (similar->dpy),
260                                      width, height,
261                                      xrender_format->depth);
262
263     surface =
264             cairo_xlib_surface_create_with_xrender_format (similar->dpy,
265                                                            similar->pixmap,
266                                                            DefaultScreenOfDisplay (similar->dpy),
267                                                            xrender_format,
268                                                            width, height);
269
270     cairo_surface_set_user_data (surface, &key, similar, _destroy_similar);
271
272     return surface;
273 }
274
275 static cairo_surface_t *
276 _cairo_boilerplate_xlib_create_surface (const char                *name,
277                                         cairo_content_t            content,
278                                         double                     width,
279                                         double                     height,
280                                         double                     max_width,
281                                         double                     max_height,
282                                         cairo_boilerplate_mode_t   mode,
283                                         void                     **closure)
284 {
285     xlib_target_closure_t *xtc;
286     Display *dpy;
287     cairo_surface_t *surface;
288
289     *closure = xtc = xcalloc (1, sizeof (xlib_target_closure_t));
290
291     width = ceil (width);
292     if (width < 1)
293         width = 1;
294
295     height = ceil (height);
296     if (height < 1)
297         height = 1;
298
299     xtc->dpy = dpy = XOpenDisplay (NULL);
300     if (xtc->dpy == NULL) {
301         free (xtc);
302         CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
303         return NULL;
304     }
305
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);
310
311     if (surface == NULL || cairo_surface_status (surface))
312         _cairo_boilerplate_xlib_cleanup (xtc);
313
314     return surface;
315 }
316
317 static cairo_surface_t *
318 _cairo_boilerplate_xlib_render_0_0_create_surface (const char             *name,
319                                                    cairo_content_t                 content,
320                                                    double                          width,
321                                                    double                          height,
322                                                    double                          max_width,
323                                                    double                          max_height,
324                                                    cairo_boilerplate_mode_t   mode,
325                                                    void                  **closure)
326 {
327     xlib_target_closure_t *xtc;
328     Display *dpy;
329     int screen;
330     Pixmap pixmap;
331     cairo_surface_t *surface, *dummy;
332
333     *closure = xtc = xcalloc (1, sizeof (xlib_target_closure_t));
334
335     width = ceil (width);
336     if (width < 1)
337         width = 1;
338
339     height = ceil (height);
340     if (height < 1)
341         height = 1;
342
343     xtc->dpy = dpy = XOpenDisplay (NULL);
344     if (xtc->dpy == NULL) {
345         free (xtc);
346         CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
347         return NULL;
348     }
349
350
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),
356                                        1, 1);
357     cairo_xlib_device_debug_cap_xrender_version (cairo_surface_get_device (dummy),
358                                                  0, 0);
359
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);
364
365     cairo_surface_destroy (dummy);
366     XFreePixmap (dpy, pixmap);
367
368     if (surface == NULL || cairo_surface_status (surface))
369         _cairo_boilerplate_xlib_cleanup (xtc);
370
371     return surface;
372 }
373
374 static cairo_surface_t *
375 _cairo_boilerplate_xlib_window_create_surface (const char                *name,
376                                                cairo_content_t            content,
377                                                double                     width,
378                                                double                     height,
379                                                double                     max_width,
380                                                double                     max_height,
381                                                cairo_boilerplate_mode_t   mode,
382                                                void                     **closure)
383 {
384     xlib_target_closure_t *xtc;
385     Display *dpy;
386     int screen;
387     XSetWindowAttributes attr;
388     cairo_surface_t *surface;
389
390     /* We're not yet bothering to support perf mode for the
391      * xlib-fallback surface. */
392     if (mode == CAIRO_BOILERPLATE_MODE_PERF)
393         return NULL;
394
395     /* We also don't support drawing with destination-alpha in the
396      * xlib-fallback surface. */
397     if (content == CAIRO_CONTENT_COLOR_ALPHA)
398         return NULL;
399
400     *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
401
402     width = ceil (width);
403     if (width < 1)
404         width = 1;
405
406     height = ceil (height);
407     if (height < 1)
408         height = 1;
409
410     xtc->dpy = dpy = XOpenDisplay (NULL);
411     if (xtc->dpy == NULL) {
412         CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
413         free (xtc);
414         return NULL;
415     }
416
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);
421
422     screen = DefaultScreen (dpy);
423     if (! _cairo_boilerplate_xlib_check_screen_size (dpy, screen,
424                                                      width, height)) {
425         CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n"));
426         XCloseDisplay (dpy);
427         free (xtc);
428         return NULL;
429     }
430
431     attr.override_redirect = True;
432     xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
433                                    0, 0,
434                                    width, height, 0,
435                                    DefaultDepth (dpy, screen),
436                                    InputOutput,
437                                    DefaultVisual (dpy, screen),
438                                    CWOverrideRedirect, &attr);
439     XMapWindow (dpy, xtc->drawable);
440     xtc->drawable_is_pixmap = FALSE;
441
442     surface = cairo_xlib_surface_create (dpy, xtc->drawable,
443                                          DefaultVisual (dpy, screen),
444                                          width, height);
445     if (cairo_surface_status (surface))
446         _cairo_boilerplate_xlib_cleanup (xtc);
447
448     _cairo_boilerplate_xlib_setup_test_surface(surface);
449
450     return surface;
451 }
452 #endif
453
454
455 #if CAIRO_HAS_XLIB_SURFACE
456 /* The xlib-fallback target differs from the xlib target in two ways:
457  *
458  * 1. It creates its surfaces without relying on the Render extension
459  *
460  * 2. It disables use of the Render extension for its surfaces
461  *
462  * This provides testing of the non-Render fallback paths we have in
463  * cairo-xlib-surface.c
464  */
465 static cairo_surface_t *
466 _cairo_boilerplate_xlib_fallback_create_surface (const char                *name,
467                                                  cairo_content_t            content,
468                                                  double                     width,
469                                                  double                     height,
470                                                  double                     max_width,
471                                                  double                     max_height,
472                                                  cairo_boilerplate_mode_t   mode,
473                                                  void                     **closure)
474 {
475     xlib_target_closure_t *xtc;
476     Display *dpy;
477     int screen;
478     XSetWindowAttributes attr;
479     cairo_surface_t *surface, *dummy;
480
481     /* We're not yet bothering to support perf mode for the
482      * xlib-fallback surface. */
483     if (mode == CAIRO_BOILERPLATE_MODE_PERF)
484         return NULL;
485
486     /* We also don't support drawing with destination-alpha in the
487      * xlib-fallback surface. */
488     if (content == CAIRO_CONTENT_COLOR_ALPHA)
489         return NULL;
490
491     *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
492
493     width = ceil (width);
494     if (width < 1)
495         width = 1;
496
497     height = ceil (height);
498     if (height < 1)
499         height = 1;
500
501     xtc->dpy = dpy = XOpenDisplay (NULL);
502     if (xtc->dpy == NULL) {
503         CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0)));
504         free (xtc);
505         return NULL;
506     }
507
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);
512
513     screen = DefaultScreen (dpy);
514     if (! _cairo_boilerplate_xlib_check_screen_size (dpy, screen,
515                                                      width, height)) {
516         CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n"));
517         XCloseDisplay (dpy);
518         free (xtc);
519         return NULL;
520     }
521
522     attr.override_redirect = True;
523     xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
524                                    0, 0,
525                                    width, height, 0,
526                                    DefaultDepth (dpy, screen),
527                                    InputOutput,
528                                    DefaultVisual (dpy, screen),
529                                    CWOverrideRedirect, &attr);
530     XMapWindow (dpy, xtc->drawable);
531     xtc->drawable_is_pixmap = FALSE;
532
533     dummy = cairo_xlib_surface_create (dpy, xtc->drawable,
534                                        DefaultVisual (dpy, screen),
535                                        width, height);
536     cairo_xlib_device_debug_cap_xrender_version (cairo_surface_get_device (dummy),
537                                                  -1, -1);
538
539     surface = cairo_xlib_surface_create (dpy, xtc->drawable,
540                                          DefaultVisual (dpy, screen),
541                                          width, height);
542     cairo_surface_destroy (dummy);
543     if (cairo_surface_status (surface))
544         _cairo_boilerplate_xlib_cleanup (xtc);
545
546     _cairo_boilerplate_xlib_setup_test_surface(surface);
547
548     return surface;
549 }
550 #endif
551
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. */
556     {
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,
562         NULL, NULL,
563         _cairo_boilerplate_get_image_surface,
564         cairo_surface_write_to_png,
565         _cairo_boilerplate_xlib_cleanup,
566         _cairo_boilerplate_xlib_synchronize,
567         NULL,
568         TRUE, FALSE, FALSE
569     },
570     {
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,
576         NULL, NULL,
577         _cairo_boilerplate_get_image_surface,
578         cairo_surface_write_to_png,
579         _cairo_boilerplate_xlib_cleanup,
580         _cairo_boilerplate_xlib_synchronize,
581         NULL,
582         FALSE, FALSE, FALSE
583     },
584     {
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,
590         NULL, NULL,
591         _cairo_boilerplate_get_image_surface,
592         cairo_surface_write_to_png,
593         _cairo_boilerplate_xlib_cleanup,
594         _cairo_boilerplate_xlib_synchronize,
595         NULL,
596         FALSE, FALSE, FALSE
597     },
598     {
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,
604         NULL, NULL,
605         _cairo_boilerplate_get_image_surface,
606         cairo_surface_write_to_png,
607         _cairo_boilerplate_xlib_cleanup,
608         _cairo_boilerplate_xlib_synchronize,
609         NULL,
610         FALSE, FALSE, FALSE
611     },
612 #endif
613 #if CAIRO_HAS_XLIB_SURFACE
614     /* This is a fallback surface which uses xlib fallbacks instead of
615      * the Render extension. */
616     {
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,
622         NULL, NULL,
623         _cairo_boilerplate_get_image_surface,
624         cairo_surface_write_to_png,
625         _cairo_boilerplate_xlib_cleanup,
626         _cairo_boilerplate_xlib_synchronize,
627         NULL,
628         FALSE, FALSE, FALSE
629     },
630 #endif
631 };
632 CAIRO_BOILERPLATE (xlib, targets)