[cairo-commit] src/cairo-directfb-surface.c src/cairo-glitz-surface.c src/cairo-gstate.c src/cairoint.h src/cairo-meta-surface.c src/cairo-mutex-impl-private.h src/cairo-mutex-type-private.h src/cairo-paginated-surface.c src/cairo-pdf-surface.c src/cairo-scaled-font.c src/cairo-scaled-font-subsets.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-svg-surface.c src/cairo-type1-fallback.c src/cairo-type3-glyph-surface.c src/cairo-user-font.c src/cairo-win32-font.c src/cairo-xcb-surface.c src/cairo-xlib-surface.c src/test-meta-surface.c src/test-paginated-surface.c

Chris Wilson ickle at kemper.freedesktop.org
Tue Oct 21 16:54:04 PDT 2008


 src/cairo-directfb-surface.c    |    4 
 src/cairo-glitz-surface.c       |    2 
 src/cairo-gstate.c              |    4 
 src/cairo-meta-surface.c        |    2 
 src/cairo-mutex-impl-private.h  |    3 
 src/cairo-mutex-type-private.h  |    3 
 src/cairo-paginated-surface.c   |    2 
 src/cairo-pdf-surface.c         |    2 
 src/cairo-scaled-font-subsets.c |   30 ++---
 src/cairo-scaled-font.c         |   81 ++++++++++-----
 src/cairo-surface-fallback.c    |    1 
 src/cairo-surface.c             |    4 
 src/cairo-svg-surface.c         |    4 
 src/cairo-type1-fallback.c      |    9 +
 src/cairo-type3-glyph-surface.c |   18 +--
 src/cairo-user-font.c           |    1 
 src/cairo-win32-font.c          |   12 +-
 src/cairo-xcb-surface.c         |  216 +++++++++++++++++++++++-----------------
 src/cairo-xlib-surface.c        |   57 ++++++----
 src/cairoint.h                  |    4 
 src/test-meta-surface.c         |   25 ----
 src/test-paginated-surface.c    |   25 ----
 22 files changed, 280 insertions(+), 229 deletions(-)

New commits:
commit 1db8949f2baf1e620e1d5ef73a66de211420bd0a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Oct 21 22:48:17 2008 +0100

    Ensure that the scaled font is frozen for the lifetime of the scaled glyph.
    
    After discussing the scaled font locking with Behdad, it transpired that it
    is not sufficient for a font to be locked for the lifetime of a scaled glyph,
    but that the scaled font's glyph cache must be frozen for the glyph'
    lifetime.  If the cache is not frozen, then there is a possibility that the
    glyph may be evicted before the reference goes out of scope i.e. the glyph
    becomes invalid whilst we are trying to use it.
    
    Since the freezing of the cache is the stronger barrier, we remove the
    locking/unlocking of the mutex from the backends and instead move the
    mutex acquisition into the freeze/thaw routines. Then update the rule on
    acquiring glyphs to enforce that the cache is frozen and review the usage
    of freeze/thaw by all the backends to ensure that the cache is frozen for
    the lifetime of the glyph.

diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 662448e..aa67b02 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -1432,14 +1432,14 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t     *surface,
 
     D_DEBUG_AT (CairoDFB_Font, "%s( %p [%d] )\n", __FUNCTION__, glyphs, num_glyphs );
 
+    _cairo_cache_freeze (scaled_font->glyphs);
+
     if (scaled_font->surface_private) {
 	cache = scaled_font->surface_private;
 	x = cache->x;
 	y = cache->y;
     }
 
-    _cairo_cache_freeze (scaled_font->glyphs);
-
     for (i = 0; i < num_glyphs; i++) {
 	cairo_scaled_glyph_t  *scaled_glyph;
 	cairo_image_surface_t *img;
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 9a148bf..784bff9 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -2020,7 +2020,7 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface,
 
     if (glyph_surface->width  > GLYPH_CACHE_MAX_WIDTH ||
 	glyph_surface->height > GLYPH_CACHE_MAX_HEIGHT)
-	return CAIRO_STATUS_SUCCESS;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (scaled_font->surface_private == NULL)
     {
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index e9387f5..00f498e 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1615,11 +1615,9 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
 
 	_cairo_path_fixed_init (&path);
 
-	CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
 	status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
 						transformed_glyphs, num_glyphs,
 						&path);
-	CAIRO_MUTEX_UNLOCK (gstate->scaled_font->mutex);
 
 	if (status == CAIRO_STATUS_SUCCESS)
 	  status = _cairo_surface_fill (gstate->target,
@@ -1670,11 +1668,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
     if (status)
 	goto CLEANUP_GLYPHS;
 
-    CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
     status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
 					    transformed_glyphs, num_glyphs,
 					    path);
-    CAIRO_MUTEX_UNLOCK (gstate->scaled_font->mutex);
 
   CLEANUP_GLYPHS:
     if (transformed_glyphs != stack_transformed_glyphs)
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index f45bdb9..b86cb51 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -730,12 +730,10 @@ _cairo_meta_surface_get_path (cairo_surface_t	 *surface,
 	}
 	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
 	{
-	    CAIRO_MUTEX_LOCK (command->show_text_glyphs.scaled_font->mutex);
 	    status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
 						    command->show_text_glyphs.glyphs,
 						    command->show_text_glyphs.num_glyphs,
 						    path);
-	    CAIRO_MUTEX_UNLOCK (command->show_text_glyphs.scaled_font->mutex);
 	    break;
 	}
 
diff --git a/src/cairo-mutex-impl-private.h b/src/cairo-mutex-impl-private.h
index 3e19616..239dbbb 100644
--- a/src/cairo-mutex-impl-private.h
+++ b/src/cairo-mutex-impl-private.h
@@ -181,7 +181,8 @@
 # define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex))
 # define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
 #if HAVE_LOCKDEP
-# define CAIRO_MUTEX_IS_LOCKED(mutex) LOCKDEP_HOLDS_LOCK (&(mutex))
+# define CAIRO_MUTEX_IS_LOCKED(mutex) LOCKDEP_IS_LOCKED (&(mutex))
+# define CAIRO_MUTEX_IS_UNLOCKED(mutex) LOCKDEP_IS_UNLOCKED (&(mutex))
 #endif
 # define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex))
 #if ! HAVE_LOCKDEP
diff --git a/src/cairo-mutex-type-private.h b/src/cairo-mutex-type-private.h
index 040e99f..adf17bb 100644
--- a/src/cairo-mutex-type-private.h
+++ b/src/cairo-mutex-type-private.h
@@ -171,6 +171,9 @@ typedef cairo_mutex_impl_t cairo_mutex_t;
 #ifndef CAIRO_MUTEX_IS_LOCKED
 # define CAIRO_MUTEX_IS_LOCKED(name) 1
 #endif
+#ifndef CAIRO_MUTEX_IS_UNLOCKED
+# define CAIRO_MUTEX_IS_UNLOCKED(name) 1
+#endif
 
 
 /* Debugging support */
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 97a1f21..a94ca80 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -637,14 +637,12 @@ _cairo_paginated_surface_show_text_glyphs (void			    *abstract_surface,
      * show_glyphs functions, (which would get less testing and likely
      * lead to bugs).
      */
-    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
     status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
 					      utf8, utf8_len,
 					      glyphs, num_glyphs,
 					      clusters, num_clusters,
 					      cluster_flags,
 					      scaled_font);
-    CAIRO_MUTEX_LOCK (scaled_font->mutex);
 
     return status;
 }
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b07ee98..2823508 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -4050,14 +4050,12 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t     *surface,
 					      &group->ctm_inverse);
 	break;
     case PDF_SHOW_GLYPHS:
-	CAIRO_MUTEX_LOCK (group->scaled_font->mutex);
 	status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
 							group->utf8, group->utf8_len,
 							group->glyphs, group->num_glyphs,
 							group->clusters, group->num_clusters,
 							group->cluster_flags,
 							group->scaled_font);
-	CAIRO_MUTEX_UNLOCK (group->scaled_font->mutex);
 	break;
     }
     if (status)
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 3bf9073..f5212d7 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -445,12 +445,13 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
 {
     cairo_sub_font_glyph_t key, *sub_font_glyph;
     cairo_status_t status;
-    cairo_scaled_glyph_t *scaled_glyph;
 
     _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
     if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
 				    (cairo_hash_entry_t **) &sub_font_glyph))
     {
+	cairo_scaled_glyph_t *scaled_glyph;
+
 	if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
 	{
 	    cairo_scaled_font_subsets_glyph_t tmp_subset_glyph;
@@ -464,19 +465,24 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
 		return status;
 	}
 
+	_cairo_scaled_font_freeze_cache (sub_font->scaled_font);
         status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
                                              scaled_font_glyph_index,
                                              CAIRO_SCALED_GLYPH_INFO_METRICS,
                                              &scaled_glyph);
 	assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
-	if (status)
+	if (status) {
+	    _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
 	    return status;
+	}
 
         sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
 						       sub_font->current_subset,
 						       sub_font->num_glyphs_in_current_subset,
                                                        scaled_glyph->metrics.x_advance,
                                                        scaled_glyph->metrics.y_advance);
+	_cairo_scaled_font_thaw_cache (sub_font->scaled_font);
+
 	if (sub_font_glyph == NULL)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -702,10 +708,12 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
     if (scaled_font_glyph_index == 0) {
 	status = CAIRO_STATUS_SUCCESS;
     } else {
+	_cairo_scaled_font_freeze_cache (scaled_font);
 	status = _cairo_scaled_glyph_lookup (scaled_font,
 					     scaled_font_glyph_index,
 					     CAIRO_SCALED_GLYPH_INFO_PATH,
 					     &scaled_glyph);
+	_cairo_scaled_font_thaw_cache (scaled_font);
     }
     if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
         return status;
@@ -745,7 +753,6 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
                 subset_glyph->is_composite = FALSE;
             }
 
-	    CAIRO_MUTEX_LOCK (unscaled_font->mutex);
             status = _cairo_sub_font_create (subsets,
 					     unscaled_font,
 					     subsets->num_sub_fonts,
@@ -753,7 +760,6 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
 					     subset_glyph->is_scaled,
 					     subset_glyph->is_composite,
 					     &sub_font);
-	    CAIRO_MUTEX_UNLOCK (unscaled_font->mutex);
 
             if (status) {
 		cairo_scaled_font_destroy (unscaled_font);
@@ -815,18 +821,10 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
         }
     }
 
-    if (sub_font->scaled_font != scaled_font)
-	CAIRO_MUTEX_LOCK (sub_font->scaled_font->mutex);
-
-    status =  _cairo_sub_font_map_glyph (sub_font,
-					 scaled_font_glyph_index,
-					 utf8, utf8_len,
-					 subset_glyph);
-
-    if (sub_font->scaled_font != scaled_font)
-	CAIRO_MUTEX_UNLOCK (sub_font->scaled_font->mutex);
-
-    return status;
+    return _cairo_sub_font_map_glyph (sub_font,
+				      scaled_font_glyph_index,
+				      utf8, utf8_len,
+				      subset_glyph);
 }
 
 static cairo_status_t
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 83a3927..d312a4c 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -145,6 +145,9 @@
  *  and note that glyph origin = device-space origin.
  */
 
+static void
+_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font);
+
 static cairo_bool_t
 _cairo_scaled_glyph_keys_equal (const void *abstract_key_a, const void *abstract_key_b)
 {
@@ -377,11 +380,11 @@ _cairo_scaled_font_map_destroy (void)
 
 	font_map->num_holdovers--;
 
-	/* release the lock to avoid the possibility of a recursive
-	 * deadlock when the scaled font destroy closure gets called */
-	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+	/* This releases the font_map lock to avoid the possibility of a
+	 * recursive deadlock when the scaled font destroy closure gets
+	 * called
+	 */
 	_cairo_scaled_font_fini (scaled_font);
-	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
 
 	free (scaled_font);
     }
@@ -451,7 +454,7 @@ _cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t
     return CAIRO_STATUS_SUCCESS;
 
   FINI_PLACEHOLDER:
-    _cairo_scaled_font_fini (placeholder_scaled_font);
+    _cairo_scaled_font_fini_internal (placeholder_scaled_font);
   FREE_PLACEHOLDER:
     free (placeholder_scaled_font);
 
@@ -498,8 +501,9 @@ _cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t
 
     /* ok, creation done.  just clean up and back out */
     CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
-    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
     cairo_scaled_font_destroy (placeholder_scaled_font);
+
+    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
 }
 
 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
@@ -656,17 +660,18 @@ _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
 void
 _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
 {
-    assert (CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex));
+    /* ensure we do not modify an error object */
+    assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
 
+    CAIRO_MUTEX_LOCK (scaled_font->mutex);
     _cairo_cache_freeze (scaled_font->glyphs);
 }
 
 void
 _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
 {
-    assert (CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex));
-
     _cairo_cache_thaw (scaled_font->glyphs);
+    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 }
 
 void
@@ -707,8 +712,8 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t	    *scaled_font,
     return CAIRO_STATUS_SUCCESS;
 }
 
-void
-_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+static void
+_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
 {
     scaled_font->finished = TRUE;
 
@@ -730,6 +735,16 @@ _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
     _cairo_user_data_array_fini (&scaled_font->user_data);
 }
 
+void
+_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+{
+    /* Release the lock to avoid the possibility of a recursive
+     * deadlock when the scaled font destroy closure gets called. */
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+    _cairo_scaled_font_fini_internal (scaled_font);
+    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+}
+
 /**
  * cairo_scaled_font_create:
  * @font_face: a #cairo_font_face_t
@@ -881,7 +896,7 @@ cairo_scaled_font_create (cairo_font_face_t          *font_face,
 	/* 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);
+	_cairo_scaled_font_fini_internal (scaled_font);
 	free (scaled_font);
 	return _cairo_scaled_font_create_in_error (status);
     }
@@ -985,6 +1000,8 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
     cairo_scaled_font_t *lru = NULL;
     cairo_scaled_font_map_t *font_map;
 
+    assert (CAIRO_MUTEX_IS_UNLOCKED (_cairo_scaled_font_map_mutex));
+
     if (scaled_font == NULL ||
 	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
 	return;
@@ -1025,7 +1042,7 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
 
     }
 
-    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+    _cairo_scaled_font_map_unlock ();
 
     /* If we pulled an item from the holdovers array, (while the font
      * map lock was held, of course), then there is no way that anyone
@@ -1034,7 +1051,7 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
      * as we never want to call into any backend function with a lock
      * held. */
     if (lru) {
-	_cairo_scaled_font_fini (lru);
+	_cairo_scaled_font_fini_internal (lru);
 	free (lru);
     }
 }
@@ -1114,6 +1131,13 @@ cairo_scaled_font_set_user_data (cairo_scaled_font_t	     *scaled_font,
 					    key, user_data, destroy);
 }
 
+static cairo_bool_t
+_cairo_scaled_font_is_frozen (cairo_scaled_font_t *scaled_font)
+{
+    return CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex) &&
+	   scaled_font->glyphs->freeze_count > 0;
+}
+
 /* Public font API follows. */
 
 /**
@@ -1257,7 +1281,6 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
 	return;
     }
 
-    CAIRO_MUTEX_LOCK (scaled_font->mutex);
     _cairo_scaled_font_freeze_cache (scaled_font);
 
     for (i = 0; i < num_glyphs; i++) {
@@ -1326,7 +1349,6 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
 
  UNLOCK:
     _cairo_scaled_font_thaw_cache (scaled_font);
-    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 }
 slim_hidden_def (cairo_scaled_font_glyph_extents);
 
@@ -1551,7 +1573,6 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
     if (status)
 	goto BAIL;
 
-    CAIRO_MUTEX_LOCK (scaled_font->mutex);
     _cairo_scaled_font_freeze_cache (scaled_font);
 
     orig_glyphs = *glyphs;
@@ -1657,7 +1678,6 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 
  DONE: /* error that should be logged on scaled_font happened */
     _cairo_scaled_font_thaw_cache (scaled_font);
-    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 
     if (status) {
 	*num_glyphs = 0;
@@ -1706,7 +1726,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
     if (scaled_font->status)
 	return scaled_font->status;
 
-    assert (CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex));
+    _cairo_scaled_font_freeze_cache (scaled_font);
 
     for (i = 0; i < num_glyphs; i++) {
 	cairo_scaled_glyph_t	*scaled_glyph;
@@ -1719,7 +1739,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
 					     CAIRO_SCALED_GLYPH_INFO_METRICS,
 					     &scaled_glyph);
 	if (status)
-	    return _cairo_scaled_font_set_error (scaled_font, status);
+	    break;
 
 	/* XXX glyph images are snapped to pixel locations */
 	x = _cairo_lround (glyphs[i].x);
@@ -1735,6 +1755,11 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
 	if (top < min.y) min.y = top;
 	if (bottom > max.y) max.y = bottom;
     }
+
+    _cairo_scaled_font_thaw_cache (scaled_font);
+    if (status)
+	return _cairo_scaled_font_set_error (scaled_font, status);
+
     if (min.x < max.x && min.y < max.y) {
 	extents->x = min.x;
 	extents->width = max.x - min.x;
@@ -1744,6 +1769,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
 	extents->x = extents->y = 0;
 	extents->width = extents->height = 0;
     }
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1779,7 +1805,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
     if (!num_glyphs)
 	return CAIRO_STATUS_SUCCESS;
 
-    assert (CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex));
     if (scaled_font->backend->show_glyphs != NULL) {
 	int remaining_glyphs = num_glyphs;
 	status = scaled_font->backend->show_glyphs (scaled_font,
@@ -1801,7 +1826,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
 
     _cairo_pattern_init_solid (&white_pattern, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
 
-    _cairo_cache_freeze (scaled_font->glyphs);
+    _cairo_scaled_font_freeze_cache (scaled_font);
 
     for (i = 0; i < num_glyphs; i++) {
 	int x, y;
@@ -1921,7 +1946,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
     _cairo_pattern_fini (&mask_pattern.base);
 
 CLEANUP_MASK:
-    _cairo_cache_thaw (scaled_font->glyphs);
+    _cairo_scaled_font_thaw_cache (scaled_font);
 
     _cairo_pattern_fini (&white_pattern.base);
 
@@ -2094,8 +2119,6 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
     if (status)
 	return status;
 
-    assert (CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex));
-
     closure.path = path;
     _cairo_scaled_font_freeze_cache (scaled_font);
     for (i = 0; i < num_glyphs; i++) {
@@ -2282,7 +2305,11 @@ _cairo_scaled_glyph_set_meta_surface (cairo_scaled_glyph_t *scaled_glyph,
  * get INFO_PATH with a bitmapped font), this function will return
  * %CAIRO_INT_STATUS_UNSUPPORTED.
  *
- * Note: This function must be called with scaled_font->mutex held.
+ * Note: This function must be called with the scaled font frozen, and it must
+ * remain frozen for as long as the @scaled_glyph_ret is alive. (If the scaled
+ * font was not frozen, then there is no guarantee that the glyph would not be
+ * evicted before you tried to access it.) See
+ * _cairo_scaled_font_freeze_cache() and _cairo_scaled_font_thaw_cache().
  *
  * Returns: a glyph with the requested portions filled in. Glyph
  * lookup is cached and glyph will be automatically freed along
@@ -2306,7 +2333,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
     if (scaled_font->status)
 	return scaled_font->status;
 
-    assert (CAIRO_MUTEX_IS_LOCKED (scaled_font->mutex));
+    assert (_cairo_scaled_font_is_frozen (scaled_font));
 
     key.hash = index;
     /*
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 8bafb34..c44dfaf 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -988,6 +988,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t		*surface,
 
     if (_cairo_operator_bounded_by_mask (op)) {
         cairo_rectangle_int_t glyph_extents;
+
 	status = _cairo_scaled_font_glyph_device_extents (scaled_font,
 							  glyphs,
 							  num_glyphs,
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 75cccae..d1df186 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2267,8 +2267,6 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
 	return _cairo_surface_set_error (surface, status);
     }
 
-    CAIRO_MUTEX_LOCK (dev_scaled_font->mutex);
-
     status = CAIRO_INT_STATUS_UNSUPPORTED;
 
     /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
@@ -2328,8 +2326,6 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
 						      glyphs, num_glyphs,
 						      dev_scaled_font);
 
-    CAIRO_MUTEX_UNLOCK (dev_scaled_font->mutex);
-
     if (dev_scaled_font != scaled_font)
 	cairo_scaled_font_destroy (dev_scaled_font);
 
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 1219d18..f392c8e 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -739,7 +739,7 @@ _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t	*font_subset,
     unsigned int i;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
-    CAIRO_MUTEX_LOCK (font_subset->scaled_font->mutex);
+    _cairo_scaled_font_freeze_cache (font_subset->scaled_font);
     for (i = 0; i < font_subset->num_glyphs; i++) {
 	status = _cairo_svg_document_emit_glyph (document,
 					         font_subset->scaled_font,
@@ -748,7 +748,7 @@ _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t	*font_subset,
 	if (status)
 	    break;
     }
-    CAIRO_MUTEX_UNLOCK (font_subset->scaled_font->mutex);
+    _cairo_scaled_font_thaw_cache (font_subset->scaled_font);
 
     return status;
 }
diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c
index 840fc7d..83ddc44 100644
--- a/src/cairo-type1-fallback.c
+++ b/src/cairo-type1-fallback.c
@@ -348,7 +348,6 @@ cairo_type1_font_create_charstring (cairo_type1_font_t      *font,
     cairo_bool_t emit_path = TRUE;
 
     /* This call may return CAIRO_INT_STATUS_UNSUPPORTED for bitmap fonts. */
-    CAIRO_MUTEX_LOCK (font->type1_scaled_font->mutex);
     status = _cairo_scaled_glyph_lookup (font->type1_scaled_font,
 					 glyph_index,
 					 CAIRO_SCALED_GLYPH_INFO_METRICS|
@@ -364,7 +363,6 @@ cairo_type1_font_create_charstring (cairo_type1_font_t      *font,
 					     CAIRO_SCALED_GLYPH_INFO_METRICS,
 					     &scaled_glyph);
     }
-    CAIRO_MUTEX_UNLOCK (font->type1_scaled_font->mutex);
     if (status)
         return status;
 
@@ -446,18 +444,21 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t    *font,
                                  "2 index /CharStrings %d dict dup begin\n",
                                  font->scaled_font_subset->num_glyphs + 1);
 
+    _cairo_scaled_font_freeze_cache (font->type1_scaled_font);
     for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
         _cairo_array_truncate (&data, 0);
         /* four "random" bytes required by encryption algorithm */
         status = _cairo_array_append_multiple (&data, zeros, 4);
         if (status)
             goto fail;
+
         status = cairo_type1_font_create_charstring (font, i,
 						     font->scaled_font_subset->glyphs[i],
                                                      CAIRO_CHARSTRING_TYPE1,
 						     &data);
         if (status)
             goto fail;
+
         charstring_encrypt (&data);
         length = _cairo_array_num_elements (&data);
 	if (font->scaled_font_subset->glyph_names != NULL) {
@@ -476,6 +477,7 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t    *font,
     }
 
 fail:
+    _cairo_scaled_font_thaw_cache (font->type1_scaled_font);
     _cairo_array_fini (&data);
     return status;
 }
@@ -825,6 +827,7 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset,
         goto fail1;
     }
 
+    _cairo_scaled_font_freeze_cache (font->type1_scaled_font);
     for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
         _cairo_array_init (&charstring, sizeof (unsigned char));
         status = _cairo_array_grow_by (&charstring, 32);
@@ -842,6 +845,7 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset,
         if (status)
             goto fail2;
     }
+    _cairo_scaled_font_thaw_cache (font->type1_scaled_font);
 
     for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
 	type2_subset->widths[i] = font->widths[i];
@@ -856,6 +860,7 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset,
     return cairo_type1_font_destroy (font);
 
 fail2:
+    _cairo_scaled_font_thaw_cache (font->type1_scaled_font);
     _cairo_array_fini (&charstring);
     _cairo_type2_charstrings_fini (type2_subset);
 fail1:
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 3508ce7..ed8fff7 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -286,14 +286,12 @@ _cairo_type3_glyph_surface_show_glyphs (void		     *abstract_surface,
 				     &new_ctm,
 				     &scaled_font->options);
 
-    CAIRO_MUTEX_LOCK (font->mutex);
     status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
 						    NULL, 0,
 						    glyphs, num_glyphs,
 						    NULL, 0,
 						    FALSE,
 						    font);
-    CAIRO_MUTEX_UNLOCK (font->mutex);
 
     cairo_scaled_font_destroy (font);
 
@@ -349,13 +347,11 @@ _cairo_type3_glyph_surface_emit_fallback_image (cairo_type3_glyph_surface_t *sur
     cairo_matrix_t mat;
     double x, y;
 
-    CAIRO_MUTEX_LOCK (surface->scaled_font->mutex);
     status = _cairo_scaled_glyph_lookup (surface->scaled_font,
 					 glyph_index,
 					 CAIRO_SCALED_GLYPH_INFO_METRICS |
 					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
 					 &scaled_glyph);
-    CAIRO_MUTEX_UNLOCK (surface->scaled_font->mutex);
     if (status)
 	return status;
 
@@ -401,13 +397,12 @@ _cairo_type3_glyph_surface_analyze_glyph (void		     *abstract_surface,
     null_stream = _cairo_null_stream_create ();
     _cairo_type3_glyph_surface_set_stream (surface, null_stream);
 
-    CAIRO_MUTEX_LOCK (surface->scaled_font->mutex);
+    _cairo_scaled_font_freeze_cache (surface->scaled_font);
     status = _cairo_scaled_glyph_lookup (surface->scaled_font,
 					 glyph_index,
 					 CAIRO_SCALED_GLYPH_INFO_METRICS |
 					 CAIRO_SCALED_GLYPH_INFO_META_SURFACE,
 					 &scaled_glyph);
-    CAIRO_MUTEX_UNLOCK (surface->scaled_font->mutex);
 
     if (_cairo_status_is_error (status))
 	goto cleanup;
@@ -430,6 +425,8 @@ _cairo_type3_glyph_surface_analyze_glyph (void		     *abstract_surface,
 	status = CAIRO_STATUS_SUCCESS;
 
 cleanup:
+    _cairo_scaled_font_thaw_cache (surface->scaled_font);
+
     status2 = _cairo_output_stream_destroy (null_stream);
     if (status == CAIRO_STATUS_SUCCESS)
 	status = status2;
@@ -469,7 +466,7 @@ _cairo_type3_glyph_surface_emit_glyph (void		     *abstract_surface,
 
     _cairo_type3_glyph_surface_set_stream (surface, stream);
 
-    CAIRO_MUTEX_LOCK (surface->scaled_font->mutex);
+    _cairo_scaled_font_freeze_cache (surface->scaled_font);
     status = _cairo_scaled_glyph_lookup (surface->scaled_font,
 					 glyph_index,
 					 CAIRO_SCALED_GLYPH_INFO_METRICS |
@@ -483,9 +480,10 @@ _cairo_type3_glyph_surface_emit_glyph (void		     *abstract_surface,
 	if (status == CAIRO_STATUS_SUCCESS)
 	    status = CAIRO_INT_STATUS_IMAGE_FALLBACK;
     }
-    CAIRO_MUTEX_UNLOCK (surface->scaled_font->mutex);
-    if (_cairo_status_is_error (status))
+    if (_cairo_status_is_error (status)) {
+	_cairo_scaled_font_thaw_cache (surface->scaled_font);
 	return status;
+    }
 
     x_advance = scaled_glyph->metrics.x_advance;
     y_advance = scaled_glyph->metrics.y_advance;
@@ -538,6 +536,8 @@ _cairo_type3_glyph_surface_emit_glyph (void		     *abstract_surface,
     if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
 	status = _cairo_type3_glyph_surface_emit_fallback_image (surface, glyph_index);
 
+    _cairo_scaled_font_thaw_cache (surface->scaled_font);
+
     return status;
 }
 
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index 5645287..385b841 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -481,7 +481,6 @@ _cairo_user_font_face_scaled_font_create (void                        *abstract_
     if (status == CAIRO_STATUS_SUCCESS)
 	status = _cairo_scaled_font_set_metrics (&user_scaled_font->base, &font_extents);
 
-
     if (status != CAIRO_STATUS_SUCCESS) {
         _cairo_scaled_font_fini (&user_scaled_font->base);
 	free (user_scaled_font);
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index f82d528..dc93758 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -640,21 +640,25 @@ _cairo_win32_scaled_font_type1_text_to_glyphs (cairo_win32_scaled_font_t *scaled
 
     if (GetGlyphIndicesW (hdc, utf16, n16, glyph_indices, 0) == GDI_ERROR) {
 	status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_type1_text_to_glyphs:GetGlyphIndicesW");
-	goto FAIL2;
+	goto FAIL3;
     }
 
     *num_glyphs = n16;
     *glyphs = _cairo_malloc_ab (n16, sizeof (cairo_glyph_t));
     if (!*glyphs) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto FAIL2;
+	goto FAIL3;
     }
 
     x_pos = x;
     y_pos = y;
+
     mat = scaled_font->base.ctm;
     status = cairo_matrix_invert (&mat);
     assert (status == CAIRO_STATUS_SUCCESS);
+
+    _cairo_scaled_font_freeze_cache (&scaled_font->base);
+
     for (i = 0; i < n16; i++) {
 	cairo_scaled_glyph_t *scaled_glyph;
 
@@ -668,7 +672,7 @@ _cairo_win32_scaled_font_type1_text_to_glyphs (cairo_win32_scaled_font_t *scaled
 					     &scaled_glyph);
 	if (status) {
 	    free (*glyphs);
-	    goto FAIL2;
+	    goto FAIL3;
 	}
 
 	x = scaled_glyph->x_advance;
@@ -678,6 +682,8 @@ _cairo_win32_scaled_font_type1_text_to_glyphs (cairo_win32_scaled_font_t *scaled
 	y_pos += y;
     }
 
+FAIL3:
+    _cairo_scaled_font_thaw_cache (&scaled_font->base);
     cairo_win32_scaled_font_done_font (&scaled_font->base);
 
 FAIL2:
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 895d8e8..1760bcb 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -2332,14 +2332,121 @@ typedef cairo_status_t (*cairo_xcb_surface_show_glyphs_func_t)
     (cairo_xcb_surface_t *, cairo_operator_t, cairo_xcb_surface_t *, int, int,
      const cairo_glyph_t *, int, cairo_scaled_font_t *);
 
+static cairo_bool_t
+_cairo_xcb_surface_owns_font (cairo_xcb_surface_t *dst,
+			      cairo_scaled_font_t *scaled_font)
+{
+    cairo_xcb_surface_font_private_t *font_private;
+
+    font_private = scaled_font->surface_private;
+    if ((scaled_font->surface_backend != NULL &&
+	 scaled_font->surface_backend != &cairo_xcb_surface_backend) ||
+	(font_private != NULL && font_private->dpy != dst->dpy))
+    {
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+
+static cairo_status_t
+_cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst,
+				cairo_glyph_t       *glyphs,
+				int                  num_glyphs,
+				cairo_scaled_font_t *scaled_font,
+				cairo_operator_t     op,
+				cairo_xcb_surface_t *src,
+				cairo_surface_attributes_t *attributes,
+				int                 *remaining_glyphs)
+{
+    cairo_scaled_glyph_t *scaled_glyph;
+    int i, o;
+    unsigned long max_index = 0;
+    cairo_status_t status;
+    cairo_glyph_t *output_glyphs;
+    const cairo_glyph_t *glyphs_chunk;
+    int glyphs_remaining, chunk_size, max_chunk_size;
+    cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
+
+    /* We make a copy of the glyphs so that we can elide any size-zero
+     * glyphs to workaround an X server bug, (present in at least Xorg
+     * 7.1 without EXA). */
+    output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
+    if (output_glyphs == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    for (i = 0, o = 0; i < num_glyphs; i++) {
+	if (glyphs[i].index > max_index)
+	    max_index = glyphs[i].index;
+	status = _cairo_scaled_glyph_lookup (scaled_font,
+					     glyphs[i].index,
+					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
+					     &scaled_glyph);
+	if (status) {
+	    free (output_glyphs);
+	    return status;
+	}
+
+	/* Don't put any size-zero glyphs into output_glyphs to avoid
+	 * an X server bug which stops rendering glyphs after the
+	 * first size-zero glyph. */
+	if (scaled_glyph->surface->width && scaled_glyph->surface->height) {
+	    output_glyphs[o++] = glyphs[i];
+	    if (scaled_glyph->surface_private == NULL) {
+		_cairo_xcb_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph);
+		scaled_glyph->surface_private = (void *) 1;
+	    }
+	}
+    }
+    num_glyphs = o;
+
+    _cairo_xcb_surface_ensure_dst_picture (dst);
+
+    max_chunk_size = xcb_get_maximum_request_length (dst->dpy);
+    if (max_index < 256) {
+	/* XXX: these are all the same size! (28) */
+	max_chunk_size -= sizeof(xcb_render_composite_glyphs_8_request_t);
+	show_glyphs_func = _cairo_xcb_surface_show_glyphs_8;
+    } else if (max_index < 65536) {
+	max_chunk_size -= sizeof(xcb_render_composite_glyphs_16_request_t);
+	show_glyphs_func = _cairo_xcb_surface_show_glyphs_16;
+    } else {
+	max_chunk_size -= sizeof(xcb_render_composite_glyphs_32_request_t);
+	show_glyphs_func = _cairo_xcb_surface_show_glyphs_32;
+    }
+    /* XXX: I think this is wrong; this is only the header size (2 longs) */
+    /*      but should also include the glyph (1 long) */
+    /* max_chunk_size /= sz_xGlyphElt; */
+    max_chunk_size /= 3*sizeof(uint32_t);
+
+    for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs;
+	 glyphs_remaining;
+	 glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
+    {
+	chunk_size = MIN (glyphs_remaining, max_chunk_size);
+
+	status = show_glyphs_func (dst, op, src,
+                                   attributes->x_offset, attributes->y_offset,
+                                   glyphs_chunk, chunk_size, scaled_font);
+	if (status) {
+	    free (output_glyphs);
+	    return status;
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_int_status_t
 _cairo_xcb_surface_show_glyphs (void                *abstract_dst,
-				 cairo_operator_t     op,
-				 cairo_pattern_t     *src_pattern,
-				 cairo_glyph_t       *glyphs,
-				 int		      num_glyphs,
-				 cairo_scaled_font_t *scaled_font,
-				 int		     *remaining_glyphs)
+				cairo_operator_t     op,
+				cairo_pattern_t     *src_pattern,
+				cairo_glyph_t       *glyphs,
+				int		      num_glyphs,
+				cairo_scaled_font_t *scaled_font,
+				int		     *remaining_glyphs)
 {
     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
     cairo_xcb_surface_t *dst = abstract_dst;
@@ -2348,17 +2455,6 @@ _cairo_xcb_surface_show_glyphs (void                *abstract_dst,
     cairo_surface_attributes_t attributes;
     cairo_xcb_surface_t *src = NULL;
 
-    cairo_glyph_t *output_glyphs;
-    const cairo_glyph_t *glyphs_chunk;
-    int glyphs_remaining, chunk_size, max_chunk_size;
-    cairo_scaled_glyph_t *scaled_glyph;
-    cairo_xcb_surface_font_private_t *font_private;
-
-    int i, o;
-    unsigned long max_index = 0;
-
-    cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
-
     cairo_solid_pattern_t solid_pattern;
 
     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
@@ -2392,29 +2488,16 @@ _cairo_xcb_surface_show_glyphs (void                *abstract_dst,
     if (operation == DO_UNSUPPORTED)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    font_private = scaled_font->surface_private;
-    if ((scaled_font->surface_backend != NULL &&
-	 scaled_font->surface_backend != &cairo_xcb_surface_backend) ||
-	(font_private != NULL && font_private->dpy != dst->dpy))
+    if (! _cairo_xcb_surface_owns_font (dst, scaled_font))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    /* We make a copy of the glyphs so that we can elide any size-zero
-     * glyphs to workaround an X server bug, (present in at least Xorg
-     * 7.1 without EXA). */
-    output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
-    if (output_glyphs == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
     /* After passing all those tests, we're now committed to rendering
      * these glyphs or to fail trying. We first upload any glyphs to
      * the X server that it doesn't have already, then we draw
      * them. We tie into the scaled_font's glyph cache and remove
      * glyphs from the X server when they are ejected from the
-     * scaled_font cache. Because of this we first freeze the
-     * scaled_font's cache so that we don't cause any of our glyphs to
-     * be ejected and removed from the X server before we have a
-     * chance to render them. */
-    _cairo_scaled_font_freeze_cache (scaled_font);
+     * scaled_font cache.
+     */
 
     /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
      * the mask (the glyphs).  This code below was executed as a side effect
@@ -2464,64 +2547,21 @@ _cairo_xcb_surface_show_glyphs (void                *abstract_dst,
         goto BAIL;
 
     /* Send all unsent glyphs to the server, and count the max of the glyph indices */
-    for (i = 0, o = 0; i < num_glyphs; i++) {
-	if (glyphs[i].index > max_index)
-	    max_index = glyphs[i].index;
-	status = _cairo_scaled_glyph_lookup (scaled_font,
-					     glyphs[i].index,
-					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
-					     &scaled_glyph);
-	if (status != CAIRO_STATUS_SUCCESS)
-	    goto BAIL;
-	/* Don't put any size-zero glyphs into output_glyphs to avoid
-	 * an X server bug which stops rendering glyphs after the
-	 * first size-zero glyph. */
-	if (scaled_glyph->surface->width && scaled_glyph->surface->height) {
-	    output_glyphs[o++] = glyphs[i];
-	    if (scaled_glyph->surface_private == NULL) {
-		_cairo_xcb_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph);
-		scaled_glyph->surface_private = (void *) 1;
-	    }
-	}
-    }
-    num_glyphs = o;
-
-    _cairo_xcb_surface_ensure_dst_picture (dst);
-
-    max_chunk_size = xcb_get_maximum_request_length (dst->dpy);
-    if (max_index < 256) {
-	/* XXX: these are all the same size! (28) */
-	max_chunk_size -= sizeof(xcb_render_composite_glyphs_8_request_t);
-	show_glyphs_func = _cairo_xcb_surface_show_glyphs_8;
-    } else if (max_index < 65536) {
-	max_chunk_size -= sizeof(xcb_render_composite_glyphs_16_request_t);
-	show_glyphs_func = _cairo_xcb_surface_show_glyphs_16;
-    } else {
-	max_chunk_size -= sizeof(xcb_render_composite_glyphs_32_request_t);
-	show_glyphs_func = _cairo_xcb_surface_show_glyphs_32;
-    }
-    /* XXX: I think this is wrong; this is only the header size (2 longs) */
-    /*      but should also include the glyph (1 long) */
-    /* max_chunk_size /= sz_xGlyphElt; */
-    max_chunk_size /= 3*sizeof(uint32_t);
-
-    for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs;
-	 glyphs_remaining;
-	 glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
-    {
-	chunk_size = MIN (glyphs_remaining, max_chunk_size);
-
-	status = show_glyphs_func (dst, op, src,
-                                   attributes.x_offset, attributes.y_offset,
-                                   glyphs_chunk, chunk_size, scaled_font);
-	if (status != CAIRO_STATUS_SUCCESS)
-	    break;
-    }
+    _cairo_scaled_font_freeze_cache (scaled_font);
 
-  BAIL:
+    if (_cairo_xcb_surface_owns_font (dst, scaled_font))
+	status = _cairo_xcb_surface_emit_glyphs (dst,
+						 glyphs, num_glyphs,
+						 scaled_font,
+						 op,
+						 src,
+						 &attributes,
+						 remaining_glyphs);
+    else
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
     _cairo_scaled_font_thaw_cache (scaled_font);
-    free (output_glyphs);
 
+  BAIL:
     if (src)
         _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
     if (src_pattern == &solid_pattern.base)
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 7bf34ee..ac840b8 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -3107,7 +3107,7 @@ _cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t	*display,
     scaled_font = font_private->scaled_font;
 
     CAIRO_MUTEX_LOCK (scaled_font->mutex);
-    font_private  = scaled_font->surface_private;
+    font_private = scaled_font->surface_private;
     scaled_font->surface_private = NULL;
 
     _cairo_scaled_font_reset_cache (scaled_font);
@@ -3936,6 +3936,23 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
     return status;
 }
 
+static cairo_bool_t
+_cairo_xlib_surface_owns_font (cairo_xlib_surface_t *dst,
+			       cairo_scaled_font_t *scaled_font)
+{
+    cairo_xlib_surface_font_private_t *font_private;
+
+    font_private = scaled_font->surface_private;
+    if ((scaled_font->surface_backend != NULL &&
+	 scaled_font->surface_backend != &cairo_xlib_surface_backend) ||
+	(font_private != NULL && font_private->display != dst->display))
+    {
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
 static cairo_int_status_t
 _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
 				 cairo_operator_t     op,
@@ -3952,8 +3969,6 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
     cairo_surface_attributes_t attributes;
     cairo_xlib_surface_t *src = NULL;
 
-    cairo_xlib_surface_font_private_t *font_private;
-
     cairo_solid_pattern_t solid_pattern;
 
     if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
@@ -3987,22 +4002,14 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
     if (operation == DO_UNSUPPORTED)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    font_private = scaled_font->surface_private;
-    if ((scaled_font->surface_backend != NULL &&
-	 scaled_font->surface_backend != &cairo_xlib_surface_backend) ||
-	(font_private != NULL && font_private->display != dst->display))
+    if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     /* After passing all those tests, we're now committed to rendering
      * these glyphs or to fail trying. We first upload any glyphs to
      * the X server that it doesn't have already, then we draw
-     * them. We tie into the scaled_font's glyph cache and remove
-     * glyphs from the X server when they are ejected from the
-     * scaled_font cache. Because of this we first freeze the
-     * scaled_font's cache so that we don't cause any of our glyphs to
-     * be ejected and removed from the X server before we have a
-     * chance to render them. */
-    _cairo_scaled_font_freeze_cache (scaled_font);
+     * them.
+     */
 
     /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
      * the mask (the glyphs).  This code below was executed as a side effect
@@ -4053,14 +4060,19 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
     if (status)
         goto BAIL1;
 
-    status = _cairo_xlib_surface_emit_glyphs (dst,
-	                                      (cairo_xlib_glyph_t *) glyphs,
-					      num_glyphs,
-					      scaled_font,
-					      op,
-					      src,
-					      &attributes,
-					      remaining_glyphs);
+    _cairo_scaled_font_freeze_cache (scaled_font);
+    if (_cairo_xlib_surface_owns_font (dst, scaled_font)) {
+	status = _cairo_xlib_surface_emit_glyphs (dst,
+						  (cairo_xlib_glyph_t *) glyphs,
+						  num_glyphs,
+						  scaled_font,
+						  op,
+						  src,
+						  &attributes,
+						  remaining_glyphs);
+    } else
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+    _cairo_scaled_font_thaw_cache (scaled_font);
 
   BAIL1:
     if (src)
@@ -4068,7 +4080,6 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
     if (src_pattern == &solid_pattern.base)
 	_cairo_pattern_fini (&solid_pattern.base);
   BAIL0:
-    _cairo_scaled_font_thaw_cache (scaled_font);
     _cairo_xlib_display_notify (dst->display);
 
     return status;
diff --git a/src/cairoint.h b/src/cairoint.h
index cdf28b4..577c032 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1559,6 +1559,10 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t	    *scaled_font,
 cairo_private void
 _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font);
 
+/* This should only be called on an error path by a scaled_font constructor */
+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);
diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c
index 9554c53..6038430 100644
--- a/src/test-meta-surface.c
+++ b/src/test-meta-surface.c
@@ -277,29 +277,14 @@ _test_meta_surface_show_text_glyphs (void		    *abstract_surface,
 				     cairo_scaled_font_t    *scaled_font)
 {
     test_meta_surface_t *surface = abstract_surface;
-    cairo_int_status_t status;
 
     surface->image_reflects_meta = FALSE;
 
-    /* Since this is a "wrapping" surface, we're calling back into
-     * _cairo_surface_show_text_glyphs from within a call to the same.
-     * Since _cairo_surface_show_text_glyphs acquires a mutex, we release
-     * and re-acquire the mutex around this nested call.
-     *
-     * Yes, this is ugly, but we consider it pragmatic as compared to
-     * adding locking code to all 18 surface-backend-specific
-     * show_glyphs functions, (which would get less testing and likely
-     * lead to bugs).
-     */
-    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
-    status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
-					      utf8, utf8_len,
-					      glyphs, num_glyphs,
-					      clusters, num_clusters, cluster_flags,
-					      scaled_font);
-    CAIRO_MUTEX_LOCK (scaled_font->mutex);
-
-    return status;
+    return _cairo_surface_show_text_glyphs (surface->meta, op, source,
+					    utf8, utf8_len,
+					    glyphs, num_glyphs,
+					    clusters, num_clusters, cluster_flags,
+					    scaled_font);
 }
 
 
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index fb7e2e4..354f95d 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -256,30 +256,15 @@ _test_paginated_surface_show_text_glyphs (void			    *abstract_surface,
 					  cairo_scaled_font_t	    *scaled_font)
 {
     test_paginated_surface_t *surface = abstract_surface;
-    cairo_int_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return CAIRO_STATUS_SUCCESS;
 
-    /* Since this is a "wrapping" surface, we're calling back into
-     * _cairo_surface_show_text_glyphs from within a call to the same.
-     * Since _cairo_surface_show_text_glyphs acquires a mutex, we release
-     * and re-acquire the mutex around this nested call.
-     *
-     * Yes, this is ugly, but we consider it pragmatic as compared to
-     * adding locking code to all 18 surface-backend-specific
-     * show_glyphs functions, (which would get less testing and likely
-     * lead to bugs).
-     */
-    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
-    status = _cairo_surface_show_text_glyphs (surface->target, op, source,
-					      utf8, utf8_len,
-					      glyphs, num_glyphs,
-					      clusters, num_clusters, cluster_flags,
-					      scaled_font);
-    CAIRO_MUTEX_LOCK (scaled_font->mutex);
-
-    return status;
+    return _cairo_surface_show_text_glyphs (surface->target, op, source,
+					    utf8, utf8_len,
+					    glyphs, num_glyphs,
+					    clusters, num_clusters, cluster_flags,
+					    scaled_font);
 }
 
 


More information about the cairo-commit mailing list