1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
4 * Copyright © 2013 Samsung Research America, Silicon Valley
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
30 * Chris Wilson <chris@chris-wilson.co.uk>
31 * Henry Song <henry.song@samsung.com>
36 #include "cairo-xcb-private.h"
38 #include "cairo-boxes-private.h"
39 #include "cairo-clip-inline.h"
40 #include "cairo-clip-private.h"
41 #include "cairo-composite-rectangles-private.h"
42 #include "cairo-image-surface-private.h"
43 #include "cairo-list-inline.h"
44 #include "cairo-region-private.h"
45 #include "cairo-surface-offset-private.h"
46 #include "cairo-surface-snapshot-inline.h"
47 #include "cairo-surface-subsurface-private.h"
48 #include "cairo-traps-private.h"
49 #include "cairo-recording-surface-inline.h"
50 #include "cairo-paginated-private.h"
51 #include "cairo-pattern-inline.h"
52 #include "cairo-filters-private.h"
54 #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
57 _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
59 const cairo_pattern_t *src,
61 cairo_composite_rectangles_t *extents);
63 static inline cairo_xcb_connection_t *
64 _picture_to_connection (cairo_xcb_picture_t *picture)
66 return (cairo_xcb_connection_t *) picture->base.device;
70 _cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface);
73 hars_petruska_f54_1_random (void)
75 #define rol(x,k) ((x << k) | (x >> (32-k)))
77 return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
82 _cairo_xcb_picture_finish (void *abstract_surface)
84 cairo_xcb_picture_t *surface = abstract_surface;
85 cairo_xcb_connection_t *connection = _picture_to_connection (surface);
86 cairo_status_t status;
88 status = _cairo_xcb_connection_acquire (connection);
89 cairo_list_del (&surface->link);
90 if (unlikely (status))
93 _cairo_xcb_connection_render_free_picture (connection, surface->picture);
95 _cairo_xcb_connection_release (connection);
97 return CAIRO_STATUS_SUCCESS;
100 static const cairo_surface_backend_t _cairo_xcb_picture_backend = {
101 CAIRO_SURFACE_TYPE_XCB,
102 _cairo_xcb_picture_finish,
105 static const struct xcb_render_transform_t identity_transform = {
111 static cairo_xcb_picture_t *
112 _cairo_xcb_picture_create (cairo_xcb_screen_t *screen,
113 pixman_format_code_t pixman_format,
114 xcb_render_pictformat_t xrender_format,
115 int width, int height)
117 cairo_xcb_picture_t *surface;
119 surface = malloc (sizeof (cairo_xcb_picture_t));
120 if (unlikely (surface == NULL))
121 return (cairo_xcb_picture_t *)
122 _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
124 _cairo_surface_init (&surface->base,
125 &_cairo_xcb_picture_backend,
126 &screen->connection->device,
127 _cairo_content_from_pixman_format (pixman_format));
129 cairo_list_add (&surface->link, &screen->pictures);
131 surface->screen = screen;
132 surface->picture = _cairo_xcb_connection_get_xid (screen->connection);
133 surface->pixman_format = pixman_format;
134 surface->xrender_format = xrender_format;
136 surface->x0 = surface->y0 = 0;
137 surface->x = surface->y = 0;
138 surface->width = width;
139 surface->height = height;
141 surface->transform = identity_transform;
142 surface->extend = CAIRO_EXTEND_NONE;
143 surface->filter = CAIRO_FILTER_NEAREST;
144 surface->has_component_alpha = FALSE;
149 static inline cairo_bool_t
150 _operator_is_supported (uint32_t flags, cairo_operator_t op)
152 if (op <= CAIRO_OPERATOR_SATURATE)
155 /* Can we use PDF operators? */
156 #if CAIRO_XCB_RENDER_AT_LEAST(0, 11)
157 if (op <= CAIRO_OPERATOR_HSL_LUMINOSITY)
158 return flags & CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
165 _render_operator (cairo_operator_t op)
167 #define C(x,y) case CAIRO_OPERATOR_##x: return XCB_RENDER_PICT_OP_##y
178 C(DEST_OVER, OVER_REVERSE);
179 C(DEST_IN, IN_REVERSE);
180 C(DEST_OUT, OUT_REVERSE);
181 C(DEST_ATOP, ATOP_REVERSE);
185 C(SATURATE, SATURATE);
187 /* PDF operators were added in RENDER 0.11, check if the xcb headers have
188 * the defines, else fall through to the default case. */
189 #if CAIRO_XCB_RENDER_AT_LEAST(0, 11)
190 #define BLEND(x,y) C(x,y)
192 #define BLEND(x,y) case CAIRO_OPERATOR_##x:
194 BLEND(MULTIPLY, MULTIPLY);
195 BLEND(SCREEN, SCREEN);
196 BLEND(OVERLAY, OVERLAY);
197 BLEND(DARKEN, DARKEN);
198 BLEND(LIGHTEN, LIGHTEN);
199 BLEND(COLOR_DODGE, COLOR_DODGE);
200 BLEND(COLOR_BURN, COLOR_BURN);
201 BLEND(HARD_LIGHT, HARD_LIGHT);
202 BLEND(SOFT_LIGHT, SOFT_LIGHT);
203 BLEND(DIFFERENCE, DIFFERENCE);
204 BLEND(EXCLUSION, EXCLUSION);
205 BLEND(HSL_HUE, HSL_HUE);
206 BLEND(HSL_SATURATION, HSL_SATURATION);
207 BLEND(HSL_COLOR, HSL_COLOR);
208 BLEND(HSL_LUMINOSITY, HSL_LUMINOSITY);
212 return XCB_RENDER_PICT_OP_OVER;
216 static cairo_status_t
217 _cairo_xcb_surface_set_clip_region (cairo_xcb_surface_t *surface,
218 cairo_region_t *region)
220 xcb_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
221 xcb_rectangle_t *rects = stack_rects;
224 num_rects = cairo_region_num_rectangles (region);
226 if (num_rects > ARRAY_LENGTH (stack_rects)) {
227 rects = _cairo_malloc_ab (num_rects, sizeof (xcb_rectangle_t));
228 if (unlikely (rects == NULL)) {
229 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
233 for (i = 0; i < num_rects; i++) {
234 cairo_rectangle_int_t rect;
236 cairo_region_get_rectangle (region, i, &rect);
240 rects[i].width = rect.width;
241 rects[i].height = rect.height;
244 _cairo_xcb_connection_render_set_picture_clip_rectangles (surface->connection,
249 if (rects != stack_rects)
252 return CAIRO_STATUS_SUCCESS;
256 _cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t *surface)
258 uint32_t values[] = { XCB_NONE };
259 _cairo_xcb_connection_render_change_picture (surface->connection,
261 XCB_RENDER_CP_CLIP_MASK,
266 _cairo_xcb_surface_set_precision (cairo_xcb_surface_t *surface,
267 cairo_antialias_t antialias)
269 cairo_xcb_connection_t *connection = surface->connection;
272 if (connection->force_precision != -1)
273 precision = connection->force_precision;
274 else switch (antialias) {
276 case CAIRO_ANTIALIAS_DEFAULT:
277 case CAIRO_ANTIALIAS_GRAY:
278 case CAIRO_ANTIALIAS_NONE:
279 case CAIRO_ANTIALIAS_FAST:
280 case CAIRO_ANTIALIAS_GOOD:
281 precision = XCB_RENDER_POLY_MODE_IMPRECISE;
283 case CAIRO_ANTIALIAS_SUBPIXEL:
284 case CAIRO_ANTIALIAS_BEST:
285 precision = XCB_RENDER_POLY_MODE_PRECISE;
289 if (surface->precision != precision) {
290 _cairo_xcb_connection_render_change_picture (connection,
292 XCB_RENDER_CP_POLY_MODE,
294 surface->precision = precision;
300 _cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface)
302 assert (surface->fallback == NULL);
303 if (surface->picture == XCB_NONE) {
307 if (surface->precision != XCB_RENDER_POLY_MODE_PRECISE) {
308 flags |= XCB_RENDER_CP_POLY_MODE;
309 values[0] = surface->precision;
312 surface->picture = _cairo_xcb_connection_get_xid (surface->connection);
313 _cairo_xcb_connection_render_create_picture (surface->connection,
316 surface->xrender_format,
321 static cairo_xcb_picture_t *
322 _picture_from_image (cairo_xcb_surface_t *target,
323 xcb_render_pictformat_t format,
324 cairo_image_surface_t *image,
325 cairo_xcb_shm_info_t *shm_info)
329 cairo_xcb_picture_t *picture;
331 pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
334 image->width, image->height);
336 gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, image->depth);
338 if (shm_info != NULL) {
339 _cairo_xcb_connection_shm_put_image (target->connection,
341 image->width, image->height,
343 image->width, image->height,
351 /* Do we need to trim the image? */
352 len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format));
353 if (len == image->stride) {
354 _cairo_xcb_connection_put_image (target->connection,
356 image->width, image->height,
362 _cairo_xcb_connection_put_subimage (target->connection,
365 image->width, image->height,
366 PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
375 _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
377 picture = _cairo_xcb_picture_create (target->screen,
378 image->pixman_format, format,
379 image->width, image->height);
380 if (likely (picture->base.status == CAIRO_STATUS_SUCCESS)) {
381 _cairo_xcb_connection_render_create_picture (target->connection,
382 picture->picture, pixmap, format,
386 _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
392 _pattern_is_supported (uint32_t flags,
393 const cairo_pattern_t *pattern)
396 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
399 if (! _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL)) {
400 if ((flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) == 0)
404 switch (pattern->extend) {
407 case CAIRO_EXTEND_NONE:
408 case CAIRO_EXTEND_REPEAT:
410 case CAIRO_EXTEND_PAD:
411 case CAIRO_EXTEND_REFLECT:
412 if ((flags & CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT) == 0)
416 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
417 cairo_filter_t filter;
419 filter = pattern->filter;
420 if (_cairo_matrix_has_unity_scale (&pattern->matrix) &&
421 _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
423 filter = CAIRO_FILTER_NEAREST;
426 if (! (filter == CAIRO_FILTER_NEAREST || filter == CAIRO_FILTER_FAST)) {
427 if ((flags & CAIRO_XCB_RENDER_HAS_FILTERS) == 0)
430 } else { /* gradient */
431 if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
434 /* The RENDER specification says that the inner circle has to be
435 * completely contained inside the outer one. */
436 if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL &&
437 ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) pattern))
443 return pattern->type != CAIRO_PATTERN_TYPE_MESH;
447 _cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
448 const cairo_matrix_t *matrix,
449 cairo_filter_t filter,
450 double xc, double yc)
452 xcb_render_transform_t transform;
453 pixman_transform_t *pixman_transform;
454 cairo_int_status_t ignored;
456 /* Casting between pixman_transform_t and xcb_render_transform_t is safe
457 * because they happen to be the exact same type.
459 pixman_transform = (pixman_transform_t *) &transform;
461 picture->x = picture->x0;
462 picture->y = picture->y0;
463 ignored = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
465 &picture->x, &picture->y);
468 if (memcmp (&picture->transform, &transform, sizeof (xcb_render_transform_t))) {
469 _cairo_xcb_connection_render_set_picture_transform (_picture_to_connection (picture),
473 picture->transform = transform;
478 _cairo_xcb_picture_set_filter (cairo_xcb_picture_t *picture,
479 cairo_filter_t filter,
481 xcb_render_fixed_t *values)
483 const char *render_filter;
486 if (picture->filter == filter)
490 case CAIRO_FILTER_FAST:
491 render_filter = "fast";
492 len = strlen ("fast");
495 case CAIRO_FILTER_GOOD:
496 render_filter = "good";
497 len = strlen ("good");
500 case CAIRO_FILTER_BEST:
501 render_filter = "best";
502 len = strlen ("best");
505 case CAIRO_FILTER_NEAREST:
506 render_filter = "nearest";
507 len = strlen ("nearest");
510 case CAIRO_FILTER_BILINEAR:
511 render_filter = "bilinear";
512 len = strlen ("bilinear");
517 case CAIRO_FILTER_GAUSSIAN:
518 if (values_len == 0 || values == NULL) {
519 render_filter = "best";
520 len = strlen ("best");
523 render_filter = "convolution";
524 len = strlen ("convolution");
529 _cairo_xcb_connection_render_set_picture_filter (_picture_to_connection (picture),
531 len, (char *) render_filter,
533 picture->filter = filter;
537 _cairo_xcb_picture_set_extend (cairo_xcb_picture_t *picture,
538 cairo_extend_t extend)
542 if (picture->extend == extend)
548 case CAIRO_EXTEND_NONE:
549 pa[0] = XCB_RENDER_REPEAT_NONE;
552 case CAIRO_EXTEND_REPEAT:
553 pa[0] = XCB_RENDER_REPEAT_NORMAL;
556 case CAIRO_EXTEND_REFLECT:
557 pa[0] = XCB_RENDER_REPEAT_REFLECT;
560 case CAIRO_EXTEND_PAD:
561 pa[0] = XCB_RENDER_REPEAT_PAD;
565 _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture),
567 XCB_RENDER_CP_REPEAT, pa);
568 picture->extend = extend;
572 _cairo_xcb_picture_set_component_alpha (cairo_xcb_picture_t *picture,
577 if (picture->has_component_alpha == ca)
582 _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture),
584 XCB_RENDER_CP_COMPONENT_ALPHA,
586 picture->has_component_alpha = ca;
589 static cairo_xcb_picture_t *
590 _solid_picture (cairo_xcb_surface_t *target,
591 const cairo_color_t *color)
593 xcb_render_color_t xcb_color;
594 xcb_render_pictformat_t xrender_format;
595 cairo_xcb_picture_t *picture;
597 xcb_color.red = color->red_short;
598 xcb_color.green = color->green_short;
599 xcb_color.blue = color->blue_short;
600 xcb_color.alpha = color->alpha_short;
602 xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
603 picture = _cairo_xcb_picture_create (target->screen,
607 if (unlikely (picture->base.status))
610 if (target->connection->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) {
611 _cairo_xcb_connection_render_create_solid_fill (target->connection,
616 uint32_t values[] = { XCB_RENDER_REPEAT_NORMAL };
618 pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
619 32, target->drawable, 1, 1);
620 _cairo_xcb_connection_render_create_picture (target->connection,
624 XCB_RENDER_CP_REPEAT,
626 if (target->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
627 xcb_rectangle_t rect;
630 rect.width = rect.height = 1;
632 _cairo_xcb_connection_render_fill_rectangles (_picture_to_connection (picture),
633 XCB_RENDER_PICT_OP_SRC,
635 xcb_color, 1, &rect);
640 gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, 32);
642 /* XXX byte ordering? */
643 pixel = ((color->alpha_short >> 8) << 24) |
644 ((color->red_short >> 8) << 16) |
645 ((color->green_short >> 8) << 8) |
646 ((color->blue_short >> 8) << 0);
648 _cairo_xcb_connection_put_image (target->connection,
653 _cairo_xcb_screen_put_gc (target->screen, 32, gc);
656 _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
662 static cairo_xcb_picture_t *
663 _cairo_xcb_transparent_picture (cairo_xcb_surface_t *target)
665 cairo_xcb_picture_t *picture;
667 picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT];
668 if (picture == NULL) {
669 picture = _solid_picture (target, CAIRO_COLOR_TRANSPARENT);
670 target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT] = &picture->base;
673 return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
676 static cairo_xcb_picture_t *
677 _cairo_xcb_black_picture (cairo_xcb_surface_t *target)
679 cairo_xcb_picture_t *picture;
681 picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_BLACK];
682 if (picture == NULL) {
683 picture = _solid_picture (target, CAIRO_COLOR_BLACK);
684 target->screen->stock_colors[CAIRO_STOCK_BLACK] = &picture->base;
687 return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
690 static cairo_xcb_picture_t *
691 _cairo_xcb_white_picture (cairo_xcb_surface_t *target)
693 cairo_xcb_picture_t *picture;
695 picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_WHITE];
696 if (picture == NULL) {
697 picture = _solid_picture (target, CAIRO_COLOR_WHITE);
698 target->screen->stock_colors[CAIRO_STOCK_WHITE] = &picture->base;
701 return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
704 static cairo_xcb_picture_t *
705 _cairo_xcb_solid_picture (cairo_xcb_surface_t *target,
706 const cairo_solid_pattern_t *pattern)
708 cairo_xcb_picture_t *picture;
709 cairo_xcb_screen_t *screen;
712 if (pattern->color.alpha_short <= 0x00ff)
713 return _cairo_xcb_transparent_picture (target);
715 if (pattern->color.alpha_short >= 0xff00) {
716 if (pattern->color.red_short <= 0x00ff &&
717 pattern->color.green_short <= 0x00ff &&
718 pattern->color.blue_short <= 0x00ff)
720 return _cairo_xcb_black_picture (target);
723 if (pattern->color.red_short >= 0xff00 &&
724 pattern->color.green_short >= 0xff00 &&
725 pattern->color.blue_short >= 0xff00)
727 return _cairo_xcb_white_picture (target);
731 screen = target->screen;
732 n_cached = screen->solid_cache_size;
733 for (i = 0; i < n_cached; i++) {
734 if (_cairo_color_equal (&screen->solid_cache[i].color, &pattern->color)) {
735 return (cairo_xcb_picture_t *) cairo_surface_reference (screen->solid_cache[i].picture);
739 picture = _solid_picture (target, &pattern->color);
740 if (unlikely (picture->base.status))
743 if (screen->solid_cache_size < ARRAY_LENGTH (screen->solid_cache)) {
744 i = screen->solid_cache_size++;
746 i = hars_petruska_f54_1_random () % ARRAY_LENGTH (screen->solid_cache);
747 cairo_surface_destroy (screen->solid_cache[i].picture);
749 screen->solid_cache[i].picture = cairo_surface_reference (&picture->base);
750 screen->solid_cache[i].color = pattern->color;
755 static cairo_xcb_picture_t *
756 _render_to_picture (cairo_xcb_surface_t *target,
757 const cairo_pattern_t *pattern,
758 const cairo_rectangle_int_t *extents)
760 cairo_image_surface_t *image;
761 cairo_xcb_shm_info_t *shm_info;
762 cairo_pattern_union_t copy;
763 cairo_status_t status;
764 cairo_xcb_picture_t *picture;
765 pixman_format_code_t pixman_format;
766 xcb_render_pictformat_t xrender_format;
768 /* XXX handle extend modes via tiling? */
769 /* XXX alpha-only masks? */
771 pixman_format = PIXMAN_a8r8g8b8;
772 xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
774 status = _cairo_xcb_shm_image_create (target->screen->connection,
776 extents->width, extents->height,
778 if (unlikely (status))
779 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
781 _cairo_pattern_init_static_copy (©.base, pattern);
782 cairo_matrix_translate (©.base.matrix, extents->x, extents->y);
783 status = _cairo_surface_paint (&image->base,
784 CAIRO_OPERATOR_SOURCE,
787 if (unlikely (status)) {
788 cairo_surface_destroy (&image->base);
789 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
792 picture = _picture_from_image (target, xrender_format, image, shm_info);
793 cairo_surface_destroy (&image->base);
795 if (unlikely (picture->base.status))
798 _cairo_xcb_picture_set_component_alpha (picture, pattern->has_component_alpha);
799 picture->x = -extents->x;
800 picture->y = -extents->y;
805 static xcb_render_fixed_t *
806 _gradient_to_xcb (const cairo_gradient_pattern_t *gradient,
807 unsigned int *n_stops,
808 char *buf, unsigned int buflen)
810 xcb_render_fixed_t *stops;
811 xcb_render_color_t *colors;
814 assert (gradient->n_stops > 0);
815 *n_stops = MAX (gradient->n_stops, 2);
817 if (*n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen)
819 stops = (xcb_render_fixed_t *) buf;
824 _cairo_malloc_ab (*n_stops,
825 sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t));
826 if (unlikely (stops == NULL))
830 colors = (xcb_render_color_t *) (stops + *n_stops);
831 for (i = 0; i < gradient->n_stops; i++) {
833 _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
835 colors[i].red = gradient->stops[i].color.red_short;
836 colors[i].green = gradient->stops[i].color.green_short;
837 colors[i].blue = gradient->stops[i].color.blue_short;
838 colors[i].alpha = gradient->stops[i].color.alpha_short;
841 /* RENDER does not support gradients with less than 2 stops. If a
842 * gradient has only a single stop, duplicate it to make RENDER
844 if (gradient->n_stops == 1) {
845 stops[1] = _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
847 colors[1].red = gradient->stops[0].color.red_short;
848 colors[1].green = gradient->stops[0].color.green_short;
849 colors[1].blue = gradient->stops[0].color.blue_short;
850 colors[1].alpha = gradient->stops[0].color.alpha_short;
856 static cairo_xcb_picture_t *
857 _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
858 const cairo_linear_pattern_t *pattern,
859 const cairo_rectangle_int_t *extents)
861 char buf[CAIRO_STACK_BUFFER_SIZE];
862 xcb_render_fixed_t *stops;
863 xcb_render_color_t *colors;
864 xcb_render_pointfix_t p1, p2;
865 cairo_matrix_t matrix;
866 cairo_circle_double_t extremes[2];
867 cairo_xcb_picture_t *picture;
868 cairo_status_t status;
869 unsigned int n_stops;
871 _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
873 picture = (cairo_xcb_picture_t *)
874 _cairo_xcb_screen_lookup_linear_picture (target->screen, pattern);
878 stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf));
879 if (unlikely (stops == NULL))
880 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
882 picture = _cairo_xcb_picture_create (target->screen,
883 target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
886 if (unlikely (picture->base.status)) {
887 if (stops != (xcb_render_fixed_t *) buf)
891 picture->filter = CAIRO_FILTER_DEFAULT;
893 colors = (xcb_render_color_t *) (stops + n_stops);
895 p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
896 p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
897 p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
898 p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
900 _cairo_xcb_connection_render_create_linear_gradient (target->connection,
906 if (stops != (xcb_render_fixed_t *) buf)
909 status = _cairo_xcb_screen_store_linear_picture (target->screen,
912 if (unlikely (status)) {
913 cairo_surface_destroy (&picture->base);
914 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
918 _cairo_xcb_picture_set_matrix (picture, &matrix,
919 pattern->base.base.filter,
920 extents->x + extents->width/2.,
921 extents->y + extents->height/2.);
922 _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter, 0, NULL);
923 _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
924 _cairo_xcb_picture_set_component_alpha (picture,
925 pattern->base.base.has_component_alpha);
930 static cairo_xcb_picture_t *
931 _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
932 const cairo_radial_pattern_t *pattern,
933 const cairo_rectangle_int_t *extents)
935 char buf[CAIRO_STACK_BUFFER_SIZE];
936 xcb_render_fixed_t *stops;
937 xcb_render_color_t *colors;
938 xcb_render_pointfix_t p1, p2;
939 xcb_render_fixed_t r1, r2;
940 cairo_matrix_t matrix;
941 cairo_circle_double_t extremes[2];
942 cairo_xcb_picture_t *picture;
943 cairo_status_t status;
944 unsigned int n_stops;
946 _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
948 picture = (cairo_xcb_picture_t *)
949 _cairo_xcb_screen_lookup_radial_picture (target->screen, pattern);
953 stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf));
954 if (unlikely (stops == NULL))
955 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
957 picture = _cairo_xcb_picture_create (target->screen,
958 target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
961 if (unlikely (picture->base.status)) {
962 if (stops != (xcb_render_fixed_t *) buf)
966 picture->filter = CAIRO_FILTER_DEFAULT;
968 colors = (xcb_render_color_t *) (stops + n_stops);
970 p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
971 p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
972 p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
973 p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
975 r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
976 r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
978 _cairo_xcb_connection_render_create_radial_gradient (target->connection,
984 if (stops != (xcb_render_fixed_t *) buf)
987 status = _cairo_xcb_screen_store_radial_picture (target->screen,
990 if (unlikely (status)) {
991 cairo_surface_destroy (&picture->base);
992 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
996 _cairo_xcb_picture_set_matrix (picture, &matrix,
997 pattern->base.base.filter,
998 extents->x + extents->width/2.,
999 extents->y + extents->height/2.);
1000 _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter, 0, NULL);
1001 _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
1002 _cairo_xcb_picture_set_component_alpha (picture,
1003 pattern->base.base.has_component_alpha);
1008 static cairo_xcb_picture_t *
1009 _copy_to_picture (cairo_xcb_surface_t *source)
1011 cairo_xcb_picture_t *picture;
1012 uint32_t values[] = { 0, 1 };
1014 if (source->deferred_clear) {
1015 cairo_status_t status = _cairo_xcb_surface_clear (source);
1016 if (unlikely (status))
1017 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
1020 picture = _cairo_xcb_picture_create (source->screen,
1021 source->xrender_format,
1022 source->pixman_format,
1025 if (unlikely (picture->base.status))
1028 _cairo_xcb_connection_render_create_picture (source->connection,
1031 source->xrender_format,
1032 XCB_RENDER_CP_GRAPHICS_EXPOSURE |
1033 XCB_RENDER_CP_SUBWINDOW_MODE,
1040 _cairo_xcb_surface_setup_surface_picture(cairo_xcb_picture_t *picture,
1041 const cairo_surface_pattern_t *pattern,
1042 const cairo_rectangle_int_t *extents)
1044 cairo_filter_t filter;
1046 filter = pattern->base.filter;
1047 if (filter != CAIRO_FILTER_NEAREST &&
1048 _cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
1049 _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.x0)) &&
1050 _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.y0)))
1052 filter = CAIRO_FILTER_NEAREST;
1054 _cairo_xcb_picture_set_filter (picture, filter, 0, NULL);
1056 _cairo_xcb_picture_set_matrix (picture,
1057 &pattern->base.matrix, filter,
1058 extents->x + extents->width/2.,
1059 extents->y + extents->height/2.);
1062 _cairo_xcb_picture_set_extend (picture, pattern->base.extend);
1063 _cairo_xcb_picture_set_component_alpha (picture, pattern->base.has_component_alpha);
1066 static cairo_xcb_picture_t *
1067 record_to_picture (cairo_surface_t *target,
1068 const cairo_surface_pattern_t *pattern,
1069 const cairo_rectangle_int_t *extents)
1071 cairo_surface_pattern_t tmp_pattern;
1072 cairo_xcb_picture_t *picture;
1073 cairo_status_t status;
1074 cairo_matrix_t matrix;
1075 cairo_surface_t *tmp;
1076 cairo_surface_t *source;
1077 cairo_rectangle_int_t limit;
1078 cairo_extend_t extend;
1080 /* XXX: The following was once more or less copied from cairo-xlibs-ource.c,
1081 * record_source() and recording_pattern_get_surface(), can we share a
1085 /* First get the 'real' recording surface and figure out the size for tmp */
1086 source = _cairo_pattern_get_source (pattern, &limit);
1087 assert (_cairo_surface_is_recording (source));
1089 if (! _cairo_matrix_is_identity (&pattern->base.matrix)) {
1090 double x1, y1, x2, y2;
1092 matrix = pattern->base.matrix;
1093 status = cairo_matrix_invert (&matrix);
1094 assert (status == CAIRO_STATUS_SUCCESS);
1098 x2 = limit.x + limit.width;
1099 y2 = limit.y + limit.height;
1101 _cairo_matrix_transform_bounding_box (&matrix,
1102 &x1, &y1, &x2, &y2, NULL);
1104 limit.x = floor (x1);
1105 limit.y = floor (y1);
1106 limit.width = ceil (x2) - limit.x;
1107 limit.height = ceil (y2) - limit.y;
1109 extend = pattern->base.extend;
1110 if (_cairo_rectangle_contains_rectangle (&limit, extents))
1111 extend = CAIRO_EXTEND_NONE;
1112 if (extend == CAIRO_EXTEND_NONE && ! _cairo_rectangle_intersect (&limit, extents))
1113 return _cairo_xcb_transparent_picture ((cairo_xcb_surface_t *) target);
1115 /* Now draw the recording surface to an xcb surface */
1116 tmp = _cairo_surface_create_similar_scratch (target,
1120 if (tmp->status != CAIRO_STATUS_SUCCESS) {
1121 return (cairo_xcb_picture_t *) tmp;
1124 cairo_matrix_init_translate (&matrix, limit.x, limit.y);
1125 cairo_matrix_multiply (&matrix, &matrix, &pattern->base.matrix);
1127 status = _cairo_recording_surface_replay_with_clip (source,
1130 if (unlikely (status)) {
1131 cairo_surface_destroy (tmp);
1132 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
1135 /* Now that we have drawn this to an xcb surface, try again with that */
1136 _cairo_pattern_init_static_copy (&tmp_pattern.base, &pattern->base);
1137 tmp_pattern.surface = tmp;
1138 cairo_matrix_init_translate (&tmp_pattern.base.matrix, -limit.x, -limit.y);
1140 picture = _copy_to_picture ((cairo_xcb_surface_t *) tmp);
1141 if (picture->base.status == CAIRO_STATUS_SUCCESS)
1142 _cairo_xcb_surface_setup_surface_picture (picture, &tmp_pattern, extents);
1143 cairo_surface_destroy (tmp);
1147 static cairo_xcb_picture_t *
1148 _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
1149 const cairo_surface_pattern_t *pattern,
1150 const cairo_rectangle_int_t *extents)
1152 cairo_surface_t *source = pattern->surface;
1153 cairo_xcb_picture_t *picture = NULL;
1154 cairo_xcb_picture_t *filtered_picture;
1155 cairo_bool_t is_gaussian_filter = FALSE;
1156 cairo_surface_pattern_t *orig_pattern = (cairo_surface_pattern_t *)pattern;
1158 picture = (cairo_xcb_picture_t *)
1159 _cairo_surface_has_snapshot (source, &_cairo_xcb_picture_backend);
1160 if (picture != NULL) {
1161 if (picture->screen == target->screen) {
1162 picture = (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
1163 _cairo_xcb_surface_setup_surface_picture (picture, pattern, extents);
1164 if (pattern->base.filter == CAIRO_FILTER_GAUSSIAN) {
1165 orig_pattern->base.filter = CAIRO_FILTER_NEAREST;
1166 is_gaussian_filter = TRUE;
1169 /* apply gaussian filter if pattern filter is gaussian */
1170 if (is_gaussian_filter)
1171 orig_pattern->base.filter = CAIRO_FILTER_GAUSSIAN;
1173 filtered_picture = _cairo_xcb_gaussian_filter (target,
1177 /* restore transform */
1178 if (filtered_picture != picture) {
1179 _cairo_xcb_picture_set_matrix (filtered_picture,
1180 &pattern->base.matrix,
1181 pattern->base.filter,
1182 extents->x + extents->width/2.,
1183 extents->y + extents->height/2.);
1185 _cairo_xcb_picture_set_matrix (picture,
1186 &pattern->base.matrix,
1187 pattern->base.filter,
1188 extents->x + extents->width/2.,
1189 extents->y + extents->height/2.);
1192 _cairo_xcb_surface_setup_surface_picture (filtered_picture, pattern, extents);
1194 cairo_surface_destroy (&picture->base);
1195 return filtered_picture;
1200 if (source->type == CAIRO_SURFACE_TYPE_XCB)
1202 if (source->backend->type == CAIRO_SURFACE_TYPE_XCB) {
1203 cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) source;
1204 if (xcb->screen == target->screen && xcb->fallback == NULL) {
1205 picture = _copy_to_picture ((cairo_xcb_surface_t *) source);
1206 if (unlikely (picture->base.status))
1209 } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1210 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
1211 cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) sub->target;
1213 /* XXX repeat interval with source clipping? */
1214 if (FALSE && xcb->screen == target->screen && xcb->fallback == NULL) {
1215 xcb_rectangle_t rect;
1217 picture = _copy_to_picture (xcb);
1218 if (unlikely (picture->base.status))
1221 rect.x = sub->extents.x;
1222 rect.y = sub->extents.y;
1223 rect.width = sub->extents.width;
1224 rect.height = sub->extents.height;
1226 _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
1230 picture->x0 = rect.x;
1231 picture->y0 = rect.y;
1232 picture->width = rect.width;
1233 picture->height = rect.height;
1235 } else if (_cairo_surface_is_snapshot (source)) {
1236 cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
1237 cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) snap->target;
1239 if (xcb->screen == target->screen && xcb->fallback == NULL) {
1240 picture = _copy_to_picture (xcb);
1241 if (unlikely (picture->base.status))
1246 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1247 else if (source->type == CAIRO_SURFACE_TYPE_XLIB)
1249 if (source->backend->type == CAIRO_SURFACE_TYPE_XLIB) {
1250 cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) source)->xcb;
1251 if (xcb->screen == target->screen && xcb->fallback == NULL) {
1252 picture = _copy_to_picture (xcb);
1253 if (unlikely (picture->base.status))
1256 } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1257 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
1258 cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) sub->target)->xcb;
1260 if (FALSE && xcb->screen == target->screen && xcb->fallback == NULL) {
1261 xcb_rectangle_t rect;
1263 picture = _copy_to_picture (xcb);
1264 if (unlikely (picture->base.status))
1267 rect.x = sub->extents.x;
1268 rect.y = sub->extents.y;
1269 rect.width = sub->extents.width;
1270 rect.height = sub->extents.height;
1272 _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
1276 picture->x0 = rect.x;
1277 picture->y0 = rect.y;
1278 picture->width = rect.width;
1279 picture->height = rect.height;
1281 } else if (_cairo_surface_is_snapshot (source)) {
1282 cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
1283 cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) snap->target)->xcb;
1285 if (xcb->screen == target->screen && xcb->fallback == NULL) {
1286 picture = _copy_to_picture (xcb);
1287 if (unlikely (picture->base.status))
1293 #if CAIRO_HAS_GL_FUNCTIONS
1294 else if (source->type == CAIRO_SURFACE_TYPE_GL)
1296 /* pixmap from texture */
1299 else if (source->type == CAIRO_SURFACE_TYPE_RECORDING)
1301 /* We have to skip the call to attach_snapshot() because we possibly
1302 * only drew part of the recording surface.
1303 * TODO: When can we safely attach a snapshot?
1306 /* XXX: do we rely on record implementation of blur? */
1307 return record_to_picture(&target->base, pattern, extents);
1310 if (picture == NULL) {
1311 cairo_image_surface_t *image;
1313 cairo_status_t status;
1315 status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
1316 if (unlikely (status))
1317 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
1319 if (image->format != CAIRO_FORMAT_INVALID) {
1320 xcb_render_pictformat_t format;
1322 format = target->screen->connection->standard_formats[image->format];
1324 picture = _picture_from_image (target, format, image, NULL);
1325 _cairo_surface_release_source_image (source, image, image_extra);
1327 cairo_image_surface_t *conv;
1328 xcb_render_pictformat_t render_format;
1330 /* XXX XRenderPutImage! */
1332 conv = _cairo_image_surface_coerce (image);
1333 _cairo_surface_release_source_image (source, image, image_extra);
1334 if (unlikely (conv->base.status))
1335 return (cairo_xcb_picture_t *) conv;
1337 render_format = target->screen->connection->standard_formats[conv->format];
1338 picture = _picture_from_image (target, render_format, conv, NULL);
1339 cairo_surface_destroy (&conv->base);
1342 if (unlikely (picture->base.status))
1346 _cairo_surface_attach_snapshot (source,
1350 if (pattern->base.filter == CAIRO_FILTER_GAUSSIAN) {
1351 orig_pattern->base.filter = CAIRO_FILTER_NEAREST;
1352 is_gaussian_filter = TRUE;
1355 /* apply gaussian filter if pattern filter is gaussian */
1356 if (is_gaussian_filter)
1357 orig_pattern->base.filter = CAIRO_FILTER_GAUSSIAN;
1359 filtered_picture = _cairo_xcb_gaussian_filter (target, picture, &pattern->base);
1361 /* restore transform */
1362 if (filtered_picture != picture) {
1363 _cairo_xcb_picture_set_matrix (filtered_picture,
1364 &pattern->base.matrix,
1365 pattern->base.filter,
1366 extents->x + extents->width/2.,
1367 extents->y + extents->height/2.);
1369 _cairo_xcb_picture_set_matrix (picture,
1370 &pattern->base.matrix,
1371 pattern->base.filter,
1372 extents->x + extents->width/2.,
1373 extents->y + extents->height/2.);
1376 _cairo_xcb_surface_setup_surface_picture (filtered_picture, pattern, extents);
1378 cairo_surface_destroy (&picture->base);
1379 return filtered_picture;
1382 static cairo_xcb_picture_t *
1383 _cairo_xcb_picture_for_pattern (cairo_xcb_surface_t *target,
1384 const cairo_pattern_t *pattern,
1385 const cairo_rectangle_int_t *extents)
1387 if (pattern == NULL)
1388 return _cairo_xcb_white_picture (target);
1390 if (! _pattern_is_supported (target->connection->flags, pattern))
1391 return _render_to_picture (target, pattern, extents);
1393 switch (pattern->type) {
1394 case CAIRO_PATTERN_TYPE_SOLID:
1395 return _cairo_xcb_solid_picture (target, (cairo_solid_pattern_t *) pattern);
1397 case CAIRO_PATTERN_TYPE_LINEAR:
1398 return _cairo_xcb_linear_picture (target,
1399 (cairo_linear_pattern_t *) pattern,
1402 case CAIRO_PATTERN_TYPE_RADIAL:
1403 return _cairo_xcb_radial_picture (target,
1404 (cairo_radial_pattern_t *) pattern,
1407 case CAIRO_PATTERN_TYPE_SURFACE:
1408 return _cairo_xcb_surface_picture (target, (cairo_surface_pattern_t *) pattern,
1413 case CAIRO_PATTERN_TYPE_MESH:
1414 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1415 return _render_to_picture (target, pattern, extents);
1419 COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t) <= sizeof (cairo_box_t));
1421 static cairo_status_t
1422 _render_fill_boxes (void *abstract_dst,
1423 cairo_operator_t op,
1424 const cairo_color_t *color,
1425 cairo_boxes_t *boxes)
1427 cairo_xcb_surface_t *dst = abstract_dst;
1428 xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (sizeof (xcb_rectangle_t))];
1429 xcb_rectangle_t *xrects = stack_xrects;
1430 xcb_render_color_t render_color;
1431 int render_op = _render_operator (op);
1432 struct _cairo_boxes_chunk *chunk;
1435 render_color.red = color->red_short;
1436 render_color.green = color->green_short;
1437 render_color.blue = color->blue_short;
1438 render_color.alpha = color->alpha_short;
1441 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
1442 if (chunk->count > max_count)
1443 max_count = chunk->count;
1445 if (max_count > ARRAY_LENGTH (stack_xrects)) {
1446 xrects = _cairo_malloc_ab (max_count, sizeof (xcb_rectangle_t));
1447 if (unlikely (xrects == NULL))
1448 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1451 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
1454 for (i = j = 0; i < chunk->count; i++) {
1455 int x1 = _cairo_fixed_integer_round_down (chunk->base[i].p1.x);
1456 int y1 = _cairo_fixed_integer_round_down (chunk->base[i].p1.y);
1457 int x2 = _cairo_fixed_integer_round_down (chunk->base[i].p2.x);
1458 int y2 = _cairo_fixed_integer_round_down (chunk->base[i].p2.y);
1460 if (x2 > x1 && y2 > y1) {
1463 xrects[j].width = x2 - x1;
1464 xrects[j].height = y2 - y1;
1470 _cairo_xcb_connection_render_fill_rectangles
1472 render_op, dst->picture,
1473 render_color, j, xrects);
1477 if (xrects != stack_xrects)
1480 return CAIRO_STATUS_SUCCESS;
1483 /* pixel aligned, non-overlapping boxes */
1484 static cairo_int_status_t
1485 _render_composite_boxes (cairo_xcb_surface_t *dst,
1486 cairo_operator_t op,
1487 const cairo_pattern_t *src_pattern,
1488 const cairo_pattern_t *mask_pattern,
1489 const cairo_rectangle_int_t *extents,
1490 const cairo_boxes_t *boxes)
1492 cairo_xcb_picture_t *src, *mask;
1493 const struct _cairo_boxes_chunk *chunk;
1494 xcb_rectangle_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
1495 xcb_rectangle_t *clip_boxes;
1496 cairo_rectangle_int_t stack_extents;
1497 cairo_status_t status;
1501 render_op = _render_operator (op);
1503 if (src_pattern == NULL) {
1504 src_pattern = mask_pattern;
1505 mask_pattern = NULL;
1508 /* amalgamate into a single Composite call by setting a clip region */
1509 clip_boxes = stack_boxes;
1510 if (boxes->num_boxes > ARRAY_LENGTH (stack_boxes)) {
1511 clip_boxes = _cairo_malloc_ab (boxes->num_boxes, sizeof (xcb_rectangle_t));
1512 if (unlikely (clip_boxes == NULL))
1513 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1516 src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
1517 status = src->base.status;
1518 if (unlikely (status))
1522 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
1523 const cairo_box_t *box = chunk->base;
1526 for (i = 0; i < chunk->count; i++) {
1527 int x = _cairo_fixed_integer_round_down (box[i].p1.x);
1528 int y = _cairo_fixed_integer_round_down (box[i].p1.y);
1529 int width = _cairo_fixed_integer_round_down (box[i].p2.x) - x;
1530 int height = _cairo_fixed_integer_round_down (box[i].p2.y) - y;
1532 if (width && height) {
1533 clip_boxes[num_boxes].x = x;
1534 clip_boxes[num_boxes].y = y;
1535 clip_boxes[num_boxes].width = width;
1536 clip_boxes[num_boxes].height = height;
1543 if (num_boxes > 1) {
1544 _cairo_xcb_connection_render_set_picture_clip_rectangles (dst->connection,
1550 stack_extents.x = clip_boxes[0].x;
1551 stack_extents.y = clip_boxes[0].y;
1552 stack_extents.width = clip_boxes[0].width;
1553 stack_extents.height = clip_boxes[0].height;
1554 extents = &stack_extents;
1557 if (mask_pattern != NULL) {
1558 mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
1559 status = mask->base.status;
1560 if (unlikely (status))
1563 _cairo_xcb_connection_render_composite (dst->connection,
1568 src->x + extents->x, src->y + extents->y,
1569 mask->x + extents->x, mask->y + extents->y,
1570 extents->x, extents->y,
1571 extents->width, extents->height);
1573 cairo_surface_destroy (&mask->base);
1576 _cairo_xcb_connection_render_composite (dst->connection,
1581 src->x + extents->x, src->y + extents->y,
1583 extents->x, extents->y,
1584 extents->width, extents->height);
1591 _cairo_xcb_surface_clear_clip_region (dst);
1594 cairo_surface_destroy (&src->base);
1598 if (clip_boxes != stack_boxes)
1605 #define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
1606 #define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
1609 _line_exceeds_16_16 (const cairo_line_t *line)
1612 line->p1.x <= CAIRO_FIXED_16_16_MIN ||
1613 line->p1.x >= CAIRO_FIXED_16_16_MAX ||
1615 line->p2.x <= CAIRO_FIXED_16_16_MIN ||
1616 line->p2.x >= CAIRO_FIXED_16_16_MAX ||
1618 line->p1.y <= CAIRO_FIXED_16_16_MIN ||
1619 line->p1.y >= CAIRO_FIXED_16_16_MAX ||
1621 line->p2.y <= CAIRO_FIXED_16_16_MIN ||
1622 line->p2.y >= CAIRO_FIXED_16_16_MAX;
1626 _project_line_x_onto_16_16 (const cairo_line_t *line,
1628 cairo_fixed_t bottom,
1629 xcb_render_linefix_t *out)
1631 cairo_point_double_t p1, p2;
1634 p1.x = _cairo_fixed_to_double (line->p1.x);
1635 p1.y = _cairo_fixed_to_double (line->p1.y);
1637 p2.x = _cairo_fixed_to_double (line->p2.x);
1638 p2.y = _cairo_fixed_to_double (line->p2.y);
1640 m = (p2.x - p1.x) / (p2.y - p1.y);
1641 out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
1642 out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
1646 cairo_traps_t traps;
1647 cairo_antialias_t antialias;
1648 } composite_traps_info_t;
1650 COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t) <= sizeof (cairo_trapezoid_t));
1652 static cairo_int_status_t
1653 _composite_traps (void *closure,
1654 cairo_xcb_surface_t *dst,
1655 cairo_operator_t op,
1656 const cairo_pattern_t *pattern,
1657 int dst_x, int dst_y,
1658 const cairo_rectangle_int_t *extents,
1661 composite_traps_info_t *info = closure;
1662 const cairo_traps_t *traps = &info->traps;
1663 cairo_xcb_picture_t *src;
1664 cairo_format_t format;
1665 xcb_render_pictformat_t xrender_format;
1666 xcb_render_trapezoid_t *xtraps;
1667 int render_reference_x, render_reference_y;
1668 cairo_status_t status;
1671 if (dst->deferred_clear) {
1672 status = _cairo_xcb_surface_clear (dst);
1673 if (unlikely (status))
1677 src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
1678 if (unlikely (src->base.status))
1679 return src->base.status;
1681 if (info->antialias == CAIRO_ANTIALIAS_NONE)
1682 format = CAIRO_FORMAT_A1;
1684 format = CAIRO_FORMAT_A8;
1685 xrender_format = dst->screen->connection->standard_formats[format];
1687 xtraps = (xcb_render_trapezoid_t *) traps->traps;
1688 for (i = 0; i < traps->num_traps; i++) {
1689 cairo_trapezoid_t t = traps->traps[i];
1691 /* top/bottom will be clamped to surface bounds */
1692 xtraps[i].top = _cairo_fixed_to_16_16 (t.top);
1693 xtraps[i].top -= dst_y << 16;
1694 xtraps[i].bottom = _cairo_fixed_to_16_16 (t.bottom);
1695 xtraps[i].bottom -= dst_y << 16;
1697 /* However, all the other coordinates will have been left untouched so
1698 * as not to introduce numerical error. Recompute them if they
1699 * exceed the 16.16 limits.
1701 if (unlikely (_line_exceeds_16_16 (&t.left))) {
1702 _project_line_x_onto_16_16 (&t.left,
1706 xtraps[i].left.p1.y = xtraps[i].top;
1707 xtraps[i].left.p2.y = xtraps[i].bottom;
1709 xtraps[i].left.p1.x = _cairo_fixed_to_16_16 (t.left.p1.x);
1710 xtraps[i].left.p1.y = _cairo_fixed_to_16_16 (t.left.p1.y);
1711 xtraps[i].left.p2.x = _cairo_fixed_to_16_16 (t.left.p2.x);
1712 xtraps[i].left.p2.y = _cairo_fixed_to_16_16 (t.left.p2.y);
1714 xtraps[i].left.p1.x -= dst_x << 16;
1715 xtraps[i].left.p1.y -= dst_y << 16;
1716 xtraps[i].left.p2.x -= dst_x << 16;
1717 xtraps[i].left.p2.y -= dst_y << 16;
1719 if (unlikely (_line_exceeds_16_16 (&t.right))) {
1720 _project_line_x_onto_16_16 (&t.right,
1724 xtraps[i].right.p1.y = xtraps[i].top;
1725 xtraps[i].right.p2.y = xtraps[i].bottom;
1727 xtraps[i].right.p1.x = _cairo_fixed_to_16_16 (t.right.p1.x);
1728 xtraps[i].right.p1.y = _cairo_fixed_to_16_16 (t.right.p1.y);
1729 xtraps[i].right.p2.x = _cairo_fixed_to_16_16 (t.right.p2.x);
1730 xtraps[i].right.p2.y = _cairo_fixed_to_16_16 (t.right.p2.y);
1732 xtraps[i].right.p1.x -= dst_x << 16;
1733 xtraps[i].right.p1.y -= dst_y << 16;
1734 xtraps[i].right.p2.x -= dst_x << 16;
1735 xtraps[i].right.p2.y -= dst_y << 16;
1738 if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
1739 render_reference_x = xtraps[0].left.p1.x >> 16;
1740 render_reference_y = xtraps[0].left.p1.y >> 16;
1742 render_reference_x = xtraps[0].left.p2.x >> 16;
1743 render_reference_y = xtraps[0].left.p2.y >> 16;
1745 render_reference_x += src->x + dst_x;
1746 render_reference_y += src->y + dst_y;
1748 _cairo_xcb_surface_set_precision (dst, info->antialias);
1749 _cairo_xcb_connection_render_trapezoids (dst->connection,
1750 _render_operator (op),
1756 traps->num_traps, xtraps);
1758 cairo_surface_destroy (&src->base);
1760 return CAIRO_STATUS_SUCCESS;
1763 /* low-level composite driver */
1765 static cairo_xcb_surface_t *
1766 get_clip_surface (const cairo_clip_t *clip,
1767 cairo_xcb_surface_t *target,
1770 cairo_surface_t *surface;
1771 cairo_status_t status;
1773 surface = _cairo_surface_create_similar_solid (&target->base,
1774 CAIRO_CONTENT_ALPHA,
1775 clip->extents.width,
1776 clip->extents.height,
1778 if (unlikely (surface->status))
1779 return (cairo_xcb_surface_t *) surface;
1781 assert (surface->backend == &_cairo_xcb_surface_backend);
1782 status = _cairo_clip_combine_with_surface (clip, surface,
1783 clip->extents.x, clip->extents.y);
1784 if (unlikely (status)) {
1785 cairo_surface_destroy (surface);
1786 surface = _cairo_surface_create_in_error (status);
1789 *tx = clip->extents.x;
1790 *ty = clip->extents.y;
1792 return (cairo_xcb_surface_t *) surface;
1795 typedef cairo_int_status_t
1796 (*xcb_draw_func_t) (void *closure,
1797 cairo_xcb_surface_t *dst,
1798 cairo_operator_t op,
1799 const cairo_pattern_t *src,
1802 const cairo_rectangle_int_t *extents,
1803 cairo_clip_t *clip);
1805 static void do_unaligned_row(void (*blt)(void *closure,
1806 int16_t x, int16_t y,
1807 int16_t w, int16_t h,
1810 const cairo_box_t *b,
1811 int tx, int y, int h,
1814 int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
1815 int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
1817 if (! _cairo_fixed_is_integer (b->p1.x)) {
1818 blt(closure, x1, y, 1, h,
1819 coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
1824 blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
1826 if (! _cairo_fixed_is_integer (b->p2.x))
1827 blt(closure, x2, y, 1, h,
1828 coverage * _cairo_fixed_fractional_part (b->p2.x));
1830 blt(closure, x1, y, 1, h,
1831 coverage * (b->p2.x - b->p1.x));
1834 static void do_unaligned_box(void (*blt)(void *closure,
1835 int16_t x, int16_t y,
1836 int16_t w, int16_t h,
1839 const cairo_box_t *b, int tx, int ty)
1841 int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
1842 int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
1844 if (! _cairo_fixed_is_integer (b->p1.y)) {
1845 do_unaligned_row(blt, closure, b, tx, y1, 1,
1846 256 - _cairo_fixed_fractional_part (b->p1.y));
1851 do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
1853 if (! _cairo_fixed_is_integer (b->p2.y))
1854 do_unaligned_row(blt, closure, b, tx, y2, 1,
1855 _cairo_fixed_fractional_part (b->p2.y));
1857 do_unaligned_row(blt, closure, b, tx, y1, 1,
1862 static void blt_in(void *closure,
1863 int16_t x, int16_t y,
1864 int16_t w, int16_t h,
1867 cairo_xcb_surface_t *mask = closure;
1868 xcb_render_color_t color;
1869 xcb_rectangle_t rect;
1871 if (coverage == 0xffff)
1874 color.red = color.green = color.blue = 0;
1875 color.alpha = coverage;
1882 _cairo_xcb_connection_render_fill_rectangles (mask->connection,
1883 XCB_RENDER_PICT_OP_IN,
1888 static cairo_xcb_surface_t *
1889 _create_composite_mask (cairo_clip_t *clip,
1890 xcb_draw_func_t draw_func,
1891 xcb_draw_func_t mask_func,
1893 cairo_xcb_surface_t *dst,
1894 const cairo_rectangle_int_t*extents)
1896 cairo_xcb_surface_t *surface;
1897 cairo_bool_t need_clip_combine;
1898 cairo_int_status_t status;
1900 surface = (cairo_xcb_surface_t *)
1901 _cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA,
1902 extents->width, extents->height);
1903 if (unlikely (surface->base.status))
1906 _cairo_xcb_surface_ensure_picture (surface);
1908 surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
1909 surface->deferred_clear = TRUE;
1910 surface->base.is_clear = TRUE;
1913 status = mask_func (draw_closure, surface,
1914 CAIRO_OPERATOR_ADD, NULL,
1915 extents->x, extents->y,
1917 if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
1921 /* Is it worth setting the clip region here? */
1922 status = draw_func (draw_closure, surface,
1923 CAIRO_OPERATOR_ADD, NULL,
1924 extents->x, extents->y,
1926 if (unlikely (status)) {
1927 cairo_surface_destroy (&surface->base);
1928 return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
1931 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
1934 for (i = 0; i < clip->num_boxes; i++) {
1935 cairo_box_t *b = &clip->boxes[i];
1937 if (! _cairo_fixed_is_integer (b->p1.x) ||
1938 ! _cairo_fixed_is_integer (b->p1.y) ||
1939 ! _cairo_fixed_is_integer (b->p2.x) ||
1940 ! _cairo_fixed_is_integer (b->p2.y))
1942 do_unaligned_box(blt_in, surface, b, extents->x, extents->y);
1946 need_clip_combine = clip->path != NULL;
1948 need_clip_combine = ! _cairo_clip_is_region (clip);
1950 if (need_clip_combine) {
1951 status = _cairo_clip_combine_with_surface (clip, &surface->base,
1952 extents->x, extents->y);
1953 if (unlikely (status)) {
1954 cairo_surface_destroy (&surface->base);
1955 return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
1962 /* Handles compositing with a clip surface when the operator allows
1963 * us to combine the clip with the mask
1965 static cairo_status_t
1966 _clip_and_composite_with_mask (cairo_clip_t *clip,
1967 cairo_operator_t op,
1968 const cairo_pattern_t *pattern,
1969 xcb_draw_func_t draw_func,
1970 xcb_draw_func_t mask_func,
1972 cairo_xcb_surface_t *dst,
1973 const cairo_rectangle_int_t*extents)
1975 cairo_xcb_surface_t *mask;
1976 cairo_xcb_picture_t *src;
1977 cairo_status_t status;
1979 mask = _create_composite_mask (clip,
1980 draw_func, mask_func, draw_closure,
1982 if (unlikely (mask->base.status)) {
1983 status = mask->base.status;
1984 cairo_surface_destroy (&mask->base);
1988 if (pattern != NULL || dst->base.content != CAIRO_CONTENT_ALPHA) {
1989 src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
1990 if (unlikely (src->base.status)) {
1991 cairo_surface_destroy (&mask->base);
1992 return src->base.status;
1995 _cairo_xcb_connection_render_composite (dst->connection,
1996 _render_operator (op),
2000 extents->x + src->x, extents->y + src->y,
2002 extents->x, extents->y,
2003 extents->width, extents->height);
2005 cairo_surface_destroy (&src->base);
2007 _cairo_xcb_connection_render_composite (dst->connection,
2008 _render_operator (op),
2014 extents->x, extents->y,
2015 extents->width, extents->height);
2017 cairo_surface_destroy (&mask->base);
2019 return CAIRO_STATUS_SUCCESS;
2022 /* Handles compositing with a clip surface when we have to do the operation
2023 * in two pieces and combine them together.
2025 static cairo_status_t
2026 _clip_and_composite_combine (cairo_clip_t *clip,
2027 cairo_operator_t op,
2028 const cairo_pattern_t *pattern,
2029 xcb_draw_func_t draw_func,
2031 cairo_xcb_surface_t *dst,
2032 const cairo_rectangle_int_t*extents)
2034 cairo_xcb_surface_t *tmp;
2035 cairo_xcb_surface_t *clip_surface;
2037 xcb_render_picture_t clip_picture;
2038 cairo_status_t status;
2040 tmp = (cairo_xcb_surface_t *)
2041 _cairo_xcb_surface_create_similar (dst, dst->base.content,
2042 extents->width, extents->height);
2043 if (unlikely (tmp->base.status)) {
2044 status = tmp->base.status;
2045 cairo_surface_destroy (&tmp->base);
2049 /* create_similar() could have done a fallback to an image surface */
2050 assert (tmp->base.backend == &_cairo_xcb_surface_backend);
2052 _cairo_xcb_surface_ensure_picture (tmp);
2054 if (pattern == NULL) {
2055 status = (*draw_func) (draw_closure, tmp,
2056 CAIRO_OPERATOR_ADD, NULL,
2057 extents->x, extents->y,
2060 /* Initialize the temporary surface from the destination surface */
2061 if (! dst->base.is_clear ||
2062 (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) == 0)
2064 /* XCopyArea may actually be quicker here.
2065 * A good driver should translate if appropriate.
2067 _cairo_xcb_connection_render_composite (dst->connection,
2068 XCB_RENDER_PICT_OP_SRC,
2072 extents->x, extents->y,
2075 extents->width, extents->height);
2079 xcb_render_color_t clear;
2080 xcb_rectangle_t xrect;
2082 clear.red = clear.green = clear.blue = clear.alpha = 0;
2084 xrect.x = xrect.y = 0;
2085 xrect.width = extents->width;
2086 xrect.height = extents->height;
2088 _cairo_xcb_connection_render_fill_rectangles (dst->connection,
2089 XCB_RENDER_PICT_OP_CLEAR,
2094 status = (*draw_func) (draw_closure, tmp, op, pattern,
2095 extents->x, extents->y,
2098 if (unlikely (status))
2099 goto CLEANUP_SURFACE;
2101 clip_surface = get_clip_surface (clip, dst, &clip_x, &clip_y);
2102 status = clip_surface->base.status;
2103 if (unlikely (status))
2104 goto CLEANUP_SURFACE;
2106 assert (clip_surface->base.backend == &_cairo_xcb_surface_backend);
2107 clip_picture = clip_surface->picture;
2108 assert (clip_picture != XCB_NONE);
2110 if (dst->base.is_clear) {
2111 _cairo_xcb_connection_render_composite (dst->connection,
2112 XCB_RENDER_PICT_OP_SRC,
2113 tmp->picture, clip_picture, dst->picture,
2116 extents->x, extents->y,
2117 extents->width, extents->height);
2119 /* Punch the clip out of the destination */
2120 _cairo_xcb_connection_render_composite (dst->connection,
2121 XCB_RENDER_PICT_OP_OUT_REVERSE,
2122 clip_picture, XCB_NONE, dst->picture,
2123 extents->x - clip_x,
2124 extents->y - clip_y,
2126 extents->x, extents->y,
2127 extents->width, extents->height);
2129 /* Now add the two results together */
2130 _cairo_xcb_connection_render_composite (dst->connection,
2131 XCB_RENDER_PICT_OP_ADD,
2132 tmp->picture, clip_picture, dst->picture,
2134 extents->x - clip_x,
2135 extents->y - clip_y,
2136 extents->x, extents->y,
2137 extents->width, extents->height);
2139 cairo_surface_destroy (&clip_surface->base);
2142 cairo_surface_destroy (&tmp->base);
2147 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
2148 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
2150 static cairo_status_t
2151 _clip_and_composite_source (cairo_clip_t *clip,
2152 const cairo_pattern_t *pattern,
2153 xcb_draw_func_t draw_func,
2154 xcb_draw_func_t mask_func,
2156 cairo_xcb_surface_t *dst,
2157 const cairo_rectangle_int_t *extents)
2159 cairo_xcb_surface_t *mask;
2160 cairo_xcb_picture_t *src;
2161 cairo_status_t status;
2163 /* Create a surface that is mask IN clip */
2164 mask = _create_composite_mask (clip,
2165 draw_func, mask_func, draw_closure,
2167 if (unlikely (mask->base.status)) {
2168 status = mask->base.status;
2169 cairo_surface_destroy (&mask->base);
2173 src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
2174 if (unlikely (src->base.status)) {
2175 cairo_surface_destroy (&mask->base);
2176 return src->base.status;
2179 if (dst->base.is_clear) {
2180 _cairo_xcb_connection_render_composite (dst->connection,
2181 XCB_RENDER_PICT_OP_SRC,
2185 extents->x + src->x, extents->y + src->y,
2187 extents->x, extents->y,
2188 extents->width, extents->height);
2190 /* Compute dest' = dest OUT (mask IN clip) */
2191 _cairo_xcb_connection_render_composite (dst->connection,
2192 XCB_RENDER_PICT_OP_OUT_REVERSE,
2197 extents->x, extents->y,
2198 extents->width, extents->height);
2200 /* Now compute (src IN (mask IN clip)) ADD dest' */
2201 _cairo_xcb_connection_render_composite (dst->connection,
2202 XCB_RENDER_PICT_OP_ADD,
2206 extents->x + src->x, extents->y + src->y,
2208 extents->x, extents->y,
2209 extents->width, extents->height);
2212 cairo_surface_destroy (&src->base);
2213 cairo_surface_destroy (&mask->base);
2215 return CAIRO_STATUS_SUCCESS;
2219 can_reduce_alpha_op (cairo_operator_t op)
2223 case CAIRO_OPERATOR_OVER:
2224 case CAIRO_OPERATOR_SOURCE:
2225 case CAIRO_OPERATOR_ADD:
2233 reduce_alpha_op (cairo_surface_t *dst,
2234 cairo_operator_t op,
2235 const cairo_pattern_t *pattern)
2237 return dst->is_clear &&
2238 dst->content == CAIRO_CONTENT_ALPHA &&
2239 _cairo_pattern_is_opaque_solid (pattern) &&
2240 can_reduce_alpha_op (op);
2243 static cairo_status_t
2244 _cairo_xcb_surface_fixup_unbounded (cairo_xcb_surface_t *dst,
2245 const cairo_composite_rectangles_t *rects)
2247 xcb_rectangle_t xrects[4];
2250 if (rects->bounded.width == rects->unbounded.width &&
2251 rects->bounded.height == rects->unbounded.height)
2253 return CAIRO_STATUS_SUCCESS;
2257 if (rects->bounded.width == 0 || rects->bounded.height == 0) {
2258 xrects[n].x = rects->unbounded.x;
2259 xrects[n].width = rects->unbounded.width;
2260 xrects[n].y = rects->unbounded.y;
2261 xrects[n].height = rects->unbounded.height;
2265 if (rects->bounded.y != rects->unbounded.y) {
2266 xrects[n].x = rects->unbounded.x;
2267 xrects[n].width = rects->unbounded.width;
2268 xrects[n].y = rects->unbounded.y;
2269 xrects[n].height = rects->bounded.y - rects->unbounded.y;
2273 if (rects->bounded.x != rects->unbounded.x) {
2274 xrects[n].x = rects->unbounded.x;
2275 xrects[n].width = rects->bounded.x - rects->unbounded.x;
2276 xrects[n].y = rects->bounded.y;
2277 xrects[n].height = rects->bounded.height;
2281 if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
2282 xrects[n].x = rects->bounded.x + rects->bounded.width;
2283 xrects[n].width = rects->unbounded.x + rects->unbounded.width - xrects[n].x;
2284 xrects[n].y = rects->bounded.y;
2285 xrects[n].height = rects->bounded.height;
2289 if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
2290 xrects[n].x = rects->unbounded.x;
2291 xrects[n].width = rects->unbounded.width;
2292 xrects[n].y = rects->bounded.y + rects->bounded.height;
2293 xrects[n].height = rects->unbounded.y + rects->unbounded.height - xrects[n].y;
2298 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
2299 xcb_render_color_t color;
2306 _cairo_xcb_connection_render_fill_rectangles (dst->connection,
2307 XCB_RENDER_PICT_OP_CLEAR,
2312 cairo_xcb_picture_t *src;
2314 src = _cairo_xcb_transparent_picture (dst);
2315 if (unlikely (src->base.status))
2316 return src->base.status;
2318 for (i = 0; i < n; i++) {
2319 _cairo_xcb_connection_render_composite (dst->connection,
2320 XCB_RENDER_PICT_OP_CLEAR,
2321 src->picture, XCB_NONE, dst->picture,
2324 xrects[i].x, xrects[i].y,
2325 xrects[i].width, xrects[i].height);
2327 cairo_surface_destroy (&src->base);
2330 return CAIRO_STATUS_SUCCESS;
2333 static cairo_status_t
2334 _cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst,
2335 const cairo_composite_rectangles_t *rects,
2338 cairo_xcb_surface_t *mask;
2341 mask = get_clip_surface (clip, dst, &mask_x, &mask_y);
2342 if (unlikely (mask->base.status))
2343 return mask->base.status;
2346 if (rects->bounded.y != rects->unbounded.y) {
2347 int x = rects->unbounded.x;
2348 int y = rects->unbounded.y;
2349 int width = rects->unbounded.width;
2350 int height = rects->bounded.y - y;
2352 _cairo_xcb_connection_render_composite (dst->connection,
2353 XCB_RENDER_PICT_OP_OUT_REVERSE,
2354 mask->picture, XCB_NONE, dst->picture,
2355 x - mask_x, y - mask_y,
2362 if (rects->bounded.x != rects->unbounded.x) {
2363 int x = rects->unbounded.x;
2364 int y = rects->bounded.y;
2365 int width = rects->bounded.x - x;
2366 int height = rects->bounded.height;
2368 _cairo_xcb_connection_render_composite (dst->connection,
2369 XCB_RENDER_PICT_OP_OUT_REVERSE,
2370 mask->picture, XCB_NONE, dst->picture,
2371 x - mask_x, y - mask_y,
2378 if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
2379 int x = rects->bounded.x + rects->bounded.width;
2380 int y = rects->bounded.y;
2381 int width = rects->unbounded.x + rects->unbounded.width - x;
2382 int height = rects->bounded.height;
2384 _cairo_xcb_connection_render_composite (dst->connection,
2385 XCB_RENDER_PICT_OP_OUT_REVERSE,
2386 mask->picture, XCB_NONE, dst->picture,
2387 x - mask_x, y - mask_y,
2394 if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
2395 int x = rects->unbounded.x;
2396 int y = rects->bounded.y + rects->bounded.height;
2397 int width = rects->unbounded.width;
2398 int height = rects->unbounded.y + rects->unbounded.height - y;
2400 _cairo_xcb_connection_render_composite (dst->connection,
2401 XCB_RENDER_PICT_OP_OUT_REVERSE,
2402 mask->picture, XCB_NONE, dst->picture,
2403 x - mask_x, y - mask_y,
2409 cairo_surface_destroy (&mask->base);
2411 return CAIRO_STATUS_SUCCESS;
2414 static cairo_status_t
2415 _cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst,
2416 const cairo_composite_rectangles_t *extents,
2418 cairo_boxes_t *boxes)
2420 cairo_boxes_t clear;
2422 cairo_status_t status;
2423 struct _cairo_boxes_chunk *chunk;
2426 if (boxes->num_boxes <= 1 && clip == NULL)
2427 return _cairo_xcb_surface_fixup_unbounded (dst, extents);
2429 _cairo_boxes_init (&clear);
2431 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
2432 box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
2433 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
2434 box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
2439 _cairo_boxes_init (&tmp);
2441 status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
2442 assert (status == CAIRO_STATUS_SUCCESS);
2444 tmp.chunks.next = &boxes->chunks;
2445 tmp.num_boxes += boxes->num_boxes;
2447 status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
2448 CAIRO_FILL_RULE_WINDING,
2451 tmp.chunks.next = NULL;
2453 _cairo_boxes_init_with_clip (&clear, clip);
2455 status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
2456 assert (status == CAIRO_STATUS_SUCCESS);
2458 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2459 for (i = 0; i < chunk->count; i++) {
2460 status = _cairo_boxes_add (&clear,
2461 CAIRO_ANTIALIAS_DEFAULT,
2463 if (unlikely (status)) {
2464 _cairo_boxes_fini (&clear);
2470 status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
2471 CAIRO_FILL_RULE_WINDING,
2475 if (likely (status == CAIRO_STATUS_SUCCESS)) {
2476 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES)
2477 status = _render_fill_boxes (dst,
2478 CAIRO_OPERATOR_CLEAR,
2479 CAIRO_COLOR_TRANSPARENT,
2482 status = _cairo_xcb_surface_core_fill_boxes (dst,
2483 CAIRO_COLOR_TRANSPARENT,
2487 _cairo_boxes_fini (&clear);
2493 _cairo_xcb_surface_clear (cairo_xcb_surface_t *dst)
2496 xcb_rectangle_t rect;
2497 cairo_status_t status;
2499 status = _cairo_xcb_connection_acquire (dst->connection);
2500 if (unlikely (status))
2503 rect.x = rect.y = 0;
2504 rect.width = dst->width;
2505 rect.height = dst->height;
2507 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
2508 xcb_render_color_t color;
2511 color.red = dst->deferred_clear_color.red_short;
2512 color.green = dst->deferred_clear_color.green_short;
2513 color.blue = dst->deferred_clear_color.blue_short;
2514 color.alpha = dst->deferred_clear_color.alpha_short;
2516 if (color.alpha == 0)
2517 op = XCB_RENDER_PICT_OP_CLEAR;
2519 op = XCB_RENDER_PICT_OP_SRC;
2521 _cairo_xcb_surface_ensure_picture (dst);
2522 _cairo_xcb_connection_render_fill_rectangles (dst->connection,
2523 op, dst->picture, color,
2526 gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
2529 _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
2533 _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
2536 _cairo_xcb_connection_release (dst->connection);
2538 dst->deferred_clear = FALSE;
2539 return CAIRO_STATUS_SUCCESS;
2543 NEED_CLIP_REGION = 0x1,
2544 NEED_CLIP_SURFACE = 0x2,
2545 FORCE_CLIP_REGION = 0x4,
2549 need_bounded_clip (cairo_composite_rectangles_t *extents)
2551 unsigned int flags = NEED_CLIP_REGION;
2552 if (! _cairo_clip_is_region (extents->clip))
2553 flags |= NEED_CLIP_SURFACE;
2558 need_unbounded_clip (cairo_composite_rectangles_t *extents)
2560 unsigned int flags = 0;
2561 if (! extents->is_bounded) {
2562 flags |= NEED_CLIP_REGION;
2563 if (! _cairo_clip_is_region (extents->clip))
2564 flags |= NEED_CLIP_SURFACE;
2566 if (extents->clip->path != NULL)
2567 flags |= NEED_CLIP_SURFACE;
2571 static cairo_status_t
2572 _clip_and_composite (cairo_xcb_surface_t *dst,
2573 cairo_operator_t op,
2574 const cairo_pattern_t *src,
2575 xcb_draw_func_t draw_func,
2576 xcb_draw_func_t mask_func,
2578 cairo_composite_rectangles_t*extents,
2579 unsigned int need_clip)
2581 cairo_region_t *clip_region = NULL;
2582 cairo_status_t status;
2584 status = _cairo_xcb_connection_acquire (dst->connection);
2585 if (unlikely (status))
2588 if (dst->deferred_clear) {
2589 status = _cairo_xcb_surface_clear (dst);
2590 if (unlikely (status)) {
2591 _cairo_xcb_connection_release (dst->connection);
2596 _cairo_xcb_surface_ensure_picture (dst);
2598 if (need_clip & NEED_CLIP_REGION) {
2599 clip_region = _cairo_clip_get_region (extents->clip);
2600 if ((need_clip & FORCE_CLIP_REGION) == 0 && clip_region != NULL &&
2601 cairo_region_contains_rectangle (clip_region,
2602 &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
2604 if (clip_region != NULL) {
2605 status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
2606 if (unlikely (status)) {
2607 _cairo_xcb_connection_release (dst->connection);
2613 if (reduce_alpha_op (&dst->base, op, src)) {
2614 op = CAIRO_OPERATOR_ADD;
2618 if (extents->bounded.width != 0 && extents->bounded.height != 0) {
2619 if (op == CAIRO_OPERATOR_SOURCE) {
2620 status = _clip_and_composite_source (extents->clip, src,
2621 draw_func, mask_func, draw_closure,
2622 dst, &extents->bounded);
2624 if (op == CAIRO_OPERATOR_CLEAR) {
2625 op = CAIRO_OPERATOR_DEST_OUT;
2629 if (need_clip & NEED_CLIP_SURFACE) {
2630 if (extents->is_bounded) {
2631 status = _clip_and_composite_with_mask (extents->clip, op, src,
2635 dst, &extents->bounded);
2637 status = _clip_and_composite_combine (extents->clip, op, src,
2638 draw_func, draw_closure,
2639 dst, &extents->bounded);
2642 status = draw_func (draw_closure,
2651 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
2652 if (need_clip & NEED_CLIP_SURFACE)
2653 status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, extents->clip);
2655 status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
2659 _cairo_xcb_surface_clear_clip_region (dst);
2661 _cairo_xcb_connection_release (dst->connection);
2666 static cairo_status_t
2667 _core_boxes (cairo_xcb_surface_t *dst,
2668 cairo_operator_t op,
2669 const cairo_pattern_t *src,
2670 cairo_boxes_t *boxes,
2671 const cairo_composite_rectangles_t *extents)
2673 if (! boxes->is_pixel_aligned)
2674 return CAIRO_INT_STATUS_UNSUPPORTED;
2676 if (! _cairo_clip_is_region (extents->clip))
2677 return CAIRO_INT_STATUS_UNSUPPORTED;
2679 if (op == CAIRO_OPERATOR_CLEAR)
2680 return _cairo_xcb_surface_core_fill_boxes (dst, CAIRO_COLOR_TRANSPARENT, boxes);
2682 if (op == CAIRO_OPERATOR_OVER) {
2683 if (dst->base.is_clear || _cairo_pattern_is_opaque (src, &extents->bounded))
2684 op = CAIRO_OPERATOR_SOURCE;
2686 if (op != CAIRO_OPERATOR_SOURCE)
2687 return CAIRO_INT_STATUS_UNSUPPORTED;
2689 if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
2690 return _cairo_xcb_surface_core_fill_boxes (dst,
2691 &((cairo_solid_pattern_t *) src)->color,
2695 return _cairo_xcb_surface_core_copy_boxes (dst, src, &extents->bounded, boxes);
2698 static cairo_status_t
2699 _composite_boxes (cairo_xcb_surface_t *dst,
2700 cairo_operator_t op,
2701 const cairo_pattern_t *src,
2702 cairo_boxes_t *boxes,
2703 const cairo_composite_rectangles_t *extents)
2705 cairo_clip_t *clip = extents->clip;
2706 cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (clip);
2707 cairo_status_t status;
2709 /* If the boxes are not pixel-aligned, we will need to compute a real mask */
2710 if (! boxes->is_pixel_aligned)
2711 return CAIRO_INT_STATUS_UNSUPPORTED;
2713 if (need_clip_mask &&
2714 (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
2716 return CAIRO_INT_STATUS_UNSUPPORTED;
2719 status = _cairo_xcb_connection_acquire (dst->connection);
2720 if (unlikely (status))
2723 _cairo_xcb_surface_ensure_picture (dst);
2724 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES && ! need_clip_mask &&
2725 (op == CAIRO_OPERATOR_CLEAR || src->type == CAIRO_PATTERN_TYPE_SOLID))
2727 const cairo_color_t *color;
2729 if (op == CAIRO_OPERATOR_CLEAR)
2730 color = CAIRO_COLOR_TRANSPARENT;
2732 color = &((cairo_solid_pattern_t *) src)->color;
2734 status = _render_fill_boxes (dst, op, color, boxes);
2738 cairo_surface_pattern_t mask;
2740 if (need_clip_mask) {
2741 cairo_xcb_surface_t *clip_surface;
2744 clip_surface = get_clip_surface (extents->clip, dst,
2746 if (unlikely (clip_surface->base.status))
2747 return clip_surface->base.status;
2749 _cairo_pattern_init_for_surface (&mask, &clip_surface->base);
2750 mask.base.filter = CAIRO_FILTER_NEAREST;
2751 cairo_matrix_init_translate (&mask.base.matrix,
2754 cairo_surface_destroy (&clip_surface->base);
2756 if (op == CAIRO_OPERATOR_CLEAR) {
2758 op = CAIRO_OPERATOR_DEST_OUT;
2762 status = _render_composite_boxes (dst, op, src,
2763 need_clip_mask ? &mask.base : NULL,
2764 &extents->bounded, boxes);
2767 _cairo_pattern_fini (&mask.base);
2770 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
2772 _cairo_xcb_surface_fixup_unbounded_boxes (dst, extents,
2776 _cairo_xcb_connection_release (dst->connection);
2782 cairo_boxes_for_each_box (cairo_boxes_t *boxes,
2783 cairo_bool_t (*func) (cairo_box_t *box,
2787 struct _cairo_boxes_chunk *chunk;
2790 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2791 for (i = 0; i < chunk->count; i++)
2792 if (! func (&chunk->base[i], data))
2799 struct _image_contains_box {
2804 static cairo_bool_t image_contains_box (cairo_box_t *box, void *closure)
2806 struct _image_contains_box *data = closure;
2808 /* The box is pixel-aligned so the truncation is safe. */
2810 _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
2811 _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
2812 _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
2813 _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
2816 struct _image_upload_box {
2817 cairo_xcb_surface_t *surface;
2818 cairo_image_surface_t *image;
2823 static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
2825 const struct _image_upload_box *iub = closure;
2826 /* The box is pixel-aligned so the truncation is safe. */
2827 int x = _cairo_fixed_integer_part (box->p1.x);
2828 int y = _cairo_fixed_integer_part (box->p1.y);
2829 int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
2830 int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
2831 int bpp = PIXMAN_FORMAT_BPP (iub->image->pixman_format);
2832 int len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp);
2833 if (len == iub->image->stride) {
2834 _cairo_xcb_connection_put_image (iub->surface->connection,
2835 iub->surface->drawable,
2842 (y + iub->ty) * iub->image->stride +
2843 (x + iub->tx) * bpp/8);
2845 _cairo_xcb_connection_put_subimage (iub->surface->connection,
2846 iub->surface->drawable,
2861 static cairo_status_t
2862 _upload_image_inplace (cairo_xcb_surface_t *surface,
2863 const cairo_pattern_t *source,
2864 cairo_boxes_t *boxes)
2866 const cairo_surface_pattern_t *pattern;
2867 struct _image_contains_box icb;
2868 struct _image_upload_box iub;
2869 cairo_image_surface_t *image;
2870 cairo_status_t status;
2873 if (! boxes->is_pixel_aligned)
2874 return CAIRO_INT_STATUS_UNSUPPORTED;
2876 if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
2877 return CAIRO_INT_STATUS_UNSUPPORTED;
2879 pattern = (const cairo_surface_pattern_t *) source;
2880 if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
2881 return CAIRO_INT_STATUS_UNSUPPORTED;
2883 /* Have we already upload this image to a pixmap? */
2885 cairo_xcb_picture_t *snapshot;
2887 snapshot = (cairo_xcb_picture_t *)
2888 _cairo_surface_has_snapshot (pattern->surface, &_cairo_xcb_picture_backend);
2889 if (snapshot != NULL) {
2890 if (snapshot->screen == surface->screen)
2891 return CAIRO_INT_STATUS_UNSUPPORTED;
2895 image = (cairo_image_surface_t *) pattern->surface;
2896 if (image->format == CAIRO_FORMAT_INVALID)
2897 return CAIRO_INT_STATUS_UNSUPPORTED;
2899 if (image->depth != surface->depth)
2900 return CAIRO_INT_STATUS_UNSUPPORTED;
2902 if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
2903 return CAIRO_INT_STATUS_UNSUPPORTED;
2905 /* Check that the data is entirely within the image */
2906 icb.width = image->width;
2907 icb.height = image->height;
2910 if (! cairo_boxes_for_each_box (boxes, image_contains_box, &icb))
2911 return CAIRO_INT_STATUS_UNSUPPORTED;
2913 if (surface->deferred_clear) {
2914 status = _cairo_xcb_surface_clear (surface);
2915 if (unlikely (status))
2919 status = _cairo_xcb_connection_acquire (surface->connection);
2920 if (unlikely (status))
2923 iub.surface = surface;
2925 iub.gc = _cairo_xcb_screen_get_gc (surface->screen,
2930 cairo_boxes_for_each_box (boxes, image_upload_box, &iub);
2932 _cairo_xcb_screen_put_gc (surface->screen, image->depth, iub.gc);
2933 _cairo_xcb_connection_release (surface->connection);
2935 return CAIRO_STATUS_SUCCESS;
2938 static cairo_int_status_t
2939 trim_extents_to_traps (cairo_composite_rectangles_t *extents,
2940 cairo_traps_t *traps)
2944 /* X trims the affected area to the extents of the trapezoids, so
2945 * we need to compensate when fixing up the unbounded area.
2947 _cairo_traps_extents (traps, &box);
2948 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
2952 _mono_edge_is_vertical (const cairo_line_t *line)
2954 return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
2958 _traps_are_pixel_aligned (cairo_traps_t *traps,
2959 cairo_antialias_t antialias)
2963 if (antialias == CAIRO_ANTIALIAS_NONE) {
2964 for (i = 0; i < traps->num_traps; i++) {
2965 if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
2966 ! _mono_edge_is_vertical (&traps->traps[i].right))
2968 traps->maybe_region = FALSE;
2973 for (i = 0; i < traps->num_traps; i++) {
2974 if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
2975 traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
2976 ! _cairo_fixed_is_integer (traps->traps[i].top) ||
2977 ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
2978 ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
2979 ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
2981 traps->maybe_region = FALSE;
2991 _boxes_for_traps (cairo_boxes_t *boxes,
2992 cairo_traps_t *traps,
2993 cairo_antialias_t antialias)
2997 _cairo_boxes_init (boxes);
2999 boxes->num_boxes = traps->num_traps;
3000 boxes->chunks.base = (cairo_box_t *) traps->traps;
3001 boxes->chunks.count = traps->num_traps;
3002 boxes->chunks.size = traps->num_traps;
3004 if (antialias != CAIRO_ANTIALIAS_NONE) {
3005 for (i = 0; i < traps->num_traps; i++) {
3006 /* Note the traps and boxes alias so we need to take the local copies first. */
3007 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
3008 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
3009 cairo_fixed_t y1 = traps->traps[i].top;
3010 cairo_fixed_t y2 = traps->traps[i].bottom;
3012 boxes->chunks.base[i].p1.x = x1;
3013 boxes->chunks.base[i].p1.y = y1;
3014 boxes->chunks.base[i].p2.x = x2;
3015 boxes->chunks.base[i].p2.y = y2;
3017 if (boxes->is_pixel_aligned) {
3018 boxes->is_pixel_aligned =
3019 _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
3020 _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
3024 boxes->is_pixel_aligned = TRUE;
3026 for (i = 0; i < traps->num_traps; i++) {
3027 /* Note the traps and boxes alias so we need to take the local copies first. */
3028 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
3029 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
3030 cairo_fixed_t y1 = traps->traps[i].top;
3031 cairo_fixed_t y2 = traps->traps[i].bottom;
3033 /* round down here to match Pixman's behavior when using traps. */
3034 boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
3035 boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
3036 boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
3037 boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
3042 static cairo_status_t
3043 _composite_polygon (cairo_xcb_surface_t *dst,
3044 cairo_operator_t op,
3045 const cairo_pattern_t *source,
3046 cairo_polygon_t *polygon,
3047 cairo_antialias_t antialias,
3048 cairo_fill_rule_t fill_rule,
3049 cairo_composite_rectangles_t *extents)
3051 composite_traps_info_t traps;
3052 cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
3053 cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
3054 cairo_status_t status;
3056 if (polygon->num_edges == 0) {
3057 status = CAIRO_STATUS_SUCCESS;
3059 if (! extents->is_bounded) {
3060 if (cairo_region_contains_rectangle (clip_region, &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
3063 if (clip_surface == FALSE) {
3064 if (clip_region != NULL) {
3065 status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
3066 if (unlikely (status))
3070 status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
3072 if (clip_region != NULL)
3073 _cairo_xcb_surface_clear_clip_region (dst);
3075 status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst,
3084 if (extents->clip->path != NULL && extents->is_bounded) {
3085 cairo_polygon_t clipper;
3086 cairo_fill_rule_t clipper_fill_rule;
3087 cairo_antialias_t clipper_antialias;
3089 status = _cairo_clip_get_polygon (extents->clip,
3092 &clipper_antialias);
3093 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3094 if (clipper_antialias == antialias) {
3095 status = _cairo_polygon_intersect (polygon, fill_rule,
3096 &clipper, clipper_fill_rule);
3097 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3098 cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
3099 _cairo_clip_destroy (extents->clip);
3100 extents->clip = clip;
3102 fill_rule = CAIRO_FILL_RULE_WINDING;
3104 _cairo_polygon_fini (&clipper);
3109 _cairo_traps_init (&traps.traps);
3111 status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
3112 if (unlikely (status))
3115 if (traps.traps.has_intersections) {
3116 if (traps.traps.is_rectangular)
3117 status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
3118 else if (traps.traps.is_rectilinear)
3119 status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
3121 status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
3122 if (unlikely (status))
3126 /* Use a fast path if the trapezoids consist of a simple region,
3127 * but we can only do this if we do not have a clip surface, or can
3128 * substitute the mask with the clip.
3130 if (traps.traps.maybe_region &&
3131 _traps_are_pixel_aligned (&traps.traps, antialias) &&
3133 (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
3135 cairo_boxes_t boxes;
3137 _boxes_for_traps (&boxes, &traps.traps, antialias);
3138 status = _clip_and_composite_boxes (dst, op, source, &boxes, extents);
3142 /* Otherwise render the trapezoids to a mask and composite in the usual
3145 traps.antialias = antialias;
3146 status = trim_extents_to_traps (extents, &traps.traps);
3147 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3148 unsigned int flags = 0;
3150 /* For unbounded operations, the X11 server will estimate the
3151 * affected rectangle and apply the operation to that. However,
3152 * there are cases where this is an overestimate (e.g. the
3153 * clip-fill-{eo,nz}-unbounded test).
3155 * The clip will trim that overestimate to our expectations.
3157 if (! extents->is_bounded)
3158 flags |= FORCE_CLIP_REGION;
3160 status = _clip_and_composite (dst, op, source, _composite_traps,
3161 NULL, &traps, extents,
3162 need_unbounded_clip (extents) | flags);
3167 _cairo_traps_fini (&traps.traps);
3172 static cairo_status_t
3173 _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
3174 cairo_operator_t op,
3175 const cairo_pattern_t *src,
3176 cairo_boxes_t *boxes,
3177 cairo_composite_rectangles_t *extents)
3179 composite_traps_info_t info;
3180 cairo_int_status_t status;
3182 if (boxes->num_boxes == 0 && extents->is_bounded)
3183 return CAIRO_STATUS_SUCCESS;
3185 if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
3186 (op == CAIRO_OPERATOR_SOURCE ||
3187 (dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))))
3189 if (boxes->num_boxes == 1 &&
3190 extents->bounded.width == dst->width &&
3191 extents->bounded.height == dst->height)
3193 op = CAIRO_OPERATOR_SOURCE;
3194 dst->deferred_clear = FALSE;
3197 status = _upload_image_inplace (dst, src, boxes);
3198 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3202 /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
3203 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS &&
3204 extents->clip->path != NULL && extents->is_bounded) {
3205 cairo_polygon_t polygon;
3206 cairo_fill_rule_t fill_rule;
3207 cairo_antialias_t antialias;
3210 clip = _cairo_clip_copy (extents->clip);
3211 clip = _cairo_clip_intersect_boxes (clip, boxes);
3212 status = _cairo_clip_get_polygon (clip, &polygon,
3213 &fill_rule, &antialias);
3214 _cairo_clip_path_destroy (clip->path);
3216 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
3217 cairo_clip_t *saved_clip = extents->clip;
3218 extents->clip = clip;
3219 status = _composite_polygon (dst, op, src,
3224 if (extents->clip != clip)
3226 extents->clip = saved_clip;
3227 _cairo_polygon_fini (&polygon);
3230 _cairo_clip_destroy (clip);
3232 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3236 if (dst->deferred_clear) {
3237 status = _cairo_xcb_surface_clear (dst);
3238 if (unlikely (status))
3242 if (boxes->is_pixel_aligned &&
3243 _cairo_clip_is_region (extents->clip) &&
3244 op == CAIRO_OPERATOR_SOURCE) {
3245 status = _upload_image_inplace (dst, src, boxes);
3246 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3250 if ((dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
3251 return _core_boxes (dst, op, src, boxes, extents);
3253 /* Use a fast path if the boxes are pixel aligned */
3254 status = _composite_boxes (dst, op, src, boxes, extents);
3255 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3258 if ((dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0)
3259 return CAIRO_INT_STATUS_UNSUPPORTED;
3261 /* Otherwise render via a mask and composite in the usual fashion. */
3262 status = _cairo_traps_init_boxes (&info.traps, boxes);
3263 if (unlikely (status))
3266 info.antialias = CAIRO_ANTIALIAS_DEFAULT;
3267 status = trim_extents_to_traps (extents, &info.traps);
3268 if (status == CAIRO_INT_STATUS_SUCCESS) {
3269 status = _clip_and_composite (dst, op, src,
3270 _composite_traps, NULL, &info,
3271 extents, need_unbounded_clip (extents));
3274 _cairo_traps_fini (&info.traps);
3278 static cairo_int_status_t
3279 _composite_mask (void *closure,
3280 cairo_xcb_surface_t *dst,
3281 cairo_operator_t op,
3282 const cairo_pattern_t *src_pattern,
3285 const cairo_rectangle_int_t *extents,
3288 const cairo_pattern_t *mask_pattern = closure;
3289 cairo_xcb_picture_t *src, *mask = NULL;
3290 cairo_status_t status;
3292 if (dst->base.is_clear) {
3293 if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)
3294 op = CAIRO_OPERATOR_SOURCE;
3297 if (op == CAIRO_OPERATOR_SOURCE && clip == NULL)
3298 dst->deferred_clear = FALSE;
3300 if (dst->deferred_clear) {
3301 status = _cairo_xcb_surface_clear (dst);
3302 if (unlikely (status))
3306 if (src_pattern != NULL) {
3307 src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
3308 if (unlikely (src->base.status))
3309 return src->base.status;
3311 mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
3312 if (unlikely (mask->base.status)) {
3313 cairo_surface_destroy (&src->base);
3314 return mask->base.status;
3317 _cairo_xcb_connection_render_composite (dst->connection,
3318 _render_operator (op),
3322 extents->x + src->x, extents->y + src->y,
3323 extents->x + mask->x, extents->y + mask->y,
3324 extents->x - dst_x, extents->y - dst_y,
3325 extents->width, extents->height);
3326 cairo_surface_destroy (&mask->base);
3327 cairo_surface_destroy (&src->base);
3329 src = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
3330 if (unlikely (src->base.status))
3331 return src->base.status;
3333 _cairo_xcb_connection_render_composite (dst->connection,
3334 _render_operator (op),
3338 extents->x + src->x, extents->y + src->y,
3340 extents->x - dst_x, extents->y - dst_y,
3341 extents->width, extents->height);
3342 cairo_surface_destroy (&src->base);
3345 return CAIRO_STATUS_SUCCESS;
3348 struct composite_box_info {
3349 cairo_xcb_surface_t *dst;
3350 cairo_xcb_picture_t *src;
3354 static void composite_box(void *closure,
3355 int16_t x, int16_t y,
3356 int16_t w, int16_t h,
3359 struct composite_box_info *info = closure;
3361 if (coverage < 0xff00) {
3362 cairo_xcb_picture_t *mask;
3363 cairo_color_t color;
3365 color.red_short = color.green_short = color.blue_short = 0;
3366 color.alpha_short = coverage;
3368 mask = _solid_picture (info->dst, &color);
3369 if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
3370 _cairo_xcb_connection_render_composite (info->dst->connection,
3375 x + info->src->x, y + info->src->y,
3380 cairo_surface_destroy (&mask->base);
3382 _cairo_xcb_connection_render_composite (info->dst->connection,
3387 x + info->src->x, y + info->src->y,
3394 static cairo_int_status_t
3395 _composite_mask_clip_boxes (void *closure,
3396 cairo_xcb_surface_t *dst,
3397 cairo_operator_t op,
3398 const cairo_pattern_t *src_pattern,
3401 const cairo_rectangle_int_t *extents,
3404 struct composite_box_info info;
3405 cairo_status_t status;
3408 assert (src_pattern == NULL);
3409 assert (op == CAIRO_OPERATOR_ADD);
3410 assert (dst->base.is_clear);
3412 if (clip->num_boxes > 1) {
3413 status = _cairo_xcb_surface_clear (dst);
3414 if (unlikely (status))
3418 info.op = XCB_RENDER_PICT_OP_SRC;
3420 info.src = _cairo_xcb_picture_for_pattern (dst, closure, extents);
3421 if (unlikely (info.src->base.status))
3422 return info.src->base.status;
3424 info.src->x += dst_x;
3425 info.src->y += dst_y;
3427 for (i = 0; i < clip->num_boxes; i++)
3428 do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
3429 cairo_surface_destroy (&info.src->base);
3431 return CAIRO_STATUS_SUCCESS;
3434 static cairo_int_status_t
3435 _composite_mask_clip (void *closure,
3436 cairo_xcb_surface_t *dst,
3437 cairo_operator_t op,
3438 const cairo_pattern_t *src_pattern,
3441 const cairo_rectangle_int_t *extents,
3444 const cairo_pattern_t *mask_pattern = closure;
3445 cairo_polygon_t polygon;
3446 cairo_fill_rule_t fill_rule;
3447 composite_traps_info_t info;
3448 cairo_status_t status;
3450 assert (src_pattern == NULL);
3451 assert (op == CAIRO_OPERATOR_ADD);
3452 assert (dst->base.is_clear);
3454 status = _cairo_clip_get_polygon (clip, &polygon,
3455 &fill_rule, &info.antialias);
3456 if (unlikely (status))
3459 _cairo_traps_init (&info.traps);
3460 status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
3463 _cairo_polygon_fini (&polygon);
3464 if (unlikely (status))
3467 if (info.traps.has_intersections) {
3468 if (info.traps.is_rectangular)
3469 status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
3470 else if (info.traps.is_rectilinear)
3471 status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
3473 status = _cairo_bentley_ottmann_tessellate_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
3474 if (unlikely (status)) {
3475 _cairo_traps_fini (&info.traps);
3480 dst->deferred_clear = FALSE; /* assert(trap extents == extents); */
3482 status = _composite_traps (&info,
3483 dst, CAIRO_OPERATOR_SOURCE, mask_pattern,
3486 _cairo_traps_fini (&info.traps);
3491 struct composite_opacity_info {
3493 cairo_xcb_surface_t *dst;
3494 cairo_xcb_picture_t *src;
3498 static void composite_opacity(void *closure,
3499 int16_t x, int16_t y,
3500 int16_t w, int16_t h,
3503 struct composite_opacity_info *info = closure;
3504 cairo_xcb_picture_t *mask;
3505 cairo_color_t color;
3507 color.red_short = color.green_short = color.blue_short = 0;
3508 color.alpha_short = info->opacity * coverage;
3510 mask = _solid_picture (info->dst, &color);
3511 if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
3513 _cairo_xcb_connection_render_composite (info->dst->connection,
3518 x + info->src->x, y + info->src->y,
3523 _cairo_xcb_connection_render_composite (info->dst->connection,
3535 cairo_surface_destroy (&mask->base);
3538 static cairo_int_status_t
3539 _composite_opacity_boxes (void *closure,
3540 cairo_xcb_surface_t *dst,
3541 cairo_operator_t op,
3542 const cairo_pattern_t *src_pattern,
3545 const cairo_rectangle_int_t *extents,
3548 const cairo_solid_pattern_t *mask_pattern = closure;
3549 struct composite_opacity_info info;
3550 cairo_status_t status;
3553 if (dst->base.is_clear) {
3554 if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)
3555 op = CAIRO_OPERATOR_SOURCE;
3558 if (op == CAIRO_OPERATOR_SOURCE &&
3560 (clip->extents.width >= extents->width &&
3561 clip->extents.height >= extents->height)))
3562 dst->deferred_clear = FALSE;
3564 if (dst->deferred_clear) {
3565 status = _cairo_xcb_surface_clear (dst);
3566 if (unlikely (status))
3570 info.op = _render_operator (op);
3573 if (src_pattern != NULL) {
3574 info.src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
3575 if (unlikely (info.src->base.status))
3576 return info.src->base.status;
3580 info.opacity = mask_pattern->color.alpha;
3582 /* XXX for lots of boxes create a clip region for the fully opaque areas */
3584 for (i = 0; i < clip->num_boxes; i++)
3585 do_unaligned_box(composite_opacity, &info,
3586 &clip->boxes[i], dst_x, dst_y);
3588 composite_opacity(&info,
3595 cairo_surface_destroy (&info.src->base);
3597 return CAIRO_STATUS_SUCCESS;
3600 /* high level rasteriser -> compositor */
3603 _cairo_xcb_render_compositor_paint (const cairo_compositor_t *compositor,
3604 cairo_composite_rectangles_t *composite)
3606 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
3607 cairo_operator_t op = composite->op;
3608 cairo_pattern_t *source = &composite->source_pattern.base;
3609 cairo_boxes_t boxes;
3610 cairo_status_t status;
3612 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
3613 return CAIRO_INT_STATUS_UNSUPPORTED;
3615 if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
3616 CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
3618 return CAIRO_INT_STATUS_UNSUPPORTED;
3621 if (composite->clip == NULL &&
3622 source->type == CAIRO_PATTERN_TYPE_SOLID &&
3623 (op == CAIRO_OPERATOR_SOURCE ||
3624 op == CAIRO_OPERATOR_CLEAR ||
3625 (surface->base.is_clear &&
3626 (op == CAIRO_OPERATOR_ADD || op == CAIRO_OPERATOR_OVER))))
3628 surface->deferred_clear = TRUE;
3629 surface->deferred_clear_color = composite->source_pattern.solid.color;
3630 return CAIRO_STATUS_SUCCESS;
3633 _cairo_clip_steal_boxes(composite->clip, &boxes);
3634 status = _clip_and_composite_boxes (surface, op, source, &boxes, composite);
3635 _cairo_clip_unsteal_boxes (composite->clip, &boxes);
3641 _cairo_xcb_render_compositor_mask (const cairo_compositor_t *compositor,
3642 cairo_composite_rectangles_t *composite)
3644 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
3645 cairo_operator_t op = composite->op;
3646 cairo_pattern_t *source = &composite->source_pattern.base;
3647 cairo_pattern_t *mask = &composite->mask_pattern.base;
3648 cairo_status_t status;
3650 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
3651 return CAIRO_INT_STATUS_UNSUPPORTED;
3653 if ((surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
3654 return CAIRO_INT_STATUS_UNSUPPORTED;
3656 if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
3657 composite->clip->path == NULL &&
3658 ! _cairo_clip_is_region (composite->clip)) {
3659 status = _clip_and_composite (surface, op, source,
3660 _composite_opacity_boxes,
3661 _composite_opacity_boxes,
3663 composite, need_unbounded_clip (composite));
3665 xcb_draw_func_t mask_func = NULL;
3666 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)
3667 mask_func = composite->clip->path ? _composite_mask_clip : _composite_mask_clip_boxes;
3668 status = _clip_and_composite (surface, op, source,
3669 _composite_mask, mask_func,
3671 composite, need_bounded_clip (composite));
3677 static cairo_int_status_t
3678 _cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst,
3679 cairo_operator_t op,
3680 const cairo_pattern_t *source,
3681 const cairo_path_fixed_t *path,
3682 const cairo_stroke_style_t *stroke_style,
3683 const cairo_matrix_t *ctm,
3684 const cairo_matrix_t *ctm_inverse,
3686 cairo_antialias_t antialias,
3687 cairo_composite_rectangles_t *extents)
3689 cairo_polygon_t polygon;
3690 cairo_status_t status;
3692 _cairo_polygon_init_with_clip (&polygon, extents->clip);
3693 status = _cairo_path_fixed_stroke_to_polygon (path,
3698 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3699 status = _composite_polygon (dst, op, source,
3700 &polygon, antialias,
3701 CAIRO_FILL_RULE_WINDING,
3704 _cairo_polygon_fini (&polygon);
3709 static cairo_status_t
3710 _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
3711 cairo_operator_t op,
3712 const cairo_pattern_t *source,
3713 const cairo_path_fixed_t *path,
3714 const cairo_stroke_style_t *stroke_style,
3715 const cairo_matrix_t *ctm,
3716 const cairo_matrix_t *ctm_inverse,
3718 cairo_antialias_t antialias,
3719 cairo_composite_rectangles_t *extents)
3721 cairo_surface_t *image;
3722 cairo_status_t status;
3726 x = extents->bounded.x;
3727 y = extents->bounded.y;
3728 image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_FORMAT_A8,
3729 extents->bounded.width,
3730 extents->bounded.height);
3731 if (unlikely (image->status)) {
3732 status = image->status;
3733 cairo_surface_destroy (image);
3737 clip = _cairo_clip_copy_region (extents->clip);
3738 status = _cairo_surface_offset_stroke (image, x, y,
3740 &_cairo_pattern_white.base,
3743 tolerance, antialias,
3745 _cairo_clip_destroy (clip);
3746 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3747 cairo_surface_pattern_t mask;
3749 _cairo_pattern_init_for_surface (&mask, image);
3750 mask.base.filter = CAIRO_FILTER_NEAREST;
3752 cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
3753 status = _clip_and_composite (dst, op, source,
3754 _composite_mask, NULL, &mask.base,
3755 extents, need_bounded_clip (extents));
3756 _cairo_pattern_fini (&mask.base);
3759 cairo_surface_finish (image);
3760 cairo_surface_destroy (image);
3766 _cairo_xcb_render_compositor_stroke (const cairo_compositor_t *compositor,
3767 cairo_composite_rectangles_t *composite,
3768 const cairo_path_fixed_t *path,
3769 const cairo_stroke_style_t *style,
3770 const cairo_matrix_t *ctm,
3771 const cairo_matrix_t *ctm_inverse,
3773 cairo_antialias_t antialias)
3775 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
3776 cairo_operator_t op = composite->op;
3777 cairo_pattern_t *source = &composite->source_pattern.base;
3778 cairo_int_status_t status;
3780 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
3781 return CAIRO_INT_STATUS_UNSUPPORTED;
3783 if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
3784 CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
3786 return CAIRO_INT_STATUS_UNSUPPORTED;
3789 status = CAIRO_INT_STATUS_UNSUPPORTED;
3790 if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
3791 cairo_boxes_t boxes;
3793 _cairo_boxes_init_with_clip (&boxes, composite->clip);
3794 status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
3799 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
3800 status = _clip_and_composite_boxes (surface, op, source,
3803 _cairo_boxes_fini (&boxes);
3806 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
3807 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) {
3808 status = _cairo_xcb_surface_render_stroke_as_polygon (surface, op, source,
3811 tolerance, antialias,
3813 } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
3814 status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source,
3817 tolerance, antialias,
3827 static cairo_status_t
3828 _cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t *dst,
3829 cairo_operator_t op,
3830 const cairo_pattern_t*source,
3831 const cairo_path_fixed_t *path,
3832 cairo_fill_rule_t fill_rule,
3834 cairo_antialias_t antialias,
3835 cairo_composite_rectangles_t *extents)
3837 cairo_polygon_t polygon;
3838 cairo_status_t status;
3840 _cairo_polygon_init_with_clip (&polygon, extents->clip);
3841 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
3842 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3843 status = _composite_polygon (dst, op, source,
3849 _cairo_polygon_fini (&polygon);
3854 static cairo_status_t
3855 _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst,
3856 cairo_operator_t op,
3857 const cairo_pattern_t *source,
3858 const cairo_path_fixed_t *path,
3859 cairo_fill_rule_t fill_rule,
3861 cairo_antialias_t antialias,
3862 cairo_composite_rectangles_t *extents)
3864 cairo_surface_t *image;
3865 cairo_status_t status;
3869 x = extents->bounded.x;
3870 y = extents->bounded.y;
3871 image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_FORMAT_A8,
3872 extents->bounded.width,
3873 extents->bounded.height);
3874 if (unlikely (image->status)) {
3875 status = image->status;
3876 cairo_surface_destroy (image);
3880 clip = _cairo_clip_copy_region (extents->clip);
3881 status = _cairo_surface_offset_fill (image, x, y,
3883 &_cairo_pattern_white.base,
3884 path, fill_rule, tolerance, antialias,
3886 _cairo_clip_destroy (clip);
3887 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3888 cairo_surface_pattern_t mask;
3890 _cairo_pattern_init_for_surface (&mask, image);
3891 mask.base.filter = CAIRO_FILTER_NEAREST;
3893 cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
3894 status = _clip_and_composite (dst, op, source,
3895 _composite_mask, NULL, &mask.base,
3896 extents, need_bounded_clip (extents));
3898 _cairo_pattern_fini (&mask.base);
3901 cairo_surface_finish (image);
3902 cairo_surface_destroy (image);
3908 _cairo_xcb_render_compositor_fill (const cairo_compositor_t *compositor,
3909 cairo_composite_rectangles_t *composite,
3910 const cairo_path_fixed_t *path,
3911 cairo_fill_rule_t fill_rule,
3913 cairo_antialias_t antialias)
3915 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
3916 cairo_operator_t op = composite->op;
3917 cairo_pattern_t *source = &composite->source_pattern.base;
3918 cairo_int_status_t status;
3920 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
3921 return CAIRO_INT_STATUS_UNSUPPORTED;
3923 if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
3924 CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
3926 return CAIRO_INT_STATUS_UNSUPPORTED;
3929 status = CAIRO_INT_STATUS_UNSUPPORTED;
3930 if (_cairo_path_fixed_fill_is_rectilinear (path)) {
3931 cairo_boxes_t boxes;
3933 _cairo_boxes_init_with_clip (&boxes, composite->clip);
3934 status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
3938 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
3939 status = _clip_and_composite_boxes (surface, op, source,
3942 _cairo_boxes_fini (&boxes);
3945 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
3946 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) {
3947 status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path,
3948 fill_rule, tolerance, antialias,
3950 } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
3951 status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path,
3952 fill_rule, tolerance, antialias,
3962 static cairo_status_t
3963 _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst,
3964 cairo_operator_t op,
3965 const cairo_pattern_t *source,
3966 cairo_scaled_font_t *scaled_font,
3967 cairo_glyph_t *glyphs,
3969 cairo_composite_rectangles_t *extents)
3971 cairo_surface_t *image;
3972 cairo_content_t content;
3973 cairo_status_t status;
3977 content = CAIRO_CONTENT_ALPHA;
3978 if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
3979 content = CAIRO_CONTENT_COLOR_ALPHA;
3981 x = extents->bounded.x;
3982 y = extents->bounded.y;
3983 image = _cairo_xcb_surface_create_similar_image (dst,
3984 _cairo_format_from_content (content),
3985 extents->bounded.width,
3986 extents->bounded.height);
3989 return _cairo_error (CAIRO_STATUS_NULL_POINTER);
3991 if (unlikely (image->status)) {
3992 status = image->status;
3993 cairo_surface_destroy (image);
3997 clip = _cairo_clip_copy_region (extents->clip);
3998 status = _cairo_surface_offset_glyphs (image, x, y,
4000 &_cairo_pattern_white.base,
4001 scaled_font, glyphs, num_glyphs,
4003 _cairo_clip_destroy (clip);
4004 if (likely (status == CAIRO_STATUS_SUCCESS)) {
4005 cairo_surface_pattern_t mask;
4007 _cairo_pattern_init_for_surface (&mask, image);
4008 mask.base.filter = CAIRO_FILTER_NEAREST;
4009 if (content & CAIRO_CONTENT_COLOR)
4010 mask.base.has_component_alpha = TRUE;
4012 cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
4013 status = _clip_and_composite (dst, op, source,
4014 _composite_mask, NULL, &mask.base,
4015 extents, need_bounded_clip (extents));
4017 _cairo_pattern_fini (&mask.base);
4020 cairo_surface_finish (image);
4021 cairo_surface_destroy (image);
4026 /* Build a struct of the same size of #cairo_glyph_t that can be used both as
4027 * an input glyph with double coordinates, and as "working" glyph with
4028 * integer from-current-point offsets. */
4031 unsigned long index;
4033 unsigned long index;
4037 } cairo_xcb_glyph_t;
4039 /* compile-time assert that #cairo_xcb_glyph_t is the same size as #cairo_glyph_t */
4040 COMPILE_TIME_ASSERT (sizeof (cairo_xcb_glyph_t) == sizeof (cairo_glyph_t));
4043 cairo_scaled_font_t *font;
4044 cairo_xcb_glyph_t *glyphs;
4046 cairo_bool_t use_mask;
4047 } composite_glyphs_info_t;
4049 static cairo_status_t
4050 _can_composite_glyphs (cairo_xcb_surface_t *dst,
4051 cairo_rectangle_int_t *extents,
4052 cairo_scaled_font_t *scaled_font,
4053 cairo_glyph_t *glyphs,
4056 #define GLYPH_CACHE_SIZE 64
4057 cairo_box_t bbox_cache[GLYPH_CACHE_SIZE];
4058 unsigned long glyph_cache[GLYPH_CACHE_SIZE];
4059 #undef GLYPH_CACHE_SIZE
4060 cairo_status_t status = CAIRO_STATUS_SUCCESS;
4061 cairo_glyph_t *glyphs_end, *valid_glyphs;
4062 const int max_glyph_size = dst->connection->maximum_request_length - 64;
4064 /* We must initialize the cache with values that cannot match the
4065 * "hash" to guarantee that when compared for the first time they
4066 * will result in a mismatch. The hash function is simply modulus,
4067 * so we cannot use 0 in glyph_cache[0], but we can use it in all
4068 * other array cells.
4070 memset (glyph_cache, 0, sizeof (glyph_cache));
4073 /* Scan for oversized glyphs or glyphs outside the representable
4074 * range and fallback in that case, discard glyphs outside of the
4077 valid_glyphs = glyphs;
4078 for (glyphs_end = glyphs + *num_glyphs; glyphs != glyphs_end; glyphs++) {
4079 double x1, y1, x2, y2;
4080 cairo_scaled_glyph_t *glyph;
4082 int width, height, len;
4085 g = glyphs->index % ARRAY_LENGTH (glyph_cache);
4086 if (glyph_cache[g] != glyphs->index) {
4087 status = _cairo_scaled_glyph_lookup (scaled_font,
4089 CAIRO_SCALED_GLYPH_INFO_METRICS,
4091 if (unlikely (status))
4094 glyph_cache[g] = glyphs->index;
4095 bbox_cache[g] = glyph->bbox;
4097 bbox = &bbox_cache[g];
4099 /* Drop glyphs outside the clipping */
4100 x1 = _cairo_fixed_to_double (bbox->p1.x);
4101 y1 = _cairo_fixed_to_double (bbox->p1.y);
4102 y2 = _cairo_fixed_to_double (bbox->p2.y);
4103 x2 = _cairo_fixed_to_double (bbox->p2.x);
4104 if (unlikely (glyphs->x + x2 <= extents->x ||
4105 glyphs->y + y2 <= extents->y ||
4106 glyphs->x + x1 >= extents->x + extents->width ||
4107 glyphs->y + y1 >= extents->y + extents->height))
4113 /* XRenderAddGlyph does not handle a glyph surface larger than
4114 * the extended maximum XRequest size.
4116 width = _cairo_fixed_integer_ceil (bbox->p2.x - bbox->p1.x);
4117 height = _cairo_fixed_integer_ceil (bbox->p2.y - bbox->p1.y);
4118 len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, 32) * height;
4119 if (unlikely (len >= max_glyph_size)) {
4120 status = CAIRO_INT_STATUS_UNSUPPORTED;
4124 /* The glyph coordinates must be representable in an int16_t.
4125 * When possible, they will be expressed as an offset from the
4126 * previous glyph, otherwise they will be an offset from the
4127 * operation extents or from the surface origin. If the last
4128 * two options are not valid, fallback.
4130 if (unlikely (glyphs->x > INT16_MAX ||
4131 glyphs->y > INT16_MAX ||
4132 glyphs->x - extents->x < INT16_MIN ||
4133 glyphs->y - extents->y < INT16_MIN))
4135 status = CAIRO_INT_STATUS_UNSUPPORTED;
4140 if (unlikely (valid_glyphs != glyphs))
4141 *valid_glyphs = *glyphs;
4145 if (unlikely (valid_glyphs != glyphs)) {
4146 for (; glyphs != glyphs_end; glyphs++) {
4147 *valid_glyphs = *glyphs;
4155 /* Start a new element for the first glyph,
4156 * or for any glyph that has unexpected position,
4157 * or if current element has too many glyphs
4158 * (Xrender limits each element to 252 glyphs, we limit them to 128)
4160 * These same conditions need to be mirrored between
4161 * _cairo_xcb_surface_emit_glyphs and _emit_glyph_chunks
4163 #define _start_new_glyph_elt(count, glyph) \
4164 (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
4166 /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
4167 * enough room for padding */
4175 #define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4)
4178 _cairo_xcb_font_destroy (cairo_xcb_font_t *font)
4182 for (i = 0; i < NUM_GLYPHSETS; i++) {
4183 cairo_xcb_font_glyphset_info_t *info;
4185 info = &font->glyphset_info[i];
4186 free (info->pending_free_glyphs);
4189 cairo_list_del (&font->base.link);
4190 cairo_list_del (&font->link);
4192 _cairo_xcb_connection_destroy (font->connection);
4198 _cairo_xcb_font_fini (cairo_scaled_font_private_t *abstract_private,
4199 cairo_scaled_font_t *scaled_font)
4201 cairo_xcb_font_t *font_private = (cairo_xcb_font_t *)abstract_private;
4202 cairo_xcb_connection_t *connection;
4203 cairo_bool_t have_connection;
4204 cairo_status_t status;
4207 connection = font_private->connection;
4209 status = _cairo_xcb_connection_acquire (connection);
4210 have_connection = status == CAIRO_STATUS_SUCCESS;
4212 for (i = 0; i < NUM_GLYPHSETS; i++) {
4213 cairo_xcb_font_glyphset_info_t *info;
4215 info = &font_private->glyphset_info[i];
4216 if (info->glyphset && status == CAIRO_STATUS_SUCCESS) {
4217 _cairo_xcb_connection_render_free_glyph_set (connection,
4222 if (have_connection)
4223 _cairo_xcb_connection_release (connection);
4225 _cairo_xcb_font_destroy (font_private);
4229 static cairo_xcb_font_t *
4230 _cairo_xcb_font_create (cairo_xcb_connection_t *connection,
4231 cairo_scaled_font_t *font)
4233 cairo_xcb_font_t *priv;
4236 priv = malloc (sizeof (cairo_xcb_font_t));
4237 if (unlikely (priv == NULL))
4240 _cairo_scaled_font_attach_private (font, &priv->base, connection,
4241 _cairo_xcb_font_fini);
4243 priv->scaled_font = font;
4244 priv->connection = _cairo_xcb_connection_reference (connection);
4245 cairo_list_add (&priv->link, &connection->fonts);
4247 for (i = 0; i < NUM_GLYPHSETS; i++) {
4248 cairo_xcb_font_glyphset_info_t *info = &priv->glyphset_info[i];
4250 case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
4251 case GLYPHSET_INDEX_A8: info->format = CAIRO_FORMAT_A8; break;
4252 case GLYPHSET_INDEX_A1: info->format = CAIRO_FORMAT_A1; break;
4253 default: ASSERT_NOT_REACHED; break;
4255 info->xrender_format = 0;
4256 info->glyphset = XCB_NONE;
4257 info->pending_free_glyphs = NULL;
4264 _cairo_xcb_font_close (cairo_xcb_font_t *font)
4266 cairo_scaled_font_t *scaled_font;
4268 scaled_font = font->scaled_font;
4270 //scaled_font->surface_private = NULL;
4271 _cairo_scaled_font_reset_cache (scaled_font);
4273 _cairo_xcb_font_destroy (font);
4277 _cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection,
4278 cairo_xcb_font_glyphset_free_glyphs_t *to_free)
4280 _cairo_xcb_connection_render_free_glyphs (connection,
4282 to_free->glyph_count,
4283 to_free->glyph_indices);
4287 _cairo_xcb_get_glyphset_index_for_format (cairo_format_t format)
4289 if (format == CAIRO_FORMAT_A8)
4290 return GLYPHSET_INDEX_A8;
4291 if (format == CAIRO_FORMAT_A1)
4292 return GLYPHSET_INDEX_A1;
4294 assert (format == CAIRO_FORMAT_ARGB32);
4295 return GLYPHSET_INDEX_ARGB32;
4300 static inline cairo_xcb_font_t *
4301 _cairo_xcb_font_get (const cairo_xcb_connection_t *c,
4302 cairo_scaled_font_t *font)
4304 return (cairo_xcb_font_t *)_cairo_scaled_font_find_private (font, c);
4308 static cairo_xcb_font_glyphset_info_t *
4309 _cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_xcb_connection_t *c,
4310 cairo_scaled_font_t *font,
4311 cairo_format_t format)
4313 cairo_xcb_font_t *priv;
4314 cairo_xcb_font_glyphset_info_t *info;
4317 glyphset_index = _cairo_xcb_get_glyphset_index_for_format (format);
4319 priv = _cairo_xcb_font_get (c, font);
4321 priv = _cairo_xcb_font_create (c, font);
4326 info = &priv->glyphset_info[glyphset_index];
4327 if (info->glyphset == XCB_NONE) {
4328 info->glyphset = _cairo_xcb_connection_get_xid (c);
4329 info->xrender_format = c->standard_formats[info->format];
4331 _cairo_xcb_connection_render_create_glyph_set (c,
4333 info->xrender_format);
4340 _cairo_xcb_glyphset_info_has_pending_free_glyph (
4341 cairo_xcb_font_glyphset_info_t *info,
4342 unsigned long glyph_index)
4344 if (info->pending_free_glyphs != NULL) {
4345 cairo_xcb_font_glyphset_free_glyphs_t *to_free;
4348 to_free = info->pending_free_glyphs;
4349 for (i = 0; i < to_free->glyph_count; i++) {
4350 if (to_free->glyph_indices[i] == glyph_index) {
4351 to_free->glyph_count--;
4352 memmove (&to_free->glyph_indices[i],
4353 &to_free->glyph_indices[i+1],
4354 (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
4364 cairo_scaled_glyph_private_t base;
4366 cairo_xcb_font_glyphset_info_t *glyphset;
4367 } cairo_xcb_glyph_private_t;
4369 static cairo_xcb_font_glyphset_info_t *
4370 _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (cairo_xcb_connection_t *c,
4371 cairo_scaled_font_t *font,
4372 unsigned long glyph_index,
4373 cairo_image_surface_t *surface)
4375 cairo_xcb_font_t *priv;
4378 priv = _cairo_xcb_font_get (c, font);
4382 if (surface != NULL) {
4383 i = _cairo_xcb_get_glyphset_index_for_format (surface->format);
4385 if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
4386 &priv->glyphset_info[i],
4389 return &priv->glyphset_info[i];
4392 for (i = 0; i < NUM_GLYPHSETS; i++) {
4393 if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
4394 &priv->glyphset_info[i],
4397 return &priv->glyphset_info[i];
4406 _cairo_xcb_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
4407 cairo_scaled_glyph_t *glyph,
4408 cairo_scaled_font_t *font)
4410 cairo_xcb_glyph_private_t *priv = (cairo_xcb_glyph_private_t *)glyph_private;
4412 if (! font->finished) {
4413 cairo_xcb_font_glyphset_info_t *info = priv->glyphset;
4414 cairo_xcb_font_glyphset_free_glyphs_t *to_free;
4415 cairo_xcb_font_t *font_private;
4417 font_private = _cairo_xcb_font_get (glyph_private->key, font);
4418 assert (font_private);
4420 to_free = info->pending_free_glyphs;
4421 if (to_free != NULL &&
4422 to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
4424 _cairo_xcb_render_free_glyphs (font_private->connection, to_free);
4425 to_free = info->pending_free_glyphs = NULL;
4428 if (to_free == NULL) {
4429 to_free = malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t));
4430 if (unlikely (to_free == NULL)) {
4431 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
4432 return; /* XXX cannot propagate failure */
4435 to_free->glyphset = info->glyphset;
4436 to_free->glyph_count = 0;
4437 info->pending_free_glyphs = to_free;
4440 to_free->glyph_indices[to_free->glyph_count++] =
4441 _cairo_scaled_glyph_index (glyph);
4444 cairo_list_del (&glyph_private->link);
4445 free (glyph_private);
4449 static cairo_status_t
4450 _cairo_xcb_glyph_attach (cairo_xcb_connection_t *c,
4451 cairo_scaled_glyph_t *glyph,
4452 cairo_xcb_font_glyphset_info_t *info)
4454 cairo_xcb_glyph_private_t *priv;
4456 priv = malloc (sizeof (*priv));
4457 if (unlikely (priv == NULL))
4458 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4460 _cairo_scaled_glyph_attach_private (glyph, &priv->base, c,
4461 _cairo_xcb_glyph_fini);
4462 priv->glyphset = info;
4464 glyph->dev_private = info;
4465 glyph->dev_private_key = c;
4466 return CAIRO_STATUS_SUCCESS;
4469 static cairo_status_t
4470 _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
4471 cairo_scaled_font_t *font,
4472 cairo_scaled_glyph_t **scaled_glyph_out)
4474 xcb_render_glyphinfo_t glyph_info;
4475 uint32_t glyph_index;
4477 cairo_status_t status = CAIRO_STATUS_SUCCESS;
4478 cairo_scaled_glyph_t *scaled_glyph = *scaled_glyph_out;
4479 cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
4480 cairo_bool_t already_had_glyph_surface;
4481 cairo_xcb_font_glyphset_info_t *info;
4483 glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
4485 /* check to see if we have a pending XRenderFreeGlyph for this glyph */
4486 info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (connection, font, glyph_index, glyph_surface);
4488 return _cairo_xcb_glyph_attach (connection, scaled_glyph, info);
4490 if (glyph_surface == NULL) {
4491 status = _cairo_scaled_glyph_lookup (font,
4493 CAIRO_SCALED_GLYPH_INFO_METRICS |
4494 CAIRO_SCALED_GLYPH_INFO_SURFACE,
4496 if (unlikely (status))
4499 scaled_glyph = *scaled_glyph_out;
4500 glyph_surface = scaled_glyph->surface;
4501 already_had_glyph_surface = FALSE;
4503 already_had_glyph_surface = TRUE;
4506 info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (connection,
4508 glyph_surface->format);
4509 if (unlikely (info == NULL)) {
4510 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4515 /* If the glyph surface has zero height or width, we create
4516 * a clear 1x1 surface, to avoid various X server bugs.
4518 if (glyph_surface->width == 0 || glyph_surface->height == 0) {
4519 cairo_surface_t *tmp_surface;
4521 tmp_surface = cairo_image_surface_create (info->format, 1, 1);
4522 status = tmp_surface->status;
4523 if (unlikely (status))
4526 tmp_surface->device_transform = glyph_surface->base.device_transform;
4527 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
4529 glyph_surface = (cairo_image_surface_t *) tmp_surface;
4533 /* If the glyph format does not match the font format, then we
4534 * create a temporary surface for the glyph image with the font's
4537 if (glyph_surface->format != info->format) {
4538 glyph_surface = _cairo_image_surface_coerce_to_format (glyph_surface,
4540 status = glyph_surface->base.status;
4541 if (unlikely (status))
4545 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
4546 glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
4547 glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
4548 glyph_info.width = glyph_surface->width;
4549 glyph_info.height = glyph_surface->height;
4550 glyph_info.x_off = scaled_glyph->x_advance;
4551 glyph_info.y_off = scaled_glyph->y_advance;
4553 data = glyph_surface->data;
4555 /* flip formats around */
4556 switch (_cairo_xcb_get_glyphset_index_for_format (scaled_glyph->surface->format)) {
4557 case GLYPHSET_INDEX_A1:
4558 /* local bitmaps are always stored with bit == byte */
4559 if (_cairo_is_little_endian() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
4560 int c = glyph_surface->stride * glyph_surface->height;
4565 if (unlikely (new == NULL)) {
4566 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4574 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
4575 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
4576 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
4583 case GLYPHSET_INDEX_A8:
4586 case GLYPHSET_INDEX_ARGB32:
4587 if (_cairo_is_little_endian() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
4588 unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
4592 new = malloc (4 * c);
4593 if (unlikely (new == NULL)) {
4594 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4599 d = (uint32_t *) data;
4601 *n++ = bswap_32 (*d);
4604 data = (uint8_t *) new;
4612 /* XXX assume X server wants pixman padding. Xft assumes this as well */
4614 _cairo_xcb_connection_render_add_glyphs (connection,
4616 1, &glyph_index, &glyph_info,
4617 glyph_surface->stride * glyph_surface->height,
4620 if (data != glyph_surface->data)
4623 status = _cairo_xcb_glyph_attach (connection, scaled_glyph, info);
4626 if (glyph_surface != scaled_glyph->surface)
4627 cairo_surface_destroy (&glyph_surface->base);
4629 /* If the scaled glyph didn't already have a surface attached
4630 * to it, release the created surface now that we have it
4631 * uploaded to the X server. If the surface has already been
4632 * there (e.g. because image backend requested it), leave it in
4635 if (! already_had_glyph_surface)
4636 _cairo_scaled_glyph_set_surface (scaled_glyph, font, NULL);
4641 typedef void (*cairo_xcb_render_composite_text_func_t)
4642 (cairo_xcb_connection_t *connection,
4644 xcb_render_picture_t src,
4645 xcb_render_picture_t dst,
4646 xcb_render_pictformat_t mask_format,
4647 xcb_render_glyphset_t glyphset,
4654 static cairo_status_t
4655 _emit_glyphs_chunk (cairo_xcb_surface_t *dst,
4656 cairo_operator_t op,
4657 cairo_xcb_picture_t *src,
4658 /* info for this chunk */
4659 cairo_xcb_glyph_t *glyphs,
4662 int estimated_req_size,
4663 cairo_xcb_font_glyphset_info_t *info,
4664 xcb_render_pictformat_t mask_format)
4666 cairo_xcb_render_composite_text_func_t composite_text_func;
4667 uint8_t stack_buf[CAIRO_STACK_BUFFER_SIZE];
4668 uint8_t *buf = stack_buf;
4669 x_glyph_elt_t *elt = NULL; /* silence compiler */
4673 if (estimated_req_size > ARRAY_LENGTH (stack_buf)) {
4674 buf = malloc (estimated_req_size);
4675 if (unlikely (buf == NULL))
4676 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4680 for (i = 0; i < num_glyphs; i++) {
4681 if (_start_new_glyph_elt (i, &glyphs[i])) {
4683 len += 4 - (len & 3);
4685 elt = (x_glyph_elt_t *) (buf + len);
4687 elt->deltax = glyphs[i].i.x;
4688 elt->deltay = glyphs[i].i.y;
4689 len += sizeof (x_glyph_elt_t);
4693 case 1: *(uint8_t *) (buf + len) = glyphs[i].index; break;
4694 case 2: *(uint16_t *) (buf + len) = glyphs[i].index; break;
4696 case 4: *(uint32_t *) (buf + len) = glyphs[i].index; break;
4702 len += 4 - (len & 3);
4706 composite_text_func = _cairo_xcb_connection_render_composite_glyphs_8;
4709 composite_text_func = _cairo_xcb_connection_render_composite_glyphs_16;
4713 composite_text_func = _cairo_xcb_connection_render_composite_glyphs_32;
4716 composite_text_func (dst->connection,
4717 _render_operator (op),
4722 src->x + glyphs[0].i.x,
4723 src->y + glyphs[0].i.y,
4726 if (buf != stack_buf)
4729 return CAIRO_STATUS_SUCCESS;
4732 static cairo_int_status_t
4733 _composite_glyphs (void *closure,
4734 cairo_xcb_surface_t *dst,
4735 cairo_operator_t op,
4736 const cairo_pattern_t *pattern,
4739 const cairo_rectangle_int_t *extents,
4742 composite_glyphs_info_t *info = closure;
4743 cairo_scaled_glyph_t *glyph_cache[64];
4744 cairo_status_t status = CAIRO_STATUS_SUCCESS;
4745 cairo_fixed_t x = 0, y = 0;
4746 cairo_xcb_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
4747 const unsigned int max_request_size = dst->connection->maximum_request_length - 64;
4748 cairo_xcb_picture_t *src;
4750 unsigned long max_index = 0;
4753 unsigned int request_size = 0;
4756 if (dst->deferred_clear) {
4757 status = _cairo_xcb_surface_clear (dst);
4758 if (unlikely (status))
4762 src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
4763 if (unlikely (src->base.status))
4764 return src->base.status;
4766 memset (glyph_cache, 0, sizeof (glyph_cache));
4768 for (i = 0; i < info->num_glyphs; i++) {
4769 cairo_scaled_glyph_t *glyph;
4770 unsigned long glyph_index = info->glyphs[i].index;
4771 int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
4772 int old_width = width;
4775 glyph = glyph_cache[cache_index];
4776 if (glyph == NULL ||
4777 _cairo_scaled_glyph_index (glyph) != glyph_index)
4779 status = _cairo_scaled_glyph_lookup (info->font,
4781 CAIRO_SCALED_GLYPH_INFO_METRICS,
4783 if (unlikely (status)) {
4784 cairo_surface_destroy (&src->base);
4788 /* Send unseen glyphs to the server */
4789 if (glyph->dev_private_key != dst->connection) {
4790 status = _cairo_xcb_surface_add_glyph (dst->connection,
4793 if (unlikely (status)) {
4794 cairo_surface_destroy (&src->base);
4799 glyph_cache[cache_index] = glyph;
4802 this_x = _cairo_lround (info->glyphs[i].d.x) - dst_x;
4803 this_y = _cairo_lround (info->glyphs[i].d.y) - dst_y;
4805 this_glyphset_info = glyph->dev_private;
4806 if (glyphset_info == NULL)
4807 glyphset_info = this_glyphset_info;
4809 /* Update max glyph index */
4810 if (glyph_index > max_index) {
4811 max_index = glyph_index;
4812 if (max_index >= 65536)
4814 else if (max_index >= 256)
4816 if (width != old_width)
4817 request_size += (width - old_width) * i;
4820 /* If we will pass the max request size by adding this glyph,
4821 * flush current glyphs. Note that we account for a
4822 * possible element being added below.
4824 * Also flush if changing glyphsets, as Xrender limits one mask
4825 * format per request, so we can either break up, or use a
4826 * wide-enough mask format. We do the former. One reason to
4827 * prefer the latter is the fact that Xserver ADDs all glyphs
4828 * to the mask first, and then composes that to final surface,
4829 * though it's not a big deal.
4831 * If the glyph has a coordinate which cannot be represented
4832 * as a 16-bit offset from the previous glyph, flush the
4833 * current chunk. The current glyph will be the first one in
4834 * the next chunk, thus its coordinates will be an offset from
4835 * the destination origin. This offset is guaranteed to be
4836 * representable as 16-bit offset in _can_composite_glyphs().
4838 if (request_size + width > max_request_size - _cairo_sz_x_glyph_elt_t ||
4839 this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
4840 this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
4841 this_glyphset_info != glyphset_info)
4843 status = _emit_glyphs_chunk (dst, op, src,
4845 old_width, request_size,
4847 info->use_mask ? glyphset_info->xrender_format : 0);
4848 if (unlikely (status)) {
4849 cairo_surface_destroy (&src->base);
4854 info->num_glyphs -= i;
4857 max_index = info->glyphs[0].index;
4858 width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
4863 glyphset_info = this_glyphset_info;
4866 /* Convert absolute glyph position to relative-to-current-point
4868 info->glyphs[i].i.x = this_x - x;
4869 info->glyphs[i].i.y = this_y - y;
4871 /* Start a new element for the first glyph,
4872 * or for any glyph that has unexpected position,
4873 * or if current element has too many glyphs.
4875 * These same conditions are mirrored in _emit_glyphs_chunk().
4877 if (_start_new_glyph_elt (i, &info->glyphs[i]))
4878 request_size += _cairo_sz_x_glyph_elt_t;
4880 /* adjust current-position */
4881 x = this_x + glyph->x_advance;
4882 y = this_y + glyph->y_advance;
4884 request_size += width;
4888 status = _emit_glyphs_chunk (dst, op, src,
4890 width, request_size,
4892 info->use_mask ? glyphset_info->xrender_format : 0);
4895 cairo_surface_destroy (&src->base);
4901 _cairo_xcb_render_compositor_glyphs (const cairo_compositor_t *compositor,
4902 cairo_composite_rectangles_t *composite,
4903 cairo_scaled_font_t *scaled_font,
4904 cairo_glyph_t *glyphs,
4906 cairo_bool_t overlap)
4908 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
4909 cairo_operator_t op = composite->op;
4910 cairo_pattern_t *source = &composite->source_pattern.base;
4911 cairo_int_status_t status;
4913 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
4914 return CAIRO_INT_STATUS_UNSUPPORTED;
4916 if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
4917 return CAIRO_INT_STATUS_UNSUPPORTED;
4919 status = CAIRO_INT_STATUS_UNSUPPORTED;
4920 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) {
4921 _cairo_scaled_font_freeze_cache (scaled_font);
4923 status = _can_composite_glyphs (surface, &composite->bounded,
4924 scaled_font, glyphs, &num_glyphs);
4925 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
4926 composite_glyphs_info_t info;
4929 info.font = scaled_font;
4930 info.glyphs = (cairo_xcb_glyph_t *) glyphs;
4931 info.num_glyphs = num_glyphs;
4934 ! composite->is_bounded ||
4935 ! _cairo_clip_is_region(composite->clip);
4937 if (composite->mask.width > composite->unbounded.width ||
4938 composite->mask.height > composite->unbounded.height)
4940 /* Glyphs are tricky since we do not directly control the
4941 * geometry and their inked extents depend on the
4942 * individual glyph-surface size. We must set a clip region
4943 * so that the X server can trim the glyphs appropriately.
4945 flags |= FORCE_CLIP_REGION;
4947 status = _clip_and_composite (surface, op, source,
4948 _composite_glyphs, NULL,
4950 need_bounded_clip (composite) |
4954 _cairo_scaled_font_thaw_cache (scaled_font);
4957 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
4958 assert (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE);
4960 _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source,
4961 scaled_font, glyphs, num_glyphs,
4968 static xcb_render_fixed_t *
4969 _create_convolution_coef (double *convolution_matrix,
4970 int col, int row, cairo_bool_t is_x_pass)
4972 xcb_render_fixed_t *values;
4978 if (! convolution_matrix || col == 0 || row == 0)
4983 values = _cairo_malloc_ab (length + 2, sizeof (xcb_render_fixed_t));
4987 values[0] = _cairo_fixed_16_16_from_double (v);
4988 values[1] = _cairo_fixed_16_16_from_double (1.0);
4989 coef = _cairo_malloc_ab (length, sizeof (double));
4994 memset (coef, 0, sizeof (double) * length);
4995 compute_x_coef_to_double (convolution_matrix, row, col, coef);
4999 values = _cairo_malloc_ab (length + 2, sizeof (xcb_render_fixed_t));
5002 values[0] = _cairo_fixed_16_16_from_double (1.0);
5004 values[1] = _cairo_fixed_16_16_from_double (v);
5005 coef = _cairo_malloc_ab (length, sizeof (double));
5010 memset (coef, 0, sizeof (double) * length);
5011 compute_y_coef_to_double (convolution_matrix, row, col, coef);
5014 for (i = 0; i < length; i++)
5015 values[i+2] = _cairo_fixed_16_16_from_double (coef[i]);
5021 cairo_xcb_picture_t *
5022 _cairo_xcb_gaussian_filter (cairo_xcb_surface_t *source,
5023 cairo_xcb_picture_t *orig_pict,
5024 const cairo_pattern_t *pattern)
5028 cairo_matrix_t matrix;
5029 cairo_format_t format;
5031 cairo_xcb_picture_t *shrinked_picture = NULL;
5032 cairo_xcb_picture_t *scratch_pictures[] = { NULL, NULL };
5033 cairo_xcb_picture_t *temp_pict;
5034 cairo_xcb_picture_t *picture;
5036 xcb_pixmap_t pixmap;
5037 pixman_format_code_t pixman_format;
5039 xcb_render_pictformat_t xrender_format;
5041 int src_width= orig_pict->width;
5042 int src_height = orig_pict->height;
5043 xcb_render_fixed_t *coef;
5046 if (pattern->filter != CAIRO_FILTER_GAUSSIAN ||
5047 pattern->convolution_matrix == NULL) {
5048 return (cairo_xcb_picture_t *)cairo_surface_reference (&orig_pict->base);
5051 row = pattern->y_radius * 2 + 1;
5052 col = pattern->x_radius * 2 + 1;
5054 width = src_width / pattern->shrink_factor_x;
5055 height = src_height / pattern->shrink_factor_y;
5056 format = _cairo_format_from_content (cairo_surface_get_content (&source->base));
5057 pixman_format = _cairo_format_to_pixman_format_code (format);
5058 depth = PIXMAN_FORMAT_DEPTH (pixman_format);
5059 xrender_format = source->connection->standard_formats[format];
5061 picture = _cairo_xcb_picture_create (source->screen,
5064 src_width, src_height);
5065 if (unlikely (picture->base.status)) {
5066 cairo_surface_destroy (&picture->base);
5067 picture = (cairo_xcb_picture_t *) cairo_surface_reference (&orig_pict->base);
5071 pixmap = _cairo_xcb_connection_create_pixmap (source->connection,
5074 src_width, src_height);
5076 _cairo_xcb_connection_render_create_picture (source->connection,
5081 _cairo_xcb_connection_free_pixmap (source->connection, pixmap);
5083 for (i = 0; i < 2; i++) {
5084 scratch_pictures[i] = _cairo_xcb_picture_create (source->screen,
5089 if (unlikely (scratch_pictures[i]->base.status)) {
5090 cairo_surface_destroy (&picture->base);
5091 picture = (cairo_xcb_picture_t *) cairo_surface_reference (&orig_pict->base);
5095 pixmap = _cairo_xcb_connection_create_pixmap (source->connection,
5100 _cairo_xcb_connection_render_create_picture (source->connection,
5101 scratch_pictures[i]->picture,
5105 _cairo_xcb_connection_free_pixmap (source->connection, pixmap);
5108 if (width != src_width || height != src_height) {
5109 shrinked_picture = _cairo_xcb_picture_create (source->screen,
5114 if (unlikely (shrinked_picture->base.status)) {
5115 cairo_surface_destroy (&picture->base);
5116 picture = (cairo_xcb_picture_t *) cairo_surface_reference (&orig_pict->base);
5120 pixmap = _cairo_xcb_connection_create_pixmap (source->connection,
5125 _cairo_xcb_connection_render_create_picture (source->connection,
5126 shrinked_picture->picture,
5131 _cairo_xcb_connection_free_pixmap (source->connection, pixmap);
5133 cairo_matrix_init_scale (&matrix,
5134 (double) src_width / (double) width,
5135 (double) src_height / (double) height);
5137 _cairo_xcb_picture_set_matrix (orig_pict,
5138 &matrix, CAIRO_FILTER_BILINEAR,
5140 _cairo_xcb_picture_set_extend (orig_pict, CAIRO_EXTEND_NONE);
5141 _cairo_xcb_picture_set_component_alpha (orig_pict,
5142 pattern->has_component_alpha);
5144 _cairo_xcb_picture_set_filter (orig_pict, CAIRO_FILTER_NEAREST, 0, NULL);
5146 _cairo_xcb_connection_render_composite (source->connection,
5147 _render_operator (CAIRO_OPERATOR_SOURCE),
5150 shrinked_picture->picture,
5156 temp_pict = shrinked_picture;
5158 temp_pict = orig_pict;
5160 /* filter with gaussian, first x pass */
5161 coef = _create_convolution_coef (pattern->convolution_matrix,
5164 cairo_surface_destroy (&picture->base);
5165 picture = (cairo_xcb_picture_t *) cairo_surface_reference (&orig_pict->base);
5169 cairo_matrix_init_identity (&matrix);
5171 _cairo_xcb_picture_set_matrix (temp_pict,
5172 &matrix, CAIRO_FILTER_NEAREST,
5174 _cairo_xcb_picture_set_extend (temp_pict, CAIRO_EXTEND_NONE);
5175 _cairo_xcb_picture_set_component_alpha (temp_pict,
5176 pattern->has_component_alpha);
5178 _cairo_xcb_picture_set_filter (temp_pict, CAIRO_FILTER_GAUSSIAN, col+2, coef);
5179 _cairo_xcb_connection_render_composite (source->connection,
5180 _render_operator (CAIRO_OPERATOR_SOURCE),
5183 scratch_pictures[0]->picture,
5192 coef = _create_convolution_coef (pattern->convolution_matrix,
5195 cairo_surface_destroy (&picture->base);
5196 picture = (cairo_xcb_picture_t *) cairo_surface_reference (&orig_pict->base);
5200 cairo_matrix_init_identity (&matrix);
5202 _cairo_xcb_picture_set_matrix (scratch_pictures[0],
5203 &matrix, CAIRO_FILTER_NEAREST,
5205 _cairo_xcb_picture_set_extend (scratch_pictures[0], CAIRO_EXTEND_NONE);
5206 _cairo_xcb_picture_set_component_alpha (scratch_pictures[0],
5207 pattern->has_component_alpha);
5209 _cairo_xcb_picture_set_filter (scratch_pictures[0], CAIRO_FILTER_GAUSSIAN, row+2, coef);
5210 _cairo_xcb_connection_render_composite (source->connection,
5211 _render_operator (CAIRO_OPERATOR_SOURCE),
5212 scratch_pictures[0]->picture,
5214 scratch_pictures[1]->picture,
5222 /* enlarge back to picture */
5223 cairo_matrix_init_scale (&matrix,
5224 (double) width / (double) src_width,
5225 (double) height / (double) src_height);
5227 _cairo_xcb_picture_set_matrix (scratch_pictures[1],
5228 &matrix, CAIRO_FILTER_BILINEAR,
5229 src_width/2, src_height/2);
5230 _cairo_xcb_picture_set_extend (scratch_pictures[1], CAIRO_EXTEND_NONE);
5231 _cairo_xcb_picture_set_component_alpha (scratch_pictures[1],
5232 pattern->has_component_alpha);
5234 _cairo_xcb_picture_set_filter (scratch_pictures[1], CAIRO_FILTER_BILINEAR, 0, NULL);
5236 _cairo_xcb_connection_render_composite (source->connection,
5237 _render_operator (CAIRO_OPERATOR_SOURCE),
5238 scratch_pictures[1]->picture,
5244 src_width, src_height);
5246 if (shrinked_picture)
5247 cairo_surface_destroy (&shrinked_picture->base);
5248 for (i = 0; i < 2; i++) {
5249 if (scratch_pictures[i])
5250 cairo_surface_destroy (&scratch_pictures[i]->base);