summaryrefslogtreecommitdiff
path: root/src/cairo-cache.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2005-01-21 14:33:47 +0000
committerOwen Taylor <otaylor@redhat.com>2005-01-21 14:33:47 +0000
commit97424a3c2a4172dd3a686d0d41f7c7781b670814 (patch)
tree9be9ca7efea23ae5d11238623370bc514735d9e8 /src/cairo-cache.c
parent90689370267f3c02d6be62e3e8c85cccdad6f577 (diff)
Change cairo_font_t to refer to a font scaled to a particular output device resolution.
src/cairoint.h src/cairo_font.c src/cairo_ft_font.c src/cairo_xlib_surface.c src/cairo_pdf_surface.c src/cairo_gstate.c src/cairo.c: Switch many internal methods from handling cairo_unscaled_font_t and cairo_font_scale_t pairs to handling cairo_font_t. src/cairo-ft-private.h src/cairo_ft_fontc: Add some internal interfaces for use by the FreeType backend. Clear the gstate's current font when the transform or target surface changes. src/cairo.h src/cairo_ft_font.c: Rename cairo_ft_font_pattern to cairo_ft_font_get_pattern(). src/cairo.h src/cairo_ft_font.c: Make cairo_ft_font_create() and cairo_ft_font_create_for_ft_face() take a font scale; make the latter take load_flags for FT_Load_Glyph() as well. Change cairo_ft_font_face() to Xft-style cairo_ft_font_lock_face, cairo_ft_font_unlock_face. Remove the name/slant/weight=>unscaled font cache, it didn't work with the new cairo_font_t setup. If it turns out to be needed, it can be added back in some other form. src/cairoint.h src/cairo_font.c: Add a 'flags' field to cairo_glyph_cache_key_t, we use it for load flags with freetype backend. Switch the caching to be from resolved fontconfig pattern => file; keep only a fixed number of FT_Face objects open at once, similar to FreeType. src/cairo_gstate.c src/cairoint.h: Add public cairo_font_glyph_extents, use it to implement _cairo_gstate_glyph_extents(). Add refcounting for glyph cache elements; there was an bug where elements got ejected from the cache and freed before they could be used. src/cairoint.h src/cairo_cache.c (_cairo_cache_random_entry()) New function to return a random entry in the cache matching a predicate; reuse the internals for the previous _random_live_entry(). src/cairoint.h src/cairo_cache.c (_cairo_cache_lookup()): Add an optional created_entry return value. src/cairo_ft_font.c src/cairo_xlib_surface.c: Adapt to _cairo_cache_lookup() change. Support max_memory == 0 to indicate an unbounded cache. src/cairoint.h src/cairo_cache.c (_cairo_cache_remove()): Add a function to manually remove entries from the cache. Update for changes, document cairo_matrix_t, cairo_glyph_t, etc. src/cairo.h src/cairo-atsui.h src/cairo-ft.h src/cairo-glitz.h src/cairo-pdf.h src/cairo-png.h src/cairo-ps.h src/cairo-quartz.h src/cairo-xcb.h src/cairo-xlib.h: Add CAIRO_BEGIN/END_DECLS for extern "C", use it on all public headers. Move header guards outermost. Fix encoding.
Diffstat (limited to 'src/cairo-cache.c')
-rw-r--r--src/cairo-cache.c104
1 files changed, 84 insertions, 20 deletions
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index b097b609..8cf432a2 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -94,9 +94,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = {
* a mostly-dead table.
*
* Generally you do not need to worry about freeing cache entries; the
- * cache will expire entries randomly as it experiences memory pressure.
- * There is currently no explicit entry-removing call, though one can be
- * added easily.
+ * cache will expire entries randomly as it experiences memory pressure.
+ * If max_memory is set, entries are not expired, and must be explicitely
+ * removed.
*
* This table is open-addressed with double hashing. Each table size is a
* prime chosen to be a little more than double the high water mark for a
@@ -282,17 +282,51 @@ _load_factor (cairo_cache_t *cache)
}
#endif
-static unsigned long
-_random_live_entry (cairo_cache_t *cache)
-{
- unsigned long idx;
- assert(cache != NULL);
- do {
- idx = rand () % cache->arrangement->size;
- } while (! LIVE_ENTRY_P(cache, idx));
- return idx;
-}
+/* Find a random in the cache matching the given predicate. We use the
+ * same algorithm as the probing algorithm to walk over the entries in
+ * the hash table in a pseudo-random order. Walking linearly would
+ * favor entries following gaps in the hash table. We could also
+ * call rand() repeatedly, which works well for almost-full tables,
+ * but degrades when the table is almost empty, or predicate
+ * returns false for most entries.
+ */
+static cairo_cache_entry_base_t **
+_random_entry (cairo_cache_t *cache,
+ int (*predicate)(void*))
+{
+ cairo_cache_entry_base_t **probe;
+ unsigned long hash;
+ unsigned long table_size, i, idx, step;
+
+ _cache_sane_state (cache);
+
+ table_size = cache->arrangement->size;
+ hash = rand ();
+ idx = hash % table_size;
+ step = 0;
+
+ for (i = 0; i < table_size; ++i)
+ {
+ assert(idx < table_size);
+ probe = cache->entries + idx;
+ if (LIVE_ENTRY_P(cache, idx)
+ && (!predicate || predicate (*probe)))
+ return probe;
+
+ if (step == 0) {
+ step = hash % cache->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ }
+
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+ }
+
+ return NULL;
+}
/* public API follows */
@@ -356,8 +390,9 @@ _cairo_cache_destroy (cairo_cache_t *cache)
cairo_status_t
_cairo_cache_lookup (cairo_cache_t *cache,
- void *key,
- void **entry_return)
+ void *key,
+ void **entry_return,
+ int *created_entry)
{
unsigned long idx;
@@ -392,6 +427,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
cache->hits++;
#endif
*entry_return = *slot;
+ if (created_entry)
+ *created_entry = 0;
return status;
}
@@ -401,19 +438,18 @@ _cairo_cache_lookup (cairo_cache_t *cache,
/* Build the new entry. */
status = cache->backend->create_entry (cache, key,
- entry_return);
+ (void **)&new_entry);
if (status != CAIRO_STATUS_SUCCESS)
return status;
- new_entry = (cairo_cache_entry_base_t *) (*entry_return);
-
/* Store the hash value in case the backend forgot. */
new_entry->hashcode = cache->backend->hash (cache, key);
/* Make some entries die if we're under memory pressure. */
while (cache->live_entries > 0 &&
+ cache->max_memory > 0 &&
((cache->max_memory - cache->used_memory) < new_entry->memory)) {
- idx = _random_live_entry (cache);
+ idx = _random_entry (cache, NULL) - cache->entries;
assert (idx < cache->arrangement->size);
_entry_destroy (cache, idx);
}
@@ -425,7 +461,6 @@ _cairo_cache_lookup (cairo_cache_t *cache,
status = _resize_cache (cache, cache->live_entries + 1);
if (status != CAIRO_STATUS_SUCCESS) {
cache->backend->destroy_entry (cache, new_entry);
- *entry_return = NULL;
return status;
}
@@ -439,9 +474,38 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_cache_sane_state (cache);
+ *entry_return = new_entry;
+ if (created_entry)
+ *created_entry = 1;
+
return status;
}
+cairo_status_t
+_cairo_cache_remove (cairo_cache_t *cache,
+ void *key)
+{
+ cairo_cache_entry_base_t **slot;
+
+ _cache_sane_state (cache);
+
+ /* See if we have an entry in the table already. */
+ slot = _find_exact_live_entry_for (cache, key);
+ if (slot != NULL)
+ _entry_destroy (cache, slot - cache->entries);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void *
+_cairo_cache_random_entry (cairo_cache_t *cache,
+ int (*predicate)(void*))
+{
+ cairo_cache_entry_base_t **slot = _random_entry (cache, predicate);
+
+ return *slot;
+}
+
unsigned long
_cairo_hash_string (const char *c)
{