diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 0f195bf..3032904 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -2006,38 +2006,88 @@ cairo_xlib_surface_set_drawable (cairo_s surface->height = height; } -typedef struct _cairo_xlib_surface_font_private { - Display *dpy; +#define GLYPH_INFO_MAX (3) +typedef struct _cairo_xlib_font_glyph_info { GlyphSet glyphset; XRenderPictFormat *format; +} cairo_xlib_font_glyph_info_t; + +typedef struct _cairo_xlib_surface_font_private { + Display *dpy; + cairo_xlib_font_glyph_info_t glyph_info[GLYPH_INFO_MAX]; + int num_formats; } cairo_xlib_surface_font_private_t; static cairo_status_t _cairo_xlib_surface_font_init (Display *dpy, - cairo_scaled_font_t *scaled_font, - cairo_format_t format) + cairo_scaled_font_t *scaled_font) { cairo_xlib_surface_font_private_t *font_private; + int i; font_private = malloc (sizeof (cairo_xlib_surface_font_private_t)); if (!font_private) return CAIRO_STATUS_NO_MEMORY; + font_private->num_formats = 0; + for (i = 0; i < GLYPH_INFO_MAX; i ++) { + font_private->glyph_info[i].format = NULL; + font_private->glyph_info[i].glyphset = None; + } + font_private->dpy = dpy; - font_private->format = _CAIRO_FORMAT_XRENDER_FORMAT(dpy, format); - font_private->glyphset = XRenderCreateGlyphSet (dpy, font_private->format); scaled_font->surface_private = font_private; scaled_font->surface_backend = &cairo_xlib_surface_backend; return CAIRO_STATUS_SUCCESS; } +static cairo_xlib_font_glyph_info_t * +_cairo_xlib_surface_font_get_glyph_info (cairo_scaled_font_t *scaled_font, + cairo_format_t format) +{ + cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; + cairo_xlib_font_glyph_info_t *glyph_info = &font_private->glyph_info[0]; + int foffset; + + switch (format) { + case CAIRO_FORMAT_A1: + foffset = 0; + break; + case CAIRO_FORMAT_A8: + foffset = 1; + break; + case CAIRO_FORMAT_ARGB32: + foffset = 2; + break; + case CAIRO_FORMAT_RGB24: + default: + ASSERT_NOT_REACHED; + } + + if (glyph_info[foffset].glyphset == None) { + glyph_info[foffset].format = _CAIRO_FORMAT_XRENDER_FORMAT(font_private->dpy, + format); + glyph_info[foffset].glyphset = XRenderCreateGlyphSet (font_private->dpy, + glyph_info[foffset].format); + font_private->num_formats ++; + } + + return glyph_info + foffset; +} + static void _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) { cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; if (font_private) { - XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset); + int i; + + for (i = 0; i < GLYPH_INFO_MAX; i ++) { + if (font_private->glyph_info[i].glyphset) + XRenderFreeGlyphSet (font_private->dpy, + font_private->glyph_info[i].glyphset); + } free (font_private); } } @@ -2050,8 +2100,10 @@ _cairo_xlib_surface_scaled_glyph_fini (c if (font_private != NULL && scaled_glyph->surface_private != NULL) { unsigned long glyph_index = _cairo_scaled_glyph_index(scaled_glyph); + cairo_xlib_font_glyph_info_t *glyph_info = scaled_glyph->surface_private; + XRenderFreeGlyphs (font_private->dpy, - font_private->glyphset, + glyph_info->glyphset, &glyph_index, 1); } } @@ -2074,16 +2126,23 @@ _cairo_xlib_surface_add_glyph (Display * unsigned char *data; cairo_status_t status; cairo_xlib_surface_font_private_t *font_private; + cairo_xlib_font_glyph_info_t * cairo_glyph_info; cairo_image_surface_t *glyph_surface = scaled_glyph->surface; if (scaled_font->surface_private == NULL) { - status = _cairo_xlib_surface_font_init (dpy, scaled_font, - glyph_surface->format); + status = _cairo_xlib_surface_font_init (dpy, scaled_font); if (status) return status; } font_private = scaled_font->surface_private; + cairo_glyph_info = _cairo_xlib_surface_font_get_glyph_info (scaled_font, + glyph_surface->format); + if (cairo_glyph_info->glyphset == None) + return CAIRO_STATUS_NO_MEMORY; + + scaled_glyph->surface_private = cairo_glyph_info; + /* * Most of the font rendering system thinks of glyph tiles as having * an origin at (0,0) and an x and y bounding box "offset" which @@ -2188,11 +2247,11 @@ _cairo_xlib_surface_add_glyph (Display * glyph_index = _cairo_scaled_glyph_index (scaled_glyph); - XRenderAddGlyphs (dpy, font_private->glyphset, + XRenderAddGlyphs (dpy, cairo_glyph_info->glyphset, &glyph_index, &(glyph_info), 1, (char *) data, glyph_surface->stride * glyph_surface->height); - + if (data != glyph_surface->data) free (data); @@ -2209,9 +2268,9 @@ _cairo_xlib_surface_old_show_glyphs8 (c int source_x, int source_y, const cairo_glyph_t *glyphs, - int num_glyphs) + int num_glyphs, + cairo_xlib_font_glyph_info_t *glyph_info) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt8 *elts = NULL; XGlyphElt8 stack_elts [N_STACK_BUF]; @@ -2239,7 +2298,7 @@ _cairo_xlib_surface_old_show_glyphs8 (c chars[i] = glyphs[i].index; elts[i].chars = &(chars[i]); elts[i].nchars = 1; - elts[i].glyphset = font_private->glyphset; + elts[i].glyphset = glyph_info->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2252,7 +2311,7 @@ _cairo_xlib_surface_old_show_glyphs8 (c _render_operator (op), src->src_picture, self->dst_picture, - font_private->format, + glyph_info->format, source_x + elts[0].xOff, source_y + elts[0].yOff, 0, 0, elts, num_glyphs); @@ -2271,9 +2330,9 @@ _cairo_xlib_surface_old_show_glyphs16 (c int source_x, int source_y, const cairo_glyph_t *glyphs, - int num_glyphs) + int num_glyphs, + cairo_xlib_font_glyph_info_t *glyph_info) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt16 *elts = NULL; XGlyphElt16 stack_elts [N_STACK_BUF]; @@ -2301,7 +2360,7 @@ _cairo_xlib_surface_old_show_glyphs16 (c chars[i] = glyphs[i].index; elts[i].chars = &(chars[i]); elts[i].nchars = 1; - elts[i].glyphset = font_private->glyphset; + elts[i].glyphset = glyph_info->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2314,7 +2373,7 @@ _cairo_xlib_surface_old_show_glyphs16 (c _render_operator (op), src->src_picture, self->dst_picture, - font_private->format, + glyph_info->format, source_x + elts[0].xOff, source_y + elts[0].yOff, 0, 0, elts, num_glyphs); @@ -2326,16 +2385,16 @@ _cairo_xlib_surface_old_show_glyphs16 (c } 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_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_font_glyph_info_t *glyph_info) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt32 *elts = NULL; XGlyphElt32 stack_elts [N_STACK_BUF]; @@ -2363,7 +2422,7 @@ _cairo_xlib_surface_old_show_glyphs32 (c chars[i] = glyphs[i].index; elts[i].chars = &(chars[i]); elts[i].nchars = 1; - elts[i].glyphset = font_private->glyphset; + elts[i].glyphset = glyph_info->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2376,7 +2435,7 @@ _cairo_xlib_surface_old_show_glyphs32 (c _render_operator (op), src->src_picture, self->dst_picture, - font_private->format, + glyph_info->format, source_x + elts[0].xOff, source_y + elts[0].yOff, 0, 0, elts, num_glyphs); @@ -2409,8 +2468,10 @@ _cairo_xlib_surface_old_show_glyphs (cai int glyphs_remaining, chunk_size, max_chunk_size; composite_operation_t operation; cairo_scaled_glyph_t *scaled_glyph; + cairo_xlib_font_glyph_info_t **glyphs_info, **glyphs_info_chunk; + cairo_xlib_font_glyph_info_t *stack_glyphs_info[N_STACK_BUF]; cairo_xlib_surface_font_private_t *font_private; - int i; + int i, boundary; unsigned long max_index = 0; @@ -2444,6 +2505,15 @@ _cairo_xlib_surface_old_show_glyphs (cai if (status) goto FAIL; + if (num_glyphs < N_STACK_BUF) + glyphs_info = stack_glyphs_info; + else + glyphs_info = malloc (sizeof(cairo_xlib_font_glyph_info_t *) * num_glyphs); + if (!glyphs_info) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + /* Send all unsent glyphs to the server */ for (i = 0; i < num_glyphs; i++) { if (glyphs[i].index > max_index) @@ -2453,11 +2523,11 @@ _cairo_xlib_surface_old_show_glyphs (cai CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (status != CAIRO_STATUS_SUCCESS) - return status; + goto FAIL1; if (scaled_glyph->surface_private == NULL) { _cairo_xlib_surface_add_glyph (self->dpy, scaled_font, scaled_glyph); - scaled_glyph->surface_private = (void *) 1; } + glyphs_info[i] = (cairo_xlib_font_glyph_info_t *)scaled_glyph->surface_private; } _cairo_xlib_surface_ensure_dst_picture (self); @@ -2471,28 +2541,40 @@ _cairo_xlib_surface_old_show_glyphs (cai max_chunk_size -= sz_xRenderCompositeGlyphs32Req; max_chunk_size /= sz_xGlyphElt; - for (glyphs_remaining = num_glyphs, glyphs_chunk = glyphs; - glyphs_remaining; - glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size) + font_private = scaled_font->surface_private; + + for (glyphs_remaining = num_glyphs, glyphs_chunk = glyphs, + glyphs_info_chunk = glyphs_info; glyphs_remaining; + glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size, + glyphs_info_chunk += chunk_size) { chunk_size = MIN (glyphs_remaining, max_chunk_size); + if (font_private->num_formats > 1 && chunk_size > 1) { + for (boundary = 1; boundary < chunk_size; boundary ++) { + if (glyphs_info_chunk[boundary - 1]->glyphset != glyphs_info_chunk[boundary]->glyphset) { + chunk_size = boundary; + break; + } + } + } + /* 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); + source_x + attributes.x_offset - dest_x, + source_y + attributes.y_offset - dest_y, + glyphs_chunk, chunk_size, glyphs_info_chunk[0]); 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); + source_x + attributes.x_offset - dest_x, + source_y + attributes.y_offset - dest_y, + glyphs_chunk, chunk_size, glyphs_info_chunk[0]); 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); + source_x + attributes.x_offset - dest_x, + source_y + attributes.y_offset - dest_y, + glyphs_chunk, chunk_size, glyphs_info_chunk[0]); if (status != CAIRO_STATUS_SUCCESS) break; } @@ -2504,14 +2586,17 @@ _cairo_xlib_surface_old_show_glyphs (cai 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); + 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); } + + FAIL1: + if (glyphs_info != stack_glyphs_info) + free (glyphs_info); FAIL: _cairo_pattern_release_surface (pattern, &src->base, &attributes);