[cairo-commit] 11 commits - AUTHORS build/configure.ac.system src/cairo-clip.c src/cairo-debug.c src/cairo-directfb-surface.c src/cairo-ft-font.c src/cairo-glitz-surface.c src/cairo-image-surface.c src/cairoint.h src/cairo-malloc-private.h src/cairo-pattern.c src/cairo-png.c src/cairo-quartz-surface.c src/cairo-scaled-font.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-surface-fallback-private.h src/cairo-win32-surface.c src/cairo-xcb-surface.c src/cairo-xlib-surface.c src/test-fallback16-surface.c src/test-fallback-surface.c test/cairo-test.c test/cairo-test-runner.c test/ft-font-create-for-ft-face.c test/get-path-extents.c test/invalid-matrix.c test/Makefile.am test/surface-source.c test/twin.c test/twin.ps.ref.png test/twin.ref.png test/twin.svg.ref.png

Chris Wilson ickle at kemper.freedesktop.org
Fri May 15 13:31:22 PDT 2009


 AUTHORS                              |    2 
 build/configure.ac.system            |    2 
 src/cairo-clip.c                     |    1 
 src/cairo-debug.c                    |   42 +++++++++++++
 src/cairo-directfb-surface.c         |    2 
 src/cairo-ft-font.c                  |   72 +++++++++++++++--------
 src/cairo-glitz-surface.c            |    3 
 src/cairo-image-surface.c            |    4 +
 src/cairo-malloc-private.h           |    2 
 src/cairo-pattern.c                  |   20 +++++-
 src/cairo-png.c                      |    2 
 src/cairo-quartz-surface.c           |    1 
 src/cairo-scaled-font.c              |    3 
 src/cairo-surface-fallback-private.h |    1 
 src/cairo-surface-fallback.c         |    3 
 src/cairo-surface.c                  |   39 +++++++++---
 src/cairo-win32-surface.c            |    3 
 src/cairo-xcb-surface.c              |    5 +
 src/cairo-xlib-surface.c             |   42 ++++++++++---
 src/cairoint.h                       |   15 ++++
 src/test-fallback-surface.c          |    1 
 src/test-fallback16-surface.c        |    2 
 test/Makefile.am                     |    6 -
 test/cairo-test-runner.c             |   12 +++
 test/cairo-test.c                    |   62 +++++++++----------
 test/ft-font-create-for-ft-face.c    |  109 ++++++++++++++++++++++++++++++++---
 test/get-path-extents.c              |    8 +-
 test/invalid-matrix.c                |    4 +
 test/surface-source.c                |    1 
 test/twin.c                          |   11 +++
 test/twin.ps.ref.png                 |binary
 test/twin.ref.png                    |binary
 test/twin.svg.ref.png                |binary
 33 files changed, 383 insertions(+), 97 deletions(-)

New commits:
commit 31596cf2b298054bbd3e340ae77a3388eadc0d8b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 15 17:40:26 2009 +0100

    [debug] Check image contents using memcheck.
    
    As an aide to tracking down the source of uninitialised reads, run
    VALGRIND_CHECK_MEM_IS_DEFINED() over the contents of image surfaces at the
    boundary between backends, e.g. upon setting a glyph image or acquiring
    a source image.

diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 5100a85..d463be2 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -77,3 +77,45 @@ cairo_debug_reset_static_data (void)
 
     CAIRO_MUTEX_FINALIZE ();
 }
+
+#if HAVE_VALGRIND
+#include <memcheck.h>
+
+void
+_cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface)
+{
+    const cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
+    const uint8_t *bits;
+    int row, width;
+
+    if (surface == NULL)
+	return;
+
+    if (! RUNNING_ON_VALGRIND)
+	return;
+
+    bits = image->data;
+    switch (image->format) {
+    case CAIRO_FORMAT_A1:
+	width = (image->width + 7)/8;
+	break;
+    case CAIRO_FORMAT_A8:
+	width = image->width;
+	break;
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_ARGB32:
+	width = image->width*4;
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+	return;
+    }
+
+    for (row = 0; row < image->height; row++) {
+	VALGRIND_CHECK_MEM_IS_DEFINED (bits, width);
+	/* and then silence any future valgrind warnings */
+	VALGRIND_MAKE_MEM_DEFINED (bits, width);
+	bits += image->stride;
+    }
+}
+#endif
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index f9ff0b1..8a6b4a2 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -996,6 +996,8 @@ _get_bitmap_surface (FT_Bitmap		     *bitmap,
 
     _cairo_image_surface_assume_ownership_of_data ((*surface));
 
+    _cairo_debug_check_image_surface_is_defined (&(*surface)->base);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 67447a5..49187c4 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1452,6 +1452,8 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
 
     pixman_image_unref (pixman_image);
 
+    _cairo_debug_check_image_surface_is_defined (&image->base);
+
     status = _cairo_surface_clone_similar (dst, &image->base,
 					   opaque ?
 					   CAIRO_CONTENT_COLOR :
diff --git a/src/cairo-png.c b/src/cairo-png.c
index c664328..d4f0476 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -654,6 +654,8 @@ read_png (struct png_read_closure_t *png_closure)
     _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
     data = NULL;
 
+    _cairo_debug_check_image_surface_is_defined (surface);
+
     status = _cairo_memory_stream_destroy (png_closure->png_data,
 					   &mime_data,
 					   &mime_data_length);
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index b8d9602..dbe2de8 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -2409,6 +2409,9 @@ _cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
 {
     if (scaled_glyph->surface != NULL)
 	cairo_surface_destroy (&scaled_glyph->surface->base);
+
+    /* sanity check the backend glyph contents */
+    _cairo_debug_check_image_surface_is_defined (&surface->base);
     scaled_glyph->surface = surface;
 }
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 26a7a13..dbc1490 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1153,6 +1153,8 @@ _cairo_surface_acquire_source_image (cairo_surface_t         *surface,
 				     cairo_image_surface_t  **image_out,
 				     void                   **image_extra)
 {
+    cairo_status_t status;
+
     if (surface->status)
 	return surface->status;
 
@@ -1161,9 +1163,14 @@ _cairo_surface_acquire_source_image (cairo_surface_t         *surface,
     if (surface->backend->acquire_source_image == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    return _cairo_surface_set_error (surface,
-	    surface->backend->acquire_source_image (surface,
-						    image_out, image_extra));
+    status = surface->backend->acquire_source_image (surface,
+						     image_out, image_extra);
+    if (unlikely (status))
+	return _cairo_surface_set_error (surface, status);
+
+    _cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 /**
@@ -1222,6 +1229,8 @@ _cairo_surface_acquire_dest_image (cairo_surface_t         *surface,
 				   cairo_rectangle_int_t   *image_rect,
 				   void                   **image_extra)
 {
+    cairo_status_t status;
+
     if (surface->status)
 	return surface->status;
 
@@ -1230,12 +1239,17 @@ _cairo_surface_acquire_dest_image (cairo_surface_t         *surface,
     if (surface->backend->acquire_dest_image == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    return _cairo_surface_set_error (surface,
-	    surface->backend->acquire_dest_image (surface,
-						  interest_rect,
-						  image_out,
-						  image_rect,
-						  image_extra));
+    status = surface->backend->acquire_dest_image (surface,
+						   interest_rect,
+						   image_out,
+						   image_rect,
+						   image_extra);
+    if (unlikely (status))
+	return _cairo_surface_set_error (surface, status);
+
+    _cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 /**
diff --git a/src/cairoint.h b/src/cairoint.h
index fc51d60..f1ba063 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2741,4 +2741,15 @@ CAIRO_END_DECLS
 #include "cairo-malloc-private.h"
 #include "cairo-hash-private.h"
 
+#if HAVE_VALGRIND
+
+cairo_private void
+_cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface);
+
+#else
+
+#define _cairo_debug_check_image_surface_is_defined(X)
+
+#endif
+
 #endif
commit 791a6fa399894e735d522781b15b7f18c3ecd4d1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 15 16:57:49 2009 +0100

    [memfault] Update macros to avoid namescape collision with memcheck
    
    Basing the macro names of the memfault skin lead to a namespace
    collision with memcheck. After updating the headers, update cairo's usage
    to match.

diff --git a/src/cairo-malloc-private.h b/src/cairo-malloc-private.h
index e36f93b..d812058 100644
--- a/src/cairo-malloc-private.h
+++ b/src/cairo-malloc-private.h
@@ -41,7 +41,7 @@
 
 #if HAVE_MEMFAULT
 #include <memfault.h>
-#define CAIRO_INJECT_FAULT() VALGRIND_INJECT_FAULT()
+#define CAIRO_INJECT_FAULT() MEMFAULT_INJECT_FAULT()
 #else
 #define CAIRO_INJECT_FAULT() 0
 #endif
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 96ab2dc..4e3d2fb 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -131,7 +131,7 @@ _cairo_test_init (cairo_test_context_t *ctx,
 {
     char *log_name;
 
-    MF (VALGRIND_DISABLE_FAULTS ());
+    MF (MEMFAULT_DISABLE_FAULTS ());
 
 #if HAVE_FEENABLEEXCEPT
     feenableexcept (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
@@ -222,7 +222,7 @@ cairo_test_init_thread (cairo_test_context_t *ctx,
 			cairo_test_context_t *master,
 			int thread)
 {
-    MF (VALGRIND_DISABLE_FAULTS ());
+    MF (MEMFAULT_DISABLE_FAULTS ());
 
     *ctx = *master;
     ctx->thread = thread;
@@ -739,17 +739,17 @@ cairo_test_for_target (cairo_test_context_t		 *ctx,
 
 #if HAVE_MEMFAULT
 REPEAT:
-    VALGRIND_CLEAR_FAULTS ();
-    VALGRIND_RESET_LEAKS ();
+    MEMFAULT_CLEAR_FAULTS ();
+    MEMFAULT_RESET_LEAKS ();
     ctx->last_fault_count = 0;
-    last_fault_count = VALGRIND_COUNT_FAULTS ();
+    last_fault_count = MEMFAULT_COUNT_FAULTS ();
 
     /* Pre-initialise fontconfig so that the configuration is loaded without
      * malloc failures (our primary goal is to test cairo fault tolerance).
      */
     FcInit ();
 
-    VALGRIND_ENABLE_FAULTS ();
+    MEMFAULT_ENABLE_FAULTS ();
 #endif
     have_output = FALSE;
     have_result = FALSE;
@@ -772,7 +772,7 @@ REPEAT:
 
 #if HAVE_MEMFAULT
     if (ctx->malloc_failure &&
-	VALGRIND_COUNT_FAULTS () - last_fault_count > 0 &&
+	MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
 	cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY)
     {
 	goto REPEAT;
@@ -780,7 +780,7 @@ REPEAT:
 #endif
 
     if (cairo_surface_status (surface)) {
-	MF (VALGRIND_PRINT_FAULTS ());
+	MF (MEMFAULT_PRINT_FAULTS ());
 	cairo_test_log (ctx, "Error: Created an error surface\n");
 	ret = CAIRO_TEST_FAILURE;
 	goto UNWIND_STRINGS;
@@ -788,7 +788,7 @@ REPEAT:
 
     /* Check that we created a surface of the expected type. */
     if (cairo_surface_get_type (surface) != target->expected_type) {
-	MF (VALGRIND_PRINT_FAULTS ());
+	MF (MEMFAULT_PRINT_FAULTS ());
 	cairo_test_log (ctx, "Error: Created surface is of type %d (expected %d)\n",
 			cairo_surface_get_type (surface), target->expected_type);
 	ret = CAIRO_TEST_FAILURE;
@@ -801,7 +801,7 @@ REPEAT:
     expected_content = cairo_boilerplate_content (target->content);
 
     if (cairo_surface_get_content (surface) != expected_content) {
-	MF (VALGRIND_PRINT_FAULTS ());
+	MF (MEMFAULT_PRINT_FAULTS ());
 	cairo_test_log (ctx, "Error: Created surface has content %d (expected %d)\n",
 			cairo_surface_get_content (surface), expected_content);
 	ret = CAIRO_TEST_FAILURE;
@@ -856,11 +856,11 @@ REPEAT:
     }
 
 #if HAVE_MEMFAULT
-    VALGRIND_DISABLE_FAULTS ();
+    MEMFAULT_DISABLE_FAULTS ();
 
     /* repeat test after malloc failure injection */
     if (ctx->malloc_failure &&
-	VALGRIND_COUNT_FAULTS () - last_fault_count > 0 &&
+	MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
 	(status == CAIRO_TEST_NO_MEMORY ||
 	 cairo_status (cr) == CAIRO_STATUS_NO_MEMORY ||
 	 cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY))
@@ -874,9 +874,9 @@ REPEAT:
 #if HAVE_FCFINI
 	    FcFini ();
 #endif
-	    if (VALGRIND_COUNT_LEAKS () > 0) {
-		VALGRIND_PRINT_FAULTS ();
-		VALGRIND_PRINT_LEAKS ();
+	    if (MEMFAULT_COUNT_LEAKS () > 0) {
+		MEMFAULT_PRINT_FAULTS ();
+		MEMFAULT_PRINT_LEAKS ();
 	    }
 	}
 
@@ -899,11 +899,11 @@ REPEAT:
     }
 
 #if HAVE_MEMFAULT
-    if (VALGRIND_COUNT_FAULTS () - last_fault_count > 0 &&
-	VALGRIND_HAS_FAULTS ())
+    if (MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
+	MEMFAULT_HAS_FAULTS ())
     {
 	VALGRIND_PRINTF ("Unreported memfaults...");
-	VALGRIND_PRINT_FAULTS ();
+	MEMFAULT_PRINT_FAULTS ();
     }
 #endif
 
@@ -920,18 +920,18 @@ REPEAT:
 	    /* We need to re-enable faults as most meta-surface processing
 	     * is done during cairo_surface_finish().
 	     */
-	    VALGRIND_CLEAR_FAULTS ();
-	    last_fault_count = VALGRIND_COUNT_FAULTS ();
-	    VALGRIND_ENABLE_FAULTS ();
+	    MEMFAULT_CLEAR_FAULTS ();
+	    last_fault_count = MEMFAULT_COUNT_FAULTS ();
+	    MEMFAULT_ENABLE_FAULTS ();
 #endif
 
 	    diff_status = target->finish_surface (surface);
 
 #if HAVE_MEMFAULT
-	    VALGRIND_DISABLE_FAULTS ();
+	    MEMFAULT_DISABLE_FAULTS ();
 
 	    if (ctx->malloc_failure &&
-		VALGRIND_COUNT_FAULTS () - last_fault_count > 0 &&
+		MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
 		diff_status == CAIRO_STATUS_NO_MEMORY)
 	    {
 		cairo_destroy (cr);
@@ -943,9 +943,9 @@ REPEAT:
 #if HAVE_FCFINI
 		    FcFini ();
 #endif
-		    if (VALGRIND_COUNT_LEAKS () > 0) {
-			VALGRIND_PRINT_FAULTS ();
-			VALGRIND_PRINT_LEAKS ();
+		    if (MEMFAULT_COUNT_LEAKS () > 0) {
+			MEMFAULT_PRINT_FAULTS ();
+			MEMFAULT_PRINT_LEAKS ();
 		    }
 		}
 
@@ -1135,7 +1135,7 @@ UNWIND_CAIRO:
 
 #if HAVE_MEMFAULT
     if (ret == CAIRO_TEST_FAILURE && ctx->expectation != CAIRO_TEST_FAILURE)
-	VALGRIND_PRINT_FAULTS ();
+	MEMFAULT_PRINT_FAULTS ();
 #endif
     cairo_destroy (cr);
 UNWIND_SURFACE:
@@ -1152,13 +1152,13 @@ UNWIND_SURFACE:
 	FcFini ();
 #endif
 
-	if (VALGRIND_COUNT_LEAKS () > 0) {
+	if (MEMFAULT_COUNT_LEAKS () > 0) {
 	    if (ret != CAIRO_TEST_FAILURE ||
 		ctx->expectation == CAIRO_TEST_FAILURE)
 	    {
-		VALGRIND_PRINT_FAULTS ();
+		MEMFAULT_PRINT_FAULTS ();
 	    }
-	    VALGRIND_PRINT_LEAKS ();
+	    MEMFAULT_PRINT_LEAKS ();
 	}
     }
 
@@ -1648,7 +1648,7 @@ cairo_test_malloc_failure (const cairo_test_context_t *ctx,
 	int n_faults;
 
 	/* prevent infinite loops... */
-	n_faults = VALGRIND_COUNT_FAULTS ();
+	n_faults = MEMFAULT_COUNT_FAULTS ();
 	if (n_faults == ctx->last_fault_count)
 	    return FALSE;
 
commit c897f36a6b09f3591d858142e3236f256f0bd6a2
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 15 20:37:52 2009 +0100

    [test] Stress the ft from-face cache
    
    Create a set of font faces using the same FT_Face to stress test the
    handling of from-face fonts within the backend cache.

diff --git a/test/ft-font-create-for-ft-face.c b/test/ft-font-create-for-ft-face.c
index 702b846..52c838d 100644
--- a/test/ft-font-create-for-ft-face.c
+++ b/test/ft-font-create-for-ft-face.c
@@ -26,6 +26,84 @@
 #include "cairo-test.h"
 #include <cairo-ft.h>
 
+static void
+_stress_font_cache (FT_Face ft_face, cairo_t *cr, int lvl);
+
+static cairo_font_face_t *
+_load_font (FT_Face ft_face, int flags, cairo_t *cr, int lvl)
+{
+    cairo_font_face_t *font_face;
+    cairo_font_extents_t font_extents;
+
+    _stress_font_cache (ft_face, cr, lvl+1);
+
+    font_face = cairo_ft_font_face_create_for_ft_face (ft_face, flags);
+
+    cairo_set_font_face (cr, font_face);
+    cairo_font_extents (cr, &font_extents);
+
+    _stress_font_cache (ft_face, cr, lvl+1);
+
+    return font_face;
+}
+
+static void
+_stress_font_cache (FT_Face ft_face, cairo_t *cr, int lvl)
+{
+#define A _load_font (ft_face, 0, cr, lvl)
+#define B _load_font (ft_face, FT_LOAD_NO_BITMAP, cr, lvl)
+#define C _load_font (ft_face, FT_LOAD_NO_RECURSE, cr, lvl)
+#define D _load_font (ft_face, FT_LOAD_FORCE_AUTOHINT, cr, lvl)
+
+    cairo_font_face_t *font_face[4];
+
+    while (lvl++ < 5) {
+	font_face[0] = A; font_face[1] = A;
+	font_face[2] = A; font_face[3] = A;
+	cairo_font_face_destroy (font_face[0]);
+	cairo_font_face_destroy (font_face[1]);
+	cairo_font_face_destroy (font_face[2]);
+	cairo_font_face_destroy (font_face[3]);
+
+	font_face[0] = A; font_face[1] = B;
+	font_face[2] = C; font_face[3] = D;
+	cairo_font_face_destroy (font_face[0]);
+	cairo_font_face_destroy (font_face[1]);
+	cairo_font_face_destroy (font_face[2]);
+	cairo_font_face_destroy (font_face[3]);
+
+	font_face[0] = A; font_face[1] = B;
+	font_face[2] = C; font_face[3] = D;
+	cairo_font_face_destroy (font_face[3]);
+	cairo_font_face_destroy (font_face[2]);
+	cairo_font_face_destroy (font_face[1]);
+	cairo_font_face_destroy (font_face[0]);
+
+	font_face[0] = A;
+	font_face[1] = A;
+	cairo_font_face_destroy (font_face[0]);
+	font_face[2] = A;
+	cairo_font_face_destroy (font_face[1]);
+	font_face[3] = A;
+	cairo_font_face_destroy (font_face[2]);
+	cairo_font_face_destroy (font_face[3]);
+
+	font_face[0] = A;
+	font_face[1] = B;
+	cairo_font_face_destroy (font_face[0]);
+	font_face[2] = C;
+	cairo_font_face_destroy (font_face[1]);
+	font_face[3] = D;
+	cairo_font_face_destroy (font_face[2]);
+	cairo_font_face_destroy (font_face[3]);
+    }
+
+#undef A
+#undef B
+#undef C
+#undef D
+}
+
 static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
@@ -48,23 +126,31 @@ draw (cairo_t *cr, int width, int height)
     pattern = FcPatternCreate ();
     if (! pattern) {
 	cairo_test_log (ctx, "FcPatternCreate failed.\n");
-	return CAIRO_TEST_FAILURE;
+	return cairo_test_status_from_status (ctx, CAIRO_STATUS_NO_MEMORY);
     }
 
     FcConfigSubstitute (NULL, pattern, FcMatchPattern);
     FcDefaultSubstitute (pattern);
     resolved = FcFontMatch (NULL, pattern, &result);
     if (! resolved) {
+	FcPatternDestroy (pattern);
 	cairo_test_log (ctx, "FcFontMatch failed.\n");
-	return CAIRO_TEST_FAILURE;
+	return cairo_test_status_from_status (ctx, CAIRO_STATUS_NO_MEMORY);
     }
 
     font_face = cairo_ft_font_face_create_for_pattern (resolved);
+    if (cairo_font_face_status (font_face)) {
+	FcPatternDestroy (resolved);
+	FcPatternDestroy (pattern);
+	return cairo_test_status_from_status (ctx, cairo_font_face_status (font_face));
+    }
 
     if (cairo_font_face_get_type (font_face) != CAIRO_FONT_TYPE_FT) {
 	cairo_test_log (ctx, "Unexpected value from cairo_font_face_get_type: %d (expected %d)\n",
 			cairo_font_face_get_type (font_face), CAIRO_FONT_TYPE_FT);
 	cairo_font_face_destroy (font_face);
+	FcPatternDestroy (resolved);
+	FcPatternDestroy (pattern);
 	return CAIRO_TEST_FAILURE;
     }
 
@@ -81,13 +167,16 @@ draw (cairo_t *cr, int width, int height)
 					    &ctm,
 					    font_options);
 
-    ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
-
     cairo_font_options_destroy (font_options);
     cairo_font_face_destroy (font_face);
     FcPatternDestroy (pattern);
     FcPatternDestroy (resolved);
 
+    if (cairo_scaled_font_status (scaled_font)) {
+	return cairo_test_status_from_status (ctx,
+					      cairo_scaled_font_status (scaled_font));
+    }
+
     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_FT) {
 	cairo_test_log (ctx, "Unexpected value from cairo_scaled_font_get_type: %d (expected %d)\n",
 			cairo_scaled_font_get_type (scaled_font), CAIRO_FONT_TYPE_FT);
@@ -95,7 +184,8 @@ draw (cairo_t *cr, int width, int height)
 	return CAIRO_TEST_FAILURE;
     }
 
-    if (!ft_face) {
+    ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+    if (ft_face == NULL) {
 	cairo_test_log (ctx, "Failed to get an ft_face with cairo_ft_scaled_font_lock_face\n");
 	cairo_scaled_font_destroy (scaled_font);
 	return CAIRO_TEST_FAILURE;
@@ -107,13 +197,18 @@ draw (cairo_t *cr, int width, int height)
      *
      * Now, on to the simple thing we actually want to test.
      */
-    font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+
+    cairo_save (cr);
+
+    /* First we want to test caching behaviour */
+    _stress_font_cache (ft_face, cr, 0);
 
     /* Set the font_face and force cairo to actually use it for
      * something. */
-    cairo_save (cr);
+    font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
     cairo_set_font_face (cr, font_face);
     cairo_font_extents (cr, &font_extents);
+
     cairo_restore (cr);
 
     /* Finally, even more cleanup */
commit 477df1f5504a507d0c5960aa7e21375284a6f99c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 15 10:48:56 2009 +0100

    [test] Clear expected floating point exceptions
    
    test/invalid-matrix deliberately feeds garbage into the API to test our
    error detection. This causes FPE to be raised during the course of the
    test - so they are deliberately disable for the duration. However, the
    exceptions were not being cleared and so the FPE could be triggered on
    the next floating point operation. This was being masked during make check,
    by the fact that each test is run in its own forked process and was only
    observed when multiple tests were run in foreground mode.

diff --git a/build/configure.ac.system b/build/configure.ac.system
index d71d2d0..2ee0cc4 100644
--- a/build/configure.ac.system
+++ b/build/configure.ac.system
@@ -65,7 +65,7 @@ AC_CHECK_HEADERS([sched.h],
 
 dnl check for GNU-extensions to fenv
 AC_CHECK_HEADER(fenv.h,
-	[AC_CHECK_FUNCS(feenableexcept fedisableexcept)])
+	[AC_CHECK_FUNCS(feenableexcept fedisableexcept feclearexcept)])
 
 dnl check for misc headers and functions
 AC_CHECK_HEADERS([libgen.h byteswap.h signal.h setjmp.h])
diff --git a/test/invalid-matrix.c b/test/invalid-matrix.c
index 933e81c..4fbda61 100644
--- a/test/invalid-matrix.c
+++ b/test/invalid-matrix.c
@@ -363,6 +363,10 @@ if ((status) == CAIRO_STATUS_SUCCESS) {							\
     CHECK_STATUS (status, "cairo_rotate(∞)");
     cairo_destroy (cr2);
 
+#if HAVE_FECLEAREXCEPT
+    feclearexcept (FE_INVALID);
+#endif
+
     return CAIRO_TEST_SUCCESS;
 }
 
commit f47a93ef30249b531e588335045d052c3dcc71bd
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat May 9 09:55:49 2009 +0100

    [test] Check text->path with user-fonts (twin)
    
    Check behaviour of user-fonts, twin in particular, when using the text as
    a path.

diff --git a/test/twin.c b/test/twin.c
index b71d97e..08865f0 100644
--- a/test/twin.c
+++ b/test/twin.c
@@ -41,6 +41,15 @@ draw (cairo_t *cr, int width, int height)
     cairo_move_to (cr, 4, 14);
     cairo_show_text (cr, "Is cairo's twin giza?");
 
+    cairo_move_to (cr, 4, 34);
+    cairo_text_path (cr, "Is cairo's twin giza?");
+    cairo_fill (cr);
+
+    cairo_move_to (cr, 4, 54);
+    cairo_text_path (cr, "Is cairo's twin giza?");
+    cairo_set_line_width (cr, 2/16.);
+    cairo_stroke (cr);
+
     return CAIRO_TEST_SUCCESS;
 }
 
@@ -48,5 +57,5 @@ CAIRO_TEST (twin,
 	    "Tests the internal font",
 	    "twin, font", /* keywords */
 	    NULL, /* requirements */
-	    140, 20,
+	    140, 60,
 	    NULL, draw)
diff --git a/test/twin.ps.ref.png b/test/twin.ps.ref.png
index f9374e3..e75062c 100644
Binary files a/test/twin.ps.ref.png and b/test/twin.ps.ref.png differ
diff --git a/test/twin.ref.png b/test/twin.ref.png
index 8bf098c..3c46b02 100644
Binary files a/test/twin.ref.png and b/test/twin.ref.png differ
diff --git a/test/twin.svg.ref.png b/test/twin.svg.ref.png
index 8b4617f..b5d4a31 100644
Binary files a/test/twin.svg.ref.png and b/test/twin.svg.ref.png differ
commit 669e7ae5c98812360bf20b798c20024ae2e9810b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 8 17:36:01 2009 +0100

    [test] Relax APPROX_EQUALS condition
    
    The bounding box of the text is rounded to the nearest pixel boundaries,
    so therefore the test must accept a similar level of imprecision.

diff --git a/test/get-path-extents.c b/test/get-path-extents.c
index 96fdfcc..337dad2 100644
--- a/test/get-path-extents.c
+++ b/test/get-path-extents.c
@@ -74,10 +74,10 @@ check_extents (const cairo_test_context_t *ctx,
         break;
     case APPROX_EQUALS:
         relation_string = "approx. equal";
-        if (floor (ext_x1 + 0.5) == floor (x + 0.5) &&
-	    floor (ext_y1 + 0.5) == floor (y + 0.5) &&
-	    floor (ext_x2 + 0.5) == floor (x + width + 0.5) &&
-	    floor (ext_y2 + 0.5) == floor (y + height + 0.5))
+        if (fabs (ext_x1 - x) < 1. &&
+	    fabs (ext_y1 - y) < 1. &&
+	    fabs (ext_x2 - (x + width))  < 1. &&
+	    fabs (ext_y2 - (y + height)) < 1.)
 	{
             return 1;
 	}
commit fe7410c6cdc19bb366bf1e93481bf8287a14d52e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat May 9 19:01:06 2009 +0100

    [test] Add a note to "Getting the elusive zero failures"
    
    The test suite depends upon many external factors and in order to achieve
    a pass, your system must match that upon which the reference images were
    generated. Add a note to read test/README in case of failures so that the
    casual user is not unduly alarmed by cairo reportedly failing.

diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index 0f437c4..3652a9b 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -64,6 +64,7 @@ typedef struct _cairo_test_runner {
 
     unsigned int num_device_offsets;
 
+    cairo_bool_t passed;
     int num_passed;
     int num_xpassed;
     int num_skipped;
@@ -339,6 +340,8 @@ _runner_init (cairo_test_runner_t *runner)
 {
     cairo_test_init (&runner->base, "cairo-test-suite");
 
+    runner->passed = TRUE;
+
     runner->xpasses_per_target = xcalloc (sizeof (cairo_test_list_t *),
 					  runner->base.num_targets);
     runner->fails_per_target = xcalloc (sizeof (cairo_test_list_t *),
@@ -449,6 +452,13 @@ _runner_print_results (cairo_test_runner_t *runner)
 {
     _runner_print_summary (runner);
     _runner_print_details (runner);
+
+    if (! runner->passed) {
+	_log (&runner->base,
+"\n"
+"Note: These failures may be due to external factors.\n"
+"Please read test/README -- \"Getting the elusive zero failures\".\n");
+    }
 }
 
 static cairo_test_status_t
@@ -856,6 +866,7 @@ main (int argc, char **argv)
 	    targets[len-2] = '\0';
 	    _log (&runner.base, "\n%s: CRASH! (%s)\n", name, targets);
 	    runner.num_crashed++;
+	    runner.passed = FALSE;
 	} else if (failed) {
 	    if (expectation == CAIRO_TEST_SUCCESS) {
 		len = 0;
@@ -878,6 +889,7 @@ main (int argc, char **argv)
 		    targets[len-2] = '\0';
 		    _log (&runner.base, "%s: FAIL (%s)\n", name, targets);
 		    runner.num_failed++;
+		    runner.passed = FALSE;
 		}
 	    } else {
 		_log (&runner.base, "%s: XFAIL\n", name);
commit 2f962799a77faef0e6ad62c79bd7eebc9b8c5a4b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 15 18:49:03 2009 +0100

    [test] Fix typos that excluded backend test sources

diff --git a/test/Makefile.am b/test/Makefile.am
index efac53f..ef2d875 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -13,16 +13,16 @@ test_sources += $(pthread_test_sources)
 endif
 
 if CAIRO_HAS_FT_FONT
-test_sources += $(ft_font_sources)
+test_sources += $(ft_font_test_sources)
 endif
 
 # Need to add quartz-surface-source
 if CAIRO_HAS_QUARTZ_SURFACE
-test_sources += $(quartz_surface_sources)
+test_sources += $(quartz_surface_test_sources)
 endif
 
 if CAIRO_HAS_GLITZ_SURFACE
-test_sources += $(glitz_surface_sources)
+test_sources += $(glitz_surface_test_sources)
 endif
 
 if CAIRO_HAS_PDF_SURFACE
commit c25992479aca481d326f72665ebdcf0904273eac
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat May 9 10:10:14 2009 +0100

    [xlib] Use minimal depth for similar clones.
    
    Damian Frank noted
    [http://lists.cairographics.org/archives/cairo/2009-May/017095.html]
    a performance problem with an older XServer with an
    unaccelerated composite - similar problems will be seen with non-XRender
    servers which will trigger extraneous fallbacks. The problem he found was
    that painting an ARGB32 image onto an RGB24 destination window (using
    SOURCE) was going via the RENDER protocol and not core. He was able to
    demonstrate that this could be worked around by declaring the pixel data as
    an RGB24 image. The issue is that the image is uploaded into a temporary
    pixmap of matching depth (i.e. 32 bit for ARGB32 and 24 bit for RGB23
    data), however the core protocol can only blit between Drawables of
    matching depth - so without the work-around the Drawables are mismatched
    and we either need to use RENDER or fallback.
    
    This patch adds a content mask to _cairo_surface_clone_similar() to
    provide the extra bit of information to the backends for when it is
    possible for them to drop channels from the clone. This is used by the
    xlib backend to only create a 24 bit source when blitting to a Window.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 7066b93..bb04a9e 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -772,6 +772,7 @@ _cairo_clip_init_deep_copy (cairo_clip_t    *clip,
         if (other->surface) {
 	    int dx, dy;
             status = _cairo_surface_clone_similar (target, other->surface,
+						   CAIRO_CONTENT_ALPHA,
 					           0,
 						   0,
 						   other->surface_rect.width,
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 3eee33c..df9c0e9 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -617,6 +617,7 @@ _cairo_directfb_surface_release_dest_image (void                  *abstract_surf
 static cairo_status_t
 _cairo_directfb_surface_clone_similar (void             *abstract_surface,
                                        cairo_surface_t  *src,
+				       cairo_content_t	 content,
                                        int               src_x,
                                        int               src_y,
                                        int               width,
@@ -763,6 +764,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t    *dst,
     }
 
     status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+					     CAIRO_CONTENT_COLOR_ALPHA,
 					     *src_x, *src_y, width, height,
 					     (cairo_surface_t **) &src,
 					     &src_attr);
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 284198b..9ee8a88 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -352,6 +352,7 @@ _cairo_glitz_surface_release_dest_image (void                    *abstract_surfa
 static cairo_status_t
 _cairo_glitz_surface_clone_similar (void	    *abstract_surface,
 				    cairo_surface_t *src,
+				    cairo_content_t  content,
 				    int              src_x,
 				    int              src_y,
 				    int              width,
@@ -716,6 +717,7 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t	       *pattern,
 	cairo_int_status_t status;
 
 	status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+						 CAIRO_CONTENT_COLOR_ALPHA,
 						 x, y, width, height,
 						 (cairo_surface_t **) &src,
 						 &attr->base);
@@ -2133,6 +2135,7 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
 		status =
 		    _cairo_glitz_surface_clone_similar (abstract_surface,
 							image,
+							CAIRO_CONTENT_COLOR_ALPHA,
 							0,
 							0,
 							glyph_width,
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index a027f72..cf23393 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -784,6 +784,7 @@ _cairo_image_surface_release_dest_image (void                    *abstract_surfa
 static cairo_status_t
 _cairo_image_surface_clone_similar (void		*abstract_surface,
 				    cairo_surface_t	*src,
+				    cairo_content_t	 content,
 				    int                  src_x,
 				    int                  src_y,
 				    int                  width,
@@ -962,6 +963,7 @@ _cairo_image_surface_composite (cairo_operator_t	op,
 
     status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
 					      &dst->base,
+					      CAIRO_CONTENT_COLOR_ALPHA,
 					      src_x, src_y,
 					      mask_x, mask_y,
 					      width, height,
@@ -1164,6 +1166,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
     }
 
     status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+					     CAIRO_CONTENT_COLOR_ALPHA,
 					     src_x, src_y, width, height,
 					     (cairo_surface_t **) &src,
 					     &attributes);
@@ -1398,6 +1401,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t	 op,
 
     status = _cairo_pattern_acquire_surface (
 	renderer->pattern, &renderer->dst->base,
+	CAIRO_CONTENT_COLOR_ALPHA,
 	rects->src.x, rects->src.y,
 	width, height,
 	(cairo_surface_t **) &renderer->src,
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 0fb36bf..67447a5 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1256,6 +1256,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
     pixman_transform_t	  pixman_transform;
     cairo_status_t	  status;
     cairo_bool_t	  repeat = FALSE;
+    cairo_bool_t          opaque = TRUE;
 
     pixman_gradient_stop_t pixman_stops_static[2];
     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
@@ -1279,6 +1280,8 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
 	pixman_stops[i].color.green = pattern->stops[i].color.green_short;
 	pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
 	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
+	if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (pixman_stops[i].color.alpha))
+	    opaque = FALSE;
     }
 
     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
@@ -1450,6 +1453,9 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
     pixman_image_unref (pixman_image);
 
     status = _cairo_surface_clone_similar (dst, &image->base,
+					   opaque ?
+					   CAIRO_CONTENT_COLOR :
+					   CAIRO_CONTENT_COLOR_ALPHA,
 					   0, 0, width, height,
 					   &clone_offset_x,
 					   &clone_offset_y,
@@ -1781,6 +1787,7 @@ _pixman_nearest_sample (double d)
 static cairo_int_status_t
 _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pattern,
 					    cairo_surface_t	       *dst,
+					    cairo_content_t	    content,
 					    int			       x,
 					    int			       y,
 					    unsigned int	       width,
@@ -1855,7 +1862,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pat
 	if (unlikely (status))
 	    goto BAIL;
 
-	status = _cairo_surface_clone_similar (dst, surface,
+	status = _cairo_surface_clone_similar (dst, surface, content,
 					       extents.x, extents.y,
 					       extents.width, extents.height,
 					       &extents.x, &extents.y, &src);
@@ -1978,7 +1985,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pat
 
     /* XXX can we use is_empty? */
 
-    status = _cairo_surface_clone_similar (dst, surface,
+    status = _cairo_surface_clone_similar (dst, surface, content,
 					   extents.x, extents.y,
 					   extents.width, extents.height,
 					   &x, &y, out);
@@ -2052,6 +2059,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pat
 cairo_int_status_t
 _cairo_pattern_acquire_surface (const cairo_pattern_t	   *pattern,
 				cairo_surface_t		   *dst,
+				cairo_content_t		    content,
 				int			   x,
 				int			   y,
 				unsigned int		   width,
@@ -2144,6 +2152,7 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t	   *pattern,
 	cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
 
 	status = _cairo_pattern_acquire_surface_for_surface (src, dst,
+							     content,
 							     x, y, width, height,
 							     surface_out,
 							     attributes);
@@ -2176,6 +2185,7 @@ cairo_int_status_t
 _cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
 				 const cairo_pattern_t	    *mask,
 				 cairo_surface_t	    *dst,
+				 cairo_content_t	    src_content,
 				 int			    src_x,
 				 int			    src_y,
 				 int			    mask_x,
@@ -2212,13 +2222,14 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
 	_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
 
 	_cairo_pattern_init_solid (&src_tmp.solid, &combined,
-				   src_solid->content | mask_solid->content);
+				   (src_solid->content | mask_solid->content) & src_content);
 
 	src = &src_tmp.base;
 	mask = NULL;
     }
 
     status = _cairo_pattern_acquire_surface (src, dst,
+					     src_content,
 					     src_x, src_y,
 					     width, height,
 					     src_out, src_attributes);
@@ -2231,6 +2242,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
     }
 
     status = _cairo_pattern_acquire_surface (mask, dst,
+					     CAIRO_CONTENT_ALPHA,
 					     mask_x, mask_y,
 					     width, height,
 					     mask_out, mask_attributes);
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index c827f97..982ede4 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1598,6 +1598,7 @@ _cairo_quartz_surface_create_similar (void *abstract_surface,
 static cairo_status_t
 _cairo_quartz_surface_clone_similar (void *abstract_surface,
 				     cairo_surface_t *src,
+				     cairo_content_t  content,
 				     int              src_x,
 				     int              src_y,
 				     int              width,
diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h
index 61e5b90..cd18178 100644
--- a/src/cairo-surface-fallback-private.h
+++ b/src/cairo-surface-fallback-private.h
@@ -121,6 +121,7 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t		op,
 cairo_private cairo_status_t
 _cairo_surface_fallback_clone_similar (cairo_surface_t  *surface,
 				       cairo_surface_t  *src,
+				       cairo_content_t	 content,
 				       int               src_x,
 				       int               src_y,
 				       int               width,
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 9019102..469e9b3 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -1336,6 +1336,7 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t		op,
 cairo_status_t
 _cairo_surface_fallback_clone_similar (cairo_surface_t	*surface,
 				       cairo_surface_t	*src,
+				       cairo_content_t	 content,
 				       int		 src_x,
 				       int		 src_y,
 				       int		 width,
@@ -1349,7 +1350,7 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t	*surface,
     cairo_status_t status;
 
     new_surface = _cairo_surface_create_similar_scratch (surface,
-							 src->content,
+							 src->content & content,
 							 width, height);
     if (new_surface->status)
 	return new_surface->status;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 42b101a..26a7a13 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1268,6 +1268,7 @@ _cairo_surface_release_dest_image (cairo_surface_t         *surface,
  * _cairo_surface_clone_similar:
  * @surface: a #cairo_surface_t
  * @src: the source image
+ * @content: target content mask
  * @src_x: extent for the rectangle in src we actually care about
  * @src_y: extent for the rectangle in src we actually care about
  * @width: extent for the rectangle in src we actually care about
@@ -1287,6 +1288,7 @@ _cairo_surface_release_dest_image (cairo_surface_t         *surface,
 cairo_status_t
 _cairo_surface_clone_similar (cairo_surface_t  *surface,
 			      cairo_surface_t  *src,
+			      cairo_content_t	content,
 			      int               src_x,
 			      int               src_y,
 			      int               width,
@@ -1307,6 +1309,7 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 
     if (surface->backend->clone_similar) {
 	status = surface->backend->clone_similar (surface, src,
+						  content,
 						  src_x, src_y,
 						  width, height,
 						  clone_offset_x,
@@ -1319,7 +1322,7 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 		cairo_surface_t *similar;
 
 		similar = cairo_surface_create_similar (surface,
-							src->content,
+							src->content & content,
 							width, height);
 		status = similar->status;
 		if (unlikely (status))
@@ -1344,6 +1347,7 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 	    if (status == CAIRO_STATUS_SUCCESS) {
 		status =
 		    surface->backend->clone_similar (surface, &image->base,
+						     content,
 						     src_x, src_y,
 						     width, height,
 						     clone_offset_x,
@@ -1359,6 +1363,7 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
 	status =
 	    _cairo_surface_fallback_clone_similar (surface, src,
+						   content,
 						   src_x, src_y,
 						   width, height,
 						   clone_offset_x,
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 649a96b..389515b 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -431,6 +431,7 @@ _cairo_win32_surface_create_similar (void	    *abstract_src,
 cairo_status_t
 _cairo_win32_surface_clone_similar (void *abstract_surface,
 				    cairo_surface_t *src,
+				    cairo_content_t content,
 				    int src_x,
 				    int src_y,
 				    int width,
@@ -444,7 +445,7 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
     cairo_status_t status;
     cairo_surface_pattern_t pattern;
 
-    src_content = cairo_surface_get_content(src);
+    src_content = src->content & content;
     new_surface =
 	_cairo_win32_surface_create_similar_internal (abstract_surface,
 						      src_content,
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 8d0090b..c21e600 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -671,6 +671,7 @@ _cairo_xcb_surface_same_screen (cairo_xcb_surface_t *dst,
 static cairo_status_t
 _cairo_xcb_surface_clone_similar (void			*abstract_surface,
 				  cairo_surface_t	*src,
+				  cairo_content_t	 content,
 				  int                    src_x,
 				  int                    src_y,
 				  int                    width,
@@ -1119,6 +1120,7 @@ _cairo_xcb_surface_composite (cairo_operator_t		op,
 
     status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
 					      &dst->base,
+					      CAIRO_CONTENT_COLOR_ALPHA,
 					      src_x, src_y,
 					      mask_x, mask_y,
 					      width, height,
@@ -1407,6 +1409,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t	op,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+					     CAIRO_CONTENT_COLOR_ALPHA,
 					     src_x, src_y, width, height,
 					     (cairo_surface_t **) &src,
 					     &attributes);
@@ -2499,6 +2502,7 @@ _cairo_xcb_surface_show_glyphs (void			*abstract_dst,
 
     if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
         status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+						 CAIRO_CONTENT_COLOR_ALPHA,
                                                  0, 0, 1, 1,
                                                  (cairo_surface_t **) &src,
                                                  &attributes);
@@ -2513,6 +2517,7 @@ _cairo_xcb_surface_show_glyphs (void			*abstract_dst,
 	    goto BAIL;
 
         status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+						 CAIRO_CONTENT_COLOR_ALPHA,
                                                  glyph_extents.x, glyph_extents.y,
                                                  glyph_extents.width, glyph_extents.height,
                                                  (cairo_surface_t **) &src,
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index b56b340..bbbdc4b 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -950,10 +950,10 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
     ximage.blue_mask = surface->b_mask;
     ximage.xoffset = 0;
 
-    if (image_masks.alpha_mask == surface->a_mask &&
-	image_masks.red_mask   == surface->r_mask &&
-	image_masks.green_mask == surface->g_mask &&
-	image_masks.blue_mask  == surface->b_mask)
+    if ((image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
+	(image_masks.red_mask   == surface->r_mask || surface->r_mask == 0) &&
+	(image_masks.green_mask == surface->g_mask || surface->g_mask == 0) &&
+	(image_masks.blue_mask  == surface->b_mask || surface->b_mask == 0))
     {
 	int ret;
 
@@ -1169,6 +1169,7 @@ _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
 static cairo_status_t
 _cairo_xlib_surface_clone_similar (void			*abstract_surface,
 				   cairo_surface_t	*src,
+				   cairo_content_t	 content,
 				   int                   src_x,
 				   int                   src_y,
 				   int                   width,
@@ -1201,8 +1202,11 @@ _cairo_xlib_surface_clone_similar (void			*abstract_surface,
 	    return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
 
 	format = image_src->format;
-	if (format == CAIRO_FORMAT_INVALID)
-	    format = _cairo_format_from_content (image_src->base.content);
+	if (format == CAIRO_FORMAT_INVALID ||
+	    (_cairo_content_from_format (format) & ~content))
+	{
+	    format = _cairo_format_from_content (image_src->base.content & content);
+	}
 	clone = (cairo_xlib_surface_t *)
 	    _cairo_xlib_surface_create_similar_with_format (surface,
 							    format,
@@ -1508,14 +1512,15 @@ _surface_has_alpha (cairo_xlib_surface_t *surface)
  */
 static cairo_bool_t
 _operator_needs_alpha_composite (cairo_operator_t op,
-				 cairo_bool_t     surface_has_alpha)
+				 cairo_bool_t     destination_has_alpha,
+				 cairo_bool_t     source_has_alpha)
 {
     if (op == CAIRO_OPERATOR_SOURCE ||
-	(!surface_has_alpha &&
+	(! source_has_alpha &&
 	 (op == CAIRO_OPERATOR_OVER ||
 	  op == CAIRO_OPERATOR_ATOP ||
 	  op == CAIRO_OPERATOR_IN)))
-	return FALSE;
+	return destination_has_alpha;
 
     return TRUE;
 }
@@ -1624,7 +1629,9 @@ _recategorize_composite_operation (cairo_xlib_surface_t	      *dst,
 	return DO_UNSUPPORTED;
 
     needs_alpha_composite =
-	_operator_needs_alpha_composite (op, _surface_has_alpha (src));
+	_operator_needs_alpha_composite (op,
+					 _surface_has_alpha (dst),
+					 _surface_has_alpha (src));
 
     if (! have_mask &&
 	is_integer_translation &&
@@ -1721,6 +1728,8 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
     composite_operation_t       operation;
     int				itx, ity;
     cairo_bool_t		is_integer_translation;
+    cairo_bool_t		needs_alpha_composite;
+    cairo_content_t		src_content;
 
     _cairo_xlib_display_notify (dst->display);
 
@@ -1729,8 +1738,17 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
     if (operation == DO_UNSUPPORTED)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    needs_alpha_composite =
+	_operator_needs_alpha_composite (op,
+					 _surface_has_alpha (dst),
+					 ! _cairo_pattern_is_opaque (src_pattern));
+    src_content = CAIRO_CONTENT_COLOR_ALPHA;
+    if (! needs_alpha_composite)
+	src_content &= ~CAIRO_CONTENT_ALPHA;
+
     status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
 					      &dst->base,
+					      src_content,
 					      src_x, src_y,
 					      mask_x, mask_y,
 					      width, height,
@@ -1892,6 +1910,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
         return status;
 
     status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
+					     CAIRO_CONTENT_COLOR_ALPHA,
 					     0, 0,
 					     ARRAY_LENGTH (dither_pattern[0]),
 					     ARRAY_LENGTH (dither_pattern),
@@ -2142,6 +2161,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t	op,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+					     CAIRO_CONTENT_COLOR_ALPHA,
 					     src_x, src_y, width, height,
 					     (cairo_surface_t **) &src,
 					     &attributes);
@@ -4071,6 +4091,7 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
 
     if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
         status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+						 CAIRO_CONTENT_COLOR_ALPHA,
                                                  0, 0, 1, 1,
                                                  (cairo_surface_t **) &src,
                                                  &attributes);
@@ -4087,6 +4108,7 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
 	    goto BAIL0;
 
         status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+						 CAIRO_CONTENT_COLOR_ALPHA,
                                                  glyph_extents.x, glyph_extents.y,
                                                  glyph_extents.width, glyph_extents.height,
                                                  (cairo_surface_t **) &src,
diff --git a/src/cairoint.h b/src/cairoint.h
index 29b8ea6..fc51d60 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -591,6 +591,7 @@ struct _cairo_surface_backend {
     cairo_warn cairo_status_t
     (*clone_similar)            (void                   *surface,
 				 cairo_surface_t        *src,
+				 cairo_content_t	 content,
 				 int                     src_x,
 				 int                     src_y,
 				 int                     width,
@@ -1963,6 +1964,7 @@ _cairo_surface_release_dest_image (cairo_surface_t        *surface,
 cairo_private cairo_status_t
 _cairo_surface_clone_similar (cairo_surface_t  *surface,
 			      cairo_surface_t  *src,
+			      cairo_content_t	content,
 			      int               src_x,
 			      int               src_y,
 			      int               width,
@@ -2482,6 +2484,7 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern);
 cairo_private cairo_int_status_t
 _cairo_pattern_acquire_surface (const cairo_pattern_t	   *pattern,
 				cairo_surface_t		   *dst,
+				cairo_content_t		    content,
 				int			   x,
 				int			   y,
 				unsigned int		   width,
@@ -2498,6 +2501,7 @@ cairo_private cairo_int_status_t
 _cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
 				 const cairo_pattern_t	    *mask,
 				 cairo_surface_t	    *dst,
+				 cairo_content_t	    src_content,
 				 int			    src_x,
 				 int			    src_y,
 				 int			    mask_x,
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index 8acd91e..2a7f148 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -172,6 +172,7 @@ _test_fallback_surface_release_dest_image (void			   *abstract_surface,
 static cairo_status_t
 _test_fallback_surface_clone_similar (void		  *abstract_surface,
 				      cairo_surface_t     *src,
+				      cairo_content_t      content,
 				      int                  src_x,
 				      int                  src_y,
 				      int                  width,
diff --git a/src/test-fallback16-surface.c b/src/test-fallback16-surface.c
index 7974c1f..07c0610 100644
--- a/src/test-fallback16-surface.c
+++ b/src/test-fallback16-surface.c
@@ -166,6 +166,7 @@ _test_fallback16_surface_release_dest_image (void			   *abstract_surface,
 static cairo_status_t
 _test_fallback16_surface_clone_similar (void		  *abstract_surface,
 					cairo_surface_t     *src,
+					cairo_content_t	     content,
 					int                  src_x,
 					int                  src_y,
 					int                  width,
@@ -184,6 +185,7 @@ _test_fallback16_surface_clone_similar (void		  *abstract_surface,
 	return CAIRO_STATUS_SUCCESS;
     } else {
 	return _cairo_surface_clone_similar (surface->backing, src,
+					     content,
 					     src_x, src_y,
 					     width, height,
 					     clone_offset_x, clone_offset_y,
diff --git a/test/surface-source.c b/test/surface-source.c
index 0906924..5d978f2 100644
--- a/test/surface-source.c
+++ b/test/surface-source.c
@@ -102,6 +102,7 @@ draw (cairo_t *cr, int width, int height)
 			      (height - INTER_SIZE)/2);
     cairo_destroy (cr2);
     cairo_rectangle (cr, 15, 15, 60, 60);
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
     cairo_fill (cr);
 
     /* destroy the surface last, as this triggers XCloseDisplay */
commit 0238fe2cafea2e1ed19bb222117bd73ee6898d4d
Author: Karl Tomlinson <karlt+ at karlt.net>
Date:   Thu May 14 11:46:29 2009 +0100

    [ft] Resolve mutual referencing problems with zombie faces
    
    Bug 21706 -- zombie ft_font_face / ft_unscaled_font mutual
                 referencing problems
    [http://bugs.freedesktop.org/show_bug.cgi?id=21706]
    
    There can be more than one zombie font_face belonging to an unscaled_font,
    but only the first is destroyed.  This leaks the client's FT_Face
    (and associated font data) as release of the FT_Face depends on release
    of the font_face.
    
    (The reason why Firefox ends up with two different font_faces for one
    unscaled_font is that load_flags for faces with artificial oblique have
    FT_LOAD_NO_BITMAP set.
    https://bugzilla.mozilla.org/show_bug.cgi?id=486974)
    
    Also it's possible for _cairo_ft_font_face_create to pull out a zombie
    font_face from the unscaled_font, which would crash
    _cairo_ft_font_face_scaled_font_create, as that expects non-null
    font_face->unscaled (if !font-face->pattern).

diff --git a/AUTHORS b/AUTHORS
index 289fecb..8c06174 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -86,7 +86,7 @@ Travis Spencer <tspencer at cs.pdx.edu> XCB backend fix
 Bill Spitzak <spitzak at d2.com> Build fix to find Xrender.h without xrender.pc
 Zhe Su <james.su at gmail.com> Add support for fontconfig's embeddedbitmap option
 Owen Taylor <otaylor at redhat.com> Font rewrite, documentation, win32 backend
-Karl Tomlinson <karlt+ at karlt.net>
+Karl Tomlinson <karlt+ at karlt.net> Optimisation and obscure bug fixes (mozilla)
 Alp Toker <alp at atoker.com> Fix several code/comment typos
 Malcolm Tredinnick <malcolm at commsecure.com.au> Documentation fixes
 David Turner <david at freetype.org> Optimize gradient calculations
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 1e2a18e..f9ff0b1 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -543,8 +543,10 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font)
 	/* See comments in _ft_font_face_destroy about the "zombie" state
 	 * for a _ft_font_face.
 	 */
-	if (unscaled->faces && !unscaled->faces->unscaled)
+	if (unscaled->faces && unscaled->faces->unscaled == NULL) {
+	    assert (unscaled->faces->next == NULL);
 	    cairo_font_face_destroy (&unscaled->faces->base);
+	}
     } else {
 	_font_map_release_face_lock_held (font_map, unscaled);
     }
@@ -2233,9 +2235,10 @@ _cairo_ft_font_face_destroy (void *abstract_face)
     if (font_face == NULL)
 	return;
 
-    /* When destroying the face created by cairo_ft_font_face_create_for_ft_face,
+    /* When destroying a face created by cairo_ft_font_face_create_for_ft_face,
      * we have a special "zombie" state for the face when the unscaled font
-     * is still alive but there are no public references to the font face.
+     * is still alive but there are no other references to a font face with
+     * the same FT_Face.
      *
      * We go from:
      *
@@ -2249,6 +2252,8 @@ _cairo_ft_font_face_destroy (void *abstract_face)
 
     if (font_face->unscaled &&
 	font_face->unscaled->from_face &&
+	font_face->next == NULL &&
+	font_face->unscaled->faces == font_face &&
 	CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count) > 1)
     {
 	cairo_font_face_reference (&font_face->base);
@@ -2394,12 +2399,21 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
 	    font_face->ft_options.extra_flags == ft_options->extra_flags &&
 	    cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base))
 	{
-	    if (font_face->base.status == CAIRO_STATUS_SUCCESS)
-		return cairo_font_face_reference (&font_face->base);
+	    if (font_face->base.status) {
+		/* The font_face has been left in an error state, abandon it. */
+		*prev_font_face = font_face->next;
+		break;
+	    }
 
-	    /* The font_face has been left in an error state, abandon it. */
-	    *prev_font_face = font_face->next;
-	    break;
+	    if (font_face->unscaled == NULL) {
+		/* Resurrect this "zombie" font_face (from
+		 * _cairo_ft_font_face_destroy), switching its unscaled_font
+		 * from owner to ownee. */
+		font_face->unscaled = unscaled;
+		_cairo_unscaled_font_reference (&unscaled->base);
+		return &font_face->base;
+	    } else
+		return cairo_font_face_reference (&font_face->base);
 	}
     }
 
@@ -2415,6 +2429,14 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
 
     font_face->ft_options = *ft_options;
 
+    if (unscaled->faces && unscaled->faces->unscaled == NULL) {
+	/* This "zombie" font_face (from _cairo_ft_font_face_destroy)
+	 * is no longer needed. */
+	assert (unscaled->from_face && unscaled->faces->next == NULL);
+	cairo_font_face_destroy (&unscaled->faces->base);
+	unscaled->faces = NULL;
+    }
+
     font_face->next = unscaled->faces;
     unscaled->faces = font_face;
 
commit d6f6ec9082c86b9fd9e2389b9627f08a91c2cdd3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 8 16:43:43 2009 +0100

    [ft] Restore the ability to lazily resolve patterns.
    
    I broke the ability for the ft font backend to resolve patterns whilst
    fixing the font creation to propagate the error status from fontconfig
    (be27e8). By adjusting the sequence of error checks we do not confuse
    the absence of a match with a fatal error and thereby restoring the
    lazy pattern resolution whilst ensuring error propagation.

diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index e701c21..1e2a18e 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -482,24 +482,26 @@ _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern,
     FcResult ret;
 
     ret = FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face);
-    switch ((int) ret) {
-    case FcResultMatch:
+    if (ret == FcResultMatch)
+	goto DONE;
+    if (ret == FcResultOutOfMemory)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    ret = FcPatternGetString (pattern, FC_FILE, 0, (FcChar8 **) &filename);
+    if (ret == FcResultOutOfMemory)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    if (ret == FcResultMatch) {
+	/* If FC_INDEX is not set, we just use 0 */
+	ret = FcPatternGetInteger (pattern, FC_INDEX, 0, &id);
+	if (ret == FcResultOutOfMemory)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
 	goto DONE;
-    case FcResultOutOfMemory:
-	break;
-    default:
-	if (FcPatternGetString (pattern, FC_FILE, 0,
-				(FcChar8 **) &filename) == FcResultMatch)
-	{
-	    /* If FC_INDEX is not set, we just use 0 */
-	    if (FcPatternGetInteger (pattern,
-				     FC_INDEX, 0, &id) != FcResultOutOfMemory)
-		goto DONE;
-	}
-	break;
     }
 
-    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    /* The pattern contains neither a face nor a filename, resolve it later. */
+    *out = NULL;
+    return CAIRO_STATUS_SUCCESS;
 
 DONE:
     return _cairo_ft_unscaled_font_create_internal (font_face != NULL,


More information about the cairo-commit mailing list