[cairo-commit] cairo/src cairo-ft-font.c, 1.97, 1.98 cairoint.h, 1.191, 1.192

Carl Worth commit at pdx.freedesktop.org
Thu Aug 11 14:49:15 PDT 2005


Committed by: cworth

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

Modified Files:
	cairo-ft-font.c cairoint.h 
Log Message:

2005-08-11  Carl Worth  <cworth at cworth.org>

        * src/cairo-ft-font.c: (_cairo_ft_unscaled_font_init),
        (_cairo_ft_unscaled_font_init_key),
        (_cairo_ft_unscaled_font_keys_equal),
        (_cairo_ft_unscaled_font_fini),
        (_cairo_ft_unscaled_font_map_destroy),
        (_cairo_ft_unscaled_font_map_lock),
        (_cairo_ft_unscaled_font_map_unlock),
        (_cairo_ft_unscaled_font_map_create),
        (_cairo_ft_unscaled_font_create_for_pattern), (_has_unlocked_face),
        (_cairo_ft_unscaled_font_lock_face),
        (_cairo_ft_unscaled_font_destroy),
        (_cairo_ft_scaled_font_create_toy),
        (cairo_ft_font_face_create_for_pattern),
        (_cairo_ft_font_reset_static_data):
        Move implementation of filename/id => cairo_ft_unscaled_font_t
        from cairo-cache.c to cairo-hash.c, with new
        cairo_ft_unscaled_font_map.

        * src/cairoint.h: Add cairo_unscaled_font->hash_entry so that
        unscaled fonts can live in hash tables.


Index: cairo-ft-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ft-font.c,v
retrieving revision 1.97
retrieving revision 1.98
diff -u -d -r1.97 -r1.98
--- cairo-ft-font.c	11 Aug 2005 13:35:21 -0000	1.97
+++ cairo-ft-font.c	11 Aug 2005 21:49:07 -0000	1.98
@@ -112,6 +112,18 @@
     cairo_ft_font_face_t *faces;	/* Linked list of faces for this font */
 };
 
+static int
+_cairo_ft_unscaled_font_keys_equal (void *key_a,
+				    void *key_b);
+
+static void
+_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
+				  char			   *filename,
+				  int			    id);
+
+static void
+_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled);
+
 struct _cairo_ft_font_face {
     cairo_font_face_t base;
     cairo_ft_unscaled_font_t *unscaled;
@@ -163,8 +175,7 @@
 	    return CAIRO_STATUS_NO_MEMORY;
     }
 
-    unscaled->filename = filename_copy;
-    unscaled->id = id;
+    _cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id);
 
     if (face) {
 	unscaled->from_face = 1;
@@ -210,223 +221,238 @@
     return unscaled_font->backend == &cairo_ft_unscaled_font_backend;
 }
 
-static cairo_ft_unscaled_font_t *
-_cairo_ft_unscaled_font_create_from_filename (const char *filename,
-					      int         id)
-{
-    cairo_status_t status;
-    cairo_ft_unscaled_font_t *unscaled;
-    
-    unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
-    if (unscaled == NULL)
-	return NULL;
-
-    status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL);
-    if (status) {
-	free (unscaled);
-	return NULL;
-    }
-
-    return unscaled;
-}
-
 /*
- * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This
- * hash isn't limited in size. However, we limit the number of
- * FT_Face objects we keep around; when we've exceeeded that
- * limit and need to create a new FT_Face, we dump the FT_Face from
- * a random ft_unscaled_font_t.
+ * We maintain a hash table to map file/id => cairo_ft_unscaled_font_t.
+ * The hash table itself isn't limited in size. However, we limit the
+ * number of FT_Face objects we keep around; when we've exceeeded that
+ * limit and need to create a new FT_Face, we dump the FT_Face from a
+ * random cairo_ft_unscaled_font_t which has an unlocked FT_Face, (if
+ * there are any).
  */
 
-typedef struct {
-    cairo_cache_entry_base_t base;
-    char *filename;
-    int id;
-} cairo_ft_cache_key_t;
-
-typedef struct {
-    cairo_ft_cache_key_t key;
-    cairo_ft_unscaled_font_t *unscaled;
-} cairo_ft_cache_entry_t;
-
-typedef struct {
-    cairo_cache_t base;
-    FT_Library lib;
-    int n_faces;		/* Number of open FT_Face objects */
-} ft_cache_t;
-
-static unsigned long
-_cairo_ft_font_cache_hash (void *cache, void *key)
+static void
+_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
+				  char			   *filename,
+				  int			    id)
 {
-    cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key;
     unsigned long hash;
 
-    /* 1607 is just a random prime. */
-    hash = _cairo_hash_string (in->filename);
-    hash += ((unsigned long) in->id) * 1607;
+    key->filename = filename;
+    key->id = id;
+
+    /* 1607 is just an arbitrary prime. */
+    hash = _cairo_hash_string (filename);
+    hash += ((unsigned long) id) * 1607;
 	
-    return hash;
+    key->base.hash_entry.hash = hash;
 }
 
 static int
-_cairo_ft_font_cache_keys_equal (void *cache,
-				 void *k1,
-				 void *k2)
+_cairo_ft_unscaled_font_keys_equal (void *key_a,
+				    void *key_b)
 {
-    cairo_ft_cache_key_t *a;
-    cairo_ft_cache_key_t *b;
-    a = (cairo_ft_cache_key_t *) k1;
-    b = (cairo_ft_cache_key_t *) k2;
+    cairo_ft_unscaled_font_t *unscaled_a = key_a;
+    cairo_ft_unscaled_font_t *unscaled_b = key_b;
 
-    return strcmp (a->filename, b->filename) == 0 &&
-	a->id == b->id;
+    return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 &&
+	    unscaled_a->id == unscaled_b->id);
 }
 
-static cairo_status_t
-_cairo_ft_font_cache_create_entry (void *cache,
-				   void *key,
-				   void **return_entry)
+static void
+_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled)
 {
-    cairo_ft_cache_key_t *k = key;
-    cairo_ft_cache_entry_t *entry;
-
-    entry = malloc (sizeof (cairo_ft_cache_entry_t));
-    if (entry == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
-
-    entry->unscaled = _cairo_ft_unscaled_font_create_from_filename (k->filename,
-								    k->id);
-    if (!entry->unscaled) {
-	free (entry);
-	return CAIRO_STATUS_NO_MEMORY;
+    if (unscaled->filename) {
+	free (unscaled->filename);
+	unscaled->filename = NULL;
     }
-    
-    entry->key.base.memory = 0;
-    entry->key.filename = entry->unscaled->filename;
-    entry->key.id = entry->unscaled->id;
-    
-    *return_entry = entry;
 
-    return CAIRO_STATUS_SUCCESS;
+    if (unscaled->face) {
+	FT_Done_Face (unscaled->face);
+	unscaled->face = NULL;
+    }
 }
 
-/* Entries are never spontaneously destroyed; but only when
- * we remove them from the cache specifically. We free entry->unscaled
- * in the code that removes the entry from the cache
- */
-static void
-_cairo_ft_font_cache_destroy_entry (void *cache,
-				    void *entry)
-{    
-    cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry;
+typedef struct _cairo_ft_unscaled_font_map {
+    cairo_hash_table_t *hash_table;
+    FT_Library ft_library;
+    int num_open_faces;
+} cairo_ft_unscaled_font_map_t;
 
-    free (e);
-}
+static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL;
 
-static void 
-_cairo_ft_font_cache_destroy_cache (void *cache)
+CAIRO_MUTEX_DECLARE(cairo_ft_unscaled_font_map_mutex);
+
+static void
+_cairo_ft_unscaled_font_map_destroy (void)
 {
-    ft_cache_t *fc = (ft_cache_t *) cache;
+    cairo_ft_unscaled_font_t *unscaled;
+    cairo_ft_unscaled_font_map_t *font_map;
 
-    FT_Done_FreeType (fc->lib);
-    free (fc);
-}
+    CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex);
 
-static const cairo_cache_backend_t _ft_font_cache_backend = {
-    _cairo_ft_font_cache_hash,
-    _cairo_ft_font_cache_keys_equal,
-    _cairo_ft_font_cache_create_entry,
-    _cairo_ft_font_cache_destroy_entry,
-    _cairo_ft_font_cache_destroy_cache
-};
+    if (cairo_ft_unscaled_font_map) {
+	font_map = cairo_ft_unscaled_font_map;
 
-static ft_cache_t *_global_ft_cache = NULL;
+	/* This is rather inefficient, but destroying the hash table
+	 * is something we only do during debugging, (during
+	 * cairo_debug_reset_static_data), when efficiency is not
+	 * relevant. */
+        while (1) {
+	    unscaled = _cairo_hash_table_random_entry (font_map->hash_table,
+						       NULL);
+	    if (unscaled == NULL)
+		break;
+	    _cairo_hash_table_remove (font_map->hash_table,
+				      &unscaled->base.hash_entry);
+	    _cairo_ft_unscaled_font_fini (unscaled);
+	    free (unscaled);
+	}
 
-CAIRO_MUTEX_DECLARE(_global_ft_cache_mutex);
+	FT_Done_FreeType (font_map->ft_library);
+
+	_cairo_hash_table_destroy (font_map->hash_table);
+
+	free (font_map);
+
+	cairo_ft_unscaled_font_map = NULL;
+    }
+
+    CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex);
+}
 
 static void
-_lock_global_ft_cache (void)
+_cairo_ft_unscaled_font_map_create (void);
+
+static cairo_ft_unscaled_font_map_t *
+_cairo_ft_unscaled_font_map_lock (void)
 {
-    CAIRO_MUTEX_LOCK(_global_ft_cache_mutex);
+    CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex);
+
+    if (cairo_ft_unscaled_font_map == NULL)
+    {
+	_cairo_ft_unscaled_font_map_create ();
+
+	if (cairo_ft_unscaled_font_map == NULL) {
+	    CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex);
+	    return NULL;
+	}
+    }
+
+    return cairo_ft_unscaled_font_map;
 }
 
 static void
-_unlock_global_ft_cache (void)
+_cairo_ft_unscaled_font_map_unlock (void)
 {
-    CAIRO_MUTEX_UNLOCK(_global_ft_cache_mutex);
+    CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex);
 }
 
-static cairo_cache_t *
-_get_global_ft_cache (void)
+static void
+_cairo_ft_unscaled_font_map_create (void)
 {
-    if (_global_ft_cache == NULL)
-    {
-	_global_ft_cache = malloc (sizeof(ft_cache_t));	
-	if (!_global_ft_cache)
-	    goto FAIL;
+    cairo_ft_unscaled_font_map_t *font_map;
 
-	if (_cairo_cache_init (&_global_ft_cache->base,
-			       &_ft_font_cache_backend,
-			       0)) /* No memory limit */
-	    goto FAIL;
-	
-	if (FT_Init_FreeType (&_global_ft_cache->lib)) 
-	    goto FAIL;
-	_global_ft_cache->n_faces = 0;
-    }
-    return &_global_ft_cache->base;
+    /* This function is only intended to be called from
+     * _cairo_ft_unscaled_font_map_lock. So we'll crash if we can
+     * detect some other call path. */
+    assert (cairo_ft_unscaled_font_map == NULL);
 
- FAIL:
-    if (_global_ft_cache)
-	free (_global_ft_cache);
-    _global_ft_cache = NULL;
-    return NULL;
+    font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t));
+    if (font_map == NULL)
+	goto FAIL;
+
+    font_map->hash_table =
+	_cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal);
+
+    if (font_map->hash_table == NULL)
+	goto FAIL;
+
+    if (FT_Init_FreeType (&font_map->ft_library))
+	goto FAIL;
+
+    font_map->num_open_faces = 0;
+
+    cairo_ft_unscaled_font_map = font_map;
+    return;
+
+FAIL:
+    if (font_map) {
+	if (font_map->hash_table)
+	    _cairo_hash_table_destroy (font_map->hash_table);
+	free (font_map);
+    }
+    cairo_ft_unscaled_font_map = NULL;
 }
 
-/* Finds or creates a ft_unscaled_font for the filename/id from pattern.
- * Returns a new reference to the unscaled font.
+/* Finds or creates a cairo_ft_unscaled_font for the filename/id from
+ * pattern.  Returns a new reference to the unscaled font.
  */
 static cairo_ft_unscaled_font_t *
-_cairo_ft_unscaled_font_get_for_pattern (FcPattern *pattern)
+_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
 {
-    cairo_ft_cache_entry_t *entry;
-    cairo_ft_cache_key_t key;
-    cairo_cache_t *cache;
+    cairo_ft_unscaled_font_t key, *unscaled;
+    cairo_ft_unscaled_font_map_t *font_map;
     cairo_status_t status;
-    FcChar8 *filename;
-    int created_entry;
+    FcChar8 *fc_filename;
+    char *filename;
+    int id;
     
-    if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch)
-	return NULL;
-    key.filename = (char *)filename;
-	    
-    if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
-	return NULL;
+    if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch)
+	goto UNWIND;
+    filename = (char *) fc_filename;
+
+    if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
+	goto UNWIND;
     
-    _lock_global_ft_cache ();
-    cache = _get_global_ft_cache ();
-    if (cache == NULL) {
-	_unlock_global_ft_cache ();
-	return NULL;
+    font_map = _cairo_ft_unscaled_font_map_lock ();
+    if (font_map == NULL)
+	goto UNWIND;
+
+    _cairo_ft_unscaled_font_init_key (&key, filename, id);
+
+    /* Return exsiting unscaled font if it exists in the hash table. */
+    if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry,
+				  (cairo_hash_entry_t **) &unscaled))
+    {
+	_cairo_ft_unscaled_font_map_unlock ();
+	_cairo_unscaled_font_reference (&unscaled->base);
+	return unscaled;
     }
 
-    status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
-    if (status == CAIRO_STATUS_SUCCESS && !created_entry)
-	_cairo_unscaled_font_reference (&entry->unscaled->base);
+    /* Otherwise create it and insert into hash table. */
+    unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
+    if (unscaled == NULL)
+	goto UNWIND_FONT_MAP_LOCK;
 
-    _unlock_global_ft_cache ();
+    status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL);
     if (status)
-	return NULL;
+	goto UNWIND_UNSCALED_MALLOC;
 
-    return entry->unscaled;
+    status = _cairo_hash_table_insert (font_map->hash_table,
+				       &unscaled->base.hash_entry);
+    if (status)
+	goto UNWIND_UNSCALED_FONT_INIT;
+
+    _cairo_ft_unscaled_font_map_unlock ();
+
+    return unscaled;
+
+UNWIND_UNSCALED_FONT_INIT:
+    _cairo_ft_unscaled_font_fini (unscaled);
+UNWIND_UNSCALED_MALLOC:
+    free (unscaled);
+UNWIND_FONT_MAP_LOCK:
+    _cairo_ft_unscaled_font_map_unlock ();
+UNWIND:    
+    return NULL;
 }
 
-static int
+static cairo_bool_t
 _has_unlocked_face (void *entry)
 {
-    cairo_ft_cache_entry_t *e = entry;
+    cairo_ft_unscaled_font_t *unscaled = entry;
 
-    return (e->unscaled->lock == 0 && e->unscaled->face);
+    return (unscaled->lock == 0 && unscaled->face);
 }
 
 /* Ensures that an unscaled font has a face object. If we exceed
@@ -438,7 +464,7 @@
 FT_Face
 _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
 {
-    ft_cache_t *ftcache;
+    cairo_ft_unscaled_font_map_t *font_map;
     FT_Face face = NULL;
 
     if (unscaled->face) {
@@ -446,27 +472,30 @@
 	return unscaled->face;
     }
 
+    /* If the unscaled font was created from an FT_Face then we just
+     * returned it above. */
     assert (!unscaled->from_face);
     
-    _lock_global_ft_cache ();
-    ftcache = (ft_cache_t *) _get_global_ft_cache ();
-    assert (ftcache != NULL);
+    font_map = _cairo_ft_unscaled_font_map_lock ();
+    assert (font_map != NULL);
     
-    while (ftcache->n_faces >= MAX_OPEN_FACES) {
-	cairo_ft_cache_entry_t *entry;
+    while (font_map->num_open_faces >= MAX_OPEN_FACES)
+    {
+	cairo_ft_unscaled_font_t *entry;
     
-	entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face);
-	if (entry) {
-	    FT_Done_Face (entry->unscaled->face);
-	    entry->unscaled->face = NULL;
-	    entry->unscaled->have_scale = 0;
-	    ftcache->n_faces--;
-	} else {
+	entry = _cairo_hash_table_random_entry (font_map->hash_table,
+						_has_unlocked_face);
+	if (entry == NULL)
 	    break;
-	}
+
+	FT_Done_Face (entry->face);
+	unscaled->face = NULL;
+	unscaled->have_scale = 0;
+
+	font_map->num_open_faces--;
     }
 
-    if (FT_New_Face (ftcache->lib,
+    if (FT_New_Face (font_map->ft_library,
 		     unscaled->filename,
 		     unscaled->id,
 		     &face) != FT_Err_Ok)
@@ -474,14 +503,16 @@
 
     unscaled->face = face;
     unscaled->lock++;
-    ftcache->n_faces++;
+
+    font_map->num_open_faces++;
 
  FAIL:
-    _unlock_global_ft_cache ();
+    _cairo_ft_unscaled_font_map_unlock ();
+
     return face;
 }
 
-/* Unlock unscaled font locked with _ft_unscaled_font_lock_face
+/* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face
  */
 void
 _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled)
@@ -620,25 +651,18 @@
 	if (unscaled->faces && !unscaled->faces->unscaled)
 	    cairo_font_face_destroy (&unscaled->faces->base);
     } else {
-	cairo_cache_t *cache;
-	cairo_ft_cache_key_t key;
+	cairo_ft_unscaled_font_map_t *font_map;
 	
-	_lock_global_ft_cache ();
-	cache = _get_global_ft_cache ();
-	assert (cache);
+	font_map = _cairo_ft_unscaled_font_map_lock ();
+	/* All created objects must have been mapped in the font map. */
+	assert (font_map != NULL);
 
-	key.filename = unscaled->filename;
-	key.id = unscaled->id;
-	
-	_cairo_cache_remove (cache, &key);
-	
-	_unlock_global_ft_cache ();
-	
-	if (unscaled->filename)
-	    free (unscaled->filename);
-	
-	if (unscaled->face)
-	    FT_Done_Face (unscaled->face);
+	_cairo_hash_table_remove (font_map->hash_table,
+				  &unscaled->base.hash_entry);
+
+	_cairo_ft_unscaled_font_map_unlock ();
+
+	_cairo_ft_unscaled_font_fini (unscaled);
     }
 }
 
@@ -1527,7 +1551,7 @@
     if (!resolved)
 	goto FREE_PATTERN;
 
-    unscaled = _cairo_ft_unscaled_font_get_for_pattern (resolved);
+    unscaled = _cairo_ft_unscaled_font_create_for_pattern (resolved);
     if (!unscaled)
 	goto FREE_RESOLVED;
 
@@ -2415,7 +2439,7 @@
     cairo_ft_unscaled_font_t *unscaled;
     cairo_font_face_t *font_face;
 
-    unscaled = _cairo_ft_unscaled_font_get_for_pattern (pattern);
+    unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern);
     if (unscaled == NULL) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_font_face_t *)&_cairo_font_face_nil;
@@ -2568,12 +2592,5 @@
 void
 _cairo_ft_font_reset_static_data (void)
 {
-    _lock_global_ft_cache ();
-    if (_global_ft_cache) {
-	FT_Done_FreeType (_global_ft_cache->lib);
-	_global_ft_cache->lib = NULL;
-    }
-    _cairo_cache_destroy (&_global_ft_cache->base);
-    _global_ft_cache = NULL;
-    _unlock_global_ft_cache ();
+    _cairo_ft_unscaled_font_map_destroy ();
 }

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.191
retrieving revision 1.192
diff -u -d -r1.191 -r1.192
--- cairoint.h	11 Aug 2005 13:35:21 -0000	1.191
+++ cairoint.h	11 Aug 2005 21:49:13 -0000	1.192
@@ -465,6 +465,7 @@
  * glyph cache.
  */
 typedef struct _cairo_unscaled_font {
+    cairo_hash_entry_t hash_entry;
     int ref_count;
     const cairo_unscaled_font_backend_t *backend;
 } cairo_unscaled_font_t;




More information about the cairo-commit mailing list