Changes.
[cairo/gpu.git] / src / cairo-xcb-surface.c
blob733710a5611cf8c286cbaeca30c1f50949220916
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2002 University of Southern California
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is University of Southern
31 * California.
33 * Contributor(s):
34 * Carl D. Worth <cworth@cworth.org>
37 #include "cairoint.h"
38 #include "cairo-xcb.h"
39 #include "cairo-xcb-xrender.h"
40 #include "cairo-clip-private.h"
41 #include <xcb/xcb_renderutil.h>
43 #define AllPlanes ((unsigned long)~0L)
45 slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
48 * Instead of taking two round trips for each blending request,
49 * assume that if a particular drawable fails GetImage that it will
50 * fail for a "while"; use temporary pixmaps to avoid the errors
53 #define CAIRO_ASSUME_PIXMAP 20
55 typedef struct cairo_xcb_surface {
56 cairo_surface_t base;
58 xcb_connection_t *dpy;
59 xcb_screen_t *screen;
61 xcb_gcontext_t gc;
62 xcb_drawable_t drawable;
63 cairo_bool_t owns_pixmap;
64 xcb_visualtype_t *visual;
66 int use_pixmap;
68 int render_major;
69 int render_minor;
71 int width;
72 int height;
73 int depth;
75 cairo_bool_t have_clip_rects;
76 xcb_rectangle_t *clip_rects;
77 int num_clip_rects;
79 xcb_render_picture_t src_picture, dst_picture;
80 xcb_render_pictforminfo_t xrender_format;
81 } cairo_xcb_surface_t;
83 #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
84 (((surface)->render_major > major) || \
85 (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
87 #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
88 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
89 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
91 #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
92 #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
94 #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
95 #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
97 #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
98 #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
99 #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
100 #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
102 #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
103 #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
104 #define CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
105 #define CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
107 static void
108 _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
110 static int
111 _CAIRO_FORMAT_DEPTH (cairo_format_t format)
113 switch (format) {
114 case CAIRO_FORMAT_A1:
115 return 1;
116 case CAIRO_FORMAT_A8:
117 return 8;
118 case CAIRO_FORMAT_RGB24:
119 return 24;
120 case CAIRO_FORMAT_ARGB32:
121 default:
122 return 32;
126 static xcb_render_pictforminfo_t *
127 _CAIRO_FORMAT_TO_XRENDER_FORMAT(xcb_connection_t *dpy, cairo_format_t format)
129 xcb_pict_standard_t std_format;
130 switch (format) {
131 case CAIRO_FORMAT_A1:
132 std_format = XCB_PICT_STANDARD_A_1; break;
133 case CAIRO_FORMAT_A8:
134 std_format = XCB_PICT_STANDARD_A_8; break;
135 case CAIRO_FORMAT_RGB24:
136 std_format = XCB_PICT_STANDARD_RGB_24; break;
137 case CAIRO_FORMAT_ARGB32:
138 default:
139 std_format = XCB_PICT_STANDARD_ARGB_32; break;
141 return xcb_render_util_find_standard_format (xcb_render_util_query_formats (dpy), std_format);
144 static cairo_content_t
145 _xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format)
147 cairo_bool_t xrender_format_has_alpha;
148 cairo_bool_t xrender_format_has_color;
150 /* This only happens when using a non-Render server. Let's punt
151 * and say there's no alpha here. */
152 if (xrender_format == NULL)
153 return CAIRO_CONTENT_COLOR;
155 xrender_format_has_alpha = (xrender_format->direct.alpha_mask != 0);
156 xrender_format_has_color = (xrender_format->direct.red_mask != 0 ||
157 xrender_format->direct.green_mask != 0 ||
158 xrender_format->direct.blue_mask != 0);
160 if (xrender_format_has_alpha)
161 if (xrender_format_has_color)
162 return CAIRO_CONTENT_COLOR_ALPHA;
163 else
164 return CAIRO_CONTENT_ALPHA;
165 else
166 return CAIRO_CONTENT_COLOR;
169 static cairo_surface_t *
170 _cairo_xcb_surface_create_similar (void *abstract_src,
171 cairo_content_t content,
172 int width,
173 int height)
175 cairo_xcb_surface_t *src = abstract_src;
176 xcb_connection_t *dpy = src->dpy;
177 xcb_pixmap_t pixmap;
178 cairo_xcb_surface_t *surface;
179 cairo_format_t format = _cairo_format_from_content (content);
180 xcb_render_pictforminfo_t *xrender_format;
182 /* As a good first approximation, if the display doesn't have COMPOSITE,
183 * we're better off using image surfaces for all temporary operations
185 if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
186 return cairo_image_surface_create (format, width, height);
189 pixmap = xcb_generate_id (dpy);
190 xcb_create_pixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
191 pixmap, src->drawable,
192 width <= 0 ? 1 : width,
193 height <= 0 ? 1 : height);
195 xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, format);
196 /* XXX: what to do if xrender_format is null? */
197 surface = (cairo_xcb_surface_t *)
198 cairo_xcb_surface_create_with_xrender_format (dpy, pixmap, src->screen,
199 xrender_format,
200 width, height);
201 if (surface->base.status)
202 return &surface->base;
204 surface->owns_pixmap = TRUE;
206 return &surface->base;
209 static cairo_status_t
210 _cairo_xcb_surface_finish (void *abstract_surface)
212 cairo_xcb_surface_t *surface = abstract_surface;
213 if (surface->dst_picture != XCB_NONE)
214 xcb_render_free_picture (surface->dpy, surface->dst_picture);
216 if (surface->src_picture != XCB_NONE)
217 xcb_render_free_picture (surface->dpy, surface->src_picture);
219 if (surface->owns_pixmap)
220 xcb_free_pixmap (surface->dpy, surface->drawable);
222 if (surface->gc != XCB_NONE)
223 xcb_free_gc (surface->dpy, surface->gc);
225 free (surface->clip_rects);
227 surface->dpy = NULL;
229 return CAIRO_STATUS_SUCCESS;
232 static int
233 _bits_per_pixel(xcb_connection_t *c, int depth)
235 xcb_format_t *fmt = xcb_setup_pixmap_formats(xcb_get_setup(c));
236 xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(xcb_get_setup(c));
238 for(; fmt != fmtend; ++fmt)
239 if(fmt->depth == depth)
240 return fmt->bits_per_pixel;
242 if(depth <= 4)
243 return 4;
244 if(depth <= 8)
245 return 8;
246 if(depth <= 16)
247 return 16;
248 return 32;
251 static int
252 _bytes_per_line(xcb_connection_t *c, int width, int bpp)
254 int bitmap_pad = xcb_get_setup(c)->bitmap_format_scanline_pad;
255 return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
258 static cairo_bool_t
259 _CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
261 switch (masks->bpp) {
262 case 32:
263 if (masks->alpha_mask == 0xff000000 &&
264 masks->red_mask == 0x00ff0000 &&
265 masks->green_mask == 0x0000ff00 &&
266 masks->blue_mask == 0x000000ff)
268 *format = CAIRO_FORMAT_ARGB32;
269 return TRUE;
271 if (masks->alpha_mask == 0x00000000 &&
272 masks->red_mask == 0x00ff0000 &&
273 masks->green_mask == 0x0000ff00 &&
274 masks->blue_mask == 0x000000ff)
276 *format = CAIRO_FORMAT_RGB24;
277 return TRUE;
279 break;
280 case 8:
281 if (masks->alpha_mask == 0xff)
283 *format = CAIRO_FORMAT_A8;
284 return TRUE;
286 break;
287 case 1:
288 if (masks->alpha_mask == 0x1)
290 *format = CAIRO_FORMAT_A1;
291 return TRUE;
293 break;
295 return FALSE;
298 static cairo_status_t
299 _get_image_surface (cairo_xcb_surface_t *surface,
300 cairo_rectangle_int_t *interest_rect,
301 cairo_image_surface_t **image_out,
302 cairo_rectangle_int_t *image_rect)
304 cairo_image_surface_t *image;
305 xcb_get_image_reply_t *imagerep;
306 int bpp, bytes_per_line;
307 cairo_rectangle_int_t extents;
308 unsigned char *data;
309 cairo_format_masks_t masks;
310 cairo_format_t format;
312 extents.x = 0;
313 extents.y = 0;
314 extents.width = surface->width;
315 extents.height = surface->height;
317 if (interest_rect) {
318 if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
319 *image_out = NULL;
320 return CAIRO_STATUS_SUCCESS;
324 if (image_rect)
325 *image_rect = extents;
327 /* XXX: This should try to use the XShm extension if available */
329 if (surface->use_pixmap == 0)
331 xcb_generic_error_t *error;
332 imagerep = xcb_get_image_reply(surface->dpy,
333 xcb_get_image(surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
334 surface->drawable,
335 extents.x, extents.y,
336 extents.width, extents.height,
337 AllPlanes), &error);
339 /* If we get an error, the surface must have been a window,
340 * so retry with the safe code path.
342 if (error)
343 surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
345 else
347 surface->use_pixmap--;
348 imagerep = NULL;
351 if (!imagerep)
353 /* xcb_get_image_t from a window is dangerous because it can
354 * produce errors if the window is unmapped or partially
355 * outside the screen. We could check for errors and
356 * retry, but to keep things simple, we just create a
357 * temporary pixmap
359 xcb_pixmap_t pixmap;
360 pixmap = xcb_generate_id (surface->dpy);
361 xcb_create_pixmap (surface->dpy,
362 surface->depth,
363 pixmap,
364 surface->drawable,
365 extents.width, extents.height);
366 _cairo_xcb_surface_ensure_gc (surface);
368 xcb_copy_area (surface->dpy, surface->drawable, pixmap, surface->gc,
369 extents.x, extents.y, 0, 0, extents.width, extents.height);
371 imagerep = xcb_get_image_reply(surface->dpy,
372 xcb_get_image(surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
373 pixmap,
374 extents.x, extents.y,
375 extents.width, extents.height,
376 AllPlanes), 0);
377 xcb_free_pixmap (surface->dpy, pixmap);
380 if (!imagerep)
381 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
383 bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
384 bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
386 data = _cairo_malloc_ab (surface->height, bytes_per_line);
387 if (data == NULL) {
388 free (imagerep);
389 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
392 memcpy (data, xcb_get_image_data (imagerep), bytes_per_line * surface->height);
393 free (imagerep);
396 * Compute the pixel format masks from either an xcb_visualtype_t or
397 * a xcb_render_pctforminfo_t, failing we assume the drawable is an
398 * alpha-only pixmap as it could only have been created that way
399 * through the cairo_xlib_surface_create_for_bitmap function.
401 if (surface->visual) {
402 masks.bpp = bpp;
403 masks.alpha_mask = 0;
404 masks.red_mask = surface->visual->red_mask;
405 masks.green_mask = surface->visual->green_mask;
406 masks.blue_mask = surface->visual->blue_mask;
407 } else if (surface->xrender_format.id != XCB_NONE) {
408 masks.bpp = bpp;
409 masks.red_mask = (unsigned long)surface->xrender_format.direct.red_mask << surface->xrender_format.direct.red_shift;
410 masks.green_mask = (unsigned long)surface->xrender_format.direct.green_mask << surface->xrender_format.direct.green_shift;
411 masks.blue_mask = (unsigned long)surface->xrender_format.direct.blue_mask << surface->xrender_format.direct.blue_shift;
412 masks.alpha_mask = (unsigned long)surface->xrender_format.direct.alpha_mask << surface->xrender_format.direct.alpha_shift;
413 } else {
414 masks.bpp = bpp;
415 masks.red_mask = 0;
416 masks.green_mask = 0;
417 masks.blue_mask = 0;
418 if (surface->depth < 32)
419 masks.alpha_mask = (1 << surface->depth) - 1;
420 else
421 masks.alpha_mask = 0xffffffff;
425 * Prefer to use a standard pixman format instead of the
426 * general masks case.
428 if (_CAIRO_MASK_FORMAT (&masks, &format)) {
429 image = (cairo_image_surface_t *)
430 cairo_image_surface_create_for_data (data,
431 format,
432 extents.width,
433 extents.height,
434 bytes_per_line);
435 if (image->base.status)
436 goto FAIL;
437 } else {
439 * XXX This can't work. We must convert the data to one of the
440 * supported pixman formats. Pixman needs another function
441 * which takes data in an arbitrary format and converts it
442 * to something supported by that library.
444 image = (cairo_image_surface_t *)
445 cairo_image_surface_create_with_masks (data,
446 &masks,
447 extents.width,
448 extents.height,
449 bytes_per_line);
450 if (image->base.status)
451 goto FAIL;
454 /* Let the surface take ownership of the data */
455 _cairo_image_surface_assume_ownership_of_data (image);
457 *image_out = image;
458 return CAIRO_STATUS_SUCCESS;
460 FAIL:
461 free (data);
462 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
465 static void
466 _cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface)
468 if (!surface->src_picture) {
469 surface->src_picture = xcb_generate_id(surface->dpy);
470 xcb_render_create_picture (surface->dpy,
471 surface->src_picture,
472 surface->drawable,
473 surface->xrender_format.id,
474 0, NULL);
478 static void
479 _cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
481 if (surface->have_clip_rects)
482 xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture,
483 0, 0,
484 surface->num_clip_rects,
485 surface->clip_rects);
488 static void
489 _cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
491 if (surface->have_clip_rects)
492 xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
493 0, 0,
494 surface->num_clip_rects,
495 surface->clip_rects );
498 static void
499 _cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface)
501 if (!surface->dst_picture) {
502 surface->dst_picture = xcb_generate_id(surface->dpy);
503 xcb_render_create_picture (surface->dpy,
504 surface->dst_picture,
505 surface->drawable,
506 surface->xrender_format.id,
507 0, NULL);
508 _cairo_xcb_surface_set_picture_clip_rects (surface);
513 static void
514 _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
516 if (surface->gc)
517 return;
519 surface->gc = xcb_generate_id(surface->dpy);
520 xcb_create_gc (surface->dpy, surface->gc, surface->drawable, 0, 0);
521 _cairo_xcb_surface_set_gc_clip_rects(surface);
524 static cairo_status_t
525 _draw_image_surface (cairo_xcb_surface_t *surface,
526 cairo_image_surface_t *image,
527 int src_x,
528 int src_y,
529 int width,
530 int height,
531 int dst_x,
532 int dst_y)
534 int bpp, bpl;
535 uint32_t data_len;
536 uint8_t *data, left_pad=0;
538 /* equivalent of XPutImage(..., src_x,src_y, dst_x,dst_y, width,height); */
539 /* XXX: assumes image and surface formats and depths are the same */
540 /* XXX: assumes depth is a multiple of 8 (not bitmap) */
542 /* fit src_{x,y,width,height} within image->{0,0,width,height} */
543 if (src_x < 0) {
544 width += src_x;
545 src_x = 0;
547 if (src_y < 0) {
548 height += src_y;
549 src_y = 0;
551 if (width + src_x > image->width)
552 width = image->width - src_x;
553 if (height + src_y > image->height)
554 height = image->height - src_y;
555 if (width <= 0 || height <= 0)
556 return CAIRO_STATUS_SUCCESS;
558 bpp = _bits_per_pixel(surface->dpy, image->depth);
559 /* XXX: could use bpl = image->stride? */
560 bpl = _bytes_per_line(surface->dpy, image->width, bpp);
562 if (src_x == 0 && width == image->width) {
563 /* can work in-place */
564 data_len = height * bpl;
565 data = image->data + src_y * bpl;
566 } else {
567 /* must copy {src_x,src_y,width,height} into new data */
568 int line = 0;
569 uint8_t *data_line, *image_line;
570 int data_bpl = _bytes_per_line(surface->dpy, width, bpp);
571 data_len = height * data_bpl;
572 data_line = data = malloc(data_len);
573 if (data == NULL)
574 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
576 image_line = image->data + src_y * bpl + (src_x * bpp / 8);
577 while (line++ < height) {
578 memcpy(data_line, image_line, data_bpl);
579 data_line += data_bpl;
580 image_line += bpl;
583 _cairo_xcb_surface_ensure_gc (surface);
584 xcb_put_image (surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
585 surface->drawable, surface->gc,
586 width, height,
587 dst_x, dst_y,
588 left_pad, image->depth,
589 data_len, data);
591 if (data < image->data || data >= image->data + image->height * bpl)
592 free(data);
594 return CAIRO_STATUS_SUCCESS;
597 static cairo_status_t
598 _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
599 cairo_image_surface_t **image_out,
600 void **image_extra)
602 cairo_xcb_surface_t *surface = abstract_surface;
603 cairo_image_surface_t *image;
604 cairo_status_t status;
606 status = _get_image_surface (surface, NULL, &image, NULL);
607 if (status)
608 return status;
610 *image_out = image;
611 *image_extra = NULL;
613 return CAIRO_STATUS_SUCCESS;
616 static cairo_surface_t *
617 _cairo_xcb_surface_snapshot (void *abstract_surface)
619 cairo_xcb_surface_t *surface = abstract_surface;
620 cairo_image_surface_t *image;
621 cairo_status_t status;
623 status = _get_image_surface (surface, NULL, &image, NULL);
624 if (unlikely (status))
625 return _cairo_surface_create_in_error (status);
627 return &image->base;
630 static void
631 _cairo_xcb_surface_release_source_image (void *abstract_surface,
632 cairo_image_surface_t *image,
633 void *image_extra)
635 cairo_surface_destroy (&image->base);
638 static cairo_status_t
639 _cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
640 cairo_rectangle_int_t *interest_rect,
641 cairo_image_surface_t **image_out,
642 cairo_rectangle_int_t *image_rect_out,
643 void **image_extra)
645 cairo_xcb_surface_t *surface = abstract_surface;
646 cairo_image_surface_t *image;
647 cairo_status_t status;
649 status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
650 if (status)
651 return status;
653 *image_out = image;
654 *image_extra = NULL;
656 return CAIRO_STATUS_SUCCESS;
659 static void
660 _cairo_xcb_surface_release_dest_image (void *abstract_surface,
661 cairo_rectangle_int_t *interest_rect,
662 cairo_image_surface_t *image,
663 cairo_rectangle_int_t *image_rect,
664 void *image_extra)
666 cairo_xcb_surface_t *surface = abstract_surface;
668 /* ignore errors */
669 _draw_image_surface (surface, image, 0, 0, image->width, image->height,
670 image_rect->x, image_rect->y);
672 cairo_surface_destroy (&image->base);
676 * Return whether two xcb surfaces share the same
677 * screen. Both core and Render drawing require this
678 * when using multiple drawables in an operation.
680 static cairo_bool_t
681 _cairo_xcb_surface_same_screen (cairo_xcb_surface_t *dst,
682 cairo_xcb_surface_t *src)
684 return dst->dpy == src->dpy && dst->screen == src->screen;
687 static cairo_status_t
688 _cairo_xcb_surface_clone_similar (void *abstract_surface,
689 cairo_surface_t *src,
690 cairo_content_t content,
691 int src_x,
692 int src_y,
693 int width,
694 int height,
695 int *clone_offset_x,
696 int *clone_offset_y,
697 cairo_surface_t **clone_out)
699 cairo_xcb_surface_t *surface = abstract_surface;
700 cairo_xcb_surface_t *clone;
702 if (src->backend == surface->base.backend ) {
703 cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
705 if (_cairo_xcb_surface_same_screen(surface, xcb_src)) {
706 *clone_offset_x = 0;
707 *clone_offset_y = 0;
708 *clone_out = cairo_surface_reference (src);
710 return CAIRO_STATUS_SUCCESS;
712 } else if (_cairo_surface_is_image (src)) {
713 cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
714 cairo_content_t content = _cairo_content_from_format (image_src->format);
715 cairo_status_t status;
717 if (surface->base.status)
718 return surface->base.status;
720 clone = (cairo_xcb_surface_t *)
721 _cairo_xcb_surface_create_similar (surface, content, width, height);
722 if (clone == NULL)
723 return CAIRO_INT_STATUS_UNSUPPORTED;
724 if (clone->base.status)
725 return clone->base.status;
727 status = _draw_image_surface (clone, image_src,
728 src_x, src_y,
729 width, height,
730 0, 0);
731 if (status) {
732 cairo_surface_destroy (&clone->base);
733 return status;
736 *clone_offset_x = src_x;
737 *clone_offset_y = src_y;
738 *clone_out = &clone->base;
740 return CAIRO_STATUS_SUCCESS;
743 return CAIRO_INT_STATUS_UNSUPPORTED;
746 static cairo_status_t
747 _cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
748 cairo_matrix_t *matrix)
750 xcb_render_transform_t xtransform;
752 if (!surface->src_picture)
753 return CAIRO_STATUS_SUCCESS;
755 xtransform.matrix11 = _cairo_fixed_16_16_from_double (matrix->xx);
756 xtransform.matrix12 = _cairo_fixed_16_16_from_double (matrix->xy);
757 xtransform.matrix13 = _cairo_fixed_16_16_from_double (matrix->x0);
759 xtransform.matrix21 = _cairo_fixed_16_16_from_double (matrix->yx);
760 xtransform.matrix22 = _cairo_fixed_16_16_from_double (matrix->yy);
761 xtransform.matrix23 = _cairo_fixed_16_16_from_double (matrix->y0);
763 xtransform.matrix31 = 0;
764 xtransform.matrix32 = 0;
765 xtransform.matrix33 = 1 << 16;
767 if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
769 static const xcb_render_transform_t identity = {
770 1 << 16, 0x00000, 0x00000,
771 0x00000, 1 << 16, 0x00000,
772 0x00000, 0x00000, 1 << 16
775 if (memcmp (&xtransform, &identity, sizeof (xcb_render_transform_t)) == 0)
776 return CAIRO_STATUS_SUCCESS;
778 return CAIRO_INT_STATUS_UNSUPPORTED;
781 xcb_render_set_picture_transform (surface->dpy, surface->src_picture, xtransform);
783 return CAIRO_STATUS_SUCCESS;
786 static cairo_status_t
787 _cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
788 cairo_filter_t filter)
790 const char *render_filter;
792 if (!surface->src_picture)
793 return CAIRO_STATUS_SUCCESS;
795 if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
797 if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
798 return CAIRO_STATUS_SUCCESS;
800 return CAIRO_INT_STATUS_UNSUPPORTED;
803 switch (filter) {
804 case CAIRO_FILTER_FAST:
805 render_filter = "fast";
806 break;
807 case CAIRO_FILTER_GOOD:
808 render_filter = "good";
809 break;
810 case CAIRO_FILTER_BEST:
811 render_filter = "best";
812 break;
813 case CAIRO_FILTER_NEAREST:
814 render_filter = "nearest";
815 break;
816 case CAIRO_FILTER_BILINEAR:
817 render_filter = "bilinear";
818 break;
819 case CAIRO_FILTER_GAUSSIAN:
820 default:
821 render_filter = "best";
822 break;
825 xcb_render_set_picture_filter(surface->dpy, surface->src_picture,
826 strlen(render_filter), render_filter, 0, NULL);
828 return CAIRO_STATUS_SUCCESS;
831 static cairo_status_t
832 _cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
834 uint32_t mask = XCB_RENDER_CP_REPEAT;
835 uint32_t pa[] = { repeat };
837 if (!surface->src_picture)
838 return CAIRO_STATUS_SUCCESS;
840 xcb_render_change_picture (surface->dpy, surface->src_picture, mask, pa);
842 return CAIRO_STATUS_SUCCESS;
845 static cairo_int_status_t
846 _cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
847 cairo_surface_attributes_t *attributes)
849 cairo_int_status_t status;
851 _cairo_xcb_surface_ensure_src_picture (surface);
853 status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
854 if (status)
855 return status;
857 switch (attributes->extend) {
858 case CAIRO_EXTEND_NONE:
859 _cairo_xcb_surface_set_repeat (surface, XCB_RENDER_REPEAT_NONE);
860 break;
861 case CAIRO_EXTEND_REPEAT:
862 _cairo_xcb_surface_set_repeat (surface, XCB_RENDER_REPEAT_NORMAL);
863 break;
864 case CAIRO_EXTEND_REFLECT:
865 if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface))
866 return CAIRO_INT_STATUS_UNSUPPORTED;
867 _cairo_xcb_surface_set_repeat (surface, XCB_RENDER_REPEAT_REFLECT);
868 break;
869 case CAIRO_EXTEND_PAD:
870 if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface))
871 return CAIRO_INT_STATUS_UNSUPPORTED;
872 _cairo_xcb_surface_set_repeat (surface, XCB_RENDER_REPEAT_PAD);
873 break;
874 default:
875 return CAIRO_INT_STATUS_UNSUPPORTED;
878 status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
879 if (status)
880 return status;
882 return CAIRO_STATUS_SUCCESS;
885 /* Checks whether we can can directly draw from src to dst with
886 * the core protocol: either with CopyArea or using src as a
887 * a tile in a GC.
889 static cairo_bool_t
890 _surfaces_compatible (cairo_xcb_surface_t *dst,
891 cairo_xcb_surface_t *src)
893 /* same screen */
894 if (!_cairo_xcb_surface_same_screen (dst, src))
895 return FALSE;
897 /* same depth (for core) */
898 if (src->depth != dst->depth)
899 return FALSE;
901 /* if Render is supported, match picture formats */
902 if (src->xrender_format.id != dst->xrender_format.id)
903 return FALSE;
904 else if (src->xrender_format.id != XCB_NONE)
905 return TRUE;
907 /* Without Render, match visuals instead */
908 if (src->visual == dst->visual)
909 return TRUE;
911 return FALSE;
914 static cairo_bool_t
915 _surface_has_alpha (cairo_xcb_surface_t *surface)
917 if (surface->xrender_format.id != XCB_NONE) {
918 if (surface->xrender_format.type == XCB_RENDER_PICT_TYPE_DIRECT &&
919 surface->xrender_format.direct.alpha_mask != 0)
920 return TRUE;
921 else
922 return FALSE;
923 } else {
925 /* In the no-render case, we never have alpha */
926 return FALSE;
930 /* Returns true if the given operator and source-alpha combination
931 * requires alpha compositing to complete.
933 static cairo_bool_t
934 _operator_needs_alpha_composite (cairo_operator_t op,
935 cairo_bool_t surface_has_alpha)
937 if (op == CAIRO_OPERATOR_SOURCE ||
938 (!surface_has_alpha &&
939 (op == CAIRO_OPERATOR_OVER ||
940 op == CAIRO_OPERATOR_ATOP ||
941 op == CAIRO_OPERATOR_IN)))
942 return FALSE;
944 return TRUE;
947 /* There is a bug in most older X servers with compositing using a
948 * untransformed repeating source pattern when the source is in off-screen
949 * video memory, and another with repeated transformed images using a
950 * general transform matrix. When these bugs could be triggered, we need a
951 * fallback: in the common case where we have no transformation and the
952 * source and destination have the same format/visual, we can do the
953 * operation using the core protocol for the first bug, otherwise, we need
954 * a software fallback.
956 * We can also often optimize a compositing operation by calling XCopyArea
957 * for some common cases where there is no alpha compositing to be done.
958 * We figure that out here as well.
960 typedef enum {
961 DO_RENDER, /* use render */
962 DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */
963 DO_XTILE, /* core protocol XSetTile optimization/fallback */
964 DO_UNSUPPORTED /* software fallback */
965 } composite_operation_t;
967 /* Initial check for the render bugs; we need to recheck for the
968 * offscreen-memory bug after we turn patterns into surfaces, since that
969 * may introduce a repeating pattern for gradient patterns. We don't need
970 * to check for the repeat+transform bug because gradient surfaces aren't
971 * transformed.
973 * All we do here is reject cases where we *know* are going to
974 * hit the bug and won't be able to use a core protocol fallback.
976 static composite_operation_t
977 _categorize_composite_operation (cairo_xcb_surface_t *dst,
978 cairo_operator_t op,
979 const cairo_pattern_t *src_pattern,
980 cairo_bool_t have_mask)
983 #if XXX_BUGGY_REPEAT
984 if (!dst->buggy_repeat)
985 return DO_RENDER;
987 if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
989 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
991 if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
992 src_pattern->extend == CAIRO_EXTEND_REPEAT)
994 /* This is the case where we have the bug involving
995 * untransformed repeating source patterns with off-screen
996 * video memory; reject some cases where a core protocol
997 * fallback is impossible.
999 if (have_mask ||
1000 !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
1001 return DO_UNSUPPORTED;
1003 if (_cairo_surface_is_xcb (surface_pattern->surface)) {
1004 cairo_xcb_surface_t *src = (cairo_xcb_surface_t *)surface_pattern->surface;
1006 if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
1007 return DO_UNSUPPORTED;
1009 /* If these are on the same screen but otherwise incompatible,
1010 * make a copy as core drawing can't cross depths and doesn't
1011 * work rightacross visuals of the same depth
1013 if (_cairo_xcb_surface_same_screen (dst, src) &&
1014 !_surfaces_compatible (dst, src))
1015 return DO_UNSUPPORTED;
1019 /* Check for the other bug involving repeat patterns with general
1020 * transforms. */
1021 if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
1022 src_pattern->extend == CAIRO_EXTEND_REPEAT)
1023 return DO_UNSUPPORTED;
1025 #endif
1026 return DO_RENDER;
1029 /* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
1030 * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
1031 * did to turn gradients into a pattern, but most of the time we can handle
1032 * that case with core protocol fallback.
1034 * Also check here if we can just use XCopyArea, instead of going through
1035 * Render.
1037 static composite_operation_t
1038 _recategorize_composite_operation (cairo_xcb_surface_t *dst,
1039 cairo_operator_t op,
1040 cairo_xcb_surface_t *src,
1041 cairo_surface_attributes_t *src_attr,
1042 cairo_bool_t have_mask)
1044 cairo_bool_t is_integer_translation =
1045 _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
1046 cairo_bool_t needs_alpha_composite =
1047 _operator_needs_alpha_composite (op, _surface_has_alpha (src));
1049 if (!have_mask &&
1050 is_integer_translation &&
1051 src_attr->extend == CAIRO_EXTEND_NONE &&
1052 !needs_alpha_composite &&
1053 _surfaces_compatible(src, dst))
1055 return DO_XCOPYAREA;
1057 #if XXX_BUGGY_REPEAT
1058 if (!dst->buggy_repeat)
1059 return DO_RENDER;
1061 if (is_integer_translation &&
1062 src_attr->extend == CAIRO_EXTEND_REPEAT &&
1063 (src->width != 1 || src->height != 1))
1065 if (!have_mask &&
1066 !needs_alpha_composite &&
1067 _surfaces_compatible (dst, src))
1069 return DO_XTILE;
1072 return DO_UNSUPPORTED;
1074 #endif
1075 return DO_RENDER;
1078 static int
1079 _render_operator (cairo_operator_t op)
1081 switch (op) {
1082 case CAIRO_OPERATOR_CLEAR:
1083 return XCB_RENDER_PICT_OP_CLEAR;
1084 case CAIRO_OPERATOR_SOURCE:
1085 return XCB_RENDER_PICT_OP_SRC;
1086 case CAIRO_OPERATOR_DEST:
1087 return XCB_RENDER_PICT_OP_DST;
1088 case CAIRO_OPERATOR_OVER:
1089 return XCB_RENDER_PICT_OP_OVER;
1090 case CAIRO_OPERATOR_DEST_OVER:
1091 return XCB_RENDER_PICT_OP_OVER_REVERSE;
1092 case CAIRO_OPERATOR_IN:
1093 return XCB_RENDER_PICT_OP_IN;
1094 case CAIRO_OPERATOR_DEST_IN:
1095 return XCB_RENDER_PICT_OP_IN_REVERSE;
1096 case CAIRO_OPERATOR_OUT:
1097 return XCB_RENDER_PICT_OP_OUT;
1098 case CAIRO_OPERATOR_DEST_OUT:
1099 return XCB_RENDER_PICT_OP_OUT_REVERSE;
1100 case CAIRO_OPERATOR_ATOP:
1101 return XCB_RENDER_PICT_OP_ATOP;
1102 case CAIRO_OPERATOR_DEST_ATOP:
1103 return XCB_RENDER_PICT_OP_ATOP_REVERSE;
1104 case CAIRO_OPERATOR_XOR:
1105 return XCB_RENDER_PICT_OP_XOR;
1106 case CAIRO_OPERATOR_ADD:
1107 return XCB_RENDER_PICT_OP_ADD;
1108 case CAIRO_OPERATOR_SATURATE:
1109 return XCB_RENDER_PICT_OP_SATURATE;
1110 default:
1111 return XCB_RENDER_PICT_OP_OVER;
1115 static cairo_int_status_t
1116 _cairo_xcb_surface_composite (cairo_operator_t op,
1117 const cairo_pattern_t *src_pattern,
1118 const cairo_pattern_t *mask_pattern,
1119 void *abstract_dst,
1120 int src_x,
1121 int src_y,
1122 int mask_x,
1123 int mask_y,
1124 int dst_x,
1125 int dst_y,
1126 unsigned int width,
1127 unsigned int height)
1129 cairo_surface_attributes_t src_attr, mask_attr;
1130 cairo_xcb_surface_t *dst = abstract_dst;
1131 cairo_xcb_surface_t *src;
1132 cairo_xcb_surface_t *mask;
1133 cairo_int_status_t status;
1134 composite_operation_t operation;
1135 int itx, ity;
1136 cairo_bool_t is_integer_translation;
1138 if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
1139 return CAIRO_INT_STATUS_UNSUPPORTED;
1141 operation = _categorize_composite_operation (dst, op, src_pattern,
1142 mask_pattern != NULL);
1143 if (operation == DO_UNSUPPORTED)
1144 return CAIRO_INT_STATUS_UNSUPPORTED;
1146 status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
1147 &dst->base,
1148 CAIRO_CONTENT_COLOR_ALPHA,
1149 src_x, src_y,
1150 mask_x, mask_y,
1151 width, height,
1152 CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
1153 (cairo_surface_t **) &src,
1154 (cairo_surface_t **) &mask,
1155 &src_attr, &mask_attr);
1156 if (status)
1157 return status;
1159 operation = _recategorize_composite_operation (dst, op, src, &src_attr,
1160 mask_pattern != NULL);
1161 if (operation == DO_UNSUPPORTED) {
1162 status = CAIRO_INT_STATUS_UNSUPPORTED;
1163 goto BAIL;
1166 status = _cairo_xcb_surface_set_attributes (src, &src_attr);
1167 if (status)
1168 goto BAIL;
1170 switch (operation)
1172 case DO_RENDER:
1173 _cairo_xcb_surface_ensure_dst_picture (dst);
1174 if (mask) {
1175 status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
1176 if (status)
1177 goto BAIL;
1179 xcb_render_composite (dst->dpy,
1180 _render_operator (op),
1181 src->src_picture,
1182 mask->src_picture,
1183 dst->dst_picture,
1184 src_x + src_attr.x_offset,
1185 src_y + src_attr.y_offset,
1186 mask_x + mask_attr.x_offset,
1187 mask_y + mask_attr.y_offset,
1188 dst_x, dst_y,
1189 width, height);
1190 } else {
1191 static xcb_render_picture_t maskpict = { XCB_NONE };
1193 xcb_render_composite (dst->dpy,
1194 _render_operator (op),
1195 src->src_picture,
1196 maskpict,
1197 dst->dst_picture,
1198 src_x + src_attr.x_offset,
1199 src_y + src_attr.y_offset,
1200 0, 0,
1201 dst_x, dst_y,
1202 width, height);
1204 break;
1206 case DO_XCOPYAREA:
1207 _cairo_xcb_surface_ensure_gc (dst);
1208 xcb_copy_area (dst->dpy,
1209 src->drawable,
1210 dst->drawable,
1211 dst->gc,
1212 src_x + src_attr.x_offset,
1213 src_y + src_attr.y_offset,
1214 dst_x, dst_y,
1215 width, height);
1216 break;
1218 case DO_XTILE:
1219 /* This case is only used for bug fallbacks, though it is theoretically
1220 * applicable to the case where we don't have the RENDER extension as
1221 * well.
1223 * We've checked that we have a repeating unscaled source in
1224 * _recategorize_composite_operation.
1227 _cairo_xcb_surface_ensure_gc (dst);
1228 is_integer_translation =
1229 _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
1230 assert (is_integer_translation == TRUE);
1232 uint32_t mask = XCB_GC_FILL_STYLE | XCB_GC_TILE
1233 | XCB_GC_TILE_STIPPLE_ORIGIN_X
1234 | XCB_GC_TILE_STIPPLE_ORIGIN_Y;
1235 uint32_t values[] = {
1236 XCB_FILL_STYLE_TILED, src->drawable,
1237 - (itx + src_attr.x_offset),
1238 - (ity + src_attr.y_offset)
1240 xcb_rectangle_t rect = { dst_x, dst_y, width, height };
1242 xcb_change_gc( dst->dpy, dst->gc, mask, values );
1243 xcb_poly_fill_rectangle(dst->dpy, dst->drawable, dst->gc, 1, &rect);
1245 break;
1247 case DO_UNSUPPORTED:
1248 default:
1249 ASSERT_NOT_REACHED;
1252 if (!_cairo_operator_bounded_by_source (op))
1253 status = _cairo_surface_composite_fixup_unbounded (&dst->base,
1254 &src_attr, src->width, src->height,
1255 mask ? &mask_attr : NULL,
1256 mask ? mask->width : 0,
1257 mask ? mask->height : 0,
1258 src_x, src_y,
1259 mask_x, mask_y,
1260 dst_x, dst_y, width, height);
1262 BAIL:
1263 if (mask)
1264 _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
1266 _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
1268 return status;
1271 static cairo_int_status_t
1272 _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
1273 cairo_operator_t op,
1274 const cairo_color_t * color,
1275 cairo_rectangle_int_t *rects,
1276 int num_rects)
1278 cairo_xcb_surface_t *surface = abstract_surface;
1279 xcb_render_color_t render_color;
1280 xcb_rectangle_t static_xrects[16];
1281 xcb_rectangle_t *xrects = static_xrects;
1282 int i;
1284 if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
1285 return CAIRO_INT_STATUS_UNSUPPORTED;
1287 render_color.red = color->red_short;
1288 render_color.green = color->green_short;
1289 render_color.blue = color->blue_short;
1290 render_color.alpha = color->alpha_short;
1292 if (num_rects > ARRAY_LENGTH(static_xrects)) {
1293 xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t));
1294 if (xrects == NULL)
1295 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1298 for (i = 0; i < num_rects; i++) {
1299 xrects[i].x = rects[i].x;
1300 xrects[i].y = rects[i].y;
1301 xrects[i].width = rects[i].width;
1302 xrects[i].height = rects[i].height;
1305 _cairo_xcb_surface_ensure_dst_picture (surface);
1306 xcb_render_fill_rectangles (surface->dpy,
1307 _render_operator (op),
1308 surface->dst_picture,
1309 render_color, num_rects, xrects);
1311 if (xrects != static_xrects)
1312 free(xrects);
1314 return CAIRO_STATUS_SUCCESS;
1317 /* Creates an A8 picture of size @width x @height, initialized with @color
1319 static xcb_render_picture_t
1320 _create_a8_picture (cairo_xcb_surface_t *surface,
1321 xcb_render_color_t *color,
1322 int width,
1323 int height,
1324 cairo_bool_t repeat)
1326 uint32_t values[] = { TRUE };
1327 uint32_t mask = repeat ? XCB_RENDER_CP_REPEAT : 0;
1329 xcb_pixmap_t pixmap = xcb_generate_id (surface->dpy);
1330 xcb_render_picture_t picture = xcb_generate_id (surface->dpy);
1332 xcb_render_pictforminfo_t *format
1333 = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8);
1334 xcb_rectangle_t rect = { 0, 0, width, height };
1336 xcb_create_pixmap (surface->dpy, 8, pixmap, surface->drawable,
1337 width <= 0 ? 1 : width,
1338 height <= 0 ? 1 : height);
1339 xcb_render_create_picture (surface->dpy, picture, pixmap, format->id, mask, values);
1340 xcb_render_fill_rectangles (surface->dpy, XCB_RENDER_PICT_OP_SRC, picture, *color, 1, &rect);
1341 xcb_free_pixmap (surface->dpy, pixmap);
1343 return picture;
1346 /* Creates a temporary mask for the trapezoids covering the area
1347 * [@dst_x, @dst_y, @width, @height] of the destination surface.
1349 static cairo_status_t
1350 _create_trapezoid_mask (cairo_xcb_surface_t *dst,
1351 cairo_trapezoid_t *traps,
1352 int num_traps,
1353 int dst_x,
1354 int dst_y,
1355 int width,
1356 int height,
1357 xcb_render_pictforminfo_t *pict_format,
1358 xcb_render_picture_t *mask_picture_out)
1360 xcb_render_color_t transparent = { 0, 0, 0, 0 };
1361 xcb_render_color_t solid = { 0xffff, 0xffff, 0xffff, 0xffff };
1362 xcb_render_picture_t mask_picture, solid_picture;
1363 xcb_render_trapezoid_t *offset_traps;
1364 int i;
1366 /* This would be considerably simpler using XRenderAddTraps(), but since
1367 * we are only using this in the unbounded-operator case, we stick with
1368 * XRenderCompositeTrapezoids, which is available on older versions
1369 * of RENDER rather than conditionalizing. We should still hit an
1370 * optimization that avoids creating another intermediate surface on
1371 * the servers that have XRenderAddTraps().
1373 mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
1374 solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
1376 offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t));
1377 if (offset_traps == NULL)
1378 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1380 for (i = 0; i < num_traps; i++) {
1381 offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
1382 offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y;
1383 offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x;
1384 offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y;
1385 offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x;
1386 offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y;
1387 offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x;
1388 offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y;
1389 offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x;
1390 offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y;
1393 xcb_render_trapezoids (dst->dpy, XCB_RENDER_PICT_OP_ADD,
1394 solid_picture, mask_picture,
1395 pict_format->id,
1396 0, 0,
1397 num_traps, offset_traps);
1399 xcb_render_free_picture (dst->dpy, solid_picture);
1400 free (offset_traps);
1402 *mask_picture_out = mask_picture;
1403 return CAIRO_STATUS_SUCCESS;
1406 static cairo_int_status_t
1407 _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
1408 const cairo_pattern_t *pattern,
1409 void *abstract_dst,
1410 cairo_antialias_t antialias,
1411 int src_x,
1412 int src_y,
1413 int dst_x,
1414 int dst_y,
1415 unsigned int width,
1416 unsigned int height,
1417 cairo_trapezoid_t *traps,
1418 int num_traps)
1420 cairo_surface_attributes_t attributes;
1421 cairo_xcb_surface_t *dst = abstract_dst;
1422 cairo_xcb_surface_t *src;
1423 cairo_int_status_t status;
1424 composite_operation_t operation;
1425 int render_reference_x, render_reference_y;
1426 int render_src_x, render_src_y;
1427 int cairo_format;
1428 xcb_render_pictforminfo_t *render_format;
1430 if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
1431 return CAIRO_INT_STATUS_UNSUPPORTED;
1433 operation = _categorize_composite_operation (dst, op, pattern, TRUE);
1434 if (operation == DO_UNSUPPORTED)
1435 return CAIRO_INT_STATUS_UNSUPPORTED;
1437 status = _cairo_pattern_acquire_surface (pattern, &dst->base,
1438 CAIRO_CONTENT_COLOR_ALPHA,
1439 src_x, src_y, width, height,
1440 CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
1441 (cairo_surface_t **) &src,
1442 &attributes);
1443 if (status)
1444 return status;
1446 operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
1447 if (operation == DO_UNSUPPORTED) {
1448 status = CAIRO_INT_STATUS_UNSUPPORTED;
1449 goto BAIL;
1452 if(antialias == CAIRO_ANTIALIAS_NONE)
1453 cairo_format = CAIRO_FORMAT_A1;
1454 else
1455 cairo_format = CAIRO_FORMAT_A8;
1457 render_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dst->dpy, cairo_format);
1458 /* XXX: what to do if render_format is null? */
1460 if (traps[0].left.p1.y < traps[0].left.p2.y) {
1461 render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
1462 render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
1463 } else {
1464 render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
1465 render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
1468 render_src_x = src_x + render_reference_x - dst_x;
1469 render_src_y = src_y + render_reference_y - dst_y;
1471 _cairo_xcb_surface_ensure_dst_picture (dst);
1472 status = _cairo_xcb_surface_set_attributes (src, &attributes);
1473 if (status)
1474 goto BAIL;
1476 if (!_cairo_operator_bounded_by_mask (op)) {
1477 /* xcb_render_composite+trapezoids() creates a mask only large enough for the
1478 * trapezoids themselves, but if the operator is unbounded, then we need
1479 * to actually composite all the way out to the bounds, so we create
1480 * the mask and composite ourselves. There actually would
1481 * be benefit to doing this in all cases, since RENDER implementations
1482 * will frequently create a too temporary big mask, ignoring destination
1483 * bounds and clip. (xcb_render_add_traps() could be used to make creating
1484 * the mask somewhat cheaper.)
1486 xcb_render_picture_t mask_picture = 0; /* silence compiler */
1488 status = _create_trapezoid_mask (dst, traps, num_traps,
1489 dst_x, dst_y, width, height,
1490 render_format,
1491 &mask_picture);
1492 if (status)
1493 goto BAIL;
1495 xcb_render_composite (dst->dpy,
1496 _render_operator (op),
1497 src->src_picture,
1498 mask_picture,
1499 dst->dst_picture,
1500 src_x + attributes.x_offset,
1501 src_y + attributes.y_offset,
1502 0, 0,
1503 dst_x, dst_y,
1504 width, height);
1506 xcb_render_free_picture (dst->dpy, mask_picture);
1508 status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
1509 &attributes, src->width, src->height,
1510 width, height,
1511 src_x, src_y,
1512 0, 0,
1513 dst_x, dst_y, width, height);
1515 } else {
1516 xcb_render_trapezoid_t xtraps_stack[16];
1517 xcb_render_trapezoid_t *xtraps = xtraps_stack;
1518 int i;
1520 if (num_traps > ARRAY_LENGTH(xtraps_stack)) {
1521 xtraps = _cairo_malloc_ab (num_traps, sizeof(xcb_render_trapezoid_t));
1522 if (xtraps == NULL) {
1523 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1524 goto BAIL;
1528 for (i = 0; i < num_traps; i++) {
1529 xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
1530 xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
1531 xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
1532 xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
1533 xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
1534 xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
1535 xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
1536 xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
1537 xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
1538 xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
1541 xcb_render_trapezoids (dst->dpy,
1542 _render_operator (op),
1543 src->src_picture, dst->dst_picture,
1544 render_format->id,
1545 render_src_x + attributes.x_offset,
1546 render_src_y + attributes.y_offset,
1547 num_traps, xtraps);
1549 if (xtraps != xtraps_stack)
1550 free(xtraps);
1553 BAIL:
1554 _cairo_pattern_release_surface (pattern, &src->base, &attributes);
1556 return status;
1559 static cairo_int_status_t
1560 _cairo_xcb_surface_set_clip_region (void *abstract_surface,
1561 cairo_region_t *region)
1563 cairo_xcb_surface_t *surface = abstract_surface;
1565 if (surface->clip_rects) {
1566 free (surface->clip_rects);
1567 surface->clip_rects = NULL;
1570 surface->have_clip_rects = FALSE;
1571 surface->num_clip_rects = 0;
1573 if (region == NULL) {
1574 uint32_t none[] = { XCB_NONE };
1575 if (surface->gc)
1576 xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
1578 if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
1579 xcb_render_change_picture (surface->dpy, surface->dst_picture,
1580 XCB_RENDER_CP_CLIP_MASK, none);
1581 } else {
1582 xcb_rectangle_t *rects = NULL;
1583 int n_rects, i;
1585 n_rects = cairo_region_num_rectangles (region);
1587 if (n_rects > 0) {
1588 rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
1589 if (rects == NULL)
1590 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1591 } else {
1592 rects = NULL;
1595 for (i = 0; i < n_rects; i++) {
1596 cairo_rectangle_int_t rect;
1598 cairo_region_get_rectangle (region, i, &rect);
1600 rects[i].x = rect.x;
1601 rects[i].y = rect.y;
1602 rects[i].width = rect.width;
1603 rects[i].height = rect.height;
1606 surface->have_clip_rects = TRUE;
1607 surface->clip_rects = rects;
1608 surface->num_clip_rects = n_rects;
1610 if (surface->gc)
1611 _cairo_xcb_surface_set_gc_clip_rects (surface);
1613 if (surface->dst_picture)
1614 _cairo_xcb_surface_set_picture_clip_rects (surface);
1617 return CAIRO_STATUS_SUCCESS;
1620 static cairo_int_status_t
1621 _cairo_xcb_surface_get_extents (void *abstract_surface,
1622 cairo_rectangle_int_t *rectangle)
1624 cairo_xcb_surface_t *surface = abstract_surface;
1626 rectangle->x = 0;
1627 rectangle->y = 0;
1629 rectangle->width = surface->width;
1630 rectangle->height = surface->height;
1632 return CAIRO_STATUS_SUCCESS;
1635 /* XXX: _cairo_xcb_surface_get_font_options */
1637 static void
1638 _cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
1640 static void
1641 _cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
1642 cairo_scaled_font_t *scaled_font);
1644 static cairo_int_status_t
1645 _cairo_xcb_surface_show_glyphs (void *abstract_dst,
1646 cairo_operator_t op,
1647 const cairo_pattern_t *src_pattern,
1648 cairo_glyph_t *glyphs,
1649 int num_glyphs,
1650 cairo_scaled_font_t *scaled_font,
1651 int *remaining_glyphs,
1652 cairo_rectangle_int_t *extents);
1654 static cairo_bool_t
1655 _cairo_xcb_surface_is_similar (void *surface_a,
1656 void *surface_b,
1657 cairo_content_t content)
1659 cairo_xcb_surface_t *a = surface_a;
1660 cairo_xcb_surface_t *b = surface_b;
1661 xcb_render_pictforminfo_t *xrender_format;
1663 /* XXX: disable caching by the solid pattern cache until we implement
1664 * display notification to avoid issuing xcb calls from the wrong thread
1665 * or accessing the surface after the Display has been closed.
1667 return FALSE;
1669 if (! _cairo_xcb_surface_same_screen (a, b))
1670 return FALSE;
1672 /* now check that the target is a similar format */
1673 xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy,
1674 _cairo_format_from_content (content));
1676 return a->xrender_format.id == xrender_format->id;
1679 static cairo_status_t
1680 _cairo_xcb_surface_reset (void *abstract_surface)
1682 cairo_xcb_surface_t *surface = abstract_surface;
1683 cairo_status_t status;
1685 status = _cairo_xcb_surface_set_clip_region (surface, NULL);
1686 if (status)
1687 return status;
1689 return CAIRO_STATUS_SUCCESS;
1693 /* XXX: move this to the bottom of the file, XCB and Xlib */
1695 static const cairo_surface_backend_t cairo_xcb_surface_backend = {
1696 CAIRO_SURFACE_TYPE_XCB,
1697 _cairo_xcb_surface_create_similar,
1698 _cairo_xcb_surface_finish,
1699 _cairo_xcb_surface_acquire_source_image,
1700 _cairo_xcb_surface_release_source_image,
1701 _cairo_xcb_surface_acquire_dest_image,
1702 _cairo_xcb_surface_release_dest_image,
1703 _cairo_xcb_surface_clone_similar,
1704 _cairo_xcb_surface_composite,
1705 _cairo_xcb_surface_fill_rectangles,
1706 _cairo_xcb_surface_composite_trapezoids,
1707 NULL, /* create_span_renderer */
1708 NULL, /* check_span_renderer */
1709 NULL, /* copy_page */
1710 NULL, /* show_page */
1711 _cairo_xcb_surface_set_clip_region,
1712 NULL, /* intersect_clip_path */
1713 _cairo_xcb_surface_get_extents,
1714 NULL, /* old_show_glyphs */
1715 NULL, /* get_font_options */
1716 NULL, /* flush */
1717 NULL, /* mark_dirty_rectangle */
1718 _cairo_xcb_surface_scaled_font_fini,
1719 _cairo_xcb_surface_scaled_glyph_fini,
1721 NULL, /* paint */
1722 NULL, /* mask */
1723 NULL, /* stroke */
1724 NULL, /* fill */
1725 _cairo_xcb_surface_show_glyphs,
1727 _cairo_xcb_surface_snapshot,
1729 _cairo_xcb_surface_is_similar,
1731 _cairo_xcb_surface_reset
1735 * _cairo_surface_is_xcb:
1736 * @surface: a #cairo_surface_t
1738 * Checks if a surface is a #cairo_xcb_surface_t
1740 * Return value: True if the surface is an xcb surface
1742 static cairo_bool_t
1743 _cairo_surface_is_xcb (cairo_surface_t *surface)
1745 return surface->backend == &cairo_xcb_surface_backend;
1748 static cairo_surface_t *
1749 _cairo_xcb_surface_create_internal (xcb_connection_t *dpy,
1750 xcb_drawable_t drawable,
1751 xcb_screen_t *screen,
1752 xcb_visualtype_t *visual,
1753 xcb_render_pictforminfo_t *xrender_format,
1754 int width,
1755 int height,
1756 int depth)
1758 cairo_xcb_surface_t *surface;
1759 const xcb_query_extension_reply_t *er;
1760 const xcb_render_query_version_reply_t *r = NULL;
1762 surface = malloc (sizeof (cairo_xcb_surface_t));
1763 if (surface == NULL)
1764 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1766 if (xrender_format) {
1767 depth = xrender_format->depth;
1768 } else if (visual) {
1769 xcb_depth_iterator_t depths;
1770 xcb_visualtype_iterator_t visuals;
1772 /* This is ugly, but we have to walk over all visuals
1773 * for the screen to find the depth.
1775 depths = xcb_screen_allowed_depths_iterator(screen);
1776 for(; depths.rem; xcb_depth_next(&depths))
1778 visuals = xcb_depth_visuals_iterator(depths.data);
1779 for(; visuals.rem; xcb_visualtype_next(&visuals))
1781 if(visuals.data->visual_id == visual->visual_id)
1783 depth = depths.data->depth;
1784 goto found;
1788 found:
1792 er = xcb_get_extension_data(dpy, &xcb_render_id);
1793 if(er && er->present) {
1794 r = xcb_render_util_query_version(dpy);
1796 if (r) {
1797 surface->render_major = r->major_version;
1798 surface->render_minor = r->minor_version;
1799 } else {
1800 surface->render_major = -1;
1801 surface->render_minor = -1;
1804 if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
1805 if (!xrender_format) {
1806 if (visual) {
1807 const xcb_render_query_pict_formats_reply_t *formats;
1808 xcb_render_pictvisual_t *pict_visual;
1809 formats = xcb_render_util_query_formats (dpy);
1810 pict_visual = xcb_render_util_find_visual_format (formats, visual->visual_id);
1811 if (pict_visual) {
1812 xcb_render_pictforminfo_t template;
1813 template.id = pict_visual->format;
1814 xrender_format = xcb_render_util_find_format (formats, XCB_PICT_FORMAT_ID, &template, 0);
1816 } else if (depth == 1) {
1817 xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, CAIRO_FORMAT_A1);
1820 } else {
1821 xrender_format = NULL;
1824 _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend,
1825 _xcb_render_format_to_content (xrender_format));
1827 surface->dpy = dpy;
1829 surface->gc = XCB_NONE;
1830 surface->drawable = drawable;
1831 surface->screen = screen;
1832 surface->owns_pixmap = FALSE;
1833 surface->use_pixmap = 0;
1834 surface->width = width;
1835 surface->height = height;
1837 /* XXX: set buggy_repeat based on ServerVendor and VendorRelease */
1839 surface->dst_picture = XCB_NONE;
1840 surface->src_picture = XCB_NONE;
1842 surface->visual = visual;
1843 surface->xrender_format.id = XCB_NONE;
1844 if (xrender_format) surface->xrender_format = *xrender_format;
1845 surface->depth = depth;
1847 surface->have_clip_rects = FALSE;
1848 surface->clip_rects = NULL;
1849 surface->num_clip_rects = 0;
1851 return (cairo_surface_t *) surface;
1854 static xcb_screen_t *
1855 _cairo_xcb_screen_from_visual (xcb_connection_t *c, xcb_visualtype_t *visual)
1857 xcb_depth_iterator_t d;
1858 xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c));
1859 for (; s.rem; xcb_screen_next(&s))
1861 if (s.data->root_visual == visual->visual_id)
1862 return s.data;
1864 d = xcb_screen_allowed_depths_iterator(s.data);
1865 for (; d.rem; xcb_depth_next(&d))
1867 xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data);
1868 for (; v.rem; xcb_visualtype_next(&v))
1870 if (v.data->visual_id == visual->visual_id)
1871 return s.data;
1875 return NULL;
1879 * cairo_xcb_surface_create:
1880 * @c: an XCB connection
1881 * @drawable: an XCB drawable
1882 * @visual: the visual to use for drawing to @drawable. The depth
1883 * of the visual must match the depth of the drawable.
1884 * Currently, only TrueColor visuals are fully supported.
1885 * @width: the current width of @drawable.
1886 * @height: the current height of @drawable.
1888 * Creates an XCB surface that draws to the given drawable.
1889 * The way that colors are represented in the drawable is specified
1890 * by the provided visual.
1892 * Note: If @drawable is a window, then the function
1893 * cairo_xcb_surface_set_size() must be called whenever the size of the
1894 * window changes.
1896 * Return value: the newly created surface
1898 cairo_surface_t *
1899 cairo_xcb_surface_create (xcb_connection_t *c,
1900 xcb_drawable_t drawable,
1901 xcb_visualtype_t *visual,
1902 int width,
1903 int height)
1905 xcb_screen_t *screen = _cairo_xcb_screen_from_visual (c, visual);
1907 if (screen == NULL)
1908 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
1910 return _cairo_xcb_surface_create_internal (c, drawable, screen,
1911 visual, NULL,
1912 width, height, 0);
1916 * cairo_xcb_surface_create_for_bitmap:
1917 * @c: an XCB connection
1918 * @bitmap: an XCB Pixmap (a depth-1 pixmap)
1919 * @screen: an XCB Screen
1920 * @width: the current width of @bitmap
1921 * @height: the current height of @bitmap
1923 * Creates an XCB surface that draws to the given bitmap.
1924 * This will be drawn to as a %CAIRO_FORMAT_A1 object.
1926 * Return value: the newly created surface
1928 cairo_surface_t *
1929 cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
1930 xcb_pixmap_t bitmap,
1931 xcb_screen_t *screen,
1932 int width,
1933 int height)
1935 return _cairo_xcb_surface_create_internal (c, bitmap, screen,
1936 NULL, NULL,
1937 width, height, 1);
1941 * cairo_xcb_surface_create_with_xrender_format:
1942 * @c: an XCB connection
1943 * @drawable: an XCB drawable
1944 * @screen: the XCB screen associated with @drawable
1945 * @format: the picture format to use for drawing to @drawable. The
1946 * depth of @format mush match the depth of the drawable.
1947 * @width: the current width of @drawable
1948 * @height: the current height of @drawable
1950 * Creates an XCB surface that draws to the given drawable.
1951 * The way that colors are represented in the drawable is specified
1952 * by the provided picture format.
1954 * Note: If @drawable is a Window, then the function
1955 * cairo_xcb_surface_set_size() must be called whenever the size of the
1956 * window changes.
1958 * Return value: the newly created surface.
1960 cairo_surface_t *
1961 cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *c,
1962 xcb_drawable_t drawable,
1963 xcb_screen_t *screen,
1964 xcb_render_pictforminfo_t *format,
1965 int width,
1966 int height)
1968 return _cairo_xcb_surface_create_internal (c, drawable, screen,
1969 NULL, format,
1970 width, height, 0);
1972 slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
1975 * cairo_xcb_surface_set_size:
1976 * @surface: a #cairo_surface_t for the XCB backend
1977 * @width: the new width of the surface
1978 * @height: the new height of the surface
1980 * Informs cairo of the new size of the XCB drawable underlying the
1981 * surface. For a surface created for a window (rather than a pixmap),
1982 * this function must be called each time the size of the window
1983 * changes. (For a subwindow, you are normally resizing the window
1984 * yourself, but for a toplevel window, it is necessary to listen for
1985 * ConfigureNotify events.)
1987 * A pixmap can never change size, so it is never necessary to call
1988 * this function on a surface created for a pixmap.
1990 void
1991 cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
1992 int width,
1993 int height)
1995 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) abstract_surface;
1996 cairo_status_t status_ignored;
1998 if (! _cairo_surface_is_xcb (abstract_surface)) {
1999 status_ignored = _cairo_surface_set_error (abstract_surface,
2000 CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2001 return;
2004 surface->width = width;
2005 surface->height = height;
2009 * Glyph rendering support
2012 typedef struct _cairo_xcb_surface_font_private {
2013 xcb_connection_t *dpy;
2014 xcb_render_glyphset_t glyphset;
2015 cairo_format_t format;
2016 xcb_render_pictforminfo_t *xrender_format;
2017 } cairo_xcb_surface_font_private_t;
2019 static cairo_status_t
2020 _cairo_xcb_surface_font_init (xcb_connection_t *dpy,
2021 cairo_scaled_font_t *scaled_font,
2022 cairo_format_t format)
2024 cairo_xcb_surface_font_private_t *font_private;
2026 font_private = malloc (sizeof (cairo_xcb_surface_font_private_t));
2027 if (!font_private)
2028 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2030 font_private->dpy = dpy;
2031 font_private->format = format;
2032 font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format);
2033 font_private->glyphset = xcb_generate_id(dpy);
2034 xcb_render_create_glyph_set (dpy, font_private->glyphset, font_private->xrender_format->id);
2036 scaled_font->surface_private = font_private;
2037 scaled_font->surface_backend = &cairo_xcb_surface_backend;
2038 return CAIRO_STATUS_SUCCESS;
2041 static void
2042 _cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
2044 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2046 if (font_private) {
2047 xcb_render_free_glyph_set (font_private->dpy, font_private->glyphset);
2048 free (font_private);
2052 static void
2053 _cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
2054 cairo_scaled_font_t *scaled_font)
2056 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2058 if (font_private != NULL && scaled_glyph->surface_private != NULL) {
2059 xcb_render_glyph_t glyph_index = _cairo_scaled_glyph_index(scaled_glyph);
2060 xcb_render_free_glyphs (font_private->dpy,
2061 font_private->glyphset,
2062 1, &glyph_index);
2066 static cairo_bool_t
2067 _native_byte_order_lsb (void)
2069 int x = 1;
2071 return *((char *) &x) == 1;
2074 static cairo_status_t
2075 _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy,
2076 cairo_scaled_font_t *scaled_font,
2077 cairo_scaled_glyph_t *scaled_glyph)
2079 xcb_render_glyphinfo_t glyph_info;
2080 xcb_render_glyph_t glyph_index;
2081 unsigned char *data;
2082 cairo_status_t status = CAIRO_STATUS_SUCCESS;
2083 cairo_xcb_surface_font_private_t *font_private;
2084 cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
2086 if (scaled_font->surface_private == NULL) {
2087 status = _cairo_xcb_surface_font_init (dpy, scaled_font,
2088 glyph_surface->format);
2089 if (status)
2090 return status;
2092 font_private = scaled_font->surface_private;
2094 /* If the glyph format does not match the font format, then we
2095 * create a temporary surface for the glyph image with the font's
2096 * format.
2098 if (glyph_surface->format != font_private->format) {
2099 cairo_t *cr;
2100 cairo_surface_t *tmp_surface;
2101 double x_offset, y_offset;
2103 tmp_surface = cairo_image_surface_create (font_private->format,
2104 glyph_surface->width,
2105 glyph_surface->height);
2106 cr = cairo_create (tmp_surface);
2107 cairo_surface_get_device_offset (&glyph_surface->base, &x_offset, &y_offset);
2108 cairo_set_source_surface (cr, &glyph_surface->base, x_offset, y_offset);
2109 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
2110 cairo_paint (cr);
2112 status = cairo_status (cr);
2114 cairo_destroy (cr);
2116 tmp_surface->device_transform = glyph_surface->base.device_transform;
2117 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
2119 glyph_surface = (cairo_image_surface_t *) tmp_surface;
2121 if (status)
2122 goto BAIL;
2125 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
2126 glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
2127 glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
2128 glyph_info.width = glyph_surface->width;
2129 glyph_info.height = glyph_surface->height;
2130 glyph_info.x_off = 0;
2131 glyph_info.y_off = 0;
2133 data = glyph_surface->data;
2135 /* flip formats around */
2136 switch (scaled_glyph->surface->format) {
2137 case CAIRO_FORMAT_A1:
2138 /* local bitmaps are always stored with bit == byte */
2139 if (_native_byte_order_lsb() != (xcb_get_setup(dpy)->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
2140 int c = glyph_surface->stride * glyph_surface->height;
2141 unsigned char *d;
2142 unsigned char *new, *n;
2144 new = malloc (c);
2145 if (!new) {
2146 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2147 goto BAIL;
2149 n = new;
2150 d = data;
2151 while (c--)
2153 char b = *d++;
2154 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
2155 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
2156 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
2157 *n++ = b;
2159 data = new;
2161 break;
2162 case CAIRO_FORMAT_A8:
2163 break;
2164 case CAIRO_FORMAT_ARGB32:
2165 if (_native_byte_order_lsb() != (xcb_get_setup(dpy)->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
2166 unsigned int c = glyph_surface->stride * glyph_surface->height;
2167 unsigned char *d;
2168 unsigned char *new, *n;
2170 new = malloc (c);
2171 if (new == NULL) {
2172 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2173 goto BAIL;
2175 n = new;
2176 d = data;
2177 while (c >= 4)
2179 n[3] = d[0];
2180 n[2] = d[1];
2181 n[1] = d[2];
2182 n[0] = d[3];
2183 d += 4;
2184 n += 4;
2185 c -= 4;
2187 data = new;
2189 break;
2190 case CAIRO_FORMAT_RGB24:
2191 default:
2192 ASSERT_NOT_REACHED;
2193 break;
2195 /* XXX assume X server wants pixman padding. Xft assumes this as well */
2197 glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
2199 xcb_render_add_glyphs (dpy, font_private->glyphset,
2200 1, &glyph_index, &glyph_info,
2201 glyph_surface->stride * glyph_surface->height,
2202 data);
2204 if (data != glyph_surface->data)
2205 free (data);
2207 BAIL:
2208 if (glyph_surface != scaled_glyph->surface)
2209 cairo_surface_destroy (&glyph_surface->base);
2211 return status;
2214 #define N_STACK_BUF 1024
2216 static cairo_status_t
2217 _cairo_xcb_surface_show_glyphs_8 (cairo_xcb_surface_t *dst,
2218 cairo_operator_t op,
2219 cairo_xcb_surface_t *src,
2220 int src_x_offset, int src_y_offset,
2221 const cairo_glyph_t *glyphs,
2222 int num_glyphs,
2223 cairo_scaled_font_t *scaled_font)
2225 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2226 xcb_render_util_composite_text_stream_t *stream;
2227 int i;
2228 int thisX, thisY;
2229 int lastX = 0, lastY = 0;
2230 uint8_t glyph;
2232 stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
2234 for (i = 0; i < num_glyphs; ++i) {
2235 thisX = _cairo_lround (glyphs[i].x);
2236 thisY = _cairo_lround (glyphs[i].y);
2237 glyph = glyphs[i].index;
2238 xcb_render_util_glyphs_8 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
2239 lastX = thisX;
2240 lastY = thisY;
2243 xcb_render_util_composite_text (dst->dpy,
2244 _render_operator (op),
2245 src->src_picture,
2246 dst->dst_picture,
2247 font_private->xrender_format->id,
2248 src_x_offset + _cairo_lround (glyphs[0].x),
2249 src_y_offset + _cairo_lround (glyphs[0].y),
2250 stream);
2252 xcb_render_util_composite_text_free (stream);
2254 return CAIRO_STATUS_SUCCESS;
2257 static cairo_status_t
2258 _cairo_xcb_surface_show_glyphs_16 (cairo_xcb_surface_t *dst,
2259 cairo_operator_t op,
2260 cairo_xcb_surface_t *src,
2261 int src_x_offset, int src_y_offset,
2262 const cairo_glyph_t *glyphs,
2263 int num_glyphs,
2264 cairo_scaled_font_t *scaled_font)
2266 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2267 xcb_render_util_composite_text_stream_t *stream;
2268 int i;
2269 int thisX, thisY;
2270 int lastX = 0, lastY = 0;
2271 uint16_t glyph;
2273 stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
2275 for (i = 0; i < num_glyphs; ++i) {
2276 thisX = _cairo_lround (glyphs[i].x);
2277 thisY = _cairo_lround (glyphs[i].y);
2278 glyph = glyphs[i].index;
2279 xcb_render_util_glyphs_16 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
2280 lastX = thisX;
2281 lastY = thisY;
2284 xcb_render_util_composite_text (dst->dpy,
2285 _render_operator (op),
2286 src->src_picture,
2287 dst->dst_picture,
2288 font_private->xrender_format->id,
2289 src_x_offset + _cairo_lround (glyphs[0].x),
2290 src_y_offset + _cairo_lround (glyphs[0].y),
2291 stream);
2293 xcb_render_util_composite_text_free (stream);
2295 return CAIRO_STATUS_SUCCESS;
2298 static cairo_status_t
2299 _cairo_xcb_surface_show_glyphs_32 (cairo_xcb_surface_t *dst,
2300 cairo_operator_t op,
2301 cairo_xcb_surface_t *src,
2302 int src_x_offset, int src_y_offset,
2303 const cairo_glyph_t *glyphs,
2304 int num_glyphs,
2305 cairo_scaled_font_t *scaled_font)
2307 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2308 xcb_render_util_composite_text_stream_t *stream;
2309 int i;
2310 int thisX, thisY;
2311 int lastX = 0, lastY = 0;
2312 uint32_t glyph;
2314 stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
2316 for (i = 0; i < num_glyphs; ++i) {
2317 thisX = _cairo_lround (glyphs[i].x);
2318 thisY = _cairo_lround (glyphs[i].y);
2319 glyph = glyphs[i].index;
2320 xcb_render_util_glyphs_32 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
2321 lastX = thisX;
2322 lastY = thisY;
2325 xcb_render_util_composite_text (dst->dpy,
2326 _render_operator (op),
2327 src->src_picture,
2328 dst->dst_picture,
2329 font_private->xrender_format->id,
2330 src_x_offset + _cairo_lround (glyphs[0].x),
2331 src_y_offset + _cairo_lround (glyphs[0].y),
2332 stream);
2334 xcb_render_util_composite_text_free (stream);
2336 return CAIRO_STATUS_SUCCESS;
2339 typedef cairo_status_t (*cairo_xcb_surface_show_glyphs_func_t)
2340 (cairo_xcb_surface_t *, cairo_operator_t, cairo_xcb_surface_t *, int, int,
2341 const cairo_glyph_t *, int, cairo_scaled_font_t *);
2343 static cairo_bool_t
2344 _cairo_xcb_surface_owns_font (cairo_xcb_surface_t *dst,
2345 cairo_scaled_font_t *scaled_font)
2347 cairo_xcb_surface_font_private_t *font_private;
2349 font_private = scaled_font->surface_private;
2350 if ((scaled_font->surface_backend != NULL &&
2351 scaled_font->surface_backend != &cairo_xcb_surface_backend) ||
2352 (font_private != NULL && font_private->dpy != dst->dpy))
2354 return FALSE;
2357 return TRUE;
2362 static cairo_status_t
2363 _cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst,
2364 cairo_glyph_t *glyphs,
2365 int num_glyphs,
2366 cairo_scaled_font_t *scaled_font,
2367 cairo_operator_t op,
2368 cairo_xcb_surface_t *src,
2369 cairo_surface_attributes_t *attributes,
2370 int *remaining_glyphs)
2372 cairo_scaled_glyph_t *scaled_glyph;
2373 int i, o;
2374 unsigned long max_index = 0;
2375 cairo_status_t status;
2376 cairo_glyph_t *output_glyphs;
2377 const cairo_glyph_t *glyphs_chunk;
2378 int glyphs_remaining, chunk_size, max_chunk_size;
2379 cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
2381 /* We make a copy of the glyphs so that we can elide any size-zero
2382 * glyphs to workaround an X server bug, (present in at least Xorg
2383 * 7.1 without EXA). */
2384 output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
2385 if (output_glyphs == NULL)
2386 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2388 for (i = 0, o = 0; i < num_glyphs; i++) {
2389 if (glyphs[i].index > max_index)
2390 max_index = glyphs[i].index;
2391 status = _cairo_scaled_glyph_lookup (scaled_font,
2392 glyphs[i].index,
2393 CAIRO_SCALED_GLYPH_INFO_SURFACE,
2394 &scaled_glyph);
2395 if (status) {
2396 free (output_glyphs);
2397 return status;
2400 /* Don't put any size-zero glyphs into output_glyphs to avoid
2401 * an X server bug which stops rendering glyphs after the
2402 * first size-zero glyph. */
2403 if (scaled_glyph->surface->width && scaled_glyph->surface->height) {
2404 output_glyphs[o++] = glyphs[i];
2405 if (scaled_glyph->surface_private == NULL) {
2406 _cairo_xcb_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph);
2407 scaled_glyph->surface_private = (void *) 1;
2411 num_glyphs = o;
2413 _cairo_xcb_surface_ensure_dst_picture (dst);
2415 max_chunk_size = xcb_get_maximum_request_length (dst->dpy);
2416 if (max_index < 256) {
2417 /* XXX: these are all the same size! (28) */
2418 max_chunk_size -= sizeof(xcb_render_composite_glyphs_8_request_t);
2419 show_glyphs_func = _cairo_xcb_surface_show_glyphs_8;
2420 } else if (max_index < 65536) {
2421 max_chunk_size -= sizeof(xcb_render_composite_glyphs_16_request_t);
2422 show_glyphs_func = _cairo_xcb_surface_show_glyphs_16;
2423 } else {
2424 max_chunk_size -= sizeof(xcb_render_composite_glyphs_32_request_t);
2425 show_glyphs_func = _cairo_xcb_surface_show_glyphs_32;
2427 /* XXX: I think this is wrong; this is only the header size (2 longs) */
2428 /* but should also include the glyph (1 long) */
2429 /* max_chunk_size /= sz_xGlyphElt; */
2430 max_chunk_size /= 3*sizeof(uint32_t);
2432 for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs;
2433 glyphs_remaining;
2434 glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
2436 chunk_size = MIN (glyphs_remaining, max_chunk_size);
2438 status = show_glyphs_func (dst, op, src,
2439 attributes->x_offset, attributes->y_offset,
2440 glyphs_chunk, chunk_size, scaled_font);
2441 if (status) {
2442 free (output_glyphs);
2443 return status;
2447 /* We wouldn't want to leak memory, would we? */
2448 free(output_glyphs);
2450 return CAIRO_STATUS_SUCCESS;
2453 static cairo_int_status_t
2454 _cairo_xcb_surface_show_glyphs (void *abstract_dst,
2455 cairo_operator_t op,
2456 const cairo_pattern_t *src_pattern,
2457 cairo_glyph_t *glyphs,
2458 int num_glyphs,
2459 cairo_scaled_font_t *scaled_font,
2460 int *remaining_glyphs,
2461 cairo_rectangle_int_t *extents)
2463 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2464 cairo_xcb_surface_t *dst = abstract_dst;
2466 composite_operation_t operation;
2467 cairo_surface_attributes_t attributes;
2468 cairo_xcb_surface_t *src = NULL;
2470 cairo_solid_pattern_t solid_pattern;
2472 if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
2473 return CAIRO_INT_STATUS_UNSUPPORTED;
2475 /* Just let unbounded operators go through the fallback code
2476 * instead of trying to do the fixups here */
2477 if (!_cairo_operator_bounded_by_mask (op))
2478 return CAIRO_INT_STATUS_UNSUPPORTED;
2480 /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
2481 * the solid source seems to be multiplied by the glyph mask, and
2482 * then the entire thing is copied to the destination surface,
2483 * including the fully transparent "background" of the rectangular
2484 * glyph surface. */
2485 if (op == CAIRO_OPERATOR_SOURCE &&
2486 !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
2487 return CAIRO_INT_STATUS_UNSUPPORTED;
2489 /* We can only use our code if we either have no clip or
2490 * have a real native clip region set. If we're using
2491 * fallback clip masking, we have to go through the full
2492 * fallback path.
2494 if (dst->base.clip &&
2495 (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
2496 dst->base.clip->surface != NULL))
2497 return CAIRO_INT_STATUS_UNSUPPORTED;
2499 operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
2500 if (operation == DO_UNSUPPORTED)
2501 return CAIRO_INT_STATUS_UNSUPPORTED;
2503 if (! _cairo_xcb_surface_owns_font (dst, scaled_font))
2504 return CAIRO_INT_STATUS_UNSUPPORTED;
2506 /* After passing all those tests, we're now committed to rendering
2507 * these glyphs or to fail trying. We first upload any glyphs to
2508 * the X server that it doesn't have already, then we draw
2509 * them. We tie into the scaled_font's glyph cache and remove
2510 * glyphs from the X server when they are ejected from the
2511 * scaled_font cache.
2514 /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
2515 * the mask (the glyphs). This code below was executed as a side effect
2516 * of going through the _clip_and_composite fallback code for old_show_glyphs,
2517 * so PictOpClear was never used with CompositeText before.
2519 if (op == CAIRO_OPERATOR_CLEAR) {
2520 _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
2521 CAIRO_CONTENT_COLOR);
2522 src_pattern = &solid_pattern.base;
2523 op = CAIRO_OPERATOR_DEST_OUT;
2526 if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
2527 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
2528 CAIRO_CONTENT_COLOR_ALPHA,
2529 0, 0, 1, 1,
2530 CAIRO_PATTERN_ACQUIRE_NONE,
2531 (cairo_surface_t **) &src,
2532 &attributes);
2533 } else {
2534 cairo_rectangle_int_t glyph_extents;
2536 status = _cairo_scaled_font_glyph_device_extents (scaled_font,
2537 glyphs,
2538 num_glyphs,
2539 &glyph_extents);
2540 if (status)
2541 goto BAIL;
2543 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
2544 CAIRO_CONTENT_COLOR_ALPHA,
2545 glyph_extents.x, glyph_extents.y,
2546 glyph_extents.width, glyph_extents.height,
2547 CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
2548 (cairo_surface_t **) &src,
2549 &attributes);
2552 if (status)
2553 goto BAIL;
2555 operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
2556 if (operation == DO_UNSUPPORTED) {
2557 status = CAIRO_INT_STATUS_UNSUPPORTED;
2558 goto BAIL;
2561 status = _cairo_xcb_surface_set_attributes (src, &attributes);
2562 if (status)
2563 goto BAIL;
2565 /* Send all unsent glyphs to the server, and count the max of the glyph indices */
2566 _cairo_scaled_font_freeze_cache (scaled_font);
2568 if (_cairo_xcb_surface_owns_font (dst, scaled_font))
2569 status = _cairo_xcb_surface_emit_glyphs (dst,
2570 glyphs, num_glyphs,
2571 scaled_font,
2573 src,
2574 &attributes,
2575 remaining_glyphs);
2576 else
2577 status = CAIRO_INT_STATUS_UNSUPPORTED;
2578 _cairo_scaled_font_thaw_cache (scaled_font);
2580 BAIL:
2581 if (src)
2582 _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
2583 if (src_pattern == &solid_pattern.base)
2584 _cairo_pattern_fini (&solid_pattern.base);
2586 return status;
2590 typedef struct
2592 cairo_space_t base;
2593 xcb_connection_t* conn;
2594 xcb_screen_t* screen;
2595 int owns_conn;
2596 Display* dpy;
2597 } cairo_xcb_space_t;
2599 static void
2600 _cairo_xcb_space_destroy(void* abstract_space)
2602 cairo_xcb_space_t* space = abstract_space;
2603 if(space->owns_conn)
2604 xcb_disconnect(space->conn);
2605 if(space->dpy)
2606 XCloseDisplay(space->dpy);
2607 free(space);
2610 static cairo_surface_t*
2611 _cairo_xcb_space_surface_create(void* abstract_space, cairo_content_t content, int width, int height, int mantissa_bits, int shared_exponent_bits, int component_exponent_bits)
2613 cairo_xcb_space_t* space = abstract_space;
2614 cairo_xlib_display_t* display;
2615 Pixmap pix;
2616 cairo_xlib_surface_t *surface;
2617 XRenderPictFormat *xrender_format;
2619 assert (width <= XLIB_COORD_MAX && height <= XLIB_COORD_MAX);
2621 if(_cairo_xlib_display_get(space->dpy, &display))
2622 return NULL;
2624 /* As a good first approximation, if the display doesn't have even
2625 * the most elementary RENDER operation, then we're better off
2626 * using image surfaces for all temporary operations, so return NULL
2627 * and let the fallback code happen.
2629 if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (display))
2630 return NULL;
2632 xrender_format = _cairo_xlib_display_get_xrender_format (display,
2633 _cairo_format_from_content(content));
2634 if (xrender_format == NULL)
2635 return NULL;
2637 pix = XCreatePixmap (space->dpy, RootWindowOfScreen(space->screen),
2638 width <= 0 ? 1 : width, height <= 0 ? 1 : height,
2639 xrender_format->depth);
2641 surface = (cairo_xlib_surface_t *)
2642 _cairo_xlib_surface_create_internal (space->dpy, pix,
2643 space->screen, NULL,
2644 xrender_format,
2645 width, height,
2646 xrender_format->depth);
2647 if (surface->base.status) {
2648 XFreePixmap (space->dpy, pix);
2649 return &surface->base;
2652 surface->owns_pixmap = TRUE;
2654 return &surface->base;
2657 static
2658 _cairo_get_visualtype(xcb_connection_t* conn, xcb_screen* screen, unsigned long drawable, unsigned long visualid)
2660 xcb_depth_iterator_t depths;
2661 xcb_visualtype_iterator_t visuals;
2662 xcb_screen_t* screen;
2664 if(!visualid)
2666 if(!drawable)
2667 visualid = screen->root_visual;
2668 else
2670 xcb_generic_error_t* e = 0;
2671 xcb_get_window_attributes_reply_t * gwa;
2673 gwa = xcb_get_window_attributes_reply(conn, xcb_get_window_attributes(conn, drawable), &e);
2674 if(e)
2675 free(e);
2677 visualid = gwa->visualid;
2678 free(gwa);
2683 xcb_depth_iterator_t d;
2684 xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(conn));
2685 for (; s.rem; xcb_screen_next(&s))
2687 if (s.data->root_visual == visual->visual_id)
2688 return s.data;
2690 d = xcb_screen_allowed_depths_iterator(s.data);
2691 for (; d.rem; xcb_depth_next(&d))
2693 xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data);
2694 for (; v.rem; xcb_visualtype_next(&v))
2696 if (v.data->visual_id == visualid)
2697 return s.data;
2701 return 0;
2704 static cairo_surface_t*
2705 _cairo_xcb_space_surface_create_for_drawable(void* abstract_space, unsigned long drawable, unsigned long visualid, int width, int height)
2707 cairo_xcb_space_t* space = abstract_space;
2708 xcb_visualtype* vi = _cairo_get_visualtype(space->conn, space->screen, drawable, visual);
2709 if(!vi)
2710 return _cairo_surface_create_in_error(CAIRO_STATUS_INVALID_VISUAL);
2711 else
2713 cairo_surface_t* surface = cairo_xcb_surface_create(space->conn, (xcb_drawable_t)drawable, vi->visual, width, height);
2715 XFree(vi);
2716 return surface;
2720 cairo_space_backend_t _cairo_xcb_space_backend =
2722 _cairo_xcb_space_destroy,
2723 _cairo_xcb_space_surface_create,
2724 _cairo_xcb_space_surface_create_for_drawable,
2727 cairo_public cairo_space_t *
2728 cairo_xcb_space_create(const char* name)
2730 xcb_connect_t* conn;
2731 int screen;
2732 conn = xcb_connect(name, &screen);
2733 if(!conn)
2734 return 0;
2736 return cairo_xcb_space_wrap(conn, screen, 1);
2739 cairo_public cairo_space_t *
2740 cairo_xcb_space_wrap(xcb_connection_t* conn, int screen, int owns_conn)
2742 cairo_xcb_space_t* space;
2743 if(!conn)
2744 return cairo_xcb_space_create(0);
2746 space = calloc(sizeof(cairo_xcb_space_t), 1);
2748 CAIRO_REFERENCE_COUNT_INIT(&space->base.ref_count, 1);
2749 space->base.backend = &_cairo_xcb_space_backend;
2750 space->conn = conn;
2752 xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(conn));
2753 for (; s.rem; xcb_screen_next(&s))
2755 if(s.index == screen)
2757 space->screen = s.data;
2758 break;
2761 if(!s.index)
2762 space->screen = s.data;
2765 space->owns_conn = owns_conn;
2767 return &space->base;
2770 cairo_public cairo_space_t *
2771 cairo_xcb_space_wrap_xlib(Display* dpy, int screen, int owns_dpy)
2773 cairo_space_t* space = cairo_xcb_space_wrap(XGetXCBConnection(dpy), screen, 0);
2774 if(space)
2775 ((cairo_xcb_space_t*)space)->dpy = dpy;
2776 return space;