diff --git a/particles/string.c b/particles/string.c index 51ab520..4ffd119 100644 --- a/particles/string.c +++ b/particles/string.c @@ -15,8 +15,16 @@ struct private { }; struct eprivate { + /* Set when instantiating */ char *text; + + /* Set in begin_expose() */ cairo_text_extents_t extents; + cairo_glyph_t *glyphs; + cairo_text_cluster_t *clusters; + cairo_text_cluster_flags_t cluster_flags; + int num_glyphs; + int num_clusters; }; static void @@ -34,21 +42,21 @@ begin_expose(struct exposable *exposable) struct eprivate *e = exposable->private; cairo_scaled_font_t *scaled = font_scaled_font(exposable->particle->font); - - cairo_glyph_t *glyphs = NULL; - int num_glyphs; cairo_status_t status = cairo_scaled_font_text_to_glyphs( - scaled, 0, 0, e->text, -1, &glyphs, &num_glyphs, NULL, NULL, NULL); + scaled, 0, 0, e->text, -1, &e->glyphs, &e->num_glyphs, + &e->clusters, &e->num_clusters, &e->cluster_flags); if (status != CAIRO_STATUS_SUCCESS) { LOG_WARN("failed to convert \"%s\" to glyphs: %s", e->text, cairo_status_to_string(status)); + e->num_glyphs = -1; + e->num_clusters = -1; memset(&e->extents, 0, sizeof(e->extents)); exposable->width = 0; } else { - cairo_scaled_font_glyph_extents(scaled, glyphs, num_glyphs, &e->extents); - cairo_glyph_free(glyphs); + cairo_scaled_font_glyph_extents( + scaled, e->glyphs, e->num_glyphs, &e->extents); exposable->width = (exposable->particle->left_margin + e->extents.x_advance + @@ -64,38 +72,32 @@ expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) exposable_render_deco(exposable, cr, x, y, height); const struct eprivate *e = exposable->private; - const size_t text_len = strlen(e->text); + + if (e->num_glyphs == -1) + return; + + /* Adjust glyph offsets */ + for (int i = 0; i < e->num_glyphs; i++) { + e->glyphs[i].x += x + exposable->particle->left_margin; + e->glyphs[i].y += (double)y + + ((double)height - e->extents.height) / 2 - e->extents.y_bearing; + } cairo_scaled_font_t *scaled = font_scaled_font(exposable->particle->font); + cairo_set_scaled_font(cr, scaled); + cairo_set_source_rgba(cr, + exposable->particle->foreground.red, + exposable->particle->foreground.green, + exposable->particle->foreground.blue, + exposable->particle->foreground.alpha); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_glyph_t *glyphs = NULL; - cairo_text_cluster_t *clusters = NULL; - cairo_text_cluster_flags_t cluster_flags; - int num_glyphs, num_clusters; + cairo_show_text_glyphs( + cr, e->text, -1, e->glyphs, e->num_glyphs, + e->clusters, e->num_clusters, e->cluster_flags); - cairo_status_t status = cairo_scaled_font_text_to_glyphs( - scaled, - x + exposable->particle->left_margin, - (double)y + ((double)height - e->extents.height) / 2 - e->extents.y_bearing, - e->text, text_len, &glyphs, &num_glyphs, - &clusters, &num_clusters, &cluster_flags); - - if (status == CAIRO_STATUS_SUCCESS) { - cairo_set_scaled_font(cr, scaled); - cairo_set_source_rgba(cr, - exposable->particle->foreground.red, - exposable->particle->foreground.green, - exposable->particle->foreground.blue, - exposable->particle->foreground.alpha); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - cairo_show_text_glyphs( - cr, e->text, text_len, glyphs, num_glyphs, - clusters, num_clusters, cluster_flags); - - cairo_glyph_free(glyphs); - cairo_text_cluster_free(clusters); - } + cairo_glyph_free(e->glyphs); + cairo_text_cluster_free(e->clusters); } static struct exposable * @@ -106,6 +108,10 @@ instantiate(const struct particle *particle, const struct tag_set *tags) e->text = tags_expand_template(p->text, tags); memset(&e->extents, 0, sizeof(e->extents)); + e->glyphs = NULL; + e->clusters = NULL; + e->num_glyphs = -1; + e->num_clusters = -1; if (p->max_len > 0) { const size_t len = strlen(e->text);