Opensource Compliance Issue.
[platform/core/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 "cairo-test.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "cairo.h"
32 #include "cairo-xlib.h"
33
34 #include "cairo-boilerplate-xlib.h"
35
36 #include "buffer-diff.h"
37
38 #define SIZE 100
39 #define OFFSCREEN_OFFSET 50
40
41 cairo_bool_t result = 0;
42
43 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
44
45 #include "cairo-xlib-xrender.h"
46
47 /* Vladimir Vukicevic reported that surfaces were being created with
48  * mismatching Visuals and XRenderPictFormats.
49  */
50 static cairo_bool_t
51 surface_compare_visual_and_format (cairo_surface_t *surface)
52 {
53     Display *dpy;
54     Visual *visual;
55     XRenderPictFormat *format;
56
57     dpy = cairo_xlib_surface_get_display (surface);
58
59     visual = cairo_xlib_surface_get_visual (surface);
60     if (visual == NULL)
61         return TRUE;
62
63     format = cairo_xlib_surface_get_xrender_format (surface);
64     if (format == NULL)
65         return TRUE;
66
67     return format == XRenderFindVisualFormat (dpy, visual);
68
69 }
70 #else
71
72 static cairo_bool_t
73 surface_compare_visual_and_format (cairo_surface_t *surface)
74 {
75     return TRUE;
76 }
77
78 #endif
79
80 static cairo_bool_t
81 check_similar_visual_and_format (cairo_surface_t *surface)
82 {
83     cairo_surface_t *similar;
84     cairo_bool_t ret;
85
86     similar = cairo_surface_create_similar (surface,
87                                             CAIRO_CONTENT_COLOR_ALPHA,
88                                             1, 1);
89     if (cairo_surface_status (similar))
90         return FALSE;
91
92     ret = surface_compare_visual_and_format (similar);
93
94     cairo_surface_destroy (similar);
95
96     return ret;
97 }
98
99
100 static void
101 draw_pattern (cairo_surface_t *surface)
102 {
103     cairo_t *cr = cairo_create (surface);
104     int i;
105
106     cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
107     cairo_paint (cr);
108
109     cairo_set_source_rgba (cr, 0, 0.0, 0.0, 0.50); /* half-alpha-black */
110
111     for (i = 1; i <= 3; i++) {
112         int inset = SIZE / 8 * i;
113
114         cairo_rectangle (cr,
115                          inset,            inset,
116                          SIZE - 2 * inset, SIZE - 2 * inset);
117         cairo_fill (cr);
118     }
119
120     cairo_destroy (cr);
121 }
122
123 static void
124 erase_pattern (cairo_surface_t *surface)
125 {
126     cairo_t *cr = cairo_create (surface);
127
128     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
129     cairo_paint (cr);
130
131     cairo_destroy (cr);
132 }
133
134 static cairo_test_status_t
135 do_test (const cairo_test_context_t *ctx,
136          Display        *dpy,
137          unsigned char  *reference_data,
138          unsigned char  *test_data,
139          unsigned char  *diff_data,
140          cairo_bool_t    use_pixmap,
141          cairo_bool_t    set_size,
142          cairo_bool_t    offscreen)
143 {
144     cairo_surface_t *surface;
145     cairo_surface_t *test_surface;
146     cairo_t *test_cr;
147     buffer_diff_result_t result;
148     Drawable drawable;
149     int screen = DefaultScreen (dpy);
150
151     if (use_pixmap && offscreen)
152         return CAIRO_TEST_SUCCESS;
153
154     if (use_pixmap) {
155         drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy),
156                                   SIZE, SIZE, DefaultDepth (dpy, screen));
157     } else {
158         XSetWindowAttributes xwa;
159         int x, y;
160
161         xwa.override_redirect = True;
162
163         if (offscreen) {
164             x = - OFFSCREEN_OFFSET;
165             y = - OFFSCREEN_OFFSET;
166         } else {
167             x = 0;
168             y = 0;
169         }
170
171         drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
172                                   x, y, SIZE, SIZE, 0,
173                                   DefaultDepth (dpy, screen), InputOutput,
174                                   DefaultVisual (dpy, screen),
175                                   CWOverrideRedirect, &xwa);
176         XMapWindow (dpy, drawable);
177     }
178
179     surface = cairo_xlib_surface_create (dpy,
180                                          drawable,
181                                          DefaultVisual (dpy, screen),
182                                          SIZE, SIZE);
183
184     if (! surface_compare_visual_and_format (surface))
185         return CAIRO_TEST_FAILURE;
186
187     if (set_size) {
188         cairo_xlib_surface_set_size (surface, SIZE, SIZE);
189
190         if (cairo_xlib_surface_get_width (surface) != SIZE ||
191             cairo_xlib_surface_get_height (surface) != SIZE)
192             return CAIRO_TEST_FAILURE;
193     }
194
195     if (! check_similar_visual_and_format (surface))
196         return CAIRO_TEST_FAILURE;
197
198     draw_pattern (surface);
199
200     test_surface = cairo_image_surface_create_for_data (test_data,
201                                                         CAIRO_FORMAT_RGB24,
202                                                         SIZE, SIZE,
203                                                         SIZE * 4);
204
205     test_cr = cairo_create (test_surface);
206     cairo_set_source_surface (test_cr, surface, 0, 0);
207     cairo_paint (test_cr);
208
209     cairo_destroy (test_cr);
210     cairo_surface_destroy (test_surface);
211
212     /* We erase the surface to black in case we get the same
213      * memory back again for the pixmap case.
214      */
215     erase_pattern (surface);
216     cairo_surface_destroy (surface);
217
218     if (use_pixmap)
219         XFreePixmap (dpy, drawable);
220     else
221         XDestroyWindow (dpy, drawable);
222
223     if (offscreen) {
224         size_t offset = 4 * (SIZE * OFFSCREEN_OFFSET + OFFSCREEN_OFFSET);
225
226         buffer_diff_noalpha (reference_data + offset,
227                              test_data + offset,
228                              diff_data + offset,
229                              SIZE - OFFSCREEN_OFFSET,
230                              SIZE - OFFSCREEN_OFFSET,
231                              4 * SIZE,
232                              &result);
233     } else {
234         buffer_diff_noalpha (reference_data,
235                              test_data,
236                              diff_data,
237                              SIZE,
238                              SIZE,
239                              4 * SIZE,
240                              &result);
241     }
242
243     cairo_test_log (ctx, "xlib-surface: %s, %s, %s: %s\n",
244                     set_size ? "   size" : "no-size",
245                     use_pixmap ? "pixmap" : "window",
246                     use_pixmap ?  "           " : (offscreen ? ", offscreen" : ",  onscreen"),
247                     image_diff_is_failure (&result, 0) ? "FAIL" : "PASS");
248
249     if (image_diff_is_failure (&result, 0))
250         return CAIRO_TEST_FAILURE;
251     else
252         return CAIRO_TEST_SUCCESS;
253 }
254
255 static cairo_bool_t
256 check_visual (Display *dpy)
257 {
258     Visual *visual = DefaultVisual (dpy, DefaultScreen (dpy));
259
260     if ((visual->red_mask   == 0xff0000 &&
261          visual->green_mask == 0x00ff00 &&
262          visual->blue_mask  == 0x0000ff) ||
263         (visual->red_mask   == 0x0000ff &&
264          visual->green_mask == 0x00ff00 &&
265          visual->blue_mask  == 0xff0000))
266         return 1;
267     else
268         return 0;
269 }
270
271 #undef xcalloc
272 static void *
273 xcalloc (const cairo_test_context_t *ctx, size_t a, size_t b)
274 {
275     void *ptr = calloc (a, b);
276     if (ptr == NULL) {
277         cairo_test_log (ctx, "xlib-surface: unable to allocate memory, skipping\n");
278         abort ();
279     }
280     return ptr;
281 }
282
283 static cairo_test_status_t
284 preamble (cairo_test_context_t *ctx)
285 {
286     Display *dpy;
287     unsigned char *reference_data;
288     unsigned char *test_data;
289     unsigned char *diff_data;
290     cairo_surface_t *reference_surface;
291     cairo_bool_t use_pixmap;
292     cairo_bool_t set_size;
293     cairo_bool_t offscreen;
294     cairo_test_status_t status, result = CAIRO_TEST_UNTESTED;
295     int stride;
296
297     if (! cairo_test_is_target_enabled (ctx, "xlib"))
298         goto CLEANUP_TEST;
299
300     dpy = XOpenDisplay (NULL);
301     if (!dpy) {
302         cairo_test_log (ctx, "xlib-surface: Cannot open display, skipping\n");
303         goto CLEANUP_TEST;
304     }
305
306     if (!check_visual (dpy)) {
307         cairo_test_log (ctx, "xlib-surface: default visual is not RGB24 or BGR24, skipping\n");
308         goto CLEANUP_DISPLAY;
309     }
310
311     stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, SIZE);
312
313     reference_data = xcalloc (ctx, SIZE, stride);
314     test_data = xcalloc (ctx, SIZE, stride);
315     diff_data = xcalloc (ctx, SIZE, stride);
316
317     reference_surface = cairo_image_surface_create_for_data (reference_data,
318                                                              CAIRO_FORMAT_RGB24,
319                                                              SIZE, SIZE,
320                                                              stride);
321
322     draw_pattern (reference_surface);
323     cairo_surface_destroy (reference_surface);
324
325     result = CAIRO_TEST_SUCCESS;
326
327     for (set_size = 0; set_size <= 1; set_size++)
328         for (use_pixmap = 0; use_pixmap <= 1; use_pixmap++)
329             for (offscreen = 0; offscreen <= 1; offscreen++) {
330                 status = do_test (ctx, dpy,
331                                   reference_data, test_data, diff_data,
332                                   use_pixmap, set_size, offscreen);
333                 if (status)
334                     result = status;
335             }
336
337     free (reference_data);
338     free (test_data);
339     free (diff_data);
340
341   CLEANUP_DISPLAY:
342     XCloseDisplay (dpy);
343
344   CLEANUP_TEST:
345     return result;
346 }
347
348 CAIRO_TEST (xlib_surface,
349             "Check creating surfaces for various XWindows",
350             "xlib", /* keywords */
351             NULL, /* requirements */
352             0, 0,
353             preamble, NULL)