summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cairo-cache-private.h5
-rw-r--r--src/cairo-cache.c39
-rw-r--r--src/cairo-ft-font.c4
-rw-r--r--src/cairo-hash-private.h6
-rw-r--r--src/cairo-hash.c55
-rw-r--r--src/cairo-scaled-font-private.h6
-rw-r--r--src/cairo-scaled-font.c396
-rw-r--r--src/cairo-types-private.h3
-rw-r--r--src/cairoint.h7
9 files changed, 232 insertions, 289 deletions
diff --git a/src/cairo-cache-private.h b/src/cairo-cache-private.h
index 8ad0c774a..25858e544 100644
--- a/src/cairo-cache-private.h
+++ b/src/cairo-cache-private.h
@@ -97,6 +97,7 @@ typedef void
cairo_private cairo_cache_t *
_cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal,
+ cairo_cache_predicate_func_t predicate,
cairo_destroy_func_t entry_destroy,
unsigned long max_size);
@@ -113,10 +114,6 @@ cairo_private void *
_cairo_cache_lookup (cairo_cache_t *cache,
cairo_cache_entry_t *key);
-cairo_private void *
-_cairo_cache_steal (cairo_cache_t *cache,
- cairo_cache_entry_t *key);
-
cairo_private cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index cab6e1e9f..7542242dc 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -42,9 +42,16 @@ static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional);
+static cairo_bool_t
+_cairo_cache_entry_is_non_zero (const void *entry)
+{
+ return ((const cairo_cache_entry_t *) entry)->size;
+}
+
static cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
cairo_cache_keys_equal_func_t keys_equal,
+ cairo_cache_predicate_func_t predicate,
cairo_destroy_func_t entry_destroy,
unsigned long max_size)
{
@@ -52,6 +59,9 @@ _cairo_cache_init (cairo_cache_t *cache,
if (unlikely (cache->hash_table == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ if (predicate == NULL)
+ predicate = _cairo_cache_entry_is_non_zero;
+ cache->predicate = predicate;
cache->entry_destroy = entry_destroy;
cache->max_size = max_size;
@@ -114,6 +124,7 @@ _cairo_cache_fini (cairo_cache_t *cache)
**/
cairo_cache_t *
_cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal,
+ cairo_cache_predicate_func_t predicate,
cairo_destroy_func_t entry_destroy,
unsigned long max_size)
{
@@ -126,7 +137,11 @@ _cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal,
return NULL;
}
- status = _cairo_cache_init (cache, keys_equal, entry_destroy, max_size);
+ status = _cairo_cache_init (cache,
+ keys_equal,
+ predicate,
+ entry_destroy,
+ max_size);
if (unlikely (status)) {
free (cache);
return NULL;
@@ -221,26 +236,6 @@ _cairo_cache_lookup (cairo_cache_t *cache,
(cairo_hash_entry_t *) key);
}
-void *
-_cairo_cache_steal (cairo_cache_t *cache,
- cairo_cache_entry_t *key)
-{
- cairo_cache_entry_t *entry;
-
- entry = _cairo_hash_table_steal (cache->hash_table,
- (cairo_hash_entry_t *) key);
- if (entry != NULL)
- cache->size -= entry->size;
-
- return entry;
-}
-
-static cairo_bool_t
-_cairo_cache_entry_is_non_zero (void *entry)
-{
- return ((cairo_cache_entry_t *)entry)->size;
-}
-
/**
* _cairo_cache_remove_random:
* @cache: a cache
@@ -256,7 +251,7 @@ _cairo_cache_remove_random (cairo_cache_t *cache)
cairo_cache_entry_t *entry;
entry = _cairo_hash_table_random_entry (cache->hash_table,
- _cairo_cache_entry_is_non_zero);
+ cache->predicate);
if (unlikely (entry == NULL))
return FALSE;
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 493a1e27d..ec6041a2a 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -532,9 +532,9 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font)
}
static cairo_bool_t
-_has_unlocked_face (void *entry)
+_has_unlocked_face (const void *entry)
{
- cairo_ft_unscaled_font_t *unscaled = entry;
+ const cairo_ft_unscaled_font_t *unscaled = entry;
return (!unscaled->from_face && unscaled->lock_count == 0 && unscaled->face);
}
diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h
index 8ab085822..32078bd21 100644
--- a/src/cairo-hash-private.h
+++ b/src/cairo-hash-private.h
@@ -51,7 +51,7 @@ typedef cairo_bool_t
(*cairo_hash_keys_equal_func_t) (const void *key_a, const void *key_b);
typedef cairo_bool_t
-(*cairo_hash_predicate_func_t) (void *entry);
+(*cairo_hash_predicate_func_t) (const void *entry);
typedef void
(*cairo_hash_callback_func_t) (void *entry,
@@ -68,10 +68,6 @@ _cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key);
cairo_private void *
-_cairo_hash_table_steal (cairo_hash_table_t *hash_table,
- cairo_hash_entry_t *key);
-
-cairo_private void *
_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
cairo_hash_predicate_func_t predicate);
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index c0c9f7d86..51303f5a7 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -346,61 +346,6 @@ _cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
}
/**
- * _cairo_hash_table_steal:
- * @hash_table: a hash table
- * @key: the key of interest
- *
- * Performs a lookup in @hash_table looking for an entry which has a
- * key that matches @key, (as determined by the keys_equal() function
- * passed to _cairo_hash_table_create) and removes that entry from the
- * hash table.
- *
- * Return value: the matching entry, of %NULL if no match was found.
- **/
-void *
-_cairo_hash_table_steal (cairo_hash_table_t *hash_table,
- cairo_hash_entry_t *key)
-{
- cairo_hash_entry_t *entry;
- unsigned long table_size, i, idx, step;
-
- table_size = hash_table->arrangement->size;
- idx = key->hash % table_size;
-
- entry = hash_table->entries[idx];
- if (ENTRY_IS_LIVE (entry)) {
- if (hash_table->keys_equal (key, entry)) {
- hash_table->entries[idx] = DEAD_ENTRY;
- hash_table->live_entries--;
- return entry;
- }
- } else if (ENTRY_IS_FREE (entry))
- return NULL;
-
- i = 1;
- step = key->hash % hash_table->arrangement->rehash;
- if (step == 0)
- step = 1;
- do {
- idx += step;
- if (idx >= table_size)
- idx -= table_size;
-
- entry = hash_table->entries[idx];
- if (ENTRY_IS_LIVE (entry)) {
- if (hash_table->keys_equal (key, entry)) {
- hash_table->entries[idx] = DEAD_ENTRY;
- hash_table->live_entries--;
- return entry;
- }
- } else if (ENTRY_IS_FREE (entry))
- return NULL;
- } while (++i < table_size);
-
- return NULL;
-}
-
-/**
* _cairo_hash_table_random_entry:
* @hash_table: a hash table
* @predicate: a predicate function.
diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index 89820c8f3..f6c97488c 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -106,8 +106,10 @@ struct _cairo_scaled_font {
/* The mutex protects modification to all subsequent fields. */
cairo_mutex_t mutex;
- int cache_frozen;
- cairo_scaled_glyph_page_t *mru_page;
+ cairo_hash_table_t *glyphs;
+ cairo_scaled_glyph_page_t *glyph_pages;
+ cairo_bool_t cache_frozen;
+ cairo_bool_t global_cache_frozen;
/*
* One surface backend may store data in each glyph.
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 58733a798..e14aa2e98 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -49,21 +49,30 @@
#define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
#endif
-#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_BASE_INDEX(I) ((I) & -CAIRO_SCALED_GLYPH_PAGE_SIZE)
-#define CAIRO_SCALED_GLYPH_PAGE_HAS_INDEX(P, I) \
- ((I) - (P)->base_index < 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;
+/* 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 reduce the frequency at which we have to probe the
+ * global cache and ameliorates the memory allocation pressure.
+ */
+
+/* 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;
+#define CAIRO_SCALED_GLYPH_PAGE_SIZE 32
struct _cairo_scaled_glyph_page {
- cairo_scaled_glyph_page_key_t key;
- unsigned long base_index;
+ cairo_cache_entry_t cache_entry;
+
+ struct _cairo_scaled_glyph_page *prev, *next;
+
+ unsigned int num_glyphs;
cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE];
};
@@ -176,13 +185,9 @@ static void
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font);
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)
+_cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph)
{
- cairo_scaled_font_t *scaled_font = scaled_glyph->scaled_font;
const cairo_surface_backend_t *surface_backend = scaled_font->surface_backend;
if (surface_backend != NULL && surface_backend->scaled_glyph_fini != NULL)
@@ -196,8 +201,6 @@ _cairo_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph)
if (scaled_glyph->meta_surface != NULL)
cairo_surface_destroy (scaled_glyph->meta_surface);
-
- scaled_glyph->scaled_font = NULL;
}
#define ZOMBIE 0
@@ -222,8 +225,10 @@ 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, /* pages */
FALSE, /* cache_frozen */
- NULL, /* mru_page */
+ FALSE, /* global_cache_frozen */
NULL, /* surface_backend */
NULL, /* surface_private */
NULL /* backend */
@@ -419,112 +424,29 @@ _cairo_scaled_font_map_destroy (void)
CLEANUP_MUTEX_LOCK:
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) to reduce frequency of small
- * allocations 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 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;
-
- key.cache_entry.hash =
- (index >> CAIRO_SCALED_GLYPH_PAGE_SHIFT) ^
- (unsigned long) scaled_font;
- key.scaled_font = scaled_font;
+ cairo_scaled_font_t *scaled_font;
+ unsigned int n;
- if (scaled_font->cache_frozen) {
- CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
- page = _cairo_cache_steal (cairo_scaled_glyph_page_cache,
- &key.cache_entry);
- CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
- } else
- page = NULL;
-
- if (page == NULL) {
- /* On miss, create glyph page and insert into cache */
- page = malloc (sizeof (cairo_scaled_glyph_page_t));
- if (unlikely (page == NULL))
- return NULL;
-
- 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;
- page->base_index = CAIRO_SCALED_GLYPH_PAGE_BASE_INDEX (index);
-
- memset (page->glyphs, 0, sizeof (page->glyphs));
+ scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
+ for (n = 0; n < page->num_glyphs; n++) {
+ _cairo_hash_table_remove (scaled_font->glyphs,
+ &page->glyphs[n].hash_entry);
+ _cairo_scaled_glyph_fini (scaled_font, &page->glyphs[n]);
}
- 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)
- _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 (page->prev != NULL)
+ page->prev->next = page->next;
+ else
+ scaled_font->glyph_pages = page->next;
- 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);
- }
+ if (page->next != NULL)
+ page->next->prev = page->prev;
- CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+ free (page);
}
/* If a scaled font wants to unlock the font map while still being
@@ -702,7 +624,8 @@ _cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font,
}
static cairo_bool_t
-_cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b)
+_cairo_scaled_font_keys_equal (const void *abstract_key_a,
+ const void *abstract_key_b)
{
const cairo_scaled_font_t *key_a = abstract_key_a;
const cairo_scaled_font_t *key_b = abstract_key_b;
@@ -720,6 +643,15 @@ _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_
cairo_font_options_equal (&key_a->options, &key_b->options);
}
+static cairo_bool_t
+_cairo_scaled_glyphs_equal (const void *abstract_a, const void *abstract_b)
+{
+ const cairo_scaled_glyph_t *a = abstract_a;
+ const cairo_scaled_glyph_t *b = abstract_b;
+
+ return a->hash_entry.hash == b->hash_entry.hash;
+}
+
/*
* Basic #cairo_scaled_font_t object management
*/
@@ -769,8 +701,15 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
return status;
}
- scaled_font->finished = FALSE;
+ scaled_font->glyphs = _cairo_hash_table_create (_cairo_scaled_glyphs_equal);
+ if (unlikely (scaled_font->glyphs == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ scaled_font->glyph_pages = NULL;
scaled_font->cache_frozen = FALSE;
+ scaled_font->global_cache_frozen = FALSE;
+
+ scaled_font->finished = FALSE;
CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
@@ -781,8 +720,6 @@ _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;
@@ -798,17 +735,20 @@ _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
CAIRO_MUTEX_LOCK (scaled_font->mutex);
+ scaled_font->cache_frozen = TRUE;
}
void
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
{
- if (scaled_font->cache_frozen) {
+ scaled_font->cache_frozen = FALSE;
+
+ if (scaled_font->global_cache_frozen) {
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);
- scaled_font->cache_frozen = FALSE;
+ scaled_font->global_cache_frozen = FALSE;
}
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
@@ -817,14 +757,14 @@ _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
{
- assert (CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex));
+ assert (! scaled_font->cache_frozen);
- if (scaled_font->mru_page != NULL) {
- _cairo_scaled_glyph_page_destroy (scaled_font->mru_page);
- scaled_font->mru_page = NULL;
+ CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
+ while (scaled_font->glyph_pages != NULL) {
+ _cairo_cache_remove (cairo_scaled_glyph_page_cache,
+ &scaled_font->glyph_pages->cache_entry);
}
-
- _cairo_scaled_glyph_page_cache_remove_scaled_font (scaled_font);
+ CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
}
cairo_status_t
@@ -861,12 +801,8 @@ _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_destroy (scaled_font->mru_page);
- scaled_font->mru_page = NULL;
- }
-
- _cairo_scaled_glyph_page_cache_remove_scaled_font (scaled_font);
+ _cairo_scaled_font_reset_cache (scaled_font);
+ _cairo_hash_table_destroy (scaled_font->glyphs);
cairo_font_face_destroy (scaled_font->font_face);
cairo_font_face_destroy (scaled_font->original_font_face);
@@ -2496,6 +2432,92 @@ _cairo_scaled_glyph_set_meta_surface (cairo_scaled_glyph_t *scaled_glyph,
scaled_glyph->meta_surface = meta_surface;
}
+static cairo_bool_t
+_cairo_scaled_glyph_page_can_remove (const void *closure)
+{
+ const cairo_scaled_glyph_page_t *page = closure;
+ const cairo_scaled_font_t *scaled_font;
+
+ scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
+ return scaled_font->cache_frozen == 0;
+}
+
+static cairo_status_t
+_cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t **scaled_glyph)
+{
+ cairo_scaled_glyph_page_t *page;
+ cairo_status_t status;
+
+ /* only the first page in the list may contain available slots */
+ page = scaled_font->glyph_pages;
+ if (page != NULL && page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) {
+ *scaled_glyph = &page->glyphs[page->num_glyphs++];
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ page = malloc (sizeof (cairo_scaled_glyph_page_t));
+ if (unlikely (page == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ page->cache_entry.hash = (unsigned long) scaled_font;
+ page->cache_entry.size = 1; /* XXX occupancy weighting? */
+ page->num_glyphs = 0;
+
+ CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
+ if (scaled_font->global_cache_frozen == FALSE) {
+ if (unlikely (cairo_scaled_glyph_page_cache == NULL)) {
+ cairo_scaled_glyph_page_cache =
+ _cairo_cache_create (NULL,
+ _cairo_scaled_glyph_page_can_remove,
+ _cairo_scaled_glyph_page_destroy,
+ MAX_GLYPH_PAGES_CACHED);
+ if (unlikely (cairo_scaled_glyph_page_cache == NULL)) {
+ CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+ free (page);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ }
+
+ _cairo_cache_freeze (cairo_scaled_glyph_page_cache);
+ scaled_font->global_cache_frozen = TRUE;
+ }
+
+ status = _cairo_cache_insert (cairo_scaled_glyph_page_cache,
+ &page->cache_entry);
+ CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+ if (unlikely (status)) {
+ free (page);
+ return status;
+ }
+
+ page->next = scaled_font->glyph_pages;
+ page->prev = NULL;
+ if (scaled_font->glyph_pages != NULL)
+ scaled_font->glyph_pages->prev = page;
+ scaled_font->glyph_pages = page;
+
+ *scaled_glyph = &page->glyphs[page->num_glyphs++];
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph)
+{
+ cairo_scaled_glyph_page_t *page;
+
+ page = scaled_font->glyph_pages;
+ assert (page != NULL && scaled_glyph == &page->glyphs[page->num_glyphs-1]);
+
+ _cairo_scaled_glyph_fini (scaled_font, scaled_glyph);
+
+ if (--page->num_glyphs == 0) {
+ _cairo_cache_remove (cairo_scaled_glyph_page_cache, &page->cache_entry);
+ assert (scaled_font->glyph_pages != page);
+ }
+}
+
/**
* _cairo_scaled_glyph_lookup:
* @scaled_font: a #cairo_scaled_font_t
@@ -2529,66 +2551,40 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_info_t info,
cairo_scaled_glyph_t **scaled_glyph_ret)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_scaled_glyph_page_t *page;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_scaled_glyph_t *scaled_glyph;
- cairo_scaled_glyph_info_t need_info;
+ cairo_scaled_glyph_info_t need_info;
if (unlikely (scaled_font->status))
return scaled_font->status;
- page = scaled_font->mru_page;
- if (page != NULL && ! CAIRO_SCALED_GLYPH_PAGE_HAS_INDEX (page, index)) {
- CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
- if (! scaled_font->cache_frozen) {
- 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);
- if (unlikely (cairo_scaled_glyph_page_cache == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- }
-
- _cairo_cache_freeze (cairo_scaled_glyph_page_cache);
- scaled_font->cache_frozen = TRUE;
- }
- status = _cairo_cache_insert (cairo_scaled_glyph_page_cache,
- &page->key.cache_entry);
- BAIL:
- CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
- if (unlikely (status))
- return _cairo_scaled_font_set_error (scaled_font, status);
-
- page = scaled_font->mru_page = NULL;
- }
-
- if (page == NULL) {
- page = _cairo_scaled_glyph_page_cache_lookup (scaled_font, index);
- if (unlikely (page == NULL)) {
- return _cairo_scaled_font_set_error (scaled_font,
- _cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
- }
-
- scaled_font->mru_page = page;
-
/*
* Check cache for glyph
*/
- info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
- 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 = _cairo_hash_table_lookup (scaled_font->glyphs,
+ (cairo_hash_entry_t *) &index);
+ if (scaled_glyph == NULL) {
+ status = _cairo_scaled_font_allocate_glyph (scaled_font, &scaled_glyph);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t));
+ _cairo_scaled_glyph_set_index (scaled_glyph, index);
/* ask backend to initialize metrics and shape fields */
- status = (*scaled_font->backend->
- scaled_glyph_init) (scaled_font, scaled_glyph, info);
+ status =
+ scaled_font->backend->scaled_glyph_init (scaled_font,
+ scaled_glyph,
+ info | CAIRO_SCALED_GLYPH_INFO_METRICS);
+ if (unlikely (status)) {
+ _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
+ goto CLEANUP;
+ }
+
+ status = _cairo_hash_table_insert (scaled_font->glyphs,
+ &scaled_glyph->hash_entry);
if (unlikely (status)) {
- _cairo_scaled_glyph_fini (scaled_glyph);
+ _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
goto CLEANUP;
}
}
@@ -2600,19 +2596,26 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
need_info = 0;
if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 &&
scaled_glyph->surface == NULL)
+ {
need_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE;
+ }
- if (((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 &&
- scaled_glyph->path == NULL))
+ if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 &&
+ scaled_glyph->path == NULL)
+ {
need_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
+ }
- if (((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
- scaled_glyph->meta_surface == NULL))
+ if ((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
+ scaled_glyph->meta_surface == NULL)
+ {
need_info |= CAIRO_SCALED_GLYPH_INFO_META_SURFACE;
+ }
if (need_info) {
- status = (*scaled_font->backend->
- scaled_glyph_init) (scaled_font, scaled_glyph, need_info);
+ status = scaled_font->backend->scaled_glyph_init (scaled_font,
+ scaled_glyph,
+ need_info);
if (unlikely (status))
goto CLEANUP;
@@ -2622,19 +2625,22 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
* glyph info. */
if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 &&
- scaled_glyph->surface == NULL) {
+ scaled_glyph->surface == NULL)
+ {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 &&
- scaled_glyph->path == NULL) {
+ scaled_glyph->path == NULL)
+ {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
- scaled_glyph->meta_surface == NULL) {
+ scaled_glyph->meta_surface == NULL)
+ {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 149d894e3..0a3ec2e4f 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -123,9 +123,12 @@ struct _cairo_font_options {
cairo_hint_metrics_t hint_metrics;
};
+typedef cairo_bool_t (*cairo_cache_predicate_func_t) (const void *entry);
+
struct _cairo_cache {
cairo_hash_table_t *hash_table;
+ cairo_cache_predicate_func_t predicate;
cairo_destroy_func_t entry_destroy;
unsigned long max_size;
diff --git a/src/cairoint.h b/src/cairoint.h
index b550f867b..b93c4a44e 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -362,8 +362,7 @@ typedef struct _cairo_unscaled_font {
} cairo_unscaled_font_t;
typedef struct _cairo_scaled_glyph {
- unsigned long index;
- cairo_scaled_font_t *scaled_font; /* font the glyph lives in */
+ cairo_hash_entry_t hash_entry;
cairo_text_extents_t metrics; /* user-space metrics */
cairo_text_extents_t fs_metrics; /* font-space metrics */
@@ -378,8 +377,8 @@ typedef struct _cairo_scaled_glyph {
void *surface_private; /* for the surface backend */
} cairo_scaled_glyph_t;
-#define _cairo_scaled_glyph_index(g) ((g)->index)
-#define _cairo_scaled_glyph_set_index(g, i) ((g)->index = (i))
+#define _cairo_scaled_glyph_index(g) ((g)->hash_entry.hash)
+#define _cairo_scaled_glyph_set_index(g, i) ((g)->hash_entry.hash = (i))
#include "cairo-scaled-font-private.h"