summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pango/pangofc-font.c41
-rw-r--r--pango/pangofc-fontmap.c172
-rw-r--r--pango/pangofc-private.h26
3 files changed, 158 insertions, 81 deletions
diff --git a/pango/pangofc-font.c b/pango/pangofc-font.c
index 9c5b9ed1..46ce282c 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 1cd934a9..e6ff945e 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 bc67ffb7..0612a692 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);