[cairo-commit] cairo/src Makefile.am, 1.64, 1.65 cairo-cache-private.h, NONE, 1.1 cairo-cache.c, 1.14, 1.15 cairo-debug.c, 1.1, 1.2 cairo-font.c, 1.76, 1.77 cairo-ft-font.c, 1.110, 1.111 cairo-gstate.c, 1.168, 1.169 cairo-path.c, 1.27, 1.28 cairo-scaled-font.c, NONE, 1.1 cairo-xlib-surface.c, 1.118, 1.119 cairoint.h, 1.207, 1.208

Keith Packard commit at pdx.freedesktop.org
Wed Aug 31 15:08:05 PDT 2005


Committed by: keithp

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv6824/src

Modified Files:
	Makefile.am cairo-cache.c cairo-debug.c cairo-font.c 
	cairo-ft-font.c cairo-gstate.c cairo-path.c 
	cairo-xlib-surface.c cairoint.h 
Added Files:
	cairo-cache-private.h cairo-scaled-font.c 
Log Message:
2005-08-31  Keith Packard  <keithp at keithp.com>

	Reviewed by: otaylor, cworth
	* src/Makefile.am:
	Split out scaled font code to cairo-scaled-font.c
	
	* src/cairo-cache-private.h:
	* src/cairo-cache.c: (_cairo_cache_init), (_cairo_cache_fini),
	(_cairo_cache_create), (_cairo_cache_destroy),
	(_cairo_cache_preserve), (_cairo_cache_release),
	(_cairo_cache_lookup), (_cairo_cache_remove_random),
	(_cairo_cache_insert), (_cairo_cache_remove),
	(_cairo_cache_foreach):
	Replace cairo cache implementation (this code from cworth)

	* src/cairo-debug.c: (cairo_debug_reset_static_data):
	* src/cairo-font.c: (_cairo_font_reset_static_data):
	No more global glyph cache to clean up
	
	* src/cairo-ft-font.c: (_get_bitmap_surface),
	(_render_glyph_outline), (_render_glyph_bitmap),
	(_transform_glyph_bitmap), (_get_pattern_ft_options),
	(_cairo_ft_scaled_font_create), (_cairo_ft_scaled_font_create_toy),
	(_decompose_glyph_outline), (_cairo_ft_scaled_glyph_init),
	(_cairo_ft_ucs4_to_index), (_cairo_ft_show_glyphs),
	(_cairo_ft_font_face_scaled_font_create),
	(_cairo_ft_font_face_create),
	(cairo_ft_font_face_create_for_pattern),
	(cairo_ft_font_face_create_for_ft_face):
	Store glyphs in new per-scaled font caches which
	hold user-space metrics and device space bounding boxes

	* src/cairo-gstate.c: (_cairo_gstate_text_to_glyphs),
	(_cairo_gstate_show_glyphs_draw_func), (_cairo_gstate_show_glyphs):
	Refactor glyph drawing APIs so that the surface API is
	invoked directly from the gstate code.

	* src/cairo-path.c: (_cairo_path_fixed_create),
	(_cairo_path_fixed_destroy):
	Add path creation/destruction routines (to hold glyph paths)
	
	* src/cairo-scaled-font.c: (_cairo_scaled_glyph_keys_equal),
	(_cairo_scaled_glyph_fini), (_cairo_scaled_glyph_destroy),
	(_cairo_scaled_font_set_error), (cairo_scaled_font_status),
	(_cairo_scaled_font_map_lock), (_cairo_scaled_font_map_unlock),
	(_cairo_scaled_font_map_destroy), (_hash_bytes_fnv),
	(_cairo_scaled_font_init_key), (_cairo_scaled_font_keys_equal),
	(_cairo_scaled_font_init), (_cairo_scaled_font_set_metrics),
	(_cairo_scaled_font_fini), (cairo_scaled_font_create),
	(cairo_scaled_font_reference), (cairo_scaled_font_destroy),
	(cairo_scaled_font_extents), (cairo_scaled_font_glyph_extents),
	(_cairo_scaled_font_text_to_glyphs),
	(_cairo_scaled_font_glyph_device_extents),
	(_cairo_scaled_font_show_glyphs), (_scaled_glyph_path_move_to),
	(_scaled_glyph_path_line_to), (_scaled_glyph_path_curve_to),
	(_scaled_glyph_path_close_path), (_cairo_scaled_font_glyph_path),
	(_cairo_scaled_glyph_set_metrics),
	(_cairo_scaled_glyph_set_surface), (_cairo_scaled_glyph_set_path),
	(_cairo_scaled_glyph_lookup):
	New implementation of scaled fonts which uses per-scaled_font
	caches for glyphs and keeps user-space metrics, device-space bboxes
	along with glyph images and/or glyph paths.
	
	* src/cairo-xlib-surface.c:
	(_cairo_xlib_surface_create_similar_with_format),
	(_cairo_xlib_surface_create_similar), (_cairo_xlib_surface_finish),
	(_cairo_xlib_surface_clone_similar),
	(_cairo_xlib_surface_font_init),
	(_cairo_xlib_surface_scaled_font_fini),
	(_cairo_xlib_surface_scaled_glyph_fini),
	(_cairo_xlib_surface_add_glyph),
	(_cairo_xlib_surface_show_glyphs8),
	(_cairo_xlib_surface_show_glyphs16),
	(_cairo_xlib_surface_show_glyphs32),
	(_cairo_xlib_surface_show_glyphs):
	Adapt to new scaled font API changes.

	* src/cairoint.h:
	New cache and scaled_font APIs

	* test/clip-operator-ref.png:
	* test/operator-clear-ref.png:
	* test/operator-source-ref.png:
	* test/text-antialias-gray-ref.png:
	* test/text-antialias-gray.c:
	* test/text-antialias-none-ref.png:
	* test/text-antialias-none.c:
	* test/text-antialias-subpixel-ref.png:
	* test/text-antialias-subpixel.c:
	* test/unbounded-operator-ref.png:
	Repond to bug fix in metrics computation for glyphs
	where y values were rounded up instead of down
	because of a sign difference between cairo and FreeType.


Index: Makefile.am
===================================================================
RCS file: /cvs/cairo/cairo/src/Makefile.am,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -d -r1.64 -r1.65
--- Makefile.am	24 Aug 2005 14:56:46 -0000	1.64
+++ Makefile.am	31 Aug 2005 22:08:02 -0000	1.65
@@ -121,6 +121,7 @@
 	cairo-pen.c				\
 	cairo-polygon.c				\
 	cairo-region.c				\
+	cairo-scaled-font.c			\
 	cairo-slope.c				\
 	cairo-spline.c				\
 	cairo-surface.c				\

--- NEW FILE: cairo-cache-private.h ---
(This appears to be a binary file; contents omitted.)

Index: cairo-cache.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-cache.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- cairo-cache.c	17 Aug 2005 16:51:09 -0000	1.14
+++ cairo-cache.c	31 Aug 2005 22:08:02 -0000	1.15
@@ -1,6 +1,7 @@
 /* cairo - a vector graphics library with display and print output
  *
- * This file is Copyright © 2004 Red Hat, Inc.
+ * Copyright © 2004 Red Hat, Inc.
+ * Copyright © 2005 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -30,481 +31,298 @@
  * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
- *      Keith Packard
+ *      Keith Packard <keithp at keithp.com>
  *	Graydon Hoare <graydon at redhat.com>
+ *	Carl Worth <cworth at cworth.org>
  */
 
 #include "cairoint.h"
 
-/* 
- * This structure, and accompanying table, is borrowed/modified from the
- * file xserver/render/glyph.c in the freedesktop.org x server, with
- * permission (and suggested modification of doubling sizes) by Keith
- * Packard.
- */
+struct _cairo_cache {
+    cairo_hash_table_t *hash_table;
 
-static const cairo_cache_arrangement_t cache_arrangements [] = {
-    { 16,		43,		41        },
-    { 32,		73,		71        },
-    { 64,		151,		149       },
-    { 128,		283,		281       },
-    { 256,		571,		569       },
-    { 512,		1153,		1151      },
-    { 1024,		2269,		2267      },
-    { 2048,		4519,		4517      },
-    { 4096,		9013,		9011      },
-    { 8192,		18043,		18041     },
-    { 16384,		36109,		36107     },
-    { 32768,		72091,		72089     },
-    { 65536,		144409,		144407    },
-    { 131072,		288361,		288359    },
-    { 262144,		576883,		576881    },
-    { 524288,		1153459,	1153457   },
-    { 1048576,		2307163,	2307161   },
-    { 2097152,		4613893,	4613891   },
-    { 4194304,		9227641,	9227639   },
-    { 8388608,		18455029,	18455027  },
-    { 16777216,		36911011,	36911009  },
-    { 33554432,		73819861,	73819859  },
-    { 67108864,		147639589,	147639587 },
-    { 134217728,	295279081,	295279079 },
-    { 268435456,	590559793,	590559791 }
+    cairo_destroy_func_t entry_destroy;
+
+    unsigned long max_size;
+    unsigned long size;
+
+    cairo_bool_t preserve_entries;
 };
 
-#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0]))
+static cairo_status_t
+_cairo_cache_init (cairo_cache_t		*cache,
+		   cairo_cache_keys_equal_func_t keys_equal,
+		   cairo_destroy_func_t		 entry_destroy,
+		   unsigned long		 max_size)
+{
+    cache->hash_table = _cairo_hash_table_create (keys_equal);
+    if (cache->hash_table == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
 
-/*
- * Entries 'e' are poiners, in one of 3 states:
- *
- * e == NULL: The entry has never had anything put in it
- * e != DEAD_ENTRY: The entry has an active value in it currently
- * e == DEAD_ENTRY: The entry *had* a value in it at some point, but the 
- *                  entry has been killed. Lookups requesting free space can
- *                  reuse these entries; lookups requesting a precise match
- *                  should neither return these entries nor stop searching when
- *                  seeing these entries. 
- *
- * We expect keys will not be destroyed frequently, so our table does not
- * contain any explicit shrinking code nor any chain-coalescing code for
- * entries randomly deleted by memory pressure (except during rehashing, of
- * course). These assumptions are potentially bad, but they make the
- * implementation straightforward.
- *
- * Revisit later if evidence appears that we're using excessive memory from
- * 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.
- * 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
- * given arrangement, so the tables should remain < 50% full. The table
- * size makes for the "first" hash modulus; a second prime (2 less than the
- * first prime) serves as the "second" hash modulus, which is co-prime and
- * thus guarantees a complete permutation of table indices.
- * 
- */
+    cache->entry_destroy = entry_destroy;
 
-#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1)
-#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL)
-#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY)
-#define LIVE_ENTRY_P(cache, i) \
- (!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
+    cache->max_size = max_size;
+    cache->size = 0;
 
-#ifdef NDEBUG
-#define _cache_sane_state(c) 
-#else
-static void 
-_cache_sane_state (cairo_cache_t *cache)
-{
-    assert (cache != NULL);
-    assert (cache->entries != NULL);
-    assert (cache->backend != NULL);
-    assert (cache->arrangement != NULL);
-    /* Cannot check this, a single object may larger */
-    /* assert (cache->used_memory <= cache->max_memory); */
-    assert (cache->live_entries <= cache->arrangement->size);   
+    cache->preserve_entries = FALSE;
+
+    return CAIRO_STATUS_SUCCESS;
 }
-#endif
 
 static void
-_entry_destroy (cairo_cache_t *cache, unsigned long i)
+_cairo_cache_fini (cairo_cache_t *cache)
 {
-    _cache_sane_state (cache);
+    cairo_cache_entry_t *entry;
 
-    if (LIVE_ENTRY_P(cache, i))
-    {
-	cairo_cache_entry_base_t *entry = cache->entries[i];
-	assert(cache->live_entries > 0);
-	assert(cache->used_memory >= entry->memory);
+    /* We have to manually remove all entries from the cache ourselves
+     * rather than relying on _cairo_hash_table_destroy to do that
+     * since otherwise the cache->entry_destroy callback would not get
+     * called on each entry. */
 
-	cache->live_entries--;
- 	cache->used_memory -= entry->memory;
-	cache->backend->destroy_entry (cache, entry);
-	cache->entries[i] = DEAD_ENTRY;
+    while (1) {
+	entry = _cairo_hash_table_random_entry (cache->hash_table, NULL);
+	if (entry == NULL)
+	    break;
+	_cairo_cache_remove (cache, entry);
     }
-}
-
-static cairo_cache_entry_base_t **
-_cache_lookup (cairo_cache_t *cache,
-	       void *key,
-	       int (*predicate)(void*,void*,void*))
-{    
-
-    cairo_cache_entry_base_t **probe;
-    unsigned long hash;
-    unsigned long table_size, i, idx, step;
-    
-    _cache_sane_state (cache);
-    assert (key != NULL);
-
-    table_size = cache->arrangement->size;
-    hash = cache->backend->hash (cache, key);
-    idx = hash % table_size;
-    step = 0;
-
-    for (i = 0; i < table_size; ++i)
-    {
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-	cache->probes++;
-#endif	
-	assert(idx < table_size);
-	probe = cache->entries + idx;
 
-	/* 
-	 * There are two lookup modes: searching for a free slot and searching
-	 * for an exact entry. 
-	 */ 
+    _cairo_hash_table_destroy (cache->hash_table);
+    cache->size = 0;
+}
 
-	if (predicate != NULL)
-	{
-	    /* We are looking up an exact entry. */
-	    if (*probe == NULL)
-	    {
-		/* Found an empty spot, there can't be a match */
-		break;
-	    }
-	    else if (*probe != DEAD_ENTRY 
-		     && (*probe)->hashcode == hash
-		     && predicate (cache, key, *probe))
-	    {
-		return probe;
-	    }
-	}
-	else
-	{
-	    /* We are just looking for a free slot. */
-	    if (*probe == NULL 
-		|| *probe == DEAD_ENTRY)
-	    {
-		return probe;
-	    }
-	}
+/**
+ * _cairo_cache_create:
+ * @keys_equal: a function to return TRUE if two keys are equal
+ * @entry_destroy: destroy notifier for cache entries
+ * @max_size: the maximum size for this cache
+ * 
+ * Creates a new cache using the keys_equal() function to determine
+ * the equality of entries.
+ *
+ * Data is provided to the cache in the form of user-derived version
+ * of cairo_cache_entry_t. A cache entry must be able to hold hash
+ * code, a size, and the key/value pair being stored in the
+ * cache. Sometimes only the key will be necessary, (as in
+ * _cairo_cache_remove()), and in these cases the value portion of the
+ * entry need not be initialized.
+ *
+ * The units for max_size can be chosen by the caller, but should be
+ * consistent with the units of the size field of cache entries. When
+ * adding an entry with _cairo_cache_insert if the total size of
+ * entries in the cache would exceed max_size then entries will be
+ * removed at random until the new entry would fit or the cache is
+ * empty. Then the new entry is inserted.
+ *
+ * There are cases in which the automatic removal of entries is
+ * undesired. If the cache entries have reference counts, then it is a
+ * simple matter to use the reference counts to ensure that entries
+ * continue to live even after being ejected from the cache. However,
+ * in some cases the memory overhead of adding a reference count to
+ * the entry would be objectionable. In such cases, the
+ * _cairo_cache_preserve() and _cairo_cache_release() calls can be
+ * used to establish a window during which no automatic removal of
+ * entries will occur.
+ * 
+ * Return value: 
+ **/
+cairo_cache_t *
+_cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal,
+		     cairo_destroy_func_t	   entry_destroy,
+		     unsigned long		   max_size)
+{
+    cairo_status_t status;
+    cairo_cache_t *cache;
 
-	if (step == 0) { 	    
-	    step = hash % cache->arrangement->rehash;
-	    if (step == 0)
-		step = 1;
-	}
+    cache = malloc (sizeof (cairo_cache_t));
+    if (cache == NULL)
+	return NULL;
 
-	idx += step;
-	if (idx >= table_size)
-	    idx -= table_size;
+    status = _cairo_cache_init (cache, keys_equal, entry_destroy, max_size);
+    if (status) {
+	free (cache);
+	return NULL;
     }
 
-    /* 
-     * The table should not have permitted you to get here if you were just
-     * looking for a free slot: there should have been room.
-     */
-    assert(predicate != NULL);
-    return NULL;
+    return cache;
 }
 
-static cairo_cache_entry_base_t **
-_find_available_entry_for (cairo_cache_t *cache,
-			   void *key)
+/**
+ * _cairo_cache_destroy:
+ * @cache: a cache to destroy
+ * 
+ * Immediately destroys the given cache, freeing all resources
+ * associated with it. As part of this process, the entry_destroy()
+ * function, (as passed to _cairo_cache_create), will be called for
+ * each entry in the cache.
+ **/
+void
+_cairo_cache_destroy (cairo_cache_t *cache)
 {
-    return _cache_lookup (cache, key, NULL);
-}
+    _cairo_cache_fini (cache);
 
-static cairo_cache_entry_base_t **
-_find_exact_live_entry_for (cairo_cache_t *cache,
-			    void *key)
-{    
-    return _cache_lookup (cache, key, cache->backend->keys_equal);
+    free (cache);
 }
 
-static const cairo_cache_arrangement_t *
-_find_cache_arrangement (unsigned long proposed_size)
+/**
+ * _cairo_cache_preserve:
+ * @cache: a cache with some precious entries in it (or about to be
+ * added)
+ * 
+ * Disable the automatic ejection of entries from the cache. Future
+ * calls to _cairo_cache_insert will add new entries to the cache
+ * regardless of how large the cache grows. See
+ * _cairo_cache_release().
+ **/
+void
+_cairo_cache_preserve (cairo_cache_t *cache)
 {
-    unsigned long idx;
-
-    for (idx = 0; idx < N_CACHE_SIZES; ++idx)
-	if (cache_arrangements[idx].high_water_mark >= proposed_size)
-	    return &cache_arrangements[idx];
-    return NULL;
+    cache->preserve_entries = TRUE;
 }
 
-static cairo_status_t
-_resize_cache (cairo_cache_t *cache, unsigned long proposed_size)
+/**
+ * _cairo_cache_release:
+ * @cache: a cache, just after the entries in it have become less
+ * previous
+ * 
+ * Cancel the effects of _cairo_cache_preserve(). That is, allow the
+ * cache to resume ejecting entries when it is larger than max_size as
+ * passed to cairo_cache_create. If the cache is already larger than
+ * max_size, no entries will be immediately removed, but the cache
+ * will be brought down to size at the time of the next call to
+ * _cairo_cache_insert.
+ **/
+void
+_cairo_cache_release (cairo_cache_t *cache)
 {
-    cairo_cache_t tmp;
-    cairo_cache_entry_base_t **e;
-    unsigned long new_size, i;
-
-    tmp = *cache;
-    tmp.arrangement = _find_cache_arrangement (proposed_size);
-    assert(tmp.arrangement != NULL);
-    if (tmp.arrangement == cache->arrangement)
-	return CAIRO_STATUS_SUCCESS;
-
-    new_size = tmp.arrangement->size;
-    tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *));
-    if (tmp.entries == NULL) 
-	return CAIRO_STATUS_NO_MEMORY;
-        
-    for (i = 0; i < cache->arrangement->size; ++i) {
-	if (LIVE_ENTRY_P(cache, i)) {
-	    e = _find_available_entry_for (&tmp, cache->entries[i]);
-	    assert (e != NULL);
-	    *e = cache->entries[i];
-	}
-    }
-    free (cache->entries);
-    cache->entries = tmp.entries;
-    cache->arrangement = tmp.arrangement;
-    return CAIRO_STATUS_SUCCESS;
+    cache->preserve_entries = FALSE;
 }
 
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-static double
-_load_factor (cairo_cache_t *cache)
+/**
+ * _cairo_cache_lookup:
+ * @cache: a cache
+ * @key: the key of interest
+ * @entry_return: pointer for return value
+ * 
+ * Performs a lookup in @cache looking for an entry which has a key
+ * that matches @key, (as determined by the keys_equal() function
+ * passed to _cairo_cache_create).
+ * 
+ * Return value: TRUE if there is an entry in the cache that matches
+ * @key, (which will now be in *entry_return). FALSE otherwise, (in
+ * which case *entry_return will be NULL).
+ **/
+cairo_private cairo_bool_t
+_cairo_cache_lookup (cairo_cache_t	  *cache,
+		     cairo_cache_entry_t  *key,
+		     cairo_cache_entry_t **entry_return)
 {
-    return ((double) cache->live_entries) 
-	/ ((double) cache->arrangement->size);
-}
-#endif
-
-/* 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;
+    return _cairo_hash_table_lookup (cache->hash_table,
+				     (cairo_hash_entry_t *) key,
+				     (cairo_hash_entry_t **) entry_return);
 }
 
-/* public API follows */
-
-cairo_status_t
-_cairo_cache_init (cairo_cache_t *cache,
-		   const cairo_cache_backend_t *backend,
-		   unsigned long max_memory)
-{    
-    assert (backend != NULL);
+/**
+ * _cairo_cache_remove_random:
+ * @cache: a cache
+ * 
+ * Remove a random entry from the cache.
+ * 
+ * Return value: CAIRO_STATUS_SUCCESS if an entry was successfully
+ * removed. CAIRO_INT_STATUS_CACHE_EMPTY if there are no entries that
+ * can be removed.
+ **/
+static cairo_int_status_t
+_cairo_cache_remove_random (cairo_cache_t *cache)
+{
+    cairo_cache_entry_t *entry;
 
-    if (cache != NULL){
-	cache->arrangement = &cache_arrangements[0];
-	cache->max_memory = max_memory;
-	cache->used_memory = 0;
-	cache->live_entries = 0;
+    entry = _cairo_hash_table_random_entry (cache->hash_table, NULL);
+    if (entry == NULL)
+	return CAIRO_INT_STATUS_CACHE_EMPTY;
 
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-	cache->hits = 0;
-	cache->misses = 0;
-	cache->probes = 0;
-#endif
+    _cairo_cache_remove (cache, entry);
 
-	cache->backend = backend;	
-	cache->entries = calloc (cache->arrangement->size,
-				 sizeof(cairo_cache_entry_base_t *));
-				 
-	if (cache->entries == NULL)
-	    return CAIRO_STATUS_NO_MEMORY;
-    }    
-    _cache_sane_state (cache);
     return CAIRO_STATUS_SUCCESS;
 }
 
-void
-_cairo_cache_destroy (cairo_cache_t *cache)
-{
-    unsigned long i;
-    if (cache == NULL)
-	return;
-	
-    _cache_sane_state (cache);
-
-    for (i = 0; i < cache->arrangement->size; ++i)
-	_entry_destroy (cache, i);
-	
-    free (cache->entries);
-    cache->entries = NULL;
-    cache->backend->destroy_cache (cache);
-}
-
-void
-_cairo_cache_shrink_to (cairo_cache_t *cache,
-			unsigned long max_memory)
-{
-    unsigned long idx;
-    /* Make some entries die if we're under memory pressure. */
-    while (cache->live_entries > 0 && cache->used_memory > max_memory) {
-	idx =  _random_entry (cache, NULL) - cache->entries;
-	assert (idx < cache->arrangement->size);
-	_entry_destroy (cache, idx);
-    }
-}
-
-cairo_status_t
-_cairo_cache_lookup (cairo_cache_t *cache,
-		     void          *key,
-		     void         **entry_return,
-		     int           *created_entry)
+/**
+ * _cairo_cache_insert:
+ * @cache: a cache
+ * @entry: an entry to be inserted
+ * 
+ * Insert @entry into the cache. If an entry exists in the cache with
+ * a matching key, then the old entry will be removed first, (and the
+ * entry_destroy() callback will be called on it).
+ * 
+ * Return value: CAIRO_STATUS_SUCCESS if successful or
+ * CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
+ **/
+cairo_private cairo_status_t
+_cairo_cache_insert (cairo_cache_t	 *cache,
+		     cairo_cache_entry_t *entry)
 {
+    cairo_status_t status;
 
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    cairo_cache_entry_base_t **slot = NULL, *new_entry;
-
-    _cache_sane_state (cache);
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-    if ((cache->hits + cache->misses) % 0xffff == 0)
-	printf("cache %p stats: size %ld, live %ld, load %.2f\n"
-	       "                      mem %ld/%ld, hit %ld, miss %ld\n"
-	       "                      probe %ld, %.2f probe/access\n", 
-	       cache,
-	       cache->arrangement->size, 
-	       cache->live_entries, 
-	       _load_factor (cache),
-	       cache->used_memory, 
-	       cache->max_memory,
-	       cache->hits, 
-	       cache->misses, 
-	       cache->probes,
-	       ((double) cache->probes) 
-	       / ((double) (cache->hits + 
-			    cache->misses + 1)));
-#endif
-    
-    /* See if we have an entry in the table already. */
-    slot = _find_exact_live_entry_for (cache, key);
-    if (slot != NULL) {
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-	cache->hits++;
-#endif
-	*entry_return = *slot;
-	if (created_entry)
-	    *created_entry = 0;
-	return status;
+    if (! cache->preserve_entries) {
+	while (cache->size + entry->size > cache->max_size) {
+	    status = _cairo_cache_remove_random (cache);
+	    if (status) {
+		if (status == CAIRO_INT_STATUS_CACHE_EMPTY)
+		    break;
+		return status;
+	    }
+	}
     }
 
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-    cache->misses++;
-#endif
-
-    /* Build the new entry. */
-    status = cache->backend->create_entry (cache, key, 
-					   (void **)&new_entry);
-    if (status != CAIRO_STATUS_SUCCESS)
-	return status;
-
-    /* Store the hash value in case the backend forgot. */
-    new_entry->hashcode = cache->backend->hash (cache, key);
-
-    if (cache->live_entries && cache->max_memory)
-        _cairo_cache_shrink_to (cache, cache->max_memory);
-    
-    /* Can't assert this; new_entry->memory may be larger than max_memory */
-    /* assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); */
-    
-    /* Make room in the table for a new slot. */
-    status = _resize_cache (cache, cache->live_entries + 1);
-    if (status != CAIRO_STATUS_SUCCESS) {
-	cache->backend->destroy_entry (cache, new_entry);
+    status = _cairo_hash_table_insert (cache->hash_table,
+				       (cairo_hash_entry_t *) entry);
+    if (status)
 	return status;
-    }
 
-    slot = _find_available_entry_for (cache, key);
-    assert(slot != NULL);
-    
-    /* Store entry in slot and increment statistics. */
-    *slot = new_entry;
-    cache->live_entries++;
-    cache->used_memory += new_entry->memory;
-
-    _cache_sane_state (cache);
+    cache->size += entry->size;
 
-    *entry_return = new_entry;
-    if (created_entry)
-      *created_entry = 1;
-    
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
-cairo_status_t
-_cairo_cache_remove (cairo_cache_t *cache,
-		     void          *key)
+/**
+ * _cairo_cache_remove:
+ * @cache: a cache
+ * @entry: key of entry to be removed
+ * 
+ * Remove an entry from the cache which has a key that matches @key,
+ * if any (as determined by the keys_equal() function passed to
+ * _cairo_cache_create).
+ **/
+cairo_private void
+_cairo_cache_remove (cairo_cache_t	 *cache,
+		     cairo_cache_entry_t *entry)
 {
-    cairo_cache_entry_base_t **slot;
-
-    _cache_sane_state (cache);
+    cache->size -= entry->size;
 
-    /* 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);
+    _cairo_hash_table_remove (cache->hash_table,
+			      (cairo_hash_entry_t *) entry);
 
-    return CAIRO_STATUS_SUCCESS;
+    if (cache->entry_destroy)
+	cache->entry_destroy (entry);
 }
 
-void *
-_cairo_cache_random_entry (cairo_cache_t *cache,
-			   int (*predicate)(void*))
+/**
+ * _cairo_cache_foreach:
+ * @cache: a cache
+ * @cache_callback: function to be called for each entry
+ * @closure: additional argument to be passed to @cache_callback
+ * 
+ * Call @cache_callback for each entry in the cache, in a
+ * non-specified order.
+ **/
+void
+_cairo_cache_foreach (cairo_cache_t	 	      *cache,
+		      cairo_cache_callback_func_t      cache_callback,
+		      void			      *closure)
 {
-    cairo_cache_entry_base_t **slot = _random_entry (cache, predicate);
-
-    return slot ? *slot : NULL;
+    _cairo_hash_table_foreach (cache->hash_table,
+			       cache_callback,
+			       closure);
 }
 
 unsigned long

Index: cairo-debug.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-debug.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-debug.c	1 Aug 2005 20:33:47 -0000	1.1
+++ cairo-debug.c	31 Aug 2005 22:08:02 -0000	1.2
@@ -60,7 +60,6 @@
 cairo_debug_reset_static_data (void)
 {
 #if CAIRO_HAS_XLIB_SURFACE
-    _cairo_xlib_surface_reset_static_data ();
     _cairo_xlib_screen_reset_static_data ();
 #endif
 

Index: cairo-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-font.c,v
retrieving revision 1.76
retrieving revision 1.77
diff -u -d -r1.76 -r1.77
--- cairo-font.c	24 Aug 2005 04:36:08 -0000	1.76
+++ cairo-font.c	31 Aug 2005 22:08:02 -0000	1.77
@@ -413,561 +413,6 @@
     _cairo_toy_font_face_scaled_font_create
 };
 
-/* cairo_scaled_font_t */
-
-static const cairo_scaled_font_t _cairo_scaled_font_nil = {
-    { 0 },			/* hash_entry */
-    CAIRO_STATUS_NO_MEMORY,	/* status */
-    -1,				/* ref_count */
-    NULL,			/* font_face */
-    { 1., 0., 0., 1., 0, 0},	/* font_matrix */
-    { 1., 0., 0., 1., 0, 0},	/* ctm */
-    { 1., 0., 0., 1., 0, 0},	/* scale */
-    { CAIRO_ANTIALIAS_DEFAULT,	/* options */
-      CAIRO_SUBPIXEL_ORDER_DEFAULT,
-      CAIRO_HINT_STYLE_DEFAULT,
-      CAIRO_HINT_METRICS_DEFAULT} ,
-    CAIRO_SCALED_FONT_BACKEND_DEFAULT,
-};
-
-/**
- * _cairo_scaled_font_set_error:
- * @scaled_font: a scaled_font
- * @status: a status value indicating an error, (eg. not
- * CAIRO_STATUS_SUCCESS)
- * 
- * Sets scaled_font->status to @status and calls _cairo_error;
- *
- * All assignments of an error status to scaled_font->status should happen
- * through _cairo_scaled_font_set_error() or else _cairo_error() should be
- * called immediately after the assignment.
- *
- * The purpose of this function is to allow the user to set a
- * breakpoint in _cairo_error() to generate a stack trace for when the
- * user causes cairo to detect an error.
- **/
-void
-_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
-			      cairo_status_t status)
-{
-    /* Don't overwrite an existing error. This preserves the first
-     * error, which is the most significant. It also avoids attempting
-     * to write to read-only data (eg. from a nil scaled_font). */
-    if (scaled_font->status == CAIRO_STATUS_SUCCESS)
-	scaled_font->status = status;
-
-    _cairo_error (status);
-}
-
-/**
- * cairo_scaled_font_status:
- * @scaled_font: a #cairo_scaled_font_t
- * 
- * Checks whether an error has previously occurred for this
- * scaled_font.
- * 
- * Return value: %CAIRO_STATUS_SUCCESS or another error such as
- *   %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_status_t
-cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
-{
-    return scaled_font->status;
-}
-
-/* Here we keep a unique mapping from
- * cairo_font_face_t/matrix/ctm/options => cairo_scaled_font_t.
- *
- * Here are the things that we want to map:
- *
- *  a) All otherwise referenced cairo_scaled_font_t's
- *  b) Some number of not otherwise referenced cairo_scaled_font_t's
- *
- * The implementation uses a hash table which covers (a)
- * completely. Then, for (b) we have an array of otherwise
- * unreferenced fonts (holdovers) which are expired in
- * least-recently-used order.
- *
- * The cairo_scaled_font_create code gets to treat this like a regular
- * hash table. All of the magic for the little holdover cache is in
- * cairo_scaled_font_reference and cairo_scaled_font_destroy.
- */
-
-/* This defines the size of the holdover array ... that is, the number
- * of scaled fonts we keep around even when not otherwise referenced
- */
-#define CAIRO_SCALED_FONT_MAX_HOLDOVERS 24
- 
-typedef struct _cairo_scaled_font_map {
-    cairo_hash_table_t *hash_table;
-    cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
-    int num_holdovers;
-} cairo_scaled_font_map_t;
-
-static cairo_scaled_font_map_t *cairo_scaled_font_map = NULL;
-
-CAIRO_MUTEX_DECLARE (cairo_scaled_font_map_mutex);
-
-static int
-_cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b);
-
-static cairo_scaled_font_map_t *
-_cairo_scaled_font_map_lock (void)
-{
-    CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex);
-
-    if (cairo_scaled_font_map == NULL)
-    {
-	cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t));
-	if (cairo_scaled_font_map == NULL)
-	    goto CLEANUP_MUTEX_LOCK;
-
-	cairo_scaled_font_map->hash_table =
-	    _cairo_hash_table_create (_cairo_scaled_font_keys_equal);
-
-	if (cairo_scaled_font_map->hash_table == NULL)
-	    goto CLEANUP_SCALED_FONT_MAP;
-
-	cairo_scaled_font_map->num_holdovers = 0;
-    }
-
-    return cairo_scaled_font_map;
-
- CLEANUP_SCALED_FONT_MAP:
-    free (cairo_scaled_font_map);
- CLEANUP_MUTEX_LOCK:
-    CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
-    return NULL;
-}
-
-static void
-_cairo_scaled_font_map_unlock (void)
-{
-   CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
-}
-
-static void
-_cairo_scaled_font_map_destroy (void)
-{
-    int i;
-    cairo_scaled_font_map_t *font_map = cairo_scaled_font_map;
-    cairo_scaled_font_t *scaled_font;
-
-    if (font_map == NULL)
-	return;
-
-    CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
-
-    for (i = 0; i < font_map->num_holdovers; i++) {
-	scaled_font = font_map->holdovers[i];
-	/* We should only get here through the reset_static_data path
-	 * and there had better not be any active references at that
-	 * point. */
-	assert (scaled_font->ref_count == 0);
-	_cairo_hash_table_remove (font_map->hash_table,
-				  &scaled_font->hash_entry);
-	_cairo_scaled_font_fini (scaled_font);
-	free (scaled_font);
-    }
-
-    _cairo_hash_table_destroy (font_map->hash_table);
-
-    free (cairo_scaled_font_map);
-    cairo_scaled_font_map = NULL;
-}
-
-/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
- * 
- * Not necessarily better than a lot of other hashes, but should be OK, and
- * well tested with binary data.
- */
-
-#define FNV_32_PRIME ((uint32_t)0x01000193)
-#define FNV1_32_INIT ((uint32_t)0x811c9dc5)
-
-static uint32_t
-_hash_bytes_fnv (unsigned char *buffer,
-		 int            len,
-		 uint32_t       hval)
-{
-    while (len--) {
-	hval *= FNV_32_PRIME;
-	hval ^= *buffer++;
-    }
-
-    return hval;
-}
-
-static void
-_cairo_scaled_font_init_key (cairo_scaled_font_t        *scaled_font,
-			     cairo_font_face_t	        *font_face,
-			     const cairo_matrix_t       *font_matrix,
-			     const cairo_matrix_t       *ctm,
-			     const cairo_font_options_t *options)
-{
-    uint32_t hash = FNV1_32_INIT;
-
-    scaled_font->status = CAIRO_STATUS_SUCCESS;
-    scaled_font->font_face = font_face;
-    scaled_font->font_matrix = *font_matrix;
-    scaled_font->ctm = *ctm;
-    scaled_font->options = *options;
-
-    /* We do a bytewise hash on the font matrices, ignoring the
-     * translation values. */
-    hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->font_matrix.xx),
-			    sizeof(double) * 4,
-			    hash);
-    hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->ctm.xx),
-			    sizeof(double) * 4,
-			    hash);
-
-    hash ^= (unsigned long) scaled_font->font_face;
-
-    hash ^= cairo_font_options_hash (&scaled_font->options);
-
-    scaled_font->hash_entry.hash = hash;
-}
-
-static cairo_bool_t
-_cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b)
-{
-    cairo_scaled_font_t *key_a = abstract_key_a;
-    cairo_scaled_font_t *key_b = abstract_key_b;
-
-    return (key_a->font_face == key_b->font_face &&
-	    memcmp ((unsigned char *)(&key_a->font_matrix.xx),
-		    (unsigned char *)(&key_b->font_matrix.xx),
-		    sizeof(double) * 4) == 0 &&
-	    memcmp ((unsigned char *)(&key_a->ctm.xx),
-		    (unsigned char *)(&key_b->ctm.xx),
-		    sizeof(double) * 4) == 0 &&
-	    cairo_font_options_equal (&key_a->options, &key_b->options));
-}
-
-void
-_cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font, 
-			 cairo_font_face_t		   *font_face,
-			 const cairo_matrix_t              *font_matrix,
-			 const cairo_matrix_t              *ctm,
-			 const cairo_font_options_t	   *options,
-			 const cairo_scaled_font_backend_t *backend)
-{
-    scaled_font->ref_count = 1;
-
-    _cairo_scaled_font_init_key (scaled_font, font_face,
-				 font_matrix, ctm, options);
-
-    cairo_font_face_reference (font_face);
-
-    cairo_matrix_multiply (&scaled_font->scale,
-			   &scaled_font->font_matrix,
-			   &scaled_font->ctm);
-
-    scaled_font->backend = backend;
-}
-
-void
-_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
-{
-    if (scaled_font->font_face)
-	cairo_font_face_destroy (scaled_font->font_face);
-
-    scaled_font->backend->fini (scaled_font);
-}
-
-/**
- * cairo_scaled_font_create:
- * @font_face: a #cairo_font_face_t
- * @font_matrix: font space to user space transformation matrix for the
- *       font. In the simplest case of a N point font, this matrix is
- *       just a scale by N, but it can also be used to shear the font
- *       or stretch it unequally along the two axes. See
- *       cairo_set_font_matrix().
- * @ctm: user to device transformation matrix with which the font will
- *       be used.
- * @options: options to use when getting metrics for the font and
- *           rendering with it.
- * 
- * Creates a #cairo_scaled_font_t object from a font face and matrices that
- * describe the size of the font and the environment in which it will
- * be used.
- * 
- * Return value: a newly created #cairo_scaled_font_t. Destroy with
- *  cairo_scaled_font_destroy()
- **/
-cairo_scaled_font_t *
-cairo_scaled_font_create (cairo_font_face_t          *font_face,
-			  const cairo_matrix_t       *font_matrix,
-			  const cairo_matrix_t       *ctm,
-			  const cairo_font_options_t *options)
-{
-    cairo_status_t status;
-    cairo_scaled_font_map_t *font_map;
-    cairo_scaled_font_t key, *scaled_font = NULL;
-
-    font_map = _cairo_scaled_font_map_lock ();
-    if (font_map == NULL)
-	goto UNWIND;
-    
-    _cairo_scaled_font_init_key (&key, font_face,
-				 font_matrix, ctm, options);
-
-    /* Return existing scaled_font if it exists in the hash table. */
-    if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
-				  (cairo_hash_entry_t**) &scaled_font))
-    {
-	_cairo_scaled_font_map_unlock ();
-	return cairo_scaled_font_reference (scaled_font);
-    }
-
-    /* Otherwise create it and insert it into the hash table. */
-    status = font_face->backend->scaled_font_create (font_face, font_matrix,
-						     ctm, options, &scaled_font);
-    if (status)
-	goto UNWIND_FONT_MAP_LOCK;
-
-    status = _cairo_hash_table_insert (font_map->hash_table,
-				       &scaled_font->hash_entry);
-    if (status)
-	goto UNWIND_SCALED_FONT_CREATE;
-
-    _cairo_scaled_font_map_unlock ();
-
-    return scaled_font;
-
-UNWIND_SCALED_FONT_CREATE:
-    /* We can't call _cairo_scaled_font_destroy here since it expects
-     * that the font has already been successfully inserted into the
-     * hash table. */
-    _cairo_scaled_font_fini (scaled_font);
-    free (scaled_font);
-UNWIND_FONT_MAP_LOCK:
-    _cairo_scaled_font_map_unlock ();
-UNWIND:
-    return NULL;
-}
-
-/**
- * cairo_scaled_font_reference:
- * @scaled_font: a #cairo_scaled_font_t, (may be NULL in which case
- * this function does nothing)
- * 
- * Increases the reference count on @scaled_font by one. This prevents
- * @scaled_font from being destroyed until a matching call to
- * cairo_scaled_font_destroy() is made.
- *
- * Returns: the referenced #cairo_scaled_font_t
- **/
-cairo_scaled_font_t *
-cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
-{
-    if (scaled_font == NULL)
-	return NULL;
-
-    if (scaled_font->ref_count == (unsigned int)-1)
-	return scaled_font;
-
-    /* We would normally assert (scaled_font->ref_count > 0) here, but
-     * we are using ref_count == 0 as a legitimate case for the
-     * holdovers array. See below. */
-
-    /* If the original reference count is 0, then this font must have
-     * been found in font_map->holdovers, (which means this caching is
-     * actually working). So now we remove it from the holdovers
-     * array. */
-    if (scaled_font->ref_count == 0) {
-	cairo_scaled_font_map_t *font_map;
-	int i;
-
-	font_map = _cairo_scaled_font_map_lock ();
-	{
-	    for (i = 0; i < font_map->num_holdovers; i++)
-		if (font_map->holdovers[i] == scaled_font)
-		    break;
-	    assert (i < font_map->num_holdovers);
-
-	    font_map->num_holdovers--;
-	    memmove (&font_map->holdovers[i],
-		     &font_map->holdovers[i+1],
-		     (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
-	}
-	_cairo_scaled_font_map_unlock ();
-    }
-
-    scaled_font->ref_count++;
-
-    return scaled_font;
-}
-
-/**
- * cairo_scaled_font_destroy:
- * @scaled_font: a #cairo_scaled_font_t
- * 
- * Decreases the reference count on @font by one. If the result
- * is zero, then @font and all associated resources are freed.
- * See cairo_scaled_font_reference().
- **/
-void
-cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
-{
-    cairo_scaled_font_map_t *font_map;
-
-    if (scaled_font == NULL)
-	return;
-
-    if (scaled_font->ref_count == (unsigned int)-1)
-	return;
-
-    assert (scaled_font->ref_count > 0);
-
-    if (--(scaled_font->ref_count) > 0)
-	return;
-
-    font_map = _cairo_scaled_font_map_lock ();
-    assert (font_map != NULL);
-    {
-	/* Rather than immediately destroying this object, we put it into
-	 * the font_map->holdovers array in case it will get used again
-	 * soon. To make room for it, we do actually destroy the
-	 * least-recently-used holdover.
-	 */
-	if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) {
-	    cairo_scaled_font_t *lru;
-
-	    lru = font_map->holdovers[0];
-	    assert (lru->ref_count == 0);
-	
-	    _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry);
-
-	    _cairo_scaled_font_fini (lru);
-	    free (lru);
-	
-	    font_map->num_holdovers--;
-	    memmove (&font_map->holdovers[0],
-		     &font_map->holdovers[1],
-		     font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
-	}
-
-	font_map->holdovers[font_map->num_holdovers] = scaled_font;
-	font_map->num_holdovers++;
-    }
-    _cairo_scaled_font_map_unlock ();
-}
-
-cairo_status_t
-_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
-				   const char          *utf8, 
-				   cairo_glyph_t      **glyphs, 
-				   int 		       *num_glyphs)
-{
-    if (scaled_font->status)
-	return scaled_font->status;
-
-    return scaled_font->backend->text_to_glyphs (scaled_font, utf8, glyphs, num_glyphs);
-}
-
-cairo_status_t
-_cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
-				  cairo_glyph_t 	*glyphs,
-				  int 			 num_glyphs,
-				  cairo_text_extents_t  *extents)
-{
-    if (scaled_font->status)
-	return scaled_font->status;
-
-    return scaled_font->backend->glyph_extents (scaled_font, glyphs, num_glyphs, extents);
-}
-
-
-cairo_status_t
-_cairo_scaled_font_glyph_bbox (cairo_scaled_font_t *scaled_font,
-			       cairo_glyph_t       *glyphs,
-			       int                  num_glyphs,
-			       cairo_box_t	   *bbox)
-{
-    if (scaled_font->status)
-	return scaled_font->status;
-
-    return scaled_font->backend->glyph_bbox (scaled_font, glyphs, num_glyphs, bbox);
-}
-
-cairo_status_t
-_cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
-				cairo_operator_t        operator,
-				cairo_pattern_t        *pattern,
-				cairo_surface_t        *surface,
-				int                     source_x,
-				int                     source_y,
-				int			dest_x,
-				int			dest_y,
-				unsigned int		width,
-				unsigned int		height,
-				cairo_glyph_t          *glyphs,
-				int                     num_glyphs)
-{
-    cairo_status_t status;
-
-    /* These operators aren't interpreted the same way by the backends;
-     * they are implemented in terms of other operators in cairo-gstate.c
-     */
-    assert (operator != CAIRO_OPERATOR_SOURCE && operator != CAIRO_OPERATOR_CLEAR);
-    
-    if (scaled_font->status)
-	return scaled_font->status;
-
-    status = _cairo_surface_show_glyphs (scaled_font, operator, pattern, 
-					 surface,
-					 source_x, source_y,
-					 dest_x, dest_y,
-					 width, height,
-					 glyphs, num_glyphs);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return status;
-
-    /* Surface display routine either does not exist or failed. */
-    return scaled_font->backend->show_glyphs (scaled_font, operator, pattern, 
-					      surface,
-					      source_x, source_y,
-					      dest_x, dest_y,
-					      width, height,
-					      glyphs, num_glyphs);
-}
-
-cairo_status_t
-_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
-			       cairo_glyph_t	   *glyphs, 
-			       int		    num_glyphs,
-			       cairo_path_fixed_t  *path)
-{
-    if (scaled_font->status)
-	return scaled_font->status;
-
-    return scaled_font->backend->glyph_path (scaled_font, glyphs, num_glyphs, path);
-}
-
-cairo_status_t
-_cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t     *scaled_font,
-					cairo_glyph_cache_key_t *key)
-{
-    if (scaled_font->status)
-	return scaled_font->status;
-
-    scaled_font->backend->get_glyph_cache_key (scaled_font, key);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_scaled_font_font_extents (cairo_scaled_font_t  *scaled_font,
-				 cairo_font_extents_t *extents)
-{
-    if (scaled_font->status)
-	return scaled_font->status;
-
-    return scaled_font->backend->font_extents (scaled_font, extents);
-}
-
 void
 _cairo_unscaled_font_init (cairo_unscaled_font_t               *unscaled_font, 
 			   const cairo_unscaled_font_backend_t *backend)
@@ -1001,303 +446,11 @@
     free (unscaled_font);
 }
 
-/* Public font API follows. */
-
-/**
- * cairo_scaled_font_extents:
- * @scaled_font: a #cairo_scaled_font_t
- * @extents: a #cairo_font_extents_t which to store the retrieved extents.
- * 
- * Gets the metrics for a #cairo_scaled_font_t. 
- **/
-void
-cairo_scaled_font_extents (cairo_scaled_font_t  *scaled_font,
-			   cairo_font_extents_t *extents)
-{
-    cairo_int_status_t status;
-    double  font_scale_x, font_scale_y;
-    
-    if (scaled_font->status)
-	return;
-
-    status = _cairo_scaled_font_font_extents (scaled_font, extents);
-    if (status) {
-	_cairo_scaled_font_set_error (scaled_font, status);
-	return;
-    }
-    
-    _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
-					 &font_scale_x, &font_scale_y,
-					 /* XXX */ 1);
-    
-    /* 
-     * The font responded in unscaled units, scale by the font
-     * matrix scale factors to get to user space
-     */
-    
-    extents->ascent *= font_scale_y;
-    extents->descent *= font_scale_y;
-    extents->height *= font_scale_y;
-    extents->max_x_advance *= font_scale_x;
-    extents->max_y_advance *= font_scale_y;
-}
-
-/**
- * cairo_font_glyph_extents:
- * @scaled_font: a #cairo_scaled_font_t
- * @glyphs: an array of glyph IDs with X and Y offsets.
- * @num_glyphs: the number of glyphs in the @glyphs array
- * @extents: a #cairo_text_extents_t which to store the retrieved extents.
- * 
- * cairo_font_glyph_extents() gets the overall metrics for a string of
- * glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0. 
- **/
-void
-cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
-				 cairo_glyph_t         *glyphs, 
-				 int                    num_glyphs,
-				 cairo_text_extents_t  *extents)
-{
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    cairo_glyph_t origin_glyph;
-    cairo_text_extents_t origin_extents;
-    int i;
-    double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
-    double x_pos = 0.0, y_pos = 0.0;
-    int set = 0;
-
-    if (scaled_font->status)
-	return;
-
-    if (!num_glyphs)
-    {
-	extents->x_bearing = 0.0;
-	extents->y_bearing = 0.0;
-	extents->width = 0.0;
-	extents->height = 0.0;
-	extents->x_advance = 0.0;
-	extents->y_advance = 0.0;
-	
-	return;
-    }
-
-    for (i = 0; i < num_glyphs; i++)
-    {
-	double		x, y;
-	double		wm, hm;
-	
-	origin_glyph = glyphs[i];
-	origin_glyph.x = 0.0;
-	origin_glyph.y = 0.0;
-	status = _cairo_scaled_font_glyph_extents (scaled_font,
-						   &origin_glyph, 1,
-						   &origin_extents);
-	
-	/*
-	 * Transform font space metrics into user space metrics
-	 * by running the corners through the font matrix and
-	 * expanding the bounding box as necessary
-	 */
-	x = origin_extents.x_bearing;
-	y = origin_extents.y_bearing;
-	cairo_matrix_transform_point (&scaled_font->font_matrix,
-				      &x, &y);
-
-	for (hm = 0.0; hm <= 1.0; hm += 1.0)
-	    for (wm = 0.0; wm <= 1.0; wm += 1.0)
-	    {
-		x = origin_extents.x_bearing + origin_extents.width * wm;
-		y = origin_extents.y_bearing + origin_extents.height * hm;
-		cairo_matrix_transform_point (&scaled_font->font_matrix,
-					      &x, &y);
-		x += glyphs[i].x;
-		y += glyphs[i].y;
-		if (!set)
-		{
-		    min_x = max_x = x;
-		    min_y = max_y = y;
-		    set = 1;
-		}
-		else
-		{
-		    if (x < min_x) min_x = x;
-		    if (x > max_x) max_x = x;
-		    if (y < min_y) min_y = y;
-		    if (y > max_y) max_y = y;
-		}
-	    }
-
-	x = origin_extents.x_advance;
-	y = origin_extents.y_advance;
-	cairo_matrix_transform_point (&scaled_font->font_matrix,
-				      &x, &y);
-	x_pos = glyphs[i].x + x;
-	y_pos = glyphs[i].y + y;
-    }
-
-    extents->x_bearing = min_x - glyphs[0].x;
-    extents->y_bearing = min_y - glyphs[0].y;
-    extents->width = max_x - min_x;
-    extents->height = max_y - min_y;
-    extents->x_advance = x_pos - glyphs[0].x;
-    extents->y_advance = y_pos - glyphs[0].y;
-}
-
-/* Now we implement functions to access a default global image & metrics
- * cache. 
- */
-
-unsigned long
-_cairo_glyph_cache_hash (void *cache, void *key)
-{
-    cairo_glyph_cache_key_t *in;
-    in = (cairo_glyph_cache_key_t *) key;
-    return 
-	((unsigned long) in->unscaled) 
-	^ ((unsigned long) in->scale.xx) 
-	^ ((unsigned long) in->scale.yx) 
-	^ ((unsigned long) in->scale.xy) 
-	^ ((unsigned long) in->scale.yy)
-        ^ (in->flags * 1451) /* 1451 is just an abitrary prime */
-	^ in->index;
-}
-
-int
-_cairo_glyph_cache_keys_equal (void *cache,
-			       void *k1,
-			       void *k2)
-{
-    cairo_glyph_cache_key_t *a, *b;
-    a = (cairo_glyph_cache_key_t *) k1;
-    b = (cairo_glyph_cache_key_t *) k2;
-    return (a->index == b->index)
-	&& (a->unscaled == b->unscaled)
-	&& (a->flags == b->flags)
-	&& (a->scale.xx == b->scale.xx)
-	&& (a->scale.yx == b->scale.yx)
-	&& (a->scale.xy == b->scale.xy)
-	&& (a->scale.yy == b->scale.yy);
-}
-
-
-static cairo_status_t
-_image_glyph_cache_create_entry (void *cache,
-				 void *key,
-				 void **return_value)
-{
-    cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key;
-    cairo_image_glyph_cache_entry_t *im;
-    cairo_status_t status;
-
-    im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t));
-    if (im == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
-
-    im->key = *k;    
-    status = im->key.unscaled->backend->create_glyph (im->key.unscaled,
-						      im);
-
-    if (status != CAIRO_STATUS_SUCCESS) {
-	free (im);
-	return status;
-    }
-
-    _cairo_unscaled_font_reference (im->key.unscaled);
-
-    im->key.base.memory = 
-	sizeof (cairo_image_glyph_cache_entry_t) 
-	+ (im->image ? 
-	   sizeof (cairo_image_surface_t) 
-	   + 28 * sizeof (int) /* rough guess at size of pixman image structure */
-	   + (im->image->height * im->image->stride) : 0);
-
-    *return_value = im;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-
-static void
-_image_glyph_cache_destroy_entry (void *cache,
-				  void *value)
-{
-    cairo_image_glyph_cache_entry_t *im;
-
-    im = (cairo_image_glyph_cache_entry_t *) value;
-    _cairo_unscaled_font_destroy (im->key.unscaled);
-    cairo_surface_destroy (&(im->image->base));
-    free (im); 
-}
-
-static void 
-_image_glyph_cache_destroy_cache (void *cache)
-{
-    free (cache);
-}
-
-static const cairo_cache_backend_t cairo_image_cache_backend = {
-    _cairo_glyph_cache_hash,
-    _cairo_glyph_cache_keys_equal,
-    _image_glyph_cache_create_entry,
-    _image_glyph_cache_destroy_entry,
-    _image_glyph_cache_destroy_cache
-};
-
-CAIRO_MUTEX_DECLARE(_global_image_glyph_cache_mutex);
-
-static cairo_cache_t *
-_global_image_glyph_cache = NULL;
-
-void
-_cairo_lock_global_image_glyph_cache (void)
-{
-    CAIRO_MUTEX_LOCK (_global_image_glyph_cache_mutex);
-}
-
-void
-_cairo_unlock_global_image_glyph_cache (void)
-{
-    if (_global_image_glyph_cache) {
-	_cairo_cache_shrink_to (_global_image_glyph_cache, 
-				CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT);
-    }
-    CAIRO_MUTEX_UNLOCK (_global_image_glyph_cache_mutex);
-}
-
-cairo_cache_t *
-_cairo_get_global_image_glyph_cache (void)
-{
-    if (_global_image_glyph_cache == NULL) {
-	_global_image_glyph_cache = malloc (sizeof (cairo_cache_t));
-	
-	if (_global_image_glyph_cache == NULL)
-	    goto FAIL;
-	
-	if (_cairo_cache_init (_global_image_glyph_cache,
-			       &cairo_image_cache_backend,
-			       0))
-	    goto FAIL;
-    }
-
-    return _global_image_glyph_cache;
-    
- FAIL:
-    if (_global_image_glyph_cache)
-	free (_global_image_glyph_cache);
-    _global_image_glyph_cache = NULL;
-    return NULL;
-}
-
 void
 _cairo_font_reset_static_data (void)
 {
     _cairo_scaled_font_map_destroy ();
 
-    _cairo_lock_global_image_glyph_cache();
-    _cairo_cache_destroy (_global_image_glyph_cache);
-    _global_image_glyph_cache = NULL;
-    _cairo_unlock_global_image_glyph_cache();
-
     CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex);
     _cairo_hash_table_destroy (cairo_toy_font_face_hash_table);
     cairo_toy_font_face_hash_table = NULL;

Index: cairo-ft-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ft-font.c,v
retrieving revision 1.110
retrieving revision 1.111
diff -u -d -r1.110 -r1.111
--- cairo-ft-font.c	24 Aug 2005 02:52:09 -0000	1.110
+++ cairo-ft-font.c	31 Aug 2005 22:08:02 -0000	1.111
@@ -57,20 +57,6 @@
 #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
 #define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
 
-/* We pack some of our own information into the bits unused
- * by FreeType's load flags. If FreeType ever uses up all
- * the load flag bits, we'll have to do something else.
- * (probably just store what we care about in load_flags
- * then convert into FreeType terms.
- */
-#define PRIVATE_FLAG_HINT_METRICS (0x01 << 24)
-#define PRIVATE_FLAG_EMBOLDEN     (0x02 << 24)
[...1526 lines suppressed...]
@@ -2533,6 +2213,7 @@
 {
     cairo_ft_unscaled_font_t *unscaled;
     cairo_font_face_t *font_face;
+    cairo_ft_options_t ft_options;
 
     unscaled = _cairo_ft_unscaled_font_create_from_face (face);
     if (unscaled == NULL) {
@@ -2540,7 +2221,10 @@
 	return (cairo_font_face_t *)&_cairo_font_face_nil;
     }
 
-    font_face = _cairo_ft_font_face_create (unscaled, load_flags);
+    ft_options.load_flags = load_flags;
+    ft_options.extra_flags = 0;
+    
+    font_face = _cairo_ft_font_face_create (unscaled, ft_options);
     _cairo_unscaled_font_destroy (&unscaled->base);
 
     if (font_face) {

Index: cairo-gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate.c,v
retrieving revision 1.168
retrieving revision 1.169
diff -u -d -r1.168 -r1.169
--- cairo-gstate.c	24 Aug 2005 08:39:56 -0000	1.168
+++ cairo-gstate.c	31 Aug 2005 22:08:02 -0000	1.169
@@ -1950,30 +1950,17 @@
 			      int	     *num_glyphs)
 {
     cairo_status_t status;
-    int i;
 
     status = _cairo_gstate_ensure_scaled_font (gstate);
     if (status)
 	return status;
     
-    status = _cairo_scaled_font_text_to_glyphs (gstate->scaled_font, 
+    status = _cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y,
 						utf8, glyphs, num_glyphs);
 
     if (status || !glyphs || !num_glyphs || !(*glyphs) || !(num_glyphs))
 	return status;
 
-    /* The font responded in glyph space, starting from (0,0).  Convert to
-       user space by applying the font transform, then add any current point
-       offset. */
-
-    for (i = 0; i < *num_glyphs; ++i) {
-	cairo_matrix_transform_point (&gstate->font_matrix, 
-				      &((*glyphs)[i].x),
-				      &((*glyphs)[i].y));
-	(*glyphs)[i].x += x;
-	(*glyphs)[i].y += y;
-    }
-    
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -2050,6 +2037,17 @@
     if (!src)
 	src = &pattern.base;
     
+    status = _cairo_surface_show_glyphs (glyph_info->font, operator, src, 
+					 dst,
+					 extents->x, extents->y,
+					 extents->x - dst_x, extents->y - dst_y,
+					 extents->width,     extents->height,
+					 glyph_info->glyphs,
+					 glyph_info->num_glyphs);
+
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return status;
+    
     status = _cairo_scaled_font_show_glyphs (glyph_info->font, 
 					     operator, 
 					     src, dst,
@@ -2074,7 +2072,6 @@
     int i;
     cairo_glyph_t *transformed_glyphs = NULL;
     cairo_pattern_union_t pattern;
-    cairo_box_t bbox;
     cairo_rectangle_t extents;
     cairo_show_glyphs_info_t glyph_info;
 
@@ -2102,21 +2099,15 @@
     }
 
     if (_cairo_operator_bounded (gstate->operator))
-    {
-	status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font,
-						transformed_glyphs, num_glyphs, 
-						&bbox);
-	if (status)
-	    goto CLEANUP_GLYPHS;
-	
-	_cairo_box_round_to_rectangle (&bbox, &extents);
-    }
+	status = _cairo_scaled_font_glyph_device_extents (gstate->scaled_font,
+							  transformed_glyphs, 
+							  num_glyphs, 
+							  &extents);
     else
-    {
 	status = _cairo_surface_get_extents (gstate->target, &extents);
-	if (status)
-	    goto CLEANUP_GLYPHS;
-    }
+
+    if (status)
+        goto CLEANUP_GLYPHS;
     
     status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
     if (status)

Index: cairo-path.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-path.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- cairo-path.c	3 May 2005 21:28:50 -0000	1.27
+++ cairo-path.c	31 Aug 2005 22:08:02 -0000	1.28
@@ -132,6 +132,17 @@
     return CAIRO_STATUS_SUCCESS;
 }
 
+cairo_path_fixed_t *
+_cairo_path_fixed_create (void)
+{
+    cairo_path_fixed_t	*path = malloc (sizeof (cairo_path_fixed_t));
+
+    if (!path)
+	return NULL;
+    _cairo_path_fixed_init (path);
+    return path;
+}
+
 void
 _cairo_path_fixed_fini (cairo_path_fixed_t *path)
 {
@@ -155,6 +166,13 @@
     path->has_current_point = 0;
 }
 
+void
+_cairo_path_fixed_destroy (cairo_path_fixed_t *path)
+{
+    _cairo_path_fixed_fini (path);
+    free (path);
+}
+
 cairo_status_t
 _cairo_path_fixed_move_to (cairo_path_fixed_t  *path,
 			   cairo_fixed_t	x,

--- NEW FILE: cairo-scaled-font.c ---
(This appears to be a binary file; contents omitted.)

Index: cairo-xlib-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xlib-surface.c,v
retrieving revision 1.118
retrieving revision 1.119
diff -u -d -r1.118 -r1.119
--- cairo-xlib-surface.c	30 Aug 2005 17:50:27 -0000	1.118
+++ cairo-xlib-surface.c	31 Aug 2005 22:08:02 -0000	1.119
@@ -192,16 +192,15 @@
 }
 
 static cairo_surface_t *
-_cairo_xlib_surface_create_similar (void	       *abstract_src,
-				    cairo_content_t	content,
-				    int			width,
-				    int			height)
+_cairo_xlib_surface_create_similar_with_format (void	       *abstract_src,
+						cairo_format_t	format,
+						int		width,
+						int		height)
[...1058 lines suppressed...]
-
-static void
-_destroy_glyphset_cache_recurse (glyphset_cache_t *cache)
-{
-    if (cache == NULL)
-	return;
-
-    _destroy_glyphset_cache_recurse (cache->next);
-    _cairo_cache_destroy (&cache->base);
-    free (cache);
-}
-
-void
-_cairo_xlib_surface_reset_static_data (void)
-{
-    _lock_xlib_glyphset_caches ();
-    _destroy_glyphset_cache_recurse (_xlib_glyphset_caches);
-    _xlib_glyphset_caches = NULL;
-    _unlock_xlib_glyphset_caches (NULL);
-}

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.207
retrieving revision 1.208
diff -u -d -r1.207 -r1.208
--- cairoint.h	28 Aug 2005 01:46:34 -0000	1.207
+++ cairoint.h	31 Aug 2005 22:08:02 -0000	1.208
@@ -184,6 +184,7 @@
 #define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0)
 
 #include "cairo-hash-private.h"
+#include "cairo-cache-private.h"
 
 typedef struct _cairo_point {
     cairo_fixed_t x;
@@ -227,7 +228,8 @@
 typedef enum cairo_int_status {
     CAIRO_INT_STATUS_DEGENERATE = 1000,
     CAIRO_INT_STATUS_UNSUPPORTED,
-    CAIRO_INT_STATUS_NOTHING_TO_DO
+    CAIRO_INT_STATUS_NOTHING_TO_DO,
+    CAIRO_INT_STATUS_CACHE_EMPTY
 } cairo_int_status_t;
 
 typedef enum cairo_direction {
@@ -288,6 +290,8 @@
 typedef struct _cairo_color cairo_color_t;
 typedef struct _cairo_image_surface cairo_image_surface_t;
 
+typedef struct _cairo_surface_backend cairo_surface_backend_t;
+
 cairo_private void
 _cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle);
 
@@ -348,108 +352,9 @@
 				 void			     *user_data,
 				 cairo_destroy_func_t	      destroy);
 
-/* cairo_cache.c structures and functions */ 
-
-typedef struct _cairo_cache_backend {
-
-    unsigned long	(*hash)			(void *cache,
-						 void *key);
-
-    int			(*keys_equal)		(void *cache,
-						 void *k1, 
-						 void *k2);
-    
-    cairo_status_t	(*create_entry)		(void *cache,
-						 void *key,
-						 void **entry_return);
-
-    void		(*destroy_entry)	(void *cache,
-						 void *entry);
-
-    void		(*destroy_cache)	(void *cache);
-
-} cairo_cache_backend_t;
-
-/* 
- * The cairo_cache system makes the following assumptions about
- * entries in its cache:
- *
- *  - a pointer to an entry can be cast to a cairo_cache_entry_base_t.
- *  - a pointer to an entry can also be cast to the "key type".
- *
- * The practical effect of this is that your entries must be laid
- * out this way:
- *
- *    struct my_entry { 
- *      cairo_cache_entry_base_t;
- *      my_key_value_1;
- *      my_key_value_2;
- *      ...
- *      my_value;
- *    };
- */
-
-typedef struct {
-    unsigned long memory;
-    unsigned long hashcode;
-} cairo_cache_entry_base_t;
-
-typedef struct {
-    unsigned long high_water_mark;
-    unsigned long size;
-    unsigned long rehash;
-} cairo_cache_arrangement_t;
-
-#undef CAIRO_MEASURE_CACHE_PERFORMANCE
-
-typedef struct {
-    const cairo_cache_backend_t *backend;
-    const cairo_cache_arrangement_t *arrangement;
-    cairo_cache_entry_base_t **entries;
-
-    unsigned long max_memory;
-    unsigned long used_memory;
-    unsigned long live_entries;
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-    unsigned long hits;
-    unsigned long misses;
-    unsigned long probes;
-#endif
-} cairo_cache_t;
-
-cairo_private cairo_status_t
-_cairo_cache_init (cairo_cache_t *cache,
-		   const cairo_cache_backend_t *backend,
-		   unsigned long max_memory);
-
-cairo_private void
-_cairo_cache_destroy (cairo_cache_t *cache);
-
-cairo_private void
-_cairo_cache_shrink_to (cairo_cache_t *cache,
-			unsigned long max_memory);
-
-cairo_private cairo_status_t
-_cairo_cache_lookup (cairo_cache_t *cache,
-		     void          *key,
-		     void         **entry_return,
-		     int           *created_entry);
-
-cairo_private cairo_status_t
-_cairo_cache_remove (cairo_cache_t *cache,
-		     void          *key);
-
-cairo_private void *
-_cairo_cache_random_entry (cairo_cache_t *cache,
-			   int (*predicate) (void*));
-
 cairo_private unsigned long
 _cairo_hash_string (const char *c);
 
-#define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
-#define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
-
 typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
 typedef struct _cairo_scaled_font_backend   cairo_scaled_font_backend_t;
 typedef struct _cairo_font_face_backend     cairo_font_face_backend_t;
@@ -471,16 +376,47 @@
     cairo_hint_metrics_t hint_metrics;
 };
 
+typedef struct _cairo_scaled_glyph {
+    cairo_cache_entry_t	    cache_entry;	/* hash is glyph index */
+    cairo_scaled_font_t	    *scaled_font;	/* font the glyph lives in */
+    cairo_text_extents_t    metrics;		/* user-space metrics */
+    cairo_box_t		    bbox;		/* device-space bounds */
+    cairo_image_surface_t   *surface;		/* device-space image */
+    cairo_path_fixed_t	    *path;		/* device-space outline */
+    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))
+
 struct _cairo_scaled_font {
+    /* must be first to be stored in a hash table */
     cairo_hash_entry_t hash_entry;
+
+    /* useful bits for _cairo_scaled_font_nil */
     cairo_status_t status;
     int ref_count;
+    
+    /* hash key members */
     cairo_font_face_t *font_face; /* may be NULL */
     cairo_matrix_t font_matrix;	  /* font space => user space */
     cairo_matrix_t ctm;	          /* user space => device space */
-    cairo_matrix_t scale;	  /* font space => device space */
     cairo_font_options_t options;
-
+    
+    /* "live" scaled_font members */
+    cairo_matrix_t scale;	  /* font space => device space */
+    cairo_font_extents_t extents; /* user space */
+    cairo_cache_t *glyphs;	  /* glyph index -> cairo_scaled_glyph_t */
+    
+    /*
+     * One surface backend may store data in each glyph.
+     * Whichever surface manages to store its pointer here
+     * first gets to store data in each glyph
+     */
+    const cairo_surface_backend_t *surface_backend;
+    void *surface_private;
+    
+    /* font backend managing this scaled font */
     const cairo_scaled_font_backend_t *backend;
 };
 
@@ -492,40 +428,6 @@
     const cairo_font_face_backend_t *backend;
 };
 
-/* cairo_font.c is responsible for a global glyph cache: 
- *  
- *   - glyph entries: [[[base], cairo_unscaled_font_t, scale, flags, index],
- *                     image, size, extents]
- *
- * Surfaces may build their own glyph caches if they have surface-specific
- * glyph resources to maintain; those caches can feed off of the global
- * caches if need be (eg. cairo_xlib_surface.c does this).
- */
-
-typedef struct {
-    cairo_cache_entry_base_t base;
-    cairo_unscaled_font_t *unscaled;
-    cairo_matrix_t scale;	/* translation is ignored */
-    int flags;
-    unsigned long index;
-} cairo_glyph_cache_key_t;
-
-typedef struct {
-    cairo_glyph_cache_key_t key;
-    cairo_image_surface_t *image;
-    cairo_glyph_size_t size;    
-    cairo_text_extents_t extents;
-} cairo_image_glyph_cache_entry_t;
-
-cairo_private void
-_cairo_lock_global_image_glyph_cache (void);
-
-cairo_private void
-_cairo_unlock_global_image_glyph_cache (void);
-
-cairo_private cairo_cache_t *
-_cairo_get_global_image_glyph_cache (void);
-
 cairo_private void
 _cairo_font_reset_static_data (void);
 
@@ -538,22 +440,10 @@
 cairo_private void
 _cairo_xlib_screen_reset_static_data (void);
 
-/* Some glyph cache functions you can reuse. */
-
-cairo_private unsigned long
-_cairo_glyph_cache_hash (void *cache, void *key);
-
-cairo_private int
-_cairo_glyph_cache_keys_equal (void *cache,
-			       void *k1,
-			       void *k2);
-
 /* the font backend interface */
 
 struct _cairo_unscaled_font_backend {
     void (*destroy)     	    (void		             *unscaled_font);
-    cairo_status_t (*create_glyph)  (void		             *unscaled_font,
-				     cairo_image_glyph_cache_entry_t *entry);
 };
 
 /* cairo_toy_font_face_t - simple family/slant/weight font faces used for
@@ -568,6 +458,12 @@
     cairo_font_weight_t weight;
 } cairo_toy_font_face_t;
 
+typedef enum _cairo_scaled_glyph_info {
+    CAIRO_SCALED_GLYPH_INFO_METRICS	= (1 << 0),
+    CAIRO_SCALED_GLYPH_INFO_SURFACE	= (1 << 1),
+    CAIRO_SCALED_GLYPH_INFO_PATH	= (1 << 2)
+} cairo_scaled_glyph_info_t;
+
 struct _cairo_scaled_font_backend {
     cairo_status_t
     (*create_toy)  (cairo_toy_font_face_t	*toy_face,
@@ -580,28 +476,14 @@
     (*fini)		(void			*scaled_font);
 
     cairo_status_t
-    (*font_extents)	(void			*scaled_font,
-			 cairo_font_extents_t	*extents);
-
-    cairo_status_t
-    (*text_to_glyphs)	(void			*scaled_font,
-			 const char		*utf8,
-			 cairo_glyph_t	       **glyphs, 
-			 int			*num_glyphs);
-
-    cairo_status_t
-    (*glyph_extents)	(void			*scaled_font,
-			 cairo_glyph_t		*glyphs, 
-			 int			 num_glyphs,
-			 cairo_text_extents_t	*extents);
-
-    cairo_status_t
-    (*glyph_bbox)	(void			*scaled_font,
-			 const cairo_glyph_t	*glyphs,
-			 int			 num_glyphs,
-			 cairo_box_t		*bbox);
+    (*scaled_glyph_init)	(void			     *scaled_font,
+				 cairo_scaled_glyph_t	     *scaled_glyph,
+				 cairo_scaled_glyph_info_t    info);
 
-    cairo_status_t
+    unsigned long
+    (*ucs4_to_index)		(void			     *scaled_font,
+				 uint32_t		      ucs4);
+    cairo_int_status_t
     (*show_glyphs)	(void			*scaled_font,
 			 cairo_operator_t	 operator,
 			 cairo_pattern_t	*pattern,
@@ -615,15 +497,6 @@
 			 const cairo_glyph_t	*glyphs,
 			 int			 num_glyphs);
   
-    cairo_status_t
-    (*glyph_path)	(void			*scaled_font,
-			 cairo_glyph_t		*glyphs, 
-			 int			 num_glyphs,
-			 cairo_path_fixed_t	*path);
-
-    void
-    (*get_glyph_cache_key) (void		*scaled_font,
-			    cairo_glyph_cache_key_t     *key);
 };
 
 struct _cairo_font_face_backend {
@@ -660,7 +533,7 @@
 
 #endif
 
-typedef struct _cairo_surface_backend {
+struct _cairo_surface_backend {
     cairo_surface_t *
     (*create_similar)		(void			*surface,
 				 cairo_content_t	 content,
@@ -796,8 +669,8 @@
 
     /* 
      * This is an optional entry to let the surface manage its own glyph
-     * resources. If null, the font will be asked to render against this
-     * surface, using image surfaces as glyphs. 
+     * resources. If null, render against this surface, using image
+     * surfaces as glyphs. 
      */    
     cairo_int_status_t 
     (*show_glyphs)		(cairo_scaled_font_t	        *font,
@@ -835,7 +708,13 @@
 				 int                    width,
 				 int                    height);
 
-} cairo_surface_backend_t;
+    void
+    (*scaled_font_fini)		(cairo_scaled_font_t   *scaled_font);
+
+    void
+    (*scaled_glyph_fini)	(cairo_scaled_glyph_t	*scaled_glyph,
+				 cairo_scaled_font_t	*scaled_font);
+};
 
 typedef struct _cairo_format_masks {
     int bpp;
@@ -1384,63 +1263,6 @@
 cairo_private void
 _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
 
-cairo_private void
-_cairo_scaled_font_init (cairo_scaled_font_t 	           *scaled_font, 
-			 cairo_font_face_t		   *font_face,
-			 const cairo_matrix_t              *font_matrix,
-			 const cairo_matrix_t              *ctm,
-			 const cairo_font_options_t        *options,
-			 const cairo_scaled_font_backend_t *backend);
-
-void
-_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font);
-
-cairo_private cairo_status_t
-_cairo_scaled_font_font_extents (cairo_scaled_font_t  *scaled_font, 
-				 cairo_font_extents_t *extents);
-
-cairo_private cairo_status_t
-_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t	*scaled_font,
-				   const char           *utf8, 
-				   cairo_glyph_t       **glyphs, 
-				   int 		        *num_glyphs);
-
-cairo_private cairo_status_t
-_cairo_scaled_font_glyph_extents (cairo_scaled_font_t	*scaled_font,
-				  cairo_glyph_t 	*glyphs,
-				  int 			num_glyphs,
-				  cairo_text_extents_t *extents);
-
-cairo_private cairo_status_t
-_cairo_scaled_font_glyph_bbox (cairo_scaled_font_t   *scaled_font,
-			       cairo_glyph_t         *glyphs,
-			       int                    num_glyphs,
-			       cairo_box_t	     *bbox);
-
-cairo_private cairo_status_t
-_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
-				cairo_operator_t     operator,
-				cairo_pattern_t	    *source,
-				cairo_surface_t	    *surface,
-				int		     source_x,
-				int		     source_y,
-				int		     dest_x,
-				int		     dest_y,
-				unsigned int	     width,
-				unsigned int	     height,
-				cairo_glyph_t	    *glyphs,
-				int		     num_glyphs);
-
-cairo_private cairo_status_t
-_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
-			       cairo_glyph_t       *glyphs, 
-			       int                  num_glyphs,
-			       cairo_path_fixed_t  *path);
-
-cairo_private cairo_status_t
-_cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t     *scaled_font,
-					cairo_glyph_cache_key_t *key);
-
 /* cairo-font-options.c */
 
 cairo_private void
@@ -1458,9 +1280,15 @@
 _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
 			     cairo_path_fixed_t *other);
 
+cairo_path_fixed_t *
+_cairo_path_fixed_create (void);
+
 cairo_private void
 _cairo_path_fixed_fini (cairo_path_fixed_t *path);
 
+void
+_cairo_path_fixed_destroy (cairo_path_fixed_t *path);
+
 cairo_private cairo_status_t
 _cairo_path_fixed_move_to (cairo_path_fixed_t  *path,
 			   cairo_fixed_t	x,
@@ -1545,6 +1373,91 @@
 				   cairo_gstate_t     *gstate,
 				   cairo_traps_t      *traps);
 
+/* cairo-scaled-font.c */
+
+cairo_private cairo_status_t
+_cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font, 
+			 cairo_font_face_t		   *font_face,
+			 const cairo_matrix_t              *font_matrix,
+			 const cairo_matrix_t              *ctm,
+			 const cairo_font_options_t	   *options,
+			 const cairo_scaled_font_backend_t *backend);
+
+cairo_private void
+_cairo_scaled_font_set_metrics (cairo_scaled_font_t	    *scaled_font,
+				cairo_font_extents_t	    *fs_metrics);
+
+cairo_private void
+_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+
+cairo_private cairo_status_t
+_cairo_scaled_font_font_extents (cairo_scaled_font_t  *scaled_font, 
+				 cairo_font_extents_t *extents);
+
+cairo_private cairo_status_t
+_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t	*scaled_font,
+				   double		x,
+				   double		y,
+				   const char           *utf8, 
+				   cairo_glyph_t       **glyphs, 
+				   int 		        *num_glyphs);
+
+cairo_private cairo_status_t
+_cairo_scaled_font_glyph_extents (cairo_scaled_font_t	*scaled_font,
+				  cairo_glyph_t 	*glyphs,
+				  int 			num_glyphs,
+				  cairo_text_extents_t *extents);
+
+cairo_private cairo_status_t
+_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	*scaled_font,
+					 const cairo_glyph_t	*glyphs,
+					 int                     num_glyphs,
+					 cairo_rectangle_t	*extents);
+
+cairo_private cairo_status_t
+_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
+				cairo_operator_t     operator,
+				cairo_pattern_t	    *source,
+				cairo_surface_t	    *surface,
+				int		     source_x,
+				int		     source_y,
+				int		     dest_x,
+				int		     dest_y,
+				unsigned int	     width,
+				unsigned int	     height,
+				cairo_glyph_t	    *glyphs,
+				int		     num_glyphs);
+
+cairo_private cairo_status_t
+_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
+			       cairo_glyph_t       *glyphs, 
+			       int                  num_glyphs,
+			       cairo_path_fixed_t  *path);
+
+cairo_private void
+_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
+				 cairo_scaled_font_t *scaled_font,
+				 cairo_text_extents_t *fs_metrics);
+
+cairo_private void
+_cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
+				 cairo_scaled_font_t *scaled_font,
+				 cairo_image_surface_t *surface);
+
+cairo_private void
+_cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
+			      cairo_scaled_font_t *scaled_font,
+			      cairo_path_fixed_t *path);
+
+cairo_status_t
+_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
+			    unsigned long index,
+			    cairo_scaled_glyph_info_t info,
+			    cairo_scaled_glyph_t **scaled_glyph_ret);
+
+cairo_private void
+_cairo_scaled_font_map_destroy (void);
+
 /* cairo-surface.c */
 
 extern const cairo_private cairo_surface_t _cairo_surface_nil;



More information about the cairo-commit mailing list