mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-01 06:48:01 +02:00
Render color glyphs as source, not as mask
Use paint instead of show_glyphs for color glyphs. To avoid overhead, we only check for color glyphs if the font is known to contain any. Paint clusters containing only color glyphs and rewrite the inputs to remove the handled clusters and glyphs.
This commit is contained in:
parent
6a8a25cc47
commit
db14d6d707
1 changed files with 257 additions and 1 deletions
|
|
@ -508,7 +508,7 @@ cairo_surface_create_similar (cairo_surface_t *other,
|
|||
if (unlikely (! CAIRO_CONTENT_VALID (content)))
|
||||
return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
|
||||
|
||||
if (unlikely (other->status))
|
||||
if (unlikely (other->status))
|
||||
return _cairo_surface_create_in_error (other->status);
|
||||
|
||||
/* We inherit the device scale, so create a larger surface */
|
||||
|
|
@ -2521,6 +2521,240 @@ cairo_surface_has_show_text_glyphs (cairo_surface_t *surface)
|
|||
}
|
||||
slim_hidden_def (cairo_surface_has_show_text_glyphs);
|
||||
|
||||
#define GLYPH_CACHE_SIZE 64
|
||||
|
||||
static cairo_bool_t
|
||||
has_color_glyphs (cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
cairo_scaled_glyph_t **glyph_cache)
|
||||
{
|
||||
cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
|
||||
int i;
|
||||
cairo_bool_t has_color = FALSE;
|
||||
|
||||
_cairo_scaled_font_freeze_cache (scaled_font);
|
||||
|
||||
for (i = 0; i < num_glyphs; i++) {
|
||||
cairo_scaled_glyph_t *scaled_glyph;
|
||||
unsigned long glyph_index = glyphs[i].index;
|
||||
int cache_index = glyph_index % GLYPH_CACHE_SIZE;
|
||||
|
||||
scaled_glyph = glyph_cache[cache_index];
|
||||
if (scaled_glyph == NULL ||
|
||||
_cairo_scaled_glyph_index (scaled_glyph) != glyph_index) {
|
||||
status = _cairo_scaled_glyph_lookup (scaled_font,
|
||||
glyphs[i].index,
|
||||
CAIRO_SCALED_GLYPH_INFO_SURFACE,
|
||||
&scaled_glyph);
|
||||
if (unlikely (status)) {
|
||||
status = _cairo_scaled_font_set_error (scaled_font, status);
|
||||
break;
|
||||
}
|
||||
|
||||
glyph_cache[cache_index] = scaled_glyph;
|
||||
}
|
||||
|
||||
if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) != 0) {
|
||||
has_color = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_cairo_scaled_font_thaw_cache (scaled_font);
|
||||
return has_color;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
composite_color_glyphs (cairo_surface_t *surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *source,
|
||||
char *utf8,
|
||||
int *utf8_len,
|
||||
cairo_glyph_t *glyphs,
|
||||
int *num_glyphs,
|
||||
cairo_text_cluster_t *clusters,
|
||||
int *num_clusters,
|
||||
cairo_text_cluster_flags_t cluster_flags,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
const cairo_clip_t *clip,
|
||||
cairo_scaled_glyph_t **glyph_cache)
|
||||
{
|
||||
cairo_int_status_t status;
|
||||
int i, j;
|
||||
cairo_scaled_glyph_t *scaled_glyph;
|
||||
cairo_image_surface_t *glyph_surface;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_matrix_t matrix;
|
||||
unsigned long glyph_index;
|
||||
int cache_index;
|
||||
int remaining_clusters = 0;
|
||||
int remaining_glyphs = 0;
|
||||
int remaining_bytes = 0;
|
||||
int glyph_pos = 0;
|
||||
int byte_pos = 0;
|
||||
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
_cairo_scaled_font_freeze_cache (scaled_font);
|
||||
|
||||
if (clusters) {
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
glyph_pos = *num_glyphs - 1;
|
||||
|
||||
for (i = 0; i < *num_clusters; i++) {
|
||||
cairo_bool_t skip_cluster = FALSE;
|
||||
|
||||
for (j = 0; j < clusters[i].num_glyphs; j++) {
|
||||
int gp;
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
gp = glyph_pos - j;
|
||||
else
|
||||
gp = glyph_pos + j;
|
||||
|
||||
glyph_index = glyphs[gp].index;
|
||||
cache_index = glyph_index % GLYPH_CACHE_SIZE;
|
||||
scaled_glyph = glyph_cache[cache_index];
|
||||
if (scaled_glyph == NULL ||
|
||||
_cairo_scaled_glyph_index (scaled_glyph) != glyph_index) {
|
||||
status = _cairo_scaled_glyph_lookup (scaled_font,
|
||||
glyph_index,
|
||||
CAIRO_SCALED_GLYPH_INFO_SURFACE,
|
||||
&scaled_glyph);
|
||||
if (unlikely (status)) {
|
||||
status = _cairo_scaled_font_set_error (scaled_font, status);
|
||||
goto UNLOCK;
|
||||
}
|
||||
glyph_cache[cache_index] = scaled_glyph;
|
||||
}
|
||||
if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) == 0) {
|
||||
skip_cluster = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_cluster) {
|
||||
memmove (utf8 + remaining_bytes, utf8 + byte_pos, clusters[i].num_bytes);
|
||||
remaining_bytes += clusters[i].num_bytes;
|
||||
byte_pos += clusters[i].num_bytes;
|
||||
for (j = 0; j < clusters[i].num_glyphs; j++, remaining_glyphs++) {
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
glyphs[*num_glyphs - 1 - remaining_glyphs] = glyphs[glyph_pos--];
|
||||
else
|
||||
glyphs[remaining_glyphs] = glyphs[glyph_pos++];
|
||||
}
|
||||
clusters[remaining_clusters++] = clusters[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < clusters[i].num_glyphs; j++) {
|
||||
int gp;
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
gp = glyph_pos - j;
|
||||
else
|
||||
gp = glyph_pos + j;
|
||||
|
||||
glyph_index = glyphs[gp].index;
|
||||
cache_index = glyph_index % GLYPH_CACHE_SIZE;
|
||||
scaled_glyph = glyph_cache[cache_index];
|
||||
if (scaled_glyph == NULL ||
|
||||
_cairo_scaled_glyph_index (scaled_glyph) != glyph_index) {
|
||||
status = _cairo_scaled_glyph_lookup (scaled_font,
|
||||
glyph_index,
|
||||
CAIRO_SCALED_GLYPH_INFO_SURFACE,
|
||||
&scaled_glyph);
|
||||
if (unlikely (status)) {
|
||||
status = _cairo_scaled_font_set_error (scaled_font, status);
|
||||
goto UNLOCK;
|
||||
}
|
||||
glyph_cache[cache_index] = scaled_glyph;
|
||||
}
|
||||
glyph_surface = scaled_glyph->color_surface;
|
||||
|
||||
if (glyph_surface->width && glyph_surface->height) {
|
||||
int x, y;
|
||||
/* round glyph locations to the nearest pixels */
|
||||
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
|
||||
x = _cairo_lround (glyphs[gp].x - glyph_surface->base.device_transform.x0);
|
||||
y = _cairo_lround (glyphs[gp].y - glyph_surface->base.device_transform.y0);
|
||||
|
||||
pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface);
|
||||
cairo_matrix_init_translate (&matrix, - x, - y);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
status = surface->backend->paint (surface, op, pattern, clip);
|
||||
if (unlikely (status))
|
||||
goto UNLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
glyph_pos -= clusters[i].num_glyphs;
|
||||
else
|
||||
glyph_pos += clusters[i].num_glyphs;
|
||||
|
||||
byte_pos += clusters[i].num_bytes;
|
||||
}
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
memmove (utf8, utf8 + *utf8_len - remaining_bytes, remaining_bytes);
|
||||
|
||||
*utf8_len = remaining_bytes;
|
||||
*num_glyphs = remaining_glyphs;
|
||||
*num_clusters = remaining_clusters;
|
||||
|
||||
} else {
|
||||
|
||||
for (glyph_pos = 0; glyph_pos < *num_glyphs; glyph_pos++) {
|
||||
glyph_index = glyphs[glyph_pos].index;
|
||||
cache_index = glyph_index % GLYPH_CACHE_SIZE;
|
||||
scaled_glyph = glyph_cache[cache_index];
|
||||
if (scaled_glyph == NULL ||
|
||||
_cairo_scaled_glyph_index (scaled_glyph) != glyph_index) {
|
||||
status = _cairo_scaled_glyph_lookup (scaled_font,
|
||||
glyph_index,
|
||||
CAIRO_SCALED_GLYPH_INFO_SURFACE,
|
||||
&scaled_glyph);
|
||||
if (unlikely (status)) {
|
||||
status = _cairo_scaled_font_set_error (scaled_font, status);
|
||||
goto UNLOCK;
|
||||
}
|
||||
glyph_cache[cache_index] = scaled_glyph;
|
||||
}
|
||||
|
||||
if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) == 0) {
|
||||
glyphs[remaining_glyphs++] = glyphs[glyph_pos];
|
||||
continue;
|
||||
}
|
||||
|
||||
glyph_surface = scaled_glyph->color_surface;
|
||||
|
||||
if (glyph_surface->width && glyph_surface->height) {
|
||||
int x, y;
|
||||
/* round glyph locations to the nearest pixels */
|
||||
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
|
||||
x = _cairo_lround (glyphs[glyph_pos].x - glyph_surface->base.device_transform.x0);
|
||||
y = _cairo_lround (glyphs[glyph_pos].y - glyph_surface->base.device_transform.y0);
|
||||
|
||||
pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface);
|
||||
cairo_matrix_init_translate (&matrix, - x, - y);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
status = surface->backend->paint (surface, op, pattern, clip);
|
||||
if (unlikely (status))
|
||||
goto UNLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
*num_glyphs = remaining_glyphs;
|
||||
}
|
||||
|
||||
UNLOCK:
|
||||
_cairo_scaled_font_thaw_cache (scaled_font);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Note: the backends may modify the contents of the glyph array as long as
|
||||
* they do not return %CAIRO_INT_STATUS_UNSUPPORTED. This makes it possible to
|
||||
* avoid copying the array again and again, and edit it in-place.
|
||||
|
|
@ -2577,6 +2811,27 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
|
|||
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (_cairo_scaled_font_has_color_glyphs (scaled_font)) {
|
||||
cairo_scaled_glyph_t *glyph_cache[GLYPH_CACHE_SIZE];
|
||||
memset (glyph_cache, 0, sizeof (glyph_cache));
|
||||
if (has_color_glyphs (glyphs, num_glyphs, scaled_font, glyph_cache)) {
|
||||
status = composite_color_glyphs (surface, op,
|
||||
source,
|
||||
(char *)utf8, &utf8_len,
|
||||
glyphs, &num_glyphs,
|
||||
(cairo_text_cluster_t *)clusters, &num_clusters, cluster_flags,
|
||||
scaled_font,
|
||||
clip,
|
||||
glyph_cache);
|
||||
|
||||
if (unlikely (status))
|
||||
goto DONE;
|
||||
|
||||
if (num_glyphs == 0)
|
||||
goto DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
|
||||
* show_text_glyphs. Keep in synch. */
|
||||
if (clusters) {
|
||||
|
|
@ -2627,6 +2882,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
|
|||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
|
||||
surface->is_clear = FALSE;
|
||||
surface->serial++;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue