Index: cairo-xlib-surface.c =================================================================== RCS file: /cvs/cairo/cairo/src/cairo-xlib-surface.c,v retrieving revision 1.121 diff -u -p -r1.121 cairo-xlib-surface.c --- cairo-xlib-surface.c 20 Sep 2005 00:24:52 -0000 1.121 +++ cairo-xlib-surface.c 28 Sep 2005 14:14:46 -0000 @@ -2005,38 +2005,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); } } @@ -2049,8 +2097,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); } } @@ -2073,16 +2123,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 @@ -2187,7 +2244,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); @@ -2201,16 +2258,18 @@ _cairo_xlib_surface_add_glyph (Display * #define N_STACK_BUF 1024 static cairo_status_t -_cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, - cairo_operator_t operator, - 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_scaled_font_t *scaled_font, + cairo_operator_t operator, + 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]; @@ -2238,7 +2297,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 = glyph_info->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2251,7 +2310,7 @@ _cairo_xlib_surface_show_glyphs8 (cairo _render_operator (operator), 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); @@ -2259,20 +2318,25 @@ _cairo_xlib_surface_show_glyphs8 (cairo if (elts != stack_elts) free (elts); + *x_advance = elts[num_glyphs - 1].xOff; + *y_advance = elts[num_glyphs - 1].yOff; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font, - cairo_operator_t operator, - 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_scaled_font_t *scaled_font, + cairo_operator_t operator, + 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]; @@ -2300,7 +2364,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 = glyph_info->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2313,7 +2377,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo _render_operator (operator), 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); @@ -2321,20 +2385,25 @@ _cairo_xlib_surface_show_glyphs16 (cairo if (elts != stack_elts) free (elts); + *x_advance = elts[num_glyphs - 1].xOff; + *y_advance = elts[num_glyphs - 1].yOff; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font, - cairo_operator_t operator, - 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_scaled_font_t *scaled_font, + cairo_operator_t operator, + 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]; @@ -2362,7 +2431,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 = glyph_info->glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; @@ -2375,7 +2444,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo _render_operator (operator), 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); @@ -2383,6 +2452,9 @@ _cairo_xlib_surface_show_glyphs32 (cairo if (elts != stack_elts) free (elts); + *x_advance = elts[num_glyphs - 1].xOff; + *y_advance = elts[num_glyphs - 1].yOff; + return CAIRO_STATUS_SUCCESS; } @@ -2406,9 +2478,13 @@ _cairo_xlib_surface_show_glyphs (cairo_s 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) @@ -2424,23 +2500,27 @@ _cairo_xlib_surface_show_glyphs (cairo_s (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, operator, 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) @@ -2453,28 +2533,73 @@ _cairo_xlib_surface_show_glyphs (cairo_s 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_show_glyphs8 (scaled_font, operator, + 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_show_glyphs16 (scaled_font, operator, + src, self, + x_offset, y_offset, + glyphs, num_glyphs, + &glyphs_info[done], + &x_advance, &y_advance); + else + status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, + 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_show_glyphs8 (scaled_font, operator, 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_show_glyphs16 (scaled_font, operator, src, self, - source_x + attributes.x_offset - dest_x, - source_y + attributes.y_offset - dest_y, - glyphs, num_glyphs); - else - status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, 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_show_glyphs8 (scaled_font, operator, + 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_show_glyphs16 (scaled_font, operator, + src, self, + x_offset, y_offset, + glyphs, boundary - done, + &glyphs_info[done], + &x_advance, &y_advance); + else + status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, + 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 (operator)) { cairo_rectangle_t extents; @@ -2491,8 +2616,10 @@ _cairo_xlib_surface_show_glyphs (cairo_s dest_x, dest_y, width, height); } - FAIL: + FAIL1: _cairo_pattern_release_surface (pattern, &src->base, &attributes); - + FAIL: + free (glyphs_info); + return status; }