1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2002 University of Southern California
4  * Copyright © 2009 Intel Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is University of Southern
32  * California.
33  *
34  * Contributor(s):
35  *	Carl D. Worth <cworth@cworth.org>
36  *	Chris Wilson <chris@chris-wilson.co.uk>
37  */
38 
39 #include "cairoint.h"
40 
41 #include "cairo-xlib.h"
42 #include "cairo-xcb.h"
43 
44 #include "cairo-xcb-private.h"
45 #include "cairo-xlib-xrender-private.h"
46 
47 #include <X11/Xlib-xcb.h>
48 
49 static cairo_surface_t *
50 _cairo_xlib_xcb_surface_create (void *dpy,
51 				void *scr,
52 				void *visual,
53 				void *format,
54 				cairo_surface_t *xcb);
55 
56 static cairo_surface_t *
_cairo_xlib_xcb_surface_create_similar(void * abstract_other,cairo_content_t content,int width,int height)57 _cairo_xlib_xcb_surface_create_similar (void			*abstract_other,
58 					cairo_content_t		 content,
59 					int			 width,
60 					int			 height)
61 {
62     cairo_xlib_xcb_surface_t *other = abstract_other;
63     cairo_surface_t *xcb;
64 
65     xcb = other->xcb->base.backend->create_similar (other->xcb, content, width, height);
66     if (unlikely (xcb == NULL || xcb->status))
67 	return xcb;
68 
69     return _cairo_xlib_xcb_surface_create (other->display, other->screen, NULL, NULL, xcb);
70 }
71 
72 static cairo_status_t
_cairo_xlib_xcb_surface_finish(void * abstract_surface)73 _cairo_xlib_xcb_surface_finish (void *abstract_surface)
74 {
75     cairo_xlib_xcb_surface_t *surface = abstract_surface;
76     cairo_status_t status;
77 
78     cairo_surface_finish (&surface->xcb->base);
79     status = surface->xcb->base.status;
80     cairo_surface_destroy (&surface->xcb->base);
81 
82     return status;
83 }
84 
85 static cairo_status_t
_cairo_xlib_xcb_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)86 _cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface,
87 					      cairo_image_surface_t **image_out,
88 					      void **image_extra)
89 {
90     cairo_xlib_xcb_surface_t *surface = abstract_surface;
91     return _cairo_surface_acquire_source_image (&surface->xcb->base,
92 						image_out, image_extra);
93 }
94 
95 static void
_cairo_xlib_xcb_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image_out,void * image_extra)96 _cairo_xlib_xcb_surface_release_source_image (void *abstract_surface,
97 					      cairo_image_surface_t *image_out,
98 					      void *image_extra)
99 {
100     cairo_xlib_xcb_surface_t *surface = abstract_surface;
101     _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra);
102 }
103 
104 static cairo_bool_t
_cairo_xlib_xcb_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * extents)105 _cairo_xlib_xcb_surface_get_extents (void *abstract_surface,
106 				     cairo_rectangle_int_t *extents)
107 {
108     cairo_xlib_xcb_surface_t *surface = abstract_surface;
109     return _cairo_surface_get_extents (&surface->xcb->base, extents);
110 }
111 
112 static void
_cairo_xlib_xcb_surface_get_font_options(void * abstract_surface,cairo_font_options_t * options)113 _cairo_xlib_xcb_surface_get_font_options (void *abstract_surface,
114 					  cairo_font_options_t *options)
115 {
116     cairo_xlib_xcb_surface_t *surface = abstract_surface;
117     surface->xcb->base.backend->get_font_options (surface->xcb, options);
118 }
119 
120 static cairo_int_status_t
_cairo_xlib_xcb_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)121 _cairo_xlib_xcb_surface_paint (void			*abstract_surface,
122 			       cairo_operator_t		 op,
123 			       const cairo_pattern_t	*source,
124 			       cairo_clip_t		*clip)
125 {
126     cairo_xlib_xcb_surface_t *surface = abstract_surface;
127     return surface->xcb->base.backend->paint (surface->xcb, op, source, clip);
128 }
129 
130 static cairo_int_status_t
_cairo_xlib_xcb_surface_mask(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_pattern_t * mask,cairo_clip_t * clip)131 _cairo_xlib_xcb_surface_mask (void			*abstract_surface,
132 			      cairo_operator_t		 op,
133 			      const cairo_pattern_t	*source,
134 			      const cairo_pattern_t	*mask,
135 			      cairo_clip_t		*clip)
136 {
137     cairo_xlib_xcb_surface_t *surface = abstract_surface;
138     return surface->xcb->base.backend->mask (surface->xcb, op, source, mask, clip);
139 }
140 
141 static cairo_int_status_t
_cairo_xlib_xcb_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)142 _cairo_xlib_xcb_surface_stroke (void				*abstract_surface,
143 				cairo_operator_t		 op,
144 				const cairo_pattern_t		*source,
145 				cairo_path_fixed_t		*path,
146 				const cairo_stroke_style_t	*style,
147 				const cairo_matrix_t		*ctm,
148 				const cairo_matrix_t		*ctm_inverse,
149 				double				 tolerance,
150 				cairo_antialias_t		 antialias,
151 				cairo_clip_t			*clip)
152 {
153     cairo_xlib_xcb_surface_t *surface = abstract_surface;
154     return surface->xcb->base.backend->stroke (surface->xcb,
155 					       op, source, path, style,
156 					       ctm, ctm_inverse,
157 					       tolerance, antialias, clip);
158 }
159 
160 static cairo_int_status_t
_cairo_xlib_xcb_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)161 _cairo_xlib_xcb_surface_fill (void			*abstract_surface,
162 			      cairo_operator_t		 op,
163 			      const cairo_pattern_t	*source,
164 			      cairo_path_fixed_t	*path,
165 			      cairo_fill_rule_t		 fill_rule,
166 			      double			 tolerance,
167 			      cairo_antialias_t		 antialias,
168 			      cairo_clip_t		*clip)
169 {
170     cairo_xlib_xcb_surface_t *surface = abstract_surface;
171     return surface->xcb->base.backend->fill (surface->xcb,
172 					     op, source, path,
173 					     fill_rule, tolerance, antialias,
174 					     clip);
175 }
176 
177 static cairo_int_status_t
_cairo_xlib_xcb_surface_glyphs(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * scaled_font,cairo_clip_t * clip,int * num_remaining)178 _cairo_xlib_xcb_surface_glyphs (void			*abstract_surface,
179 				cairo_operator_t	 op,
180 				const cairo_pattern_t	*source,
181 				cairo_glyph_t		*glyphs,
182 				int			 num_glyphs,
183 				cairo_scaled_font_t	*scaled_font,
184 				cairo_clip_t		*clip,
185 				int *num_remaining)
186 {
187     cairo_xlib_xcb_surface_t *surface = abstract_surface;
188     return surface->xcb->base.backend->show_glyphs (surface->xcb, op, source,
189 						    glyphs, num_glyphs, scaled_font,
190 						    clip, num_remaining);
191 }
192 
193 static cairo_status_t
_cairo_xlib_xcb_surface_flush(void * abstract_surface)194 _cairo_xlib_xcb_surface_flush (void *abstract_surface)
195 {
196     cairo_xlib_xcb_surface_t *surface = abstract_surface;
197     return surface->xcb->base.backend->flush (surface->xcb);
198 }
199 
200 static cairo_status_t
_cairo_xlib_xcb_surface_mark_dirty(void * abstract_surface,int x,int y,int width,int height)201 _cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface,
202 				    int x, int y,
203 				    int width, int height)
204 {
205     cairo_xlib_xcb_surface_t *surface = abstract_surface;
206     return surface->xcb->base.backend->mark_dirty_rectangle (surface->xcb, x, y, width, height);
207 }
208 
209 static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
210     CAIRO_SURFACE_TYPE_XLIB,
211     _cairo_xlib_xcb_surface_create_similar,
212     _cairo_xlib_xcb_surface_finish,
213     _cairo_xlib_xcb_surface_acquire_source_image,
214     _cairo_xlib_xcb_surface_release_source_image,
215     NULL, NULL, NULL, /* dest acquire/release/clone */
216 
217     NULL, /* composite */
218     NULL, /* fill */
219     NULL, /* trapezoids */
220     NULL, /* span */
221     NULL, /* check-span */
222 
223     NULL, /* copy_page */
224     NULL, /* show_page */
225     _cairo_xlib_xcb_surface_get_extents,
226     NULL, /* old-glyphs */
227     _cairo_xlib_xcb_surface_get_font_options,
228 
229     _cairo_xlib_xcb_surface_flush,
230     _cairo_xlib_xcb_surface_mark_dirty,
231     NULL, NULL, /* font/glyph fini */
232 
233     _cairo_xlib_xcb_surface_paint,
234     _cairo_xlib_xcb_surface_mask,
235     _cairo_xlib_xcb_surface_stroke,
236     _cairo_xlib_xcb_surface_fill,
237     _cairo_xlib_xcb_surface_glyphs,
238 };
239 
240 static cairo_surface_t *
_cairo_xlib_xcb_surface_create(void * dpy,void * scr,void * visual,void * format,cairo_surface_t * xcb)241 _cairo_xlib_xcb_surface_create (void *dpy,
242 				void *scr,
243 				void *visual,
244 				void *format,
245 				cairo_surface_t *xcb)
246 {
247     cairo_xlib_xcb_surface_t *surface;
248 
249     if (unlikely (xcb->status))
250 	return xcb;
251 
252     surface = malloc (sizeof (*surface));
253     if (unlikely (surface == NULL)) {
254 	cairo_surface_destroy (xcb);
255 	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
256     }
257 
258     _cairo_surface_init (&surface->base,
259 			 &_cairo_xlib_xcb_surface_backend,
260 			 xcb->device,
261 			 xcb->content);
262 
263     surface->display = dpy;
264     surface->screen = scr;
265     surface->visual = visual;
266     surface->format = format;
267     surface->xcb = (cairo_xcb_surface_t *) xcb;
268 
269     return &surface->base;
270 }
271 
272 static Screen *
_cairo_xlib_screen_from_visual(Display * dpy,Visual * visual)273 _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
274 {
275     int s, d, v;
276 
277     for (s = 0; s < ScreenCount (dpy); s++) {
278 	Screen *screen;
279 
280 	screen = ScreenOfDisplay (dpy, s);
281 	if (visual == DefaultVisualOfScreen (screen))
282 	    return screen;
283 
284 	for (d = 0; d < screen->ndepths; d++) {
285 	    Depth  *depth;
286 
287 	    depth = &screen->depths[d];
288 	    for (v = 0; v < depth->nvisuals; v++)
289 		if (visual == &depth->visuals[v])
290 		    return screen;
291 	}
292     }
293 
294     return NULL;
295 }
296 
297 cairo_surface_t *
cairo_xlib_surface_create(Display * dpy,Drawable drawable,Visual * visual,int width,int height)298 cairo_xlib_surface_create (Display     *dpy,
299 			   Drawable	drawable,
300 			   Visual      *visual,
301 			   int		width,
302 			   int		height)
303 {
304     Screen *scr;
305     xcb_visualtype_t xcb_visual;
306 
307     scr = _cairo_xlib_screen_from_visual (dpy, visual);
308     if (scr == NULL)
309 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
310 
311     xcb_visual.visual_id = visual->visualid;
312 #if defined(__cplusplus) || defined(c_plusplus)
313     xcb_visual._class = visual->c_class;
314 #else
315     xcb_visual._class = visual->class;
316 #endif
317     xcb_visual.bits_per_rgb_value = visual->bits_per_rgb;
318     xcb_visual.colormap_entries = visual->map_entries;
319     xcb_visual.red_mask = visual->red_mask;
320     xcb_visual.green_mask = visual->green_mask;
321     xcb_visual.blue_mask = visual->blue_mask;
322 
323     return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL,
324 					   cairo_xcb_surface_create (XGetXCBConnection (dpy),
325 								     drawable,
326 								     &xcb_visual,
327 								     width, height));
328 }
329 
330 cairo_surface_t *
cairo_xlib_surface_create_for_bitmap(Display * dpy,Pixmap bitmap,Screen * scr,int width,int height)331 cairo_xlib_surface_create_for_bitmap (Display  *dpy,
332 				      Pixmap	bitmap,
333 				      Screen   *scr,
334 				      int	width,
335 				      int	height)
336 {
337     return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL,
338 					   cairo_xcb_surface_create_for_bitmap (XGetXCBConnection (dpy),
339 										(xcb_screen_t *) scr,
340 										bitmap,
341 										width, height));
342 }
343 
344 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
345 static xcb_screen_t *
_cairo_xcb_screen_from_root(xcb_connection_t * connection,xcb_window_t id)346 _cairo_xcb_screen_from_root (xcb_connection_t *connection,
347 			     xcb_window_t id)
348 {
349     xcb_screen_iterator_t s;
350 
351     s = xcb_setup_roots_iterator (xcb_get_setup (connection));
352     for (; s.rem; xcb_screen_next (&s)) {
353 	if (s.data->root == id)
354 	    return s.data;
355     }
356 
357     return NULL;
358 }
359 cairo_surface_t *
cairo_xlib_surface_create_with_xrender_format(Display * dpy,Drawable drawable,Screen * scr,XRenderPictFormat * format,int width,int height)360 cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
361 					       Drawable		    drawable,
362 					       Screen		    *scr,
363 					       XRenderPictFormat    *format,
364 					       int		    width,
365 					       int		    height)
366 {
367     xcb_render_pictforminfo_t xcb_format;
368     xcb_connection_t *connection;
369     xcb_screen_t *screen;
370 
371     xcb_format.id = format->id;
372     xcb_format.type = format->type;
373     xcb_format.depth = format->depth;
374     xcb_format.direct.red_shift = format->direct.red;
375     xcb_format.direct.red_mask = format->direct.redMask;
376     xcb_format.direct.green_shift = format->direct.green;
377     xcb_format.direct.green_mask = format->direct.greenMask;
378     xcb_format.direct.blue_shift = format->direct.blue;
379     xcb_format.direct.blue_mask = format->direct.blueMask;
380     xcb_format.direct.alpha_shift = format->direct.alpha;
381     xcb_format.direct.alpha_mask = format->direct.alphaMask;
382     xcb_format.colormap = format->colormap;
383 
384     connection = XGetXCBConnection (dpy);
385     screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root);
386 
387     return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format,
388 					   cairo_xcb_surface_create_with_xrender_format (connection, screen,
389 											 drawable,
390 											 &xcb_format,
391 											 width, height));
392 }
393 
394 XRenderPictFormat *
cairo_xlib_surface_get_xrender_format(cairo_surface_t * surface)395 cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
396 {
397     cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface;
398 
399     /* Throw an error for a non-xlib surface */
400     if (surface->type != CAIRO_SURFACE_TYPE_XLIB) {
401 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
402 	return NULL;
403     }
404 
405     return xlib_surface->format;
406 }
407 #endif
408 
409 void
cairo_xlib_surface_set_size(cairo_surface_t * abstract_surface,int width,int height)410 cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
411 			     int              width,
412 			     int              height)
413 {
414     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
415     cairo_status_t status;
416 
417     if (unlikely (abstract_surface->status))
418 	return;
419 
420     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
421 	status = _cairo_surface_set_error (abstract_surface,
422 		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
423 	return;
424     }
425 
426     cairo_xcb_surface_set_size (&surface->xcb->base, width, height);
427 }
428 
429 void
cairo_xlib_surface_set_drawable(cairo_surface_t * abstract_surface,Drawable drawable,int width,int height)430 cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
431 				 Drawable	    drawable,
432 				 int		    width,
433 				 int		    height)
434 {
435     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface;
436     cairo_status_t status;
437 
438     if (unlikely (abstract_surface->status))
439 	return;
440 
441     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
442 	status = _cairo_surface_set_error (abstract_surface,
443 		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
444 	return;
445     }
446 
447     ASSERT_NOT_REACHED;
448 }
449 
450 Display *
cairo_xlib_surface_get_display(cairo_surface_t * abstract_surface)451 cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
452 {
453     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
454 
455     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
456 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
457 	return NULL;
458     }
459 
460     return surface->display;
461 }
462 
463 Drawable
cairo_xlib_surface_get_drawable(cairo_surface_t * abstract_surface)464 cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
465 {
466     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
467 
468     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
469 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
470 	return 0;
471     }
472 
473     return surface->xcb->drawable;
474 }
475 
476 Screen *
cairo_xlib_surface_get_screen(cairo_surface_t * abstract_surface)477 cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
478 {
479     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
480 
481     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
482 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
483 	return NULL;
484     }
485 
486     return surface->screen;
487 }
488 
489 Visual *
cairo_xlib_surface_get_visual(cairo_surface_t * abstract_surface)490 cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
491 {
492     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
493 
494     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
495 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
496 	return NULL;
497     }
498 
499     return surface->visual;
500 }
501 
502 int
cairo_xlib_surface_get_depth(cairo_surface_t * abstract_surface)503 cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
504 {
505     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
506 
507     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
508 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
509 	return 0;
510     }
511 
512     return surface->xcb->depth;
513 }
514 
515 int
cairo_xlib_surface_get_width(cairo_surface_t * abstract_surface)516 cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
517 {
518     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
519 
520     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
521 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
522 	return 0;
523     }
524 
525     return surface->xcb->width;
526 }
527 
528 int
cairo_xlib_surface_get_height(cairo_surface_t * abstract_surface)529 cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
530 {
531     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
532 
533     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
534 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
535 	return 0;
536     }
537 
538     return surface->xcb->height;
539 }
540