diff options
author | Owen Taylor <otaylor@redhat.com> | 2005-01-21 14:33:47 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@redhat.com> | 2005-01-21 14:33:47 +0000 |
commit | 97424a3c2a4172dd3a686d0d41f7c7781b670814 (patch) | |
tree | 9be9ca7efea23ae5d11238623370bc514735d9e8 /src/cairo-cache.c | |
parent | 90689370267f3c02d6be62e3e8c85cccdad6f577 (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.c | 104 |
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) { |