summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@ximian.com>2005-11-04 23:13:07 +0000
committerFederico Mena Quintero <federico@src.gnome.org>2005-11-04 23:13:07 +0000
commit933f541030f770b446d95bb0b5b3c85d561a63e5 (patch)
tree837f1f6c93a93396580d5086a9bfdb8b7162f8f8
parent69bbb89d5436cae4602579f952d68e84efe9ec24 (diff)
downloadpango-933f541030f770b446d95bb0b5b3c85d561a63e5.tar.gz
Fixes #320665:
2005-11-04 Federico Mena Quintero <federico@ximian.com> Fixes #320665: * pango/pangocairo-fcfont.c: Use a simple, fixed-size cache to map gunichars to glyph indices within the font. The cache is described in detail here: http://primates.ximian.com/~federico/news-2005-10.html#gtkfilechooser-profile-5 (GlyphCacheEntry): new structure to hold a gunichar and a PangoGlyph. (struct _PangoCairoFcFont): Add a char_to_glyph_cache field. (pango_cairo_fc_font_get_glyph): Allocate the char_to_glyph_cache if needed. We do it on demand because while many fonts will be alive at any one time (in order to cover the whole Unicode space), only very few of them will be actually accessed for glyph lookups. (pango_cairo_fc_font_get_glyph): Look up the gunichar in the cache, and replace the cache entry if necessary. (pango_cairo_fc_font_finalize): Free the char_to_glyph_cache.
-rw-r--r--ChangeLog18
-rw-r--r--pango/pangocairo-fcfont.c111
2 files changed, 129 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index fc15b70d..d333d222 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2005-11-04 Federico Mena Quintero <federico@ximian.com>
+
+ Fixes #320665:
+
+ * pango/pangocairo-fcfont.c: Use a simple, fixed-size cache to map
+ gunichars to glyph indices within the font. The cache is
+ described in detail here:
+ http://primates.ximian.com/~federico/news-2005-10.html#gtkfilechooser-profile-5
+ (GlyphCacheEntry): new structure to hold a gunichar and a PangoGlyph.
+ (struct _PangoCairoFcFont): Add a char_to_glyph_cache field.
+ (pango_cairo_fc_font_get_glyph): Allocate the char_to_glyph_cache
+ if needed. We do it on demand because while many fonts will be
+ alive at any one time (in order to cover the whole Unicode space),
+ only very few of them will be actually accessed for glyph lookups.
+ (pango_cairo_fc_font_get_glyph): Look up the gunichar in the
+ cache, and replace the cache entry if necessary.
+ (pango_cairo_fc_font_finalize): Free the char_to_glyph_cache.
+
2005-11-04 Behdad Esfahbod <behdad@gnome.org>
* pango/pangocairo-fontmap.c: Use quarks for GObject data to improve
diff --git a/pango/pangocairo-fcfont.c b/pango/pangocairo-fcfont.c
index eb6825ef..156ff988 100644
--- a/pango/pangocairo-fcfont.c
+++ b/pango/pangocairo-fcfont.c
@@ -44,6 +44,32 @@ typedef struct _PangoCairoFcFont PangoCairoFcFont;
typedef struct _PangoCairoFcFontClass PangoCairoFcFontClass;
typedef struct _PangoCairoFcGlyphInfo PangoCairoFcGlyphInfo;
+#undef PROFILE_GLYPH_CACHE
+#ifdef PROFILE_GLYPH_CACHE
+static long num_cairo_fc_fonts;
+static long max_cairo_fc_fonts;
+static long num_glyph_caches;
+static long max_glyph_caches;
+static long num_glyph_cache_hits;
+static long num_glyph_cache_misses;
+#endif
+
+#define GLYPH_CACHE_NUM_ENTRIES 256
+#define GLYPH_CACHE_MASK 0x000000ff
+
+/* An entry in the fixed-size cache for the gunichar -> glyph mapping. The
+ * cache is indexed by the lower N bits of the gunichar (see
+ * GLYPH_CACHE_NUM_ENTRIES and GLYPH_CACHE_MASK above). For scripts with few
+ * code points, this should provide pretty much instant lookups.
+ *
+ * The "ch" field is zero if that cache entry is invalid.
+ */
+typedef struct
+{
+ gunichar ch;
+ PangoGlyph glyph;
+} GlyphCacheEntry;
+
struct _PangoCairoFcFont
{
PangoFcFont font;
@@ -55,6 +81,8 @@ struct _PangoCairoFcFont
cairo_font_options_t *options;
GHashTable *glyph_info;
+
+ GlyphCacheEntry *char_to_glyph_cache;
};
struct _PangoCairoFcFontClass
@@ -161,7 +189,21 @@ pango_cairo_fc_font_finalize (GObject *object)
g_hash_table_destroy (cffont->glyph_info);
+ if (cffont->char_to_glyph_cache)
+ {
+ g_free (cffont->char_to_glyph_cache);
+#ifdef PROFILE_GLYPH_CACHE
+ num_glyph_caches--;
+ g_assert (num_glyph_caches >= 0);
+#endif
+ }
+
G_OBJECT_CLASS (pango_cairo_fc_font_parent_class)->finalize (object);
+
+#ifdef PROFILE_GLYPH_CACHE
+ num_cairo_fc_fonts--;
+ g_assert (num_cairo_fc_fonts >= 0);
+#endif
}
static void
@@ -313,6 +355,52 @@ pango_cairo_fc_font_unlock_face (PangoFcFont *font)
}
static PangoGlyph
+pango_cairo_fc_font_get_glyph (PangoFcFont *font,
+ gunichar wc)
+{
+ PangoCairoFcFont *cffont = (PangoCairoFcFont *)font;
+ guint idx;
+ GlyphCacheEntry *entry;
+
+ /* We create the cache dynamically because although we'll have a lot of
+ * PangoCairoFcFont structures (one per font in the fontset, as many as needed
+ * to cover the whole Unicode space), we'll only end up using a few of them
+ * for the user's actual text.
+ */
+ if (cffont->char_to_glyph_cache == NULL)
+ {
+ cffont->char_to_glyph_cache = g_new0 (GlyphCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
+#ifdef PROFILE_GLYPH_CACHE
+ num_glyph_caches++;
+ if (num_glyph_caches > max_glyph_caches)
+ max_glyph_caches = num_glyph_caches;
+#endif
+ }
+
+ idx = wc & GLYPH_CACHE_MASK;
+ entry = cffont->char_to_glyph_cache + idx;
+
+ if (entry->ch != wc || wc == 0)
+ {
+#ifdef PROFILE_GLYPH_CACHE
+ num_glyph_cache_misses++;
+/* printf ("cache MISS: cffont %p, gunichar %x = '%c'\n", cffont, wc, (wc < 128) ? wc : 0); */
+#endif
+ entry->ch = wc;
+ entry->glyph = ((PangoFcFontClass *) pango_cairo_fc_font_parent_class)->get_glyph (font, wc);
+ }
+ else
+ {
+#ifdef PROFILE_GLYPH_CACHE
+ num_glyph_cache_hits++;
+/* printf ("cache HIT: cffont %p, gunichar %x = '%c'\n", cffont, wc, (wc < 128) ? wc : 0); */
+#endif
+ }
+
+ return entry->glyph;
+}
+
+static PangoGlyph
pango_cairo_fc_font_real_get_unknown_glyph (PangoFcFont *font,
gunichar wc)
{
@@ -335,6 +423,18 @@ pango_cairo_fc_font_shutdown (PangoFcFont *fcfont)
}
}
+#ifdef PROFILE_GLYPH_CACHE
+static void
+profile_glyph_cache_exit_cb (void)
+{
+ printf ("Maximum number of PangoCairoFcFont objects: %ld\n", max_cairo_fc_fonts);
+ printf ("Maximum number of glyph caches created: %ld (%ld KB)\n", max_glyph_caches, (max_glyph_caches * sizeof (GlyphCacheEntry) * GLYPH_CACHE_NUM_ENTRIES) / 1024);
+ printf ("Glyph cache hits: %ld\n", num_glyph_cache_hits);
+ printf ("Glyph cache misses: %ld\n", num_glyph_cache_misses);
+ printf ("Glyph cache miss rate: %f%%\n", 100.0 * (double) num_glyph_cache_misses / (num_glyph_cache_misses + num_glyph_cache_hits));
+}
+#endif
+
static void
pango_cairo_fc_font_class_init (PangoCairoFcFontClass *class)
{
@@ -349,8 +449,13 @@ pango_cairo_fc_font_class_init (PangoCairoFcFontClass *class)
fc_font_class->lock_face = pango_cairo_fc_font_lock_face;
fc_font_class->unlock_face = pango_cairo_fc_font_unlock_face;
+ fc_font_class->get_glyph = pango_cairo_fc_font_get_glyph;
fc_font_class->get_unknown_glyph = pango_cairo_fc_font_real_get_unknown_glyph;
fc_font_class->shutdown = pango_cairo_fc_font_shutdown;
+
+#ifdef PROFILE_GLYPH_CACHE
+ atexit (profile_glyph_cache_exit_cb);
+#endif
}
static void
@@ -360,6 +465,12 @@ pango_cairo_fc_font_init (PangoCairoFcFont *cffont)
NULL,
NULL,
(GDestroyNotify)g_free);
+
+#ifdef PROFILE_GLYPH_CACHE
+ num_cairo_fc_fonts++;
+ if (num_cairo_fc_fonts > max_cairo_fc_fonts)
+ max_cairo_fc_fonts = num_cairo_fc_fonts;
+#endif
}
/********************