summaryrefslogtreecommitdiff
path: root/libs/cairo-1.16.0/src/cairo-xcb-surface-render.c
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2023-02-12 23:53:22 -0600
committersanine <sanine.not@pm.me>2023-02-12 23:53:22 -0600
commitf1fe73d1909a2448a004a88362a1a532d0d4f7c3 (patch)
treeab37ae3837e2f858de2932bcee9f26e69fab3db1 /libs/cairo-1.16.0/src/cairo-xcb-surface-render.c
parentf567ea1e2798fd3156a416e61f083ea3e6b95719 (diff)
switch to tinyobj and nanovg from assimp and cairo
Diffstat (limited to 'libs/cairo-1.16.0/src/cairo-xcb-surface-render.c')
-rw-r--r--libs/cairo-1.16.0/src/cairo-xcb-surface-render.c4880
1 files changed, 0 insertions, 4880 deletions
diff --git a/libs/cairo-1.16.0/src/cairo-xcb-surface-render.c b/libs/cairo-1.16.0/src/cairo-xcb-surface-render.c
deleted file mode 100644
index 42f27c7..0000000
--- a/libs/cairo-1.16.0/src/cairo-xcb-surface-render.c
+++ /dev/null
@@ -1,4880 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Intel Corporation
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * Contributor(s):
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairoint.h"
-
-#include "cairo-xcb-private.h"
-
-#include "cairo-boxes-private.h"
-#include "cairo-clip-inline.h"
-#include "cairo-clip-private.h"
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-image-surface-inline.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-list-inline.h"
-#include "cairo-region-private.h"
-#include "cairo-surface-offset-private.h"
-#include "cairo-surface-snapshot-inline.h"
-#include "cairo-surface-subsurface-private.h"
-#include "cairo-traps-private.h"
-#include "cairo-recording-surface-inline.h"
-#include "cairo-paginated-private.h"
-#include "cairo-pattern-inline.h"
-
-#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
-
-static cairo_status_t
-_clip_and_composite_boxes (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- cairo_composite_rectangles_t *extents);
-
-static inline cairo_xcb_connection_t *
-_picture_to_connection (cairo_xcb_picture_t *picture)
-{
- return (cairo_xcb_connection_t *) picture->base.device;
-}
-
-static void
-_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface);
-
-static uint32_t
-hars_petruska_f54_1_random (void)
-{
-#define rol(x,k) ((x << k) | (x >> (32-k)))
- static uint32_t x;
- return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
-#undef rol
-}
-
-static cairo_status_t
-_cairo_xcb_picture_finish (void *abstract_surface)
-{
- cairo_xcb_picture_t *surface = abstract_surface;
- cairo_xcb_connection_t *connection = _picture_to_connection (surface);
- cairo_status_t status;
-
- status = _cairo_xcb_connection_acquire (connection);
- cairo_list_del (&surface->link);
- if (unlikely (status))
- return status;
-
- _cairo_xcb_connection_render_free_picture (connection, surface->picture);
-
- _cairo_xcb_connection_release (connection);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static const cairo_surface_backend_t _cairo_xcb_picture_backend = {
- CAIRO_SURFACE_TYPE_XCB,
- _cairo_xcb_picture_finish,
-};
-
-static const struct xcb_render_transform_t identity_transform = {
- 1 << 16, 0, 0,
- 0, 1 << 16, 0,
- 0, 0, 1 << 16,
-};
-
-static cairo_xcb_picture_t *
-_cairo_xcb_picture_create (cairo_xcb_screen_t *screen,
- pixman_format_code_t pixman_format,
- xcb_render_pictformat_t xrender_format,
- int width, int height)
-{
- cairo_xcb_picture_t *surface;
-
- surface = _cairo_malloc (sizeof (cairo_xcb_picture_t));
- if (unlikely (surface == NULL))
- return (cairo_xcb_picture_t *)
- _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _cairo_surface_init (&surface->base,
- &_cairo_xcb_picture_backend,
- &screen->connection->device,
- _cairo_content_from_pixman_format (pixman_format),
- FALSE); /* is_vector */
-
- cairo_list_add (&surface->link, &screen->pictures);
-
- surface->screen = screen;
- surface->picture = _cairo_xcb_connection_get_xid (screen->connection);
- surface->pixman_format = pixman_format;
- surface->xrender_format = xrender_format;
-
- surface->x0 = surface->y0 = 0;
- surface->x = surface->y = 0;
- surface->width = width;
- surface->height = height;
-
- surface->transform = identity_transform;
- surface->extend = CAIRO_EXTEND_NONE;
- surface->filter = CAIRO_FILTER_NEAREST;
- surface->has_component_alpha = FALSE;
-
- return surface;
-}
-
-static inline cairo_bool_t
-_operator_is_supported (uint32_t flags, cairo_operator_t op)
-{
- if (op <= CAIRO_OPERATOR_SATURATE)
- return TRUE;
-
- /* Can we use PDF operators? */
-#if CAIRO_XCB_RENDER_AT_LEAST(0, 11)
- if (op <= CAIRO_OPERATOR_HSL_LUMINOSITY)
- return flags & CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
-#endif
-
- return FALSE;
-}
-
-static int
-_render_operator (cairo_operator_t op)
-{
-#define C(x,y) case CAIRO_OPERATOR_##x: return XCB_RENDER_PICT_OP_##y
- switch (op) {
- C(CLEAR, CLEAR);
- C(SOURCE, SRC);
-
- C(OVER, OVER);
- C(IN, IN);
- C(OUT, OUT);
- C(ATOP, ATOP);
-
- C(DEST, DST);
- C(DEST_OVER, OVER_REVERSE);
- C(DEST_IN, IN_REVERSE);
- C(DEST_OUT, OUT_REVERSE);
- C(DEST_ATOP, ATOP_REVERSE);
-
- C(XOR, XOR);
- C(ADD, ADD);
- C(SATURATE, SATURATE);
-
- /* PDF operators were added in RENDER 0.11, check if the xcb headers have
- * the defines, else fall through to the default case. */
-#if CAIRO_XCB_RENDER_AT_LEAST(0, 11)
-#define BLEND(x,y) C(x,y)
-#else
-#define BLEND(x,y) case CAIRO_OPERATOR_##x:
-#endif
- BLEND(MULTIPLY, MULTIPLY);
- BLEND(SCREEN, SCREEN);
- BLEND(OVERLAY, OVERLAY);
- BLEND(DARKEN, DARKEN);
- BLEND(LIGHTEN, LIGHTEN);
- BLEND(COLOR_DODGE, COLOR_DODGE);
- BLEND(COLOR_BURN, COLOR_BURN);
- BLEND(HARD_LIGHT, HARD_LIGHT);
- BLEND(SOFT_LIGHT, SOFT_LIGHT);
- BLEND(DIFFERENCE, DIFFERENCE);
- BLEND(EXCLUSION, EXCLUSION);
- BLEND(HSL_HUE, HSL_HUE);
- BLEND(HSL_SATURATION, HSL_SATURATION);
- BLEND(HSL_COLOR, HSL_COLOR);
- BLEND(HSL_LUMINOSITY, HSL_LUMINOSITY);
-
- default:
- ASSERT_NOT_REACHED;
- return XCB_RENDER_PICT_OP_OVER;
- }
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_clip_region (cairo_xcb_surface_t *surface,
- cairo_region_t *region)
-{
- xcb_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
- xcb_rectangle_t *rects = stack_rects;
- int i, num_rects;
-
- num_rects = cairo_region_num_rectangles (region);
-
- if (num_rects > ARRAY_LENGTH (stack_rects)) {
- rects = _cairo_malloc_ab (num_rects, sizeof (xcb_rectangle_t));
- if (unlikely (rects == NULL)) {
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
- }
-
- for (i = 0; i < num_rects; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (region, i, &rect);
-
- rects[i].x = rect.x;
- rects[i].y = rect.y;
- rects[i].width = rect.width;
- rects[i].height = rect.height;
- }
-
- _cairo_xcb_connection_render_set_picture_clip_rectangles (surface->connection,
- surface->picture,
- 0, 0,
- num_rects, rects);
-
- if (rects != stack_rects)
- free (rects);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t *surface)
-{
- uint32_t values[] = { XCB_NONE };
- _cairo_xcb_connection_render_change_picture (surface->connection,
- surface->picture,
- XCB_RENDER_CP_CLIP_MASK,
- values);
-}
-
-static void
-_cairo_xcb_surface_set_precision (cairo_xcb_surface_t *surface,
- cairo_antialias_t antialias)
-{
- cairo_xcb_connection_t *connection = surface->connection;
- uint32_t precision;
-
- if (connection->force_precision != -1)
- precision = connection->force_precision;
- else switch (antialias) {
- default:
- case CAIRO_ANTIALIAS_DEFAULT:
- case CAIRO_ANTIALIAS_GRAY:
- case CAIRO_ANTIALIAS_NONE:
- case CAIRO_ANTIALIAS_FAST:
- case CAIRO_ANTIALIAS_GOOD:
- precision = XCB_RENDER_POLY_MODE_IMPRECISE;
- break;
- case CAIRO_ANTIALIAS_SUBPIXEL:
- case CAIRO_ANTIALIAS_BEST:
- precision = XCB_RENDER_POLY_MODE_PRECISE;
- break;
- }
-
- if (surface->precision != precision) {
- _cairo_xcb_connection_render_change_picture (connection,
- surface->picture,
- XCB_RENDER_CP_POLY_MODE,
- &precision);
- surface->precision = precision;
- }
-}
-
-
-static void
-_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface)
-{
- assert (surface->fallback == NULL);
- if (surface->picture == XCB_NONE) {
- uint32_t values[1];
- uint32_t flags = 0;
-
- if (surface->precision != XCB_RENDER_POLY_MODE_PRECISE) {
- flags |= XCB_RENDER_CP_POLY_MODE;
- values[0] = surface->precision;
- }
-
- surface->picture = _cairo_xcb_connection_get_xid (surface->connection);
- _cairo_xcb_connection_render_create_picture (surface->connection,
- surface->picture,
- surface->drawable,
- surface->xrender_format,
- flags, values);
- }
-}
-
-static cairo_xcb_picture_t *
-_picture_from_image (cairo_xcb_surface_t *target,
- xcb_render_pictformat_t format,
- cairo_image_surface_t *image,
- cairo_xcb_shm_info_t *shm_info)
-{
- xcb_pixmap_t pixmap;
- xcb_gcontext_t gc;
- cairo_xcb_picture_t *picture;
-
- pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
- image->depth,
- target->drawable,
- image->width, image->height);
-
- gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, image->depth);
-
- if (shm_info != NULL) {
- _cairo_xcb_connection_shm_put_image (target->connection,
- pixmap, gc,
- image->width, image->height,
- 0, 0,
- image->width, image->height,
- 0, 0,
- image->depth,
- shm_info->shm,
- shm_info->offset);
- } else {
- int len;
-
- /* Do we need to trim the image? */
- len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format));
- if (len == image->stride) {
- _cairo_xcb_connection_put_image (target->connection,
- pixmap, gc,
- image->width, image->height,
- 0, 0,
- image->depth,
- image->stride,
- image->data);
- } else {
- _cairo_xcb_connection_put_subimage (target->connection,
- pixmap, gc,
- 0, 0,
- image->width, image->height,
- PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
- image->stride,
- 0, 0,
- image->depth,
- image->data);
-
- }
- }
-
- _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
-
- picture = _cairo_xcb_picture_create (target->screen,
- image->pixman_format, format,
- image->width, image->height);
- if (likely (picture->base.status == CAIRO_STATUS_SUCCESS)) {
- _cairo_xcb_connection_render_create_picture (target->connection,
- picture->picture, pixmap, format,
- 0, 0);
- }
-
- _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
-
- return picture;
-}
-
-static cairo_bool_t
-_pattern_is_supported (uint32_t flags,
- const cairo_pattern_t *pattern)
-
-{
- if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
- return TRUE;
-
- switch (pattern->extend) {
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_EXTEND_NONE:
- case CAIRO_EXTEND_REPEAT:
- break;
- case CAIRO_EXTEND_PAD:
- case CAIRO_EXTEND_REFLECT:
- if ((flags & CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT) == 0)
- return FALSE;
- }
-
- if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
- switch (pattern->filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- return (flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) ||
- _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL);
- case CAIRO_FILTER_GOOD:
- return flags & CAIRO_XCB_RENDER_HAS_FILTER_GOOD;
- case CAIRO_FILTER_BEST:
- return flags & CAIRO_XCB_RENDER_HAS_FILTER_BEST;
- case CAIRO_FILTER_BILINEAR:
- case CAIRO_FILTER_GAUSSIAN:
- default:
- return flags & CAIRO_XCB_RENDER_HAS_FILTERS;
- }
- } else if (pattern->type == CAIRO_PATTERN_TYPE_MESH) {
- return FALSE;
- } else { /* gradient */
- if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
- return FALSE;
-
- /* The RENDER specification says that the inner circle has to be
- * completely contained inside the outer one. */
- if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL &&
- ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) pattern))
- {
- return FALSE;
- }
- return TRUE;
- }
-}
-
-static void
-_cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
- const cairo_matrix_t *matrix,
- cairo_filter_t filter,
- double xc, double yc)
-{
- xcb_render_transform_t transform;
- pixman_transform_t *pixman_transform;
- cairo_int_status_t ignored;
-
- /* Casting between pixman_transform_t and xcb_render_transform_t is safe
- * because they happen to be the exact same type.
- */
- pixman_transform = (pixman_transform_t *) &transform;
-
- picture->x = picture->x0;
- picture->y = picture->y0;
- ignored = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
- pixman_transform,
- &picture->x, &picture->y);
- (void) ignored;
-
- if (memcmp (&picture->transform, &transform, sizeof (xcb_render_transform_t))) {
- _cairo_xcb_connection_render_set_picture_transform (_picture_to_connection (picture),
- picture->picture,
- &transform);
-
- picture->transform = transform;
- }
-}
-
-static void
-_cairo_xcb_picture_set_filter (cairo_xcb_picture_t *picture,
- cairo_filter_t filter)
-{
- const char *render_filter;
- int len;
-
- if (picture->filter == filter)
- return;
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- render_filter = "fast";
- len = strlen ("fast");
- break;
-
- case CAIRO_FILTER_GOOD:
- render_filter = "good";
- len = strlen ("good");
- break;
-
- case CAIRO_FILTER_BEST:
- render_filter = "best";
- len = strlen ("best");
- break;
-
- case CAIRO_FILTER_NEAREST:
- render_filter = "nearest";
- len = strlen ("nearest");
- break;
-
- case CAIRO_FILTER_BILINEAR:
- render_filter = "bilinear";
- len = strlen ("bilinear");
- break;
-
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_FILTER_GAUSSIAN:
- render_filter = "best";
- len = strlen ("best");
- break;
- }
-
- _cairo_xcb_connection_render_set_picture_filter (_picture_to_connection (picture),
- picture->picture,
- len, (char *) render_filter);
- picture->filter = filter;
-}
-
-static void
-_cairo_xcb_picture_set_extend (cairo_xcb_picture_t *picture,
- cairo_extend_t extend)
-{
- uint32_t pa[1];
-
- if (picture->extend == extend)
- return;
-
- switch (extend) {
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_EXTEND_NONE:
- pa[0] = XCB_RENDER_REPEAT_NONE;
- break;
-
- case CAIRO_EXTEND_REPEAT:
- pa[0] = XCB_RENDER_REPEAT_NORMAL;
- break;
-
- case CAIRO_EXTEND_REFLECT:
- pa[0] = XCB_RENDER_REPEAT_REFLECT;
- break;
-
- case CAIRO_EXTEND_PAD:
- pa[0] = XCB_RENDER_REPEAT_PAD;
- break;
- }
-
- _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture),
- picture->picture,
- XCB_RENDER_CP_REPEAT, pa);
- picture->extend = extend;
-}
-
-static void
-_cairo_xcb_picture_set_component_alpha (cairo_xcb_picture_t *picture,
- cairo_bool_t ca)
-{
- uint32_t pa[1];
-
- if (picture->has_component_alpha == ca)
- return;
-
- pa[0] = ca;
-
- _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture),
- picture->picture,
- XCB_RENDER_CP_COMPONENT_ALPHA,
- pa);
- picture->has_component_alpha = ca;
-}
-
-static cairo_xcb_picture_t *
-_solid_picture (cairo_xcb_surface_t *target,
- const cairo_color_t *color)
-{
- xcb_render_color_t xcb_color;
- xcb_render_pictformat_t xrender_format;
- cairo_xcb_picture_t *picture;
-
- xcb_color.red = color->red_short;
- xcb_color.green = color->green_short;
- xcb_color.blue = color->blue_short;
- xcb_color.alpha = color->alpha_short;
-
- xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
- picture = _cairo_xcb_picture_create (target->screen,
- PIXMAN_a8r8g8b8,
- xrender_format,
- -1, -1);
- if (unlikely (picture->base.status))
- return picture;
-
- if (target->connection->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) {
- _cairo_xcb_connection_render_create_solid_fill (target->connection,
- picture->picture,
- xcb_color);
- } else {
- xcb_pixmap_t pixmap;
- uint32_t values[] = { XCB_RENDER_REPEAT_NORMAL };
-
- pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
- 32, target->drawable, 1, 1);
- _cairo_xcb_connection_render_create_picture (target->connection,
- picture->picture,
- pixmap,
- xrender_format,
- XCB_RENDER_CP_REPEAT,
- values);
- if (target->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
- xcb_rectangle_t rect;
-
- rect.x = rect.y = 0;
- rect.width = rect.height = 1;
-
- _cairo_xcb_connection_render_fill_rectangles (_picture_to_connection (picture),
- XCB_RENDER_PICT_OP_SRC,
- picture->picture,
- xcb_color, 1, &rect);
- } else {
- xcb_gcontext_t gc;
- uint32_t pixel;
-
- gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, 32);
-
- /* XXX byte ordering? */
- pixel = ((color->alpha_short >> 8) << 24) |
- ((color->red_short >> 8) << 16) |
- ((color->green_short >> 8) << 8) |
- ((color->blue_short >> 8) << 0);
-
- _cairo_xcb_connection_put_image (target->connection,
- pixmap, gc,
- 1, 1, 0, 0,
- 32, 4, &pixel);
-
- _cairo_xcb_screen_put_gc (target->screen, 32, gc);
- }
-
- _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
- }
-
- return picture;
-}
-
-static cairo_xcb_picture_t *
-_cairo_xcb_transparent_picture (cairo_xcb_surface_t *target)
-{
- cairo_xcb_picture_t *picture;
-
- picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT];
- if (picture == NULL) {
- picture = _solid_picture (target, CAIRO_COLOR_TRANSPARENT);
- target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT] = &picture->base;
- }
-
- return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
-}
-
-static cairo_xcb_picture_t *
-_cairo_xcb_black_picture (cairo_xcb_surface_t *target)
-{
- cairo_xcb_picture_t *picture;
-
- picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_BLACK];
- if (picture == NULL) {
- picture = _solid_picture (target, CAIRO_COLOR_BLACK);
- target->screen->stock_colors[CAIRO_STOCK_BLACK] = &picture->base;
- }
-
- return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
-}
-
-static cairo_xcb_picture_t *
-_cairo_xcb_white_picture (cairo_xcb_surface_t *target)
-{
- cairo_xcb_picture_t *picture;
-
- picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_WHITE];
- if (picture == NULL) {
- picture = _solid_picture (target, CAIRO_COLOR_WHITE);
- target->screen->stock_colors[CAIRO_STOCK_WHITE] = &picture->base;
- }
-
- return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
-}
-
-static cairo_xcb_picture_t *
-_cairo_xcb_solid_picture (cairo_xcb_surface_t *target,
- const cairo_solid_pattern_t *pattern)
-{
- cairo_xcb_picture_t *picture;
- cairo_xcb_screen_t *screen;
- int i, n_cached;
-
- if (pattern->color.alpha_short <= 0x00ff)
- return _cairo_xcb_transparent_picture (target);
-
- if (pattern->color.alpha_short >= 0xff00) {
- if (pattern->color.red_short <= 0x00ff &&
- pattern->color.green_short <= 0x00ff &&
- pattern->color.blue_short <= 0x00ff)
- {
- return _cairo_xcb_black_picture (target);
- }
-
- if (pattern->color.red_short >= 0xff00 &&
- pattern->color.green_short >= 0xff00 &&
- pattern->color.blue_short >= 0xff00)
- {
- return _cairo_xcb_white_picture (target);
- }
- }
-
- screen = target->screen;
- n_cached = screen->solid_cache_size;
- for (i = 0; i < n_cached; i++) {
- if (_cairo_color_equal (&screen->solid_cache[i].color, &pattern->color)) {
- return (cairo_xcb_picture_t *) cairo_surface_reference (screen->solid_cache[i].picture);
- }
- }
-
- picture = _solid_picture (target, &pattern->color);
- if (unlikely (picture->base.status))
- return picture;
-
- if (screen->solid_cache_size < ARRAY_LENGTH (screen->solid_cache)) {
- i = screen->solid_cache_size++;
- } else {
- i = hars_petruska_f54_1_random () % ARRAY_LENGTH (screen->solid_cache);
- cairo_surface_destroy (screen->solid_cache[i].picture);
- }
- screen->solid_cache[i].picture = cairo_surface_reference (&picture->base);
- screen->solid_cache[i].color = pattern->color;
-
- return picture;
-}
-
-static cairo_xcb_picture_t *
-_render_to_picture (cairo_xcb_surface_t *target,
- const cairo_pattern_t *pattern,
- const cairo_rectangle_int_t *extents)
-{
- cairo_image_surface_t *image;
- cairo_xcb_shm_info_t *shm_info;
- cairo_pattern_union_t copy;
- cairo_status_t status;
- cairo_xcb_picture_t *picture;
- pixman_format_code_t pixman_format;
- xcb_render_pictformat_t xrender_format;
-
- /* XXX handle extend modes via tiling? */
- /* XXX alpha-only masks? */
-
- pixman_format = PIXMAN_a8r8g8b8;
- xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
-
- status = _cairo_xcb_shm_image_create (target->screen->connection,
- pixman_format,
- extents->width, extents->height,
- &image, &shm_info);
- if (unlikely (status))
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
-
- _cairo_pattern_init_static_copy (&copy.base, pattern);
- cairo_matrix_translate (&copy.base.matrix, extents->x, extents->y);
- status = _cairo_surface_paint (&image->base,
- CAIRO_OPERATOR_SOURCE,
- &copy.base,
- NULL);
- if (unlikely (status)) {
- cairo_surface_destroy (&image->base);
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
- }
-
- picture = _picture_from_image (target, xrender_format, image, shm_info);
- cairo_surface_destroy (&image->base);
-
- if (unlikely (picture->base.status))
- return picture;
-
- _cairo_xcb_picture_set_component_alpha (picture, pattern->has_component_alpha);
- picture->x = -extents->x;
- picture->y = -extents->y;
-
- return picture;
-}
-
-static xcb_render_fixed_t *
-_gradient_to_xcb (const cairo_gradient_pattern_t *gradient,
- unsigned int *n_stops,
- char *buf, unsigned int buflen)
-{
- xcb_render_fixed_t *stops;
- xcb_render_color_t *colors;
- unsigned int i;
-
- assert (gradient->n_stops > 0);
- *n_stops = MAX (gradient->n_stops, 2);
-
- if (*n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen)
- {
- stops = (xcb_render_fixed_t *) buf;
- }
- else
- {
- stops =
- _cairo_malloc_ab (*n_stops,
- sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t));
- if (unlikely (stops == NULL))
- return NULL;
- }
-
- colors = (xcb_render_color_t *) (stops + *n_stops);
- for (i = 0; i < gradient->n_stops; i++) {
- stops[i] =
- _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
-
- colors[i].red = gradient->stops[i].color.red_short;
- colors[i].green = gradient->stops[i].color.green_short;
- colors[i].blue = gradient->stops[i].color.blue_short;
- colors[i].alpha = gradient->stops[i].color.alpha_short;
- }
-
- /* RENDER does not support gradients with less than 2 stops. If a
- * gradient has only a single stop, duplicate it to make RENDER
- * happy. */
- if (gradient->n_stops == 1) {
- stops[1] = _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
-
- colors[1].red = gradient->stops[0].color.red_short;
- colors[1].green = gradient->stops[0].color.green_short;
- colors[1].blue = gradient->stops[0].color.blue_short;
- colors[1].alpha = gradient->stops[0].color.alpha_short;
- }
-
- return stops;
-}
-
-static cairo_xcb_picture_t *
-_cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
- const cairo_linear_pattern_t *pattern,
- const cairo_rectangle_int_t *extents)
-{
- char buf[CAIRO_STACK_BUFFER_SIZE];
- xcb_render_fixed_t *stops;
- xcb_render_color_t *colors;
- xcb_render_pointfix_t p1, p2;
- cairo_matrix_t matrix;
- cairo_circle_double_t extremes[2];
- cairo_xcb_picture_t *picture;
- cairo_status_t status;
- unsigned int n_stops;
-
- _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
-
- picture = (cairo_xcb_picture_t *)
- _cairo_xcb_screen_lookup_linear_picture (target->screen, pattern);
- if (picture != NULL)
- goto setup_picture;
-
- stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf));
- if (unlikely (stops == NULL))
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
- picture = _cairo_xcb_picture_create (target->screen,
- target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
- PIXMAN_a8r8g8b8,
- -1, -1);
- if (unlikely (picture->base.status)) {
- if (stops != (xcb_render_fixed_t *) buf)
- free (stops);
- return picture;
- }
- picture->filter = CAIRO_FILTER_DEFAULT;
-
- colors = (xcb_render_color_t *) (stops + n_stops);
-
- p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
- p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
- p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
- p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
-
- _cairo_xcb_connection_render_create_linear_gradient (target->connection,
- picture->picture,
- p1, p2,
- n_stops,
- stops, colors);
-
- if (stops != (xcb_render_fixed_t *) buf)
- free (stops);
-
- status = _cairo_xcb_screen_store_linear_picture (target->screen,
- pattern,
- &picture->base);
- if (unlikely (status)) {
- cairo_surface_destroy (&picture->base);
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
- }
-
-setup_picture:
- _cairo_xcb_picture_set_matrix (picture, &matrix,
- pattern->base.base.filter,
- extents->x + extents->width/2.,
- extents->y + extents->height/2.);
- _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
- _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
- _cairo_xcb_picture_set_component_alpha (picture,
- pattern->base.base.has_component_alpha);
-
- return picture;
-}
-
-static cairo_xcb_picture_t *
-_cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
- const cairo_radial_pattern_t *pattern,
- const cairo_rectangle_int_t *extents)
-{
- char buf[CAIRO_STACK_BUFFER_SIZE];
- xcb_render_fixed_t *stops;
- xcb_render_color_t *colors;
- xcb_render_pointfix_t p1, p2;
- xcb_render_fixed_t r1, r2;
- cairo_matrix_t matrix;
- cairo_circle_double_t extremes[2];
- cairo_xcb_picture_t *picture;
- cairo_status_t status;
- unsigned int n_stops;
-
- _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
-
- picture = (cairo_xcb_picture_t *)
- _cairo_xcb_screen_lookup_radial_picture (target->screen, pattern);
- if (picture != NULL)
- goto setup_picture;
-
- stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf));
- if (unlikely (stops == NULL))
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
- picture = _cairo_xcb_picture_create (target->screen,
- target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
- PIXMAN_a8r8g8b8,
- -1, -1);
- if (unlikely (picture->base.status)) {
- if (stops != (xcb_render_fixed_t *) buf)
- free (stops);
- return picture;
- }
- picture->filter = CAIRO_FILTER_DEFAULT;
-
- colors = (xcb_render_color_t *) (stops + n_stops);
-
- p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
- p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
- p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
- p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
-
- r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
- r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
-
- _cairo_xcb_connection_render_create_radial_gradient (target->connection,
- picture->picture,
- p1, p2, r1, r2,
- n_stops,
- stops, colors);
-
- if (stops != (xcb_render_fixed_t *) buf)
- free (stops);
-
- status = _cairo_xcb_screen_store_radial_picture (target->screen,
- pattern,
- &picture->base);
- if (unlikely (status)) {
- cairo_surface_destroy (&picture->base);
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
- }
-
-setup_picture:
- _cairo_xcb_picture_set_matrix (picture, &matrix,
- pattern->base.base.filter,
- extents->x + extents->width/2.,
- extents->y + extents->height/2.);
- _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
- _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
- _cairo_xcb_picture_set_component_alpha (picture,
- pattern->base.base.has_component_alpha);
-
- return picture;
-}
-
-static cairo_xcb_picture_t *
-_copy_to_picture (cairo_xcb_surface_t *source)
-{
- cairo_xcb_picture_t *picture;
- uint32_t values[] = { 0, 1 };
-
- if (source->deferred_clear) {
- cairo_status_t status = _cairo_xcb_surface_clear (source);
- if (unlikely (status))
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
- }
-
- picture = _cairo_xcb_picture_create (source->screen,
- source->xrender_format,
- source->pixman_format,
- source->width,
- source->height);
- if (unlikely (picture->base.status))
- return picture;
-
- _cairo_xcb_connection_render_create_picture (source->connection,
- picture->picture,
- source->drawable,
- source->xrender_format,
- XCB_RENDER_CP_GRAPHICS_EXPOSURE |
- XCB_RENDER_CP_SUBWINDOW_MODE,
- values);
-
- return picture;
-}
-
-static void
-_cairo_xcb_surface_setup_surface_picture(cairo_xcb_picture_t *picture,
- const cairo_surface_pattern_t *pattern,
- const cairo_rectangle_int_t *extents)
-{
- cairo_filter_t filter;
-
- filter = pattern->base.filter;
- if (filter != CAIRO_FILTER_NEAREST &&
- _cairo_matrix_is_pixel_exact (&pattern->base.matrix))
- {
- filter = CAIRO_FILTER_NEAREST;
- }
- _cairo_xcb_picture_set_filter (picture, filter);
-
- _cairo_xcb_picture_set_matrix (picture,
- &pattern->base.matrix, filter,
- extents->x + extents->width/2.,
- extents->y + extents->height/2.);
-
-
- _cairo_xcb_picture_set_extend (picture, pattern->base.extend);
- _cairo_xcb_picture_set_component_alpha (picture, pattern->base.has_component_alpha);
-}
-
-static cairo_xcb_picture_t *
-record_to_picture (cairo_surface_t *target,
- const cairo_surface_pattern_t *pattern,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_pattern_t tmp_pattern;
- cairo_xcb_picture_t *picture;
- cairo_status_t status;
- cairo_matrix_t matrix;
- cairo_surface_t *tmp;
- cairo_surface_t *source;
- cairo_rectangle_int_t limit;
- cairo_extend_t extend;
-
- /* XXX: The following was once more or less copied from cairo-xlibs-ource.c,
- * record_source() and recording_pattern_get_surface(), can we share a
- * single version?
- */
-
- /* First get the 'real' recording surface and figure out the size for tmp */
- source = _cairo_pattern_get_source (pattern, &limit);
- assert (_cairo_surface_is_recording (source));
-
- if (! _cairo_matrix_is_identity (&pattern->base.matrix)) {
- double x1, y1, x2, y2;
-
- matrix = pattern->base.matrix;
- status = cairo_matrix_invert (&matrix);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- x1 = limit.x;
- y1 = limit.y;
- x2 = limit.x + limit.width;
- y2 = limit.y + limit.height;
-
- _cairo_matrix_transform_bounding_box (&matrix,
- &x1, &y1, &x2, &y2, NULL);
-
- limit.x = floor (x1);
- limit.y = floor (y1);
- limit.width = ceil (x2) - limit.x;
- limit.height = ceil (y2) - limit.y;
- }
- extend = pattern->base.extend;
- if (_cairo_rectangle_contains_rectangle (&limit, extents))
- extend = CAIRO_EXTEND_NONE;
- if (extend == CAIRO_EXTEND_NONE && ! _cairo_rectangle_intersect (&limit, extents))
- return _cairo_xcb_transparent_picture ((cairo_xcb_surface_t *) target);
-
- /* Now draw the recording surface to an xcb surface */
- tmp = _cairo_surface_create_scratch (target,
- source->content,
- limit.width,
- limit.height,
- CAIRO_COLOR_TRANSPARENT);
- if (tmp->status != CAIRO_STATUS_SUCCESS) {
- return (cairo_xcb_picture_t *) tmp;
- }
-
- cairo_matrix_init_translate (&matrix, limit.x, limit.y);
- cairo_matrix_multiply (&matrix, &matrix, &pattern->base.matrix);
-
- status = _cairo_recording_surface_replay_with_clip (source,
- &matrix, tmp,
- NULL);
- if (unlikely (status)) {
- cairo_surface_destroy (tmp);
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
- }
-
- /* Now that we have drawn this to an xcb surface, try again with that */
- _cairo_pattern_init_static_copy (&tmp_pattern.base, &pattern->base);
- tmp_pattern.surface = tmp;
- cairo_matrix_init_translate (&tmp_pattern.base.matrix, -limit.x, -limit.y);
-
- picture = _copy_to_picture ((cairo_xcb_surface_t *) tmp);
- if (picture->base.status == CAIRO_STATUS_SUCCESS)
- _cairo_xcb_surface_setup_surface_picture (picture, &tmp_pattern, extents);
- cairo_surface_destroy (tmp);
- return picture;
-}
-
-static cairo_xcb_picture_t *
-_cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
- const cairo_surface_pattern_t *pattern,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_t *source = pattern->surface;
- cairo_xcb_picture_t *picture;
-
- picture = (cairo_xcb_picture_t *)
- _cairo_surface_has_snapshot (source, &_cairo_xcb_picture_backend);
- if (picture != NULL) {
- if (picture->screen == target->screen) {
- picture = (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
- _cairo_xcb_surface_setup_surface_picture (picture, pattern, extents);
- return picture;
- }
- picture = NULL;
- }
-
- if (source->type == CAIRO_SURFACE_TYPE_XCB)
- {
- if (_cairo_surface_is_xcb(source)) {
- cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) source;
- if (xcb->screen == target->screen && xcb->fallback == NULL) {
- picture = _copy_to_picture ((cairo_xcb_surface_t *) source);
- if (unlikely (picture->base.status))
- return picture;
- }
- } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
- cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
- cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) sub->target;
-
- /* XXX repeat interval with source clipping? */
- if (FALSE && xcb->screen == target->screen && xcb->fallback == NULL) {
- xcb_rectangle_t rect;
-
- picture = _copy_to_picture (xcb);
- if (unlikely (picture->base.status))
- return picture;
-
- rect.x = sub->extents.x;
- rect.y = sub->extents.y;
- rect.width = sub->extents.width;
- rect.height = sub->extents.height;
-
- _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
- picture->picture,
- 0, 0,
- 1, &rect);
- picture->x0 = rect.x;
- picture->y0 = rect.y;
- picture->width = rect.width;
- picture->height = rect.height;
- }
- } else if (_cairo_surface_is_snapshot (source)) {
- cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
- cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) snap->target;
-
- if (xcb->screen == target->screen && xcb->fallback == NULL) {
- picture = _copy_to_picture (xcb);
- if (unlikely (picture->base.status))
- return picture;
- }
- }
- }
-#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
- else if (source->type == CAIRO_SURFACE_TYPE_XLIB)
- {
- if (source->backend->type == CAIRO_SURFACE_TYPE_XLIB) {
- cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) source)->xcb;
- if (xcb->screen == target->screen && xcb->fallback == NULL) {
- picture = _copy_to_picture (xcb);
- if (unlikely (picture->base.status))
- return picture;
- }
- } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
- cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
- cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) sub->target)->xcb;
-
- if (FALSE && xcb->screen == target->screen && xcb->fallback == NULL) {
- xcb_rectangle_t rect;
-
- picture = _copy_to_picture (xcb);
- if (unlikely (picture->base.status))
- return picture;
-
- rect.x = sub->extents.x;
- rect.y = sub->extents.y;
- rect.width = sub->extents.width;
- rect.height = sub->extents.height;
-
- _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
- picture->picture,
- 0, 0,
- 1, &rect);
- picture->x0 = rect.x;
- picture->y0 = rect.y;
- picture->width = rect.width;
- picture->height = rect.height;
- }
- } else if (_cairo_surface_is_snapshot (source)) {
- cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
- cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) snap->target)->xcb;
-
- if (xcb->screen == target->screen && xcb->fallback == NULL) {
- picture = _copy_to_picture (xcb);
- if (unlikely (picture->base.status))
- return picture;
- }
- }
- }
-#endif
-#if CAIRO_HAS_GL_FUNCTIONS
- else if (source->type == CAIRO_SURFACE_TYPE_GL)
- {
- /* pixmap from texture */
- }
-#endif
- else if (source->type == CAIRO_SURFACE_TYPE_RECORDING)
- {
- /* We have to skip the call to attach_snapshot() because we possibly
- * only drew part of the recording surface.
- * TODO: When can we safely attach a snapshot?
- */
- return record_to_picture(&target->base, pattern, extents);
- }
-
- if (picture == NULL) {
- cairo_image_surface_t *image;
- void *image_extra;
- cairo_status_t status;
-
- status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
- if (unlikely (status))
- return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
-
- if (image->format != CAIRO_FORMAT_INVALID) {
- xcb_render_pictformat_t format;
-
- format = target->screen->connection->standard_formats[image->format];
-
- picture = _picture_from_image (target, format, image, NULL);
- _cairo_surface_release_source_image (source, image, image_extra);
- } else {
- cairo_image_surface_t *conv;
- xcb_render_pictformat_t render_format;
-
- /* XXX XRenderPutImage! */
-
- conv = _cairo_image_surface_coerce (image);
- _cairo_surface_release_source_image (source, image, image_extra);
- if (unlikely (conv->base.status))
- return (cairo_xcb_picture_t *) conv;
-
- render_format = target->screen->connection->standard_formats[conv->format];
- picture = _picture_from_image (target, render_format, conv, NULL);
- cairo_surface_destroy (&conv->base);
- }
-
- if (unlikely (picture->base.status))
- return picture;
- }
-
- /* XXX: This causes too many problems and bugs, let's skip it for now. */
-#if 0
- _cairo_surface_attach_snapshot (source,
- &picture->base,
- NULL);
-#endif
-
- _cairo_xcb_surface_setup_surface_picture (picture, pattern, extents);
- return picture;
-}
-
-static cairo_xcb_picture_t *
-_cairo_xcb_picture_for_pattern (cairo_xcb_surface_t *target,
- const cairo_pattern_t *pattern,
- const cairo_rectangle_int_t *extents)
-{
- if (pattern == NULL)
- return _cairo_xcb_white_picture (target);
-
- if (! _pattern_is_supported (target->connection->flags, pattern))
- return _render_to_picture (target, pattern, extents);
-
- switch (pattern->type) {
- case CAIRO_PATTERN_TYPE_SOLID:
- return _cairo_xcb_solid_picture (target, (cairo_solid_pattern_t *) pattern);
-
- case CAIRO_PATTERN_TYPE_LINEAR:
- return _cairo_xcb_linear_picture (target,
- (cairo_linear_pattern_t *) pattern,
- extents);
-
- case CAIRO_PATTERN_TYPE_RADIAL:
- return _cairo_xcb_radial_picture (target,
- (cairo_radial_pattern_t *) pattern,
- extents);
-
- case CAIRO_PATTERN_TYPE_SURFACE:
- return _cairo_xcb_surface_picture (target,
- (cairo_surface_pattern_t *) pattern,
- extents);
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_PATTERN_TYPE_MESH:
- case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
- return _render_to_picture (target, pattern, extents);
- }
-}
-
-COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t) <= sizeof (cairo_box_t));
-
-static cairo_status_t
-_render_fill_boxes (void *abstract_dst,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_boxes_t *boxes)
-{
- cairo_xcb_surface_t *dst = abstract_dst;
- xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
- xcb_rectangle_t *xrects = stack_xrects;
- xcb_render_color_t render_color;
- int render_op = _render_operator (op);
- struct _cairo_boxes_chunk *chunk;
- int max_count;
-
- render_color.red = color->red_short;
- render_color.green = color->green_short;
- render_color.blue = color->blue_short;
- render_color.alpha = color->alpha_short;
-
- max_count = 0;
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- if (chunk->count > max_count)
- max_count = chunk->count;
- }
- if (max_count > ARRAY_LENGTH (stack_xrects)) {
- xrects = _cairo_malloc_ab (max_count, sizeof (xcb_rectangle_t));
- if (unlikely (xrects == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- int i, j;
-
- for (i = j = 0; i < chunk->count; i++) {
- int x1 = _cairo_fixed_integer_round_down (chunk->base[i].p1.x);
- int y1 = _cairo_fixed_integer_round_down (chunk->base[i].p1.y);
- int x2 = _cairo_fixed_integer_round_down (chunk->base[i].p2.x);
- int y2 = _cairo_fixed_integer_round_down (chunk->base[i].p2.y);
-
- if (x2 > x1 && y2 > y1) {
- xrects[j].x = x1;
- xrects[j].y = y1;
- xrects[j].width = x2 - x1;
- xrects[j].height = y2 - y1;
- j++;
- }
- }
-
- if (j) {
- _cairo_xcb_connection_render_fill_rectangles
- (dst->connection,
- render_op, dst->picture,
- render_color, j, xrects);
- }
- }
-
- if (xrects != stack_xrects)
- free (xrects);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* pixel aligned, non-overlapping boxes */
-static cairo_int_status_t
-_render_composite_boxes (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- const cairo_pattern_t *mask_pattern,
- const cairo_rectangle_int_t *extents,
- const cairo_boxes_t *boxes)
-{
- cairo_xcb_picture_t *src, *mask;
- const struct _cairo_boxes_chunk *chunk;
- xcb_rectangle_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
- xcb_rectangle_t *clip_boxes;
- cairo_rectangle_int_t stack_extents;
- cairo_status_t status;
- int num_boxes;
- int render_op;
-
- render_op = _render_operator (op);
-
- if (src_pattern == NULL) {
- src_pattern = mask_pattern;
- mask_pattern = NULL;
- }
-
- /* amalgamate into a single Composite call by setting a clip region */
- clip_boxes = stack_boxes;
- if (boxes->num_boxes > ARRAY_LENGTH (stack_boxes)) {
- clip_boxes = _cairo_malloc_ab (boxes->num_boxes, sizeof (xcb_rectangle_t));
- if (unlikely (clip_boxes == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
- status = src->base.status;
- if (unlikely (status))
- goto cleanup_boxes;
-
- num_boxes = 0;
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- const cairo_box_t *box = chunk->base;
- int i;
-
- for (i = 0; i < chunk->count; i++) {
- int x = _cairo_fixed_integer_round_down (box[i].p1.x);
- int y = _cairo_fixed_integer_round_down (box[i].p1.y);
- int width = _cairo_fixed_integer_round_down (box[i].p2.x) - x;
- int height = _cairo_fixed_integer_round_down (box[i].p2.y) - y;
-
- if (width && height) {
- clip_boxes[num_boxes].x = x;
- clip_boxes[num_boxes].y = y;
- clip_boxes[num_boxes].width = width;
- clip_boxes[num_boxes].height = height;
- num_boxes++;
- }
- }
- }
-
- if (num_boxes) {
- if (num_boxes > 1) {
- _cairo_xcb_connection_render_set_picture_clip_rectangles (dst->connection,
- dst->picture,
- 0, 0,
- num_boxes,
- clip_boxes);
- } else {
- stack_extents.x = clip_boxes[0].x;
- stack_extents.y = clip_boxes[0].y;
- stack_extents.width = clip_boxes[0].width;
- stack_extents.height = clip_boxes[0].height;
- extents = &stack_extents;
- }
-
- if (mask_pattern != NULL) {
- mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
- status = mask->base.status;
- if (unlikely (status))
- goto cleanup_clip;
-
- _cairo_xcb_connection_render_composite (dst->connection,
- render_op,
- src->picture,
- mask->picture,
- dst->picture,
- src->x + extents->x, src->y + extents->y,
- mask->x + extents->x, mask->y + extents->y,
- extents->x, extents->y,
- extents->width, extents->height);
-
- cairo_surface_destroy (&mask->base);
- } else {
- _cairo_xcb_connection_render_composite (dst->connection,
- render_op,
- src->picture,
- XCB_NONE,
- dst->picture,
- src->x + extents->x, src->y + extents->y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
- }
-
-cleanup_clip:
-
- if (num_boxes > 1)
- _cairo_xcb_surface_clear_clip_region (dst);
- }
-
- cairo_surface_destroy (&src->base);
-
-cleanup_boxes:
-
- if (clip_boxes != stack_boxes)
- free (clip_boxes);
-
- return status;
-}
-
-
-#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
-#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
-
-static cairo_bool_t
-_line_exceeds_16_16 (const cairo_line_t *line)
-{
- return
- line->p1.x <= CAIRO_FIXED_16_16_MIN ||
- line->p1.x >= CAIRO_FIXED_16_16_MAX ||
-
- line->p2.x <= CAIRO_FIXED_16_16_MIN ||
- line->p2.x >= CAIRO_FIXED_16_16_MAX ||
-
- line->p1.y <= CAIRO_FIXED_16_16_MIN ||
- line->p1.y >= CAIRO_FIXED_16_16_MAX ||
-
- line->p2.y <= CAIRO_FIXED_16_16_MIN ||
- line->p2.y >= CAIRO_FIXED_16_16_MAX;
-}
-
-static void
-_project_line_x_onto_16_16 (const cairo_line_t *line,
- cairo_fixed_t top,
- cairo_fixed_t bottom,
- xcb_render_linefix_t *out)
-{
- cairo_point_double_t p1, p2;
- double m;
-
- p1.x = _cairo_fixed_to_double (line->p1.x);
- p1.y = _cairo_fixed_to_double (line->p1.y);
-
- p2.x = _cairo_fixed_to_double (line->p2.x);
- p2.y = _cairo_fixed_to_double (line->p2.y);
-
- m = (p2.x - p1.x) / (p2.y - p1.y);
- out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
- out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
-}
-
-typedef struct {
- cairo_traps_t traps;
- cairo_antialias_t antialias;
-} composite_traps_info_t;
-
-COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t) <= sizeof (cairo_trapezoid_t));
-
-static cairo_int_status_t
-_composite_traps (void *closure,
- cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- int dst_x, int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_clip_t *clip)
-{
- composite_traps_info_t *info = closure;
- const cairo_traps_t *traps = &info->traps;
- cairo_xcb_picture_t *src;
- cairo_format_t format;
- xcb_render_pictformat_t xrender_format;
- xcb_render_trapezoid_t *xtraps;
- int render_reference_x, render_reference_y;
- cairo_status_t status;
- int i;
-
- if (dst->deferred_clear) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status))
- return status;
- }
-
- src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
- if (unlikely (src->base.status))
- return src->base.status;
-
- if (info->antialias == CAIRO_ANTIALIAS_NONE)
- format = CAIRO_FORMAT_A1;
- else
- format = CAIRO_FORMAT_A8;
- xrender_format = dst->screen->connection->standard_formats[format];
-
- xtraps = (xcb_render_trapezoid_t *) traps->traps;
- for (i = 0; i < traps->num_traps; i++) {
- cairo_trapezoid_t t = traps->traps[i];
-
- /* top/bottom will be clamped to surface bounds */
- xtraps[i].top = _cairo_fixed_to_16_16 (t.top);
- xtraps[i].top -= dst_y << 16;
- xtraps[i].bottom = _cairo_fixed_to_16_16 (t.bottom);
- xtraps[i].bottom -= dst_y << 16;
-
- /* However, all the other coordinates will have been left untouched so
- * as not to introduce numerical error. Recompute them if they
- * exceed the 16.16 limits.
- */
- if (unlikely (_line_exceeds_16_16 (&t.left))) {
- _project_line_x_onto_16_16 (&t.left,
- t.top,
- t.bottom,
- &xtraps[i].left);
- xtraps[i].left.p1.y = xtraps[i].top;
- xtraps[i].left.p2.y = xtraps[i].bottom;
- } else {
- xtraps[i].left.p1.x = _cairo_fixed_to_16_16 (t.left.p1.x);
- xtraps[i].left.p1.y = _cairo_fixed_to_16_16 (t.left.p1.y);
- xtraps[i].left.p2.x = _cairo_fixed_to_16_16 (t.left.p2.x);
- xtraps[i].left.p2.y = _cairo_fixed_to_16_16 (t.left.p2.y);
- }
- xtraps[i].left.p1.x -= dst_x << 16;
- xtraps[i].left.p1.y -= dst_y << 16;
- xtraps[i].left.p2.x -= dst_x << 16;
- xtraps[i].left.p2.y -= dst_y << 16;
-
- if (unlikely (_line_exceeds_16_16 (&t.right))) {
- _project_line_x_onto_16_16 (&t.right,
- t.top,
- t.bottom,
- &xtraps[i].right);
- xtraps[i].right.p1.y = xtraps[i].top;
- xtraps[i].right.p2.y = xtraps[i].bottom;
- } else {
- xtraps[i].right.p1.x = _cairo_fixed_to_16_16 (t.right.p1.x);
- xtraps[i].right.p1.y = _cairo_fixed_to_16_16 (t.right.p1.y);
- xtraps[i].right.p2.x = _cairo_fixed_to_16_16 (t.right.p2.x);
- xtraps[i].right.p2.y = _cairo_fixed_to_16_16 (t.right.p2.y);
- }
- xtraps[i].right.p1.x -= dst_x << 16;
- xtraps[i].right.p1.y -= dst_y << 16;
- xtraps[i].right.p2.x -= dst_x << 16;
- xtraps[i].right.p2.y -= dst_y << 16;
- }
-
- if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
- render_reference_x = xtraps[0].left.p1.x >> 16;
- render_reference_y = xtraps[0].left.p1.y >> 16;
- } else {
- render_reference_x = xtraps[0].left.p2.x >> 16;
- render_reference_y = xtraps[0].left.p2.y >> 16;
- }
- render_reference_x += src->x + dst_x;
- render_reference_y += src->y + dst_y;
-
- _cairo_xcb_surface_set_precision (dst, info->antialias);
- _cairo_xcb_connection_render_trapezoids (dst->connection,
- _render_operator (op),
- src->picture,
- dst->picture,
- xrender_format,
- render_reference_x,
- render_reference_y,
- traps->num_traps, xtraps);
-
- cairo_surface_destroy (&src->base);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* low-level composite driver */
-
-static cairo_xcb_surface_t *
-get_clip_surface (const cairo_clip_t *clip,
- cairo_xcb_surface_t *target,
- int *tx, int *ty)
-{
- cairo_surface_t *surface;
- cairo_status_t status;
-
- surface = _cairo_surface_create_scratch (&target->base,
- CAIRO_CONTENT_ALPHA,
- clip->extents.width,
- clip->extents.height,
- CAIRO_COLOR_WHITE);
- if (unlikely (surface->status))
- return (cairo_xcb_surface_t *) surface;
-
- assert (surface->backend == &_cairo_xcb_surface_backend);
- status = _cairo_clip_combine_with_surface (clip, surface,
- clip->extents.x, clip->extents.y);
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- surface = _cairo_surface_create_in_error (status);
- }
-
- *tx = clip->extents.x;
- *ty = clip->extents.y;
-
- return (cairo_xcb_surface_t *) surface;
-}
-
-typedef cairo_int_status_t
-(*xcb_draw_func_t) (void *closure,
- cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_clip_t *clip);
-
-static void do_unaligned_row(void (*blt)(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage),
- void *closure,
- const cairo_box_t *b,
- int tx, int y, int h,
- uint16_t coverage)
-{
- int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
- int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
- if (x2 > x1) {
- if (! _cairo_fixed_is_integer (b->p1.x)) {
- blt(closure, x1, y, 1, h,
- coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
- x1++;
- }
-
- if (x2 > x1)
- blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
-
- if (! _cairo_fixed_is_integer (b->p2.x))
- blt(closure, x2, y, 1, h,
- coverage * _cairo_fixed_fractional_part (b->p2.x));
- } else
- blt(closure, x1, y, 1, h,
- coverage * (b->p2.x - b->p1.x));
-}
-
-static void do_unaligned_box(void (*blt)(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage),
- void *closure,
- const cairo_box_t *b, int tx, int ty)
-{
- int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
- int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
- if (y2 > y1) {
- if (! _cairo_fixed_is_integer (b->p1.y)) {
- do_unaligned_row(blt, closure, b, tx, y1, 1,
- 256 - _cairo_fixed_fractional_part (b->p1.y));
- y1++;
- }
-
- if (y2 > y1)
- do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
-
- if (! _cairo_fixed_is_integer (b->p2.y))
- do_unaligned_row(blt, closure, b, tx, y2, 1,
- _cairo_fixed_fractional_part (b->p2.y));
- } else
- do_unaligned_row(blt, closure, b, tx, y1, 1,
- b->p2.y - b->p1.y);
-}
-
-
-static void blt_in(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage)
-{
- cairo_xcb_surface_t *mask = closure;
- xcb_render_color_t color;
- xcb_rectangle_t rect;
-
- if (coverage == 0xffff)
- return;
-
- color.red = color.green = color.blue = 0;
- color.alpha = coverage;
-
- rect.x = x;
- rect.y = y;
- rect.width = w;
- rect.height = h;
-
- _cairo_xcb_connection_render_fill_rectangles (mask->connection,
- XCB_RENDER_PICT_OP_IN,
- mask->picture,
- color, 1, &rect);
-}
-
-static cairo_xcb_surface_t *
-_create_composite_mask (cairo_clip_t *clip,
- xcb_draw_func_t draw_func,
- xcb_draw_func_t mask_func,
- void *draw_closure,
- cairo_xcb_surface_t *dst,
- const cairo_rectangle_int_t*extents)
-{
- cairo_xcb_surface_t *surface;
- cairo_bool_t need_clip_combine;
- cairo_int_status_t status;
-
- surface = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA,
- extents->width, extents->height);
- if (unlikely (surface->base.status))
- return surface;
-
- _cairo_xcb_surface_ensure_picture (surface);
-
- surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
- surface->deferred_clear = TRUE;
- surface->base.is_clear = TRUE;
-
- if (mask_func) {
- status = mask_func (draw_closure, surface,
- CAIRO_OPERATOR_ADD, NULL,
- extents->x, extents->y,
- extents, clip);
- if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
- return surface;
- }
-
- /* Is it worth setting the clip region here? */
- status = draw_func (draw_closure, surface,
- CAIRO_OPERATOR_ADD, NULL,
- extents->x, extents->y,
- extents, NULL);
- if (unlikely (status)) {
- cairo_surface_destroy (&surface->base);
- return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
- }
-
- if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
- int i;
-
- for (i = 0; i < clip->num_boxes; i++) {
- cairo_box_t *b = &clip->boxes[i];
-
- if (! _cairo_fixed_is_integer (b->p1.x) ||
- ! _cairo_fixed_is_integer (b->p1.y) ||
- ! _cairo_fixed_is_integer (b->p2.x) ||
- ! _cairo_fixed_is_integer (b->p2.y))
- {
- do_unaligned_box(blt_in, surface, b, extents->x, extents->y);
- }
- }
-
- need_clip_combine = clip->path != NULL;
- } else
- need_clip_combine = ! _cairo_clip_is_region (clip);
-
- if (need_clip_combine) {
- status = _cairo_clip_combine_with_surface (clip, &surface->base,
- extents->x, extents->y);
- if (unlikely (status)) {
- cairo_surface_destroy (&surface->base);
- return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
- }
- }
-
- return surface;
-}
-
-/* Handles compositing with a clip surface when the operator allows
- * us to combine the clip with the mask
- */
-static cairo_status_t
-_clip_and_composite_with_mask (cairo_clip_t *clip,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- xcb_draw_func_t draw_func,
- xcb_draw_func_t mask_func,
- void *draw_closure,
- cairo_xcb_surface_t *dst,
- const cairo_rectangle_int_t*extents)
-{
- cairo_xcb_surface_t *mask;
- cairo_xcb_picture_t *src;
-
- mask = _create_composite_mask (clip,
- draw_func, mask_func, draw_closure,
- dst, extents);
- if (unlikely (mask->base.status))
- return mask->base.status;
-
- if (pattern != NULL || dst->base.content != CAIRO_CONTENT_ALPHA) {
- src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
- if (unlikely (src->base.status)) {
- cairo_surface_destroy (&mask->base);
- return src->base.status;
- }
-
- _cairo_xcb_connection_render_composite (dst->connection,
- _render_operator (op),
- src->picture,
- mask->picture,
- dst->picture,
- extents->x + src->x, extents->y + src->y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
-
- cairo_surface_destroy (&src->base);
- } else {
- _cairo_xcb_connection_render_composite (dst->connection,
- _render_operator (op),
- mask->picture,
- XCB_NONE,
- dst->picture,
- 0, 0,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
- }
- cairo_surface_destroy (&mask->base);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Handles compositing with a clip surface when we have to do the operation
- * in two pieces and combine them together.
- */
-static cairo_status_t
-_clip_and_composite_combine (cairo_clip_t *clip,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- xcb_draw_func_t draw_func,
- void *draw_closure,
- cairo_xcb_surface_t *dst,
- const cairo_rectangle_int_t*extents)
-{
- cairo_xcb_surface_t *tmp;
- cairo_xcb_surface_t *clip_surface;
- int clip_x = 0, clip_y = 0;
- xcb_render_picture_t clip_picture;
- cairo_status_t status;
-
- tmp = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (dst, dst->base.content,
- extents->width, extents->height);
- if (unlikely (tmp->base.status))
- return tmp->base.status;
-
- /* create_similar() could have done a fallback to an image surface */
- assert (tmp->base.backend == &_cairo_xcb_surface_backend);
-
- _cairo_xcb_surface_ensure_picture (tmp);
-
- if (pattern == NULL) {
- status = (*draw_func) (draw_closure, tmp,
- CAIRO_OPERATOR_ADD, NULL,
- extents->x, extents->y,
- extents, NULL);
- } else {
- /* Initialize the temporary surface from the destination surface */
- if (! dst->base.is_clear ||
- (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) == 0)
- {
- /* XCopyArea may actually be quicker here.
- * A good driver should translate if appropriate.
- */
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_SRC,
- dst->picture,
- XCB_NONE,
- tmp->picture,
- extents->x, extents->y,
- 0, 0,
- 0, 0,
- extents->width, extents->height);
- }
- else
- {
- xcb_render_color_t clear;
- xcb_rectangle_t xrect;
-
- clear.red = clear.green = clear.blue = clear.alpha = 0;
-
- xrect.x = xrect.y = 0;
- xrect.width = extents->width;
- xrect.height = extents->height;
-
- _cairo_xcb_connection_render_fill_rectangles (dst->connection,
- XCB_RENDER_PICT_OP_CLEAR,
- dst->picture,
- clear, 1, &xrect);
- }
-
- status = (*draw_func) (draw_closure, tmp, op, pattern,
- extents->x, extents->y,
- extents, NULL);
- }
- if (unlikely (status))
- goto CLEANUP_SURFACE;
-
- clip_surface = get_clip_surface (clip, dst, &clip_x, &clip_y);
- status = clip_surface->base.status;
- if (unlikely (status))
- goto CLEANUP_SURFACE;
-
- assert (clip_surface->base.backend == &_cairo_xcb_surface_backend);
- clip_picture = clip_surface->picture;
- assert (clip_picture != XCB_NONE);
-
- if (dst->base.is_clear) {
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_SRC,
- tmp->picture, clip_picture, dst->picture,
- 0, 0,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
- } else {
- /* Punch the clip out of the destination */
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_OUT_REVERSE,
- clip_picture, XCB_NONE, dst->picture,
- extents->x - clip_x,
- extents->y - clip_y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
-
- /* Now add the two results together */
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_ADD,
- tmp->picture, clip_picture, dst->picture,
- 0, 0,
- extents->x - clip_x,
- extents->y - clip_y,
- extents->x, extents->y,
- extents->width, extents->height);
- }
- cairo_surface_destroy (&clip_surface->base);
-
- CLEANUP_SURFACE:
- cairo_surface_destroy (&tmp->base);
-
- return status;
-}
-
-/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
- * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
- */
-static cairo_status_t
-_clip_and_composite_source (cairo_clip_t *clip,
- const cairo_pattern_t *pattern,
- xcb_draw_func_t draw_func,
- xcb_draw_func_t mask_func,
- void *draw_closure,
- cairo_xcb_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_xcb_surface_t *mask;
- cairo_xcb_picture_t *src;
-
- /* Create a surface that is mask IN clip */
- mask = _create_composite_mask (clip,
- draw_func, mask_func, draw_closure,
- dst, extents);
- if (unlikely (mask->base.status))
- return mask->base.status;
-
- src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
- if (unlikely (src->base.status)) {
- cairo_surface_destroy (&mask->base);
- return src->base.status;
- }
-
- if (dst->base.is_clear) {
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_SRC,
- src->picture,
- mask->picture,
- dst->picture,
- extents->x + src->x, extents->y + src->y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
- } else {
- /* Compute dest' = dest OUT (mask IN clip) */
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_OUT_REVERSE,
- mask->picture,
- XCB_NONE,
- dst->picture,
- 0, 0, 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
-
- /* Now compute (src IN (mask IN clip)) ADD dest' */
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_ADD,
- src->picture,
- mask->picture,
- dst->picture,
- extents->x + src->x, extents->y + src->y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
- }
-
- cairo_surface_destroy (&src->base);
- cairo_surface_destroy (&mask->base);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_bool_t
-can_reduce_alpha_op (cairo_operator_t op)
-{
- int iop = op;
- switch (iop) {
- case CAIRO_OPERATOR_OVER:
- case CAIRO_OPERATOR_SOURCE:
- case CAIRO_OPERATOR_ADD:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-static cairo_bool_t
-reduce_alpha_op (cairo_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *pattern)
-{
- return dst->is_clear &&
- dst->content == CAIRO_CONTENT_ALPHA &&
- _cairo_pattern_is_opaque_solid (pattern) &&
- can_reduce_alpha_op (op);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_fixup_unbounded (cairo_xcb_surface_t *dst,
- const cairo_composite_rectangles_t *rects)
-{
- xcb_rectangle_t xrects[4];
- int n;
-
- if (rects->bounded.width == rects->unbounded.width &&
- rects->bounded.height == rects->unbounded.height)
- {
- return CAIRO_STATUS_SUCCESS;
- }
-
- n = 0;
- if (rects->bounded.width == 0 || rects->bounded.height == 0) {
- xrects[n].x = rects->unbounded.x;
- xrects[n].width = rects->unbounded.width;
- xrects[n].y = rects->unbounded.y;
- xrects[n].height = rects->unbounded.height;
- n++;
- } else {
- /* top */
- if (rects->bounded.y != rects->unbounded.y) {
- xrects[n].x = rects->unbounded.x;
- xrects[n].width = rects->unbounded.width;
- xrects[n].y = rects->unbounded.y;
- xrects[n].height = rects->bounded.y - rects->unbounded.y;
- n++;
- }
- /* left */
- if (rects->bounded.x != rects->unbounded.x) {
- xrects[n].x = rects->unbounded.x;
- xrects[n].width = rects->bounded.x - rects->unbounded.x;
- xrects[n].y = rects->bounded.y;
- xrects[n].height = rects->bounded.height;
- n++;
- }
- /* right */
- if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
- xrects[n].x = rects->bounded.x + rects->bounded.width;
- xrects[n].width = rects->unbounded.x + rects->unbounded.width - xrects[n].x;
- xrects[n].y = rects->bounded.y;
- xrects[n].height = rects->bounded.height;
- n++;
- }
- /* bottom */
- if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
- xrects[n].x = rects->unbounded.x;
- xrects[n].width = rects->unbounded.width;
- xrects[n].y = rects->bounded.y + rects->bounded.height;
- xrects[n].height = rects->unbounded.y + rects->unbounded.height - xrects[n].y;
- n++;
- }
- }
-
- if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
- xcb_render_color_t color;
-
- color.red = 0;
- color.green = 0;
- color.blue = 0;
- color.alpha = 0;
-
- _cairo_xcb_connection_render_fill_rectangles (dst->connection,
- XCB_RENDER_PICT_OP_CLEAR,
- dst->picture,
- color, n, xrects);
- } else {
- int i;
- cairo_xcb_picture_t *src;
-
- src = _cairo_xcb_transparent_picture (dst);
- if (unlikely (src->base.status))
- return src->base.status;
-
- for (i = 0; i < n; i++) {
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_CLEAR,
- src->picture, XCB_NONE, dst->picture,
- 0, 0,
- 0, 0,
- xrects[i].x, xrects[i].y,
- xrects[i].width, xrects[i].height);
- }
- cairo_surface_destroy (&src->base);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst,
- const cairo_composite_rectangles_t *rects,
- cairo_clip_t *clip)
-{
- cairo_xcb_surface_t *mask;
- int mask_x = 0, mask_y = 0;
-
- mask = get_clip_surface (clip, dst, &mask_x, &mask_y);
- if (unlikely (mask->base.status))
- return mask->base.status;
-
- /* top */
- if (rects->bounded.y != rects->unbounded.y) {
- int x = rects->unbounded.x;
- int y = rects->unbounded.y;
- int width = rects->unbounded.width;
- int height = rects->bounded.y - y;
-
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_OUT_REVERSE,
- mask->picture, XCB_NONE, dst->picture,
- x - mask_x, y - mask_y,
- 0, 0,
- x, y,
- width, height);
- }
-
- /* left */
- if (rects->bounded.x != rects->unbounded.x) {
- int x = rects->unbounded.x;
- int y = rects->bounded.y;
- int width = rects->bounded.x - x;
- int height = rects->bounded.height;
-
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_OUT_REVERSE,
- mask->picture, XCB_NONE, dst->picture,
- x - mask_x, y - mask_y,
- 0, 0,
- x, y,
- width, height);
- }
-
- /* right */
- if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
- int x = rects->bounded.x + rects->bounded.width;
- int y = rects->bounded.y;
- int width = rects->unbounded.x + rects->unbounded.width - x;
- int height = rects->bounded.height;
-
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_OUT_REVERSE,
- mask->picture, XCB_NONE, dst->picture,
- x - mask_x, y - mask_y,
- 0, 0,
- x, y,
- width, height);
- }
-
- /* bottom */
- if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
- int x = rects->unbounded.x;
- int y = rects->bounded.y + rects->bounded.height;
- int width = rects->unbounded.width;
- int height = rects->unbounded.y + rects->unbounded.height - y;
-
- _cairo_xcb_connection_render_composite (dst->connection,
- XCB_RENDER_PICT_OP_OUT_REVERSE,
- mask->picture, XCB_NONE, dst->picture,
- x - mask_x, y - mask_y,
- 0, 0,
- x, y,
- width, height);
- }
-
- cairo_surface_destroy (&mask->base);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst,
- const cairo_composite_rectangles_t *extents,
- cairo_clip_t *clip,
- cairo_boxes_t *boxes)
-{
- cairo_boxes_t clear;
- cairo_box_t box;
- cairo_status_t status;
- struct _cairo_boxes_chunk *chunk;
- int i;
-
- if (boxes->num_boxes <= 1 && clip == NULL)
- return _cairo_xcb_surface_fixup_unbounded (dst, extents);
-
- _cairo_boxes_init (&clear);
-
- box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
- box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
- box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
- box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
-
- if (clip == NULL) {
- cairo_boxes_t tmp;
-
- _cairo_boxes_init (&tmp);
-
- status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- tmp.chunks.next = &boxes->chunks;
- tmp.num_boxes += boxes->num_boxes;
-
- status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
- CAIRO_FILL_RULE_WINDING,
- &clear);
-
- tmp.chunks.next = NULL;
- } else {
- _cairo_boxes_init_with_clip (&clear, clip);
-
- status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- status = _cairo_boxes_add (&clear,
- CAIRO_ANTIALIAS_DEFAULT,
- &chunk->base[i]);
- if (unlikely (status)) {
- _cairo_boxes_fini (&clear);
- return status;
- }
- }
- }
-
- status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
- CAIRO_FILL_RULE_WINDING,
- &clear);
- }
-
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES)
- status = _render_fill_boxes (dst,
- CAIRO_OPERATOR_CLEAR,
- CAIRO_COLOR_TRANSPARENT,
- &clear);
- else
- status = _cairo_xcb_surface_core_fill_boxes (dst,
- CAIRO_COLOR_TRANSPARENT,
- &clear);
- }
-
- _cairo_boxes_fini (&clear);
-
- return status;
-}
-
-cairo_status_t
-_cairo_xcb_surface_clear (cairo_xcb_surface_t *dst)
-{
- xcb_gcontext_t gc;
- xcb_rectangle_t rect;
- cairo_status_t status;
-
- status = _cairo_xcb_connection_acquire (dst->connection);
- if (unlikely (status))
- return status;
-
- rect.x = rect.y = 0;
- rect.width = dst->width;
- rect.height = dst->height;
-
- if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
- xcb_render_color_t color;
- uint8_t op;
-
- color.red = dst->deferred_clear_color.red_short;
- color.green = dst->deferred_clear_color.green_short;
- color.blue = dst->deferred_clear_color.blue_short;
- color.alpha = dst->deferred_clear_color.alpha_short;
-
- if (color.alpha == 0)
- op = XCB_RENDER_PICT_OP_CLEAR;
- else
- op = XCB_RENDER_PICT_OP_SRC;
-
- _cairo_xcb_surface_ensure_picture (dst);
- _cairo_xcb_connection_render_fill_rectangles (dst->connection,
- op, dst->picture, color,
- 1, &rect);
- } else {
- gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
-
- /* XXX color */
- _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
- dst->drawable, gc,
- 1, &rect);
-
- _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
- }
-
- _cairo_xcb_connection_release (dst->connection);
-
- dst->deferred_clear = FALSE;
- return CAIRO_STATUS_SUCCESS;
-}
-
-enum {
- NEED_CLIP_REGION = 0x1,
- NEED_CLIP_SURFACE = 0x2,
- FORCE_CLIP_REGION = 0x4,
-};
-
-static cairo_bool_t
-need_bounded_clip (cairo_composite_rectangles_t *extents)
-{
- unsigned int flags = NEED_CLIP_REGION;
- if (! _cairo_clip_is_region (extents->clip))
- flags |= NEED_CLIP_SURFACE;
- return flags;
-}
-
-static cairo_bool_t
-need_unbounded_clip (cairo_composite_rectangles_t *extents)
-{
- unsigned int flags = 0;
- if (! extents->is_bounded) {
- flags |= NEED_CLIP_REGION;
- if (! _cairo_clip_is_region (extents->clip))
- flags |= NEED_CLIP_SURFACE;
- }
- if (extents->clip->path != NULL)
- flags |= NEED_CLIP_SURFACE;
- return flags;
-}
-
-static cairo_status_t
-_clip_and_composite (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- xcb_draw_func_t draw_func,
- xcb_draw_func_t mask_func,
- void *draw_closure,
- cairo_composite_rectangles_t*extents,
- unsigned int need_clip)
-{
- cairo_region_t *clip_region = NULL;
- cairo_status_t status;
-
- status = _cairo_xcb_connection_acquire (dst->connection);
- if (unlikely (status))
- return status;
-
- if (dst->deferred_clear) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status)) {
- _cairo_xcb_connection_release (dst->connection);
- return status;
- }
- }
-
- _cairo_xcb_surface_ensure_picture (dst);
-
- if (need_clip & NEED_CLIP_REGION) {
- clip_region = _cairo_clip_get_region (extents->clip);
- if ((need_clip & FORCE_CLIP_REGION) == 0 && clip_region != NULL &&
- cairo_region_contains_rectangle (clip_region,
- &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
- clip_region = NULL;
- if (clip_region != NULL) {
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status)) {
- _cairo_xcb_connection_release (dst->connection);
- return status;
- }
- }
- }
-
- if (reduce_alpha_op (&dst->base, op, src)) {
- op = CAIRO_OPERATOR_ADD;
- src = NULL;
- }
-
- if (extents->bounded.width != 0 && extents->bounded.height != 0) {
- if (op == CAIRO_OPERATOR_SOURCE) {
- status = _clip_and_composite_source (extents->clip, src,
- draw_func, mask_func, draw_closure,
- dst, &extents->bounded);
- } else {
- if (op == CAIRO_OPERATOR_CLEAR) {
- op = CAIRO_OPERATOR_DEST_OUT;
- src = NULL;
- }
-
- if (need_clip & NEED_CLIP_SURFACE) {
- if (extents->is_bounded) {
- status = _clip_and_composite_with_mask (extents->clip, op, src,
- draw_func,
- mask_func,
- draw_closure,
- dst, &extents->bounded);
- } else {
- status = _clip_and_composite_combine (extents->clip, op, src,
- draw_func, draw_closure,
- dst, &extents->bounded);
- }
- } else {
- status = draw_func (draw_closure,
- dst, op, src,
- 0, 0,
- &extents->bounded,
- extents->clip);
- }
- }
- }
-
- if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
- if (need_clip & NEED_CLIP_SURFACE)
- status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, extents->clip);
- else
- status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
- }
-
- if (clip_region)
- _cairo_xcb_surface_clear_clip_region (dst);
-
- _cairo_xcb_connection_release (dst->connection);
-
- return status;
-}
-
-static cairo_status_t
-_core_boxes (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- const cairo_composite_rectangles_t *extents)
-{
- if (! boxes->is_pixel_aligned)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_clip_is_region (extents->clip))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (op == CAIRO_OPERATOR_CLEAR)
- return _cairo_xcb_surface_core_fill_boxes (dst, CAIRO_COLOR_TRANSPARENT, boxes);
-
- if (op == CAIRO_OPERATOR_OVER) {
- if (dst->base.is_clear || _cairo_pattern_is_opaque (src, &extents->bounded))
- op = CAIRO_OPERATOR_SOURCE;
- }
- if (op != CAIRO_OPERATOR_SOURCE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
- return _cairo_xcb_surface_core_fill_boxes (dst,
- &((cairo_solid_pattern_t *) src)->color,
- boxes);
- }
-
- return _cairo_xcb_surface_core_copy_boxes (dst, src, &extents->bounded, boxes);
-}
-
-static cairo_status_t
-_composite_boxes (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- const cairo_composite_rectangles_t *extents)
-{
- cairo_clip_t *clip = extents->clip;
- cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (clip);
- cairo_status_t status;
-
- /* If the boxes are not pixel-aligned, we will need to compute a real mask */
- if (! boxes->is_pixel_aligned)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (need_clip_mask &&
- (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- status = _cairo_xcb_connection_acquire (dst->connection);
- if (unlikely (status))
- return status;
-
- _cairo_xcb_surface_ensure_picture (dst);
- if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES && ! need_clip_mask &&
- (op == CAIRO_OPERATOR_CLEAR || src->type == CAIRO_PATTERN_TYPE_SOLID))
- {
- const cairo_color_t *color;
-
- if (op == CAIRO_OPERATOR_CLEAR)
- color = CAIRO_COLOR_TRANSPARENT;
- else
- color = &((cairo_solid_pattern_t *) src)->color;
-
- status = _render_fill_boxes (dst, op, color, boxes);
- }
- else
- {
- cairo_surface_pattern_t mask;
-
- if (need_clip_mask) {
- cairo_xcb_surface_t *clip_surface;
- int clip_x = 0, clip_y = 0;
-
- clip_surface = get_clip_surface (extents->clip, dst,
- &clip_x, &clip_y);
- if (unlikely (clip_surface->base.status))
- return clip_surface->base.status;
-
- _cairo_pattern_init_for_surface (&mask, &clip_surface->base);
- mask.base.filter = CAIRO_FILTER_NEAREST;
- cairo_matrix_init_translate (&mask.base.matrix,
- -clip_x,
- -clip_y);
- cairo_surface_destroy (&clip_surface->base);
-
- if (op == CAIRO_OPERATOR_CLEAR) {
- src = NULL;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
- }
-
- status = _render_composite_boxes (dst, op, src,
- need_clip_mask ? &mask.base : NULL,
- &extents->bounded, boxes);
-
- if (need_clip_mask)
- _cairo_pattern_fini (&mask.base);
- }
-
- if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
- status =
- _cairo_xcb_surface_fixup_unbounded_boxes (dst, extents,
- clip, boxes);
- }
-
- _cairo_xcb_connection_release (dst->connection);
-
- return status;
-}
-
-static cairo_bool_t
-cairo_boxes_for_each_box (cairo_boxes_t *boxes,
- cairo_bool_t (*func) (cairo_box_t *box,
- void *data),
- void *data)
-{
- struct _cairo_boxes_chunk *chunk;
- int i;
-
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++)
- if (! func (&chunk->base[i], data))
- return FALSE;
- }
-
- return TRUE;
-}
-
-struct _image_contains_box {
- int width, height;
- int tx, ty;
-};
-
-static cairo_bool_t image_contains_box (cairo_box_t *box, void *closure)
-{
- struct _image_contains_box *data = closure;
-
- /* The box is pixel-aligned so the truncation is safe. */
- return
- _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
- _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
- _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
- _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
-}
-
-struct _image_upload_box {
- cairo_xcb_surface_t *surface;
- cairo_image_surface_t *image;
- xcb_gcontext_t gc;
- int tx, ty;
-};
-
-static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
-{
- const struct _image_upload_box *iub = closure;
- /* The box is pixel-aligned so the truncation is safe. */
- int x = _cairo_fixed_integer_part (box->p1.x);
- int y = _cairo_fixed_integer_part (box->p1.y);
- int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
- int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
- int bpp = PIXMAN_FORMAT_BPP (iub->image->pixman_format);
- int len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp);
- if (len == iub->image->stride) {
- _cairo_xcb_connection_put_image (iub->surface->connection,
- iub->surface->drawable,
- iub->gc,
- width, height,
- x, y,
- iub->image->depth,
- iub->image->stride,
- iub->image->data +
- (y + iub->ty) * iub->image->stride +
- (x + iub->tx) * bpp/8);
- } else {
- _cairo_xcb_connection_put_subimage (iub->surface->connection,
- iub->surface->drawable,
- iub->gc,
- x + iub->tx,
- y + iub->ty,
- width, height,
- bpp / 8,
- iub->image->stride,
- x, y,
- iub->image->depth,
- iub->image->data);
- }
-
- return TRUE;
-}
-
-static cairo_status_t
-_upload_image_inplace (cairo_xcb_surface_t *surface,
- const cairo_pattern_t *source,
- cairo_boxes_t *boxes)
-{
- const cairo_surface_pattern_t *pattern;
- struct _image_contains_box icb;
- struct _image_upload_box iub;
- cairo_image_surface_t *image;
- cairo_status_t status;
- int tx, ty;
-
- if (! boxes->is_pixel_aligned)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- pattern = (const cairo_surface_pattern_t *) source;
- if (! _cairo_surface_is_image (pattern->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* Have we already upload this image to a pixmap? */
- {
- cairo_xcb_picture_t *snapshot;
-
- snapshot = (cairo_xcb_picture_t *)
- _cairo_surface_has_snapshot (pattern->surface, &_cairo_xcb_picture_backend);
- if (snapshot != NULL) {
- if (snapshot->screen == surface->screen)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
- }
-
- image = (cairo_image_surface_t *) pattern->surface;
- if (image->format == CAIRO_FORMAT_INVALID)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (image->depth != surface->depth)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* Check that the data is entirely within the image */
- icb.width = image->width;
- icb.height = image->height;
- icb.tx = tx;
- icb.ty = ty;
- if (! cairo_boxes_for_each_box (boxes, image_contains_box, &icb))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (surface->deferred_clear) {
- status = _cairo_xcb_surface_clear (surface);
- if (unlikely (status))
- return status;
- }
-
- status = _cairo_xcb_connection_acquire (surface->connection);
- if (unlikely (status))
- return status;
-
- iub.surface = surface;
- iub.image = image;
- iub.gc = _cairo_xcb_screen_get_gc (surface->screen,
- surface->drawable,
- image->depth);
- iub.tx = tx;
- iub.ty = ty;
- cairo_boxes_for_each_box (boxes, image_upload_box, &iub);
-
- _cairo_xcb_screen_put_gc (surface->screen, image->depth, iub.gc);
- _cairo_xcb_connection_release (surface->connection);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-trim_extents_to_traps (cairo_composite_rectangles_t *extents,
- cairo_traps_t *traps)
-{
- cairo_box_t box;
-
- /* X trims the affected area to the extents of the trapezoids, so
- * we need to compensate when fixing up the unbounded area.
- */
- _cairo_traps_extents (traps, &box);
- return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
-}
-
-static cairo_bool_t
-_mono_edge_is_vertical (const cairo_line_t *line)
-{
- return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
-}
-
-static cairo_bool_t
-_traps_are_pixel_aligned (cairo_traps_t *traps,
- cairo_antialias_t antialias)
-{
- int i;
-
- if (antialias == CAIRO_ANTIALIAS_NONE) {
- for (i = 0; i < traps->num_traps; i++) {
- if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
- ! _mono_edge_is_vertical (&traps->traps[i].right))
- {
- traps->maybe_region = FALSE;
- return FALSE;
- }
- }
- } else {
- for (i = 0; i < traps->num_traps; i++) {
- if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
- traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
- ! _cairo_fixed_is_integer (traps->traps[i].top) ||
- ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
- ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
- ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
- {
- traps->maybe_region = FALSE;
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-static void
-_boxes_for_traps (cairo_boxes_t *boxes,
- cairo_traps_t *traps,
- cairo_antialias_t antialias)
-{
- int i, j;
-
- _cairo_boxes_init (boxes);
-
- boxes->chunks.base = (cairo_box_t *) traps->traps;
- boxes->chunks.size = traps->num_traps;
-
- if (antialias != CAIRO_ANTIALIAS_NONE) {
- for (i = j = 0; i < traps->num_traps; i++) {
- /* Note the traps and boxes alias so we need to take the local copies first. */
- cairo_fixed_t x1 = traps->traps[i].left.p1.x;
- cairo_fixed_t x2 = traps->traps[i].right.p1.x;
- cairo_fixed_t y1 = traps->traps[i].top;
- cairo_fixed_t y2 = traps->traps[i].bottom;
-
- if (x1 == x2 || y1 == y2)
- continue;
-
- boxes->chunks.base[j].p1.x = x1;
- boxes->chunks.base[j].p1.y = y1;
- boxes->chunks.base[j].p2.x = x2;
- boxes->chunks.base[j].p2.y = y2;
- j++;
-
- if (boxes->is_pixel_aligned) {
- boxes->is_pixel_aligned =
- _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
- _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
- }
- }
- } else {
- boxes->is_pixel_aligned = TRUE;
-
- for (i = j = 0; i < traps->num_traps; i++) {
- /* Note the traps and boxes alias so we need to take the local copies first. */
- cairo_fixed_t x1 = traps->traps[i].left.p1.x;
- cairo_fixed_t x2 = traps->traps[i].right.p1.x;
- cairo_fixed_t y1 = traps->traps[i].top;
- cairo_fixed_t y2 = traps->traps[i].bottom;
-
- /* round down here to match Pixman's behavior when using traps. */
- boxes->chunks.base[j].p1.x = _cairo_fixed_round_down (x1);
- boxes->chunks.base[j].p1.y = _cairo_fixed_round_down (y1);
- boxes->chunks.base[j].p2.x = _cairo_fixed_round_down (x2);
- boxes->chunks.base[j].p2.y = _cairo_fixed_round_down (y2);
-
- j += (boxes->chunks.base[j].p1.x != boxes->chunks.base[j].p2.x &&
- boxes->chunks.base[j].p1.y != boxes->chunks.base[j].p2.y);
- }
- }
-
- boxes->num_boxes = j;
- boxes->chunks.count = j;
-}
-
-static cairo_status_t
-_composite_polygon (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_polygon_t *polygon,
- cairo_antialias_t antialias,
- cairo_fill_rule_t fill_rule,
- cairo_composite_rectangles_t *extents)
-{
- composite_traps_info_t traps;
- cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
- cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
- cairo_status_t status;
-
- if (polygon->num_edges == 0) {
- status = CAIRO_STATUS_SUCCESS;
-
- if (! extents->is_bounded) {
- if (cairo_region_contains_rectangle (clip_region, &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
- clip_region = NULL;
-
- if (clip_surface == FALSE) {
- if (clip_region != NULL) {
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- return status;
- }
-
- status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
-
- if (clip_region != NULL)
- _cairo_xcb_surface_clear_clip_region (dst);
- } else {
- status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst,
- extents,
- extents->clip);
- }
- }
-
- return status;
- }
-
- if (extents->clip->path != NULL && extents->is_bounded) {
- cairo_polygon_t clipper;
- cairo_fill_rule_t clipper_fill_rule;
- cairo_antialias_t clipper_antialias;
-
- status = _cairo_clip_get_polygon (extents->clip,
- &clipper,
- &clipper_fill_rule,
- &clipper_antialias);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- if (clipper_antialias == antialias) {
- status = _cairo_polygon_intersect (polygon, fill_rule,
- &clipper, clipper_fill_rule);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
- _cairo_clip_destroy (extents->clip);
- extents->clip = clip;
-
- fill_rule = CAIRO_FILL_RULE_WINDING;
- }
- _cairo_polygon_fini (&clipper);
- }
- }
- }
-
- _cairo_traps_init (&traps.traps);
-
- status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
- if (unlikely (status))
- goto CLEANUP_TRAPS;
-
- if (traps.traps.has_intersections) {
- if (traps.traps.is_rectangular)
- status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
- else if (traps.traps.is_rectilinear)
- status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
- else
- status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
- if (unlikely (status))
- goto CLEANUP_TRAPS;
- }
-
- /* Use a fast path if the trapezoids consist of a simple region,
- * but we can only do this if we do not have a clip surface, or can
- * substitute the mask with the clip.
- */
- if (traps.traps.maybe_region &&
- _traps_are_pixel_aligned (&traps.traps, antialias) &&
- (! clip_surface ||
- (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
- {
- cairo_boxes_t boxes;
-
- _boxes_for_traps (&boxes, &traps.traps, antialias);
- status = _clip_and_composite_boxes (dst, op, source, &boxes, extents);
- }
- else
- {
- /* Otherwise render the trapezoids to a mask and composite in the usual
- * fashion.
- */
- traps.antialias = antialias;
- status = trim_extents_to_traps (extents, &traps.traps);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- unsigned int flags = 0;
-
- /* For unbounded operations, the X11 server will estimate the
- * affected rectangle and apply the operation to that. However,
- * there are cases where this is an overestimate (e.g. the
- * clip-fill-{eo,nz}-unbounded test).
- *
- * The clip will trim that overestimate to our expectations.
- */
- if (! extents->is_bounded)
- flags |= FORCE_CLIP_REGION;
-
- status = _clip_and_composite (dst, op, source, _composite_traps,
- NULL, &traps, extents,
- need_unbounded_clip (extents) | flags);
- }
- }
-
-CLEANUP_TRAPS:
- _cairo_traps_fini (&traps.traps);
-
- return status;
-}
-
-static cairo_status_t
-_clip_and_composite_boxes (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- cairo_composite_rectangles_t *extents)
-{
- composite_traps_info_t info;
- cairo_int_status_t status;
-
- if (boxes->num_boxes == 0 && extents->is_bounded)
- return CAIRO_STATUS_SUCCESS;
-
- if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
- (op == CAIRO_OPERATOR_SOURCE ||
- (dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))))
- {
- if (boxes->num_boxes == 1 &&
- extents->bounded.width == dst->width &&
- extents->bounded.height == dst->height)
- {
- op = CAIRO_OPERATOR_SOURCE;
- dst->deferred_clear = FALSE;
- }
-
- status = _upload_image_inplace (dst, src, boxes);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
- if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS &&
- extents->clip->path != NULL && extents->is_bounded) {
- cairo_polygon_t polygon;
- cairo_fill_rule_t fill_rule;
- cairo_antialias_t antialias;
- cairo_clip_t *clip;
-
- clip = _cairo_clip_copy (extents->clip);
- clip = _cairo_clip_intersect_boxes (clip, boxes);
- if (_cairo_clip_is_all_clipped (clip))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
- status = _cairo_clip_get_polygon (clip, &polygon,
- &fill_rule, &antialias);
- _cairo_clip_path_destroy (clip->path);
- clip->path = NULL;
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- cairo_clip_t *saved_clip = extents->clip;
- extents->clip = clip;
- status = _composite_polygon (dst, op, src,
- &polygon,
- antialias,
- fill_rule,
- extents);
- if (extents->clip != clip)
- clip = NULL;
- extents->clip = saved_clip;
- _cairo_polygon_fini (&polygon);
- }
- if (clip)
- _cairo_clip_destroy (clip);
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- if (dst->deferred_clear) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status))
- return status;
- }
-
- if (boxes->is_pixel_aligned &&
- _cairo_clip_is_region (extents->clip) &&
- op == CAIRO_OPERATOR_SOURCE) {
- status = _upload_image_inplace (dst, src, boxes);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- if ((dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
- return _core_boxes (dst, op, src, boxes, extents);
-
- /* Use a fast path if the boxes are pixel aligned */
- status = _composite_boxes (dst, op, src, boxes, extents);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- if ((dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* Otherwise render via a mask and composite in the usual fashion. */
- status = _cairo_traps_init_boxes (&info.traps, boxes);
- if (unlikely (status))
- return status;
-
- info.antialias = CAIRO_ANTIALIAS_DEFAULT;
- status = trim_extents_to_traps (extents, &info.traps);
- if (status == CAIRO_INT_STATUS_SUCCESS) {
- status = _clip_and_composite (dst, op, src,
- _composite_traps, NULL, &info,
- extents, need_unbounded_clip (extents));
- }
-
- _cairo_traps_fini (&info.traps);
- return status;
-}
-
-static cairo_int_status_t
-_composite_mask (void *closure,
- cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_clip_t *clip)
-{
- const cairo_pattern_t *mask_pattern = closure;
- cairo_xcb_picture_t *src, *mask = NULL;
- cairo_status_t status;
-
- if (dst->base.is_clear) {
- if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)
- op = CAIRO_OPERATOR_SOURCE;
- }
-
- if (op == CAIRO_OPERATOR_SOURCE && clip == NULL)
- dst->deferred_clear = FALSE;
-
- if (dst->deferred_clear) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status))
- return status;
- }
-
- if (src_pattern != NULL) {
- src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
- if (unlikely (src->base.status))
- return src->base.status;
-
- mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
- if (unlikely (mask->base.status)) {
- cairo_surface_destroy (&src->base);
- return mask->base.status;
- }
-
- _cairo_xcb_connection_render_composite (dst->connection,
- _render_operator (op),
- src->picture,
- mask->picture,
- dst->picture,
- extents->x + src->x, extents->y + src->y,
- extents->x + mask->x, extents->y + mask->y,
- extents->x - dst_x, extents->y - dst_y,
- extents->width, extents->height);
- cairo_surface_destroy (&mask->base);
- cairo_surface_destroy (&src->base);
- } else {
- src = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
- if (unlikely (src->base.status))
- return src->base.status;
-
- _cairo_xcb_connection_render_composite (dst->connection,
- _render_operator (op),
- src->picture,
- XCB_NONE,
- dst->picture,
- extents->x + src->x, extents->y + src->y,
- 0, 0,
- extents->x - dst_x, extents->y - dst_y,
- extents->width, extents->height);
- cairo_surface_destroy (&src->base);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-struct composite_box_info {
- cairo_xcb_surface_t *dst;
- cairo_xcb_picture_t *src;
- uint8_t op;
-};
-
-static void composite_box(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage)
-{
- struct composite_box_info *info = closure;
-
- if (coverage < 0xff00) {
- cairo_xcb_picture_t *mask;
- cairo_color_t color;
-
- color.red_short = color.green_short = color.blue_short = 0;
- color.alpha_short = coverage;
-
- mask = _solid_picture (info->dst, &color);
- if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
- _cairo_xcb_connection_render_composite (info->dst->connection,
- info->op,
- info->src->picture,
- mask->picture,
- info->dst->picture,
- x + info->src->x, y + info->src->y,
- 0, 0,
- x, y,
- w, h);
- }
- cairo_surface_destroy (&mask->base);
- } else {
- _cairo_xcb_connection_render_composite (info->dst->connection,
- info->op,
- info->src->picture,
- XCB_NONE,
- info->dst->picture,
- x + info->src->x, y + info->src->y,
- 0, 0,
- x, y,
- w, h);
- }
-}
-
-static cairo_int_status_t
-_composite_mask_clip_boxes (void *closure,
- cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_clip_t *clip)
-{
- struct composite_box_info info;
- cairo_status_t status;
- int i;
-
- assert (src_pattern == NULL);
- assert (op == CAIRO_OPERATOR_ADD);
- assert (dst->base.is_clear);
-
- if (clip->num_boxes > 1) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status))
- return status;
- }
-
- info.op = XCB_RENDER_PICT_OP_SRC;
- info.dst = dst;
- info.src = _cairo_xcb_picture_for_pattern (dst, closure, extents);
- if (unlikely (info.src->base.status))
- return info.src->base.status;
-
- info.src->x += dst_x;
- info.src->y += dst_y;
-
- for (i = 0; i < clip->num_boxes; i++)
- do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
- cairo_surface_destroy (&info.src->base);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_composite_mask_clip (void *closure,
- cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_clip_t *clip)
-{
- const cairo_pattern_t *mask_pattern = closure;
- cairo_polygon_t polygon;
- cairo_fill_rule_t fill_rule;
- composite_traps_info_t info;
- cairo_status_t status;
-
- assert (src_pattern == NULL);
- assert (op == CAIRO_OPERATOR_ADD);
- assert (dst->base.is_clear);
-
- status = _cairo_clip_get_polygon (clip, &polygon,
- &fill_rule, &info.antialias);
- if (unlikely (status))
- return status;
-
- _cairo_traps_init (&info.traps);
- status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
- &polygon,
- fill_rule);
- _cairo_polygon_fini (&polygon);
- if (unlikely (status))
- return status;
-
- if (info.traps.has_intersections) {
- if (info.traps.is_rectangular)
- status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
- else if (info.traps.is_rectilinear)
- status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
- else
- status = _cairo_bentley_ottmann_tessellate_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
- if (unlikely (status)) {
- _cairo_traps_fini (&info.traps);
- return status;
- }
- }
-
- status = _composite_traps (&info,
- dst, CAIRO_OPERATOR_SOURCE, mask_pattern,
- dst_x, dst_y,
- extents, NULL);
- _cairo_traps_fini (&info.traps);
-
- return status;
-}
-
-struct composite_opacity_info {
- uint8_t op;
- cairo_xcb_surface_t *dst;
- cairo_xcb_picture_t *src;
- double opacity;
-};
-
-static void composite_opacity(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage)
-{
- struct composite_opacity_info *info = closure;
- cairo_xcb_picture_t *mask;
- cairo_color_t color;
-
- color.red_short = color.green_short = color.blue_short = 0;
- color.alpha_short = info->opacity * coverage;
-
- mask = _solid_picture (info->dst, &color);
- if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
- if (info->src) {
- _cairo_xcb_connection_render_composite (info->dst->connection,
- info->op,
- info->src->picture,
- mask->picture,
- info->dst->picture,
- x + info->src->x, y + info->src->y,
- 0, 0,
- x, y,
- w, h);
- } else {
- _cairo_xcb_connection_render_composite (info->dst->connection,
- info->op,
- mask->picture,
- XCB_NONE,
- info->dst->picture,
- 0, 0,
- 0, 0,
- x, y,
- w, h);
- }
- }
-
- cairo_surface_destroy (&mask->base);
-}
-
-static cairo_int_status_t
-_composite_opacity_boxes (void *closure,
- cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_clip_t *clip)
-{
- const cairo_solid_pattern_t *mask_pattern = closure;
- struct composite_opacity_info info;
- cairo_status_t status;
- int i;
-
- if (dst->base.is_clear) {
- if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)
- op = CAIRO_OPERATOR_SOURCE;
- }
-
- if (op == CAIRO_OPERATOR_SOURCE &&
- (clip == NULL ||
- (clip->extents.width >= extents->width &&
- clip->extents.height >= extents->height)))
- dst->deferred_clear = FALSE;
-
- if (dst->deferred_clear) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status))
- return status;
- }
-
- info.op = _render_operator (op);
- info.dst = dst;
-
- if (src_pattern != NULL) {
- info.src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
- if (unlikely (info.src->base.status))
- return info.src->base.status;
- } else
- info.src = NULL;
-
- info.opacity = mask_pattern->color.alpha;
-
- /* XXX for lots of boxes create a clip region for the fully opaque areas */
- if (clip) {
- for (i = 0; i < clip->num_boxes; i++)
- do_unaligned_box(composite_opacity, &info,
- &clip->boxes[i], dst_x, dst_y);
- } else {
- composite_opacity(&info,
- extents->x - dst_x,
- extents->y - dst_y,
- extents->width,
- extents->height,
- 0xffff);
- }
- cairo_surface_destroy (&info.src->base);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* high level rasteriser -> compositor */
-
-cairo_int_status_t
-_cairo_xcb_render_compositor_paint (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite)
-{
- cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
- cairo_operator_t op = composite->op;
- cairo_pattern_t *source = &composite->source_pattern.base;
- cairo_boxes_t boxes;
- cairo_status_t status;
-
- if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
- CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- if (composite->clip == NULL &&
- source->type == CAIRO_PATTERN_TYPE_SOLID &&
- (op == CAIRO_OPERATOR_SOURCE ||
- op == CAIRO_OPERATOR_CLEAR ||
- (surface->base.is_clear &&
- (op == CAIRO_OPERATOR_ADD || op == CAIRO_OPERATOR_OVER))))
- {
- surface->deferred_clear = TRUE;
- surface->deferred_clear_color = composite->source_pattern.solid.color;
- return CAIRO_STATUS_SUCCESS;
- }
-
- _cairo_clip_steal_boxes(composite->clip, &boxes);
- status = _clip_and_composite_boxes (surface, op, source, &boxes, composite);
- _cairo_clip_unsteal_boxes (composite->clip, &boxes);
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_xcb_render_compositor_mask (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite)
-{
- cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
- cairo_operator_t op = composite->op;
- cairo_pattern_t *source = &composite->source_pattern.base;
- cairo_pattern_t *mask = &composite->mask_pattern.base;
- cairo_status_t status;
-
- if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if ((surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
- composite->clip->path == NULL &&
- ! _cairo_clip_is_region (composite->clip)) {
- status = _clip_and_composite (surface, op, source,
- _composite_opacity_boxes,
- _composite_opacity_boxes,
- (void *) mask,
- composite, need_unbounded_clip (composite));
- } else {
- xcb_draw_func_t mask_func = NULL;
- if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)
- mask_func = composite->clip->path ? _composite_mask_clip : _composite_mask_clip_boxes;
- status = _clip_and_composite (surface, op, source,
- _composite_mask, mask_func,
- (void *) mask,
- composite, need_bounded_clip (composite));
- }
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_composite_rectangles_t *extents)
-{
- cairo_polygon_t polygon;
- cairo_status_t status;
-
- _cairo_polygon_init_with_clip (&polygon, extents->clip);
- status = _cairo_path_fixed_stroke_to_polygon (path,
- stroke_style,
- ctm, ctm_inverse,
- tolerance,
- &polygon);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _composite_polygon (dst, op, source,
- &polygon, antialias,
- CAIRO_FILL_RULE_WINDING,
- extents);
- }
- _cairo_polygon_fini (&polygon);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_composite_rectangles_t *extents)
-{
- cairo_surface_t *image;
- cairo_status_t status;
- cairo_clip_t *clip;
- int x, y;
-
- x = extents->bounded.x;
- y = extents->bounded.y;
- image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_FORMAT_A8,
- extents->bounded.width,
- extents->bounded.height);
- if (unlikely (image->status))
- return image->status;
-
- clip = _cairo_clip_copy_region (extents->clip);
- status = _cairo_surface_offset_stroke (image, x, y,
- CAIRO_OPERATOR_ADD,
- &_cairo_pattern_white.base,
- path, stroke_style,
- ctm, ctm_inverse,
- tolerance, antialias,
- clip);
- _cairo_clip_destroy (clip);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- cairo_surface_pattern_t mask;
-
- _cairo_pattern_init_for_surface (&mask, image);
- mask.base.filter = CAIRO_FILTER_NEAREST;
-
- cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
- status = _clip_and_composite (dst, op, source,
- _composite_mask, NULL, &mask.base,
- extents, need_bounded_clip (extents));
- _cairo_pattern_fini (&mask.base);
- }
-
- cairo_surface_finish (image);
- cairo_surface_destroy (image);
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_xcb_render_compositor_stroke (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
- cairo_operator_t op = composite->op;
- cairo_pattern_t *source = &composite->source_pattern.base;
- cairo_int_status_t status;
-
- if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
- CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- _cairo_boxes_init_with_clip (&boxes, composite->clip);
- status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
- style,
- ctm,
- antialias,
- &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _clip_and_composite_boxes (surface, op, source,
- &boxes, composite);
- }
- _cairo_boxes_fini (&boxes);
- }
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) {
- status = _cairo_xcb_surface_render_stroke_as_polygon (surface, op, source,
- path, style,
- ctm, ctm_inverse,
- tolerance, antialias,
- composite);
- } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
- status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source,
- path, style,
- ctm, ctm_inverse,
- tolerance, antialias,
- composite);
- } else {
- ASSERT_NOT_REACHED;
- }
- }
-
- return status;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t*source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_composite_rectangles_t *extents)
-{
- cairo_polygon_t polygon;
- cairo_status_t status;
-
- _cairo_polygon_init_with_clip (&polygon, extents->clip);
- status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _composite_polygon (dst, op, source,
- &polygon,
- antialias,
- fill_rule,
- extents);
- }
- _cairo_polygon_fini (&polygon);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_composite_rectangles_t *extents)
-{
- cairo_surface_t *image;
- cairo_status_t status;
- cairo_clip_t *clip;
- int x, y;
-
- x = extents->bounded.x;
- y = extents->bounded.y;
- image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_FORMAT_A8,
- extents->bounded.width,
- extents->bounded.height);
- if (unlikely (image->status))
- return image->status;
-
- clip = _cairo_clip_copy_region (extents->clip);
- status = _cairo_surface_offset_fill (image, x, y,
- CAIRO_OPERATOR_ADD,
- &_cairo_pattern_white.base,
- path, fill_rule, tolerance, antialias,
- clip);
- _cairo_clip_destroy (clip);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- cairo_surface_pattern_t mask;
-
- _cairo_pattern_init_for_surface (&mask, image);
- mask.base.filter = CAIRO_FILTER_NEAREST;
-
- cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
- status = _clip_and_composite (dst, op, source,
- _composite_mask, NULL, &mask.base,
- extents, need_bounded_clip (extents));
-
- _cairo_pattern_fini (&mask.base);
- }
-
- cairo_surface_finish (image);
- cairo_surface_destroy (image);
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_xcb_render_compositor_fill (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
- cairo_operator_t op = composite->op;
- cairo_pattern_t *source = &composite->source_pattern.base;
- cairo_int_status_t status;
-
- if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
- CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_fill_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- _cairo_boxes_init_with_clip (&boxes, composite->clip);
- status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
- fill_rule,
- antialias,
- &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _clip_and_composite_boxes (surface, op, source,
- &boxes, composite);
- }
- _cairo_boxes_fini (&boxes);
- }
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) {
- status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path,
- fill_rule, tolerance, antialias,
- composite);
- } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
- status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path,
- fill_rule, tolerance, antialias,
- composite);
- } else {
- ASSERT_NOT_REACHED;
- }
- }
-
- return status;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_composite_rectangles_t *extents)
-{
- cairo_surface_t *image;
- cairo_content_t content;
- cairo_status_t status;
- cairo_clip_t *clip;
- int x, y;
-
- content = CAIRO_CONTENT_ALPHA;
- if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
- content = CAIRO_CONTENT_COLOR_ALPHA;
-
- x = extents->bounded.x;
- y = extents->bounded.y;
- image = _cairo_xcb_surface_create_similar_image (dst,
- _cairo_format_from_content (content),
- extents->bounded.width,
- extents->bounded.height);
- if (unlikely (image->status))
- return image->status;
-
- clip = _cairo_clip_copy_region (extents->clip);
- status = _cairo_surface_offset_glyphs (image, x, y,
- CAIRO_OPERATOR_ADD,
- &_cairo_pattern_white.base,
- scaled_font, glyphs, num_glyphs,
- clip);
- _cairo_clip_destroy (clip);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- cairo_surface_pattern_t mask;
-
- _cairo_pattern_init_for_surface (&mask, image);
- mask.base.filter = CAIRO_FILTER_NEAREST;
- if (content & CAIRO_CONTENT_COLOR)
- mask.base.has_component_alpha = TRUE;
-
- cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
- status = _clip_and_composite (dst, op, source,
- _composite_mask, NULL, &mask.base,
- extents, need_bounded_clip (extents));
-
- _cairo_pattern_fini (&mask.base);
- }
-
- cairo_surface_finish (image);
- cairo_surface_destroy (image);
-
- return status;
-}
-
-/* Build a struct of the same size of #cairo_glyph_t that can be used both as
- * an input glyph with double coordinates, and as "working" glyph with
- * integer from-current-point offsets. */
-typedef union {
- cairo_glyph_t d;
- unsigned long index;
- struct {
- unsigned long index;
- int x;
- int y;
- } i;
-} cairo_xcb_glyph_t;
-
-/* compile-time assert that #cairo_xcb_glyph_t is the same size as #cairo_glyph_t */
-COMPILE_TIME_ASSERT (sizeof (cairo_xcb_glyph_t) == sizeof (cairo_glyph_t));
-
-typedef struct {
- cairo_scaled_font_t *font;
- cairo_xcb_glyph_t *glyphs;
- int num_glyphs;
- cairo_bool_t use_mask;
-} composite_glyphs_info_t;
-
-static cairo_status_t
-_can_composite_glyphs (cairo_xcb_surface_t *dst,
- cairo_rectangle_int_t *extents,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int *num_glyphs)
-{
-#define GLYPH_CACHE_SIZE 64
- cairo_box_t bbox_cache[GLYPH_CACHE_SIZE];
- unsigned long glyph_cache[GLYPH_CACHE_SIZE];
-#undef GLYPH_CACHE_SIZE
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_glyph_t *glyphs_end, *valid_glyphs;
- const int max_glyph_size = dst->connection->maximum_request_length - 64;
-
- /* We must initialize the cache with values that cannot match the
- * "hash" to guarantee that when compared for the first time they
- * will result in a mismatch. The hash function is simply modulus,
- * so we cannot use 0 in glyph_cache[0], but we can use it in all
- * other array cells.
- */
- memset (glyph_cache, 0, sizeof (glyph_cache));
- glyph_cache[0] = 1;
-
- /* Scan for oversized glyphs or glyphs outside the representable
- * range and fallback in that case, discard glyphs outside of the
- * image.
- */
- valid_glyphs = glyphs;
- for (glyphs_end = glyphs + *num_glyphs; glyphs != glyphs_end; glyphs++) {
- double x1, y1, x2, y2;
- cairo_scaled_glyph_t *glyph;
- cairo_box_t *bbox;
- int width, height, len;
- int g;
-
- g = glyphs->index % ARRAY_LENGTH (glyph_cache);
- if (glyph_cache[g] != glyphs->index) {
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyphs->index,
- CAIRO_SCALED_GLYPH_INFO_METRICS,
- &glyph);
- if (unlikely (status))
- break;
-
- glyph_cache[g] = glyphs->index;
- bbox_cache[g] = glyph->bbox;
- }
- bbox = &bbox_cache[g];
-
- /* Drop glyphs outside the clipping */
- x1 = _cairo_fixed_to_double (bbox->p1.x);
- y1 = _cairo_fixed_to_double (bbox->p1.y);
- y2 = _cairo_fixed_to_double (bbox->p2.y);
- x2 = _cairo_fixed_to_double (bbox->p2.x);
- if (unlikely (glyphs->x + x2 <= extents->x ||
- glyphs->y + y2 <= extents->y ||
- glyphs->x + x1 >= extents->x + extents->width ||
- glyphs->y + y1 >= extents->y + extents->height))
- {
- (*num_glyphs)--;
- continue;
- }
-
- /* XRenderAddGlyph does not handle a glyph surface larger than
- * the extended maximum XRequest size.
- */
- width = _cairo_fixed_integer_ceil (bbox->p2.x - bbox->p1.x);
- height = _cairo_fixed_integer_ceil (bbox->p2.y - bbox->p1.y);
- len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, 32) * height;
- if (unlikely (len >= max_glyph_size)) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- break;
- }
-
- /* The glyph coordinates must be representable in an int16_t.
- * When possible, they will be expressed as an offset from the
- * previous glyph, otherwise they will be an offset from the
- * operation extents or from the surface origin. If the last
- * two options are not valid, fallback.
- */
- if (unlikely (glyphs->x > INT16_MAX ||
- glyphs->y > INT16_MAX ||
- glyphs->x - extents->x < INT16_MIN ||
- glyphs->y - extents->y < INT16_MIN))
- {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- break;
- }
-
-
- if (unlikely (valid_glyphs != glyphs))
- *valid_glyphs = *glyphs;
- valid_glyphs++;
- }
-
- if (unlikely (valid_glyphs != glyphs)) {
- for (; glyphs != glyphs_end; glyphs++) {
- *valid_glyphs = *glyphs;
- valid_glyphs++;
- }
- }
-
- return status;
-}
-
-/* Start a new element for the first glyph,
- * or for any glyph that has unexpected position,
- * or if current element has too many glyphs
- * (Xrender limits each element to 252 glyphs, we limit them to 128)
- *
- * These same conditions need to be mirrored between
- * _cairo_xcb_surface_emit_glyphs and _emit_glyph_chunks
- */
-#define _start_new_glyph_elt(count, glyph) \
- (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
-
-/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
- * enough room for padding */
-typedef struct {
- uint8_t len;
- uint8_t pad1;
- uint16_t pad2;
- int16_t deltax;
- int16_t deltay;
-} x_glyph_elt_t;
-#define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4)
-
-static void
-_cairo_xcb_font_destroy (cairo_xcb_font_t *font)
-{
- int i;
-
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xcb_font_glyphset_info_t *info;
-
- info = &font->glyphset_info[i];
- free (info->pending_free_glyphs);
- }
-
- cairo_list_del (&font->base.link);
- cairo_list_del (&font->link);
-
- _cairo_xcb_connection_destroy (font->connection);
-
- free (font);
-}
-
-static void
-_cairo_xcb_font_fini (cairo_scaled_font_private_t *abstract_private,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_font_t *font_private = (cairo_xcb_font_t *)abstract_private;
- cairo_xcb_connection_t *connection;
- cairo_bool_t have_connection;
- cairo_status_t status;
- int i;
-
- connection = font_private->connection;
-
- status = _cairo_xcb_connection_acquire (connection);
- have_connection = status == CAIRO_STATUS_SUCCESS;
-
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xcb_font_glyphset_info_t *info;
-
- info = &font_private->glyphset_info[i];
- if (info->glyphset && status == CAIRO_STATUS_SUCCESS) {
- _cairo_xcb_connection_render_free_glyph_set (connection,
- info->glyphset);
- }
- }
-
- if (have_connection)
- _cairo_xcb_connection_release (connection);
-
- _cairo_xcb_font_destroy (font_private);
-}
-
-
-static cairo_xcb_font_t *
-_cairo_xcb_font_create (cairo_xcb_connection_t *connection,
- cairo_scaled_font_t *font)
-{
- cairo_xcb_font_t *priv;
- int i;
-
- priv = _cairo_malloc (sizeof (cairo_xcb_font_t));
- if (unlikely (priv == NULL))
- return NULL;
-
- _cairo_scaled_font_attach_private (font, &priv->base, connection,
- _cairo_xcb_font_fini);
-
- priv->scaled_font = font;
- priv->connection = _cairo_xcb_connection_reference (connection);
- cairo_list_add (&priv->link, &connection->fonts);
-
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xcb_font_glyphset_info_t *info = &priv->glyphset_info[i];
- switch (i) {
- case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
- case GLYPHSET_INDEX_A8: info->format = CAIRO_FORMAT_A8; break;
- case GLYPHSET_INDEX_A1: info->format = CAIRO_FORMAT_A1; break;
- default: ASSERT_NOT_REACHED; break;
- }
- info->xrender_format = 0;
- info->glyphset = XCB_NONE;
- info->pending_free_glyphs = NULL;
- }
-
- return priv;
-}
-
-void
-_cairo_xcb_font_close (cairo_xcb_font_t *font)
-{
- cairo_scaled_font_t *scaled_font;
-
- scaled_font = font->scaled_font;
-
- //scaled_font->surface_private = NULL;
- _cairo_scaled_font_reset_cache (scaled_font);
-
- _cairo_xcb_font_destroy (font);
-}
-
-static void
-_cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection,
- cairo_xcb_font_glyphset_free_glyphs_t *to_free)
-{
- _cairo_xcb_connection_render_free_glyphs (connection,
- to_free->glyphset,
- to_free->glyph_count,
- to_free->glyph_indices);
-}
-
-static int
-_cairo_xcb_get_glyphset_index_for_format (cairo_format_t format)
-{
- if (format == CAIRO_FORMAT_A8)
- return GLYPHSET_INDEX_A8;
- if (format == CAIRO_FORMAT_A1)
- return GLYPHSET_INDEX_A1;
-
- assert (format == CAIRO_FORMAT_ARGB32);
- return GLYPHSET_INDEX_ARGB32;
-}
-
-
-
-static inline cairo_xcb_font_t *
-_cairo_xcb_font_get (const cairo_xcb_connection_t *c,
- cairo_scaled_font_t *font)
-{
- return (cairo_xcb_font_t *)_cairo_scaled_font_find_private (font, c);
-}
-
-
-static cairo_xcb_font_glyphset_info_t *
-_cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_xcb_connection_t *c,
- cairo_scaled_font_t *font,
- cairo_format_t format)
-{
- cairo_xcb_font_t *priv;
- cairo_xcb_font_glyphset_info_t *info;
- int glyphset_index;
-
- glyphset_index = _cairo_xcb_get_glyphset_index_for_format (format);
-
- priv = _cairo_xcb_font_get (c, font);
- if (priv == NULL) {
- priv = _cairo_xcb_font_create (c, font);
- if (priv == NULL)
- return NULL;
- }
-
- info = &priv->glyphset_info[glyphset_index];
- if (info->glyphset == XCB_NONE) {
- info->glyphset = _cairo_xcb_connection_get_xid (c);
- info->xrender_format = c->standard_formats[info->format];
-
- _cairo_xcb_connection_render_create_glyph_set (c,
- info->glyphset,
- info->xrender_format);
- }
-
- return info;
-}
-
-static cairo_bool_t
-_cairo_xcb_glyphset_info_has_pending_free_glyph (
- cairo_xcb_font_glyphset_info_t *info,
- unsigned long glyph_index)
-{
- if (info->pending_free_glyphs != NULL) {
- cairo_xcb_font_glyphset_free_glyphs_t *to_free;
- int i;
-
- to_free = info->pending_free_glyphs;
- for (i = 0; i < to_free->glyph_count; i++) {
- if (to_free->glyph_indices[i] == glyph_index) {
- to_free->glyph_count--;
- memmove (&to_free->glyph_indices[i],
- &to_free->glyph_indices[i+1],
- (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-typedef struct {
- cairo_scaled_glyph_private_t base;
-
- cairo_xcb_font_glyphset_info_t *glyphset;
-} cairo_xcb_glyph_private_t;
-
-static cairo_xcb_font_glyphset_info_t *
-_cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (cairo_xcb_connection_t *c,
- cairo_scaled_font_t *font,
- unsigned long glyph_index,
- cairo_image_surface_t *surface)
-{
- cairo_xcb_font_t *priv;
- int i;
-
- priv = _cairo_xcb_font_get (c, font);
- if (priv == NULL)
- return NULL;
-
- if (surface != NULL) {
- i = _cairo_xcb_get_glyphset_index_for_format (surface->format);
-
- if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
- &priv->glyphset_info[i],
- glyph_index))
- {
- return &priv->glyphset_info[i];
- }
- } else {
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
- &priv->glyphset_info[i],
- glyph_index))
- {
- return &priv->glyphset_info[i];
- }
- }
- }
-
- return NULL;
-}
-
-static void
-_cairo_xcb_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
- cairo_scaled_glyph_t *glyph,
- cairo_scaled_font_t *font)
-{
- cairo_xcb_glyph_private_t *priv = (cairo_xcb_glyph_private_t *)glyph_private;
-
- if (! font->finished) {
- cairo_xcb_font_glyphset_info_t *info = priv->glyphset;
- cairo_xcb_font_glyphset_free_glyphs_t *to_free;
- cairo_xcb_font_t *font_private;
-
- font_private = _cairo_xcb_font_get (glyph_private->key, font);
- assert (font_private);
-
- to_free = info->pending_free_glyphs;
- if (to_free != NULL &&
- to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
- {
- _cairo_xcb_render_free_glyphs (font_private->connection, to_free);
- to_free = info->pending_free_glyphs = NULL;
- }
-
- if (to_free == NULL) {
- to_free = _cairo_malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t));
- if (unlikely (to_free == NULL)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return; /* XXX cannot propagate failure */
- }
-
- to_free->glyphset = info->glyphset;
- to_free->glyph_count = 0;
- info->pending_free_glyphs = to_free;
- }
-
- to_free->glyph_indices[to_free->glyph_count++] =
- _cairo_scaled_glyph_index (glyph);
- }
-
- cairo_list_del (&glyph_private->link);
- free (glyph_private);
-}
-
-
-static cairo_status_t
-_cairo_xcb_glyph_attach (cairo_xcb_connection_t *c,
- cairo_scaled_glyph_t *glyph,
- cairo_xcb_font_glyphset_info_t *info)
-{
- cairo_xcb_glyph_private_t *priv;
-
- priv = _cairo_malloc (sizeof (*priv));
- if (unlikely (priv == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- _cairo_scaled_glyph_attach_private (glyph, &priv->base, c,
- _cairo_xcb_glyph_fini);
- priv->glyphset = info;
-
- glyph->dev_private = info;
- glyph->dev_private_key = c;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
- cairo_scaled_font_t *font,
- cairo_scaled_glyph_t **scaled_glyph_out)
-{
- xcb_render_glyphinfo_t glyph_info;
- uint32_t glyph_index;
- uint8_t *data;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_scaled_glyph_t *scaled_glyph = *scaled_glyph_out;
- cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
- cairo_bool_t already_had_glyph_surface;
- cairo_xcb_font_glyphset_info_t *info;
-
- glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
-
- /* check to see if we have a pending XRenderFreeGlyph for this glyph */
- info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (connection, font, glyph_index, glyph_surface);
- if (info != NULL)
- return _cairo_xcb_glyph_attach (connection, scaled_glyph, info);
-
- if (glyph_surface == NULL) {
- status = _cairo_scaled_glyph_lookup (font,
- glyph_index,
- CAIRO_SCALED_GLYPH_INFO_METRICS |
- CAIRO_SCALED_GLYPH_INFO_SURFACE,
- scaled_glyph_out);
- if (unlikely (status))
- return status;
-
- scaled_glyph = *scaled_glyph_out;
- glyph_surface = scaled_glyph->surface;
- already_had_glyph_surface = FALSE;
- } else {
- already_had_glyph_surface = TRUE;
- }
-
- info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (connection,
- font,
- glyph_surface->format);
- if (unlikely (info == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
-
-#if 0
- /* If the glyph surface has zero height or width, we create
- * a clear 1x1 surface, to avoid various X server bugs.
- */
- if (glyph_surface->width == 0 || glyph_surface->height == 0) {
- cairo_surface_t *tmp_surface;
-
- tmp_surface = cairo_image_surface_create (info->format, 1, 1);
- status = tmp_surface->status;
- if (unlikely (status))
- goto BAIL;
-
- tmp_surface->device_transform = glyph_surface->base.device_transform;
- tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
-
- glyph_surface = (cairo_image_surface_t *) tmp_surface;
- }
-#endif
-
- /* If the glyph format does not match the font format, then we
- * create a temporary surface for the glyph image with the font's
- * format.
- */
- if (glyph_surface->format != info->format) {
- glyph_surface = _cairo_image_surface_coerce_to_format (glyph_surface,
- info->format);
- status = glyph_surface->base.status;
- if (unlikely (status))
- goto BAIL;
- }
-
- /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
- glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
- glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
- glyph_info.width = glyph_surface->width;
- glyph_info.height = glyph_surface->height;
- glyph_info.x_off = scaled_glyph->x_advance;
- glyph_info.y_off = scaled_glyph->y_advance;
-
- data = glyph_surface->data;
-
- /* flip formats around */
- switch (_cairo_xcb_get_glyphset_index_for_format (scaled_glyph->surface->format)) {
- case GLYPHSET_INDEX_A1:
- /* local bitmaps are always stored with bit == byte */
- if (_cairo_is_little_endian() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
- int c = glyph_surface->stride * glyph_surface->height;
- const uint8_t *d;
- uint8_t *new, *n;
-
- if (c == 0)
- break;
-
- new = _cairo_malloc (c);
- if (unlikely (new == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
-
- n = new;
- d = data;
- do {
- uint8_t b = *d++;
- b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
- b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
- b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
- *n++ = b;
- } while (--c);
- data = new;
- }
- break;
-
- case GLYPHSET_INDEX_A8:
- break;
-
- case GLYPHSET_INDEX_ARGB32:
- if (_cairo_is_little_endian() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
- unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
- const uint32_t *d;
- uint32_t *new, *n;
-
- if (c == 0)
- break;
-
- new = _cairo_malloc (4 * c);
- if (unlikely (new == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
-
- n = new;
- d = (uint32_t *) data;
- do {
- *n++ = bswap_32 (*d);
- d++;
- } while (--c);
- data = (uint8_t *) new;
- }
- break;
-
- default:
- ASSERT_NOT_REACHED;
- break;
- }
- /* XXX assume X server wants pixman padding. Xft assumes this as well */
-
- _cairo_xcb_connection_render_add_glyphs (connection,
- info->glyphset,
- 1, &glyph_index, &glyph_info,
- glyph_surface->stride * glyph_surface->height,
- data);
-
- if (data != glyph_surface->data)
- free (data);
-
- status = _cairo_xcb_glyph_attach (connection, scaled_glyph, info);
-
- BAIL:
- if (glyph_surface != scaled_glyph->surface)
- cairo_surface_destroy (&glyph_surface->base);
-
- /* If the scaled glyph didn't already have a surface attached
- * to it, release the created surface now that we have it
- * uploaded to the X server. If the surface has already been
- * there (e.g. because image backend requested it), leave it in
- * the cache
- */
- if (! already_had_glyph_surface)
- _cairo_scaled_glyph_set_surface (scaled_glyph, font, NULL);
-
- return status;
-}
-
-typedef void (*cairo_xcb_render_composite_text_func_t)
- (cairo_xcb_connection_t *connection,
- uint8_t op,
- xcb_render_picture_t src,
- xcb_render_picture_t dst,
- xcb_render_pictformat_t mask_format,
- xcb_render_glyphset_t glyphset,
- int16_t src_x,
- int16_t src_y,
- uint32_t len,
- uint8_t *cmd);
-
-
-static cairo_status_t
-_emit_glyphs_chunk (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_picture_t *src,
- /* info for this chunk */
- cairo_xcb_glyph_t *glyphs,
- int num_glyphs,
- int width,
- int estimated_req_size,
- cairo_xcb_font_glyphset_info_t *info,
- xcb_render_pictformat_t mask_format)
-{
- cairo_xcb_render_composite_text_func_t composite_text_func;
- uint8_t stack_buf[CAIRO_STACK_BUFFER_SIZE];
- uint8_t *buf = stack_buf;
- x_glyph_elt_t *elt = NULL; /* silence compiler */
- uint32_t len;
- int i;
-
- if (estimated_req_size > ARRAY_LENGTH (stack_buf)) {
- buf = _cairo_malloc (estimated_req_size);
- if (unlikely (buf == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- len = 0;
- for (i = 0; i < num_glyphs; i++) {
- if (_start_new_glyph_elt (i, &glyphs[i])) {
- if (len & 3)
- len += 4 - (len & 3);
-
- elt = (x_glyph_elt_t *) (buf + len);
- elt->len = 0;
- elt->deltax = glyphs[i].i.x;
- elt->deltay = glyphs[i].i.y;
- len += sizeof (x_glyph_elt_t);
- }
-
- switch (width) {
- case 1: *(uint8_t *) (buf + len) = glyphs[i].index; break;
- case 2: *(uint16_t *) (buf + len) = glyphs[i].index; break;
- default:
- case 4: *(uint32_t *) (buf + len) = glyphs[i].index; break;
- }
- len += width;
- elt->len++;
- }
- if (len & 3)
- len += 4 - (len & 3);
-
- switch (width) {
- case 1:
- composite_text_func = _cairo_xcb_connection_render_composite_glyphs_8;
- break;
- case 2:
- composite_text_func = _cairo_xcb_connection_render_composite_glyphs_16;
- break;
- default:
- case 4:
- composite_text_func = _cairo_xcb_connection_render_composite_glyphs_32;
- break;
- }
- composite_text_func (dst->connection,
- _render_operator (op),
- src->picture,
- dst->picture,
- mask_format,
- info->glyphset,
- src->x + glyphs[0].i.x,
- src->y + glyphs[0].i.y,
- len, buf);
-
- if (buf != stack_buf)
- free (buf);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_composite_glyphs (void *closure,
- cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_clip_t *clip)
-{
- composite_glyphs_info_t *info = closure;
- cairo_scaled_glyph_t *glyph_cache[64];
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_fixed_t x = 0, y = 0;
- cairo_xcb_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
- const unsigned int max_request_size = dst->connection->maximum_request_length - 64;
- cairo_xcb_picture_t *src;
-
- unsigned long max_index = 0;
- int width = 1;
-
- unsigned int request_size = 0;
- int i;
-
- if (dst->deferred_clear) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status))
- return status;
- }
-
- src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
- if (unlikely (src->base.status))
- return src->base.status;
-
- memset (glyph_cache, 0, sizeof (glyph_cache));
-
- for (i = 0; i < info->num_glyphs; i++) {
- cairo_scaled_glyph_t *glyph;
- unsigned long glyph_index = info->glyphs[i].index;
- int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
- int old_width = width;
- int this_x, this_y;
-
- glyph = glyph_cache[cache_index];
- if (glyph == NULL ||
- _cairo_scaled_glyph_index (glyph) != glyph_index)
- {
- status = _cairo_scaled_glyph_lookup (info->font,
- glyph_index,
- CAIRO_SCALED_GLYPH_INFO_METRICS,
- &glyph);
- if (unlikely (status)) {
- cairo_surface_destroy (&src->base);
- return status;
- }
-
- /* Send unseen glyphs to the server */
- if (glyph->dev_private_key != dst->connection) {
- status = _cairo_xcb_surface_add_glyph (dst->connection,
- info->font,
- &glyph);
- if (unlikely (status)) {
- cairo_surface_destroy (&src->base);
- return status;
- }
- }
-
- glyph_cache[cache_index] = glyph;
- }
-
- this_x = _cairo_lround (info->glyphs[i].d.x) - dst_x;
- this_y = _cairo_lround (info->glyphs[i].d.y) - dst_y;
-
- this_glyphset_info = glyph->dev_private;
- if (glyphset_info == NULL)
- glyphset_info = this_glyphset_info;
-
- /* Update max glyph index */
- if (glyph_index > max_index) {
- max_index = glyph_index;
- if (max_index >= 65536)
- width = 4;
- else if (max_index >= 256)
- width = 2;
- if (width != old_width)
- request_size += (width - old_width) * i;
- }
-
- /* If we will pass the max request size by adding this glyph,
- * flush current glyphs. Note that we account for a
- * possible element being added below.
- *
- * Also flush if changing glyphsets, as Xrender limits one mask
- * format per request, so we can either break up, or use a
- * wide-enough mask format. We do the former. One reason to
- * prefer the latter is the fact that Xserver ADDs all glyphs
- * to the mask first, and then composes that to final surface,
- * though it's not a big deal.
- *
- * If the glyph has a coordinate which cannot be represented
- * as a 16-bit offset from the previous glyph, flush the
- * current chunk. The current glyph will be the first one in
- * the next chunk, thus its coordinates will be an offset from
- * the destination origin. This offset is guaranteed to be
- * representable as 16-bit offset in _can_composite_glyphs().
- */
- if (request_size + width > max_request_size - _cairo_sz_x_glyph_elt_t ||
- this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
- this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
- this_glyphset_info != glyphset_info)
- {
- status = _emit_glyphs_chunk (dst, op, src,
- info->glyphs, i,
- old_width, request_size,
- glyphset_info,
- info->use_mask ? glyphset_info->xrender_format : 0);
- if (unlikely (status)) {
- cairo_surface_destroy (&src->base);
- return status;
- }
-
- info->glyphs += i;
- info->num_glyphs -= i;
- i = 0;
-
- max_index = info->glyphs[0].index;
- width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
-
- request_size = 0;
-
- x = y = 0;
- glyphset_info = this_glyphset_info;
- }
-
- /* Convert absolute glyph position to relative-to-current-point
- * position */
- info->glyphs[i].i.x = this_x - x;
- info->glyphs[i].i.y = this_y - y;
-
- /* Start a new element for the first glyph,
- * or for any glyph that has unexpected position,
- * or if current element has too many glyphs.
- *
- * These same conditions are mirrored in _emit_glyphs_chunk().
- */
- if (_start_new_glyph_elt (i, &info->glyphs[i]))
- request_size += _cairo_sz_x_glyph_elt_t;
-
- /* adjust current-position */
- x = this_x + glyph->x_advance;
- y = this_y + glyph->y_advance;
-
- request_size += width;
- }
-
- if (i) {
- status = _emit_glyphs_chunk (dst, op, src,
- info->glyphs, i,
- width, request_size,
- glyphset_info,
- info->use_mask ? glyphset_info->xrender_format : 0);
- }
-
- cairo_surface_destroy (&src->base);
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_xcb_render_compositor_glyphs (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_bool_t overlap)
-{
- cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface;
- cairo_operator_t op = composite->op;
- cairo_pattern_t *source = &composite->source_pattern.base;
- cairo_int_status_t status;
-
- if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) {
- _cairo_scaled_font_freeze_cache (scaled_font);
-
- status = _can_composite_glyphs (surface, &composite->bounded,
- scaled_font, glyphs, &num_glyphs);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- composite_glyphs_info_t info;
- unsigned flags = 0;
-
- info.font = scaled_font;
- info.glyphs = (cairo_xcb_glyph_t *) glyphs;
- info.num_glyphs = num_glyphs;
- info.use_mask =
- overlap ||
- ! composite->is_bounded ||
- ! _cairo_clip_is_region(composite->clip);
-
- if (composite->mask.width > composite->unbounded.width ||
- composite->mask.height > composite->unbounded.height)
- {
- /* Glyphs are tricky since we do not directly control the
- * geometry and their inked extents depend on the
- * individual glyph-surface size. We must set a clip region
- * so that the X server can trim the glyphs appropriately.
- */
- flags |= FORCE_CLIP_REGION;
- }
- status = _clip_and_composite (surface, op, source,
- _composite_glyphs, NULL,
- &info, composite,
- need_bounded_clip (composite) |
- flags);
- }
-
- _cairo_scaled_font_thaw_cache (scaled_font);
- }
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- assert (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE);
- status =
- _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source,
- scaled_font, glyphs, num_glyphs,
- composite);
- }
-
- return status;
-}