mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-27 02:00:28 +01:00
image: Upconvert glyphs through a WHITE source when adding to the glyph mask
We need to scale the channels of the glyph into the destination (and indeed expand a8 into a8r8g8b8) when adding into the mask. Normally we have matching formats for the glyph surfaces and the temporary mask, for which we can continue to take the faster path. Reported-by: Søren Sandmann <sandmann@cs.au.dk> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
3f325764e5
commit
7d8d98b91c
1 changed files with 55 additions and 19 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue