--- ../cairo-master/src/cairo-xlib-surface.c 2006-06-09 00:49:42.000000000 +0800 +++ src/cairo-xlib-surface.c 2006-06-07 13:19:22.000000000 +0800 @@ -1761,7 +1761,6 @@ static const cairo_surface_backend_t cai NULL, /* mark_dirty_rectangle */ _cairo_xlib_surface_scaled_font_fini, _cairo_xlib_surface_scaled_glyph_fini, - NULL, /* paint */ NULL, /* mask */ NULL, /* stroke */ @@ -2145,40 +2144,94 @@ cairo_xlib_surface_get_depth (cairo_surf return surface->depth; } -typedef struct _cairo_xlib_surface_font_private { - Display *dpy; +#define GLYPHSETS_MAX 3 +#define A1_GLYPHSET_INDEX 0 +#define A8_GLYPHSET_INDEX 1 +#define ARGB_GLYPHSET_INDEX 2 + +typedef struct _cairo_xlib_font_glyph_info { GlyphSet glyphset; - cairo_format_t format; - XRenderPictFormat *xrender_format; + XRenderPictFormat *format; +} cairo_xlib_font_glyphset_t; + +typedef struct _cairo_xlib_surface_font_private { + Display *dpy; + cairo_xlib_font_glyphset_t glyphsets[GLYPHSETS_MAX]; + int num_glyphsets; } 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->dpy = dpy; - font_private->format = format; - font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format); - font_private->glyphset = XRenderCreateGlyphSet (dpy, font_private->xrender_format); + + font_private->num_glyphsets = 0; + for (i = 0; i < GLYPHSETS_MAX; i ++) { + font_private->glyphsets[i].format = NULL; + font_private->glyphsets[i].glyphset = None; + } + scaled_font->surface_private = font_private; scaled_font->surface_backend = &cairo_xlib_surface_backend; return CAIRO_STATUS_SUCCESS; } +static cairo_xlib_font_glyphset_t * +_cairo_xlib_surface_font_get_glyphset (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_glyphset_t *glyphsets = &font_private->glyphsets[0]; + int index; + + switch (format) { + case CAIRO_FORMAT_A1: + index = A1_GLYPHSET_INDEX; + break; + case CAIRO_FORMAT_A8: + index = A8_GLYPHSET_INDEX; + break; + case CAIRO_FORMAT_ARGB32: + index = ARGB_GLYPHSET_INDEX; + break; + case CAIRO_FORMAT_RGB24: + default: + ASSERT_NOT_REACHED; + } + + if (glyphsets[index].glyphset == None) { + glyphsets[index].format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(font_private->dpy, + format); + glyphsets[index].glyphset = XRenderCreateGlyphSet (font_private->dpy, + glyphsets[index].format); + font_private->num_glyphsets ++; + } + + return &glyphsets[index]; +} + 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 < GLYPHSETS_MAX; i ++) { + if (font_private->glyphsets[i].glyphset) + XRenderFreeGlyphSet (font_private->dpy, + font_private->glyphsets[i].glyphset); + } + free (font_private); } } @@ -2191,8 +2244,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_glyphset_t *glyphset = scaled_glyph->surface_private; + XRenderFreeGlyphs (font_private->dpy, - font_private->glyphset, + glyphset->glyphset, &glyph_index, 1); } } @@ -2215,44 +2270,22 @@ _cairo_xlib_surface_add_glyph (Display * unsigned char *data; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_xlib_surface_font_private_t *font_private; + cairo_xlib_font_glyphset_t * glyphset; 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; - /* 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 != font_private->format) { - cairo_t *cr; - cairo_surface_t *tmp_surface; - - tmp_surface = cairo_image_surface_create (font_private->format, - glyph_surface->width, - glyph_surface->height); - cr = cairo_create (tmp_surface); - cairo_set_source_surface (cr, &glyph_surface->base, 0, 0); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (cr); - - status = cairo_status (cr); - - cairo_destroy (cr); - - tmp_surface->device_x_offset = glyph_surface->base.device_x_offset; - tmp_surface->device_y_offset = glyph_surface->base.device_y_offset; - - glyph_surface = (cairo_image_surface_t *) tmp_surface; - - if (status) - goto BAIL; - } + glyphset = _cairo_xlib_surface_font_get_glyphset (scaled_font, + glyph_surface->format); + if (glyphset->glyphset == None) + return CAIRO_STATUS_NO_MEMORY; + + scaled_glyph->surface_private = glyphset; /* * Most of the font rendering system thinks of glyph tiles as having @@ -2362,7 +2395,8 @@ _cairo_xlib_surface_add_glyph (Display * glyph_index = _cairo_scaled_glyph_index (scaled_glyph); - XRenderAddGlyphs (dpy, font_private->glyphset, + + XRenderAddGlyphs (dpy, glyphset->glyphset, &glyph_index, &(glyph_info), 1, (char *) data, glyph_surface->stride * glyph_surface->height); @@ -2371,8 +2405,6 @@ _cairo_xlib_surface_add_glyph (Display * free (data); BAIL: - if (glyph_surface != scaled_glyph->surface) - cairo_surface_destroy (&glyph_surface->base); return status; } @@ -2386,9 +2418,9 @@ _cairo_xlib_surface_show_glyphs8 (cairo int src_x_offset, int src_y_offset, const cairo_glyph_t *glyphs, int num_glyphs, + cairo_xlib_font_glyphset_t *glyphset, cairo_scaled_font_t *scaled_font) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt8 *elts = NULL; XGlyphElt8 stack_elts [N_STACK_BUF]; @@ -2416,7 +2448,7 @@ _cairo_xlib_surface_show_glyphs8 (cairo chars[i] = glyphs[i].index; elts[i].chars = &(chars[i]); elts[i].nchars = 1; - elts[i].glyphset = font_private->glyphset; + elts[i].glyphset = glyphset->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2429,7 +2461,7 @@ _cairo_xlib_surface_show_glyphs8 (cairo _render_operator (op), src->src_picture, dst->dst_picture, - font_private->xrender_format, + glyphset->format, src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff, elts[0].xOff, elts[0].yOff, elts, num_glyphs); @@ -2447,9 +2479,9 @@ _cairo_xlib_surface_show_glyphs16 (cairo int src_x_offset, int src_y_offset, const cairo_glyph_t *glyphs, int num_glyphs, + cairo_xlib_font_glyphset_t *glyphset, cairo_scaled_font_t *scaled_font) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt16 *elts = NULL; XGlyphElt16 stack_elts [N_STACK_BUF]; @@ -2477,7 +2509,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo chars[i] = glyphs[i].index; elts[i].chars = &(chars[i]); elts[i].nchars = 1; - elts[i].glyphset = font_private->glyphset; + elts[i].glyphset = glyphset->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2490,7 +2522,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo _render_operator (op), src->src_picture, dst->dst_picture, - font_private->xrender_format, + glyphset->format, src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff, elts[0].xOff, elts[0].yOff, elts, num_glyphs); @@ -2508,9 +2540,9 @@ _cairo_xlib_surface_show_glyphs32 (cairo int src_x_offset, int src_y_offset, const cairo_glyph_t *glyphs, int num_glyphs, + cairo_xlib_font_glyphset_t *glyphset, cairo_scaled_font_t *scaled_font) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt32 *elts = NULL; XGlyphElt32 stack_elts [N_STACK_BUF]; @@ -2538,7 +2570,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo chars[i] = glyphs[i].index; elts[i].chars = &(chars[i]); elts[i].nchars = 1; - elts[i].glyphset = font_private->glyphset; + elts[i].glyphset = glyphset->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2551,7 +2583,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo _render_operator (op), src->src_picture, dst->dst_picture, - font_private->xrender_format, + glyphset->format, src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff, elts[0].xOff, elts[0].yOff, elts, num_glyphs); @@ -2564,7 +2596,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo 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 *); + const cairo_glyph_t *, int, cairo_xlib_font_glyphset_t *,cairo_scaled_font_t *); static cairo_int_status_t _cairo_xlib_surface_show_glyphs (void *abstract_dst, @@ -2584,9 +2616,11 @@ _cairo_xlib_surface_show_glyphs (void const cairo_glyph_t *glyphs_chunk; int glyphs_remaining, chunk_size, max_chunk_size; cairo_scaled_glyph_t *scaled_glyph; + cairo_xlib_font_glyphset_t **glyphsets, **glyphsets_chunk; + cairo_xlib_font_glyphset_t *stack_glyphsets[N_STACK_BUF]; cairo_xlib_surface_font_private_t *font_private; + int i, boundary; - int i; unsigned long max_index = 0; cairo_xlib_surface_show_glyphs_func_t show_glyphs_func; @@ -2674,7 +2708,16 @@ _cairo_xlib_surface_show_glyphs (void status = _cairo_xlib_surface_set_attributes (src, &attributes); if (status) - goto FAIL; + goto FAIL; + + if (num_glyphs > N_STACK_BUF) + glyphsets = malloc (sizeof(cairo_xlib_font_glyphset_t *) * num_glyphs); + else + glyphsets = stack_glyphsets; + if (!glyphsets) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } /* Send all unsent glyphs to the server, and count the max of the glyph indices */ for (i = 0; i < num_glyphs; i++) { @@ -2685,11 +2728,11 @@ _cairo_xlib_surface_show_glyphs (void 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 (dst->dpy, scaled_font, scaled_glyph); - scaled_glyph->surface_private = (void *) 1; } + glyphsets[i] = (cairo_xlib_font_glyphset_t *)scaled_glyph->surface_private; } _cairo_xlib_surface_ensure_dst_picture (dst); @@ -2707,23 +2750,38 @@ _cairo_xlib_surface_show_glyphs (void } 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, + glyphsets_chunk = glyphsets; glyphs_remaining; + glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size, + glyphsets_chunk += chunk_size) { chunk_size = MIN (glyphs_remaining, max_chunk_size); - + if (font_private->num_glyphsets > 1 && chunk_size > 1) { + for (boundary = 1; boundary < chunk_size; boundary ++) { + if (glyphsets_chunk[boundary - 1]->glyphset != glyphsets_chunk[boundary]->glyphset) { + chunk_size = boundary; + break; + } + } + } status = show_glyphs_func (dst, op, src, attributes.x_offset, attributes.y_offset, - glyphs_chunk, chunk_size, scaled_font); - if (status != CAIRO_STATUS_SUCCESS) + glyphs_chunk, chunk_size, glyphsets_chunk[0], + scaled_font); + if (status != CAIRO_STATUS_SUCCESS) break; } - FAIL: + FAIL1: + if (glyphsets != stack_glyphsets) + free (glyphsets); + 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; }