diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 3d528bf01..df852390f 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -40,6 +40,7 @@ #include "cairo-xlib-xrender.h" #include "cairo-xlib-test.h" #include "cairo-xlib-private.h" +#include "cairo-clip-private.h" #include #include @@ -64,6 +65,14 @@ _cairo_surface_is_xlib (cairo_surface_t *surface); static cairo_bool_t _native_byte_order_lsb (void); +static cairo_int_status_t +_cairo_xlib_surface_show_glyphs (void *abstract_dst, + cairo_operator_t op, + cairo_pattern_t *src_pattern, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font); + /* * Instead of taking two round trips for each blending request, * assume that if a particular drawable fails GetImage that it will @@ -1711,20 +1720,6 @@ _cairo_xlib_surface_get_font_options (void *abstract_surface, options->antialias = CAIRO_ANTIALIAS_GRAY; } -static cairo_int_status_t -_cairo_xlib_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, - cairo_operator_t op, - cairo_pattern_t *pattern, - void *abstract_surface, - int source_x, - int source_y, - int dest_x, - int dest_y, - unsigned int width, - unsigned int height, - const cairo_glyph_t *glyphs, - int num_glyphs); - static void _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); @@ -1749,12 +1744,19 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_set_clip_region, NULL, /* intersect_clip_path */ _cairo_xlib_surface_get_extents, - _cairo_xlib_surface_old_show_glyphs, + NULL, /* old_show_glyphs */ _cairo_xlib_surface_get_font_options, NULL, /* flush */ NULL, /* mark_dirty_rectangle */ _cairo_xlib_surface_scaled_font_fini, _cairo_xlib_surface_scaled_glyph_fini, + + NULL, /* paint */ + NULL, /* mask */ + NULL, /* stroke */ + NULL, /* fill */ + _cairo_xlib_surface_show_glyphs, + NULL /* snapshot */ }; /** @@ -2363,14 +2365,13 @@ _cairo_xlib_surface_add_glyph (Display *dpy, #define N_STACK_BUF 1024 static cairo_status_t -_cairo_xlib_surface_old_show_glyphs8 (cairo_scaled_font_t *scaled_font, - cairo_operator_t op, - cairo_xlib_surface_t *src, - cairo_xlib_surface_t *self, - int source_x, - int source_y, - const cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_xlib_surface_show_glyphs8 (cairo_xlib_surface_t *dst, + cairo_operator_t op, + cairo_xlib_surface_t *src, + int src_x_offset, int src_y_offset, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font) { cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt8 *elts = NULL; @@ -2409,13 +2410,13 @@ _cairo_xlib_surface_old_show_glyphs8 (cairo_scaled_font_t *scaled_font, lastY = thisY; } - XRenderCompositeText8 (self->dpy, + XRenderCompositeText8 (dst->dpy, _render_operator (op), src->src_picture, - self->dst_picture, + dst->dst_picture, font_private->xrender_format, - source_x + elts[0].xOff, source_y + elts[0].yOff, - 0, 0, + src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff, + elts[0].xOff, elts[0].yOff, elts, num_glyphs); if (elts != stack_elts) @@ -2425,14 +2426,13 @@ _cairo_xlib_surface_old_show_glyphs8 (cairo_scaled_font_t *scaled_font, } static cairo_status_t -_cairo_xlib_surface_old_show_glyphs16 (cairo_scaled_font_t *scaled_font, - cairo_operator_t op, - cairo_xlib_surface_t *src, - cairo_xlib_surface_t *self, - int source_x, - int source_y, - const cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_xlib_surface_show_glyphs16 (cairo_xlib_surface_t *dst, + cairo_operator_t op, + cairo_xlib_surface_t *src, + int src_x_offset, int src_y_offset, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font) { cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt16 *elts = NULL; @@ -2471,13 +2471,13 @@ _cairo_xlib_surface_old_show_glyphs16 (cairo_scaled_font_t *scaled_font, lastY = thisY; } - XRenderCompositeText16 (self->dpy, + XRenderCompositeText16 (dst->dpy, _render_operator (op), src->src_picture, - self->dst_picture, + dst->dst_picture, font_private->xrender_format, - source_x + elts[0].xOff, source_y + elts[0].yOff, - 0, 0, + src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff, + elts[0].xOff, elts[0].yOff, elts, num_glyphs); if (elts != stack_elts) @@ -2487,14 +2487,13 @@ _cairo_xlib_surface_old_show_glyphs16 (cairo_scaled_font_t *scaled_font, } static cairo_status_t -_cairo_xlib_surface_old_show_glyphs32 (cairo_scaled_font_t *scaled_font, - cairo_operator_t op, - cairo_xlib_surface_t *src, - cairo_xlib_surface_t *self, - int source_x, - int source_y, - const cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_xlib_surface_show_glyphs32 (cairo_xlib_surface_t *dst, + cairo_operator_t op, + cairo_xlib_surface_t *src, + int src_x_offset, int src_y_offset, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font) { cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt32 *elts = NULL; @@ -2533,13 +2532,13 @@ _cairo_xlib_surface_old_show_glyphs32 (cairo_scaled_font_t *scaled_font, lastY = thisY; } - XRenderCompositeText32 (self->dpy, + XRenderCompositeText32 (dst->dpy, _render_operator (op), src->src_picture, - self->dst_picture, + dst->dst_picture, font_private->xrender_format, - source_x + elts[0].xOff, source_y + elts[0].yOff, - 0, 0, + src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff, + elts[0].xOff, elts[0].yOff, elts, num_glyphs); if (elts != stack_elts) @@ -2548,63 +2547,113 @@ _cairo_xlib_surface_old_show_glyphs32 (cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_SUCCESS; } +typedef cairo_status_t (*cairo_xlib_surface_show_glyphs_func_t) + (cairo_xlib_surface_t *, cairo_operator_t, cairo_xlib_surface_t *, int, int, + const cairo_glyph_t *, int, cairo_scaled_font_t *); + static cairo_int_status_t -_cairo_xlib_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, - cairo_operator_t op, - cairo_pattern_t *pattern, - void *abstract_surface, - int source_x, - int source_y, - int dest_x, - int dest_y, - unsigned int width, - unsigned int height, - const cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_xlib_surface_show_glyphs (void *abstract_dst, + cairo_operator_t op, + cairo_pattern_t *src_pattern, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font) { - cairo_surface_attributes_t attributes; - cairo_int_status_t status; - cairo_xlib_surface_t *self = abstract_surface; - cairo_xlib_surface_t *src; + cairo_int_status_t status; + cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst; + + composite_operation_t operation; + cairo_surface_attributes_t attributes; + cairo_xlib_surface_t *src = NULL; + const cairo_glyph_t *glyphs_chunk; int glyphs_remaining, chunk_size, max_chunk_size; - composite_operation_t operation; cairo_scaled_glyph_t *scaled_glyph; cairo_xlib_surface_font_private_t *font_private; + + cairo_rectangle_fixed_t glyph_extents; + int i; unsigned long max_index = 0; - - if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self) || !self->xrender_format) + + cairo_xlib_surface_show_glyphs_func_t show_glyphs_func; + + cairo_pattern_union_t solid_pattern; + + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || !dst->xrender_format) return CAIRO_INT_STATUS_UNSUPPORTED; - operation = _categorize_composite_operation (self, op, pattern, TRUE); + /* Just let unbounded operators go through the fallback code + * instead of trying to do the fixups here */ + if (!_cairo_operator_bounded_by_mask (op)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs -- + * the solid source seems to be multiplied by the glyph mask, and + * then the entire thing is copied to the destination surface, + * including the fully transparent "background" of the rectangular + * glyph surface. */ + if (op == CAIRO_OPERATOR_SOURCE && + !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* We can only use our code if we either have no clip or + * have a real native clip region set. If we're using + * fallback clip masking, we have to go through the full + * fallback path. + */ + if (dst->base.clip && + (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION || + dst->base.clip->surface != NULL)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + operation = _categorize_composite_operation (dst, op, src_pattern, TRUE); if (operation == DO_UNSUPPORTED) return CAIRO_INT_STATUS_UNSUPPORTED; - + font_private = scaled_font->surface_private; if ((scaled_font->surface_backend != NULL && scaled_font->surface_backend != &cairo_xlib_surface_backend) || - (font_private != NULL && font_private->dpy != self->dpy)) + (font_private != NULL && font_private->dpy != dst->dpy)) return CAIRO_INT_STATUS_UNSUPPORTED; - status = _cairo_pattern_acquire_surface (pattern, &self->base, - source_x, source_y, width, height, - (cairo_surface_t **) &src, - &attributes); + status = _cairo_scaled_font_glyph_device_extents (scaled_font, + glyphs, + num_glyphs, + &glyph_extents); if (status) - return status; + return status; - operation = _recategorize_composite_operation (self, op, src, &attributes, TRUE); + /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore + * the mask (the glyphs). This code below was executed as a side effect + * of going through the _clip_and_composite fallback code for old_show_glyphs, + * so PictOpClear was never used with CompositeText before. + */ + if (op == CAIRO_OPERATOR_CLEAR) { + _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); + src_pattern = &solid_pattern.base; + op = CAIRO_OPERATOR_DEST_OUT; + } + + status = _cairo_pattern_acquire_surface (src_pattern, &dst->base, + glyph_extents.x, glyph_extents.y, + glyph_extents.width, glyph_extents.height, + (cairo_surface_t **) &src, + &attributes); + if (status) + goto FAIL; + + operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE); if (operation == DO_UNSUPPORTED) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto FAIL; } - + status = _cairo_xlib_surface_set_attributes (src, &attributes); if (status) - goto FAIL; - - /* Send all unsent glyphs to the server */ + goto FAIL; + + /* Send all unsent glyphs to the server, and count the max of the glyph indices */ for (i = 0; i < num_glyphs; i++) { if (glyphs[i].index > max_index) max_index = glyphs[i].index; @@ -2615,20 +2664,24 @@ _cairo_xlib_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, if (status != CAIRO_STATUS_SUCCESS) return status; if (scaled_glyph->surface_private == NULL) { - _cairo_xlib_surface_add_glyph (self->dpy, scaled_font, scaled_glyph); + _cairo_xlib_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph); scaled_glyph->surface_private = (void *) 1; } } - - _cairo_xlib_surface_ensure_dst_picture (self); - max_chunk_size = XMaxRequestSize (self->dpy); - if (max_index < 256) + _cairo_xlib_surface_ensure_dst_picture (dst); + + max_chunk_size = XMaxRequestSize (dst->dpy); + if (max_index < 256) { max_chunk_size -= sz_xRenderCompositeGlyphs8Req; - else if (max_index < 65536) + show_glyphs_func = _cairo_xlib_surface_show_glyphs8; + } else if (max_index < 65536) { max_chunk_size -= sz_xRenderCompositeGlyphs16Req; - else + show_glyphs_func = _cairo_xlib_surface_show_glyphs16; + } else { max_chunk_size -= sz_xRenderCompositeGlyphs32Req; + show_glyphs_func = _cairo_xlib_surface_show_glyphs32; + } max_chunk_size /= sz_xGlyphElt; for (glyphs_remaining = num_glyphs, glyphs_chunk = glyphs; @@ -2637,43 +2690,18 @@ _cairo_xlib_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, { chunk_size = MIN (glyphs_remaining, max_chunk_size); - /* Call the appropriate sub-function. */ - if (max_index < 256) - status = _cairo_xlib_surface_old_show_glyphs8 (scaled_font, op, src, self, - source_x + attributes.x_offset - dest_x, - source_y + attributes.y_offset - dest_y, - glyphs_chunk, chunk_size); - else if (max_index < 65536) - status = _cairo_xlib_surface_old_show_glyphs16 (scaled_font, op, src, self, - source_x + attributes.x_offset - dest_x, - source_y + attributes.y_offset - dest_y, - glyphs_chunk, chunk_size); - else - status = _cairo_xlib_surface_old_show_glyphs32 (scaled_font, op, src, self, - source_x + attributes.x_offset - dest_x, - source_y + attributes.y_offset - dest_y, - glyphs_chunk, chunk_size); + status = show_glyphs_func (dst, op, src, + attributes.x_offset, attributes.y_offset, + glyphs_chunk, chunk_size, scaled_font); if (status != CAIRO_STATUS_SUCCESS) break; } - if (status == CAIRO_STATUS_SUCCESS && !_cairo_operator_bounded_by_mask (op)) { - cairo_rectangle_fixed_t extents; - status = _cairo_scaled_font_glyph_device_extents (scaled_font, - glyphs, - num_glyphs, - &extents); - if (status == CAIRO_STATUS_SUCCESS) - status = _cairo_surface_composite_shape_fixup_unbounded - (&self->base, &attributes, src->width, src->height, - extents.width, extents.height, - source_x, source_y, - dest_x - extents.x, dest_y - extents.y, - dest_x, dest_y, - width, height); - } - FAIL: - _cairo_pattern_release_surface (pattern, &src->base, &attributes); - + FAIL: + if (src) + _cairo_pattern_release_surface (src_pattern, &src->base, &attributes); + if (src_pattern == &solid_pattern.base) + _cairo_pattern_fini (&solid_pattern.base); return status; } +