diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c index b0afc5d48..21fd776a9 100644 --- a/src/cairo-image-compositor.c +++ b/src/cairo-image-compositor.c @@ -819,22 +819,46 @@ composite_glyphs_via_mask (void *_dst, cairo_composite_glyphs_info_t *info) { cairo_scaled_glyph_t *glyph_cache[64]; - cairo_bool_t component_alpha = FALSE; + pixman_image_t *white = _pixman_image_for_color (CAIRO_COLOR_WHITE); + cairo_scaled_glyph_t *scaled_glyph; uint8_t buf[2048]; pixman_image_t *mask; + pixman_format_code_t format; cairo_status_t status; int i; TRACE ((stderr, "%s\n", __FUNCTION__)); + if (unlikely (white == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit * optimised paths through pixman. Should we increase the bit * depth of the target surface, we should reconsider the appropriate * mask formats. */ + + status = _cairo_scaled_glyph_lookup (info->font, + info->glyphs[0].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + if (unlikely (status)) { + pixman_image_unref (white); + return status; + } + + memset (glyph_cache, 0, sizeof (glyph_cache)); + glyph_cache[info->glyphs[0].index % ARRAY_LENGTH (glyph_cache)] = scaled_glyph; + + format = PIXMAN_a8; i = (info->extents.width + 3) & ~3; + if (scaled_glyph->surface->base.content & CAIRO_CONTENT_COLOR) { + format = PIXMAN_a8r8g8b8; + i = info->extents.width * 3; + } + if (i * info->extents.height > (int) sizeof (buf)) { - mask = pixman_image_create_bits (PIXMAN_a8, + mask = pixman_image_create_bits (format, info->extents.width, info->extents.height, NULL, 0); @@ -845,17 +869,16 @@ composite_glyphs_via_mask (void *_dst, info->extents.height, (uint32_t *)buf, i); } - if (unlikely (mask == NULL)) + if (unlikely (mask == NULL)) { + pixman_image_unref (white); return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } - memset (glyph_cache, 0, sizeof (glyph_cache)); status = CAIRO_STATUS_SUCCESS; - for (i = 0; i < info->num_glyphs; i++) { - cairo_image_surface_t *glyph_surface; - cairo_scaled_glyph_t *scaled_glyph; unsigned long glyph_index = info->glyphs[i].index; int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache); + cairo_image_surface_t *glyph_surface; int x, y; scaled_glyph = glyph_cache[cache_index]; @@ -868,6 +891,7 @@ composite_glyphs_via_mask (void *_dst, if (unlikely (status)) { pixman_image_unref (mask); + pixman_image_unref (white); return status; } @@ -877,20 +901,22 @@ composite_glyphs_via_mask (void *_dst, glyph_surface = scaled_glyph->surface; if (glyph_surface->width && glyph_surface->height) { if (glyph_surface->base.content & CAIRO_CONTENT_COLOR && - ! component_alpha) { + format == PIXMAN_a8) { pixman_image_t *ca_mask; - ca_mask = pixman_image_create_bits (PIXMAN_a8r8g8b8, + format = PIXMAN_a8r8g8b8; + ca_mask = pixman_image_create_bits (format, info->extents.width, info->extents.height, NULL, 0); if (unlikely (ca_mask == NULL)) { pixman_image_unref (mask); + pixman_image_unref (white); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } pixman_image_composite32 (PIXMAN_OP_SRC, - mask, 0, ca_mask, + white, mask, ca_mask, 0, 0, 0, 0, 0, 0, @@ -898,7 +924,6 @@ composite_glyphs_via_mask (void *_dst, info->extents.height); pixman_image_unref (mask); mask = ca_mask; - component_alpha = TRUE; } /* round glyph locations to the nearest pixel */ @@ -908,17 +933,27 @@ composite_glyphs_via_mask (void *_dst, y = _cairo_lround (info->glyphs[i].y - glyph_surface->base.device_transform.y0); - pixman_image_composite32 (PIXMAN_OP_ADD, - glyph_surface->pixman_image, NULL, mask, - 0, 0, - 0, 0, - x - info->extents.x, y - info->extents.y, - glyph_surface->width, - glyph_surface->height); + if (glyph_surface->pixman_format == format) { + pixman_image_composite32 (PIXMAN_OP_ADD, + glyph_surface->pixman_image, NULL, mask, + 0, 0, + 0, 0, + x - info->extents.x, y - info->extents.y, + glyph_surface->width, + glyph_surface->height); + } else { + pixman_image_composite32 (PIXMAN_OP_ADD, + white, glyph_surface->pixman_image, mask, + 0, 0, + 0, 0, + x - info->extents.x, y - info->extents.y, + glyph_surface->width, + glyph_surface->height); + } } } - if (component_alpha) + if (format == PIXMAN_a8r8g8b8) pixman_image_set_component_alpha (mask, TRUE); pixman_image_composite32 (_pixman_operator (op), @@ -930,6 +965,7 @@ composite_glyphs_via_mask (void *_dst, info->extents.x - dst_x, info->extents.y - dst_y, info->extents.width, info->extents.height); pixman_image_unref (mask); + pixman_image_unref (white); return CAIRO_STATUS_SUCCESS; }