[pango: 6/16] [pangofc] Share cmap cache between PangoFcFont's o



commit 03a13541fbf3f49c21d73490570ca217f559acbb
Author: Behdad Esfahbod <behdad behdad org>
Date:   Tue Mar 10 17:13:36 2009 -0400

    [pangofc] Share cmap cache between PangoFcFont's of the same face (#567160)
---
 pango/pangofc-font.c    |   41 ++++--------
 pango/pangofc-fontmap.c |  172 ++++++++++++++++++++++++++++++++--------------
 pango/pangofc-private.h |   26 +++++++
 3 files changed, 158 insertions(+), 81 deletions(-)

diff --git a/pango/pangofc-font.c b/pango/pangofc-font.c
index 9c5b9ed..46ce282 100644
--- a/pango/pangofc-font.c
+++ b/pango/pangofc-font.c
@@ -38,33 +38,15 @@ enum {
   PROP_FONTMAP
 };
 
-typedef struct _GUnicharToGlyphCacheEntry GUnicharToGlyphCacheEntry;
-
-/* 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).  For scripts with few code points,
- * this should provide pretty much instant lookups.
- *
- * The "ch" field is zero if that cache entry is invalid.
- */
-struct _GUnicharToGlyphCacheEntry
-{
-  gunichar   ch;
-  PangoGlyph glyph;
-};
-
 typedef struct _PangoFcFontPrivate PangoFcFontPrivate;
 
 struct _PangoFcFontPrivate
 {
   PangoFcDecoder *decoder;
   PangoFcFontKey *key;
-  GUnicharToGlyphCacheEntry *char_to_glyph_cache;
+  PangoFcCmapCache *cmap_cache;
 };
 
-#define GLYPH_CACHE_NUM_ENTRIES 256 /* should be power of two */
-#define GLYPH_CACHE_MASK (GLYPH_CACHE_NUM_ENTRIES - 1)
-
 static gboolean pango_fc_font_real_has_char  (PangoFcFont *font,
 					      gunichar     wc);
 static guint    pango_fc_font_real_get_glyph (PangoFcFont *font,
@@ -166,7 +148,8 @@ pango_fc_font_finalize (GObject *object)
   if (priv->decoder)
     _pango_fc_font_set_decoder (fcfont, NULL);
 
-  g_free (priv->char_to_glyph_cache);
+  if (priv->cmap_cache)
+    _pango_fc_cmap_cache_unref (priv->cmap_cache);
 
   G_OBJECT_CLASS (pango_fc_font_parent_class)->finalize (object);
 }
@@ -619,23 +602,25 @@ static guint
 pango_fc_font_real_get_glyph (PangoFcFont *font,
 			      gunichar     wc)
 {
+  PangoFcFontPrivate *priv = font->priv;
   FT_Face face;
   FT_UInt index;
 
   guint idx;
-  GUnicharToGlyphCacheEntry *entry;
+  PangoFcCmapCacheEntry *entry;
 
-  PangoFcFontPrivate *priv = font->priv;
 
-  if (G_UNLIKELY (priv->char_to_glyph_cache == NULL))
+  if (G_UNLIKELY (priv->cmap_cache == NULL))
     {
-      priv->char_to_glyph_cache = g_new0 (GUnicharToGlyphCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
-      /* Make sure all cache entries are invalid initially */
-      priv->char_to_glyph_cache[0].ch = 1; /* char 1 cannot happen in bucket 0 */
+      priv->cmap_cache = _pango_fc_font_map_get_cmap_cache ((PangoFcFontMap *) font->fontmap,
+							    font);
+
+      if (G_UNLIKELY (!priv->cmap_cache))
+	return 0;
     }
 
-  idx = wc & GLYPH_CACHE_MASK;
-  entry = priv->char_to_glyph_cache + idx;
+  idx = wc & CMAP_CACHE_MASK;
+  entry = priv->cmap_cache->entries + idx;
 
   if (entry->ch != wc)
     {
diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c
index 1cd934a..e6ff945 100644
--- a/pango/pangofc-fontmap.c
+++ b/pango/pangofc-fontmap.c
@@ -31,7 +31,7 @@
 #include "modules.h"
 #include "pango-enum-types.h"
 
-typedef struct _PangoFcCoverageKey  PangoFcCoverageKey;
+typedef struct _PangoFcFontFaceData PangoFcFontFaceData;
 typedef struct _PangoFcFace         PangoFcFace;
 typedef struct _PangoFcFamily       PangoFcFamily;
 typedef struct _PangoFcFindFuncInfo PangoFcFindFuncInfo;
@@ -64,7 +64,7 @@ struct _PangoFcFontMapPrivate
    */
   GHashTable *pattern_hash;
 
-  GHashTable *coverage_hash; /* Maps font file name/id -> PangoCoverage */
+  GHashTable *font_face_data_hash; /* Maps font file name/id -> data */
 
   /* List of all families availible */
   PangoFcFamily **families;
@@ -78,7 +78,7 @@ struct _PangoFcFontMapPrivate
   guint closed : 1;
 };
 
-struct _PangoFcCoverageKey
+struct _PangoFcFontFaceData
 {
   /* Key */
   char *filename;
@@ -86,6 +86,8 @@ struct _PangoFcCoverageKey
 
   /* Data */
   FcPattern *pattern;	/* Referenced pattern that owns filename */
+  PangoCoverage *coverage;
+  PangoFcCmapCache *cmap_cache;
 };
 
 struct _PangoFcFace
@@ -141,9 +143,9 @@ static PangoFont *pango_fc_font_map_new_font   (PangoFcFontMap    *fontmap,
 						PangoFcFontsetKey *fontset_key,
 						FcPattern         *match);
 
-static guint    pango_fc_coverage_key_hash  (PangoFcCoverageKey *key);
-static gboolean pango_fc_coverage_key_equal (PangoFcCoverageKey *key1,
-					      PangoFcCoverageKey *key2);
+static guint    pango_fc_font_face_data_hash  (PangoFcFontFaceData *key);
+static gboolean pango_fc_font_face_data_equal (PangoFcFontFaceData *key1,
+					       PangoFcFontFaceData *key2);
 
 static void               pango_fc_fontset_key_init  (PangoFcFontsetKey          *key,
 						      PangoFcFontMap             *fcfontmap,
@@ -188,23 +190,31 @@ get_gravity_class (void)
 }
 
 static guint
-pango_fc_coverage_key_hash (PangoFcCoverageKey *key)
+pango_fc_font_face_data_hash (PangoFcFontFaceData *key)
 {
   return g_str_hash (key->filename) ^ key->id;
 }
 
 static gboolean
-pango_fc_coverage_key_equal (PangoFcCoverageKey *key1,
-			     PangoFcCoverageKey *key2)
+pango_fc_font_face_data_equal (PangoFcFontFaceData *key1,
+			       PangoFcFontFaceData *key2)
 {
-  return key1->id == key2->id && (key1 == key2 || 0 == strcmp (key1->filename, key2->filename));
+  return key1->id == key2->id &&
+	 (key1 == key2 || 0 == strcmp (key1->filename, key2->filename));
 }
 
 static void
-pango_fc_coverage_key_free (PangoFcCoverageKey *key)
+pango_fc_font_face_data_free (PangoFcFontFaceData *data)
 {
-  FcPatternDestroy (key->pattern);
-  g_slice_free (PangoFcCoverageKey, key);
+  FcPatternDestroy (data->pattern);
+
+  if (data->coverage)
+    pango_coverage_unref (data->coverage);
+
+  if (data->cmap_cache)
+    _pango_fc_cmap_cache_unref (data->cmap_cache);
+
+  g_slice_free (PangoFcFontFaceData, data);
 }
 
 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
@@ -992,10 +1002,10 @@ pango_fc_font_map_init (PangoFcFontMap *fcfontmap)
 					      (GDestroyNotify) FcPatternDestroy,
 					      NULL);
 
-  priv->coverage_hash = g_hash_table_new_full ((GHashFunc)pango_fc_coverage_key_hash,
-					       (GEqualFunc)pango_fc_coverage_key_equal,
-					       (GDestroyNotify)pango_fc_coverage_key_free,
-					       (GDestroyNotify)pango_coverage_unref);
+  priv->font_face_data_hash = g_hash_table_new_full ((GHashFunc)pango_fc_font_face_data_hash,
+						     (GEqualFunc)pango_fc_font_face_data_equal,
+						     (GDestroyNotify)pango_fc_font_face_data_free,
+						     NULL);
   priv->dpi = -1;
 }
 
@@ -1017,8 +1027,8 @@ pango_fc_font_map_fini (PangoFcFontMap *fcfontmap)
   g_hash_table_destroy (priv->font_hash);
   priv->font_hash = NULL;
 
-  g_hash_table_destroy (priv->coverage_hash);
-  priv->coverage_hash = NULL;
+  g_hash_table_destroy (priv->font_face_data_hash);
+  priv->font_face_data_hash = NULL;
 
   g_hash_table_destroy (priv->pattern_hash);
   priv->pattern_hash = NULL;
@@ -1710,20 +1720,85 @@ pango_fc_font_map_cache_clear (PangoFcFontMap *fcfontmap)
   pango_fc_font_map_init (fcfontmap);
 }
 
-static void
-pango_fc_font_map_set_coverage (PangoFcFontMap            *fcfontmap,
-				PangoFcCoverageKey        *key,
-				PangoCoverage             *coverage)
+static PangoFcFontFaceData *
+pango_fc_font_map_get_font_face_data (PangoFcFontMap *fcfontmap,
+				      FcPattern      *font_pattern)
 {
   PangoFcFontMapPrivate *priv = fcfontmap->priv;
-  PangoFcCoverageKey *key_dup;
+  PangoFcFontFaceData key;
+  PangoFcFontFaceData *data;
+
+  if (FcPatternGetString (font_pattern, FC_FILE, 0, (FcChar8 **)(void*)&key.filename) != FcResultMatch)
+    return NULL;
 
-  key_dup = g_slice_new (PangoFcCoverageKey);
-  *key_dup = *key;
-  FcPatternReference (key_dup->pattern);
+  if (FcPatternGetInteger (font_pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
+    return NULL;
+
+  data = g_hash_table_lookup (priv->font_face_data_hash, &key);
+  if (G_LIKELY (data))
+    return data;
+
+  data = g_slice_new0 (PangoFcFontFaceData);
+  data->filename = key.filename;
+  data->id = key.id;
+
+  data->pattern = font_pattern;
+  FcPatternReference (data->pattern);
 
-  g_hash_table_insert (priv->coverage_hash,
-		       key_dup, pango_coverage_ref (coverage));
+  g_hash_table_insert (priv->font_face_data_hash, data, data);
+
+  return data;
+}
+
+PangoFcCmapCache *
+_pango_fc_cmap_cache_ref (PangoFcCmapCache *cmap_cache)
+{
+  g_atomic_int_inc ((int *) &cmap_cache->ref_count);
+
+  return cmap_cache;
+}
+
+void
+_pango_fc_cmap_cache_unref (PangoFcCmapCache *cmap_cache)
+{
+  g_return_if_fail (cmap_cache->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test ((int *) &cmap_cache->ref_count))
+    {
+      g_free (cmap_cache);
+    }
+}
+
+PangoFcCmapCache *
+_pango_fc_font_map_get_cmap_cache (PangoFcFontMap *fcfontmap,
+				   PangoFcFont    *fcfont)
+{
+  PangoFcFontMapPrivate *priv;
+  PangoFcFontFaceData *data;
+  PangoFcCmapCache *cmap_cache;
+
+  if (G_UNLIKELY (fcfontmap == NULL))
+	return NULL;
+
+  if (G_UNLIKELY (!fcfont->font_pattern))
+    return NULL;
+
+  priv = fcfontmap->priv;
+
+  data = pango_fc_font_map_get_font_face_data (fcfontmap, fcfont->font_pattern);
+  if (G_UNLIKELY (!data))
+    return NULL;
+
+  if (G_UNLIKELY (data->cmap_cache == NULL))
+    {
+      data->cmap_cache = g_new0 (PangoFcCmapCache, 1);
+      data->cmap_cache->ref_count = 1;
+
+      /* Make sure all cache entries are invalid initially */
+      data->cmap_cache->entries[0].ch = 1; /* char 1 cannot happen in bucket 0 */
+    }
+
+  return _pango_fc_cmap_cache_ref (data->cmap_cache);
 }
 
 PangoCoverage *
@@ -1731,39 +1806,30 @@ _pango_fc_font_map_get_coverage (PangoFcFontMap *fcfontmap,
 				 PangoFcFont    *fcfont)
 {
   PangoFcFontMapPrivate *priv = fcfontmap->priv;
-  PangoFcCoverageKey key;
+  PangoFcFontFaceData *data;
   PangoCoverage *coverage;
   FcCharSet *charset;
 
-  key.pattern = fcfont->font_pattern;
-
-  /*
-   * Assume that coverage information is identified by
-   * a filename/index pair; there shouldn't be any reason
-   * this isn't true, but it's not specified anywhere
-   */
-  if (FcPatternGetString (fcfont->font_pattern, FC_FILE, 0, (FcChar8 **)(void*)&key.filename) != FcResultMatch)
+  if (G_UNLIKELY (!fcfont->font_pattern))
     return NULL;
 
-  if (FcPatternGetInteger (fcfont->font_pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
+  data = pango_fc_font_map_get_font_face_data (fcfontmap, fcfont->font_pattern);
+  if (G_UNLIKELY (!data))
     return NULL;
 
-  coverage = g_hash_table_lookup (priv->coverage_hash, &key);
-  if (G_LIKELY (coverage))
-    return pango_coverage_ref (coverage);
-
-  /*
-   * Pull the coverage out of the pattern, this
-   * doesn't require loading the font
-   */
-  if (FcPatternGetCharSet (fcfont->font_pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
-    return NULL;
-
-  coverage = _pango_fc_font_map_fc_to_coverage (charset);
+  if (G_UNLIKELY (data->coverage == NULL))
+    {
+      /*
+       * Pull the coverage out of the pattern, this
+       * doesn't require loading the font
+       */
+      if (FcPatternGetCharSet (fcfont->font_pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
+	return NULL;
 
-  pango_fc_font_map_set_coverage (fcfontmap, &key, coverage);
+      data->coverage = _pango_fc_font_map_fc_to_coverage (charset);
+    }
 
-  return coverage;
+  return pango_coverage_ref (data->coverage);
 }
 
 /**
diff --git a/pango/pangofc-private.h b/pango/pangofc-private.h
index bc67ffb..0612a69 100644
--- a/pango/pangofc-private.h
+++ b/pango/pangofc-private.h
@@ -27,6 +27,7 @@
 
 G_BEGIN_DECLS
 
+
 typedef struct _PangoFcMetricsInfo  PangoFcMetricsInfo;
 
 struct _PangoFcMetricsInfo
@@ -35,6 +36,26 @@ struct _PangoFcMetricsInfo
   PangoFontMetrics *metrics;
 };
 
+
+typedef struct _PangoFcCmapCacheEntry  PangoFcCmapCacheEntry;
+typedef struct _PangoFcCmapCache       PangoFcCmapCache;
+
+#define CMAP_CACHE_NUM_ENTRIES 256 /* should be power of two */
+#define CMAP_CACHE_MASK (CMAP_CACHE_NUM_ENTRIES - 1)
+
+struct _PangoFcCmapCacheEntry
+{
+  gunichar   ch;
+  PangoGlyph glyph;
+};
+
+struct _PangoFcCmapCache
+{
+  guint ref_count;
+  PangoFcCmapCacheEntry entries[CMAP_CACHE_NUM_ENTRIES];
+};
+
+
 #define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6))
 #define PANGO_PIXELS_26_6(d)				\
   (((d) >= 0) ?						\
@@ -46,10 +67,15 @@ void _pango_fc_font_shutdown (PangoFcFont *fcfont);
 
 void           _pango_fc_font_map_remove          (PangoFcFontMap *fcfontmap,
 						   PangoFcFont    *fcfont);
+
 PangoCoverage *_pango_fc_font_map_get_coverage    (PangoFcFontMap *fcfontmap,
 						   PangoFcFont    *fcfont);
 PangoCoverage  *_pango_fc_font_map_fc_to_coverage (FcCharSet      *charset);
 
+PangoFcCmapCache *_pango_fc_font_map_get_cmap_cache (PangoFcFontMap *fcfontmap,
+						     PangoFcFont    *fcfont);
+void              _pango_fc_cmap_cache_unref (PangoFcCmapCache *cmap_cache);
+
 PangoFcDecoder *_pango_fc_font_get_decoder       (PangoFcFont    *font);
 void            _pango_fc_font_set_decoder       (PangoFcFont    *font,
 						  PangoFcDecoder *decoder);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]