4edc44bc4100a5ad4c9ebe7df329802fd01b6b3e
[framework/graphics/cairo.git] / test / xlib-surface.c
1 /*
2  * Copyright © 2005 Red Hat, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software
5  * and its documentation for any purpose is hereby granted without
6  * fee, provided that the above copyright notice appear in all copies
7  * and that both that copyright notice and this permission notice
8  * appear in supporting documentation, and that the name of
9  * Red Hat, Inc. not be used in advertising or publicity pertaining to
10  * distribution of the software without specific, written prior
11  * permission. Red Hat, Inc. makes no representations about the
12  * suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
18  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author: Carl D. Worth <cworth@cworth.org>
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include "cairo.h"
30 #include "cairo-xlib.h"
31 #include "cairo-test.h"
32
33 #include "cairo-boilerplate-xlib.h"
34
35 #include "buffer-diff.h"
36
37 #define SIZE 100
38 #define OFFSCREEN_OFFSET 50
39
40 cairo_bool_t result = 0;
41
42 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
43
44 #include "cairo-xlib-xrender.h"
45
46 /* Vladimir Vukicevic reported that surfaces were being created with
47  * mismatching Visuals and XRenderPictFormats.
48  */
49 static cairo_bool_t
50 surface_compare_visual_and_format (cairo_surface_t *surface)
51 {
52     Display *dpy;
53     Visual *visual;
54     XRenderPictFormat *format;
55
56     dpy = cairo_xlib_surface_get_display (surface);
57
58     visual = cairo_xlib_surface_get_visual (surface);
59     if (visual == NULL)
60         return TRUE;
61
62     format = cairo_xlib_surface_get_xrender_format (surface);
63     if (format == NULL)
64         return TRUE;
65
66     return format == XRenderFindVisualFormat (dpy, visual);
67
68 }
69 #else
70
71 static cairo_bool_t
72 surface_compare_visual_and_format (cairo_surface_t *surface)
73 {
74     return TRUE;
75 }
76
77 #endif
78
79 static cairo_bool_t
80 check_similar_visual_and_format (cairo_surface_t *surface)
81 {
82     cairo_surface_t *similar;
83     cairo_bool_t ret;
84
85     similar = cairo_surface_create_similar (surface,
86                                             CAIRO_CONTENT_COLOR_ALPHA,
87                                             1, 1);
88     if (cairo_surface_status (similar))
89         return FALSE;
90
91     ret = surface_compare_visual_and_format (similar);
92
93     cairo_surface_destroy (similar);
94
95     return ret;
96 }
97
98
99 static void
100 draw_pattern (cairo_surface_t *surface)
101 {
102     cairo_t *cr = cairo_create (surface);
103     int i;
104
105     cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
106     cairo_paint (cr);
107
108     cairo_set_source_rgba (cr, 0, 0.0, 0.0, 0.50); /* half-alpha-black */
109
110     for (i = 1; i <= 3; i++) {
111         int inset = SIZE / 8 * i;
112
113         cairo_rectangle (cr,
114                          inset,            inset,
115                          SIZE - 2 * inset, SIZE - 2 * inset);
116         cairo_fill (cr);
117     }
118
119     cairo_destroy (cr);
120 }
121
122 static void
123 erase_pattern (cairo_surface_t *surface)
124 {
125     cairo_t *cr = cairo_create (surface);
126
127     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
128     cairo_paint (cr);
129
130     cairo_destroy (cr);
131 }
132
133 static cairo_test_status_t
134 do_test (const cairo_test_context_t *ctx,
135          Display        *dpy,
136          unsigned char  *reference_data,
137          unsigned char  *test_data,
138          unsigned char  *diff_data,
139          cairo_bool_t    use_pixmap,
140          cairo_bool_t    set_size,
141          cairo_bool_t    offscreen)
142 {
143     cairo_surface_t *surface;
144     cairo_surface_t *test_surface;
145     cairo_t *test_cr;
146     buffer_diff_result_t result;
147     Drawable drawable;
148     int screen = DefaultScreen (dpy);
149
150     if (use_pixmap && offscreen)
151         return CAIRO_TEST_SUCCESS;
152
153     if (use_pixmap) {
154         drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy),
155                                   SIZE, SIZE, DefaultDepth (dpy, screen));
156     } else {
157         XSetWindowAttributes xwa;
158         int x, y;
159
160         xwa.override_redirect = True;
161
162         if (offscreen) {
163             x = - OFFSCREEN_OFFSET;
164             y = - OFFSCREEN_OFFSET;
165         } else {
166             x = 0;
167             y = 0;
168         }
169
170         drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
171                                   x, y, SIZE, SIZE, 0,
172                                   DefaultDepth (dpy, screen), InputOutput,
173                                   DefaultVisual (dpy, screen),
174                                   CWOverrideRedirect, &xwa);
175         XMapWindow (dpy, drawable);
176     }
177
178     surface = cairo_xlib_surface_create (dpy,
179                                          drawable,
180                                          DefaultVisual (dpy, screen),
181                                          SIZE, SIZE);
182
183     if (! surface_compare_visual_and_format (surface))
184         return CAIRO_TEST_FAILURE;
185
186     if (set_size) {
187         cairo_xlib_surface_set_size (surface, SIZE, SIZE);
188
189         if (cairo_xlib_surface_get_width (surface) != SIZE ||
190             cairo_xlib_surface_get_height (surface) != SIZE)
191             return CAIRO_TEST_FAILURE;
192     }
193
194     if (! check_similar_visual_and_format (surface))
195         return CAIRO_TEST_FAILURE;
196
197     draw_pattern (surface);
198
199     test_surface = cairo_image_surface_create_for_data (test_data,
200                                                         CAIRO_FORMAT_RGB24,
201                                                         SIZE, SIZE,
202                                                         SIZE * 4);
203
204     test_cr = cairo_create (test_surface);
205     cairo_set_source_surface (test_cr, surface, 0, 0);
206     cairo_paint (test_cr);
207
208     cairo_destroy (test_cr);
209     cairo_surface_destroy (test_surface);
210
211     /* We erase the surface to black in case we get the same
212      * memory back again for the pixmap case.
213      */
214     erase_pattern (surface);
215     cairo_surface_destroy (surface);
216
217     if (use_pixmap)
218         XFreePixmap (dpy, drawable);
219     else
220         XDestroyWindow (dpy, drawable);
221
222     if (offscreen) {
223         size_t offset = 4 * (SIZE * OFFSCREEN_OFFSET + OFFSCREEN_OFFSET);
224
225         buffer_diff_noalpha (reference_data + offset,
226                              test_data + offset,
227                              diff_data + offset,
228                              SIZE - OFFSCREEN_OFFSET,
229                              SIZE - OFFSCREEN_OFFSET,
230                              4 * SIZE,
231                              &result);
232     } else {
233         buffer_diff_noalpha (reference_data,
234                              test_data,
235                              diff_data,
236                              SIZE,
237                              SIZE,
238                              4 * SIZE,
239                              &result);
240     }
241
242     cairo_test_log (ctx, "xlib-surface: %s, %s, %s: %s\n",
243                     set_size ? "   size" : "no-size",
244                     use_pixmap ? "pixmap" : "window",
245                     use_pixmap ?  "           " : (offscreen ? ", offscreen" : ",  onscreen"),
246                     image_diff_is_failure (&result, 0) ? "FAIL" : "PASS");
247
248     if (image_diff_is_failure (&result, 0))
249         return CAIRO_TEST_FAILURE;
250     else
251         return CAIRO_TEST_SUCCESS;
252 }
253
254 static cairo_bool_t
255 check_visual (Display *dpy)
256 {
257     Visual *visual = DefaultVisual (dpy, DefaultScreen (dpy));
258
259     if ((visual->red_mask   == 0xff0000 &&
260          visual->green_mask == 0x00ff00 &&
261          visual->blue_mask  == 0x0000ff) ||
262         (visual->red_mask   == 0x0000ff &&
263          visual->green_mask == 0x00ff00 &&
264          visual->blue_mask  == 0xff0000))
265         return 1;
266     else
267         return 0;
268 }
269
270 #undef xcalloc
271 static void *
272 xcalloc (const cairo_test_context_t *ctx, size_t a, size_t b)
273 {
274     void *ptr = calloc (a, b);
275     if (ptr == NULL) {
276         cairo_test_log (ctx, "xlib-surface: unable to allocate memory, skipping\n");
277         abort ();
278     }
279     return ptr;
280 }
281
282 static cairo_test_status_t
283 preamble (cairo_test_context_t *ctx)
284 {
285     Display *dpy;
286     unsigned char *reference_data;
287     unsigned char *test_data;
288     unsigned char *diff_data;
289     cairo_surface_t *reference_surface;
290     cairo_bool_t use_pixmap;
291     cairo_bool_t set_size;
292     cairo_bool_t offscreen;
293     cairo_test_status_t status, result = CAIRO_TEST_UNTESTED;
294     int stride;
295
296     if (! cairo_test_is_target_enabled (ctx, "xlib"))
297         goto CLEANUP_TEST;
298
299     dpy = XOpenDisplay (NULL);
300     if (!dpy) {
301         cairo_test_log (ctx, "xlib-surface: Cannot open display, skipping\n");
302         goto CLEANUP_TEST;
303     }
304
305     if (!check_visual (dpy)) {
306         cairo_test_log (ctx, "xlib-surface: default visual is not RGB24 or BGR24, skipping\n");
307         goto CLEANUP_DISPLAY;
308     }
309
310     stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, SIZE);
311
312     reference_data = xcalloc (ctx, SIZE, stride);
313     test_data = xcalloc (ctx, SIZE, stride);
314     diff_data = xcalloc (ctx, SIZE, stride);
315
316     reference_surface = cairo_image_surface_create_for_data (reference_data,
317                                                              CAIRO_FORMAT_RGB24,
318                                                              SIZE, SIZE,
319                                                              stride);
320
321     draw_pattern (reference_surface);
322     cairo_surface_destroy (reference_surface);
323
324     result = CAIRO_TEST_SUCCESS;
325
326     for (set_size = 0; set_size <= 1; set_size++)
327         for (use_pixmap = 0; use_pixmap <= 1; use_pixmap++)
328             for (offscreen = 0; offscreen <= 1; offscreen++) {
329                 status = do_test (ctx, dpy,
330                                   reference_data, test_data, diff_data,
331                                   use_pixmap, set_size, offscreen);
332                 if (status)
333                     result = status;
334             }
335
336     free (reference_data);
337     free (test_data);
338     free (diff_data);
339
340   CLEANUP_DISPLAY:
341     XCloseDisplay (dpy);
342
343   CLEANUP_TEST:
344     return result;
345 }
346
347 CAIRO_TEST (xlib_surface,
348             "Check creating surfaces for various XWindows",
349             "xlib", /* keywords */
350             NULL, /* requirements */
351             0, 0,
352             preamble, NULL)