beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-xcb-surface-render.c
blob044339bce8f9805512824cfb2e1d67174358b944
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * Contributor(s):
29 * Chris Wilson <chris@chris-wilson.co.uk>
32 #include "cairoint.h"
34 #include "cairo-xcb-private.h"
36 #include "cairo-boxes-private.h"
37 #include "cairo-clip-inline.h"
38 #include "cairo-clip-private.h"
39 #include "cairo-composite-rectangles-private.h"
40 #include "cairo-image-surface-inline.h"
41 #include "cairo-image-surface-private.h"
42 #include "cairo-list-inline.h"
43 #include "cairo-region-private.h"
44 #include "cairo-surface-offset-private.h"
45 #include "cairo-surface-snapshot-inline.h"
46 #include "cairo-surface-subsurface-private.h"
47 #include "cairo-traps-private.h"
48 #include "cairo-recording-surface-inline.h"
49 #include "cairo-paginated-private.h"
50 #include "cairo-pattern-inline.h"
52 #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
54 static cairo_status_t
55 _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
56 cairo_operator_t op,
57 const cairo_pattern_t *src,
58 cairo_boxes_t *boxes,
59 cairo_composite_rectangles_t *extents);
61 static inline cairo_xcb_connection_t *
62 _picture_to_connection (cairo_xcb_picture_t *picture)
64 return (cairo_xcb_connection_t *) picture->base.device;
67 static void
68 _cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface);
70 static uint32_t
71 hars_petruska_f54_1_random (void)
73 #define rol(x,k) ((x << k) | (x >> (32-k)))
74 static uint32_t x;
75 return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
76 #undef rol
79 static cairo_status_t
80 _cairo_xcb_picture_finish (void *abstract_surface)
82 cairo_xcb_picture_t *surface = abstract_surface;
83 cairo_xcb_connection_t *connection = _picture_to_connection (surface);
84 cairo_status_t status;
86 status = _cairo_xcb_connection_acquire (connection);
87 cairo_list_del (&surface->link);
88 if (unlikely (status))
89 return status;
91 _cairo_xcb_connection_render_free_picture (connection, surface->picture);
93 _cairo_xcb_connection_release (connection);
95 return CAIRO_STATUS_SUCCESS;
98 static const cairo_surface_backend_t _cairo_xcb_picture_backend = {
99 CAIRO_SURFACE_TYPE_XCB,
100 _cairo_xcb_picture_finish,
103 static const struct xcb_render_transform_t identity_transform = {
104 1 << 16, 0, 0,
105 0, 1 << 16, 0,
106 0, 0, 1 << 16,
109 static cairo_xcb_picture_t *
110 _cairo_xcb_picture_create (cairo_xcb_screen_t *screen,
111 pixman_format_code_t pixman_format,
112 xcb_render_pictformat_t xrender_format,
113 int width, int height)
115 cairo_xcb_picture_t *surface;
117 surface = malloc (sizeof (cairo_xcb_picture_t));
118 if (unlikely (surface == NULL))
119 return (cairo_xcb_picture_t *)
120 _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
122 _cairo_surface_init (&surface->base,
123 &_cairo_xcb_picture_backend,
124 &screen->connection->device,
125 _cairo_content_from_pixman_format (pixman_format));
127 cairo_list_add (&surface->link, &screen->pictures);
129 surface->screen = screen;
130 surface->picture = _cairo_xcb_connection_get_xid (screen->connection);
131 surface->pixman_format = pixman_format;
132 surface->xrender_format = xrender_format;
134 surface->x0 = surface->y0 = 0;
135 surface->x = surface->y = 0;
136 surface->width = width;
137 surface->height = height;
139 surface->transform = identity_transform;
140 surface->extend = CAIRO_EXTEND_NONE;
141 surface->filter = CAIRO_FILTER_NEAREST;
142 surface->has_component_alpha = FALSE;
144 return surface;
147 static inline cairo_bool_t
148 _operator_is_supported (uint32_t flags, cairo_operator_t op)
150 if (op <= CAIRO_OPERATOR_SATURATE)
151 return TRUE;
153 /* Can we use PDF operators? */
154 #if CAIRO_XCB_RENDER_AT_LEAST(0, 11)
155 if (op <= CAIRO_OPERATOR_HSL_LUMINOSITY)
156 return flags & CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
157 #endif
159 return FALSE;
162 static int
163 _render_operator (cairo_operator_t op)
165 #define C(x,y) case CAIRO_OPERATOR_##x: return XCB_RENDER_PICT_OP_##y
166 switch (op) {
167 C(CLEAR, CLEAR);
168 C(SOURCE, SRC);
170 C(OVER, OVER);
171 C(IN, IN);
172 C(OUT, OUT);
173 C(ATOP, ATOP);
175 C(DEST, DST);
176 C(DEST_OVER, OVER_REVERSE);
177 C(DEST_IN, IN_REVERSE);
178 C(DEST_OUT, OUT_REVERSE);
179 C(DEST_ATOP, ATOP_REVERSE);
181 C(XOR, XOR);
182 C(ADD, ADD);
183 C(SATURATE, SATURATE);
185 /* PDF operators were added in RENDER 0.11, check if the xcb headers have
186 * the defines, else fall through to the default case. */
187 #if CAIRO_XCB_RENDER_AT_LEAST(0, 11)
188 #define BLEND(x,y) C(x,y)
189 #else
190 #define BLEND(x,y) case CAIRO_OPERATOR_##x:
191 #endif
192 BLEND(MULTIPLY, MULTIPLY);
193 BLEND(SCREEN, SCREEN);
194 BLEND(OVERLAY, OVERLAY);
195 BLEND(DARKEN, DARKEN);
196 BLEND(LIGHTEN, LIGHTEN);
197 BLEND(COLOR_DODGE, COLOR_DODGE);
198 BLEND(COLOR_BURN, COLOR_BURN);
199 BLEND(HARD_LIGHT, HARD_LIGHT);
200 BLEND(SOFT_LIGHT, SOFT_LIGHT);
201 BLEND(DIFFERENCE, DIFFERENCE);
202 BLEND(EXCLUSION, EXCLUSION);
203 BLEND(HSL_HUE, HSL_HUE);
204 BLEND(HSL_SATURATION, HSL_SATURATION);
205 BLEND(HSL_COLOR, HSL_COLOR);
206 BLEND(HSL_LUMINOSITY, HSL_LUMINOSITY);
208 default:
209 ASSERT_NOT_REACHED;
210 return XCB_RENDER_PICT_OP_OVER;
214 static cairo_status_t
215 _cairo_xcb_surface_set_clip_region (cairo_xcb_surface_t *surface,
216 cairo_region_t *region)
218 xcb_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
219 xcb_rectangle_t *rects = stack_rects;
220 int i, num_rects;
222 num_rects = cairo_region_num_rectangles (region);
224 if (num_rects > ARRAY_LENGTH (stack_rects)) {
225 rects = _cairo_malloc_ab (num_rects, sizeof (xcb_rectangle_t));
226 if (unlikely (rects == NULL)) {
227 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
231 for (i = 0; i < num_rects; i++) {
232 cairo_rectangle_int_t rect;
234 cairo_region_get_rectangle (region, i, &rect);
236 rects[i].x = rect.x;
237 rects[i].y = rect.y;
238 rects[i].width = rect.width;
239 rects[i].height = rect.height;
242 _cairo_xcb_connection_render_set_picture_clip_rectangles (surface->connection,
243 surface->picture,
244 0, 0,
245 num_rects, rects);
247 if (rects != stack_rects)
248 free (rects);
250 return CAIRO_STATUS_SUCCESS;
253 static void
254 _cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t *surface)
256 uint32_t values[] = { XCB_NONE };
257 _cairo_xcb_connection_render_change_picture (surface->connection,
258 surface->picture,
259 XCB_RENDER_CP_CLIP_MASK,
260 values);
263 static void
264 _cairo_xcb_surface_set_precision (cairo_xcb_surface_t *surface,
265 cairo_antialias_t antialias)
267 cairo_xcb_connection_t *connection = surface->connection;
268 uint32_t precision;
270 if (connection->force_precision != -1)
271 precision = connection->force_precision;
272 else switch (antialias) {
273 default:
274 case CAIRO_ANTIALIAS_DEFAULT:
275 case CAIRO_ANTIALIAS_GRAY:
276 case CAIRO_ANTIALIAS_NONE:
277 case CAIRO_ANTIALIAS_FAST:
278 case CAIRO_ANTIALIAS_GOOD:
279 precision = XCB_RENDER_POLY_MODE_IMPRECISE;
280 break;
281 case CAIRO_ANTIALIAS_SUBPIXEL:
282 case CAIRO_ANTIALIAS_BEST:
283 precision = XCB_RENDER_POLY_MODE_PRECISE;
284 break;
287 if (surface->precision != precision) {
288 _cairo_xcb_connection_render_change_picture (connection,
289 surface->picture,
290 XCB_RENDER_CP_POLY_MODE,
291 &precision);
292 surface->precision = precision;
297 static void
298 _cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface)
300 assert (surface->fallback == NULL);
301 if (surface->picture == XCB_NONE) {
302 uint32_t values[1];
303 uint32_t flags = 0;
305 if (surface->precision != XCB_RENDER_POLY_MODE_PRECISE) {
306 flags |= XCB_RENDER_CP_POLY_MODE;
307 values[0] = surface->precision;
310 surface->picture = _cairo_xcb_connection_get_xid (surface->connection);
311 _cairo_xcb_connection_render_create_picture (surface->connection,
312 surface->picture,
313 surface->drawable,
314 surface->xrender_format,
315 flags, values);
319 static cairo_xcb_picture_t *
320 _picture_from_image (cairo_xcb_surface_t *target,
321 xcb_render_pictformat_t format,
322 cairo_image_surface_t *image,
323 cairo_xcb_shm_info_t *shm_info)
325 xcb_pixmap_t pixmap;
326 xcb_gcontext_t gc;
327 cairo_xcb_picture_t *picture;
329 pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
330 image->depth,
331 target->drawable,
332 image->width, image->height);
334 gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, image->depth);
336 if (shm_info != NULL) {
337 _cairo_xcb_connection_shm_put_image (target->connection,
338 pixmap, gc,
339 image->width, image->height,
340 0, 0,
341 image->width, image->height,
342 0, 0,
343 image->depth,
344 shm_info->shm,
345 shm_info->offset);
346 } else {
347 int len;
349 /* Do we need to trim the image? */
350 len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format));
351 if (len == image->stride) {
352 _cairo_xcb_connection_put_image (target->connection,
353 pixmap, gc,
354 image->width, image->height,
355 0, 0,
356 image->depth,
357 image->stride,
358 image->data);
359 } else {
360 _cairo_xcb_connection_put_subimage (target->connection,
361 pixmap, gc,
362 0, 0,
363 image->width, image->height,
364 PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
365 image->stride,
366 0, 0,
367 image->depth,
368 image->data);
373 _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
375 picture = _cairo_xcb_picture_create (target->screen,
376 image->pixman_format, format,
377 image->width, image->height);
378 if (likely (picture->base.status == CAIRO_STATUS_SUCCESS)) {
379 _cairo_xcb_connection_render_create_picture (target->connection,
380 picture->picture, pixmap, format,
381 0, 0);
384 _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
386 return picture;
389 static cairo_bool_t
390 _pattern_is_supported (uint32_t flags,
391 const cairo_pattern_t *pattern)
394 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
395 return TRUE;
397 switch (pattern->extend) {
398 default:
399 ASSERT_NOT_REACHED;
400 case CAIRO_EXTEND_NONE:
401 case CAIRO_EXTEND_REPEAT:
402 break;
403 case CAIRO_EXTEND_PAD:
404 case CAIRO_EXTEND_REFLECT:
405 if ((flags & CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT) == 0)
406 return FALSE;
409 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
410 switch (pattern->filter) {
411 case CAIRO_FILTER_FAST:
412 case CAIRO_FILTER_NEAREST:
413 return (flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) ||
414 _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL);
415 case CAIRO_FILTER_GOOD:
416 return flags & CAIRO_XCB_RENDER_HAS_FILTER_GOOD;
417 case CAIRO_FILTER_BEST:
418 return flags & CAIRO_XCB_RENDER_HAS_FILTER_BEST;
419 case CAIRO_FILTER_BILINEAR:
420 case CAIRO_FILTER_GAUSSIAN:
421 default:
422 return flags & CAIRO_XCB_RENDER_HAS_FILTERS;
424 } else if (pattern->type == CAIRO_PATTERN_TYPE_MESH) {
425 return FALSE;
426 } else { /* gradient */
427 if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
428 return FALSE;
430 /* The RENDER specification says that the inner circle has to be
431 * completely contained inside the outer one. */
432 if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL &&
433 ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) pattern))
435 return FALSE;
437 return TRUE;
441 static void
442 _cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
443 const cairo_matrix_t *matrix,
444 cairo_filter_t filter,
445 double xc, double yc)
447 xcb_render_transform_t transform;
448 pixman_transform_t *pixman_transform;
449 cairo_int_status_t ignored;
451 /* Casting between pixman_transform_t and xcb_render_transform_t is safe
452 * because they happen to be the exact same type.
454 pixman_transform = (pixman_transform_t *) &transform;
456 picture->x = picture->x0;
457 picture->y = picture->y0;
458 ignored = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
459 pixman_transform,
460 &picture->x, &picture->y);
461 (void) ignored;
463 if (memcmp (&picture->transform, &transform, sizeof (xcb_render_transform_t))) {
464 _cairo_xcb_connection_render_set_picture_transform (_picture_to_connection (picture),
465 picture->picture,
466 &transform);
468 picture->transform = transform;
472 static void
473 _cairo_xcb_picture_set_filter (cairo_xcb_picture_t *picture,
474 cairo_filter_t filter)
476 const char *render_filter;
477 int len;
479 if (picture->filter == filter)
480 return;
482 switch (filter) {
483 case CAIRO_FILTER_FAST:
484 render_filter = "fast";
485 len = strlen ("fast");
486 break;
488 case CAIRO_FILTER_GOOD:
489 render_filter = "good";
490 len = strlen ("good");
491 break;
493 case CAIRO_FILTER_BEST:
494 render_filter = "best";
495 len = strlen ("best");
496 break;
498 case CAIRO_FILTER_NEAREST:
499 render_filter = "nearest";
500 len = strlen ("nearest");
501 break;
503 case CAIRO_FILTER_BILINEAR:
504 render_filter = "bilinear";
505 len = strlen ("bilinear");
506 break;
508 default:
509 ASSERT_NOT_REACHED;
510 case CAIRO_FILTER_GAUSSIAN:
511 render_filter = "best";
512 len = strlen ("best");
513 break;
516 _cairo_xcb_connection_render_set_picture_filter (_picture_to_connection (picture),
517 picture->picture,
518 len, (char *) render_filter);
519 picture->filter = filter;
522 static void
523 _cairo_xcb_picture_set_extend (cairo_xcb_picture_t *picture,
524 cairo_extend_t extend)
526 uint32_t pa[1];
528 if (picture->extend == extend)
529 return;
531 switch (extend) {
532 default:
533 ASSERT_NOT_REACHED;
534 case CAIRO_EXTEND_NONE:
535 pa[0] = XCB_RENDER_REPEAT_NONE;
536 break;
538 case CAIRO_EXTEND_REPEAT:
539 pa[0] = XCB_RENDER_REPEAT_NORMAL;
540 break;
542 case CAIRO_EXTEND_REFLECT:
543 pa[0] = XCB_RENDER_REPEAT_REFLECT;
544 break;
546 case CAIRO_EXTEND_PAD:
547 pa[0] = XCB_RENDER_REPEAT_PAD;
548 break;
551 _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture),
552 picture->picture,
553 XCB_RENDER_CP_REPEAT, pa);
554 picture->extend = extend;
557 static void
558 _cairo_xcb_picture_set_component_alpha (cairo_xcb_picture_t *picture,
559 cairo_bool_t ca)
561 uint32_t pa[1];
563 if (picture->has_component_alpha == ca)
564 return;
566 pa[0] = ca;
568 _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture),
569 picture->picture,
570 XCB_RENDER_CP_COMPONENT_ALPHA,
571 pa);
572 picture->has_component_alpha = ca;
575 static cairo_xcb_picture_t *
576 _solid_picture (cairo_xcb_surface_t *target,
577 const cairo_color_t *color)
579 xcb_render_color_t xcb_color;
580 xcb_render_pictformat_t xrender_format;
581 cairo_xcb_picture_t *picture;
583 xcb_color.red = color->red_short;
584 xcb_color.green = color->green_short;
585 xcb_color.blue = color->blue_short;
586 xcb_color.alpha = color->alpha_short;
588 xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
589 picture = _cairo_xcb_picture_create (target->screen,
590 PIXMAN_a8r8g8b8,
591 xrender_format,
592 -1, -1);
593 if (unlikely (picture->base.status))
594 return picture;
596 if (target->connection->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) {
597 _cairo_xcb_connection_render_create_solid_fill (target->connection,
598 picture->picture,
599 xcb_color);
600 } else {
601 xcb_pixmap_t pixmap;
602 uint32_t values[] = { XCB_RENDER_REPEAT_NORMAL };
604 pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
605 32, target->drawable, 1, 1);
606 _cairo_xcb_connection_render_create_picture (target->connection,
607 picture->picture,
608 pixmap,
609 xrender_format,
610 XCB_RENDER_CP_REPEAT,
611 values);
612 if (target->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
613 xcb_rectangle_t rect;
615 rect.x = rect.y = 0;
616 rect.width = rect.height = 1;
618 _cairo_xcb_connection_render_fill_rectangles (_picture_to_connection (picture),
619 XCB_RENDER_PICT_OP_SRC,
620 picture->picture,
621 xcb_color, 1, &rect);
622 } else {
623 xcb_gcontext_t gc;
624 uint32_t pixel;
626 gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, 32);
628 /* XXX byte ordering? */
629 pixel = ((color->alpha_short >> 8) << 24) |
630 ((color->red_short >> 8) << 16) |
631 ((color->green_short >> 8) << 8) |
632 ((color->blue_short >> 8) << 0);
634 _cairo_xcb_connection_put_image (target->connection,
635 pixmap, gc,
636 1, 1, 0, 0,
637 32, 4, &pixel);
639 _cairo_xcb_screen_put_gc (target->screen, 32, gc);
642 _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
645 return picture;
648 static cairo_xcb_picture_t *
649 _cairo_xcb_transparent_picture (cairo_xcb_surface_t *target)
651 cairo_xcb_picture_t *picture;
653 picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT];
654 if (picture == NULL) {
655 picture = _solid_picture (target, CAIRO_COLOR_TRANSPARENT);
656 target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT] = &picture->base;
659 return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
662 static cairo_xcb_picture_t *
663 _cairo_xcb_black_picture (cairo_xcb_surface_t *target)
665 cairo_xcb_picture_t *picture;
667 picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_BLACK];
668 if (picture == NULL) {
669 picture = _solid_picture (target, CAIRO_COLOR_BLACK);
670 target->screen->stock_colors[CAIRO_STOCK_BLACK] = &picture->base;
673 return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
676 static cairo_xcb_picture_t *
677 _cairo_xcb_white_picture (cairo_xcb_surface_t *target)
679 cairo_xcb_picture_t *picture;
681 picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_WHITE];
682 if (picture == NULL) {
683 picture = _solid_picture (target, CAIRO_COLOR_WHITE);
684 target->screen->stock_colors[CAIRO_STOCK_WHITE] = &picture->base;
687 return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
690 static cairo_xcb_picture_t *
691 _cairo_xcb_solid_picture (cairo_xcb_surface_t *target,
692 const cairo_solid_pattern_t *pattern)
694 cairo_xcb_picture_t *picture;
695 cairo_xcb_screen_t *screen;
696 int i, n_cached;
698 if (pattern->color.alpha_short <= 0x00ff)
699 return _cairo_xcb_transparent_picture (target);
701 if (pattern->color.alpha_short >= 0xff00) {
702 if (pattern->color.red_short <= 0x00ff &&
703 pattern->color.green_short <= 0x00ff &&
704 pattern->color.blue_short <= 0x00ff)
706 return _cairo_xcb_black_picture (target);
709 if (pattern->color.red_short >= 0xff00 &&
710 pattern->color.green_short >= 0xff00 &&
711 pattern->color.blue_short >= 0xff00)
713 return _cairo_xcb_white_picture (target);
717 screen = target->screen;
718 n_cached = screen->solid_cache_size;
719 for (i = 0; i < n_cached; i++) {
720 if (_cairo_color_equal (&screen->solid_cache[i].color, &pattern->color)) {
721 return (cairo_xcb_picture_t *) cairo_surface_reference (screen->solid_cache[i].picture);
725 picture = _solid_picture (target, &pattern->color);
726 if (unlikely (picture->base.status))
727 return picture;
729 if (screen->solid_cache_size < ARRAY_LENGTH (screen->solid_cache)) {
730 i = screen->solid_cache_size++;
731 } else {
732 i = hars_petruska_f54_1_random () % ARRAY_LENGTH (screen->solid_cache);
733 cairo_surface_destroy (screen->solid_cache[i].picture);
735 screen->solid_cache[i].picture = cairo_surface_reference (&picture->base);
736 screen->solid_cache[i].color = pattern->color;
738 return picture;
741 static cairo_xcb_picture_t *
742 _render_to_picture (cairo_xcb_surface_t *target,
743 const cairo_pattern_t *pattern,
744 const cairo_rectangle_int_t *extents)
746 cairo_image_surface_t *image;
747 cairo_xcb_shm_info_t *shm_info;
748 cairo_pattern_union_t copy;
749 cairo_status_t status;
750 cairo_xcb_picture_t *picture;
751 pixman_format_code_t pixman_format;
752 xcb_render_pictformat_t xrender_format;
754 /* XXX handle extend modes via tiling? */
755 /* XXX alpha-only masks? */
757 pixman_format = PIXMAN_a8r8g8b8;
758 xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
760 status = _cairo_xcb_shm_image_create (target->screen->connection,
761 pixman_format,
762 extents->width, extents->height,
763 &image, &shm_info);
764 if (unlikely (status))
765 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
767 _cairo_pattern_init_static_copy (&copy.base, pattern);
768 cairo_matrix_translate (&copy.base.matrix, extents->x, extents->y);
769 status = _cairo_surface_paint (&image->base,
770 CAIRO_OPERATOR_SOURCE,
771 &copy.base,
772 NULL);
773 if (unlikely (status)) {
774 cairo_surface_destroy (&image->base);
775 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
778 picture = _picture_from_image (target, xrender_format, image, shm_info);
779 cairo_surface_destroy (&image->base);
781 if (unlikely (picture->base.status))
782 return picture;
784 _cairo_xcb_picture_set_component_alpha (picture, pattern->has_component_alpha);
785 picture->x = -extents->x;
786 picture->y = -extents->y;
788 return picture;
791 static xcb_render_fixed_t *
792 _gradient_to_xcb (const cairo_gradient_pattern_t *gradient,
793 unsigned int *n_stops,
794 char *buf, unsigned int buflen)
796 xcb_render_fixed_t *stops;
797 xcb_render_color_t *colors;
798 unsigned int i;
800 assert (gradient->n_stops > 0);
801 *n_stops = MAX (gradient->n_stops, 2);
803 if (*n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen)
805 stops = (xcb_render_fixed_t *) buf;
807 else
809 stops =
810 _cairo_malloc_ab (*n_stops,
811 sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t));
812 if (unlikely (stops == NULL))
813 return NULL;
816 colors = (xcb_render_color_t *) (stops + *n_stops);
817 for (i = 0; i < gradient->n_stops; i++) {
818 stops[i] =
819 _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
821 colors[i].red = gradient->stops[i].color.red_short;
822 colors[i].green = gradient->stops[i].color.green_short;
823 colors[i].blue = gradient->stops[i].color.blue_short;
824 colors[i].alpha = gradient->stops[i].color.alpha_short;
827 /* RENDER does not support gradients with less than 2 stops. If a
828 * gradient has only a single stop, duplicate it to make RENDER
829 * happy. */
830 if (gradient->n_stops == 1) {
831 stops[1] = _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
833 colors[1].red = gradient->stops[0].color.red_short;
834 colors[1].green = gradient->stops[0].color.green_short;
835 colors[1].blue = gradient->stops[0].color.blue_short;
836 colors[1].alpha = gradient->stops[0].color.alpha_short;
839 return stops;
842 static cairo_xcb_picture_t *
843 _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
844 const cairo_linear_pattern_t *pattern,
845 const cairo_rectangle_int_t *extents)
847 char buf[CAIRO_STACK_BUFFER_SIZE];
848 xcb_render_fixed_t *stops;
849 xcb_render_color_t *colors;
850 xcb_render_pointfix_t p1, p2;
851 cairo_matrix_t matrix;
852 cairo_circle_double_t extremes[2];
853 cairo_xcb_picture_t *picture;
854 cairo_status_t status;
855 unsigned int n_stops;
857 _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
859 picture = (cairo_xcb_picture_t *)
860 _cairo_xcb_screen_lookup_linear_picture (target->screen, pattern);
861 if (picture != NULL)
862 goto setup_picture;
864 stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf));
865 if (unlikely (stops == NULL))
866 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
868 picture = _cairo_xcb_picture_create (target->screen,
869 target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
870 PIXMAN_a8r8g8b8,
871 -1, -1);
872 if (unlikely (picture->base.status)) {
873 if (stops != (xcb_render_fixed_t *) buf)
874 free (stops);
875 return picture;
877 picture->filter = CAIRO_FILTER_DEFAULT;
879 colors = (xcb_render_color_t *) (stops + n_stops);
881 p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
882 p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
883 p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
884 p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
886 _cairo_xcb_connection_render_create_linear_gradient (target->connection,
887 picture->picture,
888 p1, p2,
889 n_stops,
890 stops, colors);
892 if (stops != (xcb_render_fixed_t *) buf)
893 free (stops);
895 status = _cairo_xcb_screen_store_linear_picture (target->screen,
896 pattern,
897 &picture->base);
898 if (unlikely (status)) {
899 cairo_surface_destroy (&picture->base);
900 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
903 setup_picture:
904 _cairo_xcb_picture_set_matrix (picture, &matrix,
905 pattern->base.base.filter,
906 extents->x + extents->width/2.,
907 extents->y + extents->height/2.);
908 _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
909 _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
910 _cairo_xcb_picture_set_component_alpha (picture,
911 pattern->base.base.has_component_alpha);
913 return picture;
916 static cairo_xcb_picture_t *
917 _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
918 const cairo_radial_pattern_t *pattern,
919 const cairo_rectangle_int_t *extents)
921 char buf[CAIRO_STACK_BUFFER_SIZE];
922 xcb_render_fixed_t *stops;
923 xcb_render_color_t *colors;
924 xcb_render_pointfix_t p1, p2;
925 xcb_render_fixed_t r1, r2;
926 cairo_matrix_t matrix;
927 cairo_circle_double_t extremes[2];
928 cairo_xcb_picture_t *picture;
929 cairo_status_t status;
930 unsigned int n_stops;
932 _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
934 picture = (cairo_xcb_picture_t *)
935 _cairo_xcb_screen_lookup_radial_picture (target->screen, pattern);
936 if (picture != NULL)
937 goto setup_picture;
939 stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf));
940 if (unlikely (stops == NULL))
941 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
943 picture = _cairo_xcb_picture_create (target->screen,
944 target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
945 PIXMAN_a8r8g8b8,
946 -1, -1);
947 if (unlikely (picture->base.status)) {
948 if (stops != (xcb_render_fixed_t *) buf)
949 free (stops);
950 return picture;
952 picture->filter = CAIRO_FILTER_DEFAULT;
954 colors = (xcb_render_color_t *) (stops + n_stops);
956 p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
957 p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
958 p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
959 p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
961 r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
962 r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
964 _cairo_xcb_connection_render_create_radial_gradient (target->connection,
965 picture->picture,
966 p1, p2, r1, r2,
967 n_stops,
968 stops, colors);
970 if (stops != (xcb_render_fixed_t *) buf)
971 free (stops);
973 status = _cairo_xcb_screen_store_radial_picture (target->screen,
974 pattern,
975 &picture->base);
976 if (unlikely (status)) {
977 cairo_surface_destroy (&picture->base);
978 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
981 setup_picture:
982 _cairo_xcb_picture_set_matrix (picture, &matrix,
983 pattern->base.base.filter,
984 extents->x + extents->width/2.,
985 extents->y + extents->height/2.);
986 _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
987 _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
988 _cairo_xcb_picture_set_component_alpha (picture,
989 pattern->base.base.has_component_alpha);
991 return picture;
994 static cairo_xcb_picture_t *
995 _copy_to_picture (cairo_xcb_surface_t *source)
997 cairo_xcb_picture_t *picture;
998 uint32_t values[] = { 0, 1 };
1000 if (source->deferred_clear) {
1001 cairo_status_t status = _cairo_xcb_surface_clear (source);
1002 if (unlikely (status))
1003 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
1006 picture = _cairo_xcb_picture_create (source->screen,
1007 source->xrender_format,
1008 source->pixman_format,
1009 source->width,
1010 source->height);
1011 if (unlikely (picture->base.status))
1012 return picture;
1014 _cairo_xcb_connection_render_create_picture (source->connection,
1015 picture->picture,
1016 source->drawable,
1017 source->xrender_format,
1018 XCB_RENDER_CP_GRAPHICS_EXPOSURE |
1019 XCB_RENDER_CP_SUBWINDOW_MODE,
1020 values);
1022 return picture;
1025 static void
1026 _cairo_xcb_surface_setup_surface_picture(cairo_xcb_picture_t *picture,
1027 const cairo_surface_pattern_t *pattern,
1028 const cairo_rectangle_int_t *extents)
1030 cairo_filter_t filter;
1032 filter = pattern->base.filter;
1033 if (filter != CAIRO_FILTER_NEAREST &&
1034 _cairo_matrix_is_pixel_exact (&pattern->base.matrix))
1036 filter = CAIRO_FILTER_NEAREST;
1038 _cairo_xcb_picture_set_filter (picture, filter);
1040 _cairo_xcb_picture_set_matrix (picture,
1041 &pattern->base.matrix, filter,
1042 extents->x + extents->width/2.,
1043 extents->y + extents->height/2.);
1046 _cairo_xcb_picture_set_extend (picture, pattern->base.extend);
1047 _cairo_xcb_picture_set_component_alpha (picture, pattern->base.has_component_alpha);
1050 static cairo_xcb_picture_t *
1051 record_to_picture (cairo_surface_t *target,
1052 const cairo_surface_pattern_t *pattern,
1053 const cairo_rectangle_int_t *extents)
1055 cairo_surface_pattern_t tmp_pattern;
1056 cairo_xcb_picture_t *picture;
1057 cairo_status_t status;
1058 cairo_matrix_t matrix;
1059 cairo_surface_t *tmp;
1060 cairo_surface_t *source;
1061 cairo_rectangle_int_t limit;
1062 cairo_extend_t extend;
1064 /* XXX: The following was once more or less copied from cairo-xlibs-ource.c,
1065 * record_source() and recording_pattern_get_surface(), can we share a
1066 * single version?
1069 /* First get the 'real' recording surface and figure out the size for tmp */
1070 source = _cairo_pattern_get_source (pattern, &limit);
1071 assert (_cairo_surface_is_recording (source));
1073 if (! _cairo_matrix_is_identity (&pattern->base.matrix)) {
1074 double x1, y1, x2, y2;
1076 matrix = pattern->base.matrix;
1077 status = cairo_matrix_invert (&matrix);
1078 assert (status == CAIRO_STATUS_SUCCESS);
1080 x1 = limit.x;
1081 y1 = limit.y;
1082 x2 = limit.x + limit.width;
1083 y2 = limit.y + limit.height;
1085 _cairo_matrix_transform_bounding_box (&matrix,
1086 &x1, &y1, &x2, &y2, NULL);
1088 limit.x = floor (x1);
1089 limit.y = floor (y1);
1090 limit.width = ceil (x2) - limit.x;
1091 limit.height = ceil (y2) - limit.y;
1093 extend = pattern->base.extend;
1094 if (_cairo_rectangle_contains_rectangle (&limit, extents))
1095 extend = CAIRO_EXTEND_NONE;
1096 if (extend == CAIRO_EXTEND_NONE && ! _cairo_rectangle_intersect (&limit, extents))
1097 return _cairo_xcb_transparent_picture ((cairo_xcb_surface_t *) target);
1099 /* Now draw the recording surface to an xcb surface */
1100 tmp = _cairo_surface_create_scratch (target,
1101 source->content,
1102 limit.width,
1103 limit.height,
1104 CAIRO_COLOR_TRANSPARENT);
1105 if (tmp->status != CAIRO_STATUS_SUCCESS) {
1106 return (cairo_xcb_picture_t *) tmp;
1109 cairo_matrix_init_translate (&matrix, limit.x, limit.y);
1110 cairo_matrix_multiply (&matrix, &matrix, &pattern->base.matrix);
1112 status = _cairo_recording_surface_replay_with_clip (source,
1113 &matrix, tmp,
1114 NULL);
1115 if (unlikely (status)) {
1116 cairo_surface_destroy (tmp);
1117 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
1120 /* Now that we have drawn this to an xcb surface, try again with that */
1121 _cairo_pattern_init_static_copy (&tmp_pattern.base, &pattern->base);
1122 tmp_pattern.surface = tmp;
1123 cairo_matrix_init_translate (&tmp_pattern.base.matrix, -limit.x, -limit.y);
1125 picture = _copy_to_picture ((cairo_xcb_surface_t *) tmp);
1126 if (picture->base.status == CAIRO_STATUS_SUCCESS)
1127 _cairo_xcb_surface_setup_surface_picture (picture, &tmp_pattern, extents);
1128 cairo_surface_destroy (tmp);
1129 return picture;
1132 static cairo_xcb_picture_t *
1133 _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
1134 const cairo_surface_pattern_t *pattern,
1135 const cairo_rectangle_int_t *extents)
1137 cairo_surface_t *source = pattern->surface;
1138 cairo_xcb_picture_t *picture;
1140 picture = (cairo_xcb_picture_t *)
1141 _cairo_surface_has_snapshot (source, &_cairo_xcb_picture_backend);
1142 if (picture != NULL) {
1143 if (picture->screen == target->screen) {
1144 picture = (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
1145 _cairo_xcb_surface_setup_surface_picture (picture, pattern, extents);
1146 return picture;
1148 picture = NULL;
1151 if (source->type == CAIRO_SURFACE_TYPE_XCB)
1153 if (_cairo_surface_is_xcb(source)) {
1154 cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) source;
1155 if (xcb->screen == target->screen && xcb->fallback == NULL) {
1156 picture = _copy_to_picture ((cairo_xcb_surface_t *) source);
1157 if (unlikely (picture->base.status))
1158 return picture;
1160 } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1161 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
1162 cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) sub->target;
1164 /* XXX repeat interval with source clipping? */
1165 if (FALSE && xcb->screen == target->screen && xcb->fallback == NULL) {
1166 xcb_rectangle_t rect;
1168 picture = _copy_to_picture (xcb);
1169 if (unlikely (picture->base.status))
1170 return picture;
1172 rect.x = sub->extents.x;
1173 rect.y = sub->extents.y;
1174 rect.width = sub->extents.width;
1175 rect.height = sub->extents.height;
1177 _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
1178 picture->picture,
1179 0, 0,
1180 1, &rect);
1181 picture->x0 = rect.x;
1182 picture->y0 = rect.y;
1183 picture->width = rect.width;
1184 picture->height = rect.height;
1186 } else if (_cairo_surface_is_snapshot (source)) {
1187 cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
1188 cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) snap->target;
1190 if (xcb->screen == target->screen && xcb->fallback == NULL) {
1191 picture = _copy_to_picture (xcb);
1192 if (unlikely (picture->base.status))
1193 return picture;
1197 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1198 else if (source->type == CAIRO_SURFACE_TYPE_XLIB)
1200 if (source->backend->type == CAIRO_SURFACE_TYPE_XLIB) {
1201 cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) source)->xcb;
1202 if (xcb->screen == target->screen && xcb->fallback == NULL) {
1203 picture = _copy_to_picture (xcb);
1204 if (unlikely (picture->base.status))
1205 return picture;
1207 } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1208 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
1209 cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) sub->target)->xcb;
1211 if (FALSE && xcb->screen == target->screen && xcb->fallback == NULL) {
1212 xcb_rectangle_t rect;
1214 picture = _copy_to_picture (xcb);
1215 if (unlikely (picture->base.status))
1216 return picture;
1218 rect.x = sub->extents.x;
1219 rect.y = sub->extents.y;
1220 rect.width = sub->extents.width;
1221 rect.height = sub->extents.height;
1223 _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
1224 picture->picture,
1225 0, 0,
1226 1, &rect);
1227 picture->x0 = rect.x;
1228 picture->y0 = rect.y;
1229 picture->width = rect.width;
1230 picture->height = rect.height;
1232 } else if (_cairo_surface_is_snapshot (source)) {
1233 cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
1234 cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) snap->target)->xcb;
1236 if (xcb->screen == target->screen && xcb->fallback == NULL) {
1237 picture = _copy_to_picture (xcb);
1238 if (unlikely (picture->base.status))
1239 return picture;
1243 #endif
1244 #if CAIRO_HAS_GL_FUNCTIONS
1245 else if (source->type == CAIRO_SURFACE_TYPE_GL)
1247 /* pixmap from texture */
1249 #endif
1250 else if (source->type == CAIRO_SURFACE_TYPE_RECORDING)
1252 /* We have to skip the call to attach_snapshot() because we possibly
1253 * only drew part of the recording surface.
1254 * TODO: When can we safely attach a snapshot?
1256 return record_to_picture(&target->base, pattern, extents);
1259 if (picture == NULL) {
1260 cairo_image_surface_t *image;
1261 void *image_extra;
1262 cairo_status_t status;
1264 status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
1265 if (unlikely (status))
1266 return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
1268 if (image->format != CAIRO_FORMAT_INVALID) {
1269 xcb_render_pictformat_t format;
1271 format = target->screen->connection->standard_formats[image->format];
1273 picture = _picture_from_image (target, format, image, NULL);
1274 _cairo_surface_release_source_image (source, image, image_extra);
1275 } else {
1276 cairo_image_surface_t *conv;
1277 xcb_render_pictformat_t render_format;
1279 /* XXX XRenderPutImage! */
1281 conv = _cairo_image_surface_coerce (image);
1282 _cairo_surface_release_source_image (source, image, image_extra);
1283 if (unlikely (conv->base.status))
1284 return (cairo_xcb_picture_t *) conv;
1286 render_format = target->screen->connection->standard_formats[conv->format];
1287 picture = _picture_from_image (target, render_format, conv, NULL);
1288 cairo_surface_destroy (&conv->base);
1291 if (unlikely (picture->base.status))
1292 return picture;
1295 /* XXX: This causes too many problems and bugs, let's skip it for now. */
1296 #if 0
1297 _cairo_surface_attach_snapshot (source,
1298 &picture->base,
1299 NULL);
1300 #endif
1302 _cairo_xcb_surface_setup_surface_picture (picture, pattern, extents);
1303 return picture;
1306 static cairo_xcb_picture_t *
1307 _cairo_xcb_picture_for_pattern (cairo_xcb_surface_t *target,
1308 const cairo_pattern_t *pattern,
1309 const cairo_rectangle_int_t *extents)
1311 if (pattern == NULL)
1312 return _cairo_xcb_white_picture (target);
1314 if (! _pattern_is_supported (target->connection->flags, pattern))
1315 return _render_to_picture (target, pattern, extents);
1317 switch (pattern->type) {
1318 case CAIRO_PATTERN_TYPE_SOLID:
1319 return _cairo_xcb_solid_picture (target, (cairo_solid_pattern_t *) pattern);
1321 case CAIRO_PATTERN_TYPE_LINEAR:
1322 return _cairo_xcb_linear_picture (target,
1323 (cairo_linear_pattern_t *) pattern,
1324 extents);
1326 case CAIRO_PATTERN_TYPE_RADIAL:
1327 return _cairo_xcb_radial_picture (target,
1328 (cairo_radial_pattern_t *) pattern,
1329 extents);
1331 case CAIRO_PATTERN_TYPE_SURFACE:
1332 return _cairo_xcb_surface_picture (target,
1333 (cairo_surface_pattern_t *) pattern,
1334 extents);
1335 default:
1336 ASSERT_NOT_REACHED;
1337 case CAIRO_PATTERN_TYPE_MESH:
1338 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1339 return _render_to_picture (target, pattern, extents);
1343 COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t) <= sizeof (cairo_box_t));
1345 static cairo_status_t
1346 _render_fill_boxes (void *abstract_dst,
1347 cairo_operator_t op,
1348 const cairo_color_t *color,
1349 cairo_boxes_t *boxes)
1351 cairo_xcb_surface_t *dst = abstract_dst;
1352 xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
1353 xcb_rectangle_t *xrects = stack_xrects;
1354 xcb_render_color_t render_color;
1355 int render_op = _render_operator (op);
1356 struct _cairo_boxes_chunk *chunk;
1357 int max_count;
1359 render_color.red = color->red_short;
1360 render_color.green = color->green_short;
1361 render_color.blue = color->blue_short;
1362 render_color.alpha = color->alpha_short;
1364 max_count = 0;
1365 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
1366 if (chunk->count > max_count)
1367 max_count = chunk->count;
1369 if (max_count > ARRAY_LENGTH (stack_xrects)) {
1370 xrects = _cairo_malloc_ab (max_count, sizeof (xcb_rectangle_t));
1371 if (unlikely (xrects == NULL))
1372 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1375 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
1376 int i, j;
1378 for (i = j = 0; i < chunk->count; i++) {
1379 int x1 = _cairo_fixed_integer_round_down (chunk->base[i].p1.x);
1380 int y1 = _cairo_fixed_integer_round_down (chunk->base[i].p1.y);
1381 int x2 = _cairo_fixed_integer_round_down (chunk->base[i].p2.x);
1382 int y2 = _cairo_fixed_integer_round_down (chunk->base[i].p2.y);
1384 if (x2 > x1 && y2 > y1) {
1385 xrects[j].x = x1;
1386 xrects[j].y = y1;
1387 xrects[j].width = x2 - x1;
1388 xrects[j].height = y2 - y1;
1389 j++;
1393 if (j) {
1394 _cairo_xcb_connection_render_fill_rectangles
1395 (dst->connection,
1396 render_op, dst->picture,
1397 render_color, j, xrects);
1401 if (xrects != stack_xrects)
1402 free (xrects);
1404 return CAIRO_STATUS_SUCCESS;
1407 /* pixel aligned, non-overlapping boxes */
1408 static cairo_int_status_t
1409 _render_composite_boxes (cairo_xcb_surface_t *dst,
1410 cairo_operator_t op,
1411 const cairo_pattern_t *src_pattern,
1412 const cairo_pattern_t *mask_pattern,
1413 const cairo_rectangle_int_t *extents,
1414 const cairo_boxes_t *boxes)
1416 cairo_xcb_picture_t *src, *mask;
1417 const struct _cairo_boxes_chunk *chunk;
1418 xcb_rectangle_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
1419 xcb_rectangle_t *clip_boxes;
1420 cairo_rectangle_int_t stack_extents;
1421 cairo_status_t status;
1422 int num_boxes;
1423 int render_op;
1425 render_op = _render_operator (op);
1427 if (src_pattern == NULL) {
1428 src_pattern = mask_pattern;
1429 mask_pattern = NULL;
1432 /* amalgamate into a single Composite call by setting a clip region */
1433 clip_boxes = stack_boxes;
1434 if (boxes->num_boxes > ARRAY_LENGTH (stack_boxes)) {
1435 clip_boxes = _cairo_malloc_ab (boxes->num_boxes, sizeof (xcb_rectangle_t));
1436 if (unlikely (clip_boxes == NULL))
1437 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1440 src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
1441 status = src->base.status;
1442 if (unlikely (status))
1443 goto cleanup_boxes;
1445 num_boxes = 0;
1446 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
1447 const cairo_box_t *box = chunk->base;
1448 int i;
1450 for (i = 0; i < chunk->count; i++) {
1451 int x = _cairo_fixed_integer_round_down (box[i].p1.x);
1452 int y = _cairo_fixed_integer_round_down (box[i].p1.y);
1453 int width = _cairo_fixed_integer_round_down (box[i].p2.x) - x;
1454 int height = _cairo_fixed_integer_round_down (box[i].p2.y) - y;
1456 if (width && height) {
1457 clip_boxes[num_boxes].x = x;
1458 clip_boxes[num_boxes].y = y;
1459 clip_boxes[num_boxes].width = width;
1460 clip_boxes[num_boxes].height = height;
1461 num_boxes++;
1466 if (num_boxes) {
1467 if (num_boxes > 1) {
1468 _cairo_xcb_connection_render_set_picture_clip_rectangles (dst->connection,
1469 dst->picture,
1470 0, 0,
1471 num_boxes,
1472 clip_boxes);
1473 } else {
1474 stack_extents.x = clip_boxes[0].x;
1475 stack_extents.y = clip_boxes[0].y;
1476 stack_extents.width = clip_boxes[0].width;
1477 stack_extents.height = clip_boxes[0].height;
1478 extents = &stack_extents;
1481 if (mask_pattern != NULL) {
1482 mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
1483 status = mask->base.status;
1484 if (unlikely (status))
1485 goto cleanup_clip;
1487 _cairo_xcb_connection_render_composite (dst->connection,
1488 render_op,
1489 src->picture,
1490 mask->picture,
1491 dst->picture,
1492 src->x + extents->x, src->y + extents->y,
1493 mask->x + extents->x, mask->y + extents->y,
1494 extents->x, extents->y,
1495 extents->width, extents->height);
1497 cairo_surface_destroy (&mask->base);
1498 } else {
1499 _cairo_xcb_connection_render_composite (dst->connection,
1500 render_op,
1501 src->picture,
1502 XCB_NONE,
1503 dst->picture,
1504 src->x + extents->x, src->y + extents->y,
1505 0, 0,
1506 extents->x, extents->y,
1507 extents->width, extents->height);
1510 cleanup_clip:
1512 if (num_boxes > 1)
1513 _cairo_xcb_surface_clear_clip_region (dst);
1516 cairo_surface_destroy (&src->base);
1518 cleanup_boxes:
1520 if (clip_boxes != stack_boxes)
1521 free (clip_boxes);
1523 return status;
1527 #define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
1528 #define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
1530 static cairo_bool_t
1531 _line_exceeds_16_16 (const cairo_line_t *line)
1533 return
1534 line->p1.x <= CAIRO_FIXED_16_16_MIN ||
1535 line->p1.x >= CAIRO_FIXED_16_16_MAX ||
1537 line->p2.x <= CAIRO_FIXED_16_16_MIN ||
1538 line->p2.x >= CAIRO_FIXED_16_16_MAX ||
1540 line->p1.y <= CAIRO_FIXED_16_16_MIN ||
1541 line->p1.y >= CAIRO_FIXED_16_16_MAX ||
1543 line->p2.y <= CAIRO_FIXED_16_16_MIN ||
1544 line->p2.y >= CAIRO_FIXED_16_16_MAX;
1547 static void
1548 _project_line_x_onto_16_16 (const cairo_line_t *line,
1549 cairo_fixed_t top,
1550 cairo_fixed_t bottom,
1551 xcb_render_linefix_t *out)
1553 cairo_point_double_t p1, p2;
1554 double m;
1556 p1.x = _cairo_fixed_to_double (line->p1.x);
1557 p1.y = _cairo_fixed_to_double (line->p1.y);
1559 p2.x = _cairo_fixed_to_double (line->p2.x);
1560 p2.y = _cairo_fixed_to_double (line->p2.y);
1562 m = (p2.x - p1.x) / (p2.y - p1.y);
1563 out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
1564 out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
1567 typedef struct {
1568 cairo_traps_t traps;
1569 cairo_antialias_t antialias;
1570 } composite_traps_info_t;
1572 COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t) <= sizeof (cairo_trapezoid_t));
1574 static cairo_int_status_t
1575 _composite_traps (void *closure,
1576 cairo_xcb_surface_t *dst,
1577 cairo_operator_t op,
1578 const cairo_pattern_t *pattern,
1579 int dst_x, int dst_y,
1580 const cairo_rectangle_int_t *extents,
1581 cairo_clip_t *clip)
1583 composite_traps_info_t *info = closure;
1584 const cairo_traps_t *traps = &info->traps;
1585 cairo_xcb_picture_t *src;
1586 cairo_format_t format;
1587 xcb_render_pictformat_t xrender_format;
1588 xcb_render_trapezoid_t *xtraps;
1589 int render_reference_x, render_reference_y;
1590 cairo_status_t status;
1591 int i;
1593 if (dst->deferred_clear) {
1594 status = _cairo_xcb_surface_clear (dst);
1595 if (unlikely (status))
1596 return status;
1599 src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
1600 if (unlikely (src->base.status))
1601 return src->base.status;
1603 if (info->antialias == CAIRO_ANTIALIAS_NONE)
1604 format = CAIRO_FORMAT_A1;
1605 else
1606 format = CAIRO_FORMAT_A8;
1607 xrender_format = dst->screen->connection->standard_formats[format];
1609 xtraps = (xcb_render_trapezoid_t *) traps->traps;
1610 for (i = 0; i < traps->num_traps; i++) {
1611 cairo_trapezoid_t t = traps->traps[i];
1613 /* top/bottom will be clamped to surface bounds */
1614 xtraps[i].top = _cairo_fixed_to_16_16 (t.top);
1615 xtraps[i].top -= dst_y << 16;
1616 xtraps[i].bottom = _cairo_fixed_to_16_16 (t.bottom);
1617 xtraps[i].bottom -= dst_y << 16;
1619 /* However, all the other coordinates will have been left untouched so
1620 * as not to introduce numerical error. Recompute them if they
1621 * exceed the 16.16 limits.
1623 if (unlikely (_line_exceeds_16_16 (&t.left))) {
1624 _project_line_x_onto_16_16 (&t.left,
1625 t.top,
1626 t.bottom,
1627 &xtraps[i].left);
1628 xtraps[i].left.p1.y = xtraps[i].top;
1629 xtraps[i].left.p2.y = xtraps[i].bottom;
1630 } else {
1631 xtraps[i].left.p1.x = _cairo_fixed_to_16_16 (t.left.p1.x);
1632 xtraps[i].left.p1.y = _cairo_fixed_to_16_16 (t.left.p1.y);
1633 xtraps[i].left.p2.x = _cairo_fixed_to_16_16 (t.left.p2.x);
1634 xtraps[i].left.p2.y = _cairo_fixed_to_16_16 (t.left.p2.y);
1636 xtraps[i].left.p1.x -= dst_x << 16;
1637 xtraps[i].left.p1.y -= dst_y << 16;
1638 xtraps[i].left.p2.x -= dst_x << 16;
1639 xtraps[i].left.p2.y -= dst_y << 16;
1641 if (unlikely (_line_exceeds_16_16 (&t.right))) {
1642 _project_line_x_onto_16_16 (&t.right,
1643 t.top,
1644 t.bottom,
1645 &xtraps[i].right);
1646 xtraps[i].right.p1.y = xtraps[i].top;
1647 xtraps[i].right.p2.y = xtraps[i].bottom;
1648 } else {
1649 xtraps[i].right.p1.x = _cairo_fixed_to_16_16 (t.right.p1.x);
1650 xtraps[i].right.p1.y = _cairo_fixed_to_16_16 (t.right.p1.y);
1651 xtraps[i].right.p2.x = _cairo_fixed_to_16_16 (t.right.p2.x);
1652 xtraps[i].right.p2.y = _cairo_fixed_to_16_16 (t.right.p2.y);
1654 xtraps[i].right.p1.x -= dst_x << 16;
1655 xtraps[i].right.p1.y -= dst_y << 16;
1656 xtraps[i].right.p2.x -= dst_x << 16;
1657 xtraps[i].right.p2.y -= dst_y << 16;
1660 if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
1661 render_reference_x = xtraps[0].left.p1.x >> 16;
1662 render_reference_y = xtraps[0].left.p1.y >> 16;
1663 } else {
1664 render_reference_x = xtraps[0].left.p2.x >> 16;
1665 render_reference_y = xtraps[0].left.p2.y >> 16;
1667 render_reference_x += src->x + dst_x;
1668 render_reference_y += src->y + dst_y;
1670 _cairo_xcb_surface_set_precision (dst, info->antialias);
1671 _cairo_xcb_connection_render_trapezoids (dst->connection,
1672 _render_operator (op),
1673 src->picture,
1674 dst->picture,
1675 xrender_format,
1676 render_reference_x,
1677 render_reference_y,
1678 traps->num_traps, xtraps);
1680 cairo_surface_destroy (&src->base);
1682 return CAIRO_STATUS_SUCCESS;
1685 /* low-level composite driver */
1687 static cairo_xcb_surface_t *
1688 get_clip_surface (const cairo_clip_t *clip,
1689 cairo_xcb_surface_t *target,
1690 int *tx, int *ty)
1692 cairo_surface_t *surface;
1693 cairo_status_t status;
1695 surface = _cairo_surface_create_scratch (&target->base,
1696 CAIRO_CONTENT_ALPHA,
1697 clip->extents.width,
1698 clip->extents.height,
1699 CAIRO_COLOR_WHITE);
1700 if (unlikely (surface->status))
1701 return (cairo_xcb_surface_t *) surface;
1703 assert (surface->backend == &_cairo_xcb_surface_backend);
1704 status = _cairo_clip_combine_with_surface (clip, surface,
1705 clip->extents.x, clip->extents.y);
1706 if (unlikely (status)) {
1707 cairo_surface_destroy (surface);
1708 surface = _cairo_surface_create_in_error (status);
1711 *tx = clip->extents.x;
1712 *ty = clip->extents.y;
1714 return (cairo_xcb_surface_t *) surface;
1717 typedef cairo_int_status_t
1718 (*xcb_draw_func_t) (void *closure,
1719 cairo_xcb_surface_t *dst,
1720 cairo_operator_t op,
1721 const cairo_pattern_t *src,
1722 int dst_x,
1723 int dst_y,
1724 const cairo_rectangle_int_t *extents,
1725 cairo_clip_t *clip);
1727 static void do_unaligned_row(void (*blt)(void *closure,
1728 int16_t x, int16_t y,
1729 int16_t w, int16_t h,
1730 uint16_t coverage),
1731 void *closure,
1732 const cairo_box_t *b,
1733 int tx, int y, int h,
1734 uint16_t coverage)
1736 int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
1737 int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
1738 if (x2 > x1) {
1739 if (! _cairo_fixed_is_integer (b->p1.x)) {
1740 blt(closure, x1, y, 1, h,
1741 coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
1742 x1++;
1745 if (x2 > x1)
1746 blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
1748 if (! _cairo_fixed_is_integer (b->p2.x))
1749 blt(closure, x2, y, 1, h,
1750 coverage * _cairo_fixed_fractional_part (b->p2.x));
1751 } else
1752 blt(closure, x1, y, 1, h,
1753 coverage * (b->p2.x - b->p1.x));
1756 static void do_unaligned_box(void (*blt)(void *closure,
1757 int16_t x, int16_t y,
1758 int16_t w, int16_t h,
1759 uint16_t coverage),
1760 void *closure,
1761 const cairo_box_t *b, int tx, int ty)
1763 int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
1764 int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
1765 if (y2 > y1) {
1766 if (! _cairo_fixed_is_integer (b->p1.y)) {
1767 do_unaligned_row(blt, closure, b, tx, y1, 1,
1768 256 - _cairo_fixed_fractional_part (b->p1.y));
1769 y1++;
1772 if (y2 > y1)
1773 do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
1775 if (! _cairo_fixed_is_integer (b->p2.y))
1776 do_unaligned_row(blt, closure, b, tx, y2, 1,
1777 _cairo_fixed_fractional_part (b->p2.y));
1778 } else
1779 do_unaligned_row(blt, closure, b, tx, y1, 1,
1780 b->p2.y - b->p1.y);
1784 static void blt_in(void *closure,
1785 int16_t x, int16_t y,
1786 int16_t w, int16_t h,
1787 uint16_t coverage)
1789 cairo_xcb_surface_t *mask = closure;
1790 xcb_render_color_t color;
1791 xcb_rectangle_t rect;
1793 if (coverage == 0xffff)
1794 return;
1796 color.red = color.green = color.blue = 0;
1797 color.alpha = coverage;
1799 rect.x = x;
1800 rect.y = y;
1801 rect.width = w;
1802 rect.height = h;
1804 _cairo_xcb_connection_render_fill_rectangles (mask->connection,
1805 XCB_RENDER_PICT_OP_IN,
1806 mask->picture,
1807 color, 1, &rect);
1810 static cairo_xcb_surface_t *
1811 _create_composite_mask (cairo_clip_t *clip,
1812 xcb_draw_func_t draw_func,
1813 xcb_draw_func_t mask_func,
1814 void *draw_closure,
1815 cairo_xcb_surface_t *dst,
1816 const cairo_rectangle_int_t*extents)
1818 cairo_xcb_surface_t *surface;
1819 cairo_bool_t need_clip_combine;
1820 cairo_int_status_t status;
1822 surface = (cairo_xcb_surface_t *)
1823 _cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA,
1824 extents->width, extents->height);
1825 if (unlikely (surface->base.status))
1826 return surface;
1828 _cairo_xcb_surface_ensure_picture (surface);
1830 surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
1831 surface->deferred_clear = TRUE;
1832 surface->base.is_clear = TRUE;
1834 if (mask_func) {
1835 status = mask_func (draw_closure, surface,
1836 CAIRO_OPERATOR_ADD, NULL,
1837 extents->x, extents->y,
1838 extents, clip);
1839 if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
1840 return surface;
1843 /* Is it worth setting the clip region here? */
1844 status = draw_func (draw_closure, surface,
1845 CAIRO_OPERATOR_ADD, NULL,
1846 extents->x, extents->y,
1847 extents, NULL);
1848 if (unlikely (status)) {
1849 cairo_surface_destroy (&surface->base);
1850 return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
1853 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
1854 int i;
1856 for (i = 0; i < clip->num_boxes; i++) {
1857 cairo_box_t *b = &clip->boxes[i];
1859 if (! _cairo_fixed_is_integer (b->p1.x) ||
1860 ! _cairo_fixed_is_integer (b->p1.y) ||
1861 ! _cairo_fixed_is_integer (b->p2.x) ||
1862 ! _cairo_fixed_is_integer (b->p2.y))
1864 do_unaligned_box(blt_in, surface, b, extents->x, extents->y);
1868 need_clip_combine = clip->path != NULL;
1869 } else
1870 need_clip_combine = ! _cairo_clip_is_region (clip);
1872 if (need_clip_combine) {
1873 status = _cairo_clip_combine_with_surface (clip, &surface->base,
1874 extents->x, extents->y);
1875 if (unlikely (status)) {
1876 cairo_surface_destroy (&surface->base);
1877 return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
1881 return surface;
1884 /* Handles compositing with a clip surface when the operator allows
1885 * us to combine the clip with the mask
1887 static cairo_status_t
1888 _clip_and_composite_with_mask (cairo_clip_t *clip,
1889 cairo_operator_t op,
1890 const cairo_pattern_t *pattern,
1891 xcb_draw_func_t draw_func,
1892 xcb_draw_func_t mask_func,
1893 void *draw_closure,
1894 cairo_xcb_surface_t *dst,
1895 const cairo_rectangle_int_t*extents)
1897 cairo_xcb_surface_t *mask;
1898 cairo_xcb_picture_t *src;
1900 mask = _create_composite_mask (clip,
1901 draw_func, mask_func, draw_closure,
1902 dst, extents);
1903 if (unlikely (mask->base.status))
1904 return mask->base.status;
1906 if (pattern != NULL || dst->base.content != CAIRO_CONTENT_ALPHA) {
1907 src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
1908 if (unlikely (src->base.status)) {
1909 cairo_surface_destroy (&mask->base);
1910 return src->base.status;
1913 _cairo_xcb_connection_render_composite (dst->connection,
1914 _render_operator (op),
1915 src->picture,
1916 mask->picture,
1917 dst->picture,
1918 extents->x + src->x, extents->y + src->y,
1919 0, 0,
1920 extents->x, extents->y,
1921 extents->width, extents->height);
1923 cairo_surface_destroy (&src->base);
1924 } else {
1925 _cairo_xcb_connection_render_composite (dst->connection,
1926 _render_operator (op),
1927 mask->picture,
1928 XCB_NONE,
1929 dst->picture,
1930 0, 0,
1931 0, 0,
1932 extents->x, extents->y,
1933 extents->width, extents->height);
1935 cairo_surface_destroy (&mask->base);
1937 return CAIRO_STATUS_SUCCESS;
1940 /* Handles compositing with a clip surface when we have to do the operation
1941 * in two pieces and combine them together.
1943 static cairo_status_t
1944 _clip_and_composite_combine (cairo_clip_t *clip,
1945 cairo_operator_t op,
1946 const cairo_pattern_t *pattern,
1947 xcb_draw_func_t draw_func,
1948 void *draw_closure,
1949 cairo_xcb_surface_t *dst,
1950 const cairo_rectangle_int_t*extents)
1952 cairo_xcb_surface_t *tmp;
1953 cairo_xcb_surface_t *clip_surface;
1954 int clip_x = 0, clip_y = 0;
1955 xcb_render_picture_t clip_picture;
1956 cairo_status_t status;
1958 tmp = (cairo_xcb_surface_t *)
1959 _cairo_xcb_surface_create_similar (dst, dst->base.content,
1960 extents->width, extents->height);
1961 if (unlikely (tmp->base.status))
1962 return tmp->base.status;
1964 /* create_similar() could have done a fallback to an image surface */
1965 assert (tmp->base.backend == &_cairo_xcb_surface_backend);
1967 _cairo_xcb_surface_ensure_picture (tmp);
1969 if (pattern == NULL) {
1970 status = (*draw_func) (draw_closure, tmp,
1971 CAIRO_OPERATOR_ADD, NULL,
1972 extents->x, extents->y,
1973 extents, NULL);
1974 } else {
1975 /* Initialize the temporary surface from the destination surface */
1976 if (! dst->base.is_clear ||
1977 (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) == 0)
1979 /* XCopyArea may actually be quicker here.
1980 * A good driver should translate if appropriate.
1982 _cairo_xcb_connection_render_composite (dst->connection,
1983 XCB_RENDER_PICT_OP_SRC,
1984 dst->picture,
1985 XCB_NONE,
1986 tmp->picture,
1987 extents->x, extents->y,
1988 0, 0,
1989 0, 0,
1990 extents->width, extents->height);
1992 else
1994 xcb_render_color_t clear;
1995 xcb_rectangle_t xrect;
1997 clear.red = clear.green = clear.blue = clear.alpha = 0;
1999 xrect.x = xrect.y = 0;
2000 xrect.width = extents->width;
2001 xrect.height = extents->height;
2003 _cairo_xcb_connection_render_fill_rectangles (dst->connection,
2004 XCB_RENDER_PICT_OP_CLEAR,
2005 dst->picture,
2006 clear, 1, &xrect);
2009 status = (*draw_func) (draw_closure, tmp, op, pattern,
2010 extents->x, extents->y,
2011 extents, NULL);
2013 if (unlikely (status))
2014 goto CLEANUP_SURFACE;
2016 clip_surface = get_clip_surface (clip, dst, &clip_x, &clip_y);
2017 status = clip_surface->base.status;
2018 if (unlikely (status))
2019 goto CLEANUP_SURFACE;
2021 assert (clip_surface->base.backend == &_cairo_xcb_surface_backend);
2022 clip_picture = clip_surface->picture;
2023 assert (clip_picture != XCB_NONE);
2025 if (dst->base.is_clear) {
2026 _cairo_xcb_connection_render_composite (dst->connection,
2027 XCB_RENDER_PICT_OP_SRC,
2028 tmp->picture, clip_picture, dst->picture,
2029 0, 0,
2030 0, 0,
2031 extents->x, extents->y,
2032 extents->width, extents->height);
2033 } else {
2034 /* Punch the clip out of the destination */
2035 _cairo_xcb_connection_render_composite (dst->connection,
2036 XCB_RENDER_PICT_OP_OUT_REVERSE,
2037 clip_picture, XCB_NONE, dst->picture,
2038 extents->x - clip_x,
2039 extents->y - clip_y,
2040 0, 0,
2041 extents->x, extents->y,
2042 extents->width, extents->height);
2044 /* Now add the two results together */
2045 _cairo_xcb_connection_render_composite (dst->connection,
2046 XCB_RENDER_PICT_OP_ADD,
2047 tmp->picture, clip_picture, dst->picture,
2048 0, 0,
2049 extents->x - clip_x,
2050 extents->y - clip_y,
2051 extents->x, extents->y,
2052 extents->width, extents->height);
2054 cairo_surface_destroy (&clip_surface->base);
2056 CLEANUP_SURFACE:
2057 cairo_surface_destroy (&tmp->base);
2059 return status;
2062 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
2063 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
2065 static cairo_status_t
2066 _clip_and_composite_source (cairo_clip_t *clip,
2067 const cairo_pattern_t *pattern,
2068 xcb_draw_func_t draw_func,
2069 xcb_draw_func_t mask_func,
2070 void *draw_closure,
2071 cairo_xcb_surface_t *dst,
2072 const cairo_rectangle_int_t *extents)
2074 cairo_xcb_surface_t *mask;
2075 cairo_xcb_picture_t *src;
2077 /* Create a surface that is mask IN clip */
2078 mask = _create_composite_mask (clip,
2079 draw_func, mask_func, draw_closure,
2080 dst, extents);
2081 if (unlikely (mask->base.status))
2082 return mask->base.status;
2084 src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
2085 if (unlikely (src->base.status)) {
2086 cairo_surface_destroy (&mask->base);
2087 return src->base.status;
2090 if (dst->base.is_clear) {
2091 _cairo_xcb_connection_render_composite (dst->connection,
2092 XCB_RENDER_PICT_OP_SRC,
2093 src->picture,
2094 mask->picture,
2095 dst->picture,
2096 extents->x + src->x, extents->y + src->y,
2097 0, 0,
2098 extents->x, extents->y,
2099 extents->width, extents->height);
2100 } else {
2101 /* Compute dest' = dest OUT (mask IN clip) */
2102 _cairo_xcb_connection_render_composite (dst->connection,
2103 XCB_RENDER_PICT_OP_OUT_REVERSE,
2104 mask->picture,
2105 XCB_NONE,
2106 dst->picture,
2107 0, 0, 0, 0,
2108 extents->x, extents->y,
2109 extents->width, extents->height);
2111 /* Now compute (src IN (mask IN clip)) ADD dest' */
2112 _cairo_xcb_connection_render_composite (dst->connection,
2113 XCB_RENDER_PICT_OP_ADD,
2114 src->picture,
2115 mask->picture,
2116 dst->picture,
2117 extents->x + src->x, extents->y + src->y,
2118 0, 0,
2119 extents->x, extents->y,
2120 extents->width, extents->height);
2123 cairo_surface_destroy (&src->base);
2124 cairo_surface_destroy (&mask->base);
2126 return CAIRO_STATUS_SUCCESS;
2129 static cairo_bool_t
2130 can_reduce_alpha_op (cairo_operator_t op)
2132 int iop = op;
2133 switch (iop) {
2134 case CAIRO_OPERATOR_OVER:
2135 case CAIRO_OPERATOR_SOURCE:
2136 case CAIRO_OPERATOR_ADD:
2137 return TRUE;
2138 default:
2139 return FALSE;
2143 static cairo_bool_t
2144 reduce_alpha_op (cairo_surface_t *dst,
2145 cairo_operator_t op,
2146 const cairo_pattern_t *pattern)
2148 return dst->is_clear &&
2149 dst->content == CAIRO_CONTENT_ALPHA &&
2150 _cairo_pattern_is_opaque_solid (pattern) &&
2151 can_reduce_alpha_op (op);
2154 static cairo_status_t
2155 _cairo_xcb_surface_fixup_unbounded (cairo_xcb_surface_t *dst,
2156 const cairo_composite_rectangles_t *rects)
2158 xcb_rectangle_t xrects[4];
2159 int n;
2161 if (rects->bounded.width == rects->unbounded.width &&
2162 rects->bounded.height == rects->unbounded.height)
2164 return CAIRO_STATUS_SUCCESS;
2167 n = 0;
2168 if (rects->bounded.width == 0 || rects->bounded.height == 0) {
2169 xrects[n].x = rects->unbounded.x;
2170 xrects[n].width = rects->unbounded.width;
2171 xrects[n].y = rects->unbounded.y;
2172 xrects[n].height = rects->unbounded.height;
2173 n++;
2174 } else {
2175 /* top */
2176 if (rects->bounded.y != rects->unbounded.y) {
2177 xrects[n].x = rects->unbounded.x;
2178 xrects[n].width = rects->unbounded.width;
2179 xrects[n].y = rects->unbounded.y;
2180 xrects[n].height = rects->bounded.y - rects->unbounded.y;
2181 n++;
2183 /* left */
2184 if (rects->bounded.x != rects->unbounded.x) {
2185 xrects[n].x = rects->unbounded.x;
2186 xrects[n].width = rects->bounded.x - rects->unbounded.x;
2187 xrects[n].y = rects->bounded.y;
2188 xrects[n].height = rects->bounded.height;
2189 n++;
2191 /* right */
2192 if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
2193 xrects[n].x = rects->bounded.x + rects->bounded.width;
2194 xrects[n].width = rects->unbounded.x + rects->unbounded.width - xrects[n].x;
2195 xrects[n].y = rects->bounded.y;
2196 xrects[n].height = rects->bounded.height;
2197 n++;
2199 /* bottom */
2200 if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
2201 xrects[n].x = rects->unbounded.x;
2202 xrects[n].width = rects->unbounded.width;
2203 xrects[n].y = rects->bounded.y + rects->bounded.height;
2204 xrects[n].height = rects->unbounded.y + rects->unbounded.height - xrects[n].y;
2205 n++;
2209 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
2210 xcb_render_color_t color;
2212 color.red = 0;
2213 color.green = 0;
2214 color.blue = 0;
2215 color.alpha = 0;
2217 _cairo_xcb_connection_render_fill_rectangles (dst->connection,
2218 XCB_RENDER_PICT_OP_CLEAR,
2219 dst->picture,
2220 color, n, xrects);
2221 } else {
2222 int i;
2223 cairo_xcb_picture_t *src;
2225 src = _cairo_xcb_transparent_picture (dst);
2226 if (unlikely (src->base.status))
2227 return src->base.status;
2229 for (i = 0; i < n; i++) {
2230 _cairo_xcb_connection_render_composite (dst->connection,
2231 XCB_RENDER_PICT_OP_CLEAR,
2232 src->picture, XCB_NONE, dst->picture,
2233 0, 0,
2234 0, 0,
2235 xrects[i].x, xrects[i].y,
2236 xrects[i].width, xrects[i].height);
2238 cairo_surface_destroy (&src->base);
2241 return CAIRO_STATUS_SUCCESS;
2244 static cairo_status_t
2245 _cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst,
2246 const cairo_composite_rectangles_t *rects,
2247 cairo_clip_t *clip)
2249 cairo_xcb_surface_t *mask;
2250 int mask_x = 0, mask_y = 0;
2252 mask = get_clip_surface (clip, dst, &mask_x, &mask_y);
2253 if (unlikely (mask->base.status))
2254 return mask->base.status;
2256 /* top */
2257 if (rects->bounded.y != rects->unbounded.y) {
2258 int x = rects->unbounded.x;
2259 int y = rects->unbounded.y;
2260 int width = rects->unbounded.width;
2261 int height = rects->bounded.y - y;
2263 _cairo_xcb_connection_render_composite (dst->connection,
2264 XCB_RENDER_PICT_OP_OUT_REVERSE,
2265 mask->picture, XCB_NONE, dst->picture,
2266 x - mask_x, y - mask_y,
2267 0, 0,
2268 x, y,
2269 width, height);
2272 /* left */
2273 if (rects->bounded.x != rects->unbounded.x) {
2274 int x = rects->unbounded.x;
2275 int y = rects->bounded.y;
2276 int width = rects->bounded.x - x;
2277 int height = rects->bounded.height;
2279 _cairo_xcb_connection_render_composite (dst->connection,
2280 XCB_RENDER_PICT_OP_OUT_REVERSE,
2281 mask->picture, XCB_NONE, dst->picture,
2282 x - mask_x, y - mask_y,
2283 0, 0,
2284 x, y,
2285 width, height);
2288 /* right */
2289 if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
2290 int x = rects->bounded.x + rects->bounded.width;
2291 int y = rects->bounded.y;
2292 int width = rects->unbounded.x + rects->unbounded.width - x;
2293 int height = rects->bounded.height;
2295 _cairo_xcb_connection_render_composite (dst->connection,
2296 XCB_RENDER_PICT_OP_OUT_REVERSE,
2297 mask->picture, XCB_NONE, dst->picture,
2298 x - mask_x, y - mask_y,
2299 0, 0,
2300 x, y,
2301 width, height);
2304 /* bottom */
2305 if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
2306 int x = rects->unbounded.x;
2307 int y = rects->bounded.y + rects->bounded.height;
2308 int width = rects->unbounded.width;
2309 int height = rects->unbounded.y + rects->unbounded.height - y;
2311 _cairo_xcb_connection_render_composite (dst->connection,
2312 XCB_RENDER_PICT_OP_OUT_REVERSE,
2313 mask->picture, XCB_NONE, dst->picture,
2314 x - mask_x, y - mask_y,
2315 0, 0,
2316 x, y,
2317 width, height);
2320 cairo_surface_destroy (&mask->base);
2322 return CAIRO_STATUS_SUCCESS;
2325 static cairo_status_t
2326 _cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst,
2327 const cairo_composite_rectangles_t *extents,
2328 cairo_clip_t *clip,
2329 cairo_boxes_t *boxes)
2331 cairo_boxes_t clear;
2332 cairo_box_t box;
2333 cairo_status_t status;
2334 struct _cairo_boxes_chunk *chunk;
2335 int i;
2337 if (boxes->num_boxes <= 1 && clip == NULL)
2338 return _cairo_xcb_surface_fixup_unbounded (dst, extents);
2340 _cairo_boxes_init (&clear);
2342 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
2343 box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
2344 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
2345 box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
2347 if (clip == NULL) {
2348 cairo_boxes_t tmp;
2350 _cairo_boxes_init (&tmp);
2352 status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
2353 assert (status == CAIRO_STATUS_SUCCESS);
2355 tmp.chunks.next = &boxes->chunks;
2356 tmp.num_boxes += boxes->num_boxes;
2358 status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
2359 CAIRO_FILL_RULE_WINDING,
2360 &clear);
2362 tmp.chunks.next = NULL;
2363 } else {
2364 _cairo_boxes_init_with_clip (&clear, clip);
2366 status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
2367 assert (status == CAIRO_STATUS_SUCCESS);
2369 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2370 for (i = 0; i < chunk->count; i++) {
2371 status = _cairo_boxes_add (&clear,
2372 CAIRO_ANTIALIAS_DEFAULT,
2373 &chunk->base[i]);
2374 if (unlikely (status)) {
2375 _cairo_boxes_fini (&clear);
2376 return status;
2381 status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
2382 CAIRO_FILL_RULE_WINDING,
2383 &clear);
2386 if (likely (status == CAIRO_STATUS_SUCCESS)) {
2387 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES)
2388 status = _render_fill_boxes (dst,
2389 CAIRO_OPERATOR_CLEAR,
2390 CAIRO_COLOR_TRANSPARENT,
2391 &clear);
2392 else
2393 status = _cairo_xcb_surface_core_fill_boxes (dst,
2394 CAIRO_COLOR_TRANSPARENT,
2395 &clear);
2398 _cairo_boxes_fini (&clear);
2400 return status;
2403 cairo_status_t
2404 _cairo_xcb_surface_clear (cairo_xcb_surface_t *dst)
2406 xcb_gcontext_t gc;
2407 xcb_rectangle_t rect;
2408 cairo_status_t status;
2410 status = _cairo_xcb_connection_acquire (dst->connection);
2411 if (unlikely (status))
2412 return status;
2414 rect.x = rect.y = 0;
2415 rect.width = dst->width;
2416 rect.height = dst->height;
2418 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
2419 xcb_render_color_t color;
2420 uint8_t op;
2422 color.red = dst->deferred_clear_color.red_short;
2423 color.green = dst->deferred_clear_color.green_short;
2424 color.blue = dst->deferred_clear_color.blue_short;
2425 color.alpha = dst->deferred_clear_color.alpha_short;
2427 if (color.alpha == 0)
2428 op = XCB_RENDER_PICT_OP_CLEAR;
2429 else
2430 op = XCB_RENDER_PICT_OP_SRC;
2432 _cairo_xcb_surface_ensure_picture (dst);
2433 _cairo_xcb_connection_render_fill_rectangles (dst->connection,
2434 op, dst->picture, color,
2435 1, &rect);
2436 } else {
2437 gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
2439 /* XXX color */
2440 _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
2441 dst->drawable, gc,
2442 1, &rect);
2444 _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
2447 _cairo_xcb_connection_release (dst->connection);
2449 dst->deferred_clear = FALSE;
2450 return CAIRO_STATUS_SUCCESS;
2453 enum {
2454 NEED_CLIP_REGION = 0x1,
2455 NEED_CLIP_SURFACE = 0x2,
2456 FORCE_CLIP_REGION = 0x4,
2459 static cairo_bool_t
2460 need_bounded_clip (cairo_composite_rectangles_t *extents)
2462 unsigned int flags = NEED_CLIP_REGION;
2463 if (! _cairo_clip_is_region (extents->clip))
2464 flags |= NEED_CLIP_SURFACE;
2465 return flags;
2468 static cairo_bool_t
2469 need_unbounded_clip (cairo_composite_rectangles_t *extents)
2471 unsigned int flags = 0;
2472 if (! extents->is_bounded) {
2473 flags |= NEED_CLIP_REGION;
2474 if (! _cairo_clip_is_region (extents->clip))
2475 flags |= NEED_CLIP_SURFACE;
2477 if (extents->clip->path != NULL)
2478 flags |= NEED_CLIP_SURFACE;
2479 return flags;
2482 static cairo_status_t
2483 _clip_and_composite (cairo_xcb_surface_t *dst,
2484 cairo_operator_t op,
2485 const cairo_pattern_t *src,
2486 xcb_draw_func_t draw_func,
2487 xcb_draw_func_t mask_func,
2488 void *draw_closure,
2489 cairo_composite_rectangles_t*extents,
2490 unsigned int need_clip)
2492 cairo_region_t *clip_region = NULL;
2493 cairo_status_t status;
2495 status = _cairo_xcb_connection_acquire (dst->connection);
2496 if (unlikely (status))
2497 return status;
2499 if (dst->deferred_clear) {
2500 status = _cairo_xcb_surface_clear (dst);
2501 if (unlikely (status)) {
2502 _cairo_xcb_connection_release (dst->connection);
2503 return status;
2507 _cairo_xcb_surface_ensure_picture (dst);
2509 if (need_clip & NEED_CLIP_REGION) {
2510 clip_region = _cairo_clip_get_region (extents->clip);
2511 if ((need_clip & FORCE_CLIP_REGION) == 0 && clip_region != NULL &&
2512 cairo_region_contains_rectangle (clip_region,
2513 &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
2514 clip_region = NULL;
2515 if (clip_region != NULL) {
2516 status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
2517 if (unlikely (status)) {
2518 _cairo_xcb_connection_release (dst->connection);
2519 return status;
2524 if (reduce_alpha_op (&dst->base, op, src)) {
2525 op = CAIRO_OPERATOR_ADD;
2526 src = NULL;
2529 if (extents->bounded.width != 0 && extents->bounded.height != 0) {
2530 if (op == CAIRO_OPERATOR_SOURCE) {
2531 status = _clip_and_composite_source (extents->clip, src,
2532 draw_func, mask_func, draw_closure,
2533 dst, &extents->bounded);
2534 } else {
2535 if (op == CAIRO_OPERATOR_CLEAR) {
2536 op = CAIRO_OPERATOR_DEST_OUT;
2537 src = NULL;
2540 if (need_clip & NEED_CLIP_SURFACE) {
2541 if (extents->is_bounded) {
2542 status = _clip_and_composite_with_mask (extents->clip, op, src,
2543 draw_func,
2544 mask_func,
2545 draw_closure,
2546 dst, &extents->bounded);
2547 } else {
2548 status = _clip_and_composite_combine (extents->clip, op, src,
2549 draw_func, draw_closure,
2550 dst, &extents->bounded);
2552 } else {
2553 status = draw_func (draw_closure,
2554 dst, op, src,
2555 0, 0,
2556 &extents->bounded,
2557 extents->clip);
2562 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
2563 if (need_clip & NEED_CLIP_SURFACE)
2564 status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, extents->clip);
2565 else
2566 status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
2569 if (clip_region)
2570 _cairo_xcb_surface_clear_clip_region (dst);
2572 _cairo_xcb_connection_release (dst->connection);
2574 return status;
2577 static cairo_status_t
2578 _core_boxes (cairo_xcb_surface_t *dst,
2579 cairo_operator_t op,
2580 const cairo_pattern_t *src,
2581 cairo_boxes_t *boxes,
2582 const cairo_composite_rectangles_t *extents)
2584 if (! boxes->is_pixel_aligned)
2585 return CAIRO_INT_STATUS_UNSUPPORTED;
2587 if (! _cairo_clip_is_region (extents->clip))
2588 return CAIRO_INT_STATUS_UNSUPPORTED;
2590 if (op == CAIRO_OPERATOR_CLEAR)
2591 return _cairo_xcb_surface_core_fill_boxes (dst, CAIRO_COLOR_TRANSPARENT, boxes);
2593 if (op == CAIRO_OPERATOR_OVER) {
2594 if (dst->base.is_clear || _cairo_pattern_is_opaque (src, &extents->bounded))
2595 op = CAIRO_OPERATOR_SOURCE;
2597 if (op != CAIRO_OPERATOR_SOURCE)
2598 return CAIRO_INT_STATUS_UNSUPPORTED;
2600 if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
2601 return _cairo_xcb_surface_core_fill_boxes (dst,
2602 &((cairo_solid_pattern_t *) src)->color,
2603 boxes);
2606 return _cairo_xcb_surface_core_copy_boxes (dst, src, &extents->bounded, boxes);
2609 static cairo_status_t
2610 _composite_boxes (cairo_xcb_surface_t *dst,
2611 cairo_operator_t op,
2612 const cairo_pattern_t *src,
2613 cairo_boxes_t *boxes,
2614 const cairo_composite_rectangles_t *extents)
2616 cairo_clip_t *clip = extents->clip;
2617 cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (clip);
2618 cairo_status_t status;
2620 /* If the boxes are not pixel-aligned, we will need to compute a real mask */
2621 if (! boxes->is_pixel_aligned)
2622 return CAIRO_INT_STATUS_UNSUPPORTED;
2624 if (need_clip_mask &&
2625 (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
2627 return CAIRO_INT_STATUS_UNSUPPORTED;
2630 status = _cairo_xcb_connection_acquire (dst->connection);
2631 if (unlikely (status))
2632 return status;
2634 _cairo_xcb_surface_ensure_picture (dst);
2635 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES && ! need_clip_mask &&
2636 (op == CAIRO_OPERATOR_CLEAR || src->type == CAIRO_PATTERN_TYPE_SOLID))
2638 const cairo_color_t *color;
2640 if (op == CAIRO_OPERATOR_CLEAR)
2641 color = CAIRO_COLOR_TRANSPARENT;
2642 else
2643 color = &((cairo_solid_pattern_t *) src)->color;
2645 status = _render_fill_boxes (dst, op, color, boxes);
2647 else
2649 cairo_surface_pattern_t mask;
2651 if (need_clip_mask) {
2652 cairo_xcb_surface_t *clip_surface;
2653 int clip_x = 0, clip_y = 0;
2655 clip_surface = get_clip_surface (extents->clip, dst,
2656 &clip_x, &clip_y);
2657 if (unlikely (clip_surface->base.status))
2658 return clip_surface->base.status;
2660 _cairo_pattern_init_for_surface (&mask, &clip_surface->base);
2661 mask.base.filter = CAIRO_FILTER_NEAREST;
2662 cairo_matrix_init_translate (&mask.base.matrix,
2663 -clip_x,
2664 -clip_y);
2665 cairo_surface_destroy (&clip_surface->base);
2667 if (op == CAIRO_OPERATOR_CLEAR) {
2668 src = NULL;
2669 op = CAIRO_OPERATOR_DEST_OUT;
2673 status = _render_composite_boxes (dst, op, src,
2674 need_clip_mask ? &mask.base : NULL,
2675 &extents->bounded, boxes);
2677 if (need_clip_mask)
2678 _cairo_pattern_fini (&mask.base);
2681 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
2682 status =
2683 _cairo_xcb_surface_fixup_unbounded_boxes (dst, extents,
2684 clip, boxes);
2687 _cairo_xcb_connection_release (dst->connection);
2689 return status;
2692 static cairo_bool_t
2693 cairo_boxes_for_each_box (cairo_boxes_t *boxes,
2694 cairo_bool_t (*func) (cairo_box_t *box,
2695 void *data),
2696 void *data)
2698 struct _cairo_boxes_chunk *chunk;
2699 int i;
2701 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2702 for (i = 0; i < chunk->count; i++)
2703 if (! func (&chunk->base[i], data))
2704 return FALSE;
2707 return TRUE;
2710 struct _image_contains_box {
2711 int width, height;
2712 int tx, ty;
2715 static cairo_bool_t image_contains_box (cairo_box_t *box, void *closure)
2717 struct _image_contains_box *data = closure;
2719 /* The box is pixel-aligned so the truncation is safe. */
2720 return
2721 _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
2722 _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
2723 _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
2724 _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
2727 struct _image_upload_box {
2728 cairo_xcb_surface_t *surface;
2729 cairo_image_surface_t *image;
2730 xcb_gcontext_t gc;
2731 int tx, ty;
2734 static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
2736 const struct _image_upload_box *iub = closure;
2737 /* The box is pixel-aligned so the truncation is safe. */
2738 int x = _cairo_fixed_integer_part (box->p1.x);
2739 int y = _cairo_fixed_integer_part (box->p1.y);
2740 int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
2741 int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
2742 int bpp = PIXMAN_FORMAT_BPP (iub->image->pixman_format);
2743 int len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp);
2744 if (len == iub->image->stride) {
2745 _cairo_xcb_connection_put_image (iub->surface->connection,
2746 iub->surface->drawable,
2747 iub->gc,
2748 width, height,
2749 x, y,
2750 iub->image->depth,
2751 iub->image->stride,
2752 iub->image->data +
2753 (y + iub->ty) * iub->image->stride +
2754 (x + iub->tx) * bpp/8);
2755 } else {
2756 _cairo_xcb_connection_put_subimage (iub->surface->connection,
2757 iub->surface->drawable,
2758 iub->gc,
2759 x + iub->tx,
2760 y + iub->ty,
2761 width, height,
2762 bpp / 8,
2763 iub->image->stride,
2764 x, y,
2765 iub->image->depth,
2766 iub->image->data);
2769 return TRUE;
2772 static cairo_status_t
2773 _upload_image_inplace (cairo_xcb_surface_t *surface,
2774 const cairo_pattern_t *source,
2775 cairo_boxes_t *boxes)
2777 const cairo_surface_pattern_t *pattern;
2778 struct _image_contains_box icb;
2779 struct _image_upload_box iub;
2780 cairo_image_surface_t *image;
2781 cairo_status_t status;
2782 int tx, ty;
2784 if (! boxes->is_pixel_aligned)
2785 return CAIRO_INT_STATUS_UNSUPPORTED;
2787 if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
2788 return CAIRO_INT_STATUS_UNSUPPORTED;
2790 pattern = (const cairo_surface_pattern_t *) source;
2791 if (! _cairo_surface_is_image (pattern->surface))
2792 return CAIRO_INT_STATUS_UNSUPPORTED;
2794 /* Have we already upload this image to a pixmap? */
2796 cairo_xcb_picture_t *snapshot;
2798 snapshot = (cairo_xcb_picture_t *)
2799 _cairo_surface_has_snapshot (pattern->surface, &_cairo_xcb_picture_backend);
2800 if (snapshot != NULL) {
2801 if (snapshot->screen == surface->screen)
2802 return CAIRO_INT_STATUS_UNSUPPORTED;
2806 image = (cairo_image_surface_t *) pattern->surface;
2807 if (image->format == CAIRO_FORMAT_INVALID)
2808 return CAIRO_INT_STATUS_UNSUPPORTED;
2810 if (image->depth != surface->depth)
2811 return CAIRO_INT_STATUS_UNSUPPORTED;
2813 if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
2814 return CAIRO_INT_STATUS_UNSUPPORTED;
2816 /* Check that the data is entirely within the image */
2817 icb.width = image->width;
2818 icb.height = image->height;
2819 icb.tx = tx;
2820 icb.ty = ty;
2821 if (! cairo_boxes_for_each_box (boxes, image_contains_box, &icb))
2822 return CAIRO_INT_STATUS_UNSUPPORTED;
2824 if (surface->deferred_clear) {
2825 status = _cairo_xcb_surface_clear (surface);
2826 if (unlikely (status))
2827 return status;
2830 status = _cairo_xcb_connection_acquire (surface->connection);
2831 if (unlikely (status))
2832 return status;
2834 iub.surface = surface;
2835 iub.image = image;
2836 iub.gc = _cairo_xcb_screen_get_gc (surface->screen,
2837 surface->drawable,
2838 image->depth);
2839 iub.tx = tx;
2840 iub.ty = ty;
2841 cairo_boxes_for_each_box (boxes, image_upload_box, &iub);
2843 _cairo_xcb_screen_put_gc (surface->screen, image->depth, iub.gc);
2844 _cairo_xcb_connection_release (surface->connection);
2846 return CAIRO_STATUS_SUCCESS;
2849 static cairo_int_status_t
2850 trim_extents_to_traps (cairo_composite_rectangles_t *extents,
2851 cairo_traps_t *traps)
2853 cairo_box_t box;
2855 /* X trims the affected area to the extents of the trapezoids, so
2856 * we need to compensate when fixing up the unbounded area.
2858 _cairo_traps_extents (traps, &box);
2859 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
2862 static cairo_bool_t
2863 _mono_edge_is_vertical (const cairo_line_t *line)
2865 return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
2868 static cairo_bool_t
2869 _traps_are_pixel_aligned (cairo_traps_t *traps,
2870 cairo_antialias_t antialias)
2872 int i;
2874 if (antialias == CAIRO_ANTIALIAS_NONE) {
2875 for (i = 0; i < traps->num_traps; i++) {
2876 if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
2877 ! _mono_edge_is_vertical (&traps->traps[i].right))
2879 traps->maybe_region = FALSE;
2880 return FALSE;
2883 } else {
2884 for (i = 0; i < traps->num_traps; i++) {
2885 if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
2886 traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
2887 ! _cairo_fixed_is_integer (traps->traps[i].top) ||
2888 ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
2889 ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
2890 ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
2892 traps->maybe_region = FALSE;
2893 return FALSE;
2898 return TRUE;
2901 static void
2902 _boxes_for_traps (cairo_boxes_t *boxes,
2903 cairo_traps_t *traps,
2904 cairo_antialias_t antialias)
2906 int i, j;
2908 _cairo_boxes_init (boxes);
2910 boxes->chunks.base = (cairo_box_t *) traps->traps;
2911 boxes->chunks.size = traps->num_traps;
2913 if (antialias != CAIRO_ANTIALIAS_NONE) {
2914 for (i = j = 0; i < traps->num_traps; i++) {
2915 /* Note the traps and boxes alias so we need to take the local copies first. */
2916 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
2917 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
2918 cairo_fixed_t y1 = traps->traps[i].top;
2919 cairo_fixed_t y2 = traps->traps[i].bottom;
2921 if (x1 == x2 || y1 == y2)
2922 continue;
2924 boxes->chunks.base[j].p1.x = x1;
2925 boxes->chunks.base[j].p1.y = y1;
2926 boxes->chunks.base[j].p2.x = x2;
2927 boxes->chunks.base[j].p2.y = y2;
2928 j++;
2930 if (boxes->is_pixel_aligned) {
2931 boxes->is_pixel_aligned =
2932 _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
2933 _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
2936 } else {
2937 boxes->is_pixel_aligned = TRUE;
2939 for (i = j = 0; i < traps->num_traps; i++) {
2940 /* Note the traps and boxes alias so we need to take the local copies first. */
2941 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
2942 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
2943 cairo_fixed_t y1 = traps->traps[i].top;
2944 cairo_fixed_t y2 = traps->traps[i].bottom;
2946 /* round down here to match Pixman's behavior when using traps. */
2947 boxes->chunks.base[j].p1.x = _cairo_fixed_round_down (x1);
2948 boxes->chunks.base[j].p1.y = _cairo_fixed_round_down (y1);
2949 boxes->chunks.base[j].p2.x = _cairo_fixed_round_down (x2);
2950 boxes->chunks.base[j].p2.y = _cairo_fixed_round_down (y2);
2952 j += (boxes->chunks.base[j].p1.x != boxes->chunks.base[j].p2.x &&
2953 boxes->chunks.base[j].p1.y != boxes->chunks.base[j].p2.y);
2957 boxes->num_boxes = j;
2958 boxes->chunks.count = j;
2961 static cairo_status_t
2962 _composite_polygon (cairo_xcb_surface_t *dst,
2963 cairo_operator_t op,
2964 const cairo_pattern_t *source,
2965 cairo_polygon_t *polygon,
2966 cairo_antialias_t antialias,
2967 cairo_fill_rule_t fill_rule,
2968 cairo_composite_rectangles_t *extents)
2970 composite_traps_info_t traps;
2971 cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
2972 cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
2973 cairo_status_t status;
2975 if (polygon->num_edges == 0) {
2976 status = CAIRO_STATUS_SUCCESS;
2978 if (! extents->is_bounded) {
2979 if (cairo_region_contains_rectangle (clip_region, &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
2980 clip_region = NULL;
2982 if (clip_surface == FALSE) {
2983 if (clip_region != NULL) {
2984 status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
2985 if (unlikely (status))
2986 return status;
2989 status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
2991 if (clip_region != NULL)
2992 _cairo_xcb_surface_clear_clip_region (dst);
2993 } else {
2994 status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst,
2995 extents,
2996 extents->clip);
3000 return status;
3003 if (extents->clip->path != NULL && extents->is_bounded) {
3004 cairo_polygon_t clipper;
3005 cairo_fill_rule_t clipper_fill_rule;
3006 cairo_antialias_t clipper_antialias;
3008 status = _cairo_clip_get_polygon (extents->clip,
3009 &clipper,
3010 &clipper_fill_rule,
3011 &clipper_antialias);
3012 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3013 if (clipper_antialias == antialias) {
3014 status = _cairo_polygon_intersect (polygon, fill_rule,
3015 &clipper, clipper_fill_rule);
3016 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3017 cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
3018 _cairo_clip_destroy (extents->clip);
3019 extents->clip = clip;
3021 fill_rule = CAIRO_FILL_RULE_WINDING;
3023 _cairo_polygon_fini (&clipper);
3028 _cairo_traps_init (&traps.traps);
3030 status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
3031 if (unlikely (status))
3032 goto CLEANUP_TRAPS;
3034 if (traps.traps.has_intersections) {
3035 if (traps.traps.is_rectangular)
3036 status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
3037 else if (traps.traps.is_rectilinear)
3038 status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
3039 else
3040 status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
3041 if (unlikely (status))
3042 goto CLEANUP_TRAPS;
3045 /* Use a fast path if the trapezoids consist of a simple region,
3046 * but we can only do this if we do not have a clip surface, or can
3047 * substitute the mask with the clip.
3049 if (traps.traps.maybe_region &&
3050 _traps_are_pixel_aligned (&traps.traps, antialias) &&
3051 (! clip_surface ||
3052 (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
3054 cairo_boxes_t boxes;
3056 _boxes_for_traps (&boxes, &traps.traps, antialias);
3057 status = _clip_and_composite_boxes (dst, op, source, &boxes, extents);
3059 else
3061 /* Otherwise render the trapezoids to a mask and composite in the usual
3062 * fashion.
3064 traps.antialias = antialias;
3065 status = trim_extents_to_traps (extents, &traps.traps);
3066 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3067 unsigned int flags = 0;
3069 /* For unbounded operations, the X11 server will estimate the
3070 * affected rectangle and apply the operation to that. However,
3071 * there are cases where this is an overestimate (e.g. the
3072 * clip-fill-{eo,nz}-unbounded test).
3074 * The clip will trim that overestimate to our expectations.
3076 if (! extents->is_bounded)
3077 flags |= FORCE_CLIP_REGION;
3079 status = _clip_and_composite (dst, op, source, _composite_traps,
3080 NULL, &traps, extents,
3081 need_unbounded_clip (extents) | flags);
3085 CLEANUP_TRAPS:
3086 _cairo_traps_fini (&traps.traps);
3088 return status;
3091 static cairo_status_t
3092 _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
3093 cairo_operator_t op,
3094 const cairo_pattern_t *src,
3095 cairo_boxes_t *boxes,
3096 cairo_composite_rectangles_t *extents)
3098 composite_traps_info_t info;
3099 cairo_int_status_t status;
3101 if (boxes->num_boxes == 0 && extents->is_bounded)
3102 return CAIRO_STATUS_SUCCESS;
3104 if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
3105 (op == CAIRO_OPERATOR_SOURCE ||
3106 (dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))))
3108 if (boxes->num_boxes == 1 &&
3109 extents->bounded.width == dst->width &&
3110 extents->bounded.height == dst->height)
3112 op = CAIRO_OPERATOR_SOURCE;
3113 dst->deferred_clear = FALSE;
3116 status = _upload_image_inplace (dst, src, boxes);
3117 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3118 return status;
3121 /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
3122 if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS &&
3123 extents->clip->path != NULL && extents->is_bounded) {
3124 cairo_polygon_t polygon;
3125 cairo_fill_rule_t fill_rule;
3126 cairo_antialias_t antialias;
3127 cairo_clip_t *clip;
3129 clip = _cairo_clip_copy (extents->clip);
3130 clip = _cairo_clip_intersect_boxes (clip, boxes);
3131 if (_cairo_clip_is_all_clipped (clip))
3132 return CAIRO_INT_STATUS_NOTHING_TO_DO;
3134 status = _cairo_clip_get_polygon (clip, &polygon,
3135 &fill_rule, &antialias);
3136 _cairo_clip_path_destroy (clip->path);
3137 clip->path = NULL;
3138 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
3139 cairo_clip_t *saved_clip = extents->clip;
3140 extents->clip = clip;
3141 status = _composite_polygon (dst, op, src,
3142 &polygon,
3143 antialias,
3144 fill_rule,
3145 extents);
3146 if (extents->clip != clip)
3147 clip = NULL;
3148 extents->clip = saved_clip;
3149 _cairo_polygon_fini (&polygon);
3151 if (clip)
3152 _cairo_clip_destroy (clip);
3154 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3155 return status;
3158 if (dst->deferred_clear) {
3159 status = _cairo_xcb_surface_clear (dst);
3160 if (unlikely (status))
3161 return status;
3164 if (boxes->is_pixel_aligned &&
3165 _cairo_clip_is_region (extents->clip) &&
3166 op == CAIRO_OPERATOR_SOURCE) {
3167 status = _upload_image_inplace (dst, src, boxes);
3168 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3169 return status;
3172 if ((dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
3173 return _core_boxes (dst, op, src, boxes, extents);
3175 /* Use a fast path if the boxes are pixel aligned */
3176 status = _composite_boxes (dst, op, src, boxes, extents);
3177 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3178 return status;
3180 if ((dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0)
3181 return CAIRO_INT_STATUS_UNSUPPORTED;
3183 /* Otherwise render via a mask and composite in the usual fashion. */
3184 status = _cairo_traps_init_boxes (&info.traps, boxes);
3185 if (unlikely (status))
3186 return status;
3188 info.antialias = CAIRO_ANTIALIAS_DEFAULT;
3189 status = trim_extents_to_traps (extents, &info.traps);
3190 if (status == CAIRO_INT_STATUS_SUCCESS) {
3191 status = _clip_and_composite (dst, op, src,
3192 _composite_traps, NULL, &info,
3193 extents, need_unbounded_clip (extents));
3196 _cairo_traps_fini (&info.traps);
3197 return status;
3200 static cairo_int_status_t
3201 _composite_mask (void *closure,
3202 cairo_xcb_surface_t *dst,
3203 cairo_operator_t op,
3204 const cairo_pattern_t *src_pattern,
3205 int dst_x,
3206 int dst_y,
3207 const cairo_rectangle_int_t *extents,
3208 cairo_clip_t *clip)
3210 const cairo_pattern_t *mask_pattern = closure;
3211 cairo_xcb_picture_t *src, *mask = NULL;
3212 cairo_status_t status;
3214 if (dst->base.is_clear) {
3215 if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)
3216 op = CAIRO_OPERATOR_SOURCE;
3219 if (op == CAIRO_OPERATOR_SOURCE && clip == NULL)
3220 dst->deferred_clear = FALSE;
3222 if (dst->deferred_clear) {
3223 status = _cairo_xcb_surface_clear (dst);
3224 if (unlikely (status))
3225 return status;
3228 if (src_pattern != NULL) {
3229 src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
3230 if (unlikely (src->base.status))
3231 return src->base.status;
3233 mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
3234 if (unlikely (mask->base.status)) {
3235 cairo_surface_destroy (&src->base);
3236 return mask->base.status;
3239 _cairo_xcb_connection_render_composite (dst->connection,
3240 _render_operator (op),
3241 src->picture,
3242 mask->picture,
3243 dst->picture,
3244 extents->x + src->x, extents->y + src->y,
3245 extents->x + mask->x, extents->y + mask->y,
3246 extents->x - dst_x, extents->y - dst_y,
3247 extents->width, extents->height);
3248 cairo_surface_destroy (&mask->base);
3249 cairo_surface_destroy (&src->base);
3250 } else {
3251 src = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
3252 if (unlikely (src->base.status))
3253 return src->base.status;
3255 _cairo_xcb_connection_render_composite (dst->connection,
3256 _render_operator (op),
3257 src->picture,
3258 XCB_NONE,
3259 dst->picture,
3260 extents->x + src->x, extents->y + src->y,
3261 0, 0,
3262 extents->x - dst_x, extents->y - dst_y,
3263 extents->width, extents->height);
3264 cairo_surface_destroy (&src->base);
3267 return CAIRO_STATUS_SUCCESS;
3270 struct composite_box_info {
3271 cairo_xcb_surface_t *dst;
3272 cairo_xcb_picture_t *src;
3273 uint8_t op;
3276 static void composite_box(void *closure,
3277 int16_t x, int16_t y,
3278 int16_t w, int16_t h,
3279 uint16_t coverage)
3281 struct composite_box_info *info = closure;
3283 if (coverage < 0xff00) {
3284 cairo_xcb_picture_t *mask;
3285 cairo_color_t color;
3287 color.red_short = color.green_short = color.blue_short = 0;
3288 color.alpha_short = coverage;
3290 mask = _solid_picture (info->dst, &color);
3291 if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
3292 _cairo_xcb_connection_render_composite (info->dst->connection,
3293 info->op,
3294 info->src->picture,
3295 mask->picture,
3296 info->dst->picture,
3297 x + info->src->x, y + info->src->y,
3298 0, 0,
3299 x, y,
3300 w, h);
3302 cairo_surface_destroy (&mask->base);
3303 } else {
3304 _cairo_xcb_connection_render_composite (info->dst->connection,
3305 info->op,
3306 info->src->picture,
3307 XCB_NONE,
3308 info->dst->picture,
3309 x + info->src->x, y + info->src->y,
3310 0, 0,
3311 x, y,
3312 w, h);
3316 static cairo_int_status_t
3317 _composite_mask_clip_boxes (void *closure,
3318 cairo_xcb_surface_t *dst,
3319 cairo_operator_t op,
3320 const cairo_pattern_t *src_pattern,
3321 int dst_x,
3322 int dst_y,
3323 const cairo_rectangle_int_t *extents,
3324 cairo_clip_t *clip)
3326 struct composite_box_info info;
3327 cairo_status_t status;
3328 int i;
3330 assert (src_pattern == NULL);
3331 assert (op == CAIRO_OPERATOR_ADD);
3332 assert (dst->base.is_clear);
3334 if (clip->num_boxes > 1) {
3335 status = _cairo_xcb_surface_clear (dst);
3336 if (unlikely (status))
3337 return status;
3340 info.op = XCB_RENDER_PICT_OP_SRC;
3341 info.dst = dst;
3342 info.src = _cairo_xcb_picture_for_pattern (dst, closure, extents);
3343 if (unlikely (info.src->base.status))
3344 return info.src->base.status;
3346 info.src->x += dst_x;
3347 info.src->y += dst_y;
3349 for (i = 0; i < clip->num_boxes; i++)
3350 do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
3351 cairo_surface_destroy (&info.src->base);
3353 return CAIRO_STATUS_SUCCESS;
3356 static cairo_int_status_t
3357 _composite_mask_clip (void *closure,
3358 cairo_xcb_surface_t *dst,
3359 cairo_operator_t op,
3360 const cairo_pattern_t *src_pattern,
3361 int dst_x,
3362 int dst_y,
3363 const cairo_rectangle_int_t *extents,
3364 cairo_clip_t *clip)
3366 const cairo_pattern_t *mask_pattern = closure;
3367 cairo_polygon_t polygon;
3368 cairo_fill_rule_t fill_rule;
3369 composite_traps_info_t info;
3370 cairo_status_t status;
3372 assert (src_pattern == NULL);
3373 assert (op == CAIRO_OPERATOR_ADD);
3374 assert (dst->base.is_clear);
3376 status = _cairo_clip_get_polygon (clip, &polygon,
3377 &fill_rule, &info.antialias);
3378 if (unlikely (status))
3379 return status;
3381 _cairo_traps_init (&info.traps);
3382 status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
3383 &polygon,
3384 fill_rule);
3385 _cairo_polygon_fini (&polygon);
3386 if (unlikely (status))
3387 return status;
3389 if (info.traps.has_intersections) {
3390 if (info.traps.is_rectangular)
3391 status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
3392 else if (info.traps.is_rectilinear)
3393 status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
3394 else
3395 status = _cairo_bentley_ottmann_tessellate_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
3396 if (unlikely (status)) {
3397 _cairo_traps_fini (&info.traps);
3398 return status;
3402 dst->deferred_clear = FALSE; /* assert(trap extents == extents); */
3404 status = _composite_traps (&info,
3405 dst, CAIRO_OPERATOR_SOURCE, mask_pattern,
3406 dst_x, dst_y,
3407 extents, NULL);
3408 _cairo_traps_fini (&info.traps);
3410 return status;
3413 struct composite_opacity_info {
3414 uint8_t op;
3415 cairo_xcb_surface_t *dst;
3416 cairo_xcb_picture_t *src;
3417 double opacity;
3420 static void composite_opacity(void *closure,
3421 int16_t x, int16_t y,
3422 int16_t w, int16_t h,
3423 uint16_t coverage)
3425 struct composite_opacity_info *info = closure;
3426 cairo_xcb_picture_t *mask;
3427 cairo_color_t color;
3429 color.red_short = color.green_short = color.blue_short = 0;
3430 color.alpha_short = info->opacity * coverage;
3432 mask = _solid_picture (info->dst, &color);
3433 if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
3434 if (info->src) {
3435 _cairo_xcb_connection_render_composite (info->dst->connection,
3436 info->op,
3437 info->src->picture,
3438 mask->picture,
3439 info->dst->picture,
3440 x + info->src->x, y + info->src->y,
3441 0, 0,
3442 x, y,
3443 w, h);
3444 } else {
3445 _cairo_xcb_connection_render_composite (info->dst->connection,
3446 info->op,
3447 mask->picture,
3448 XCB_NONE,
3449 info->dst->picture,
3450 0, 0,
3451 0, 0,
3452 x, y,
3453 w, h);
3457 cairo_surface_destroy (&mask->base);
3460 static cairo_int_status_t
3461 _composite_opacity_boxes (void *closure,
3462 cairo_xcb_surface_t *dst,
3463 cairo_operator_t op,
3464 const cairo_pattern_t *src_pattern,
3465 int dst_x,
3466 int dst_y,
3467 const cairo_rectangle_int_t *extents,
3468 cairo_clip_t *clip)
3470 const cairo_solid_pattern_t *mask_pattern = closure;
3471 struct composite_opacity_info info;
3472 cairo_status_t status;
3473 int i;
3475 if (dst->base.is_clear) {
3476 if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)
3477 op = CAIRO_OPERATOR_SOURCE;
3480 if (op == CAIRO_OPERATOR_SOURCE &&
3481 (clip == NULL ||
3482 (clip->extents.width >= extents->width &&
3483 clip->extents.height >= extents->height)))
3484 dst->deferred_clear = FALSE;
3486 if (dst->deferred_clear) {
3487 status = _cairo_xcb_surface_clear (dst);
3488 if (unlikely (status))
3489 return status;
3492 info.op = _render_operator (op);
3493 info.dst = dst;
3495 if (src_pattern != NULL) {
3496 info.src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
3497 if (unlikely (info.src->base.status))
3498 return info.src->base.status;
3499 } else
3500 info.src = NULL;
3502 info.opacity = mask_pattern->color.alpha;
3504 /* XXX for lots of boxes create a clip region for the fully opaque areas */
3505 if (clip) {
3506 for (i = 0; i < clip->num_boxes; i++)
3507 do_unaligned_box(composite_opacity, &info,
3508 &clip->boxes[i], dst_x, dst_y);
3509 } else {
3510 composite_opacity(&info,
3511 extents->x - dst_x,
3512 extents->y - dst_y,
3513 extents->width,
3514 extents->height,
3515 0xffff);
3517 cairo_surface_destroy (&info.src->base);
3519 return CAIRO_STATUS_SUCCESS;
3522 /* high level rasteriser -> compositor */
3524 cairo_int_status_t
3525 _cairo_xcb_render_compositor_paint (const cairo_compositor_t *compositor,
3526 cairo_composite_rectangles_t *composite)
3528 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
3529 cairo_operator_t op = composite->op;
3530 cairo_pattern_t *source = &composite->source_pattern.base;
3531 cairo_boxes_t boxes;
3532 cairo_status_t status;
3534 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
3535 return CAIRO_INT_STATUS_UNSUPPORTED;
3537 if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
3538 CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
3540 return CAIRO_INT_STATUS_UNSUPPORTED;
3543 if (composite->clip == NULL &&
3544 source->type == CAIRO_PATTERN_TYPE_SOLID &&
3545 (op == CAIRO_OPERATOR_SOURCE ||
3546 op == CAIRO_OPERATOR_CLEAR ||
3547 (surface->base.is_clear &&
3548 (op == CAIRO_OPERATOR_ADD || op == CAIRO_OPERATOR_OVER))))
3550 surface->deferred_clear = TRUE;
3551 surface->deferred_clear_color = composite->source_pattern.solid.color;
3552 return CAIRO_STATUS_SUCCESS;
3555 _cairo_clip_steal_boxes(composite->clip, &boxes);
3556 status = _clip_and_composite_boxes (surface, op, source, &boxes, composite);
3557 _cairo_clip_unsteal_boxes (composite->clip, &boxes);
3559 return status;
3562 cairo_int_status_t
3563 _cairo_xcb_render_compositor_mask (const cairo_compositor_t *compositor,
3564 cairo_composite_rectangles_t *composite)
3566 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
3567 cairo_operator_t op = composite->op;
3568 cairo_pattern_t *source = &composite->source_pattern.base;
3569 cairo_pattern_t *mask = &composite->mask_pattern.base;
3570 cairo_status_t status;
3572 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
3573 return CAIRO_INT_STATUS_UNSUPPORTED;
3575 if ((surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
3576 return CAIRO_INT_STATUS_UNSUPPORTED;
3578 if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
3579 composite->clip->path == NULL &&
3580 ! _cairo_clip_is_region (composite->clip)) {
3581 status = _clip_and_composite (surface, op, source,
3582 _composite_opacity_boxes,
3583 _composite_opacity_boxes,
3584 (void *) mask,
3585 composite, need_unbounded_clip (composite));
3586 } else {
3587 xcb_draw_func_t mask_func = NULL;
3588 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)
3589 mask_func = composite->clip->path ? _composite_mask_clip : _composite_mask_clip_boxes;
3590 status = _clip_and_composite (surface, op, source,
3591 _composite_mask, mask_func,
3592 (void *) mask,
3593 composite, need_bounded_clip (composite));
3596 return status;
3599 static cairo_int_status_t
3600 _cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst,
3601 cairo_operator_t op,
3602 const cairo_pattern_t *source,
3603 const cairo_path_fixed_t *path,
3604 const cairo_stroke_style_t *stroke_style,
3605 const cairo_matrix_t *ctm,
3606 const cairo_matrix_t *ctm_inverse,
3607 double tolerance,
3608 cairo_antialias_t antialias,
3609 cairo_composite_rectangles_t *extents)
3611 cairo_polygon_t polygon;
3612 cairo_status_t status;
3614 _cairo_polygon_init_with_clip (&polygon, extents->clip);
3615 status = _cairo_path_fixed_stroke_to_polygon (path,
3616 stroke_style,
3617 ctm, ctm_inverse,
3618 tolerance,
3619 &polygon);
3620 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3621 status = _composite_polygon (dst, op, source,
3622 &polygon, antialias,
3623 CAIRO_FILL_RULE_WINDING,
3624 extents);
3626 _cairo_polygon_fini (&polygon);
3628 return status;
3631 static cairo_status_t
3632 _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
3633 cairo_operator_t op,
3634 const cairo_pattern_t *source,
3635 const cairo_path_fixed_t *path,
3636 const cairo_stroke_style_t *stroke_style,
3637 const cairo_matrix_t *ctm,
3638 const cairo_matrix_t *ctm_inverse,
3639 double tolerance,
3640 cairo_antialias_t antialias,
3641 cairo_composite_rectangles_t *extents)
3643 cairo_surface_t *image;
3644 cairo_status_t status;
3645 cairo_clip_t *clip;
3646 int x, y;
3648 x = extents->bounded.x;
3649 y = extents->bounded.y;
3650 image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_FORMAT_A8,
3651 extents->bounded.width,
3652 extents->bounded.height);
3653 if (unlikely (image->status))
3654 return image->status;
3656 clip = _cairo_clip_copy_region (extents->clip);
3657 status = _cairo_surface_offset_stroke (image, x, y,
3658 CAIRO_OPERATOR_ADD,
3659 &_cairo_pattern_white.base,
3660 path, stroke_style,
3661 ctm, ctm_inverse,
3662 tolerance, antialias,
3663 clip);
3664 _cairo_clip_destroy (clip);
3665 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3666 cairo_surface_pattern_t mask;
3668 _cairo_pattern_init_for_surface (&mask, image);
3669 mask.base.filter = CAIRO_FILTER_NEAREST;
3671 cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
3672 status = _clip_and_composite (dst, op, source,
3673 _composite_mask, NULL, &mask.base,
3674 extents, need_bounded_clip (extents));
3675 _cairo_pattern_fini (&mask.base);
3678 cairo_surface_finish (image);
3679 cairo_surface_destroy (image);
3681 return status;
3684 cairo_int_status_t
3685 _cairo_xcb_render_compositor_stroke (const cairo_compositor_t *compositor,
3686 cairo_composite_rectangles_t *composite,
3687 const cairo_path_fixed_t *path,
3688 const cairo_stroke_style_t *style,
3689 const cairo_matrix_t *ctm,
3690 const cairo_matrix_t *ctm_inverse,
3691 double tolerance,
3692 cairo_antialias_t antialias)
3694 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
3695 cairo_operator_t op = composite->op;
3696 cairo_pattern_t *source = &composite->source_pattern.base;
3697 cairo_int_status_t status;
3699 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
3700 return CAIRO_INT_STATUS_UNSUPPORTED;
3702 if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
3703 CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
3705 return CAIRO_INT_STATUS_UNSUPPORTED;
3708 status = CAIRO_INT_STATUS_UNSUPPORTED;
3709 if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
3710 cairo_boxes_t boxes;
3712 _cairo_boxes_init_with_clip (&boxes, composite->clip);
3713 status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
3714 style,
3715 ctm,
3716 antialias,
3717 &boxes);
3718 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
3719 status = _clip_and_composite_boxes (surface, op, source,
3720 &boxes, composite);
3722 _cairo_boxes_fini (&boxes);
3725 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
3726 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) {
3727 status = _cairo_xcb_surface_render_stroke_as_polygon (surface, op, source,
3728 path, style,
3729 ctm, ctm_inverse,
3730 tolerance, antialias,
3731 composite);
3732 } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
3733 status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source,
3734 path, style,
3735 ctm, ctm_inverse,
3736 tolerance, antialias,
3737 composite);
3738 } else {
3739 ASSERT_NOT_REACHED;
3743 return status;
3746 static cairo_status_t
3747 _cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t *dst,
3748 cairo_operator_t op,
3749 const cairo_pattern_t*source,
3750 const cairo_path_fixed_t *path,
3751 cairo_fill_rule_t fill_rule,
3752 double tolerance,
3753 cairo_antialias_t antialias,
3754 cairo_composite_rectangles_t *extents)
3756 cairo_polygon_t polygon;
3757 cairo_status_t status;
3759 _cairo_polygon_init_with_clip (&polygon, extents->clip);
3760 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
3761 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3762 status = _composite_polygon (dst, op, source,
3763 &polygon,
3764 antialias,
3765 fill_rule,
3766 extents);
3768 _cairo_polygon_fini (&polygon);
3770 return status;
3773 static cairo_status_t
3774 _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst,
3775 cairo_operator_t op,
3776 const cairo_pattern_t *source,
3777 const cairo_path_fixed_t *path,
3778 cairo_fill_rule_t fill_rule,
3779 double tolerance,
3780 cairo_antialias_t antialias,
3781 cairo_composite_rectangles_t *extents)
3783 cairo_surface_t *image;
3784 cairo_status_t status;
3785 cairo_clip_t *clip;
3786 int x, y;
3788 x = extents->bounded.x;
3789 y = extents->bounded.y;
3790 image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_FORMAT_A8,
3791 extents->bounded.width,
3792 extents->bounded.height);
3793 if (unlikely (image->status))
3794 return image->status;
3796 clip = _cairo_clip_copy_region (extents->clip);
3797 status = _cairo_surface_offset_fill (image, x, y,
3798 CAIRO_OPERATOR_ADD,
3799 &_cairo_pattern_white.base,
3800 path, fill_rule, tolerance, antialias,
3801 clip);
3802 _cairo_clip_destroy (clip);
3803 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3804 cairo_surface_pattern_t mask;
3806 _cairo_pattern_init_for_surface (&mask, image);
3807 mask.base.filter = CAIRO_FILTER_NEAREST;
3809 cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
3810 status = _clip_and_composite (dst, op, source,
3811 _composite_mask, NULL, &mask.base,
3812 extents, need_bounded_clip (extents));
3814 _cairo_pattern_fini (&mask.base);
3817 cairo_surface_finish (image);
3818 cairo_surface_destroy (image);
3820 return status;
3823 cairo_int_status_t
3824 _cairo_xcb_render_compositor_fill (const cairo_compositor_t *compositor,
3825 cairo_composite_rectangles_t *composite,
3826 const cairo_path_fixed_t *path,
3827 cairo_fill_rule_t fill_rule,
3828 double tolerance,
3829 cairo_antialias_t antialias)
3831 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
3832 cairo_operator_t op = composite->op;
3833 cairo_pattern_t *source = &composite->source_pattern.base;
3834 cairo_int_status_t status;
3836 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
3837 return CAIRO_INT_STATUS_UNSUPPORTED;
3839 if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
3840 CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
3842 return CAIRO_INT_STATUS_UNSUPPORTED;
3845 status = CAIRO_INT_STATUS_UNSUPPORTED;
3846 if (_cairo_path_fixed_fill_is_rectilinear (path)) {
3847 cairo_boxes_t boxes;
3849 _cairo_boxes_init_with_clip (&boxes, composite->clip);
3850 status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
3851 fill_rule,
3852 antialias,
3853 &boxes);
3854 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
3855 status = _clip_and_composite_boxes (surface, op, source,
3856 &boxes, composite);
3858 _cairo_boxes_fini (&boxes);
3861 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
3862 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) {
3863 status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path,
3864 fill_rule, tolerance, antialias,
3865 composite);
3866 } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
3867 status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path,
3868 fill_rule, tolerance, antialias,
3869 composite);
3870 } else {
3871 ASSERT_NOT_REACHED;
3875 return status;
3878 static cairo_status_t
3879 _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst,
3880 cairo_operator_t op,
3881 const cairo_pattern_t *source,
3882 cairo_scaled_font_t *scaled_font,
3883 cairo_glyph_t *glyphs,
3884 int num_glyphs,
3885 cairo_composite_rectangles_t *extents)
3887 cairo_surface_t *image;
3888 cairo_content_t content;
3889 cairo_status_t status;
3890 cairo_clip_t *clip;
3891 int x, y;
3893 content = CAIRO_CONTENT_ALPHA;
3894 if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
3895 content = CAIRO_CONTENT_COLOR_ALPHA;
3897 x = extents->bounded.x;
3898 y = extents->bounded.y;
3899 image = _cairo_xcb_surface_create_similar_image (dst,
3900 _cairo_format_from_content (content),
3901 extents->bounded.width,
3902 extents->bounded.height);
3903 if (unlikely (image->status))
3904 return image->status;
3906 clip = _cairo_clip_copy_region (extents->clip);
3907 status = _cairo_surface_offset_glyphs (image, x, y,
3908 CAIRO_OPERATOR_ADD,
3909 &_cairo_pattern_white.base,
3910 scaled_font, glyphs, num_glyphs,
3911 clip);
3912 _cairo_clip_destroy (clip);
3913 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3914 cairo_surface_pattern_t mask;
3916 _cairo_pattern_init_for_surface (&mask, image);
3917 mask.base.filter = CAIRO_FILTER_NEAREST;
3918 if (content & CAIRO_CONTENT_COLOR)
3919 mask.base.has_component_alpha = TRUE;
3921 cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
3922 status = _clip_and_composite (dst, op, source,
3923 _composite_mask, NULL, &mask.base,
3924 extents, need_bounded_clip (extents));
3926 _cairo_pattern_fini (&mask.base);
3929 cairo_surface_finish (image);
3930 cairo_surface_destroy (image);
3932 return status;
3935 /* Build a struct of the same size of #cairo_glyph_t that can be used both as
3936 * an input glyph with double coordinates, and as "working" glyph with
3937 * integer from-current-point offsets. */
3938 typedef union {
3939 cairo_glyph_t d;
3940 unsigned long index;
3941 struct {
3942 unsigned long index;
3943 int x;
3944 int y;
3945 } i;
3946 } cairo_xcb_glyph_t;
3948 /* compile-time assert that #cairo_xcb_glyph_t is the same size as #cairo_glyph_t */
3949 COMPILE_TIME_ASSERT (sizeof (cairo_xcb_glyph_t) == sizeof (cairo_glyph_t));
3951 typedef struct {
3952 cairo_scaled_font_t *font;
3953 cairo_xcb_glyph_t *glyphs;
3954 int num_glyphs;
3955 cairo_bool_t use_mask;
3956 } composite_glyphs_info_t;
3958 static cairo_status_t
3959 _can_composite_glyphs (cairo_xcb_surface_t *dst,
3960 cairo_rectangle_int_t *extents,
3961 cairo_scaled_font_t *scaled_font,
3962 cairo_glyph_t *glyphs,
3963 int *num_glyphs)
3965 #define GLYPH_CACHE_SIZE 64
3966 cairo_box_t bbox_cache[GLYPH_CACHE_SIZE];
3967 unsigned long glyph_cache[GLYPH_CACHE_SIZE];
3968 #undef GLYPH_CACHE_SIZE
3969 cairo_status_t status = CAIRO_STATUS_SUCCESS;
3970 cairo_glyph_t *glyphs_end, *valid_glyphs;
3971 const int max_glyph_size = dst->connection->maximum_request_length - 64;
3973 /* We must initialize the cache with values that cannot match the
3974 * "hash" to guarantee that when compared for the first time they
3975 * will result in a mismatch. The hash function is simply modulus,
3976 * so we cannot use 0 in glyph_cache[0], but we can use it in all
3977 * other array cells.
3979 memset (glyph_cache, 0, sizeof (glyph_cache));
3980 glyph_cache[0] = 1;
3982 /* Scan for oversized glyphs or glyphs outside the representable
3983 * range and fallback in that case, discard glyphs outside of the
3984 * image.
3986 valid_glyphs = glyphs;
3987 for (glyphs_end = glyphs + *num_glyphs; glyphs != glyphs_end; glyphs++) {
3988 double x1, y1, x2, y2;
3989 cairo_scaled_glyph_t *glyph;
3990 cairo_box_t *bbox;
3991 int width, height, len;
3992 int g;
3994 g = glyphs->index % ARRAY_LENGTH (glyph_cache);
3995 if (glyph_cache[g] != glyphs->index) {
3996 status = _cairo_scaled_glyph_lookup (scaled_font,
3997 glyphs->index,
3998 CAIRO_SCALED_GLYPH_INFO_METRICS,
3999 &glyph);
4000 if (unlikely (status))
4001 break;
4003 glyph_cache[g] = glyphs->index;
4004 bbox_cache[g] = glyph->bbox;
4006 bbox = &bbox_cache[g];
4008 /* Drop glyphs outside the clipping */
4009 x1 = _cairo_fixed_to_double (bbox->p1.x);
4010 y1 = _cairo_fixed_to_double (bbox->p1.y);
4011 y2 = _cairo_fixed_to_double (bbox->p2.y);
4012 x2 = _cairo_fixed_to_double (bbox->p2.x);
4013 if (unlikely (glyphs->x + x2 <= extents->x ||
4014 glyphs->y + y2 <= extents->y ||
4015 glyphs->x + x1 >= extents->x + extents->width ||
4016 glyphs->y + y1 >= extents->y + extents->height))
4018 (*num_glyphs)--;
4019 continue;
4022 /* XRenderAddGlyph does not handle a glyph surface larger than
4023 * the extended maximum XRequest size.
4025 width = _cairo_fixed_integer_ceil (bbox->p2.x - bbox->p1.x);
4026 height = _cairo_fixed_integer_ceil (bbox->p2.y - bbox->p1.y);
4027 len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, 32) * height;
4028 if (unlikely (len >= max_glyph_size)) {
4029 status = CAIRO_INT_STATUS_UNSUPPORTED;
4030 break;
4033 /* The glyph coordinates must be representable in an int16_t.
4034 * When possible, they will be expressed as an offset from the
4035 * previous glyph, otherwise they will be an offset from the
4036 * operation extents or from the surface origin. If the last
4037 * two options are not valid, fallback.
4039 if (unlikely (glyphs->x > INT16_MAX ||
4040 glyphs->y > INT16_MAX ||
4041 glyphs->x - extents->x < INT16_MIN ||
4042 glyphs->y - extents->y < INT16_MIN))
4044 status = CAIRO_INT_STATUS_UNSUPPORTED;
4045 break;
4049 if (unlikely (valid_glyphs != glyphs))
4050 *valid_glyphs = *glyphs;
4051 valid_glyphs++;
4054 if (unlikely (valid_glyphs != glyphs)) {
4055 for (; glyphs != glyphs_end; glyphs++) {
4056 *valid_glyphs = *glyphs;
4057 valid_glyphs++;
4061 return status;
4064 /* Start a new element for the first glyph,
4065 * or for any glyph that has unexpected position,
4066 * or if current element has too many glyphs
4067 * (Xrender limits each element to 252 glyphs, we limit them to 128)
4069 * These same conditions need to be mirrored between
4070 * _cairo_xcb_surface_emit_glyphs and _emit_glyph_chunks
4072 #define _start_new_glyph_elt(count, glyph) \
4073 (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
4075 /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
4076 * enough room for padding */
4077 typedef struct {
4078 uint8_t len;
4079 uint8_t pad1;
4080 uint16_t pad2;
4081 int16_t deltax;
4082 int16_t deltay;
4083 } x_glyph_elt_t;
4084 #define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4)
4086 static void
4087 _cairo_xcb_font_destroy (cairo_xcb_font_t *font)
4089 int i;
4091 for (i = 0; i < NUM_GLYPHSETS; i++) {
4092 cairo_xcb_font_glyphset_info_t *info;
4094 info = &font->glyphset_info[i];
4095 free (info->pending_free_glyphs);
4098 cairo_list_del (&font->base.link);
4099 cairo_list_del (&font->link);
4101 _cairo_xcb_connection_destroy (font->connection);
4103 free (font);
4106 static void
4107 _cairo_xcb_font_fini (cairo_scaled_font_private_t *abstract_private,
4108 cairo_scaled_font_t *scaled_font)
4110 cairo_xcb_font_t *font_private = (cairo_xcb_font_t *)abstract_private;
4111 cairo_xcb_connection_t *connection;
4112 cairo_bool_t have_connection;
4113 cairo_status_t status;
4114 int i;
4116 connection = font_private->connection;
4118 status = _cairo_xcb_connection_acquire (connection);
4119 have_connection = status == CAIRO_STATUS_SUCCESS;
4121 for (i = 0; i < NUM_GLYPHSETS; i++) {
4122 cairo_xcb_font_glyphset_info_t *info;
4124 info = &font_private->glyphset_info[i];
4125 if (info->glyphset && status == CAIRO_STATUS_SUCCESS) {
4126 _cairo_xcb_connection_render_free_glyph_set (connection,
4127 info->glyphset);
4131 if (have_connection)
4132 _cairo_xcb_connection_release (connection);
4134 _cairo_xcb_font_destroy (font_private);
4138 static cairo_xcb_font_t *
4139 _cairo_xcb_font_create (cairo_xcb_connection_t *connection,
4140 cairo_scaled_font_t *font)
4142 cairo_xcb_font_t *priv;
4143 int i;
4145 priv = malloc (sizeof (cairo_xcb_font_t));
4146 if (unlikely (priv == NULL))
4147 return NULL;
4149 _cairo_scaled_font_attach_private (font, &priv->base, connection,
4150 _cairo_xcb_font_fini);
4152 priv->scaled_font = font;
4153 priv->connection = _cairo_xcb_connection_reference (connection);
4154 cairo_list_add (&priv->link, &connection->fonts);
4156 for (i = 0; i < NUM_GLYPHSETS; i++) {
4157 cairo_xcb_font_glyphset_info_t *info = &priv->glyphset_info[i];
4158 switch (i) {
4159 case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
4160 case GLYPHSET_INDEX_A8: info->format = CAIRO_FORMAT_A8; break;
4161 case GLYPHSET_INDEX_A1: info->format = CAIRO_FORMAT_A1; break;
4162 default: ASSERT_NOT_REACHED; break;
4164 info->xrender_format = 0;
4165 info->glyphset = XCB_NONE;
4166 info->pending_free_glyphs = NULL;
4169 return priv;
4172 void
4173 _cairo_xcb_font_close (cairo_xcb_font_t *font)
4175 cairo_scaled_font_t *scaled_font;
4177 scaled_font = font->scaled_font;
4179 //scaled_font->surface_private = NULL;
4180 _cairo_scaled_font_reset_cache (scaled_font);
4182 _cairo_xcb_font_destroy (font);
4185 static void
4186 _cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection,
4187 cairo_xcb_font_glyphset_free_glyphs_t *to_free)
4189 _cairo_xcb_connection_render_free_glyphs (connection,
4190 to_free->glyphset,
4191 to_free->glyph_count,
4192 to_free->glyph_indices);
4195 static int
4196 _cairo_xcb_get_glyphset_index_for_format (cairo_format_t format)
4198 if (format == CAIRO_FORMAT_A8)
4199 return GLYPHSET_INDEX_A8;
4200 if (format == CAIRO_FORMAT_A1)
4201 return GLYPHSET_INDEX_A1;
4203 assert (format == CAIRO_FORMAT_ARGB32);
4204 return GLYPHSET_INDEX_ARGB32;
4209 static inline cairo_xcb_font_t *
4210 _cairo_xcb_font_get (const cairo_xcb_connection_t *c,
4211 cairo_scaled_font_t *font)
4213 return (cairo_xcb_font_t *)_cairo_scaled_font_find_private (font, c);
4217 static cairo_xcb_font_glyphset_info_t *
4218 _cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_xcb_connection_t *c,
4219 cairo_scaled_font_t *font,
4220 cairo_format_t format)
4222 cairo_xcb_font_t *priv;
4223 cairo_xcb_font_glyphset_info_t *info;
4224 int glyphset_index;
4226 glyphset_index = _cairo_xcb_get_glyphset_index_for_format (format);
4228 priv = _cairo_xcb_font_get (c, font);
4229 if (priv == NULL) {
4230 priv = _cairo_xcb_font_create (c, font);
4231 if (priv == NULL)
4232 return NULL;
4235 info = &priv->glyphset_info[glyphset_index];
4236 if (info->glyphset == XCB_NONE) {
4237 info->glyphset = _cairo_xcb_connection_get_xid (c);
4238 info->xrender_format = c->standard_formats[info->format];
4240 _cairo_xcb_connection_render_create_glyph_set (c,
4241 info->glyphset,
4242 info->xrender_format);
4245 return info;
4248 static cairo_bool_t
4249 _cairo_xcb_glyphset_info_has_pending_free_glyph (
4250 cairo_xcb_font_glyphset_info_t *info,
4251 unsigned long glyph_index)
4253 if (info->pending_free_glyphs != NULL) {
4254 cairo_xcb_font_glyphset_free_glyphs_t *to_free;
4255 int i;
4257 to_free = info->pending_free_glyphs;
4258 for (i = 0; i < to_free->glyph_count; i++) {
4259 if (to_free->glyph_indices[i] == glyph_index) {
4260 to_free->glyph_count--;
4261 memmove (&to_free->glyph_indices[i],
4262 &to_free->glyph_indices[i+1],
4263 (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
4264 return TRUE;
4269 return FALSE;
4272 typedef struct {
4273 cairo_scaled_glyph_private_t base;
4275 cairo_xcb_font_glyphset_info_t *glyphset;
4276 } cairo_xcb_glyph_private_t;
4278 static cairo_xcb_font_glyphset_info_t *
4279 _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (cairo_xcb_connection_t *c,
4280 cairo_scaled_font_t *font,
4281 unsigned long glyph_index,
4282 cairo_image_surface_t *surface)
4284 cairo_xcb_font_t *priv;
4285 int i;
4287 priv = _cairo_xcb_font_get (c, font);
4288 if (priv == NULL)
4289 return NULL;
4291 if (surface != NULL) {
4292 i = _cairo_xcb_get_glyphset_index_for_format (surface->format);
4294 if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
4295 &priv->glyphset_info[i],
4296 glyph_index))
4298 return &priv->glyphset_info[i];
4300 } else {
4301 for (i = 0; i < NUM_GLYPHSETS; i++) {
4302 if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
4303 &priv->glyphset_info[i],
4304 glyph_index))
4306 return &priv->glyphset_info[i];
4311 return NULL;
4314 static void
4315 _cairo_xcb_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
4316 cairo_scaled_glyph_t *glyph,
4317 cairo_scaled_font_t *font)
4319 cairo_xcb_glyph_private_t *priv = (cairo_xcb_glyph_private_t *)glyph_private;
4321 if (! font->finished) {
4322 cairo_xcb_font_glyphset_info_t *info = priv->glyphset;
4323 cairo_xcb_font_glyphset_free_glyphs_t *to_free;
4324 cairo_xcb_font_t *font_private;
4326 font_private = _cairo_xcb_font_get (glyph_private->key, font);
4327 assert (font_private);
4329 to_free = info->pending_free_glyphs;
4330 if (to_free != NULL &&
4331 to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
4333 _cairo_xcb_render_free_glyphs (font_private->connection, to_free);
4334 to_free = info->pending_free_glyphs = NULL;
4337 if (to_free == NULL) {
4338 to_free = malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t));
4339 if (unlikely (to_free == NULL)) {
4340 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
4341 return; /* XXX cannot propagate failure */
4344 to_free->glyphset = info->glyphset;
4345 to_free->glyph_count = 0;
4346 info->pending_free_glyphs = to_free;
4349 to_free->glyph_indices[to_free->glyph_count++] =
4350 _cairo_scaled_glyph_index (glyph);
4353 cairo_list_del (&glyph_private->link);
4354 free (glyph_private);
4358 static cairo_status_t
4359 _cairo_xcb_glyph_attach (cairo_xcb_connection_t *c,
4360 cairo_scaled_glyph_t *glyph,
4361 cairo_xcb_font_glyphset_info_t *info)
4363 cairo_xcb_glyph_private_t *priv;
4365 priv = malloc (sizeof (*priv));
4366 if (unlikely (priv == NULL))
4367 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4369 _cairo_scaled_glyph_attach_private (glyph, &priv->base, c,
4370 _cairo_xcb_glyph_fini);
4371 priv->glyphset = info;
4373 glyph->dev_private = info;
4374 glyph->dev_private_key = c;
4375 return CAIRO_STATUS_SUCCESS;
4378 static cairo_status_t
4379 _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
4380 cairo_scaled_font_t *font,
4381 cairo_scaled_glyph_t **scaled_glyph_out)
4383 xcb_render_glyphinfo_t glyph_info;
4384 uint32_t glyph_index;
4385 uint8_t *data;
4386 cairo_status_t status = CAIRO_STATUS_SUCCESS;
4387 cairo_scaled_glyph_t *scaled_glyph = *scaled_glyph_out;
4388 cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
4389 cairo_bool_t already_had_glyph_surface;
4390 cairo_xcb_font_glyphset_info_t *info;
4392 glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
4394 /* check to see if we have a pending XRenderFreeGlyph for this glyph */
4395 info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (connection, font, glyph_index, glyph_surface);
4396 if (info != NULL)
4397 return _cairo_xcb_glyph_attach (connection, scaled_glyph, info);
4399 if (glyph_surface == NULL) {
4400 status = _cairo_scaled_glyph_lookup (font,
4401 glyph_index,
4402 CAIRO_SCALED_GLYPH_INFO_METRICS |
4403 CAIRO_SCALED_GLYPH_INFO_SURFACE,
4404 scaled_glyph_out);
4405 if (unlikely (status))
4406 return status;
4408 scaled_glyph = *scaled_glyph_out;
4409 glyph_surface = scaled_glyph->surface;
4410 already_had_glyph_surface = FALSE;
4411 } else {
4412 already_had_glyph_surface = TRUE;
4415 info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (connection,
4416 font,
4417 glyph_surface->format);
4418 if (unlikely (info == NULL)) {
4419 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4420 goto BAIL;
4423 #if 0
4424 /* If the glyph surface has zero height or width, we create
4425 * a clear 1x1 surface, to avoid various X server bugs.
4427 if (glyph_surface->width == 0 || glyph_surface->height == 0) {
4428 cairo_surface_t *tmp_surface;
4430 tmp_surface = cairo_image_surface_create (info->format, 1, 1);
4431 status = tmp_surface->status;
4432 if (unlikely (status))
4433 goto BAIL;
4435 tmp_surface->device_transform = glyph_surface->base.device_transform;
4436 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
4438 glyph_surface = (cairo_image_surface_t *) tmp_surface;
4440 #endif
4442 /* If the glyph format does not match the font format, then we
4443 * create a temporary surface for the glyph image with the font's
4444 * format.
4446 if (glyph_surface->format != info->format) {
4447 glyph_surface = _cairo_image_surface_coerce_to_format (glyph_surface,
4448 info->format);
4449 status = glyph_surface->base.status;
4450 if (unlikely (status))
4451 goto BAIL;
4454 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
4455 glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
4456 glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
4457 glyph_info.width = glyph_surface->width;
4458 glyph_info.height = glyph_surface->height;
4459 glyph_info.x_off = scaled_glyph->x_advance;
4460 glyph_info.y_off = scaled_glyph->y_advance;
4462 data = glyph_surface->data;
4464 /* flip formats around */
4465 switch (_cairo_xcb_get_glyphset_index_for_format (scaled_glyph->surface->format)) {
4466 case GLYPHSET_INDEX_A1:
4467 /* local bitmaps are always stored with bit == byte */
4468 if (_cairo_is_little_endian() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
4469 int c = glyph_surface->stride * glyph_surface->height;
4470 const uint8_t *d;
4471 uint8_t *new, *n;
4473 if (c == 0)
4474 break;
4476 new = malloc (c);
4477 if (unlikely (new == NULL)) {
4478 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4479 goto BAIL;
4482 n = new;
4483 d = data;
4484 do {
4485 uint8_t b = *d++;
4486 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
4487 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
4488 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
4489 *n++ = b;
4490 } while (--c);
4491 data = new;
4493 break;
4495 case GLYPHSET_INDEX_A8:
4496 break;
4498 case GLYPHSET_INDEX_ARGB32:
4499 if (_cairo_is_little_endian() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
4500 unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
4501 const uint32_t *d;
4502 uint32_t *new, *n;
4504 if (c == 0)
4505 break;
4507 new = malloc (4 * c);
4508 if (unlikely (new == NULL)) {
4509 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4510 goto BAIL;
4513 n = new;
4514 d = (uint32_t *) data;
4515 do {
4516 *n++ = bswap_32 (*d);
4517 d++;
4518 } while (--c);
4519 data = (uint8_t *) new;
4521 break;
4523 default:
4524 ASSERT_NOT_REACHED;
4525 break;
4527 /* XXX assume X server wants pixman padding. Xft assumes this as well */
4529 _cairo_xcb_connection_render_add_glyphs (connection,
4530 info->glyphset,
4531 1, &glyph_index, &glyph_info,
4532 glyph_surface->stride * glyph_surface->height,
4533 data);
4535 if (data != glyph_surface->data)
4536 free (data);
4538 status = _cairo_xcb_glyph_attach (connection, scaled_glyph, info);
4540 BAIL:
4541 if (glyph_surface != scaled_glyph->surface)
4542 cairo_surface_destroy (&glyph_surface->base);
4544 /* If the scaled glyph didn't already have a surface attached
4545 * to it, release the created surface now that we have it
4546 * uploaded to the X server. If the surface has already been
4547 * there (e.g. because image backend requested it), leave it in
4548 * the cache
4550 if (! already_had_glyph_surface)
4551 _cairo_scaled_glyph_set_surface (scaled_glyph, font, NULL);
4553 return status;
4556 typedef void (*cairo_xcb_render_composite_text_func_t)
4557 (cairo_xcb_connection_t *connection,
4558 uint8_t op,
4559 xcb_render_picture_t src,
4560 xcb_render_picture_t dst,
4561 xcb_render_pictformat_t mask_format,
4562 xcb_render_glyphset_t glyphset,
4563 int16_t src_x,
4564 int16_t src_y,
4565 uint32_t len,
4566 uint8_t *cmd);
4569 static cairo_status_t
4570 _emit_glyphs_chunk (cairo_xcb_surface_t *dst,
4571 cairo_operator_t op,
4572 cairo_xcb_picture_t *src,
4573 /* info for this chunk */
4574 cairo_xcb_glyph_t *glyphs,
4575 int num_glyphs,
4576 int width,
4577 int estimated_req_size,
4578 cairo_xcb_font_glyphset_info_t *info,
4579 xcb_render_pictformat_t mask_format)
4581 cairo_xcb_render_composite_text_func_t composite_text_func;
4582 uint8_t stack_buf[CAIRO_STACK_BUFFER_SIZE];
4583 uint8_t *buf = stack_buf;
4584 x_glyph_elt_t *elt = NULL; /* silence compiler */
4585 uint32_t len;
4586 int i;
4588 if (estimated_req_size > ARRAY_LENGTH (stack_buf)) {
4589 buf = malloc (estimated_req_size);
4590 if (unlikely (buf == NULL))
4591 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4594 len = 0;
4595 for (i = 0; i < num_glyphs; i++) {
4596 if (_start_new_glyph_elt (i, &glyphs[i])) {
4597 if (len & 3)
4598 len += 4 - (len & 3);
4600 elt = (x_glyph_elt_t *) (buf + len);
4601 elt->len = 0;
4602 elt->deltax = glyphs[i].i.x;
4603 elt->deltay = glyphs[i].i.y;
4604 len += sizeof (x_glyph_elt_t);
4607 switch (width) {
4608 case 1: *(uint8_t *) (buf + len) = glyphs[i].index; break;
4609 case 2: *(uint16_t *) (buf + len) = glyphs[i].index; break;
4610 default:
4611 case 4: *(uint32_t *) (buf + len) = glyphs[i].index; break;
4613 len += width;
4614 elt->len++;
4616 if (len & 3)
4617 len += 4 - (len & 3);
4619 switch (width) {
4620 case 1:
4621 composite_text_func = _cairo_xcb_connection_render_composite_glyphs_8;
4622 break;
4623 case 2:
4624 composite_text_func = _cairo_xcb_connection_render_composite_glyphs_16;
4625 break;
4626 default:
4627 case 4:
4628 composite_text_func = _cairo_xcb_connection_render_composite_glyphs_32;
4629 break;
4631 composite_text_func (dst->connection,
4632 _render_operator (op),
4633 src->picture,
4634 dst->picture,
4635 mask_format,
4636 info->glyphset,
4637 src->x + glyphs[0].i.x,
4638 src->y + glyphs[0].i.y,
4639 len, buf);
4641 if (buf != stack_buf)
4642 free (buf);
4644 return CAIRO_STATUS_SUCCESS;
4647 static cairo_int_status_t
4648 _composite_glyphs (void *closure,
4649 cairo_xcb_surface_t *dst,
4650 cairo_operator_t op,
4651 const cairo_pattern_t *pattern,
4652 int dst_x,
4653 int dst_y,
4654 const cairo_rectangle_int_t *extents,
4655 cairo_clip_t *clip)
4657 composite_glyphs_info_t *info = closure;
4658 cairo_scaled_glyph_t *glyph_cache[64];
4659 cairo_status_t status = CAIRO_STATUS_SUCCESS;
4660 cairo_fixed_t x = 0, y = 0;
4661 cairo_xcb_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
4662 const unsigned int max_request_size = dst->connection->maximum_request_length - 64;
4663 cairo_xcb_picture_t *src;
4665 unsigned long max_index = 0;
4666 int width = 1;
4668 unsigned int request_size = 0;
4669 int i;
4671 if (dst->deferred_clear) {
4672 status = _cairo_xcb_surface_clear (dst);
4673 if (unlikely (status))
4674 return status;
4677 src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
4678 if (unlikely (src->base.status))
4679 return src->base.status;
4681 memset (glyph_cache, 0, sizeof (glyph_cache));
4683 for (i = 0; i < info->num_glyphs; i++) {
4684 cairo_scaled_glyph_t *glyph;
4685 unsigned long glyph_index = info->glyphs[i].index;
4686 int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
4687 int old_width = width;
4688 int this_x, this_y;
4690 glyph = glyph_cache[cache_index];
4691 if (glyph == NULL ||
4692 _cairo_scaled_glyph_index (glyph) != glyph_index)
4694 status = _cairo_scaled_glyph_lookup (info->font,
4695 glyph_index,
4696 CAIRO_SCALED_GLYPH_INFO_METRICS,
4697 &glyph);
4698 if (unlikely (status)) {
4699 cairo_surface_destroy (&src->base);
4700 return status;
4703 /* Send unseen glyphs to the server */
4704 if (glyph->dev_private_key != dst->connection) {
4705 status = _cairo_xcb_surface_add_glyph (dst->connection,
4706 info->font,
4707 &glyph);
4708 if (unlikely (status)) {
4709 cairo_surface_destroy (&src->base);
4710 return status;
4714 glyph_cache[cache_index] = glyph;
4717 this_x = _cairo_lround (info->glyphs[i].d.x) - dst_x;
4718 this_y = _cairo_lround (info->glyphs[i].d.y) - dst_y;
4720 this_glyphset_info = glyph->dev_private;
4721 if (glyphset_info == NULL)
4722 glyphset_info = this_glyphset_info;
4724 /* Update max glyph index */
4725 if (glyph_index > max_index) {
4726 max_index = glyph_index;
4727 if (max_index >= 65536)
4728 width = 4;
4729 else if (max_index >= 256)
4730 width = 2;
4731 if (width != old_width)
4732 request_size += (width - old_width) * i;
4735 /* If we will pass the max request size by adding this glyph,
4736 * flush current glyphs. Note that we account for a
4737 * possible element being added below.
4739 * Also flush if changing glyphsets, as Xrender limits one mask
4740 * format per request, so we can either break up, or use a
4741 * wide-enough mask format. We do the former. One reason to
4742 * prefer the latter is the fact that Xserver ADDs all glyphs
4743 * to the mask first, and then composes that to final surface,
4744 * though it's not a big deal.
4746 * If the glyph has a coordinate which cannot be represented
4747 * as a 16-bit offset from the previous glyph, flush the
4748 * current chunk. The current glyph will be the first one in
4749 * the next chunk, thus its coordinates will be an offset from
4750 * the destination origin. This offset is guaranteed to be
4751 * representable as 16-bit offset in _can_composite_glyphs().
4753 if (request_size + width > max_request_size - _cairo_sz_x_glyph_elt_t ||
4754 this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
4755 this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
4756 this_glyphset_info != glyphset_info)
4758 status = _emit_glyphs_chunk (dst, op, src,
4759 info->glyphs, i,
4760 old_width, request_size,
4761 glyphset_info,
4762 info->use_mask ? glyphset_info->xrender_format : 0);
4763 if (unlikely (status)) {
4764 cairo_surface_destroy (&src->base);
4765 return status;
4768 info->glyphs += i;
4769 info->num_glyphs -= i;
4770 i = 0;
4772 max_index = info->glyphs[0].index;
4773 width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
4775 request_size = 0;
4777 x = y = 0;
4778 glyphset_info = this_glyphset_info;
4781 /* Convert absolute glyph position to relative-to-current-point
4782 * position */
4783 info->glyphs[i].i.x = this_x - x;
4784 info->glyphs[i].i.y = this_y - y;
4786 /* Start a new element for the first glyph,
4787 * or for any glyph that has unexpected position,
4788 * or if current element has too many glyphs.
4790 * These same conditions are mirrored in _emit_glyphs_chunk().
4792 if (_start_new_glyph_elt (i, &info->glyphs[i]))
4793 request_size += _cairo_sz_x_glyph_elt_t;
4795 /* adjust current-position */
4796 x = this_x + glyph->x_advance;
4797 y = this_y + glyph->y_advance;
4799 request_size += width;
4802 if (i) {
4803 status = _emit_glyphs_chunk (dst, op, src,
4804 info->glyphs, i,
4805 width, request_size,
4806 glyphset_info,
4807 info->use_mask ? glyphset_info->xrender_format : 0);
4810 cairo_surface_destroy (&src->base);
4812 return status;
4815 cairo_int_status_t
4816 _cairo_xcb_render_compositor_glyphs (const cairo_compositor_t *compositor,
4817 cairo_composite_rectangles_t *composite,
4818 cairo_scaled_font_t *scaled_font,
4819 cairo_glyph_t *glyphs,
4820 int num_glyphs,
4821 cairo_bool_t overlap)
4823 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
4824 cairo_operator_t op = composite->op;
4825 cairo_pattern_t *source = &composite->source_pattern.base;
4826 cairo_int_status_t status;
4828 if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
4829 return CAIRO_INT_STATUS_UNSUPPORTED;
4831 if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
4832 return CAIRO_INT_STATUS_UNSUPPORTED;
4834 status = CAIRO_INT_STATUS_UNSUPPORTED;
4835 if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) {
4836 _cairo_scaled_font_freeze_cache (scaled_font);
4838 status = _can_composite_glyphs (surface, &composite->bounded,
4839 scaled_font, glyphs, &num_glyphs);
4840 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
4841 composite_glyphs_info_t info;
4842 unsigned flags = 0;
4844 info.font = scaled_font;
4845 info.glyphs = (cairo_xcb_glyph_t *) glyphs;
4846 info.num_glyphs = num_glyphs;
4847 info.use_mask =
4848 overlap ||
4849 ! composite->is_bounded ||
4850 ! _cairo_clip_is_region(composite->clip);
4852 if (composite->mask.width > composite->unbounded.width ||
4853 composite->mask.height > composite->unbounded.height)
4855 /* Glyphs are tricky since we do not directly control the
4856 * geometry and their inked extents depend on the
4857 * individual glyph-surface size. We must set a clip region
4858 * so that the X server can trim the glyphs appropriately.
4860 flags |= FORCE_CLIP_REGION;
4862 status = _clip_and_composite (surface, op, source,
4863 _composite_glyphs, NULL,
4864 &info, composite,
4865 need_bounded_clip (composite) |
4866 flags);
4869 _cairo_scaled_font_thaw_cache (scaled_font);
4872 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
4873 assert (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE);
4874 status =
4875 _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source,
4876 scaled_font, glyphs, num_glyphs,
4877 composite);
4880 return status;