[cairo-commit] 3 commits - src/cairoint.h src/cairo-matrix.c src/cairo-scaled-font.c src/cairo-scaled-font-private.h src/cairo-user-font.c

Behdad Esfahbod behdad at kemper.freedesktop.org
Sat May 24 22:08:22 PDT 2008


 src/cairo-matrix.c              |    6 +-
 src/cairo-scaled-font-private.h |    2 
 src/cairo-scaled-font.c         |  117 ++++++++++++++++++++++++++++++++++++++--
 src/cairo-user-font.c           |   21 ++++---
 src/cairoint.h                  |    5 +
 5 files changed, 135 insertions(+), 16 deletions(-)

New commits:
commit 0621f412ff7986bc883a613d332f121da62e38fe
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun May 25 00:55:36 2008 -0400

    [cairo-matrix] Move IS_FINITE(det) checks before det==0 checks
    
    I'm still getting floating point exceptions in test suite in a
    made-to-overflow test though.  Not sure why isfinite() doesn't work.

diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index b743273..b704cde 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -490,10 +490,10 @@ cairo_matrix_invert (cairo_matrix_t *matrix)
 
     _cairo_matrix_compute_determinant (matrix, &det);
 
-    if (det == 0)
+    if (! ISFINITE (det))
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
-    if (! ISFINITE (det))
+    if (det == 0)
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
     _cairo_matrix_compute_adjoint (matrix);
@@ -510,7 +510,7 @@ _cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
 
     _cairo_matrix_compute_determinant (matrix, &det);
 
-    return det != 0. && ISFINITE (det);
+    return ISFINITE (det) && det != 0.;
 }
 
 void
commit 9827dae57085f9452889499ff799c378abd5c60e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun May 25 00:17:43 2008 -0400

    [user-font] Fix fontmap locking
    
    After consulting with Keith Packard we came up with a farily simple
    solution.  Documented in the code.

diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index 86fbec6..6571d06 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -89,6 +89,8 @@ struct _cairo_scaled_font {
     cairo_matrix_t ctm;	          /* user space => device space */
     cairo_font_options_t options;
 
+    cairo_bool_t created; /*  protected by fontmap mutex */
+
     cairo_bool_t finished;
 
     /* "live" scaled_font members */
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 01bf169..6521fe8 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -192,6 +192,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
       CAIRO_SUBPIXEL_ORDER_DEFAULT,
       CAIRO_HINT_STYLE_DEFAULT,
       CAIRO_HINT_METRICS_DEFAULT} ,
+    TRUE,			/* created */
     TRUE,			/* finished */
     { 1., 0., 0., 1., 0, 0},	/* scale */
     { 1., 0., 0., 1., 0, 0},	/* scale_inverse */
@@ -386,6 +387,96 @@ _cairo_scaled_font_map_destroy (void)
     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 }
 
+
+/* If a scaled font wants to unlock the font map while still being
+ * created (needed for user-fonts), we need to take extra care not
+ * ending up with multiple identical scaled fonts being created.
+ *
+ * What we do is, we create a dummy identical scaled font, also marked
+ * as being created, lock its mutex, and insert that in the fontmap
+ * hash table.  This makes other code trying to create an identical
+ * scaled font to just wait and retry.
+ *
+ * The reason we have to create a new key instead of just using
+ * scaled_font is for lifecycle management: we need to (or rather,
+ * other code needs to) reference the key.  We can't do that on the
+ * input scaled_font as it may be freed by font backend upon error.
+ */
+
+void
+_cairo_scaled_font_unlock_font_map (cairo_scaled_font_t *scaled_font)
+{
+    if (!scaled_font->created) {
+        cairo_status_t status = CAIRO_STATUS_SUCCESS;
+	cairo_scaled_font_t *key;
+
+	key = malloc (sizeof (cairo_scaled_font_t));
+	if (!key) {
+	    status = CAIRO_STATUS_NO_MEMORY;
+	    goto FREE;
+	}
+
+	/* full initialization is wasteful, but who cares... */
+	status = _cairo_scaled_font_init (key,
+					  scaled_font->font_face,
+					  &scaled_font->font_matrix,
+					  &scaled_font->ctm,
+					  &scaled_font->options,
+					  NULL);
+	if (status)
+	    goto FINI;
+
+	CAIRO_MUTEX_LOCK (key->mutex);
+
+	status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
+					   &key->hash_entry);
+	if (status)
+	    goto UNLOCK_KEY;
+
+	goto UNLOCK;
+
+       UNLOCK_KEY:
+	CAIRO_MUTEX_UNLOCK (key->mutex);
+
+       FINI:
+	_cairo_scaled_font_fini (key);
+
+       FREE:
+	free (key);
+
+	status = _cairo_scaled_font_set_error (scaled_font, status);
+    }
+
+ UNLOCK:
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+}
+
+void
+_cairo_scaled_font_lock_font_map (cairo_scaled_font_t *scaled_font)
+{
+    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+
+    if (!scaled_font->created) {
+	cairo_scaled_font_t *key;
+	cairo_bool_t found;
+
+	found = _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
+					  &scaled_font->hash_entry,
+					  (cairo_hash_entry_t**) &key);
+	assert (found);
+
+	_cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
+				  &scaled_font->hash_entry);
+
+	CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+
+	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+	cairo_scaled_font_destroy (key);
+	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+    }
+}
+
+
 /* 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
@@ -418,6 +509,7 @@ _cairo_scaled_font_init_key (cairo_scaled_font_t        *scaled_font,
     uint32_t hash = FNV1_32_INIT;
 
     scaled_font->status = CAIRO_STATUS_SUCCESS;
+    scaled_font->created = FALSE;
     scaled_font->font_face = font_face;
     scaled_font->font_matrix = *font_matrix;
     scaled_font->ctm = *ctm;
@@ -601,7 +693,7 @@ _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
 	scaled_font->surface_backend->scaled_font_fini != NULL)
 	scaled_font->surface_backend->scaled_font_fini (scaled_font);
 
-    if (scaled_font->backend->fini != NULL)
+    if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
 	scaled_font->backend->fini (scaled_font);
 
     _cairo_user_data_array_fini (&scaled_font->user_data);
@@ -655,9 +747,25 @@ cairo_scaled_font_create (cairo_font_face_t          *font_face,
     _cairo_scaled_font_init_key (&key, font_face,
 				 font_matrix, ctm, options);
 
+
+    while (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
+				     (cairo_hash_entry_t**) &scaled_font))
+    {
+	if (scaled_font->created)
+	    break;
+
+	/* If the scaled font is being created (happens for user-font),
+	 * just wait until it's done, then retry */
+	cairo_scaled_font_reference (scaled_font);
+	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+	CAIRO_MUTEX_LOCK (scaled_font->mutex);
+	CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+	cairo_scaled_font_destroy (scaled_font);
+    }
+
     /* 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))
+    if (scaled_font)
     {
 	/* If the original reference count is 0, then this font must have
 	 * been found in font_map->holdovers, (which means this caching is
@@ -704,6 +812,7 @@ cairo_scaled_font_create (cairo_font_face_t          *font_face,
 	return _cairo_scaled_font_create_in_error (status);
     }
 
+    scaled_font->created = TRUE;
     status = _cairo_hash_table_insert (font_map->hash_table,
 				       &scaled_font->hash_entry);
     _cairo_scaled_font_map_unlock ();
@@ -828,7 +937,7 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
 	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
 	font_map = cairo_scaled_font_map;
 
-	if (font_map && scaled_font->hash_entry.hash != ZOMBIE) {
+	if (scaled_font->created && font_map && scaled_font->hash_entry.hash != ZOMBIE) {
 	    /* Rather than immediately destroying this object, we put it into
 	     * the font_map->holdovers array in case it will get used again
 	     * soon (and is why we must hold the lock over the atomic op on
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index b33bf12..e9b1d7c 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -327,21 +327,19 @@ _cairo_user_font_face_scaled_font_create (void                        *abstract_
     }
 
     if (font_face->scaled_font_methods.init != NULL) {
-	/* XXX by releasing fontmap lock here, we open up the case for having
-	 * two scaled fonts with the same key to be inserted in the fontmap.
-	 *
-	 * To fix that, we should make _cairo_scaled_font_init() insert
-	 * scaled_font in the fontmap, then lock the scaled_font lock here and
-	 * release the fontmap's.
-	 */
+
 	/* Lock the scaled_font mutex such that user doesn't accidentally try
-	 * to use it just yet.
-	 */
+         * to use it just yet. */
 	CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex);
-	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+
+	/* Give away fontmap lock such that user-font can use other fonts */
+	_cairo_scaled_font_unlock_font_map (&user_scaled_font->base);
+
 	status = font_face->scaled_font_methods.init (&user_scaled_font->base,
 						      &font_extents);
-	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+
+	_cairo_scaled_font_lock_font_map (&user_scaled_font->base);
+
 	CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex);
     }
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 54cd0d8..cc97cb2 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1471,6 +1471,11 @@ _cairo_scaled_font_create_in_error (cairo_status_t status);
 cairo_private void
 _cairo_scaled_font_reset_static_data (void);
 
+cairo_private void
+_cairo_scaled_font_unlock_font_map (cairo_scaled_font_t *scaled_font);
+
+cairo_private void
+_cairo_scaled_font_lock_font_map (cairo_scaled_font_t *scaled_font);
 
 cairo_private cairo_status_t
 _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
commit 96f7178226640226625c0e4db57257035e0b48c6
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 23:28:15 2008 -0400

    [user-font] Lock the font mutex such that user doesn't accidentally use it yet

diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index e1928df..b33bf12 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -334,10 +334,15 @@ _cairo_user_font_face_scaled_font_create (void                        *abstract_
 	 * scaled_font in the fontmap, then lock the scaled_font lock here and
 	 * release the fontmap's.
 	 */
+	/* Lock the scaled_font mutex such that user doesn't accidentally try
+	 * to use it just yet.
+	 */
+	CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex);
 	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 	status = font_face->scaled_font_methods.init (&user_scaled_font->base,
 						      &font_extents);
 	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+	CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex);
     }
 
     if (status == CAIRO_STATUS_SUCCESS)


More information about the cairo-commit mailing list