[gtk+] Some fixes for the glyph cache
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Some fixes for the glyph cache
- Date: Mon, 11 Sep 2017 18:03:45 +0000 (UTC)
commit b0d108291bcd49a4a286cfcdc131a1bbb15b46f4
Author: Matthias Clasen <mclasen redhat com>
Date: Mon Sep 11 14:02:44 2017 -0400
Some fixes for the glyph cache
Copy the way cogl does its glyph caching some more.
At the minimum, this fixes problems where we were getting
wrong-sized Emoji inserted.
gsk/gskvulkanrenderer.c | 226 ++++++++++++++++++++---------------------------
1 files changed, 94 insertions(+), 132 deletions(-)
---
diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c
index 558299a..a56fd57 100644
--- a/gsk/gskvulkanrenderer.c
+++ b/gsk/gskvulkanrenderer.c
@@ -32,7 +32,7 @@ typedef struct {
typedef struct _GlyphCache GlyphCache;
struct _GlyphCache {
- GHashTable *fonts;
+ GHashTable *hash_table;
cairo_surface_t *surface;
int width, height;
@@ -386,28 +386,30 @@ gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
return g_object_ref (self->glyph_cache->image);
}
-typedef struct _FontEntry FontEntry;
-typedef struct _GlyphEntry GlyphEntry;
+typedef struct _GlyphCacheKey GlyphCacheKey;
+typedef struct _GlyphCacheValue GlyphCacheValue;
-struct _FontEntry {
+struct _GlyphCacheKey {
PangoFont *font;
- PangoFontDescription *desc;
- guint hash;
- GArray *glyphs;
+ PangoGlyph glyph;
};
-struct _GlyphEntry {
- PangoGlyph glyph;
- float tx, ty, tw, th;
- float ascent, height;
+struct _GlyphCacheValue {
+ float tx;
+ float ty;
+ float tw;
+ float th;
+
+ float draw_x;
+ float draw_y;
+ float draw_width;
+ float draw_height;
};
-static FontEntry *get_font_entry (GlyphCache *cache,
- PangoFont *font);
-static GlyphEntry *get_glyph_entry (GlyphCache *cache,
- FontEntry *fe,
- PangoGlyph glyph,
- gboolean may_add);
+static GlyphCacheValue *glyph_cache_lookup (GlyphCache *cache,
+ gboolean create,
+ PangoFont *font,
+ PangoGlyph glyph);
void
gsk_vulkan_renderer_get_glyph_coords (GskVulkanRenderer *self,
@@ -420,84 +422,74 @@ gsk_vulkan_renderer_get_glyph_coords (GskVulkanRenderer *self,
float *ascent,
float *height)
{
- FontEntry *fe;
- GlyphEntry *ge;
+ GlyphCacheValue *gv;
- fe = get_font_entry (self->glyph_cache, font);
- ge = get_glyph_entry (self->glyph_cache, fe, glyph, FALSE);
+ gv = glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph);
- if (ge)
+ if (gv)
{
- *tx = ge->tx;
- *ty = ge->ty;
- *tw = ge->tw;
- *th = ge->th;
- *ascent = ge->ascent;
- *height = ge->height;
+ *tx = gv->tx;
+ *ty = gv->ty;
+ *tw = gv->tw;
+ *th = gv->th;
+ *ascent = - gv->draw_y;
+ *height = gv->draw_height;
}
}
/*** Glyph cache ***/
static gboolean
-font_equal (gconstpointer v1, gconstpointer v2)
+glyph_cache_equal (gconstpointer v1, gconstpointer v2)
{
- const FontEntry *f1 = v1;
- const FontEntry *f2 = v2;
+ const GlyphCacheKey *key1 = v1;
+ const GlyphCacheKey *key2 = v2;
- return pango_font_description_equal (f1->desc, f2->desc);
+ return key1->font == key2->font &&
+ key1->glyph == key2->glyph;
}
static guint
-font_hash (gconstpointer v)
+glyph_cache_hash (gconstpointer v)
{
- FontEntry *f = (FontEntry *)v;
-
- if (f->hash != 0)
- return f->hash;
+ const GlyphCacheKey *key = v;
- f->hash = pango_font_description_hash (f->desc);
-
- if (f->hash == 0)
- f->hash++;
-
- return f->hash;
+ return GPOINTER_TO_UINT (key->font) ^ key->glyph;
}
static void
-font_entry_free (gpointer v)
+glyph_cache_key_free (gpointer v)
{
- FontEntry *f = v;
+ GlyphCacheKey *f = v;
- pango_font_description_free (f->desc);
g_object_unref (f->font);
- g_array_unref (f->glyphs);
-
g_free (f);
}
static void
-add_to_cache (GlyphCache *cache,
- PangoFont *font,
- PangoGlyph glyph,
- GlyphEntry *ge)
+glyph_cache_value_free (gpointer v)
+{
+ g_free (v);
+}
+
+static void
+add_to_cache (GlyphCache *cache,
+ PangoFont *font,
+ PangoGlyph glyph,
+ GlyphCacheValue *value)
{
- PangoRectangle ink_rect;
cairo_t *cr;
cairo_scaled_font_t *scaled_font;
cairo_glyph_t cg;
- pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
- pango_extents_to_pixels (&ink_rect, NULL);
-
- if (cache->x + ink_rect.width + 1 >= cache->width)
+ if (cache->x + value->draw_width + 1 >= cache->width)
{
/* start a new row */
cache->y0 = cache->y + 1;
cache->x = 1;
}
- if (cache->y0 + ink_rect.height + 1 >= cache->height)
+ if (cache->y0 + value->draw_height + 1 >= cache->height)
{
g_critical ("Drats! Out of cache space. We should really handle this");
return;
@@ -514,80 +506,65 @@ add_to_cache (GlyphCache *cache,
cg.index = glyph;
cg.x = cache->x;
- cg.y = cache->y0 - ink_rect.y;
+ cg.y = cache->y0 - value->draw_y;
cairo_show_glyphs (cr, &cg, 1);
cairo_destroy (cr);
- cache->x = cache->x + ink_rect.width + 1;
- cache->y = MAX (cache->y, cache->y0 + ink_rect.height + 1);
+ cache->x = cache->x + value->draw_width + 1;
+ cache->y = MAX (cache->y, cache->y0 + value->draw_height + 1);
- ge->glyph = glyph;
- ge->tx = cg.x / cache->width;
- ge->ty = (cg.y + ink_rect.y) / cache->height;
- ge->tw = (float)ink_rect.width / cache->width;
- ge->th = (float)ink_rect.height / cache->height;
- ge->ascent = (float) - ink_rect.y;
- ge->height = (float) ink_rect.height;
+ value->tx = cg.x / cache->width;
+ value->ty = (cg.y + value->draw_y) / cache->height;
+ value->tw = (float)value->draw_width / cache->width;
+ value->th = (float)value->draw_height / cache->height;
}
-static GlyphEntry *
-get_glyph_entry (GlyphCache *cache,
- FontEntry *fe,
- PangoGlyph glyph,
- gboolean may_add)
+static GlyphCacheValue *
+glyph_cache_lookup (GlyphCache *cache,
+ gboolean create,
+ PangoFont *font,
+ PangoGlyph glyph)
{
- int i;
- GlyphEntry g;
- GlyphEntry *ge;
+ GlyphCacheKey lookup_key;
+ GlyphCacheValue *value;
- for (i = 0; i < fe->glyphs->len; i++)
- {
- ge = &g_array_index (fe->glyphs, GlyphEntry, i);
+ lookup_key.font = font;
+ lookup_key.glyph = glyph;
- if (ge->glyph == glyph)
- return ge;
- }
+ value = g_hash_table_lookup (cache->hash_table, &lookup_key);
- if (!may_add)
- return NULL;
+ if (create && value == NULL)
+ {
+ GlyphCacheKey *key;
+ PangoRectangle ink_rect;
- g_clear_object (&cache->image);
+ value = g_new (GlyphCacheValue, 1);
- add_to_cache (cache, fe->font, glyph, &g);
+ pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
+ pango_extents_to_pixels (&ink_rect, NULL);
- g_array_append_val (fe->glyphs, g);
- ge = &g_array_index (fe->glyphs, GlyphEntry, fe->glyphs->len - 1);
+ value->draw_x = ink_rect.x;
+ value->draw_y = ink_rect.y;
+ value->draw_width = ink_rect.width;
+ value->draw_height = ink_rect.height;
- return ge;
-}
+ if (ink_rect.width > 0 && ink_rect.height > 0)
+ {
+ add_to_cache (cache, font, glyph, value);
-static FontEntry *
-get_font_entry (GlyphCache *cache,
- PangoFont *font)
-{
- FontEntry key;
- FontEntry *fe;
+ g_clear_object (&cache->image);
+ }
- key.font = font;
- key.desc = pango_font_describe (font);
- key.hash = 0;
+ key = g_new (GlyphCacheKey, 1);
+ key->font = g_object_ref (font);
+ key->glyph = glyph;
- fe = g_hash_table_lookup (cache->fonts, &key);
- if (fe == NULL)
- {
- fe = g_new0 (FontEntry, 1);
- fe->font = g_object_ref (font);
- fe->desc = key.desc;
- fe->hash = 0;
- fe->glyphs = g_array_sized_new (FALSE, FALSE, sizeof (GlyphEntry), 256);
- g_hash_table_add (cache->fonts, fe);
+ g_hash_table_insert (cache->hash_table, key, value);
}
- else
- pango_font_description_free (key.desc);
- return fe;
+ return value;
}
void
@@ -595,11 +572,8 @@ gsk_vulkan_renderer_cache_glyphs (GskVulkanRenderer *self,
PangoFont *font,
PangoGlyphString *glyphs)
{
- FontEntry *fe;
int i;
- fe = get_font_entry (self->glyph_cache, font);
-
for (i = 0; i < glyphs->num_glyphs; i++)
{
PangoGlyphInfo *gi = &glyphs->glyphs[i];
@@ -607,7 +581,7 @@ gsk_vulkan_renderer_cache_glyphs (GskVulkanRenderer *self,
if (gi->glyph != PANGO_GLYPH_EMPTY)
{
if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
- get_glyph_entry (self->glyph_cache, fe, gi->glyph, TRUE);
+ (void) glyph_cache_lookup (self->glyph_cache, TRUE, font, gi->glyph);
}
}
}
@@ -618,7 +592,8 @@ create_glyph_cache (void)
GlyphCache *cache;
cache = g_new0 (GlyphCache, 1);
- cache->fonts = g_hash_table_new_full (font_hash, font_equal, NULL, font_entry_free);
+ cache->hash_table = g_hash_table_new_full (glyph_cache_hash, glyph_cache_equal,
+ glyph_cache_key_free, glyph_cache_value_free);
cache->width = 1024;
cache->height = 1024;
cache->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, cache->width, cache->height);
@@ -632,7 +607,7 @@ create_glyph_cache (void)
static void
free_glyph_cache (GlyphCache *cache)
{
- g_hash_table_unref (cache->fonts);
+ g_hash_table_unref (cache->hash_table);
cairo_surface_destroy (cache->surface);
g_free (cache);
}
@@ -640,12 +615,10 @@ free_glyph_cache (GlyphCache *cache)
static void
dump_glyph_cache_stats (GlyphCache *cache)
{
- GHashTableIter iter;
- FontEntry *fe;
static gint64 time;
gint64 now;
- if (!cache->fonts)
+ if (!cache->hash_table)
return;
now = g_get_monotonic_time ();
@@ -654,16 +627,5 @@ dump_glyph_cache_stats (GlyphCache *cache)
time = now;
- g_print ("Glyph cache:\n");
- g_hash_table_iter_init (&iter, cache->fonts);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&fe))
- {
- char *s;
-
- s = pango_font_description_to_string (fe->desc);
- g_print ("%s: %d glyphs cached\n", s, fe->glyphs->len);
- g_free (s);
- }
- g_print ("---\n");
- cairo_surface_write_to_png (cache->surface, "glyph-cache.png");
+ cairo_surface_write_to_png (cache->surface, "gsk-glyph-cache.png");
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]