[PATCH] global glyph cache

Chris Wilson chris at chris-wilson.co.uk
Fri Nov 21 07:04:47 PST 2008


---
 boilerplate/cairo-boilerplate.c |    5 +-
 src/cairo-cache-private.h       |    4 +
 src/cairo-cache.c               |   22 ++--
 src/cairo-mutex-list-private.h  |    1 +
 src/cairo-scaled-font-private.h |    5 +-
 src/cairo-scaled-font.c         |  314 ++++++++++++++++++++++++++++-----------
 src/cairoint.h                  |    9 +-
 7 files changed, 253 insertions(+), 107 deletions(-)

diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index f6f68f9..65b8aa9 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -866,10 +866,7 @@ void
 cairo_boilerplate_scaled_font_set_max_glyphs_cached (cairo_scaled_font_t *scaled_font,
 						     int max_glyphs)
 {
-    if (cairo_scaled_font_status (scaled_font))
-	return;
-
-    scaled_font->glyphs->max_size = max_glyphs;
+    /* XXX CAIRO_DEBUG */
 }
 
 #if HAS_DAEMON
diff --git a/src/cairo-cache-private.h b/src/cairo-cache-private.h
index 5ac8cc8..0936c3f 100644
--- a/src/cairo-cache-private.h
+++ b/src/cairo-cache-private.h
@@ -118,6 +118,10 @@ _cairo_cache_insert (cairo_cache_t	 *cache,
 		     cairo_cache_entry_t *entry);
 
 cairo_private void
+_cairo_cache_remove (cairo_cache_t	 *cache,
+		     cairo_cache_entry_t *entry);
+
+cairo_private void
 _cairo_cache_foreach (cairo_cache_t		 *cache,
 		      cairo_cache_callback_func_t cache_callback,
 		      void			 *closure);
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index 07c8b71..c5412e4 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -39,10 +39,6 @@
 #include "cairoint.h"
 
 static void
-_cairo_cache_remove (cairo_cache_t	 *cache,
-		     cairo_cache_entry_t *entry);
-
-static void
 _cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
 				    unsigned long  additional);
 
@@ -225,6 +221,12 @@ _cairo_cache_lookup (cairo_cache_t	  *cache,
 				     (cairo_hash_entry_t *) key);
 }
 
+static cairo_bool_t
+_cairo_cache_entry_is_non_zero (const void *entry)
+{
+    return ((cairo_cache_entry_t *)entry)->size;
+}
+
 /**
  * _cairo_cache_remove_random:
  * @cache: a cache
@@ -239,7 +241,8 @@ _cairo_cache_remove_random (cairo_cache_t *cache)
 {
     cairo_cache_entry_t *entry;
 
-    entry = _cairo_hash_table_random_entry (cache->hash_table, NULL);
+    entry = _cairo_hash_table_random_entry (cache->hash_table,
+					    _cairo_cache_entry_is_non_zero);
     if (unlikely (entry == NULL))
 	return FALSE;
 
@@ -307,13 +310,8 @@ _cairo_cache_insert (cairo_cache_t	 *cache,
  * @entry: an entry that exists in the cache
  *
  * Remove an existing entry from the cache.
- *
- * (Note: If any caller wanted access to a non-static version of this
- * function, an improved version would require only a key rather than
- * an entry. Fixing that would require fixing _cairo_hash_table_remove
- * to return (a copy of?) the entry being removed.)
  **/
-static void
+void
 _cairo_cache_remove (cairo_cache_t	 *cache,
 		     cairo_cache_entry_t *entry)
 {
@@ -336,7 +334,7 @@ _cairo_cache_remove (cairo_cache_t	 *cache,
  * non-specified order.
  **/
 void
-_cairo_cache_foreach (cairo_cache_t	 	      *cache,
+_cairo_cache_foreach (cairo_cache_t		      *cache,
 		      cairo_cache_callback_func_t      cache_callback,
 		      void			      *closure)
 {
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index f5f654d..1f66bf8 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -42,6 +42,7 @@ CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock)
 CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex)
+CAIRO_MUTEX_DECLARE (_cairo_scaled_glyph_page_cache_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex)
 
 #if CAIRO_HAS_FT_FONT
diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index 86a50bb..412f66c 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -44,6 +44,8 @@
 #include "cairo-mutex-type-private.h"
 #include "cairo-reference-count-private.h"
 
+typedef struct _cairo_scaled_glyph_page cairo_scaled_glyph_page_t;
+
 struct _cairo_scaled_font {
     /* For most cairo objects, the rule for multiple threads is that
      * the user is responsible for any locking if the same object is
@@ -75,7 +77,6 @@ struct _cairo_scaled_font {
      *    scaled_font->mutex in the generic scaled_font code.
      */
 
-    /* must be first to be stored in a hash table */
     cairo_hash_entry_t hash_entry;
 
     /* useful bits for _cairo_scaled_font_nil */
@@ -103,7 +104,7 @@ struct _cairo_scaled_font {
     /* The mutex protects modification to all subsequent fields. */
     cairo_mutex_t mutex;
 
-    cairo_cache_t *glyphs;	  /* glyph index -> cairo_scaled_glyph_t */
+    cairo_scaled_glyph_page_t *mru_page;
 
     /*
      * One surface backend may store data in each glyph.
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index ca86f51..031dedb 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -35,11 +35,28 @@
  *      Graydon Hoare <graydon at redhat.com>
  *      Owen Taylor <otaylor at redhat.com>
  *      Behdad Esfahbod <behdad at behdad.org>
+ *      Chris Wilson <chris at chris-wilson.co.uk>
  */
 
 #include "cairoint.h"
 #include "cairo-scaled-font-private.h"
 
+#define CAIRO_SCALED_GLYPH_PAGE_SHIFT 7
+#define CAIRO_SCALED_GLYPH_PAGE_SIZE (1 << CAIRO_SCALED_GLYPH_PAGE_SHIFT)
+#define CAIRO_SCALED_GLYPH_PAGE_INDEX(I) \
+    ((I) & (CAIRO_SCALED_GLYPH_PAGE_SIZE - 1))
+#define CAIRO_SCALED_GLYPH_PAGE_HAS_INDEX(P, I) \
+    ((I) - (P)->key.cache_entry.hash < CAIRO_SCALED_GLYPH_PAGE_SIZE)
+typedef struct _cairo_scaled_glyph_page_key {
+    cairo_cache_entry_t cache_entry;
+    cairo_scaled_font_t *scaled_font;
+} cairo_scaled_glyph_page_key_t;
+
+struct _cairo_scaled_glyph_page {
+    cairo_scaled_glyph_page_key_t key;
+    cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE];
+};
+
 /*
  *  Notes:
  *
@@ -131,16 +148,16 @@
  *  Now compare the scaled-glyph space to device-space and surface-space
  *  and convince yourself that:
  *
- *  	(x_bearing,y_bearing) = (-x,-y) = - device_offset
+ *	(x_bearing,y_bearing) = (-x,-y) = - device_offset
  *
  *  That's right.  If you are not convinced yet, contrast the definition
  *  of the two:
  *
- *  	"(x_bearing,y_bearing) is the coordinates of top-left of the
- *  	 glyph relative to the glyph origin."
+ *	"(x_bearing,y_bearing) is the coordinates of top-left of the
+ *	 glyph relative to the glyph origin."
  *
- *  	"In other words: device_offset is the coordinates of the
- *  	 device-space origin relative to the top-left of the surface."
+ *	"In other words: device_offset is the coordinates of the
+ *	 device-space origin relative to the top-left of the surface."
  *
  *  and note that glyph origin = device-space origin.
  */
@@ -148,15 +165,9 @@
 static void
 _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font);
 
-static cairo_bool_t
-_cairo_scaled_glyph_keys_equal (const void *abstract_key_a, const void *abstract_key_b)
-{
-    const cairo_scaled_glyph_t *key_a = abstract_key_a;
-    const cairo_scaled_glyph_t *key_b = abstract_key_b;
-
-    return (_cairo_scaled_glyph_index (key_a) ==
-	    _cairo_scaled_glyph_index (key_b));
-}
+static void
+_cairo_scaled_glyph_page_cache_remove_scaled_font (cairo_scaled_font_t
+						   *scaled_font);
 
 static void
 _cairo_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph)
@@ -166,20 +177,17 @@ _cairo_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph)
 
     if (surface_backend != NULL && surface_backend->scaled_glyph_fini != NULL)
 	surface_backend->scaled_glyph_fini (scaled_glyph, scaled_font);
+
     if (scaled_glyph->surface != NULL)
 	cairo_surface_destroy (&scaled_glyph->surface->base);
+
     if (scaled_glyph->path != NULL)
 	_cairo_path_fixed_destroy (scaled_glyph->path);
+
     if (scaled_glyph->meta_surface != NULL)
 	cairo_surface_destroy (scaled_glyph->meta_surface);
-}
 
-static void
-_cairo_scaled_glyph_destroy (void *abstract_glyph)
-{
-    cairo_scaled_glyph_t *scaled_glyph = abstract_glyph;
-    _cairo_scaled_glyph_fini (scaled_glyph);
-    free (scaled_glyph);
+    scaled_glyph->scaled_font = NULL;
 }
 
 #define ZOMBIE 0
@@ -203,7 +211,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
     { 0., 0., 0., 0., 0. },	/* extents */
     { 0., 0., 0., 0., 0. },	/* fs_extents */
     CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
-    NULL,			/* glyphs */
+    NULL,			/* mru_page */
     NULL,			/* surface_backend */
     NULL,			/* surface_private */
     CAIRO_SCALED_FONT_BACKEND_DEFAULT,
@@ -309,7 +317,7 @@ typedef struct _cairo_scaled_font_map {
     int num_holdovers;
 } cairo_scaled_font_map_t;
 
-static cairo_scaled_font_map_t *cairo_scaled_font_map = NULL;
+static cairo_scaled_font_map_t *cairo_scaled_font_map;
 
 static int
 _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b);
@@ -399,6 +407,150 @@ _cairo_scaled_font_map_destroy (void)
     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 }
 
+/* Global Glyph Cache
+ *
+ * We maintain a global pool of glyphs split between all open fonts. This
+ * allows a heavily used individual font to cache more glyphs than we could
+ * manage if we used per-font glyph caches, but at the same time maintains
+ * fairness across all fonts and provides a cap on the maximum number of
+ * global glyphs.
+ *
+ * The glyphs are allocated in pages, which are cached in the global pool.
+ * Using pages means we can exploit spatial locality within the font (nearby
+ * indices are typically used in clusters) and allow the scaled font to
+ * reserve a single MRU page of glyphs.
+ */
+
+/* XXX: This number is arbitrary---we've never done any measurement of this. */
+#define MAX_GLYPH_PAGES_CACHED 512
+
+static cairo_cache_t *cairo_scaled_glyph_page_cache;
+
+static cairo_bool_t
+_cairo_scaled_glyph_pages_equal (const void *key_a, const void *key_b)
+{
+    const cairo_scaled_glyph_page_key_t *a = key_a;
+    const cairo_scaled_glyph_page_key_t *b = key_b;
+
+    return
+	a->cache_entry.hash == b->cache_entry.hash &&
+	a->scaled_font == b->scaled_font;
+}
+
+static void
+_cairo_scaled_glyph_page_destroy (void *closure)
+{
+    cairo_scaled_glyph_page_t *page = closure;
+    int n;
+
+    for (n = 0; n < CAIRO_SCALED_GLYPH_PAGE_SIZE; n++) {
+	if (page->glyphs[n].scaled_font != NULL)
+	    _cairo_scaled_glyph_fini (&page->glyphs[n]);
+    }
+
+    free (page);
+}
+
+static void
+_cairo_scaled_glyph_page_cache_freeze (void)
+{
+    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
+
+    if (cairo_scaled_glyph_page_cache == NULL) {
+	cairo_scaled_glyph_page_cache =
+	    _cairo_cache_create (_cairo_scaled_glyph_pages_equal,
+				 _cairo_scaled_glyph_page_destroy,
+				 MAX_GLYPH_PAGES_CACHED);
+    }
+
+    _cairo_cache_freeze (cairo_scaled_glyph_page_cache);
+
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+}
+
+static cairo_scaled_glyph_page_t *
+_cairo_scaled_glyph_page_cache_lookup (cairo_scaled_font_t *scaled_font,
+				       unsigned long index)
+{
+    cairo_scaled_glyph_page_key_t key;
+    cairo_scaled_glyph_page_t *page;
+    cairo_status_t status;
+
+    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
+
+    assert (cairo_scaled_glyph_page_cache != NULL);
+    assert (cairo_scaled_glyph_page_cache->freeze_count > 0);
+
+    key.cache_entry.hash =
+	(index >> CAIRO_SCALED_GLYPH_PAGE_SHIFT) ^
+	(unsigned long) scaled_font;
+    key.scaled_font = scaled_font;
+
+    page = _cairo_cache_lookup (cairo_scaled_glyph_page_cache,
+				&key.cache_entry);
+    if (page == NULL) {
+	/*
+	 * On miss, create glyph page and insert into cache
+	 */
+	page = malloc (sizeof (cairo_scaled_glyph_page_t));
+	if (unlikely (page == NULL))
+	    goto UNLOCK;
+
+	page->key.cache_entry.hash = key.cache_entry.hash;
+	/* We currently don't differentiate on glyph size at all */
+	page->key.cache_entry.size = 1;
+	page->key.scaled_font = scaled_font;
+
+	status = _cairo_cache_insert (cairo_scaled_glyph_page_cache,
+				      &page->key.cache_entry);
+	if (unlikely (status)) {
+	    free (page);
+	    page = NULL;
+	    goto UNLOCK;
+	}
+
+	memset (page->glyphs, 0, sizeof (page->glyphs));
+    }
+
+  UNLOCK:
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+
+    return page;
+}
+
+static void
+_cairo_scaled_glyph_page_cache_remove_scaled_font_cb (void *entry,
+						      void *closure)
+{
+    cairo_scaled_glyph_page_key_t *key = entry;
+
+    if (key->scaled_font == closure && key->cache_entry.size)
+	_cairo_cache_remove (cairo_scaled_glyph_page_cache, entry);
+}
+
+static void
+_cairo_scaled_glyph_page_cache_remove_scaled_font (cairo_scaled_font_t *scaled_font)
+{
+    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
+
+    if (cairo_scaled_glyph_page_cache != NULL) {
+	_cairo_cache_foreach (cairo_scaled_glyph_page_cache,
+			      _cairo_scaled_glyph_page_cache_remove_scaled_font_cb,
+			      scaled_font);
+    }
+
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+}
+
+static void
+_cairo_scaled_glyph_page_cache_thaw (void)
+{
+    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
+
+    _cairo_cache_thaw (cairo_scaled_glyph_page_cache);
+
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+}
 
 /* If a scaled font wants to unlock the font map while still being
  * created (needed for user-fonts), we need to take extra care not
@@ -577,13 +729,6 @@ _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_
 	    cairo_font_options_equal (&key_a->options, &key_b->options));
 }
 
-/* XXX: This 256 number is arbitrary---we've never done any measurement
- * of this. In fact, having a per-font glyph caches each managed
- * separately is probably not what we want anyway. Would probably be
- * much better to have a single cache for glyphs with random
- * replacement across all glyphs of all fonts. */
-#define MAX_GLYPHS_CACHED_PER_FONT 256
-
 /*
  * Basic #cairo_scaled_font_t object management
  */
@@ -635,12 +780,6 @@ _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
 
     scaled_font->finished = FALSE;
 
-    scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
-					       _cairo_scaled_glyph_destroy,
-					       MAX_GLYPHS_CACHED_PER_FONT);
-    if (unlikely (scaled_font->glyphs == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
     CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
 
     _cairo_user_data_array_init (&scaled_font->user_data);
@@ -649,6 +788,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
 
     CAIRO_MUTEX_INIT (scaled_font->mutex);
 
+    scaled_font->mru_page = NULL;
+
     scaled_font->surface_backend = NULL;
     scaled_font->surface_private = NULL;
 
@@ -664,13 +805,13 @@ _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
     assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
 
     CAIRO_MUTEX_LOCK (scaled_font->mutex);
-    _cairo_cache_freeze (scaled_font->glyphs);
+    _cairo_scaled_glyph_page_cache_freeze ();
 }
 
 void
 _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
 {
-    _cairo_cache_thaw (scaled_font->glyphs);
+    _cairo_scaled_glyph_page_cache_thaw ();
     CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 }
 
@@ -679,10 +820,13 @@ _cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
 {
     assert (CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex));
 
-    _cairo_cache_destroy (scaled_font->glyphs);
-    scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
-					       _cairo_scaled_glyph_destroy,
-					       MAX_GLYPHS_CACHED_PER_FONT);
+    if (scaled_font->mru_page != NULL) {
+	cairo_scaled_glyph_page_cache->size++;
+	scaled_font->mru_page->key.cache_entry.size = 1;
+	scaled_font->mru_page = NULL;
+    }
+
+    _cairo_scaled_glyph_page_cache_remove_scaled_font (scaled_font);
 }
 
 cairo_status_t
@@ -719,12 +863,17 @@ _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
 {
     scaled_font->finished = TRUE;
 
+    if (scaled_font->mru_page != NULL) {
+	cairo_scaled_glyph_page_cache->size++;
+	scaled_font->mru_page->key.cache_entry.size = 1;
+	scaled_font->mru_page = NULL;
+    }
+
+    _cairo_scaled_glyph_page_cache_remove_scaled_font (scaled_font);
+
     if (scaled_font->font_face != NULL)
 	cairo_font_face_destroy (scaled_font->font_face);
 
-    if (scaled_font->glyphs != NULL)
-	_cairo_cache_destroy (scaled_font->glyphs);
-
     CAIRO_MUTEX_FINI (scaled_font->mutex);
 
     if (scaled_font->surface_backend != NULL &&
@@ -968,6 +1117,13 @@ _cairo_scaled_font_reset_static_data (void)
 	}
     }
     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
+
+    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
+    if (cairo_scaled_glyph_page_cache != NULL) {
+	_cairo_cache_destroy (cairo_scaled_glyph_page_cache);
+	cairo_scaled_glyph_page_cache = NULL;
+    }
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
 }
 
 /**
@@ -1025,9 +1181,9 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
     assert (font_map != NULL);
 
     if (_cairo_reference_count_dec_and_test (&scaled_font->ref_count)) {
-
-
-	if (!scaled_font->placeholder && scaled_font->hash_entry.hash != ZOMBIE) {
+	if (! scaled_font->placeholder &&
+	    scaled_font->hash_entry.hash != ZOMBIE)
+	{
 	    /* Rather than immediately destroying this object, we put it into
 	     * the font_map->holdovers array in case it will get used again
 	     * soon (and is why we must hold the lock over the atomic op on
@@ -1053,7 +1209,6 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
 	    font_map->num_holdovers++;
 	} else
 	    lru = scaled_font;
-
     }
 
     _cairo_scaled_font_map_unlock ();
@@ -1145,13 +1300,6 @@ cairo_scaled_font_set_user_data (cairo_scaled_font_t	     *scaled_font,
 					    key, user_data, destroy);
 }
 
-static cairo_bool_t
-_cairo_scaled_font_is_frozen (cairo_scaled_font_t *scaled_font)
-{
-    return CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex) &&
-	   scaled_font->glyphs->freeze_count > 0;
-}
-
 /* Public font API follows. */
 
 /**
@@ -2340,58 +2488,52 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
 			    cairo_scaled_glyph_t **scaled_glyph_ret)
 {
     cairo_status_t		status = CAIRO_STATUS_SUCCESS;
-    cairo_cache_entry_t		key;
+    cairo_scaled_glyph_page_t	*page;
     cairo_scaled_glyph_t	*scaled_glyph;
     cairo_scaled_glyph_info_t	need_info;
 
     if (scaled_font->status)
 	return scaled_font->status;
 
-    assert (_cairo_scaled_font_is_frozen (scaled_font));
+    page = scaled_font->mru_page;
+    if (page != NULL && ! CAIRO_SCALED_GLYPH_PAGE_HAS_INDEX (page, index)) {
+	cairo_scaled_glyph_page_cache->size++;
+	page->key.cache_entry.size = 1;
+	scaled_font->mru_page = NULL;
+	page = NULL;
+    }
+
+    if (page == NULL) {
+	page = _cairo_scaled_glyph_page_cache_lookup (scaled_font, index);
+	if (page == NULL)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    scaled_font->mru_page = page;
+    page->key.cache_entry.size = 0;
+    cairo_scaled_glyph_page_cache->size--;
 
-    key.hash = index;
     /*
      * Check cache for glyph
      */
     info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
-    scaled_glyph = _cairo_cache_lookup (scaled_font->glyphs, &key);
-    if (scaled_glyph == NULL) {
-	/*
-	 * On miss, create glyph and insert into cache
-	 */
-	scaled_glyph = malloc (sizeof (cairo_scaled_glyph_t));
-	if (unlikely (scaled_glyph == NULL)) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto CLEANUP;
-	}
-
-	_cairo_scaled_glyph_set_index(scaled_glyph, index);
-	scaled_glyph->cache_entry.size = 1;	/* We currently don't differentiate on glyph size at all */
+    scaled_glyph = &page->glyphs[CAIRO_SCALED_GLYPH_PAGE_INDEX (index)];
+    if (scaled_glyph->scaled_font == NULL) {
+	scaled_glyph->index = index;
 	scaled_glyph->scaled_font = scaled_font;
-	scaled_glyph->surface = NULL;
-	scaled_glyph->path = NULL;
-	scaled_glyph->meta_surface = NULL;
-	scaled_glyph->surface_private = NULL;
 
 	/* ask backend to initialize metrics and shape fields */
 	status = (*scaled_font->backend->
 		  scaled_glyph_init) (scaled_font, scaled_glyph, info);
 	if (unlikely (status)) {
-	    _cairo_scaled_glyph_destroy (scaled_glyph);
-	    goto CLEANUP;
-	}
-
-	/* on success, the cache takes ownership of the scaled_glyph */
-	status = _cairo_cache_insert (scaled_font->glyphs,
-				      &scaled_glyph->cache_entry);
-	if (unlikely (status)) {
-	    _cairo_scaled_glyph_destroy (scaled_glyph);
+	    _cairo_scaled_glyph_fini (scaled_glyph);
 	    goto CLEANUP;
 	}
     }
+
     /*
      * Check and see if the glyph, as provided,
-     * already has the requested data and ammend it if not
+     * already has the requested data and amend it if not
      */
     need_info = 0;
     if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 &&
diff --git a/src/cairoint.h b/src/cairoint.h
index 24ce6b4..aff3343 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -343,21 +343,24 @@ typedef struct _cairo_unscaled_font {
 } cairo_unscaled_font_t;
 
 typedef struct _cairo_scaled_glyph {
-    cairo_cache_entry_t	    cache_entry;	/* hash is glyph index */
+    unsigned long index;
     cairo_scaled_font_t	    *scaled_font;	/* font the glyph lives in */
+
     cairo_text_extents_t    metrics;		/* user-space metrics */
     cairo_text_extents_t    fs_metrics;		/* font-space metrics */
     cairo_box_t		    bbox;		/* device-space bounds */
     int16_t                 x_advance;		/* device-space rounded X advance */
     int16_t                 y_advance;		/* device-space rounded Y advance */
+
     cairo_image_surface_t   *surface;		/* device-space image */
     cairo_path_fixed_t	    *path;		/* device-space outline */
     cairo_surface_t         *meta_surface;	/* device-space meta-surface */
+
     void		    *surface_private;	/* for the surface backend */
 } cairo_scaled_glyph_t;
 
-#define _cairo_scaled_glyph_index(g) ((g)->cache_entry.hash)
-#define _cairo_scaled_glyph_set_index(g,i)  ((g)->cache_entry.hash = (i))
+#define _cairo_scaled_glyph_index(g) ((g)->index)
+#define _cairo_scaled_glyph_set_index(g, i)  ((g)->index = (i))
 
 #include "cairo-scaled-font-private.h"
 
-- 
1.6.0.4


--=-eNDd1Q3hiD2gO39lYJIr--



More information about the cairo mailing list