added MouseWheel event support for Silverlight 3.0
[moon.git] / cairo / src / cairo-xcb-surface.c
blobdede00f3b54847fd94431d7e811e178909d59391
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)
105 static void
106 _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
108 static int
109 _CAIRO_FORMAT_DEPTH (cairo_format_t format)
111 switch (format) {
112 case CAIRO_FORMAT_A1:
113 return 1;
114 case CAIRO_FORMAT_A8:
115 return 8;
116 case CAIRO_FORMAT_RGB24:
117 return 24;
118 case CAIRO_FORMAT_ARGB32:
119 default:
120 return 32;
124 static xcb_render_pictforminfo_t *
125 _CAIRO_FORMAT_TO_XRENDER_FORMAT(xcb_connection_t *dpy, cairo_format_t format)
127 xcb_pict_standard_t std_format;
128 switch (format) {
129 case CAIRO_FORMAT_A1:
130 std_format = XCB_PICT_STANDARD_A_1; break;
131 case CAIRO_FORMAT_A8:
132 std_format = XCB_PICT_STANDARD_A_8; break;
133 case CAIRO_FORMAT_RGB24:
134 std_format = XCB_PICT_STANDARD_RGB_24; break;
135 case CAIRO_FORMAT_ARGB32:
136 default:
137 std_format = XCB_PICT_STANDARD_ARGB_32; break;
139 return xcb_render_util_find_standard_format (xcb_render_util_query_formats (dpy), std_format);
142 static cairo_content_t
143 _xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format)
145 cairo_bool_t xrender_format_has_alpha;
146 cairo_bool_t xrender_format_has_color;
148 /* This only happens when using a non-Render server. Let's punt
149 * and say there's no alpha here. */
150 if (xrender_format == NULL)
151 return CAIRO_CONTENT_COLOR;
153 xrender_format_has_alpha = (xrender_format->direct.alpha_mask != 0);
154 xrender_format_has_color = (xrender_format->direct.red_mask != 0 ||
155 xrender_format->direct.green_mask != 0 ||
156 xrender_format->direct.blue_mask != 0);
158 if (xrender_format_has_alpha)
159 if (xrender_format_has_color)
160 return CAIRO_CONTENT_COLOR_ALPHA;
161 else
162 return CAIRO_CONTENT_ALPHA;
163 else
164 return CAIRO_CONTENT_COLOR;
167 static cairo_surface_t *
168 _cairo_xcb_surface_create_similar (void *abstract_src,
169 cairo_content_t content,
170 int width,
171 int height)
173 cairo_xcb_surface_t *src = abstract_src;
174 xcb_connection_t *dpy = src->dpy;
175 xcb_pixmap_t pixmap;
176 cairo_xcb_surface_t *surface;
177 cairo_format_t format = _cairo_format_from_content (content);
178 xcb_render_pictforminfo_t *xrender_format;
180 /* As a good first approximation, if the display doesn't have COMPOSITE,
181 * we're better off using image surfaces for all temporary operations
183 if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
184 return cairo_image_surface_create (format, width, height);
187 pixmap = xcb_generate_id (dpy);
188 xcb_create_pixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
189 pixmap, src->drawable,
190 width <= 0 ? 1 : width,
191 height <= 0 ? 1 : height);
193 xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, format);
194 /* XXX: what to do if xrender_format is null? */
195 surface = (cairo_xcb_surface_t *)
196 cairo_xcb_surface_create_with_xrender_format (dpy, pixmap, src->screen,
197 xrender_format,
198 width, height);
199 if (surface->base.status)
200 return &surface->base;
202 surface->owns_pixmap = TRUE;
204 return &surface->base;
207 static cairo_status_t
208 _cairo_xcb_surface_finish (void *abstract_surface)
210 cairo_xcb_surface_t *surface = abstract_surface;
211 if (surface->dst_picture != XCB_NONE)
212 xcb_render_free_picture (surface->dpy, surface->dst_picture);
214 if (surface->src_picture != XCB_NONE)
215 xcb_render_free_picture (surface->dpy, surface->src_picture);
217 if (surface->owns_pixmap)
218 xcb_free_pixmap (surface->dpy, surface->drawable);
220 if (surface->gc != XCB_NONE)
221 xcb_free_gc (surface->dpy, surface->gc);
223 free (surface->clip_rects);
225 surface->dpy = NULL;
227 return CAIRO_STATUS_SUCCESS;
230 static int
231 _bits_per_pixel(xcb_connection_t *c, int depth)
233 xcb_format_t *fmt = xcb_setup_pixmap_formats(xcb_get_setup(c));
234 xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(xcb_get_setup(c));
236 for(; fmt != fmtend; ++fmt)
237 if(fmt->depth == depth)
238 return fmt->bits_per_pixel;
240 if(depth <= 4)
241 return 4;
242 if(depth <= 8)
243 return 8;
244 if(depth <= 16)
245 return 16;
246 return 32;
249 static int
250 _bytes_per_line(xcb_connection_t *c, int width, int bpp)
252 int bitmap_pad = xcb_get_setup(c)->bitmap_format_scanline_pad;
253 return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
256 static cairo_bool_t
257 _CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
259 switch (masks->bpp) {
260 case 32:
261 if (masks->alpha_mask == 0xff000000 &&
262 masks->red_mask == 0x00ff0000 &&
263 masks->green_mask == 0x0000ff00 &&
264 masks->blue_mask == 0x000000ff)
266 *format = CAIRO_FORMAT_ARGB32;
267 return TRUE;
269 if (masks->alpha_mask == 0x00000000 &&
270 masks->red_mask == 0x00ff0000 &&
271 masks->green_mask == 0x0000ff00 &&
272 masks->blue_mask == 0x000000ff)
274 *format = CAIRO_FORMAT_RGB24;
275 return TRUE;
277 break;
278 case 8:
279 if (masks->alpha_mask == 0xff)
281 *format = CAIRO_FORMAT_A8;
282 return TRUE;
284 break;
285 case 1:
286 if (masks->alpha_mask == 0x1)
288 *format = CAIRO_FORMAT_A1;
289 return TRUE;
291 break;
293 return FALSE;
296 static cairo_status_t
297 _get_image_surface (cairo_xcb_surface_t *surface,
298 cairo_rectangle_int_t *interest_rect,
299 cairo_image_surface_t **image_out,
300 cairo_rectangle_int_t *image_rect)
302 cairo_image_surface_t *image;
303 xcb_get_image_reply_t *imagerep;
304 int bpp, bytes_per_line;
305 cairo_rectangle_int_t extents;
306 unsigned char *data;
307 cairo_format_masks_t masks;
308 cairo_format_t format;
310 extents.x = 0;
311 extents.y = 0;
312 extents.width = surface->width;
313 extents.height = surface->height;
315 if (interest_rect) {
316 if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
317 *image_out = NULL;
318 return CAIRO_STATUS_SUCCESS;
322 if (image_rect)
323 *image_rect = extents;
325 /* XXX: This should try to use the XShm extension if available */
327 if (surface->use_pixmap == 0)
329 xcb_generic_error_t *error;
330 imagerep = xcb_get_image_reply(surface->dpy,
331 xcb_get_image(surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
332 surface->drawable,
333 extents.x, extents.y,
334 extents.width, extents.height,
335 AllPlanes), &error);
337 /* If we get an error, the surface must have been a window,
338 * so retry with the safe code path.
340 if (error)
341 surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
343 else
345 surface->use_pixmap--;
346 imagerep = NULL;
349 if (!imagerep)
351 /* xcb_get_image_t from a window is dangerous because it can
352 * produce errors if the window is unmapped or partially
353 * outside the screen. We could check for errors and
354 * retry, but to keep things simple, we just create a
355 * temporary pixmap
357 xcb_pixmap_t pixmap;
358 pixmap = xcb_generate_id (surface->dpy);
359 xcb_create_pixmap (surface->dpy,
360 surface->depth,
361 pixmap,
362 surface->drawable,
363 extents.width, extents.height);
364 _cairo_xcb_surface_ensure_gc (surface);
366 xcb_copy_area (surface->dpy, surface->drawable, pixmap, surface->gc,
367 extents.x, extents.y, 0, 0, extents.width, extents.height);
369 imagerep = xcb_get_image_reply(surface->dpy,
370 xcb_get_image(surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
371 pixmap,
372 extents.x, extents.y,
373 extents.width, extents.height,
374 AllPlanes), 0);
375 xcb_free_pixmap (surface->dpy, pixmap);
378 if (!imagerep)
379 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
381 bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
382 bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
384 data = _cairo_malloc_ab (surface->height, bytes_per_line);
385 if (data == NULL) {
386 free (imagerep);
387 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
390 memcpy (data, xcb_get_image_data (imagerep), bytes_per_line * surface->height);
391 free (imagerep);
394 * Compute the pixel format masks from either an xcb_visualtype_t or
395 * a xcb_render_pctforminfo_t, failing we assume the drawable is an
396 * alpha-only pixmap as it could only have been created that way
397 * through the cairo_xlib_surface_create_for_bitmap function.
399 if (surface->visual) {
400 masks.bpp = bpp;
401 masks.alpha_mask = 0;
402 masks.red_mask = surface->visual->red_mask;
403 masks.green_mask = surface->visual->green_mask;
404 masks.blue_mask = surface->visual->blue_mask;
405 } else if (surface->xrender_format.id != XCB_NONE) {
406 masks.bpp = bpp;
407 masks.red_mask = (unsigned long)surface->xrender_format.direct.red_mask << surface->xrender_format.direct.red_shift;
408 masks.green_mask = (unsigned long)surface->xrender_format.direct.green_mask << surface->xrender_format.direct.green_shift;
409 masks.blue_mask = (unsigned long)surface->xrender_format.direct.blue_mask << surface->xrender_format.direct.blue_shift;
410 masks.alpha_mask = (unsigned long)surface->xrender_format.direct.alpha_mask << surface->xrender_format.direct.alpha_shift;
411 } else {
412 masks.bpp = bpp;
413 masks.red_mask = 0;
414 masks.green_mask = 0;
415 masks.blue_mask = 0;
416 if (surface->depth < 32)
417 masks.alpha_mask = (1 << surface->depth) - 1;
418 else
419 masks.alpha_mask = 0xffffffff;
423 * Prefer to use a standard pixman format instead of the
424 * general masks case.
426 if (_CAIRO_MASK_FORMAT (&masks, &format)) {
427 image = (cairo_image_surface_t *)
428 cairo_image_surface_create_for_data (data,
429 format,
430 extents.width,
431 extents.height,
432 bytes_per_line);
433 if (image->base.status)
434 goto FAIL;
435 } else {
437 * XXX This can't work. We must convert the data to one of the
438 * supported pixman formats. Pixman needs another function
439 * which takes data in an arbitrary format and converts it
440 * to something supported by that library.
442 image = (cairo_image_surface_t *)
443 _cairo_image_surface_create_with_masks (data,
444 &masks,
445 extents.width,
446 extents.height,
447 bytes_per_line);
448 if (image->base.status)
449 goto FAIL;
452 /* Let the surface take ownership of the data */
453 _cairo_image_surface_assume_ownership_of_data (image);
455 *image_out = image;
456 return CAIRO_STATUS_SUCCESS;
458 FAIL:
459 free (data);
460 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
463 static void
464 _cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface)
466 if (!surface->src_picture) {
467 surface->src_picture = xcb_generate_id(surface->dpy);
468 xcb_render_create_picture (surface->dpy,
469 surface->src_picture,
470 surface->drawable,
471 surface->xrender_format.id,
472 0, NULL);
476 static void
477 _cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
479 if (surface->have_clip_rects)
480 xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture,
481 0, 0,
482 surface->num_clip_rects,
483 surface->clip_rects);
486 static void
487 _cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
489 if (surface->have_clip_rects)
490 xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
491 0, 0,
492 surface->num_clip_rects,
493 surface->clip_rects );
496 static void
497 _cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface)
499 if (!surface->dst_picture) {
500 surface->dst_picture = xcb_generate_id(surface->dpy);
501 xcb_render_create_picture (surface->dpy,
502 surface->dst_picture,
503 surface->drawable,
504 surface->xrender_format.id,
505 0, NULL);
506 _cairo_xcb_surface_set_picture_clip_rects (surface);
511 static void
512 _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
514 if (surface->gc)
515 return;
517 surface->gc = xcb_generate_id(surface->dpy);
518 xcb_create_gc (surface->dpy, surface->gc, surface->drawable, 0, 0);
519 _cairo_xcb_surface_set_gc_clip_rects(surface);
522 static cairo_status_t
523 _draw_image_surface (cairo_xcb_surface_t *surface,
524 cairo_image_surface_t *image,
525 int src_x,
526 int src_y,
527 int width,
528 int height,
529 int dst_x,
530 int dst_y)
532 int bpp, bpl;
533 uint32_t data_len;
534 uint8_t *data, left_pad=0;
536 /* equivalent of XPutImage(..., src_x,src_y, dst_x,dst_y, width,height); */
537 /* XXX: assumes image and surface formats and depths are the same */
538 /* XXX: assumes depth is a multiple of 8 (not bitmap) */
540 /* fit src_{x,y,width,height} within image->{0,0,width,height} */
541 if (src_x < 0) {
542 width += src_x;
543 src_x = 0;
545 if (src_y < 0) {
546 height += src_y;
547 src_y = 0;
549 if (width + src_x > image->width)
550 width = image->width - src_x;
551 if (height + src_y > image->height)
552 height = image->height - src_y;
553 if (width <= 0 || height <= 0)
554 return CAIRO_STATUS_SUCCESS;
556 bpp = _bits_per_pixel(surface->dpy, image->depth);
557 /* XXX: could use bpl = image->stride? */
558 bpl = _bytes_per_line(surface->dpy, image->width, bpp);
560 if (src_x == 0 && width == image->width) {
561 /* can work in-place */
562 data_len = height * bpl;
563 data = image->data + src_y * bpl;
564 } else {
565 /* must copy {src_x,src_y,width,height} into new data */
566 int line = 0;
567 uint8_t *data_line, *image_line;
568 int data_bpl = _bytes_per_line(surface->dpy, width, bpp);
569 data_len = height * data_bpl;
570 data_line = data = malloc(data_len);
571 if (data == NULL)
572 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
574 image_line = image->data + src_y * bpl + (src_x * bpp / 8);
575 while (line++ < height) {
576 memcpy(data_line, image_line, data_bpl);
577 data_line += data_bpl;
578 image_line += bpl;
581 _cairo_xcb_surface_ensure_gc (surface);
582 xcb_put_image (surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
583 surface->drawable, surface->gc,
584 width, height,
585 dst_x, dst_y,
586 left_pad, image->depth,
587 data_len, data);
589 if (data < image->data || data >= image->data + image->height * bpl)
590 free(data);
592 return CAIRO_STATUS_SUCCESS;
595 static cairo_status_t
596 _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
597 cairo_image_surface_t **image_out,
598 void **image_extra)
600 cairo_xcb_surface_t *surface = abstract_surface;
601 cairo_image_surface_t *image;
602 cairo_status_t status;
604 status = _get_image_surface (surface, NULL, &image, NULL);
605 if (status)
606 return status;
608 *image_out = image;
609 *image_extra = NULL;
611 return CAIRO_STATUS_SUCCESS;
614 static void
615 _cairo_xcb_surface_release_source_image (void *abstract_surface,
616 cairo_image_surface_t *image,
617 void *image_extra)
619 cairo_surface_destroy (&image->base);
622 static cairo_status_t
623 _cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
624 cairo_rectangle_int_t *interest_rect,
625 cairo_image_surface_t **image_out,
626 cairo_rectangle_int_t *image_rect_out,
627 void **image_extra)
629 cairo_xcb_surface_t *surface = abstract_surface;
630 cairo_image_surface_t *image;
631 cairo_status_t status;
633 status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
634 if (status)
635 return status;
637 *image_out = image;
638 *image_extra = NULL;
640 return CAIRO_STATUS_SUCCESS;
643 static void
644 _cairo_xcb_surface_release_dest_image (void *abstract_surface,
645 cairo_rectangle_int_t *interest_rect,
646 cairo_image_surface_t *image,
647 cairo_rectangle_int_t *image_rect,
648 void *image_extra)
650 cairo_xcb_surface_t *surface = abstract_surface;
652 /* ignore errors */
653 _draw_image_surface (surface, image, 0, 0, image->width, image->height,
654 image_rect->x, image_rect->y);
656 cairo_surface_destroy (&image->base);
660 * Return whether two xcb surfaces share the same
661 * screen. Both core and Render drawing require this
662 * when using multiple drawables in an operation.
664 static cairo_bool_t
665 _cairo_xcb_surface_same_screen (cairo_xcb_surface_t *dst,
666 cairo_xcb_surface_t *src)
668 return dst->dpy == src->dpy && dst->screen == src->screen;
671 static cairo_status_t
672 _cairo_xcb_surface_clone_similar (void *abstract_surface,
673 cairo_surface_t *src,
674 int src_x,
675 int src_y,
676 int width,
677 int height,
678 int *clone_offset_x,
679 int *clone_offset_y,
680 cairo_surface_t **clone_out)
682 cairo_xcb_surface_t *surface = abstract_surface;
683 cairo_xcb_surface_t *clone;
685 if (src->backend == surface->base.backend ) {
686 cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
688 if (_cairo_xcb_surface_same_screen(surface, xcb_src)) {
689 *clone_offset_x = 0;
690 *clone_offset_y = 0;
691 *clone_out = cairo_surface_reference (src);
693 return CAIRO_STATUS_SUCCESS;
695 } else if (_cairo_surface_is_image (src)) {
696 cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
697 cairo_content_t content = _cairo_content_from_format (image_src->format);
698 cairo_status_t status;
700 if (surface->base.status)
701 return surface->base.status;
703 clone = (cairo_xcb_surface_t *)
704 _cairo_xcb_surface_create_similar (surface, content, width, height);
705 if (clone == NULL)
706 return CAIRO_INT_STATUS_UNSUPPORTED;
707 if (clone->base.status)
708 return clone->base.status;
710 status = _draw_image_surface (clone, image_src,
711 src_x, src_y,
712 width, height,
713 0, 0);
714 if (status) {
715 cairo_surface_destroy (&clone->base);
716 return status;
719 *clone_offset_x = src_x;
720 *clone_offset_y = src_y;
721 *clone_out = &clone->base;
723 return CAIRO_STATUS_SUCCESS;
726 return CAIRO_INT_STATUS_UNSUPPORTED;
729 static cairo_status_t
730 _cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
731 cairo_matrix_t *matrix)
733 xcb_render_transform_t xtransform;
735 if (!surface->src_picture)
736 return CAIRO_STATUS_SUCCESS;
738 xtransform.matrix11 = _cairo_fixed_16_16_from_double (matrix->xx);
739 xtransform.matrix12 = _cairo_fixed_16_16_from_double (matrix->xy);
740 xtransform.matrix13 = _cairo_fixed_16_16_from_double (matrix->x0);
742 xtransform.matrix21 = _cairo_fixed_16_16_from_double (matrix->yx);
743 xtransform.matrix22 = _cairo_fixed_16_16_from_double (matrix->yy);
744 xtransform.matrix23 = _cairo_fixed_16_16_from_double (matrix->y0);
746 xtransform.matrix31 = 0;
747 xtransform.matrix32 = 0;
748 xtransform.matrix33 = 1 << 16;
750 if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
752 static const xcb_render_transform_t identity = {
753 1 << 16, 0x00000, 0x00000,
754 0x00000, 1 << 16, 0x00000,
755 0x00000, 0x00000, 1 << 16
758 if (memcmp (&xtransform, &identity, sizeof (xcb_render_transform_t)) == 0)
759 return CAIRO_STATUS_SUCCESS;
761 return CAIRO_INT_STATUS_UNSUPPORTED;
764 xcb_render_set_picture_transform (surface->dpy, surface->src_picture, xtransform);
766 return CAIRO_STATUS_SUCCESS;
769 static cairo_status_t
770 _cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
771 cairo_filter_t filter)
773 const char *render_filter;
775 if (!surface->src_picture)
776 return CAIRO_STATUS_SUCCESS;
778 if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
780 if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
781 return CAIRO_STATUS_SUCCESS;
783 return CAIRO_INT_STATUS_UNSUPPORTED;
786 switch (filter) {
787 case CAIRO_FILTER_FAST:
788 render_filter = "fast";
789 break;
790 case CAIRO_FILTER_GOOD:
791 render_filter = "good";
792 break;
793 case CAIRO_FILTER_BEST:
794 render_filter = "best";
795 break;
796 case CAIRO_FILTER_NEAREST:
797 render_filter = "nearest";
798 break;
799 case CAIRO_FILTER_BILINEAR:
800 render_filter = "bilinear";
801 break;
802 case CAIRO_FILTER_GAUSSIAN:
803 default:
804 render_filter = "best";
805 break;
808 xcb_render_set_picture_filter(surface->dpy, surface->src_picture,
809 strlen(render_filter), render_filter, 0, NULL);
811 return CAIRO_STATUS_SUCCESS;
814 static cairo_status_t
815 _cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
817 uint32_t mask = XCB_RENDER_CP_REPEAT;
818 uint32_t pa[] = { repeat };
820 if (!surface->src_picture)
821 return CAIRO_STATUS_SUCCESS;
823 xcb_render_change_picture (surface->dpy, surface->src_picture, mask, pa);
825 return CAIRO_STATUS_SUCCESS;
828 static cairo_int_status_t
829 _cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
830 cairo_surface_attributes_t *attributes)
832 cairo_int_status_t status;
834 _cairo_xcb_surface_ensure_src_picture (surface);
836 status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
837 if (status)
838 return status;
840 switch (attributes->extend) {
841 case CAIRO_EXTEND_NONE:
842 _cairo_xcb_surface_set_repeat (surface, 0);
843 break;
844 case CAIRO_EXTEND_REPEAT:
845 _cairo_xcb_surface_set_repeat (surface, 1);
846 break;
847 case CAIRO_EXTEND_REFLECT:
848 case CAIRO_EXTEND_PAD:
849 return CAIRO_INT_STATUS_UNSUPPORTED;
852 status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
853 if (status)
854 return status;
856 return CAIRO_STATUS_SUCCESS;
859 /* Checks whether we can can directly draw from src to dst with
860 * the core protocol: either with CopyArea or using src as a
861 * a tile in a GC.
863 static cairo_bool_t
864 _surfaces_compatible (cairo_xcb_surface_t *dst,
865 cairo_xcb_surface_t *src)
867 /* same screen */
868 if (!_cairo_xcb_surface_same_screen (dst, src))
869 return FALSE;
871 /* same depth (for core) */
872 if (src->depth != dst->depth)
873 return FALSE;
875 /* if Render is supported, match picture formats */
876 if (src->xrender_format.id != dst->xrender_format.id)
877 return FALSE;
878 else if (src->xrender_format.id != XCB_NONE)
879 return TRUE;
881 /* Without Render, match visuals instead */
882 if (src->visual == dst->visual)
883 return TRUE;
885 return FALSE;
888 static cairo_bool_t
889 _surface_has_alpha (cairo_xcb_surface_t *surface)
891 if (surface->xrender_format.id != XCB_NONE) {
892 if (surface->xrender_format.type == XCB_RENDER_PICT_TYPE_DIRECT &&
893 surface->xrender_format.direct.alpha_mask != 0)
894 return TRUE;
895 else
896 return FALSE;
897 } else {
899 /* In the no-render case, we never have alpha */
900 return FALSE;
904 /* Returns true if the given operator and source-alpha combination
905 * requires alpha compositing to complete.
907 static cairo_bool_t
908 _operator_needs_alpha_composite (cairo_operator_t op,
909 cairo_bool_t surface_has_alpha)
911 if (op == CAIRO_OPERATOR_SOURCE ||
912 (!surface_has_alpha &&
913 (op == CAIRO_OPERATOR_OVER ||
914 op == CAIRO_OPERATOR_ATOP ||
915 op == CAIRO_OPERATOR_IN)))
916 return FALSE;
918 return TRUE;
921 /* There is a bug in most older X servers with compositing using a
922 * untransformed repeating source pattern when the source is in off-screen
923 * video memory, and another with repeated transformed images using a
924 * general transform matrix. When these bugs could be triggered, we need a
925 * fallback: in the common case where we have no transformation and the
926 * source and destination have the same format/visual, we can do the
927 * operation using the core protocol for the first bug, otherwise, we need
928 * a software fallback.
930 * We can also often optimize a compositing operation by calling XCopyArea
931 * for some common cases where there is no alpha compositing to be done.
932 * We figure that out here as well.
934 typedef enum {
935 DO_RENDER, /* use render */
936 DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */
937 DO_XTILE, /* core protocol XSetTile optimization/fallback */
938 DO_UNSUPPORTED /* software fallback */
939 } composite_operation_t;
941 /* Initial check for the render bugs; we need to recheck for the
942 * offscreen-memory bug after we turn patterns into surfaces, since that
943 * may introduce a repeating pattern for gradient patterns. We don't need
944 * to check for the repeat+transform bug because gradient surfaces aren't
945 * transformed.
947 * All we do here is reject cases where we *know* are going to
948 * hit the bug and won't be able to use a core protocol fallback.
950 static composite_operation_t
951 _categorize_composite_operation (cairo_xcb_surface_t *dst,
952 cairo_operator_t op,
953 cairo_pattern_t *src_pattern,
954 cairo_bool_t have_mask)
957 #if XXX_BUGGY_REPEAT
958 if (!dst->buggy_repeat)
959 return DO_RENDER;
961 if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
963 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
965 if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
966 src_pattern->extend == CAIRO_EXTEND_REPEAT)
968 /* This is the case where we have the bug involving
969 * untransformed repeating source patterns with off-screen
970 * video memory; reject some cases where a core protocol
971 * fallback is impossible.
973 if (have_mask ||
974 !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
975 return DO_UNSUPPORTED;
977 if (_cairo_surface_is_xcb (surface_pattern->surface)) {
978 cairo_xcb_surface_t *src = (cairo_xcb_surface_t *)surface_pattern->surface;
980 if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
981 return DO_UNSUPPORTED;
983 /* If these are on the same screen but otherwise incompatible,
984 * make a copy as core drawing can't cross depths and doesn't
985 * work rightacross visuals of the same depth
987 if (_cairo_xcb_surface_same_screen (dst, src) &&
988 !_surfaces_compatible (dst, src))
989 return DO_UNSUPPORTED;
993 /* Check for the other bug involving repeat patterns with general
994 * transforms. */
995 if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
996 src_pattern->extend == CAIRO_EXTEND_REPEAT)
997 return DO_UNSUPPORTED;
999 #endif
1000 return DO_RENDER;
1003 /* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
1004 * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
1005 * did to turn gradients into a pattern, but most of the time we can handle
1006 * that case with core protocol fallback.
1008 * Also check here if we can just use XCopyArea, instead of going through
1009 * Render.
1011 static composite_operation_t
1012 _recategorize_composite_operation (cairo_xcb_surface_t *dst,
1013 cairo_operator_t op,
1014 cairo_xcb_surface_t *src,
1015 cairo_surface_attributes_t *src_attr,
1016 cairo_bool_t have_mask)
1018 cairo_bool_t is_integer_translation =
1019 _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
1020 cairo_bool_t needs_alpha_composite =
1021 _operator_needs_alpha_composite (op, _surface_has_alpha (src));
1023 if (!have_mask &&
1024 is_integer_translation &&
1025 src_attr->extend == CAIRO_EXTEND_NONE &&
1026 !needs_alpha_composite &&
1027 _surfaces_compatible(src, dst))
1029 return DO_XCOPYAREA;
1031 #if XXX_BUGGY_REPEAT
1032 if (!dst->buggy_repeat)
1033 return DO_RENDER;
1035 if (is_integer_translation &&
1036 src_attr->extend == CAIRO_EXTEND_REPEAT &&
1037 (src->width != 1 || src->height != 1))
1039 if (!have_mask &&
1040 !needs_alpha_composite &&
1041 _surfaces_compatible (dst, src))
1043 return DO_XTILE;
1046 return DO_UNSUPPORTED;
1048 #endif
1049 return DO_RENDER;
1052 static int
1053 _render_operator (cairo_operator_t op)
1055 switch (op) {
1056 case CAIRO_OPERATOR_CLEAR:
1057 return XCB_RENDER_PICT_OP_CLEAR;
1058 case CAIRO_OPERATOR_SOURCE:
1059 return XCB_RENDER_PICT_OP_SRC;
1060 case CAIRO_OPERATOR_DEST:
1061 return XCB_RENDER_PICT_OP_DST;
1062 case CAIRO_OPERATOR_OVER:
1063 return XCB_RENDER_PICT_OP_OVER;
1064 case CAIRO_OPERATOR_DEST_OVER:
1065 return XCB_RENDER_PICT_OP_OVER_REVERSE;
1066 case CAIRO_OPERATOR_IN:
1067 return XCB_RENDER_PICT_OP_IN;
1068 case CAIRO_OPERATOR_DEST_IN:
1069 return XCB_RENDER_PICT_OP_IN_REVERSE;
1070 case CAIRO_OPERATOR_OUT:
1071 return XCB_RENDER_PICT_OP_OUT;
1072 case CAIRO_OPERATOR_DEST_OUT:
1073 return XCB_RENDER_PICT_OP_OUT_REVERSE;
1074 case CAIRO_OPERATOR_ATOP:
1075 return XCB_RENDER_PICT_OP_ATOP;
1076 case CAIRO_OPERATOR_DEST_ATOP:
1077 return XCB_RENDER_PICT_OP_ATOP_REVERSE;
1078 case CAIRO_OPERATOR_XOR:
1079 return XCB_RENDER_PICT_OP_XOR;
1080 case CAIRO_OPERATOR_ADD:
1081 return XCB_RENDER_PICT_OP_ADD;
1082 case CAIRO_OPERATOR_SATURATE:
1083 return XCB_RENDER_PICT_OP_SATURATE;
1084 default:
1085 return XCB_RENDER_PICT_OP_OVER;
1089 static cairo_int_status_t
1090 _cairo_xcb_surface_composite (cairo_operator_t op,
1091 cairo_pattern_t *src_pattern,
1092 cairo_pattern_t *mask_pattern,
1093 void *abstract_dst,
1094 int src_x,
1095 int src_y,
1096 int mask_x,
1097 int mask_y,
1098 int dst_x,
1099 int dst_y,
1100 unsigned int width,
1101 unsigned int height)
1103 cairo_surface_attributes_t src_attr, mask_attr;
1104 cairo_xcb_surface_t *dst = abstract_dst;
1105 cairo_xcb_surface_t *src;
1106 cairo_xcb_surface_t *mask;
1107 cairo_int_status_t status;
1108 composite_operation_t operation;
1109 int itx, ity;
1110 cairo_bool_t is_integer_translation;
1112 if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
1113 return CAIRO_INT_STATUS_UNSUPPORTED;
1115 operation = _categorize_composite_operation (dst, op, src_pattern,
1116 mask_pattern != NULL);
1117 if (operation == DO_UNSUPPORTED)
1118 return CAIRO_INT_STATUS_UNSUPPORTED;
1120 status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
1121 &dst->base,
1122 src_x, src_y,
1123 mask_x, mask_y,
1124 width, height,
1125 (cairo_surface_t **) &src,
1126 (cairo_surface_t **) &mask,
1127 &src_attr, &mask_attr);
1128 if (status)
1129 return status;
1131 operation = _recategorize_composite_operation (dst, op, src, &src_attr,
1132 mask_pattern != NULL);
1133 if (operation == DO_UNSUPPORTED) {
1134 status = CAIRO_INT_STATUS_UNSUPPORTED;
1135 goto BAIL;
1138 status = _cairo_xcb_surface_set_attributes (src, &src_attr);
1139 if (status)
1140 goto BAIL;
1142 switch (operation)
1144 case DO_RENDER:
1145 _cairo_xcb_surface_ensure_dst_picture (dst);
1146 if (mask) {
1147 status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
1148 if (status)
1149 goto BAIL;
1151 xcb_render_composite (dst->dpy,
1152 _render_operator (op),
1153 src->src_picture,
1154 mask->src_picture,
1155 dst->dst_picture,
1156 src_x + src_attr.x_offset,
1157 src_y + src_attr.y_offset,
1158 mask_x + mask_attr.x_offset,
1159 mask_y + mask_attr.y_offset,
1160 dst_x, dst_y,
1161 width, height);
1162 } else {
1163 static xcb_render_picture_t maskpict = { XCB_NONE };
1165 xcb_render_composite (dst->dpy,
1166 _render_operator (op),
1167 src->src_picture,
1168 maskpict,
1169 dst->dst_picture,
1170 src_x + src_attr.x_offset,
1171 src_y + src_attr.y_offset,
1172 0, 0,
1173 dst_x, dst_y,
1174 width, height);
1176 break;
1178 case DO_XCOPYAREA:
1179 _cairo_xcb_surface_ensure_gc (dst);
1180 xcb_copy_area (dst->dpy,
1181 src->drawable,
1182 dst->drawable,
1183 dst->gc,
1184 src_x + src_attr.x_offset,
1185 src_y + src_attr.y_offset,
1186 dst_x, dst_y,
1187 width, height);
1188 break;
1190 case DO_XTILE:
1191 /* This case is only used for bug fallbacks, though it is theoretically
1192 * applicable to the case where we don't have the RENDER extension as
1193 * well.
1195 * We've checked that we have a repeating unscaled source in
1196 * _recategorize_composite_operation.
1199 _cairo_xcb_surface_ensure_gc (dst);
1200 is_integer_translation =
1201 _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
1202 assert (is_integer_translation == TRUE);
1204 uint32_t mask = XCB_GC_FILL_STYLE | XCB_GC_TILE
1205 | XCB_GC_TILE_STIPPLE_ORIGIN_X
1206 | XCB_GC_TILE_STIPPLE_ORIGIN_Y;
1207 uint32_t values[] = {
1208 XCB_FILL_STYLE_TILED, src->drawable,
1209 - (itx + src_attr.x_offset),
1210 - (ity + src_attr.y_offset)
1212 xcb_rectangle_t rect = { dst_x, dst_y, width, height };
1214 xcb_change_gc( dst->dpy, dst->gc, mask, values );
1215 xcb_poly_fill_rectangle(dst->dpy, dst->drawable, dst->gc, 1, &rect);
1217 break;
1219 case DO_UNSUPPORTED:
1220 default:
1221 ASSERT_NOT_REACHED;
1224 if (!_cairo_operator_bounded_by_source (op))
1225 status = _cairo_surface_composite_fixup_unbounded (&dst->base,
1226 &src_attr, src->width, src->height,
1227 mask ? &mask_attr : NULL,
1228 mask ? mask->width : 0,
1229 mask ? mask->height : 0,
1230 src_x, src_y,
1231 mask_x, mask_y,
1232 dst_x, dst_y, width, height);
1234 BAIL:
1235 if (mask)
1236 _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
1238 _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
1240 return status;
1243 static cairo_int_status_t
1244 _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
1245 cairo_operator_t op,
1246 const cairo_color_t * color,
1247 cairo_rectangle_int_t *rects,
1248 int num_rects)
1250 cairo_xcb_surface_t *surface = abstract_surface;
1251 xcb_render_color_t render_color;
1252 xcb_rectangle_t static_xrects[16];
1253 xcb_rectangle_t *xrects = static_xrects;
1254 int i;
1256 if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
1257 return CAIRO_INT_STATUS_UNSUPPORTED;
1259 render_color.red = color->red_short;
1260 render_color.green = color->green_short;
1261 render_color.blue = color->blue_short;
1262 render_color.alpha = color->alpha_short;
1264 if (num_rects > ARRAY_LENGTH(static_xrects)) {
1265 xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t));
1266 if (xrects == NULL)
1267 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1270 for (i = 0; i < num_rects; i++) {
1271 xrects[i].x = rects[i].x;
1272 xrects[i].y = rects[i].y;
1273 xrects[i].width = rects[i].width;
1274 xrects[i].height = rects[i].height;
1277 _cairo_xcb_surface_ensure_dst_picture (surface);
1278 xcb_render_fill_rectangles (surface->dpy,
1279 _render_operator (op),
1280 surface->dst_picture,
1281 render_color, num_rects, xrects);
1283 if (xrects != static_xrects)
1284 free(xrects);
1286 return CAIRO_STATUS_SUCCESS;
1289 /* Creates an A8 picture of size @width x @height, initialized with @color
1291 static xcb_render_picture_t
1292 _create_a8_picture (cairo_xcb_surface_t *surface,
1293 xcb_render_color_t *color,
1294 int width,
1295 int height,
1296 cairo_bool_t repeat)
1298 uint32_t values[] = { TRUE };
1299 uint32_t mask = repeat ? XCB_RENDER_CP_REPEAT : 0;
1301 xcb_pixmap_t pixmap = xcb_generate_id (surface->dpy);
1302 xcb_render_picture_t picture = xcb_generate_id (surface->dpy);
1304 xcb_render_pictforminfo_t *format
1305 = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8);
1306 xcb_rectangle_t rect = { 0, 0, width, height };
1308 xcb_create_pixmap (surface->dpy, 8, pixmap, surface->drawable,
1309 width <= 0 ? 1 : width,
1310 height <= 0 ? 1 : height);
1311 xcb_render_create_picture (surface->dpy, picture, pixmap, format->id, mask, values);
1312 xcb_render_fill_rectangles (surface->dpy, XCB_RENDER_PICT_OP_SRC, picture, *color, 1, &rect);
1313 xcb_free_pixmap (surface->dpy, pixmap);
1315 return picture;
1318 /* Creates a temporary mask for the trapezoids covering the area
1319 * [@dst_x, @dst_y, @width, @height] of the destination surface.
1321 static cairo_status_t
1322 _create_trapezoid_mask (cairo_xcb_surface_t *dst,
1323 cairo_trapezoid_t *traps,
1324 int num_traps,
1325 int dst_x,
1326 int dst_y,
1327 int width,
1328 int height,
1329 xcb_render_pictforminfo_t *pict_format,
1330 xcb_render_picture_t *mask_picture_out)
1332 xcb_render_color_t transparent = { 0, 0, 0, 0 };
1333 xcb_render_color_t solid = { 0xffff, 0xffff, 0xffff, 0xffff };
1334 xcb_render_picture_t mask_picture, solid_picture;
1335 xcb_render_trapezoid_t *offset_traps;
1336 int i;
1338 /* This would be considerably simpler using XRenderAddTraps(), but since
1339 * we are only using this in the unbounded-operator case, we stick with
1340 * XRenderCompositeTrapezoids, which is available on older versions
1341 * of RENDER rather than conditionalizing. We should still hit an
1342 * optimization that avoids creating another intermediate surface on
1343 * the servers that have XRenderAddTraps().
1345 mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
1346 solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
1348 offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t));
1349 if (offset_traps == NULL)
1350 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1352 for (i = 0; i < num_traps; i++) {
1353 offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
1354 offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y;
1355 offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x;
1356 offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y;
1357 offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x;
1358 offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y;
1359 offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x;
1360 offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y;
1361 offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x;
1362 offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y;
1365 xcb_render_trapezoids (dst->dpy, XCB_RENDER_PICT_OP_ADD,
1366 solid_picture, mask_picture,
1367 pict_format->id,
1368 0, 0,
1369 num_traps, offset_traps);
1371 xcb_render_free_picture (dst->dpy, solid_picture);
1372 free (offset_traps);
1374 *mask_picture_out = mask_picture;
1375 return CAIRO_STATUS_SUCCESS;
1378 static cairo_int_status_t
1379 _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
1380 cairo_pattern_t *pattern,
1381 void *abstract_dst,
1382 cairo_antialias_t antialias,
1383 int src_x,
1384 int src_y,
1385 int dst_x,
1386 int dst_y,
1387 unsigned int width,
1388 unsigned int height,
1389 cairo_trapezoid_t *traps,
1390 int num_traps)
1392 cairo_surface_attributes_t attributes;
1393 cairo_xcb_surface_t *dst = abstract_dst;
1394 cairo_xcb_surface_t *src;
1395 cairo_int_status_t status;
1396 composite_operation_t operation;
1397 int render_reference_x, render_reference_y;
1398 int render_src_x, render_src_y;
1399 int cairo_format;
1400 xcb_render_pictforminfo_t *render_format;
1402 if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
1403 return CAIRO_INT_STATUS_UNSUPPORTED;
1405 operation = _categorize_composite_operation (dst, op, pattern, TRUE);
1406 if (operation == DO_UNSUPPORTED)
1407 return CAIRO_INT_STATUS_UNSUPPORTED;
1409 status = _cairo_pattern_acquire_surface (pattern, &dst->base,
1410 src_x, src_y, width, height,
1411 (cairo_surface_t **) &src,
1412 &attributes);
1413 if (status)
1414 return status;
1416 operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
1417 if (operation == DO_UNSUPPORTED) {
1418 status = CAIRO_INT_STATUS_UNSUPPORTED;
1419 goto BAIL;
1422 switch (antialias) {
1423 case CAIRO_ANTIALIAS_NONE:
1424 cairo_format = CAIRO_FORMAT_A1;
1425 break;
1426 case CAIRO_ANTIALIAS_GRAY:
1427 case CAIRO_ANTIALIAS_SUBPIXEL:
1428 case CAIRO_ANTIALIAS_DEFAULT:
1429 default:
1430 cairo_format = CAIRO_FORMAT_A8;
1431 break;
1433 render_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dst->dpy, cairo_format);
1434 /* XXX: what to do if render_format is null? */
1436 if (traps[0].left.p1.y < traps[0].left.p2.y) {
1437 render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
1438 render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
1439 } else {
1440 render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
1441 render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
1444 render_src_x = src_x + render_reference_x - dst_x;
1445 render_src_y = src_y + render_reference_y - dst_y;
1447 _cairo_xcb_surface_ensure_dst_picture (dst);
1448 status = _cairo_xcb_surface_set_attributes (src, &attributes);
1449 if (status)
1450 goto BAIL;
1452 if (!_cairo_operator_bounded_by_mask (op)) {
1453 /* xcb_render_composite+trapezoids() creates a mask only large enough for the
1454 * trapezoids themselves, but if the operator is unbounded, then we need
1455 * to actually composite all the way out to the bounds, so we create
1456 * the mask and composite ourselves. There actually would
1457 * be benefit to doing this in all cases, since RENDER implementations
1458 * will frequently create a too temporary big mask, ignoring destination
1459 * bounds and clip. (xcb_render_add_traps() could be used to make creating
1460 * the mask somewhat cheaper.)
1462 xcb_render_picture_t mask_picture = 0; /* silence compiler */
1464 status = _create_trapezoid_mask (dst, traps, num_traps,
1465 dst_x, dst_y, width, height,
1466 render_format,
1467 &mask_picture);
1468 if (status)
1469 goto BAIL;
1471 xcb_render_composite (dst->dpy,
1472 _render_operator (op),
1473 src->src_picture,
1474 mask_picture,
1475 dst->dst_picture,
1476 src_x + attributes.x_offset,
1477 src_y + attributes.y_offset,
1478 0, 0,
1479 dst_x, dst_y,
1480 width, height);
1482 xcb_render_free_picture (dst->dpy, mask_picture);
1484 status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
1485 &attributes, src->width, src->height,
1486 width, height,
1487 src_x, src_y,
1488 0, 0,
1489 dst_x, dst_y, width, height);
1491 } else {
1492 xcb_render_trapezoid_t xtraps_stack[16];
1493 xcb_render_trapezoid_t *xtraps = xtraps_stack;
1494 int i;
1496 if (num_traps > ARRAY_LENGTH(xtraps_stack)) {
1497 xtraps = _cairo_malloc_ab (num_traps, sizeof(xcb_render_trapezoid_t));
1498 if (xtraps == NULL) {
1499 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1500 goto BAIL;
1504 for (i = 0; i < num_traps; i++) {
1505 xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
1506 xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
1507 xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
1508 xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
1509 xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
1510 xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
1511 xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
1512 xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
1513 xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
1514 xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
1517 xcb_render_trapezoids (dst->dpy,
1518 _render_operator (op),
1519 src->src_picture, dst->dst_picture,
1520 render_format->id,
1521 render_src_x + attributes.x_offset,
1522 render_src_y + attributes.y_offset,
1523 num_traps, xtraps);
1525 if (xtraps != xtraps_stack)
1526 free(xtraps);
1529 BAIL:
1530 _cairo_pattern_release_surface (pattern, &src->base, &attributes);
1532 return status;
1535 static cairo_int_status_t
1536 _cairo_xcb_surface_set_clip_region (void *abstract_surface,
1537 cairo_region_t *region)
1539 cairo_xcb_surface_t *surface = abstract_surface;
1541 if (surface->clip_rects) {
1542 free (surface->clip_rects);
1543 surface->clip_rects = NULL;
1546 surface->have_clip_rects = FALSE;
1547 surface->num_clip_rects = 0;
1549 if (region == NULL) {
1550 uint32_t none[] = { XCB_NONE };
1551 if (surface->gc)
1552 xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
1554 if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
1555 xcb_render_change_picture (surface->dpy, surface->dst_picture,
1556 XCB_RENDER_CP_CLIP_MASK, none);
1557 } else {
1558 cairo_box_int_t *boxes;
1559 cairo_status_t status;
1560 xcb_rectangle_t *rects = NULL;
1561 int n_boxes, i;
1563 status = _cairo_region_get_boxes (region, &n_boxes, &boxes);
1564 if (status)
1565 return status;
1567 if (n_boxes > 0) {
1568 rects = _cairo_malloc_ab (n_boxes, sizeof(xcb_rectangle_t));
1569 if (rects == NULL) {
1570 _cairo_region_boxes_fini (region, boxes);
1571 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1573 } else {
1574 rects = NULL;
1577 for (i = 0; i < n_boxes; i++) {
1578 rects[i].x = boxes[i].p1.x;
1579 rects[i].y = boxes[i].p1.y;
1580 rects[i].width = boxes[i].p2.x - boxes[i].p1.x;
1581 rects[i].height = boxes[i].p2.y - boxes[i].p1.y;
1584 _cairo_region_boxes_fini (region, boxes);
1586 surface->have_clip_rects = TRUE;
1587 surface->clip_rects = rects;
1588 surface->num_clip_rects = n_boxes;
1590 if (surface->gc)
1591 _cairo_xcb_surface_set_gc_clip_rects (surface);
1593 if (surface->dst_picture)
1594 _cairo_xcb_surface_set_picture_clip_rects (surface);
1597 return CAIRO_STATUS_SUCCESS;
1600 static cairo_int_status_t
1601 _cairo_xcb_surface_get_extents (void *abstract_surface,
1602 cairo_rectangle_int_t *rectangle)
1604 cairo_xcb_surface_t *surface = abstract_surface;
1606 rectangle->x = 0;
1607 rectangle->y = 0;
1609 rectangle->width = surface->width;
1610 rectangle->height = surface->height;
1612 return CAIRO_STATUS_SUCCESS;
1615 /* XXX: _cairo_xcb_surface_get_font_options */
1617 static void
1618 _cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
1620 static void
1621 _cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
1622 cairo_scaled_font_t *scaled_font);
1624 static cairo_int_status_t
1625 _cairo_xcb_surface_show_glyphs (void *abstract_dst,
1626 cairo_operator_t op,
1627 cairo_pattern_t *src_pattern,
1628 cairo_glyph_t *glyphs,
1629 int num_glyphs,
1630 cairo_scaled_font_t *scaled_font,
1631 int *remaining_glyphs);
1633 static cairo_bool_t
1634 _cairo_xcb_surface_is_similar (void *surface_a,
1635 void *surface_b,
1636 cairo_content_t content)
1638 cairo_xcb_surface_t *a = surface_a;
1639 cairo_xcb_surface_t *b = surface_b;
1640 xcb_render_pictforminfo_t *xrender_format;
1642 /* XXX: disable caching by the solid pattern cache until we implement
1643 * display notification to avoid issuing xcb calls from the wrong thread
1644 * or accessing the surface after the Display has been closed.
1646 return FALSE;
1648 if (! _cairo_xcb_surface_same_screen (a, b))
1649 return FALSE;
1651 /* now check that the target is a similar format */
1652 xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy,
1653 _cairo_format_from_content (content));
1655 return a->xrender_format.id == xrender_format->id;
1658 static cairo_status_t
1659 _cairo_xcb_surface_reset (void *abstract_surface)
1661 cairo_xcb_surface_t *surface = abstract_surface;
1662 cairo_status_t status;
1664 status = _cairo_xcb_surface_set_clip_region (surface, NULL);
1665 if (status)
1666 return status;
1668 return CAIRO_STATUS_SUCCESS;
1672 /* XXX: move this to the bottom of the file, XCB and Xlib */
1674 static const cairo_surface_backend_t cairo_xcb_surface_backend = {
1675 CAIRO_SURFACE_TYPE_XCB,
1676 _cairo_xcb_surface_create_similar,
1677 _cairo_xcb_surface_finish,
1678 _cairo_xcb_surface_acquire_source_image,
1679 _cairo_xcb_surface_release_source_image,
1680 _cairo_xcb_surface_acquire_dest_image,
1681 _cairo_xcb_surface_release_dest_image,
1682 _cairo_xcb_surface_clone_similar,
1683 _cairo_xcb_surface_composite,
1684 _cairo_xcb_surface_fill_rectangles,
1685 _cairo_xcb_surface_composite_trapezoids,
1686 NULL, /* copy_page */
1687 NULL, /* show_page */
1688 _cairo_xcb_surface_set_clip_region,
1689 NULL, /* intersect_clip_path */
1690 _cairo_xcb_surface_get_extents,
1691 NULL, /* old_show_glyphs */
1692 NULL, /* get_font_options */
1693 NULL, /* flush */
1694 NULL, /* mark_dirty_rectangle */
1695 _cairo_xcb_surface_scaled_font_fini,
1696 _cairo_xcb_surface_scaled_glyph_fini,
1698 NULL, /* paint */
1699 NULL, /* mask */
1700 NULL, /* stroke */
1701 NULL, /* fill */
1702 _cairo_xcb_surface_show_glyphs,
1703 NULL, /* snapshot */
1705 _cairo_xcb_surface_is_similar,
1707 _cairo_xcb_surface_reset
1711 * _cairo_surface_is_xcb:
1712 * @surface: a #cairo_surface_t
1714 * Checks if a surface is a #cairo_xcb_surface_t
1716 * Return value: True if the surface is an xcb surface
1718 static cairo_bool_t
1719 _cairo_surface_is_xcb (cairo_surface_t *surface)
1721 return surface->backend == &cairo_xcb_surface_backend;
1724 static cairo_surface_t *
1725 _cairo_xcb_surface_create_internal (xcb_connection_t *dpy,
1726 xcb_drawable_t drawable,
1727 xcb_screen_t *screen,
1728 xcb_visualtype_t *visual,
1729 xcb_render_pictforminfo_t *xrender_format,
1730 int width,
1731 int height,
1732 int depth)
1734 cairo_xcb_surface_t *surface;
1735 const xcb_render_query_version_reply_t *r;
1737 surface = malloc (sizeof (cairo_xcb_surface_t));
1738 if (surface == NULL)
1739 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1741 if (xrender_format) {
1742 depth = xrender_format->depth;
1743 } else if (visual) {
1744 xcb_depth_iterator_t depths;
1745 xcb_visualtype_iterator_t visuals;
1747 /* This is ugly, but we have to walk over all visuals
1748 * for the screen to find the depth.
1750 depths = xcb_screen_allowed_depths_iterator(screen);
1751 for(; depths.rem; xcb_depth_next(&depths))
1753 visuals = xcb_depth_visuals_iterator(depths.data);
1754 for(; visuals.rem; xcb_visualtype_next(&visuals))
1756 if(visuals.data->visual_id == visual->visual_id)
1758 depth = depths.data->depth;
1759 goto found;
1763 found:
1767 r = xcb_render_util_query_version(dpy);
1768 if (r) {
1769 surface->render_major = r->major_version;
1770 surface->render_minor = r->minor_version;
1771 } else {
1772 surface->render_major = -1;
1773 surface->render_minor = -1;
1776 if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
1777 if (!xrender_format) {
1778 if (visual) {
1779 const xcb_render_query_pict_formats_reply_t *formats;
1780 xcb_render_pictvisual_t *pict_visual;
1781 formats = xcb_render_util_query_formats (dpy);
1782 pict_visual = xcb_render_util_find_visual_format (formats, visual->visual_id);
1783 if (pict_visual) {
1784 xcb_render_pictforminfo_t template;
1785 template.id = pict_visual->format;
1786 xrender_format = xcb_render_util_find_format (formats, XCB_PICT_FORMAT_ID, &template, 0);
1788 } else if (depth == 1) {
1789 xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, CAIRO_FORMAT_A1);
1792 } else {
1793 xrender_format = NULL;
1796 _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend,
1797 _xcb_render_format_to_content (xrender_format));
1799 surface->dpy = dpy;
1801 surface->gc = XCB_NONE;
1802 surface->drawable = drawable;
1803 surface->screen = screen;
1804 surface->owns_pixmap = FALSE;
1805 surface->use_pixmap = 0;
1806 surface->width = width;
1807 surface->height = height;
1809 /* XXX: set buggy_repeat based on ServerVendor and VendorRelease */
1811 surface->dst_picture = XCB_NONE;
1812 surface->src_picture = XCB_NONE;
1814 surface->visual = visual;
1815 surface->xrender_format.id = XCB_NONE;
1816 if (xrender_format) surface->xrender_format = *xrender_format;
1817 surface->depth = depth;
1819 surface->have_clip_rects = FALSE;
1820 surface->clip_rects = NULL;
1821 surface->num_clip_rects = 0;
1823 return (cairo_surface_t *) surface;
1826 static xcb_screen_t *
1827 _cairo_xcb_screen_from_visual (xcb_connection_t *c, xcb_visualtype_t *visual)
1829 xcb_depth_iterator_t d;
1830 xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c));
1831 for (; s.rem; xcb_screen_next(&s))
1833 if (s.data->root_visual == visual->visual_id)
1834 return s.data;
1836 d = xcb_screen_allowed_depths_iterator(s.data);
1837 for (; d.rem; xcb_depth_next(&d))
1839 xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data);
1840 for (; v.rem; xcb_visualtype_next(&v))
1842 if (v.data->visual_id == visual->visual_id)
1843 return s.data;
1847 return NULL;
1851 * cairo_xcb_surface_create:
1852 * @c: an XCB connection
1853 * @drawable: an XCB drawable
1854 * @visual: the visual to use for drawing to @drawable. The depth
1855 * of the visual must match the depth of the drawable.
1856 * Currently, only TrueColor visuals are fully supported.
1857 * @width: the current width of @drawable.
1858 * @height: the current height of @drawable.
1860 * Creates an XCB surface that draws to the given drawable.
1861 * The way that colors are represented in the drawable is specified
1862 * by the provided visual.
1864 * Note: If @drawable is a window, then the function
1865 * cairo_xcb_surface_set_size() must be called whenever the size of the
1866 * window changes.
1868 * Return value: the newly created surface
1870 cairo_surface_t *
1871 cairo_xcb_surface_create (xcb_connection_t *c,
1872 xcb_drawable_t drawable,
1873 xcb_visualtype_t *visual,
1874 int width,
1875 int height)
1877 xcb_screen_t *screen = _cairo_xcb_screen_from_visual (c, visual);
1879 if (screen == NULL)
1880 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
1882 return _cairo_xcb_surface_create_internal (c, drawable, screen,
1883 visual, NULL,
1884 width, height, 0);
1888 * cairo_xcb_surface_create_for_bitmap:
1889 * @c: an XCB connection
1890 * @bitmap: an XCB Pixmap (a depth-1 pixmap)
1891 * @screen: an XCB Screen
1892 * @width: the current width of @bitmap
1893 * @height: the current height of @bitmap
1895 * Creates an XCB surface that draws to the given bitmap.
1896 * This will be drawn to as a %CAIRO_FORMAT_A1 object.
1898 * Return value: the newly created surface
1900 cairo_surface_t *
1901 cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
1902 xcb_pixmap_t bitmap,
1903 xcb_screen_t *screen,
1904 int width,
1905 int height)
1907 return _cairo_xcb_surface_create_internal (c, bitmap, screen,
1908 NULL, NULL,
1909 width, height, 1);
1913 * cairo_xcb_surface_create_with_xrender_format:
1914 * @c: an XCB connection
1915 * @drawable: an XCB drawable
1916 * @screen: the XCB screen associated with @drawable
1917 * @format: the picture format to use for drawing to @drawable. The
1918 * depth of @format mush match the depth of the drawable.
1919 * @width: the current width of @drawable
1920 * @height: the current height of @drawable
1922 * Creates an XCB surface that draws to the given drawable.
1923 * The way that colors are represented in the drawable is specified
1924 * by the provided picture format.
1926 * Note: If @drawable is a Window, then the function
1927 * cairo_xcb_surface_set_size() must be called whenever the size of the
1928 * window changes.
1930 * Return value: the newly created surface.
1932 cairo_surface_t *
1933 cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *c,
1934 xcb_drawable_t drawable,
1935 xcb_screen_t *screen,
1936 xcb_render_pictforminfo_t *format,
1937 int width,
1938 int height)
1940 return _cairo_xcb_surface_create_internal (c, drawable, screen,
1941 NULL, format,
1942 width, height, 0);
1944 slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
1947 * cairo_xcb_surface_set_size:
1948 * @surface: a #cairo_surface_t for the XCB backend
1949 * @width: the new width of the surface
1950 * @height: the new height of the surface
1952 * Informs cairo of the new size of the XCB drawable underlying the
1953 * surface. For a surface created for a window (rather than a pixmap),
1954 * this function must be called each time the size of the window
1955 * changes. (For a subwindow, you are normally resizing the window
1956 * yourself, but for a toplevel window, it is necessary to listen for
1957 * ConfigureNotify events.)
1959 * A pixmap can never change size, so it is never necessary to call
1960 * this function on a surface created for a pixmap.
1962 void
1963 cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
1964 int width,
1965 int height)
1967 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) abstract_surface;
1968 cairo_status_t status_ignored;
1970 if (! _cairo_surface_is_xcb (abstract_surface)) {
1971 status_ignored = _cairo_surface_set_error (abstract_surface,
1972 CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1973 return;
1976 surface->width = width;
1977 surface->height = height;
1981 * Glyph rendering support
1984 typedef struct _cairo_xcb_surface_font_private {
1985 xcb_connection_t *dpy;
1986 xcb_render_glyphset_t glyphset;
1987 cairo_format_t format;
1988 xcb_render_pictforminfo_t *xrender_format;
1989 } cairo_xcb_surface_font_private_t;
1991 static cairo_status_t
1992 _cairo_xcb_surface_font_init (xcb_connection_t *dpy,
1993 cairo_scaled_font_t *scaled_font,
1994 cairo_format_t format)
1996 cairo_xcb_surface_font_private_t *font_private;
1998 font_private = malloc (sizeof (cairo_xcb_surface_font_private_t));
1999 if (!font_private)
2000 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2002 font_private->dpy = dpy;
2003 font_private->format = format;
2004 font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format);
2005 font_private->glyphset = xcb_generate_id(dpy);
2006 xcb_render_create_glyph_set (dpy, font_private->glyphset, font_private->xrender_format->id);
2008 scaled_font->surface_private = font_private;
2009 scaled_font->surface_backend = &cairo_xcb_surface_backend;
2010 return CAIRO_STATUS_SUCCESS;
2013 static void
2014 _cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
2016 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2018 if (font_private) {
2019 xcb_render_free_glyph_set (font_private->dpy, font_private->glyphset);
2020 free (font_private);
2024 static void
2025 _cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
2026 cairo_scaled_font_t *scaled_font)
2028 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2030 if (font_private != NULL && scaled_glyph->surface_private != NULL) {
2031 xcb_render_glyph_t glyph_index = _cairo_scaled_glyph_index(scaled_glyph);
2032 xcb_render_free_glyphs (font_private->dpy,
2033 font_private->glyphset,
2034 1, &glyph_index);
2038 static cairo_bool_t
2039 _native_byte_order_lsb (void)
2041 int x = 1;
2043 return *((char *) &x) == 1;
2046 static cairo_status_t
2047 _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy,
2048 cairo_scaled_font_t *scaled_font,
2049 cairo_scaled_glyph_t *scaled_glyph)
2051 xcb_render_glyphinfo_t glyph_info;
2052 xcb_render_glyph_t glyph_index;
2053 unsigned char *data;
2054 cairo_status_t status = CAIRO_STATUS_SUCCESS;
2055 cairo_xcb_surface_font_private_t *font_private;
2056 cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
2058 if (scaled_font->surface_private == NULL) {
2059 status = _cairo_xcb_surface_font_init (dpy, scaled_font,
2060 glyph_surface->format);
2061 if (status)
2062 return status;
2064 font_private = scaled_font->surface_private;
2066 /* If the glyph format does not match the font format, then we
2067 * create a temporary surface for the glyph image with the font's
2068 * format.
2070 if (glyph_surface->format != font_private->format) {
2071 cairo_t *cr;
2072 cairo_surface_t *tmp_surface;
2073 double x_offset, y_offset;
2075 tmp_surface = cairo_image_surface_create (font_private->format,
2076 glyph_surface->width,
2077 glyph_surface->height);
2078 cr = cairo_create (tmp_surface);
2079 cairo_surface_get_device_offset (&glyph_surface->base, &x_offset, &y_offset);
2080 cairo_set_source_surface (cr, &glyph_surface->base, x_offset, y_offset);
2081 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
2082 cairo_paint (cr);
2084 status = cairo_status (cr);
2086 cairo_destroy (cr);
2088 tmp_surface->device_transform = glyph_surface->base.device_transform;
2089 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
2091 glyph_surface = (cairo_image_surface_t *) tmp_surface;
2093 if (status)
2094 goto BAIL;
2097 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
2098 glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
2099 glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
2100 glyph_info.width = glyph_surface->width;
2101 glyph_info.height = glyph_surface->height;
2102 glyph_info.x_off = 0;
2103 glyph_info.y_off = 0;
2105 data = glyph_surface->data;
2107 /* flip formats around */
2108 switch (scaled_glyph->surface->format) {
2109 case CAIRO_FORMAT_A1:
2110 /* local bitmaps are always stored with bit == byte */
2111 if (_native_byte_order_lsb() != (xcb_get_setup(dpy)->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
2112 int c = glyph_surface->stride * glyph_surface->height;
2113 unsigned char *d;
2114 unsigned char *new, *n;
2116 new = malloc (c);
2117 if (!new) {
2118 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2119 goto BAIL;
2121 n = new;
2122 d = data;
2123 while (c--)
2125 char b = *d++;
2126 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
2127 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
2128 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
2129 *n++ = b;
2131 data = new;
2133 break;
2134 case CAIRO_FORMAT_A8:
2135 break;
2136 case CAIRO_FORMAT_ARGB32:
2137 if (_native_byte_order_lsb() != (xcb_get_setup(dpy)->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
2138 unsigned int c = glyph_surface->stride * glyph_surface->height;
2139 unsigned char *d;
2140 unsigned char *new, *n;
2142 new = malloc (c);
2143 if (new == NULL) {
2144 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2145 goto BAIL;
2147 n = new;
2148 d = data;
2149 while (c >= 4)
2151 n[3] = d[0];
2152 n[2] = d[1];
2153 n[1] = d[2];
2154 n[0] = d[3];
2155 d += 4;
2156 n += 4;
2157 c -= 4;
2159 data = new;
2161 break;
2162 case CAIRO_FORMAT_RGB24:
2163 default:
2164 ASSERT_NOT_REACHED;
2165 break;
2167 /* XXX assume X server wants pixman padding. Xft assumes this as well */
2169 glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
2171 xcb_render_add_glyphs (dpy, font_private->glyphset,
2172 1, &glyph_index, &glyph_info,
2173 glyph_surface->stride * glyph_surface->height,
2174 data);
2176 if (data != glyph_surface->data)
2177 free (data);
2179 BAIL:
2180 if (glyph_surface != scaled_glyph->surface)
2181 cairo_surface_destroy (&glyph_surface->base);
2183 return status;
2186 #define N_STACK_BUF 1024
2188 static cairo_status_t
2189 _cairo_xcb_surface_show_glyphs_8 (cairo_xcb_surface_t *dst,
2190 cairo_operator_t op,
2191 cairo_xcb_surface_t *src,
2192 int src_x_offset, int src_y_offset,
2193 const cairo_glyph_t *glyphs,
2194 int num_glyphs,
2195 cairo_scaled_font_t *scaled_font)
2197 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2198 xcb_render_util_composite_text_stream_t *stream;
2199 int i;
2200 int thisX, thisY;
2201 int lastX = 0, lastY = 0;
2202 uint8_t glyph;
2204 stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
2206 for (i = 0; i < num_glyphs; ++i) {
2207 thisX = _cairo_lround (glyphs[i].x);
2208 thisY = _cairo_lround (glyphs[i].y);
2209 glyph = glyphs[i].index;
2210 xcb_render_util_glyphs_8 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
2211 lastX = thisX;
2212 lastY = thisY;
2215 xcb_render_util_composite_text (dst->dpy,
2216 _render_operator (op),
2217 src->src_picture,
2218 dst->dst_picture,
2219 font_private->xrender_format->id,
2220 src_x_offset + _cairo_lround (glyphs[0].x),
2221 src_y_offset + _cairo_lround (glyphs[0].y),
2222 stream);
2224 xcb_render_util_composite_text_free (stream);
2226 return CAIRO_STATUS_SUCCESS;
2229 static cairo_status_t
2230 _cairo_xcb_surface_show_glyphs_16 (cairo_xcb_surface_t *dst,
2231 cairo_operator_t op,
2232 cairo_xcb_surface_t *src,
2233 int src_x_offset, int src_y_offset,
2234 const cairo_glyph_t *glyphs,
2235 int num_glyphs,
2236 cairo_scaled_font_t *scaled_font)
2238 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2239 xcb_render_util_composite_text_stream_t *stream;
2240 int i;
2241 int thisX, thisY;
2242 int lastX = 0, lastY = 0;
2243 uint16_t glyph;
2245 stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
2247 for (i = 0; i < num_glyphs; ++i) {
2248 thisX = _cairo_lround (glyphs[i].x);
2249 thisY = _cairo_lround (glyphs[i].y);
2250 glyph = glyphs[i].index;
2251 xcb_render_util_glyphs_16 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
2252 lastX = thisX;
2253 lastY = thisY;
2256 xcb_render_util_composite_text (dst->dpy,
2257 _render_operator (op),
2258 src->src_picture,
2259 dst->dst_picture,
2260 font_private->xrender_format->id,
2261 src_x_offset + _cairo_lround (glyphs[0].x),
2262 src_y_offset + _cairo_lround (glyphs[0].y),
2263 stream);
2265 xcb_render_util_composite_text_free (stream);
2267 return CAIRO_STATUS_SUCCESS;
2270 static cairo_status_t
2271 _cairo_xcb_surface_show_glyphs_32 (cairo_xcb_surface_t *dst,
2272 cairo_operator_t op,
2273 cairo_xcb_surface_t *src,
2274 int src_x_offset, int src_y_offset,
2275 const cairo_glyph_t *glyphs,
2276 int num_glyphs,
2277 cairo_scaled_font_t *scaled_font)
2279 cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
2280 xcb_render_util_composite_text_stream_t *stream;
2281 int i;
2282 int thisX, thisY;
2283 int lastX = 0, lastY = 0;
2284 uint32_t glyph;
2286 stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
2288 for (i = 0; i < num_glyphs; ++i) {
2289 thisX = _cairo_lround (glyphs[i].x);
2290 thisY = _cairo_lround (glyphs[i].y);
2291 glyph = glyphs[i].index;
2292 xcb_render_util_glyphs_32 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
2293 lastX = thisX;
2294 lastY = thisY;
2297 xcb_render_util_composite_text (dst->dpy,
2298 _render_operator (op),
2299 src->src_picture,
2300 dst->dst_picture,
2301 font_private->xrender_format->id,
2302 src_x_offset + _cairo_lround (glyphs[0].x),
2303 src_y_offset + _cairo_lround (glyphs[0].y),
2304 stream);
2306 xcb_render_util_composite_text_free (stream);
2308 return CAIRO_STATUS_SUCCESS;
2311 typedef cairo_status_t (*cairo_xcb_surface_show_glyphs_func_t)
2312 (cairo_xcb_surface_t *, cairo_operator_t, cairo_xcb_surface_t *, int, int,
2313 const cairo_glyph_t *, int, cairo_scaled_font_t *);
2315 static cairo_bool_t
2316 _cairo_xcb_surface_owns_font (cairo_xcb_surface_t *dst,
2317 cairo_scaled_font_t *scaled_font)
2319 cairo_xcb_surface_font_private_t *font_private;
2321 font_private = scaled_font->surface_private;
2322 if ((scaled_font->surface_backend != NULL &&
2323 scaled_font->surface_backend != &cairo_xcb_surface_backend) ||
2324 (font_private != NULL && font_private->dpy != dst->dpy))
2326 return FALSE;
2329 return TRUE;
2334 static cairo_status_t
2335 _cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst,
2336 cairo_glyph_t *glyphs,
2337 int num_glyphs,
2338 cairo_scaled_font_t *scaled_font,
2339 cairo_operator_t op,
2340 cairo_xcb_surface_t *src,
2341 cairo_surface_attributes_t *attributes,
2342 int *remaining_glyphs)
2344 cairo_scaled_glyph_t *scaled_glyph;
2345 int i, o;
2346 unsigned long max_index = 0;
2347 cairo_status_t status;
2348 cairo_glyph_t *output_glyphs;
2349 const cairo_glyph_t *glyphs_chunk;
2350 int glyphs_remaining, chunk_size, max_chunk_size;
2351 cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
2353 /* We make a copy of the glyphs so that we can elide any size-zero
2354 * glyphs to workaround an X server bug, (present in at least Xorg
2355 * 7.1 without EXA). */
2356 output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
2357 if (output_glyphs == NULL)
2358 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2360 for (i = 0, o = 0; i < num_glyphs; i++) {
2361 if (glyphs[i].index > max_index)
2362 max_index = glyphs[i].index;
2363 status = _cairo_scaled_glyph_lookup (scaled_font,
2364 glyphs[i].index,
2365 CAIRO_SCALED_GLYPH_INFO_SURFACE,
2366 &scaled_glyph);
2367 if (status) {
2368 free (output_glyphs);
2369 return status;
2372 /* Don't put any size-zero glyphs into output_glyphs to avoid
2373 * an X server bug which stops rendering glyphs after the
2374 * first size-zero glyph. */
2375 if (scaled_glyph->surface->width && scaled_glyph->surface->height) {
2376 output_glyphs[o++] = glyphs[i];
2377 if (scaled_glyph->surface_private == NULL) {
2378 _cairo_xcb_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph);
2379 scaled_glyph->surface_private = (void *) 1;
2383 num_glyphs = o;
2385 _cairo_xcb_surface_ensure_dst_picture (dst);
2387 max_chunk_size = xcb_get_maximum_request_length (dst->dpy);
2388 if (max_index < 256) {
2389 /* XXX: these are all the same size! (28) */
2390 max_chunk_size -= sizeof(xcb_render_composite_glyphs_8_request_t);
2391 show_glyphs_func = _cairo_xcb_surface_show_glyphs_8;
2392 } else if (max_index < 65536) {
2393 max_chunk_size -= sizeof(xcb_render_composite_glyphs_16_request_t);
2394 show_glyphs_func = _cairo_xcb_surface_show_glyphs_16;
2395 } else {
2396 max_chunk_size -= sizeof(xcb_render_composite_glyphs_32_request_t);
2397 show_glyphs_func = _cairo_xcb_surface_show_glyphs_32;
2399 /* XXX: I think this is wrong; this is only the header size (2 longs) */
2400 /* but should also include the glyph (1 long) */
2401 /* max_chunk_size /= sz_xGlyphElt; */
2402 max_chunk_size /= 3*sizeof(uint32_t);
2404 for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs;
2405 glyphs_remaining;
2406 glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
2408 chunk_size = MIN (glyphs_remaining, max_chunk_size);
2410 status = show_glyphs_func (dst, op, src,
2411 attributes->x_offset, attributes->y_offset,
2412 glyphs_chunk, chunk_size, scaled_font);
2413 if (status) {
2414 free (output_glyphs);
2415 return status;
2419 return CAIRO_STATUS_SUCCESS;
2422 static cairo_int_status_t
2423 _cairo_xcb_surface_show_glyphs (void *abstract_dst,
2424 cairo_operator_t op,
2425 cairo_pattern_t *src_pattern,
2426 cairo_glyph_t *glyphs,
2427 int num_glyphs,
2428 cairo_scaled_font_t *scaled_font,
2429 int *remaining_glyphs)
2431 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2432 cairo_xcb_surface_t *dst = abstract_dst;
2434 composite_operation_t operation;
2435 cairo_surface_attributes_t attributes;
2436 cairo_xcb_surface_t *src = NULL;
2438 cairo_solid_pattern_t solid_pattern;
2440 if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
2441 return CAIRO_INT_STATUS_UNSUPPORTED;
2443 /* Just let unbounded operators go through the fallback code
2444 * instead of trying to do the fixups here */
2445 if (!_cairo_operator_bounded_by_mask (op))
2446 return CAIRO_INT_STATUS_UNSUPPORTED;
2448 /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
2449 * the solid source seems to be multiplied by the glyph mask, and
2450 * then the entire thing is copied to the destination surface,
2451 * including the fully transparent "background" of the rectangular
2452 * glyph surface. */
2453 if (op == CAIRO_OPERATOR_SOURCE &&
2454 !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
2455 return CAIRO_INT_STATUS_UNSUPPORTED;
2457 /* We can only use our code if we either have no clip or
2458 * have a real native clip region set. If we're using
2459 * fallback clip masking, we have to go through the full
2460 * fallback path.
2462 if (dst->base.clip &&
2463 (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
2464 dst->base.clip->surface != NULL))
2465 return CAIRO_INT_STATUS_UNSUPPORTED;
2467 operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
2468 if (operation == DO_UNSUPPORTED)
2469 return CAIRO_INT_STATUS_UNSUPPORTED;
2471 if (! _cairo_xcb_surface_owns_font (dst, scaled_font))
2472 return CAIRO_INT_STATUS_UNSUPPORTED;
2474 /* After passing all those tests, we're now committed to rendering
2475 * these glyphs or to fail trying. We first upload any glyphs to
2476 * the X server that it doesn't have already, then we draw
2477 * them. We tie into the scaled_font's glyph cache and remove
2478 * glyphs from the X server when they are ejected from the
2479 * scaled_font cache.
2482 /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
2483 * the mask (the glyphs). This code below was executed as a side effect
2484 * of going through the _clip_and_composite fallback code for old_show_glyphs,
2485 * so PictOpClear was never used with CompositeText before.
2487 if (op == CAIRO_OPERATOR_CLEAR) {
2488 _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
2489 CAIRO_CONTENT_COLOR);
2490 src_pattern = &solid_pattern.base;
2491 op = CAIRO_OPERATOR_DEST_OUT;
2494 if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
2495 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
2496 0, 0, 1, 1,
2497 (cairo_surface_t **) &src,
2498 &attributes);
2499 } else {
2500 cairo_rectangle_int_t glyph_extents;
2502 status = _cairo_scaled_font_glyph_device_extents (scaled_font,
2503 glyphs,
2504 num_glyphs,
2505 &glyph_extents);
2506 if (status)
2507 goto BAIL;
2509 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
2510 glyph_extents.x, glyph_extents.y,
2511 glyph_extents.width, glyph_extents.height,
2512 (cairo_surface_t **) &src,
2513 &attributes);
2516 if (status)
2517 goto BAIL;
2519 operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
2520 if (operation == DO_UNSUPPORTED) {
2521 status = CAIRO_INT_STATUS_UNSUPPORTED;
2522 goto BAIL;
2525 status = _cairo_xcb_surface_set_attributes (src, &attributes);
2526 if (status)
2527 goto BAIL;
2529 /* Send all unsent glyphs to the server, and count the max of the glyph indices */
2530 _cairo_scaled_font_freeze_cache (scaled_font);
2532 if (_cairo_xcb_surface_owns_font (dst, scaled_font))
2533 status = _cairo_xcb_surface_emit_glyphs (dst,
2534 glyphs, num_glyphs,
2535 scaled_font,
2537 src,
2538 &attributes,
2539 remaining_glyphs);
2540 else
2541 status = CAIRO_INT_STATUS_UNSUPPORTED;
2542 _cairo_scaled_font_thaw_cache (scaled_font);
2544 BAIL:
2545 if (src)
2546 _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
2547 if (src_pattern == &solid_pattern.base)
2548 _cairo_pattern_fini (&solid_pattern.base);
2550 return status;