From 9eba3c899c4d6e91b69ebf93aeca386e77eb8638 Mon Sep 17 00:00:00 2001 Message-Id: <9eba3c899c4d6e91b69ebf93aeca386e77eb8638.1505152993.git.jan.steffens@gmail.com> From: "Jan Alexander Steffens (heftig)" Date: Mon, 11 Sep 2017 19:46:06 +0200 Subject: [PATCH] Hacky hack: Use color glyph alpha as mask - When loading a color glyph, separate the alpha channel and save it as the non-color surface. - Use the non-color surface as the mask when compositing color glyphs. - Plug a leak of patterns in composite_one_color_glyph => Drawing glyphs with CAIRO_OPERATOR_SOURCE no longer clears dest. In general the handling of color glyphs should match the handling of normal glyphs now, except for the source color. => Possible extension: Let the user deactivate color glyph handling (in the context? in the pattern?) in order to draw with the chosen source instead, for things like text shadows. Since the normal surface is the alpha mask now, this handles color glyphs nicely. To do that, just have it override the check of _cairo_scaled_font_has_color_glyphs to be false. My ignorance of cairo and pixman internals means this is probably terrible code. --- src/cairo-ft-font.c | 34 +++++++++++++++++++++++++++++++++- src/cairo-surface.c | 19 ++++++++++++------- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 3b3087578927e54e..2f9aff2defb444e5 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -2475,9 +2475,41 @@ LOAD: if (pixman_image_get_format (surface->pixman_image) == PIXMAN_a8r8g8b8 && !pixman_image_get_component_alpha (surface->pixman_image)) { + cairo_surface_t *alpha_surface, *color_surface; + cairo_pattern_t *pattern; + + /* XXX: HACK */ + alpha_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, + surface->width, + surface->height); + color_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + surface->width, + surface->height); + pattern = cairo_pattern_create_for_surface (&surface->base); + status |= alpha_surface->backend->paint (alpha_surface, CAIRO_OPERATOR_SOURCE, pattern, NULL); + status |= color_surface->backend->paint (color_surface, CAIRO_OPERATOR_SOURCE, pattern, NULL); + cairo_surface_set_device_offset (color_surface, + surface->base.device_transform.x0, + surface->base.device_transform.y0); + cairo_surface_set_device_offset (alpha_surface, + surface->base.device_transform.x0, + surface->base.device_transform.y0); + cairo_surface_destroy (&surface->base); + cairo_pattern_destroy (pattern); + + if (unlikely (status)) { + cairo_surface_destroy (alpha_surface); + cairo_surface_destroy (color_surface); + goto FAIL; + } + + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t *) alpha_surface); + _cairo_scaled_glyph_set_color_surface (scaled_glyph, &scaled_font->base, - surface); + (cairo_image_surface_t *) color_surface); } else { _cairo_scaled_glyph_set_surface (scaled_glyph, &scaled_font->base, diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 6f25bd7c044f2400..49fcd9f8dfcbcdf0 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -2547,31 +2547,36 @@ ensure_scaled_glyph (cairo_scaled_font_t *scaled_font, static inline cairo_int_status_t composite_one_color_glyph (cairo_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *source, + const cairo_pattern_t *unused_source, const cairo_clip_t *clip, cairo_glyph_t *glyph, cairo_scaled_glyph_t *scaled_glyph) { cairo_int_status_t status; cairo_image_surface_t *glyph_surface; - cairo_pattern_t *pattern; - cairo_matrix_t matrix; status = CAIRO_INT_STATUS_SUCCESS; - glyph_surface = scaled_glyph->color_surface; + glyph_surface = scaled_glyph->surface; if (glyph_surface->width && glyph_surface->height) { + cairo_pattern_t *source, *mask; + cairo_matrix_t matrix; int x, y; + /* round glyph locations to the nearest pixels */ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ x = _cairo_lround (glyph->x - glyph_surface->base.device_transform.x0); y = _cairo_lround (glyph->y - glyph_surface->base.device_transform.y0); - pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface); + source = cairo_pattern_create_for_surface (&scaled_glyph->color_surface->base); + mask = cairo_pattern_create_for_surface (&glyph_surface->base); cairo_matrix_init_translate (&matrix, - x, - y); - cairo_pattern_set_matrix (pattern, &matrix); - status = surface->backend->paint (surface, op, pattern, clip); + cairo_pattern_set_matrix (source, &matrix); + cairo_pattern_set_matrix (mask, &matrix); + status = surface->backend->mask (surface, op, source, mask, clip); + cairo_pattern_destroy (source); + cairo_pattern_destroy (mask); } return status; -- 2.14.1