diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 38c7c76..d80d8d4 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -2004,38 +2004,86 @@ 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->dpy = dpy; - font_private->format = _CAIRO_FORMAT_XRENDER_FORMAT(dpy, format); - font_private->glyphset = XRenderCreateGlyphSet (dpy, font_private->format); + 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; + } + 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 i; + + switch (format) { + case CAIRO_FORMAT_A1: + i = 0; + break; + case CAIRO_FORMAT_A8: + i = 1; + break; + case CAIRO_FORMAT_ARGB32: + i = 2; + break; + case CAIRO_FORMAT_RGB24: + default: + ASSERT_NOT_REACHED; + } + + if (glyph_info[i].glyphset == None) { + glyph_info[i].format = _CAIRO_FORMAT_XRENDER_FORMAT(font_private->dpy, + format); + glyph_info[i].glyphset = XRenderCreateGlyphSet (font_private->dpy, + glyph_info[i].format); + font_private->num_formats ++; + } + + return glyph_info + i; +} + 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; + int i; if (font_private) { - XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset); + 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); } } @@ -2048,8 +2096,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); } } @@ -2072,16 +2122,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 @@ -2186,7 +2243,7 @@ _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); @@ -2200,16 +2257,18 @@ _cairo_xlib_surface_add_glyph (Display * #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_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_font_glyph_info_t *glyph_info, + int *x_advance, + int *y_advance) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt8 *elts = NULL; XGlyphElt8 stack_elts [N_STACK_BUF]; @@ -2237,7 +2296,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; @@ -2250,11 +2309,14 @@ _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); + *x_advance = elts[num_glyphs - 1].xOff; + *y_advance = elts[num_glyphs - 1].yOff; + if (elts != stack_elts) free (elts); @@ -2262,16 +2324,18 @@ _cairo_xlib_surface_old_show_glyphs8 (c } 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_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_font_glyph_info_t *glyph_info, + int *x_advance, + int *y_advance) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt16 *elts = NULL; XGlyphElt16 stack_elts [N_STACK_BUF]; @@ -2299,7 +2363,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; @@ -2312,11 +2376,14 @@ _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); + *x_advance = elts[num_glyphs - 1].xOff; + *y_advance = elts[num_glyphs - 1].yOff; + if (elts != stack_elts) free (elts); @@ -2324,16 +2391,18 @@ _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, + int *x_advance, + int *y_advance) { - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; XGlyphElt32 *elts = NULL; XGlyphElt32 stack_elts [N_STACK_BUF]; @@ -2361,7 +2430,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; @@ -2374,11 +2443,14 @@ _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); + *x_advance = elts[num_glyphs - 1].xOff; + *y_advance = elts[num_glyphs - 1].yOff; + if (elts != stack_elts) free (elts); @@ -2405,9 +2477,13 @@ _cairo_xlib_surface_old_show_glyphs (cai cairo_xlib_surface_t *src; composite_operation_t operation; cairo_scaled_glyph_t *scaled_glyph; + cairo_xlib_font_glyph_info_t *glyphs_info; cairo_xlib_surface_font_private_t *font_private; - int i; unsigned long max_index = 0; + int x_offset, y_offset; + int x_advance, y_advance; + int i, boundary, done; + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self) || !self->format) @@ -2423,23 +2499,27 @@ _cairo_xlib_surface_old_show_glyphs (cai (font_private != NULL && font_private->dpy != self->dpy)) return CAIRO_INT_STATUS_UNSUPPORTED; + glyphs_info = malloc (sizeof (cairo_xlib_font_glyph_info_t) * num_glyphs); + if (glyphs_info == NULL) + return CAIRO_STATUS_NO_MEMORY; + status = _cairo_pattern_acquire_surface (pattern, &self->base, source_x, source_y, width, height, (cairo_surface_t **) &src, &attributes); if (status) - return status; + goto FAIL; operation = _recategorize_composite_operation (self, op, src, &attributes, TRUE); if (operation == DO_UNSUPPORTED) { status = CAIRO_INT_STATUS_UNSUPPORTED; - goto FAIL; + goto FAIL1; } status = _cairo_xlib_surface_set_attributes (src, &attributes); if (status) - goto FAIL; - + goto FAIL1; + /* Send all unsent glyphs to the server */ for (i = 0; i < num_glyphs; i++) { if (glyphs[i].index > max_index) @@ -2452,28 +2532,73 @@ _cairo_xlib_surface_old_show_glyphs (cai return status; 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); /* Call the appropriate sub-function. */ + font_private = scaled_font->surface_private; + x_offset = source_x + attributes.x_offset - dest_x; + y_offset = source_y + attributes.y_offset - dest_y; + done = 0; + + if (font_private->num_formats == 1) { + if (max_index < 256) + status = _cairo_xlib_surface_old_show_glyphs8 (scaled_font, op, + src, self, + x_offset, y_offset, + glyphs, num_glyphs, + &glyphs_info[done], + &x_advance, &y_advance); + else if (max_index < 65536) + status = _cairo_xlib_surface_old_show_glyphs16 (scaled_font, op, + src, self, + x_offset, y_offset, + glyphs, num_glyphs, + &glyphs_info[done], + &x_advance, &y_advance); + else + status = _cairo_xlib_surface_old_show_glyphs32 (scaled_font, op, + src, self, + x_offset, y_offset, + glyphs, num_glyphs, + &glyphs_info[done], + &x_advance, &y_advance); + } else { + while (done < num_glyphs && !status) { + for (boundary = done + 1; boundary < num_glyphs; boundary ++) { + if (glyphs_info[boundary - 1].glyphset != glyphs_info[boundary].glyphset) + break; + } - 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, num_glyphs); - 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, num_glyphs); - 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, num_glyphs); + if (max_index < 256) + status = _cairo_xlib_surface_old_show_glyphs8 (scaled_font, op, + src, self, + x_offset, y_offset, + glyphs, boundary - done, + &glyphs_info[done], + &x_advance, &y_advance); + else if (max_index < 65536) + status = _cairo_xlib_surface_old_show_glyphs16 (scaled_font, op, + src, self, + x_offset, y_offset, + glyphs, boundary - done, + &glyphs_info[done], + &x_advance, &y_advance); + else + status = _cairo_xlib_surface_old_show_glyphs32 (scaled_font, op, + src, self, + x_offset, y_offset, + glyphs, boundary - done, + &glyphs_info[done], + &x_advance, &y_advance); + glyphs += boundary - done; + x_offset += x_advance; + y_offset += y_advance; + done = boundary; + } + } if (status == CAIRO_STATUS_SUCCESS && !_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_t extents; @@ -2490,8 +2615,10 @@ _cairo_xlib_surface_old_show_glyphs (cai dest_x, dest_y, width, height); } - FAIL: + FAIL1: _cairo_pattern_release_surface (pattern, &src->base, &attributes); - + FAIL: + free (glyphs_info); + return status; }