[cairo-commit] 10 commits - boilerplate/make-cairo-boilerplate-constructors.c boilerplate/make-cairo-boilerplate-constructors.sh boilerplate/Makefile.am build/configure.ac.system build/configure.ac.tools configure.ac perf/box-outline.c perf/cairo-perf.c perf/cairo-perf.h perf/cairo-perf-report.c perf/composite-checker.c perf/dragon.c perf/fill.c perf/glyphs.c perf/intersections.c perf/long-dashed-lines.c perf/long-lines.c perf/mask.c perf/mosaic.c perf/paint.c perf/paint-with-alpha.c perf/pattern_create_radial.c perf/pythagoras-tree.c perf/rectangles.c perf/rounded-rectangles.c perf/spiral.c perf/stroke.c perf/subimage_copy.c perf/tessellate.c perf/text.c perf/twin.c perf/unaligned-clip.c perf/world-map.c perf/zrusin.c src/cairo-directfb-surface.c src/cairoint.h src/cairo-matrix.c src/cairo-path-fixed.c src/cairo-pattern.c src/cairo-surface.c test/make-cairo-test-constructors.c test/make-cairo-test-constructors.sh test/Makefile.am

Chris Wilson ickle at kemper.freedesktop.org
Thu Aug 6 02:21:58 PDT 2009


 boilerplate/Makefile.am                            |   17 --
 boilerplate/make-cairo-boilerplate-constructors.c  |  163 ---------------------
 boilerplate/make-cairo-boilerplate-constructors.sh |   24 +++
 build/configure.ac.system                          |   10 +
 build/configure.ac.tools                           |    8 -
 configure.ac                                       |    1 
 perf/box-outline.c                                 |   14 +
 perf/cairo-perf-report.c                           |    4 
 perf/cairo-perf.c                                  |   39 +++--
 perf/cairo-perf.h                                  |    2 
 perf/composite-checker.c                           |   22 +-
 perf/dragon.c                                      |  142 +++++++++---------
 perf/fill.c                                        |   21 +-
 perf/glyphs.c                                      |   32 ++--
 perf/intersections.c                               |   81 ++++++++--
 perf/long-dashed-lines.c                           |    9 -
 perf/long-lines.c                                  |   68 ++++----
 perf/mask.c                                        |   45 +++--
 perf/mosaic.c                                      |   38 ++--
 perf/paint-with-alpha.c                            |    5 
 perf/paint.c                                       |    5 
 perf/pattern_create_radial.c                       |   24 +--
 perf/pythagoras-tree.c                             |   20 +-
 perf/rectangles.c                                  |   38 ++--
 perf/rounded-rectangles.c                          |   47 ++++--
 perf/spiral.c                                      |   51 +++---
 perf/stroke.c                                      |   19 +-
 perf/subimage_copy.c                               |    7 
 perf/tessellate.c                                  |   17 +-
 perf/text.c                                        |   27 +--
 perf/twin.c                                        |   29 ++-
 perf/unaligned-clip.c                              |   37 ++--
 perf/world-map.c                                   |   78 +++++-----
 perf/zrusin.c                                      |   10 -
 src/cairo-directfb-surface.c                       |    4 
 src/cairo-matrix.c                                 |    4 
 src/cairo-path-fixed.c                             |   31 +++
 src/cairo-pattern.c                                |    4 
 src/cairo-surface.c                                |    8 +
 src/cairoint.h                                     |    7 
 test/Makefile.am                                   |   11 -
 test/make-cairo-test-constructors.c                |  162 --------------------
 test/make-cairo-test-constructors.sh               |   24 +++
 43 files changed, 668 insertions(+), 741 deletions(-)

New commits:
commit a439bd99d0439c007bc74584c1eb56700c520b52
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Aug 5 17:34:29 2009 +0100

    [perf] Compare drawing random curves
    
    Extend the intersection tests with straight lines, with random curves as
    well.

diff --git a/perf/intersections.c b/perf/intersections.c
index f35e090..7a7cc55 100644
--- a/perf/intersections.c
+++ b/perf/intersections.c
@@ -43,9 +43,9 @@ static cairo_perf_ticks_t
 draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule,
 	     int width, int height, int loops)
 {
-    int i;
     double x[NUM_SEGMENTS];
     double y[NUM_SEGMENTS];
+    int i;
 
     cairo_save (cr);
     cairo_set_source_rgb (cr, 0, 0, 0);
@@ -77,6 +77,47 @@ draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule,
 }
 
 static cairo_perf_ticks_t
+draw_random_curve (cairo_t *cr, cairo_fill_rule_t fill_rule,
+		   int width, int height, int loops)
+{
+    double x[3*NUM_SEGMENTS];
+    double y[3*NUM_SEGMENTS];
+    int i;
+
+    cairo_save (cr);
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_paint (cr);
+
+    for (i = 0; i < 3*NUM_SEGMENTS; i++) {
+         x[i] = uniform_random (0, width);
+         y[i] = uniform_random (0, height);
+    }
+
+    state = 0x12345678;
+    cairo_translate (cr, 1, 1);
+    cairo_set_fill_rule (cr, fill_rule);
+    cairo_set_source_rgb (cr, 1, 0, 0);
+
+    cairo_move_to (cr, 0, 0);
+    for (i = 0; i < NUM_SEGMENTS; i++) {
+	cairo_curve_to (cr,
+			x[3*i+0], y[3*i+0],
+			x[3*i+1], y[3*i+1],
+			x[3*i+2], y[3*i+2]);
+    }
+    cairo_close_path (cr);
+
+    cairo_perf_timer_start ();
+    while (loops--)
+        cairo_fill_preserve (cr);
+    cairo_perf_timer_stop ();
+
+    cairo_restore (cr);
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_perf_ticks_t
 random_eo (cairo_t *cr, int width, int height, int loops)
 {
     return draw_random (cr, CAIRO_FILL_RULE_EVEN_ODD, width, height, loops);
@@ -88,6 +129,18 @@ random_nz (cairo_t *cr, int width, int height, int loops)
     return draw_random (cr, CAIRO_FILL_RULE_WINDING, width, height, loops);
 }
 
+static cairo_perf_ticks_t
+random_curve_eo (cairo_t *cr, int width, int height, int loops)
+{
+    return draw_random_curve (cr, CAIRO_FILL_RULE_EVEN_ODD, width, height, loops);
+}
+
+static cairo_perf_ticks_t
+random_curve_nz (cairo_t *cr, int width, int height, int loops)
+{
+    return draw_random_curve (cr, CAIRO_FILL_RULE_WINDING, width, height, loops);
+}
+
 void
 intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
@@ -96,4 +149,7 @@ intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 
     cairo_perf_run (perf, "intersections-nz-fill", random_nz);
     cairo_perf_run (perf, "intersections-eo-fill", random_eo);
+
+    cairo_perf_run (perf, "intersections-nz-curve-fill", random_curve_nz);
+    cairo_perf_run (perf, "intersections-eo-curve-fill", random_curve_eo);
 }
commit 1327df2cf2f2dd9f98533d824503dfb081803b05
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Aug 4 20:15:13 2009 +0100

    [pattern] Invalid access beyond end of freed-pool
    
    Oops, we were attempting to return a pointer from beyond the end of our
    array.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 6eabaa4..4303106 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -511,7 +511,9 @@ _freed_pattern_put (freed_pool_t *pool,
 {
     int i = pool->top;
 
-    if (_atomic_store (&pool->pool[i], pattern)) {
+    if (i < ARRAY_LENGTH (pool->pool) &&
+	_atomic_store (&pool->pool[i], pattern))
+    {
 	pool->top = i + 1;
 	return;
     }
commit 920f59a755ce142b068f21b9db07f76f35449f16
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Aug 4 20:13:43 2009 +0100

    [build] Configure switch to disable atomics
    
    Workaround for my arm toolchain which succeeds in linking the configure
    program, only to complain when linking a program (such as cairo-perf)
    against libcairo.so. Annoying.

diff --git a/build/configure.ac.system b/build/configure.ac.system
index c75460d..46b7f43 100644
--- a/build/configure.ac.system
+++ b/build/configure.ac.system
@@ -8,8 +8,14 @@ dnl ====================================================================
 
 AM_CONDITIONAL(CROSS_COMPILING, test "x$cross_compiling" = "xyes")
 CAIRO_BIGENDIAN
-CAIRO_CHECK_NATIVE_ATOMIC_PRIMITIVES
-CAIRO_CHECK_ATOMIC_OP_NEEDS_MEMORY_BARRIER
+AC_ARG_ENABLE(atomic,
+	      [AS_HELP_STRING([--disable-atomic],
+			      [disable use of native atomic operations])],
+	      [use_atomic=$enableval], [use_atomic=yes])
+AS_IF([test "x$use_atomic" = "xyes"], [
+  CAIRO_CHECK_NATIVE_ATOMIC_PRIMITIVES
+  CAIRO_CHECK_ATOMIC_OP_NEEDS_MEMORY_BARRIER
+])
 AC_CHECK_SIZEOF(void *)
 AC_CHECK_SIZEOF(int)
 AC_CHECK_SIZEOF(long)
commit cb30c1f367967e3395296a5d01a3eb9050635e3b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Aug 4 13:59:03 2009 +0100

    [path] Extend identical lines.
    
    If a subsequent PATH_OP is just a continuation of the previous line, i.e.
    it has the same gradient, then just replace the end-point of the previous
    line with the new point rather than adding a new operation. Surprisingly
    this occurs in the wild, but the main motivation is a future optimisation
    to reduce the number of intersections during stroke-to-path.

diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 921c79e..b716030 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -445,22 +445,47 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
     if (! path->has_current_point) {
 	status = _cairo_path_fixed_move_to (path, point.x, point.y);
     } else {
+	/* If the previous op was also a LINE_TO with the same gradient,
+	 * then just change its end-point rather than adding a new op.
+	 */
+	if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
+	    cairo_path_buf_t *buf;
+	    cairo_point_t *p;
+	    cairo_slope_t prev, self;
+
+	    buf = cairo_path_tail (path);
+	    if (likely (buf->num_points >= 2)) {
+		p = &buf->points[buf->num_points-2];
+	    } else {
+		cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
+		p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
+	    }
+	    _cairo_slope_init (&prev, p, &path->current_point);
+	    _cairo_slope_init (&self, &path->current_point, &point);
+	    if (_cairo_slope_equal (&prev, &self)) {
+		buf->points[buf->num_points - 1] = point;
+		status = CAIRO_STATUS_SUCCESS;
+		goto DONE;
+	    }
+	}
+
 	status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
 	if (path->is_rectilinear) {
 	    path->is_rectilinear = path->current_point.x == x ||
-		                   path->current_point.y == y;
+		path->current_point.y == y;
 	    path->maybe_fill_region &= path->is_rectilinear;
 	}
 	if (path->maybe_fill_region) {
 	    path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
-		                      _cairo_fixed_is_integer (y);
+		_cairo_fixed_is_integer (y);
 	}
 	if (path->is_empty_fill) {
 	    path->is_empty_fill = path->current_point.x == x &&
-		                  path->current_point.y == y;
+		path->current_point.y == y;
 	}
     }
 
+DONE:
     path->current_point = point;
     path->has_current_point = TRUE;
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 30e7d38..12e4098 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2726,6 +2726,13 @@ CAIRO_END_DECLS
 #include "cairo-malloc-private.h"
 #include "cairo-hash-private.h"
 
+static inline cairo_bool_t
+_cairo_slope_equal (const cairo_slope_t *a, const cairo_slope_t *b)
+{
+    return _cairo_int64_eq (_cairo_int32x32_64_mul (a->dy, b->dx),
+			    _cairo_int32x32_64_mul (b->dy, a->dx));
+}
+
 #if HAVE_VALGRIND
 #include <memcheck.h>
 
commit 85b688a3f6271427befca699de3a7a15162fc59e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Aug 3 22:27:22 2009 +0100

    [matrix] Use hypot()
    
    Use hypot() instead of open-coding sqrt(x*x + y*y). In theory, the
    compiler could emit highly efficient code. In practice it's slower, but
    more likely to be more accurate -- but the difference over a bare sqrt()
    is likely not to be perceptible.

diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index b9e7290..6c83388 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -624,7 +624,7 @@ _cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
 	double major, minor;
 
 	cairo_matrix_transform_distance (matrix, &x, &y);
-	major = sqrt(x*x + y*y);
+	major = hypot (x, y);
 	/*
 	 * ignore mirroring
 	 */
@@ -856,7 +856,7 @@ _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
     g = 0.5 * (i - j);
     h = a*c + b*d;
 
-    return radius * sqrt (f + sqrt (g*g+h*h));
+    return radius * sqrt (f + hypot (g, h));
 
     /*
      * we don't need the minor axis length, which is
commit 0db9e010fa70c65451d324cc9c0ade989f77fedd
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Aug 3 22:23:19 2009 +0100

    [perf] Calibrate tests to run for at least 2 seconds
    
    By ensuring that tests take longer than a couple of seconds we eliminate
    systematic errors in our measurements. However, we also effectively
    eliminate the synchronisation overhead. To compensate, we attempt to
    estimate the overhead by reporting the difference between a single
    instance and the minimum averaged instance.

diff --git a/perf/box-outline.c b/perf/box-outline.c
index 2d826e6..6b97b08 100644
--- a/perf/box-outline.c
+++ b/perf/box-outline.c
@@ -41,7 +41,7 @@
  */
 
 static cairo_perf_ticks_t
-box_outline_stroke (cairo_t *cr, int width, int height)
+box_outline_stroke (cairo_t *cr, int width, int height, int loops)
 {
     cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
     cairo_paint (cr);
@@ -54,15 +54,18 @@ box_outline_stroke (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_stroke (cr);
+    while (loops--)
+	cairo_stroke_preserve (cr);
 
     cairo_perf_timer_stop ();
 
+    cairo_new_path (cr);
+
     return cairo_perf_timer_elapsed ();
 }
 
 static cairo_perf_ticks_t
-box_outline_fill (cairo_t *cr, int width, int height)
+box_outline_fill (cairo_t *cr, int width, int height, int loops)
 {
     cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
     cairo_paint (cr);
@@ -78,10 +81,13 @@ box_outline_fill (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_fill (cr);
+    while (loops--)
+	cairo_fill_preserve (cr);
 
     cairo_perf_timer_stop ();
 
+    cairo_new_path (cr);
+
     return cairo_perf_timer_elapsed ();
 }
 
diff --git a/perf/cairo-perf-report.c b/perf/cairo-perf-report.c
index 65340a1..1690e62 100644
--- a/perf/cairo-perf-report.c
+++ b/perf/cairo-perf-report.c
@@ -49,7 +49,7 @@
 typedef ptrdiff_t ssize_t;
 #endif
 
-#ifndef __USE_GNU
+#if !defined (__USE_GNU) && !defined(__USE_XOPEN2K8)
 static ssize_t
 getline (char **lineptr, size_t *n, FILE *stream);
 
@@ -227,7 +227,7 @@ test_report_parse (test_report_t *report, char *line, char *configuration)
  * as needed. These aren't necessary full-fledged general purpose
  * implementations. They just get the job done for our purposes.
  */
-#ifndef __USE_GNU
+#if !defined (__USE_GNU) && !defined(__USE_XOPEN2K8)
 #define POORMANS_GETLINE_BUFFER_SIZE (65536)
 static ssize_t
 getline (char **lineptr, size_t *n, FILE *stream)
diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index 792120b..21d48f4 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -191,9 +191,9 @@ cairo_perf_run (cairo_perf_t		*perf,
 
 	if (perf->summary) {
 	    fprintf (perf->summary,
-		     "[ # ] %8s.%-4s %28s %8s %8s %5s %5s %s\n",
+		     "[ # ] %8s.%-4s %28s %8s %8s %5s %5s %s %s\n",
 		     "backend", "content", "test-size", "min(ticks)", "min(ms)", "median(ms)",
-		     "stddev.", "iterations");
+		     "stddev.", "iterations", "overhead");
 	}
 	first_run = FALSE;
     }
@@ -208,7 +208,7 @@ cairo_perf_run (cairo_perf_t		*perf,
 		   name, perf->target->name,
 		   _content_to_string (perf->target->content, 0),
 		   perf->size);
-	perf_func (perf->cr, perf->size, perf->size);
+	perf_func (perf->cr, perf->size, perf->size, 1);
 	status = cairo_surface_write_to_png (cairo_get_target (perf->cr), filename);
 	if (status) {
 	    fprintf (stderr, "Failed to generate output check '%s': %s\n",
@@ -221,6 +221,9 @@ cairo_perf_run (cairo_perf_t		*perf,
 
     has_similar = cairo_perf_has_similar (perf);
     for (similar = 0; similar <= has_similar; similar++) {
+	cairo_perf_ticks_t calibration0, calibration;
+	unsigned loops;
+
 	if (perf->summary) {
 	    fprintf (perf->summary,
 		     "[%3d] %8s.%-5s %26s.%-3d ",
@@ -230,22 +233,41 @@ cairo_perf_run (cairo_perf_t		*perf,
 	    fflush (perf->summary);
 	}
 
-	/* We run one iteration in advance to warm caches, etc. */
+	/* We run one iteration in advance to warm caches and calibrate. */
 	cairo_perf_yield ();
 	if (similar)
 	    cairo_push_group_with_content (perf->cr,
 		                           cairo_boilerplate_content (perf->target->content));
-	(perf_func) (perf->cr, perf->size, perf->size);
+	perf_func (perf->cr, perf->size, perf->size, 1);
+	calibration0 = perf_func (perf->cr, perf->size, perf->size, 1);
+	loops = cairo_perf_ticks_per_second () / 100 / calibration0;
+	if (loops < 3)
+	    loops = 3;
+	calibration = (calibration0 + perf_func (perf->cr, perf->size, perf->size, loops)) / (loops + 1);
 	if (similar)
 	    cairo_pattern_destroy (cairo_pop_group (perf->cr));
 
+	/* XXX
+	 * Compute the number of loops required for the timing interval to
+	 * be ~2 seconds. This helps to eliminate sampling variance due to
+	 * timing and other systematic errors. However, it also hides
+	 * synchronisation overhead as we attempt to process a large batch
+	 * of identical operations in a single shot. This can be considered
+	 * both good and bad... It would be good to perform a more rigorous
+	 * analysis of the synchronisation overhead, that is to estimate
+	 * the time for loop=0.
+	 */
+	loops = 2 * cairo_perf_ticks_per_second () / calibration;
+	if (loops < 10)
+	    loops = 10;
+
 	low_std_dev_count = 0;
 	for (i =0; i < perf->iterations; i++) {
 	    cairo_perf_yield ();
 	    if (similar)
 		cairo_push_group_with_content (perf->cr,
 			                       cairo_boilerplate_content (perf->target->content));
-	    times[i] = (perf_func) (perf->cr, perf->size, perf->size);
+	    times[i] = perf_func (perf->cr, perf->size, perf->size, loops) / loops;
 	    if (similar)
 		cairo_pattern_destroy (cairo_pop_group (perf->cr));
 
@@ -279,11 +301,12 @@ cairo_perf_run (cairo_perf_t		*perf,
 	if (perf->summary) {
 	    _cairo_stats_compute (&stats, times, i);
 	    fprintf (perf->summary,
-		     "%10lld %#8.3f %#8.3f %#5.2f%% %3d\n",
+		     "%10lld %#8.3f %#8.3f %#5.2f%% %3d %10lld\n",
 		     (long long) stats.min_ticks,
 		     (stats.min_ticks * 1000.0) / cairo_perf_ticks_per_second (),
 		     (stats.median_ticks * 1000.0) / cairo_perf_ticks_per_second (),
-		     stats.std_dev * 100.0, stats.iterations);
+		     stats.std_dev * 100.0, stats.iterations,
+		     (long long) (calibration0 - stats.min_ticks));
 	    fflush (perf->summary);
 	}
 
diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h
index b6c502c..139de8e 100644
--- a/perf/cairo-perf.h
+++ b/perf/cairo-perf.h
@@ -94,7 +94,7 @@ typedef struct _cairo_perf {
 } cairo_perf_t;
 
 typedef cairo_perf_ticks_t
-(*cairo_perf_func_t) (cairo_t *cr, int width, int height);
+(*cairo_perf_func_t) (cairo_t *cr, int width, int height, int loops);
 
 cairo_bool_t
 cairo_perf_can_run (cairo_perf_t	*perf,
diff --git a/perf/composite-checker.c b/perf/composite-checker.c
index e978990..301006f 100644
--- a/perf/composite-checker.c
+++ b/perf/composite-checker.c
@@ -50,7 +50,8 @@ static cairo_pattern_t *src_pattern = NULL;
 static cairo_perf_ticks_t
 do_composite_checker (cairo_t *cr,
                       int      width,
-                      int      height)
+                      int      height,
+		      int loops)
 {
     /* Compute zoom so that the src_pattern covers the whole output image. */
     double xscale = width / (double) SRC_SIZE;
@@ -58,16 +59,17 @@ do_composite_checker (cairo_t *cr,
 
     cairo_perf_timer_start ();
 
-    cairo_identity_matrix (cr);
+    while (loops--) {
+	/* Fill the surface with our background. */
+	cairo_identity_matrix (cr);
+	cairo_set_source (cr, checkerboard);
+	cairo_paint (cr);
 
-    /* Fill the surface with our background. */
-    cairo_set_source (cr, checkerboard);
-    cairo_paint (cr);
-
-    /* Draw the scaled image on top. */
-    cairo_scale (cr, xscale, yscale);
-    cairo_set_source (cr, src_pattern);
-    cairo_paint (cr);
+	/* Draw the scaled image on top. */
+	cairo_scale (cr, xscale, yscale);
+	cairo_set_source (cr, src_pattern);
+	cairo_paint (cr);
+    }
 
     cairo_perf_timer_stop ();
     return cairo_perf_timer_elapsed ();
diff --git a/perf/dragon.c b/perf/dragon.c
index 1866c9a..366b63c 100644
--- a/perf/dragon.c
+++ b/perf/dragon.c
@@ -94,7 +94,7 @@ path (cairo_t *cr, int step, int dir, int iterations)
 }
 
 static cairo_perf_ticks_t
-do_dragon (cairo_t *cr, int width, int height)
+do_dragon (cairo_t *cr, int width, int height, int loops)
 {
     cairo_pattern_t *pattern;
     double cx, cy, r;
@@ -104,54 +104,56 @@ do_dragon (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
-    cairo_pattern_add_color_stop_rgb (pattern, 0., .0, .0, .0);
-    cairo_pattern_add_color_stop_rgb (pattern, 0.25, .5, .4, .4);
-    cairo_pattern_add_color_stop_rgb (pattern, .5, .8, .8, .9);
-    cairo_pattern_add_color_stop_rgb (pattern, 1., .9, .9, 1.);
-    cairo_set_source (cr, pattern);
-    cairo_pattern_destroy (pattern);
-    cairo_paint (cr);
-
-    cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
-    cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
-    cairo_set_line_width (cr, 4.);
-
-    cairo_move_to (cr, cx, cy);
-    path (cr, 12, 0, 2048);
-    pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
-    cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 1., 1.);
-    cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 0., 0.);
-    cairo_set_source (cr, pattern);
-    cairo_pattern_destroy (pattern);
-    cairo_stroke(cr);
-
-    cairo_move_to (cr, cx, cy);
-    path (cr, 12, 1, 2048);
-    pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
-    cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 1., 0.);
-    cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 0., 0.);
-    cairo_set_source (cr, pattern);
-    cairo_pattern_destroy (pattern);
-    cairo_stroke(cr);
-
-    cairo_move_to (cr, cx, cy);
-    path (cr, 12, 2, 2048);
-    pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
-    cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 1., 1.);
-    cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 1., 0.);
-    cairo_set_source (cr, pattern);
-    cairo_pattern_destroy (pattern);
-    cairo_stroke(cr);
-
-    cairo_move_to (cr, cx, cy);
-    path (cr, 12, 3, 2048);
-    pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
-    cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 0., 1.);
-    cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 0., 1.);
-    cairo_set_source (cr, pattern);
-    cairo_pattern_destroy (pattern);
-    cairo_stroke(cr);
+    while (loops--) {
+	pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+	cairo_pattern_add_color_stop_rgb (pattern, 0., .0, .0, .0);
+	cairo_pattern_add_color_stop_rgb (pattern, 0.25, .5, .4, .4);
+	cairo_pattern_add_color_stop_rgb (pattern, .5, .8, .8, .9);
+	cairo_pattern_add_color_stop_rgb (pattern, 1., .9, .9, 1.);
+	cairo_set_source (cr, pattern);
+	cairo_pattern_destroy (pattern);
+	cairo_paint (cr);
+
+	cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+	cairo_set_line_width (cr, 4.);
+
+	cairo_move_to (cr, cx, cy);
+	path (cr, 12, 0, 2048);
+	pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+	cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 1., 1.);
+	cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 0., 0.);
+	cairo_set_source (cr, pattern);
+	cairo_pattern_destroy (pattern);
+	cairo_stroke(cr);
+
+	cairo_move_to (cr, cx, cy);
+	path (cr, 12, 1, 2048);
+	pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+	cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 1., 0.);
+	cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 0., 0.);
+	cairo_set_source (cr, pattern);
+	cairo_pattern_destroy (pattern);
+	cairo_stroke(cr);
+
+	cairo_move_to (cr, cx, cy);
+	path (cr, 12, 2, 2048);
+	pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+	cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 1., 1.);
+	cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 1., 0.);
+	cairo_set_source (cr, pattern);
+	cairo_pattern_destroy (pattern);
+	cairo_stroke(cr);
+
+	cairo_move_to (cr, cx, cy);
+	path (cr, 12, 3, 2048);
+	pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+	cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 0., 1.);
+	cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 0., 1.);
+	cairo_set_source (cr, pattern);
+	cairo_pattern_destroy (pattern);
+	cairo_stroke(cr);
+    }
 
     cairo_perf_timer_stop ();
 
@@ -159,7 +161,7 @@ do_dragon (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_dragon_solid (cairo_t *cr, int width, int height)
+do_dragon_solid (cairo_t *cr, int width, int height, int loops)
 {
     double cx, cy, r;
 
@@ -168,30 +170,32 @@ do_dragon_solid (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_set_source_rgb (cr, 0, 0, 0);
-    cairo_paint (cr);
+    while (loops--) {
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_paint (cr);
 
-    cairo_set_line_width (cr, 4.);
+	cairo_set_line_width (cr, 4.);
 
-    cairo_move_to (cr, cx, cy);
-    path (cr, 12, 0, 2048);
-    cairo_set_source_rgb (cr, 1, 0, 0);
-    cairo_stroke(cr);
+	cairo_move_to (cr, cx, cy);
+	path (cr, 12, 0, 2048);
+	cairo_set_source_rgb (cr, 1, 0, 0);
+	cairo_stroke(cr);
 
-    cairo_move_to (cr, cx, cy);
-    path (cr, 12, 1, 2048);
-    cairo_set_source_rgb (cr, 0, 1, 0);
-    cairo_stroke(cr);
+	cairo_move_to (cr, cx, cy);
+	path (cr, 12, 1, 2048);
+	cairo_set_source_rgb (cr, 0, 1, 0);
+	cairo_stroke(cr);
 
-    cairo_move_to (cr, cx, cy);
-    path (cr, 12, 2, 2048);
-    cairo_set_source_rgb (cr, 0, 0, 1);
-    cairo_stroke(cr);
+	cairo_move_to (cr, cx, cy);
+	path (cr, 12, 2, 2048);
+	cairo_set_source_rgb (cr, 0, 0, 1);
+	cairo_stroke(cr);
 
-    cairo_move_to (cr, cx, cy);
-    path (cr, 12, 3, 2048);
-    cairo_set_source_rgb (cr, 1, 1, 1);
-    cairo_stroke(cr);
+	cairo_move_to (cr, cx, cy);
+	path (cr, 12, 3, 2048);
+	cairo_set_source_rgb (cr, 1, 1, 1);
+	cairo_stroke(cr);
+    }
 
     cairo_perf_timer_stop ();
 
diff --git a/perf/fill.c b/perf/fill.c
index 0bad3cd..453f9a4 100644
--- a/perf/fill.c
+++ b/perf/fill.c
@@ -26,7 +26,7 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_fill (cairo_t *cr, int width, int height)
+do_fill (cairo_t *cr, int width, int height, int loops)
 {
     cairo_arc (cr,
 	       width/2.0, height/2.0,
@@ -35,15 +35,18 @@ do_fill (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_fill (cr);
+    while (loops--)
+	cairo_fill_preserve (cr);
 
     cairo_perf_timer_stop ();
 
+    cairo_new_path (cr);
+
     return cairo_perf_timer_elapsed ();
 }
 
 static cairo_perf_ticks_t
-do_fill_annuli (cairo_t *cr, int width, int height)
+do_fill_annuli (cairo_t *cr, int width, int height, int loops)
 {
     cairo_new_sub_path (cr);
     cairo_arc (cr,
@@ -71,15 +74,18 @@ do_fill_annuli (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_fill (cr);
+    while (loops--)
+	cairo_fill_preserve (cr);
 
     cairo_perf_timer_stop ();
 
+    cairo_new_path (cr);
+
     return cairo_perf_timer_elapsed ();
 }
 
 static cairo_perf_ticks_t
-do_fill_eo_noaa (cairo_t *cr, int width, int height)
+do_fill_eo_noaa (cairo_t *cr, int width, int height, int loops)
 {
     cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
     cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
@@ -91,10 +97,13 @@ do_fill_eo_noaa (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_fill (cr);
+    while (loops--)
+	cairo_fill_preserve (cr);
 
     cairo_perf_timer_stop ();
 
+    cairo_new_path (cr);
+
     return cairo_perf_timer_elapsed ();
 }
 
diff --git a/perf/glyphs.c b/perf/glyphs.c
index fdd4d97..bead68c 100644
--- a/perf/glyphs.c
+++ b/perf/glyphs.c
@@ -28,7 +28,7 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_glyphs (cairo_t *cr, int width, int height)
+do_glyphs (cairo_t *cr, int width, int height, int loops)
 {
     const char text[] = "the jay, pig, fox, zebra and my wolves quack";
     cairo_scaled_font_t *scaled_font;
@@ -61,22 +61,24 @@ do_glyphs (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    do {
-	x = 0;
+    while (loops--) {
 	do {
-	    for (n = 0; n < num_glyphs; n++) {
-		glyphs_copy[n] = glyphs[n];
-		glyphs_copy[n].x += x;
-		glyphs_copy[n].y += y;
-	    }
-	    cairo_show_glyphs (cr, glyphs_copy, num_glyphs);
-	    if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
-		goto out;
+	    x = 0;
+	    do {
+		for (n = 0; n < num_glyphs; n++) {
+		    glyphs_copy[n] = glyphs[n];
+		    glyphs_copy[n].x += x;
+		    glyphs_copy[n].y += y;
+		}
+		cairo_show_glyphs (cr, glyphs_copy, num_glyphs);
+		if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
+		    goto out;
 
-	    x += extents.width;
-	} while (x < width);
-	y += extents.height;
-    } while (y < height);
+		x += extents.width;
+	    } while (x < width);
+	    y += extents.height;
+	} while (y < height);
+    }
 out:
 
     cairo_perf_timer_stop ();
diff --git a/perf/intersections.c b/perf/intersections.c
index 347c4a5..f35e090 100644
--- a/perf/intersections.c
+++ b/perf/intersections.c
@@ -40,7 +40,8 @@ uniform_random (double minval, double maxval)
 }
 
 static cairo_perf_ticks_t
-draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule, int width, int height)
+draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule,
+	     int width, int height, int loops)
 {
     int i;
     double x[NUM_SEGMENTS];
@@ -60,16 +61,14 @@ draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule, int width, int height)
     cairo_set_fill_rule (cr, fill_rule);
     cairo_set_source_rgb (cr, 1, 0, 0);
 
-    cairo_perf_timer_start (); {
+    cairo_move_to (cr, 0, 0);
+    for (i = 0; i < NUM_SEGMENTS; i++)
+	cairo_line_to (cr, x[i], y[i]);
+    cairo_close_path (cr);
 
-        cairo_move_to (cr, 0, 0);
-        for (i = 0; i < NUM_SEGMENTS; i++) {
-            cairo_line_to (cr, x[i], y[i]);
-        }
-        cairo_close_path (cr);
-
-        cairo_fill (cr);
-    }
+    cairo_perf_timer_start ();
+    while (loops--)
+        cairo_fill_preserve (cr);
     cairo_perf_timer_stop ();
 
     cairo_restore (cr);
@@ -78,15 +77,15 @@ draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule, int width, int height)
 }
 
 static cairo_perf_ticks_t
-random_eo (cairo_t *cr, int width, int height)
+random_eo (cairo_t *cr, int width, int height, int loops)
 {
-    return draw_random (cr, CAIRO_FILL_RULE_EVEN_ODD, width, height);
+    return draw_random (cr, CAIRO_FILL_RULE_EVEN_ODD, width, height, loops);
 }
 
 static cairo_perf_ticks_t
-random_nz (cairo_t *cr, int width, int height)
+random_nz (cairo_t *cr, int width, int height, int loops)
 {
-    return draw_random (cr, CAIRO_FILL_RULE_WINDING, width, height);
+    return draw_random (cr, CAIRO_FILL_RULE_WINDING, width, height, loops);
 }
 
 void
diff --git a/perf/long-dashed-lines.c b/perf/long-dashed-lines.c
index 3520a19..96e6486 100644
--- a/perf/long-dashed-lines.c
+++ b/perf/long-dashed-lines.c
@@ -28,7 +28,7 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_long_dashed_lines (cairo_t *cr, int width, int height)
+do_long_dashed_lines (cairo_t *cr, int width, int height, int loops)
 {
     double dash[2] = { 2.0, 2.0 };
     int i;
@@ -40,8 +40,6 @@ do_long_dashed_lines (cairo_t *cr, int width, int height)
     cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
     cairo_set_dash (cr, dash, 2, 0.0);
 
-    cairo_perf_timer_start ();
-
     cairo_new_path (cr);
     cairo_set_line_width (cr, 1.0);
 
@@ -51,7 +49,10 @@ do_long_dashed_lines (cairo_t *cr, int width, int height)
 	cairo_line_to (cr, width, y0);
     }
 
-    cairo_stroke (cr);
+    cairo_perf_timer_start ();
+
+    while (loops--)
+	cairo_stroke_preserve (cr);
 
     cairo_perf_timer_stop ();
 
diff --git a/perf/long-lines.c b/perf/long-lines.c
index 67f698a..124c4f2 100644
--- a/perf/long-lines.c
+++ b/perf/long-lines.c
@@ -43,7 +43,7 @@ typedef enum {
 #define LONG_FACTOR  50.0
 
 static cairo_perf_ticks_t
-do_long_lines (cairo_t *cr, int width, int height, long_lines_crop_t crop)
+do_long_lines (cairo_t *cr, int width, int height, int loops, long_lines_crop_t crop)
 {
     int i;
     double x, y, dx, dy, min_x, min_y, max_x, max_y;
@@ -72,32 +72,34 @@ do_long_lines (cairo_t *cr, int width, int height, long_lines_crop_t crop)
 
     cairo_perf_timer_start ();
 
-    for (i = 0; i <= NUM_LINES; i++) {
-	cairo_move_to (cr, 0, 0);
-	cairo_line_to (cr, x, min_y);
-	if ((crop & LONG_LINES_ONCE) == 0)
+    while (loops--) {
+	for (i = 0; i <= NUM_LINES; i++) {
+	    cairo_move_to (cr, 0, 0);
+	    cairo_line_to (cr, x, min_y);
+	    if ((crop & LONG_LINES_ONCE) == 0)
+		cairo_stroke (cr);
+
+	    cairo_move_to (cr, 0, 0);
+	    cairo_line_to (cr, x, max_y);
+	    if ((crop & LONG_LINES_ONCE) == 0)
+		cairo_stroke (cr);
+
+	    cairo_move_to (cr, 0, 0);
+	    cairo_line_to (cr, min_x, y);
+	    if ((crop & LONG_LINES_ONCE) == 0)
+		cairo_stroke (cr);
+
+	    cairo_move_to (cr, 0, 0);
+	    cairo_line_to (cr, max_x, y);
+	    if ((crop & LONG_LINES_ONCE) == 0)
+		cairo_stroke (cr);
+
+	    x += dx;
+	    y += dy;
+	}
+	if (crop & LONG_LINES_ONCE)
 	    cairo_stroke (cr);
-
-	cairo_move_to (cr, 0, 0);
-	cairo_line_to (cr, x, max_y);
-	if ((crop & LONG_LINES_ONCE) == 0)
-	    cairo_stroke (cr);
-
-	cairo_move_to (cr, 0, 0);
-	cairo_line_to (cr, min_x, y);
-	if ((crop & LONG_LINES_ONCE) == 0)
-	    cairo_stroke (cr);
-
-	cairo_move_to (cr, 0, 0);
-	cairo_line_to (cr, max_x, y);
-	if ((crop & LONG_LINES_ONCE) == 0)
-	    cairo_stroke (cr);
-
-	x += dx;
-	y += dy;
     }
-    if (crop & LONG_LINES_ONCE)
-	cairo_stroke (cr);
 
     cairo_perf_timer_stop ();
 
@@ -107,27 +109,27 @@ do_long_lines (cairo_t *cr, int width, int height, long_lines_crop_t crop)
 }
 
 static cairo_perf_ticks_t
-long_lines_uncropped (cairo_t *cr, int width, int height)
+long_lines_uncropped (cairo_t *cr, int width, int height, int loops)
 {
-    return do_long_lines (cr, width, height, 0);
+    return do_long_lines (cr, width, height, loops, 0);
 }
 
 static cairo_perf_ticks_t
-long_lines_uncropped_once (cairo_t *cr, int width, int height)
+long_lines_uncropped_once (cairo_t *cr, int width, int height, int loops)
 {
-    return do_long_lines (cr, width, height, LONG_LINES_ONCE);
+    return do_long_lines (cr, width, height, loops, LONG_LINES_ONCE);
 }
 
 static cairo_perf_ticks_t
-long_lines_cropped (cairo_t *cr, int width, int height)
+long_lines_cropped (cairo_t *cr, int width, int height, int loops)
 {
-    return do_long_lines (cr, width, height, LONG_LINES_CROPPED);
+    return do_long_lines (cr, width, height, loops, LONG_LINES_CROPPED);
 }
 
 static cairo_perf_ticks_t
-long_lines_cropped_once (cairo_t *cr, int width, int height)
+long_lines_cropped_once (cairo_t *cr, int width, int height, int loops)
 {
-    return do_long_lines (cr, width, height, LONG_LINES_CROPPED | LONG_LINES_ONCE);
+    return do_long_lines (cr, width, height, loops, LONG_LINES_CROPPED | LONG_LINES_ONCE);
 }
 
 void
diff --git a/perf/mask.c b/perf/mask.c
index 4dc305e..55dc20a 100644
--- a/perf/mask.c
+++ b/perf/mask.c
@@ -28,7 +28,7 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_mask_solid (cairo_t *cr, int width, int height)
+do_mask_solid (cairo_t *cr, int width, int height, int loops)
 {
     cairo_pattern_t *mask;
 
@@ -36,7 +36,8 @@ do_mask_solid (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
@@ -70,7 +71,7 @@ init_surface (cairo_surface_t *surface, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_mask_image (cairo_t *cr, int width, int height)
+do_mask_image (cairo_t *cr, int width, int height, int loops)
 {
     cairo_surface_t *surface;
     cairo_pattern_t *mask;
@@ -83,7 +84,8 @@ do_mask_image (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
@@ -93,7 +95,7 @@ do_mask_image (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_mask_image_half (cairo_t *cr, int width, int height)
+do_mask_image_half (cairo_t *cr, int width, int height, int loops)
 {
     cairo_surface_t *surface;
     cairo_pattern_t *mask;
@@ -109,7 +111,8 @@ do_mask_image_half (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
@@ -119,7 +122,7 @@ do_mask_image_half (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_mask_image_double (cairo_t *cr, int width, int height)
+do_mask_image_double (cairo_t *cr, int width, int height, int loops)
 {
     cairo_surface_t *surface;
     cairo_pattern_t *mask;
@@ -135,7 +138,8 @@ do_mask_image_double (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
@@ -145,7 +149,7 @@ do_mask_image_double (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_mask_similar (cairo_t *cr, int width, int height)
+do_mask_similar (cairo_t *cr, int width, int height, int loops)
 {
     cairo_surface_t *surface;
     cairo_pattern_t *mask;
@@ -159,7 +163,8 @@ do_mask_similar (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
@@ -169,7 +174,7 @@ do_mask_similar (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_mask_similar_half (cairo_t *cr, int width, int height)
+do_mask_similar_half (cairo_t *cr, int width, int height, int loops)
 {
     cairo_surface_t *surface;
     cairo_pattern_t *mask;
@@ -186,7 +191,8 @@ do_mask_similar_half (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
@@ -196,7 +202,7 @@ do_mask_similar_half (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_mask_similar_double (cairo_t *cr, int width, int height)
+do_mask_similar_double (cairo_t *cr, int width, int height, int loops)
 {
     cairo_surface_t *surface;
     cairo_pattern_t *mask;
@@ -213,7 +219,8 @@ do_mask_similar_double (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
@@ -223,7 +230,7 @@ do_mask_similar_double (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_mask_linear (cairo_t *cr, int width, int height)
+do_mask_linear (cairo_t *cr, int width, int height, int loops)
 {
     cairo_pattern_t *mask;
 
@@ -233,7 +240,8 @@ do_mask_linear (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
@@ -243,7 +251,7 @@ do_mask_linear (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_mask_radial (cairo_t *cr, int width, int height)
+do_mask_radial (cairo_t *cr, int width, int height, int loops)
 {
     cairo_pattern_t *mask;
 
@@ -254,7 +262,8 @@ do_mask_radial (cairo_t *cr, int width, int height)
 
     cairo_perf_timer_start ();
 
-    cairo_mask (cr, mask);
+    while (loops--)
+	cairo_mask (cr, mask);
 
     cairo_perf_timer_stop ();
 
diff --git a/perf/mosaic.c b/perf/mosaic.c
index bab6276..715dffb 100644
--- a/perf/mosaic.c
+++ b/perf/mosaic.c
@@ -93,7 +93,7 @@ mosaic_next_path (cairo_t *cr, struct mosaic_region_iter *iter)
 }
 
 static cairo_perf_ticks_t
-mosaic_perform(cairo_t *cr, unsigned flags, int width, int height)
+mosaic_perform(cairo_t *cr, unsigned flags, int width, int height, int loops)
 {
     struct mosaic_region_iter iter;
 
@@ -116,17 +116,19 @@ mosaic_perform(cairo_t *cr, unsigned flags, int width, int height)
 
     /* Iterate over all closed regions in the mosaic filling or
      * tessellating them as dictated by the flags.  */
-    mosaic_region_iter_init (&iter, flags & MOSAIC_CURVE_TO);
 
     cairo_perf_timer_start ();
-    while (mosaic_next_path (cr, &iter)) {
-	if (flags & MOSAIC_FILL) {
-	    cairo_fill (cr);
-	}
-	else {
-	    double x, y;
-	    cairo_get_current_point (cr, &x, &y);
-	    cairo_in_fill (cr, x, y);
+    while (loops--) {
+	mosaic_region_iter_init (&iter, flags & MOSAIC_CURVE_TO);
+	while (mosaic_next_path (cr, &iter)) {
+	    if (flags & MOSAIC_FILL) {
+		cairo_fill (cr);
+	    }
+	    else {
+		double x, y;
+		cairo_get_current_point (cr, &x, &y);
+		cairo_in_fill (cr, x, y);
+	    }
 	}
     }
     cairo_perf_timer_stop ();
@@ -135,27 +137,27 @@ mosaic_perform(cairo_t *cr, unsigned flags, int width, int height)
 }
 
 static cairo_perf_ticks_t
-mosaic_fill_curves (cairo_t *cr, int width, int height)
+mosaic_fill_curves (cairo_t *cr, int width, int height, int loops)
 {
-    return mosaic_perform (cr, MOSAIC_FILL | MOSAIC_CURVE_TO, width, height);
+    return mosaic_perform (cr, MOSAIC_FILL | MOSAIC_CURVE_TO, width, height, loops);
 }
 
 static cairo_perf_ticks_t
-mosaic_fill_lines (cairo_t *cr, int width, int height)
+mosaic_fill_lines (cairo_t *cr, int width, int height, int loops)
 {
-    return mosaic_perform (cr, MOSAIC_FILL | MOSAIC_LINE_TO, width, height);
+    return mosaic_perform (cr, MOSAIC_FILL | MOSAIC_LINE_TO, width, height, loops);
 }
 
 static cairo_perf_ticks_t
-mosaic_tessellate_lines (cairo_t *cr, int width, int height)
+mosaic_tessellate_lines (cairo_t *cr, int width, int height, int loops)
 {
-    return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_LINE_TO, width, height);
+    return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_LINE_TO, width, height, loops);
 }
 
 static cairo_perf_ticks_t
-mosaic_tessellate_curves (cairo_t *cr, int width, int height)
+mosaic_tessellate_curves (cairo_t *cr, int width, int height, int loops)
 {
-    return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height);
+    return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height, loops);
 }
 
 void
diff --git a/perf/paint-with-alpha.c b/perf/paint-with-alpha.c
index 6ffe8bb..cef353d 100644
--- a/perf/paint-with-alpha.c
+++ b/perf/paint-with-alpha.c
@@ -26,11 +26,12 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_paint_with_alpha (cairo_t *cr, int width, int height)
+do_paint_with_alpha (cairo_t *cr, int width, int height, int loops)
 {
     cairo_perf_timer_start ();
 
-    cairo_paint_with_alpha (cr, 0.5);
+    while (loops--)
+	cairo_paint_with_alpha (cr, 0.5);
 
     cairo_perf_timer_stop ();
 
diff --git a/perf/paint.c b/perf/paint.c
index a60d132..ac7c724 100644
--- a/perf/paint.c
+++ b/perf/paint.c
@@ -26,11 +26,12 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_paint (cairo_t *cr, int width, int height)
+do_paint (cairo_t *cr, int width, int height, int loops)
 {
     cairo_perf_timer_start ();
 
-    cairo_paint (cr);
+    while (loops--)
+	cairo_paint (cr);
 
     cairo_perf_timer_stop ();
 
diff --git a/perf/pattern_create_radial.c b/perf/pattern_create_radial.c
index b908151..26dc713 100644
--- a/perf/pattern_create_radial.c
+++ b/perf/pattern_create_radial.c
@@ -56,20 +56,22 @@ generate_double_in_range (double min, double max)
 }
 
 static cairo_perf_ticks_t
-do_pattern_create_radial (cairo_t *cr, int width, int height)
+do_pattern_create_radial (cairo_t *cr, int width, int height, int loops)
 {
-    int i;
-    cairo_pattern_t *pattern;
-
     cairo_perf_timer_start ();
 
-    for (i = 0; i < RADIALS_COUNT; i++)
-    {
-        pattern = cairo_pattern_create_radial (radials[i].cx0, radials[i].cy0,
-                                               radials[i].radius0,
-                                               radials[i].cx1, radials[i].cy1,
-                                               radials[i].radius1);
-        cairo_pattern_destroy (pattern);
+    while (loops--) {
+	cairo_pattern_t *pattern;
+	int i;
+
+	for (i = 0; i < RADIALS_COUNT; i++) {
+	    pattern =
+		cairo_pattern_create_radial (radials[i].cx0, radials[i].cy0,
+					     radials[i].radius0,
+					     radials[i].cx1, radials[i].cy1,
+					     radials[i].radius1);
+	    cairo_pattern_destroy (pattern);
+	}
     }
 
     cairo_perf_timer_stop ();
diff --git a/perf/pythagoras-tree.c b/perf/pythagoras-tree.c
index a1cce5c..bf37f5f 100644
--- a/perf/pythagoras-tree.c
+++ b/perf/pythagoras-tree.c
@@ -58,21 +58,23 @@ add_rectangle (cairo_t *cr, double size)
 }
 
 static cairo_perf_ticks_t
-do_pythagoras_tree (cairo_t *cr, int width, int height)
+do_pythagoras_tree (cairo_t *cr, int width, int height, int loops)
 {
     double size = 128;
 
     cairo_perf_timer_start ();
 
-    cairo_save (cr);
-    cairo_translate (cr, 0, height);
-    cairo_scale (cr, 1, -1);
+    while (loops--) {
+	cairo_save (cr);
+	cairo_translate (cr, 0, height);
+	cairo_scale (cr, 1, -1);
 
-    cairo_move_to (cr, width/2, size/2);
-    add_rectangle (cr, size);
-    cairo_set_source_rgb (cr, 0., 0., 0.);
-    cairo_fill (cr);
-    cairo_restore (cr);
+	cairo_move_to (cr, width/2, size/2);
+	add_rectangle (cr, size);
+	cairo_set_source_rgb (cr, 0., 0., 0.);
+	cairo_fill (cr);
+	cairo_restore (cr);
+    }
 
     cairo_perf_timer_stop ();
 
diff --git a/perf/rectangles.c b/perf/rectangles.c
index c224968..53b908e 100644
--- a/perf/rectangles.c
+++ b/perf/rectangles.c
@@ -32,8 +32,7 @@
 
 #define RECTANGLE_COUNT (1000)
 
-static struct
-{
+static struct {
     double x;
     double y;
     double width;
@@ -41,17 +40,18 @@ static struct
 } rects[RECTANGLE_COUNT];
 
 static cairo_perf_ticks_t
-do_rectangles (cairo_t *cr, int width, int height)
+do_rectangles (cairo_t *cr, int width, int height, int loops)
 {
     int i;
 
     cairo_perf_timer_start ();
 
-    for (i = 0; i < RECTANGLE_COUNT; i++)
-    {
-        cairo_rectangle (cr, rects[i].x, rects[i].y,
-                             rects[i].width, rects[i].height);
-        cairo_fill (cr);
+    while (loops--) {
+	for (i = 0; i < RECTANGLE_COUNT; i++) {
+	    cairo_rectangle (cr, rects[i].x, rects[i].y,
+			     rects[i].width, rects[i].height);
+	    cairo_fill (cr);
+	}
     }
 
     cairo_perf_timer_stop ();
@@ -60,18 +60,20 @@ do_rectangles (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_rectangles_once (cairo_t *cr, int width, int height)
+do_rectangles_once (cairo_t *cr, int width, int height, int loops)
 {
     int i;
 
     cairo_perf_timer_start ();
 
-    for (i = 0; i < RECTANGLE_COUNT; i++)
-    {
-        cairo_rectangle (cr, rects[i].x, rects[i].y,
-                             rects[i].width, rects[i].height);
+    while (loops--) {
+	for (i = 0; i < RECTANGLE_COUNT; i++) {
+	    cairo_rectangle (cr, rects[i].x, rects[i].y,
+			     rects[i].width, rects[i].height);
+	}
+
+	cairo_fill (cr);
     }
-    cairo_fill (cr);
 
     cairo_perf_timer_stop ();
 
@@ -79,12 +81,14 @@ do_rectangles_once (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_rectangle (cairo_t *cr, int width, int height)
+do_rectangle (cairo_t *cr, int width, int height, int loops)
 {
     cairo_perf_timer_start ();
 
-    cairo_rectangle (cr, 0, 0, width, height);
-    cairo_fill (cr);
+    while (loops--) {
+	cairo_rectangle (cr, 0, 0, width, height);
+	cairo_fill (cr);
+    }
 
     cairo_perf_timer_stop ();
 
diff --git a/perf/rounded-rectangles.c b/perf/rounded-rectangles.c
index 25133f3..2cd89a8 100644
--- a/perf/rounded-rectangles.c
+++ b/perf/rounded-rectangles.c
@@ -61,12 +61,14 @@ rounded_rectangle (cairo_t *cr,
 }
 
 static cairo_perf_ticks_t
-do_rectangle (cairo_t *cr, int width, int height)
+do_rectangle (cairo_t *cr, int width, int height, int loops)
 {
     cairo_perf_timer_start ();
 
-    rounded_rectangle (cr, 0, 0, width, height, 3.0);
-    cairo_fill (cr);
+    while (loops--) {
+	rounded_rectangle (cr, 0, 0, width, height, 3.0);
+	cairo_fill (cr);
+    }
 
     cairo_perf_timer_stop ();
 
@@ -74,18 +76,42 @@ do_rectangle (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-do_rectangles (cairo_t *cr, int width, int height)
+do_rectangles (cairo_t *cr, int width, int height, int loops)
 {
     int i;
 
     cairo_perf_timer_start ();
 
-    for (i = 0; i < RECTANGLE_COUNT; i++) {
-        rounded_rectangle (cr,
-		           rects[i].x, rects[i].y,
-                           rects[i].width, rects[i].height,
-			   3.0);
-        cairo_fill (cr);
+    while (loops--) {
+	for (i = 0; i < RECTANGLE_COUNT; i++) {
+	    rounded_rectangle (cr,
+			       rects[i].x, rects[i].y,
+			       rects[i].width, rects[i].height,
+			       3.0);
+	    cairo_fill (cr);
+	}
+    }
+
+    cairo_perf_timer_stop ();
+
+    return cairo_perf_timer_elapsed ();
+}
+
+static cairo_perf_ticks_t
+do_rectangles_once (cairo_t *cr, int width, int height, int loops)
+{
+    int i;
+
+    cairo_perf_timer_start ();
+
+    while (loops--) {
+	for (i = 0; i < RECTANGLE_COUNT; i++) {
+	    rounded_rectangle (cr,
+			       rects[i].x, rects[i].y,
+			       rects[i].width, rects[i].height,
+			       3.0);
+	}
+	cairo_fill (cr);
     }
 
     cairo_perf_timer_stop ();
@@ -111,4 +137,5 @@ rounded_rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 
     MODE (perf, "one-rounded-rectangle", do_rectangle);
     MODE (perf, "rounded-rectangles", do_rectangles);
+    MODE (perf, "rounded-rectangles-once", do_rectangles_once);
 }
diff --git a/perf/spiral.c b/perf/spiral.c
index fb2af61..2a4e568 100644
--- a/perf/spiral.c
+++ b/perf/spiral.c
@@ -44,7 +44,7 @@ draw_spiral (cairo_t *cr,
              cairo_fill_rule_t fill_rule,
              align_t align,
              close_t close,
-             int width, int height)
+             int width, int height, int loops)
 {
     int i;
     int n=0;
@@ -89,16 +89,15 @@ draw_spiral (cairo_t *cr,
     cairo_set_fill_rule (cr, fill_rule);
     cairo_set_source_rgb (cr, 1, 0, 0);
 
-    cairo_perf_timer_start (); {
-
-        cairo_move_to (cr, x[0], y[0]);
-        for (i = 1; i < n; i++) {
-            cairo_line_to (cr, x[i], y[i]);
-        }
-        cairo_close_path (cr);
-
-        cairo_fill (cr);
+    cairo_move_to (cr, x[0], y[0]);
+    for (i = 1; i < n; i++) {
+	cairo_line_to (cr, x[i], y[i]);
     }
+    cairo_close_path (cr);
+
+    cairo_perf_timer_start ();
+    while (loops--)
+        cairo_fill_preserve (cr);
     cairo_perf_timer_stop ();
 
     cairo_restore (cr);
@@ -107,83 +106,83 @@ draw_spiral (cairo_t *cr,
 }
 
 static cairo_perf_ticks_t
-draw_spiral_eo_pa_re (cairo_t *cr, int width, int height)
+draw_spiral_eo_pa_re (cairo_t *cr, int width, int height, int loops)
 {
     return draw_spiral (cr,
                         CAIRO_FILL_RULE_EVEN_ODD,
                         PIXALIGN,
                         RECTCLOSE,
-                        width, height);
+                        width, height, loops);
 }
 
 static cairo_perf_ticks_t
-draw_spiral_nz_pa_re (cairo_t *cr, int width, int height)
+draw_spiral_nz_pa_re (cairo_t *cr, int width, int height, int loops)
 {
     return draw_spiral (cr,
                         CAIRO_FILL_RULE_WINDING,
                         PIXALIGN,
                         RECTCLOSE,
-                        width, height);
+                        width, height, loops);
 }
 
 static cairo_perf_ticks_t
-draw_spiral_eo_na_re (cairo_t *cr, int width, int height)
+draw_spiral_eo_na_re (cairo_t *cr, int width, int height, int loops)
 {
     return draw_spiral (cr,
                         CAIRO_FILL_RULE_EVEN_ODD,
                         NONALIGN,
                         RECTCLOSE,
-                        width, height);
+                        width, height, loops);
 }
 
 static cairo_perf_ticks_t
-draw_spiral_nz_na_re (cairo_t *cr, int width, int height)
+draw_spiral_nz_na_re (cairo_t *cr, int width, int height, int loops)
 {
     return draw_spiral (cr,
                         CAIRO_FILL_RULE_WINDING,
                         NONALIGN,
                         RECTCLOSE,
-                        width, height);
+                        width, height, loops);
 }
 
 static cairo_perf_ticks_t
-draw_spiral_eo_pa_di (cairo_t *cr, int width, int height)
+draw_spiral_eo_pa_di (cairo_t *cr, int width, int height, int loops)
 {
     return draw_spiral (cr,
                         CAIRO_FILL_RULE_EVEN_ODD,
                         PIXALIGN,
                         DIAGCLOSE,
-                        width, height);
+                        width, height, loops);
 }
 
 static cairo_perf_ticks_t
-draw_spiral_nz_pa_di (cairo_t *cr, int width, int height)
+draw_spiral_nz_pa_di (cairo_t *cr, int width, int height, int loops)
 {
     return draw_spiral (cr,
                         CAIRO_FILL_RULE_WINDING,
                         PIXALIGN,
                         DIAGCLOSE,
-                        width, height);
+                        width, height, loops);
 }
 
 static cairo_perf_ticks_t
-draw_spiral_eo_na_di (cairo_t *cr, int width, int height)
+draw_spiral_eo_na_di (cairo_t *cr, int width, int height, int loops)
 {
     return draw_spiral (cr,
                         CAIRO_FILL_RULE_EVEN_ODD,
                         NONALIGN,
                         DIAGCLOSE,
-                        width, height);
+                        width, height, loops);
 }
 
 static cairo_perf_ticks_t
-draw_spiral_nz_na_di (cairo_t *cr, int width, int height)
+draw_spiral_nz_na_di (cairo_t *cr, int width, int height, int loops)
 {
     return draw_spiral (cr,
                         CAIRO_FILL_RULE_WINDING,
                         NONALIGN,
                         DIAGCLOSE,
-                        width, height);
+                        width, height, loops);
 }
 
 void
diff --git a/perf/stroke.c b/perf/stroke.c
index b360226..81ba8f2 100644
--- a/perf/stroke.c
+++ b/perf/stroke.c
@@ -26,7 +26,7 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_stroke (cairo_t *cr, int width, int height)
+do_stroke (cairo_t *cr, int width, int height, int loops)
 {
     cairo_arc (cr,
 	       width/2.0, height/2.0,
@@ -34,13 +34,17 @@ do_stroke (cairo_t *cr, int width, int height)
 	       0, 2 * M_PI);
     cairo_close_path (cr);
 
+    cairo_set_line_width (cr, width/5.0);
+
     cairo_perf_timer_start ();
 
-    cairo_set_line_width (cr, width/5.0);
-    cairo_stroke (cr);
+    while (loops--)
+	cairo_stroke_preserve (cr);
 
     cairo_perf_timer_stop ();
 
+    cairo_new_path (cr);
+
     return cairo_perf_timer_elapsed ();
 }
 
@@ -57,7 +61,7 @@ rounded_rectangle (cairo_t *cr,
 }
 
 static cairo_perf_ticks_t
-do_strokes (cairo_t *cr, int width, int height)
+do_strokes (cairo_t *cr, int width, int height, int loops)
 {
     /* a pair of overlapping rectangles */
     rounded_rectangle (cr,
@@ -65,17 +69,20 @@ do_strokes (cairo_t *cr, int width, int height)
 		       10);
     rounded_rectangle (cr,
 		       width/2. - 10, height/2. - 10,
-		       width - 2, height - 2,
+		       width/2. - 2, height/2. - 2,
 		       10);
 
     cairo_set_line_width (cr, 2.);
 
     cairo_perf_timer_start ();
 
-    cairo_stroke (cr);
+    while (loops--)
+	cairo_stroke_preserve (cr);
 
     cairo_perf_timer_stop ();
 
+    cairo_new_path (cr);
+
     return cairo_perf_timer_elapsed ();
 }
 
diff --git a/perf/subimage_copy.c b/perf/subimage_copy.c
index 25b16cc..9bec2fb 100644
--- a/perf/subimage_copy.c
+++ b/perf/subimage_copy.c
@@ -35,17 +35,20 @@
  */
 
 static cairo_perf_ticks_t
-do_subimage_copy (cairo_t *cr, int width, int height)
+do_subimage_copy (cairo_t *cr, int width, int height, int loops)
 {
     cairo_rectangle (cr, 2, 2, 4, 4);
     cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
     cairo_perf_timer_start ();
 
-    cairo_fill (cr);
+    while (loops--)
+	cairo_fill_preserve (cr);
 
     cairo_perf_timer_stop ();
 
+    cairo_new_path (cr);
+
     return cairo_perf_timer_elapsed ();
 }
 
diff --git a/perf/tessellate.c b/perf/tessellate.c
index 4af3841..1a4d978 100644
--- a/perf/tessellate.c
+++ b/perf/tessellate.c
@@ -99,7 +99,7 @@ point_t points[300] = {
 };
 
 static cairo_perf_ticks_t
-do_tessellate (cairo_t *cr, int num_points)
+do_tessellate (cairo_t *cr, int num_points, int loops)
 {
     int i;
 
@@ -113,7 +113,8 @@ do_tessellate (cairo_t *cr, int num_points)
      * we'll have to be careful since cairo_in_fill might eventually
      * be optimized to have an implementation that doesn't necessarily
      * include tessellation. */
-    cairo_in_fill (cr, 50, 50);
+    while (loops--)
+	cairo_in_fill (cr, 50, 50);
 
     cairo_perf_timer_stop ();
 
@@ -123,21 +124,21 @@ do_tessellate (cairo_t *cr, int num_points)
 }
 
 static cairo_perf_ticks_t
-tessellate_16 (cairo_t *cr, int width, int height)
+tessellate_16 (cairo_t *cr, int width, int height, int loops)
 {
-    return do_tessellate (cr, 16);
+    return do_tessellate (cr, 16, loops);
 }
 
 static cairo_perf_ticks_t
-tessellate_64 (cairo_t *cr, int width, int height)
+tessellate_64 (cairo_t *cr, int width, int height, int loops)
 {
-    return do_tessellate (cr, 64);
+    return do_tessellate (cr, 64, loops);
 }
 
 static cairo_perf_ticks_t
-tessellate_256 (cairo_t *cr, int width, int height)
+tessellate_256 (cairo_t *cr, int width, int height, int loops)
 {
-    return do_tessellate (cr, 256);
+    return do_tessellate (cr, 256, loops);
 }
 
 void
diff --git a/perf/text.c b/perf/text.c
index 4448802..9c51274 100644
--- a/perf/text.c
+++ b/perf/text.c
@@ -26,27 +26,30 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_text (cairo_t *cr, int width, int height)
+do_text (cairo_t *cr, int width, int height, int loops)
 {
     const char text[] = "the jay, pig, fox, zebra and my wolves quack";
     int len = strlen (text);
     double x, y;
     int i = 0, j = 0;
 
+    cairo_set_font_size (cr, 9);
+
     cairo_perf_timer_start ();
 
-    cairo_set_font_size (cr, 9);
-    do {
-	cairo_move_to (cr, 0, j++ * 10);
-	cairo_show_text (cr, text + i);
-	cairo_get_current_point (cr, &x, &y);
-	while (x < width && cairo_status (cr) == CAIRO_STATUS_SUCCESS) {
-	    cairo_show_text (cr, text);
+    while (loops--) {
+	do {
+	    cairo_move_to (cr, 0, j++ * 10);
+	    cairo_show_text (cr, text + i);
 	    cairo_get_current_point (cr, &x, &y);
-	}
-	if (++i >= len)
-	    i = 0;
-    } while (y < height && cairo_status (cr) == CAIRO_STATUS_SUCCESS);
+	    while (x < width && cairo_status (cr) == CAIRO_STATUS_SUCCESS) {
+		cairo_show_text (cr, text);
+		cairo_get_current_point (cr, &x, &y);
+	    }
+	    if (++i >= len)
+		i = 0;
+	} while (y < height && cairo_status (cr) == CAIRO_STATUS_SUCCESS);
+    }
 
     cairo_perf_timer_stop ();
 
diff --git a/perf/twin.c b/perf/twin.c
index f65cccf..4dd06dd 100644
--- a/perf/twin.c
+++ b/perf/twin.c
@@ -6,7 +6,8 @@
 static cairo_perf_ticks_t
 do_twin (cairo_t *cr,
 	 int width,
-	 int height)
+	 int height,
+	 int loops)
 {
     int i, j, h;
     unsigned char s[2] = {0, 0};
@@ -15,26 +16,28 @@ do_twin (cairo_t *cr,
     cairo_paint (cr);
     cairo_set_source_rgb (cr, 0, 0, 0);
 
-    cairo_perf_timer_start ();
-
     cairo_select_font_face (cr,
 			    "@cairo:",
 			    CAIRO_FONT_SLANT_NORMAL,
 			    CAIRO_FONT_WEIGHT_NORMAL);
 
-    h = 2;
-    for (i = 8; i < 48; i >= 24 ? i+=3 : i++) {
-	cairo_set_font_size (cr, i);
-	for (j = 33; j < 128; j++) {
-	    if (j == 33 || (j == 80 && i > 24)) {
-		h += i + 2;
-		cairo_move_to (cr, 10, h);
+    cairo_perf_timer_start ();
+
+    while (loops--) {
+	h = 2;
+	for (i = 8; i < 48; i >= 24 ? i+=3 : i++) {
+	    cairo_set_font_size (cr, i);
+	    for (j = 33; j < 128; j++) {
+		if (j == 33 || (j == 80 && i > 24)) {
+		    h += i + 2;
+		    cairo_move_to (cr, 10, h);
+		}
+		s[0] = j;
+		cairo_text_path (cr, (const char *) s);
 	    }
-	    s[0] = j;
-	    cairo_text_path (cr, (const char *) s);
 	}
+	cairo_fill (cr);
     }
-    cairo_fill (cr);
 
     cairo_perf_timer_stop ();
     return cairo_perf_timer_elapsed ();
diff --git a/perf/unaligned-clip.c b/perf/unaligned-clip.c
index f379b61..f532b55 100644
--- a/perf/unaligned-clip.c
+++ b/perf/unaligned-clip.c
@@ -29,33 +29,32 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_unaligned_clip (cairo_t *cr, int width, int height)
+do_unaligned_clip (cairo_t *cr, int width, int height, int loops)
 {
-    cairo_save (cr);
-
     cairo_perf_timer_start ();
 
-    /* First a triangular clip that obviously isn't along device-pixel
-     * boundaries. */
-    cairo_move_to (cr, 50, 50);
-    cairo_line_to (cr, 50, 90);
-    cairo_line_to (cr, 90, 90);
-    cairo_close_path (cr);
-    cairo_clip (cr);
+    while (loops--) {
+	/* First a triangular clip that obviously isn't along device-pixel
+	 * boundaries. */
+	cairo_move_to (cr, 50, 50);
+	cairo_line_to (cr, 50, 90);
+	cairo_line_to (cr, 90, 90);
+	cairo_close_path (cr);
+	cairo_clip (cr);
 
-    /* Then a rectangular clip that would be but for the non-integer
-     * scaling. */
-    cairo_scale (cr, 1.1, 1.1);
-    cairo_rectangle (cr, 55, 55, 35, 35);
-    cairo_clip (cr);
+	/* Then a rectangular clip that would be but for the non-integer
+	 * scaling. */
+	cairo_scale (cr, 1.1, 1.1);
+	cairo_rectangle (cr, 55, 55, 35, 35);
+	cairo_clip (cr);
 
-    /* And paint something to force the clip to be evaluated. */
-    cairo_paint (cr);
+	/* And paint something to force the clip to be evaluated. */
+	cairo_paint (cr);
 
+	cairo_reset_clip (cr);
+    }
     cairo_perf_timer_stop ();
 
-    cairo_restore (cr);
-
     return cairo_perf_timer_elapsed ();
 }
 
diff --git a/perf/world-map.c b/perf/world-map.c
index 5a53f30..265c8e3 100644
--- a/perf/world-map.c
+++ b/perf/world-map.c
@@ -49,52 +49,54 @@ typedef struct _wm_element {
 #include "world-map.h"
 
 static cairo_perf_ticks_t
-do_world_map (cairo_t *cr, int width, int height)
+do_world_map (cairo_t *cr, int width, int height, int loops)
 {
     const wm_element_t *e;
     double cx, cy;
 
-    cairo_perf_timer_start ();
+    cairo_set_line_width (cr, 0.2);
 
-    cairo_set_source_rgb (cr, .68, .85, .90); /* lightblue */
-    cairo_rectangle (cr, 0, 0, 800, 400);
-    cairo_fill (cr);
+    cairo_perf_timer_start ();
 
-    cairo_set_line_width (cr, 0.2);
+    while (loops--) {
+	cairo_set_source_rgb (cr, .68, .85, .90); /* lightblue */
+	cairo_rectangle (cr, 0, 0, 800, 400);
+	cairo_fill (cr);
 
-    e = &countries[0];
-    while (1) {
-	switch (e->type) {
-	case WM_NEW_PATH:
-	case WM_END:
-	    cairo_set_source_rgb (cr, .75, .75, .75); /* silver */
-	    cairo_fill_preserve (cr);
-	    cairo_set_source_rgb (cr, .50, .50, .50); /* gray */
-	    cairo_stroke (cr);
-	    cairo_move_to (cr, e->x, e->y);
-	    break;
-	case WM_MOVE_TO:
-	    cairo_close_path (cr);
-	    cairo_move_to (cr, e->x, e->y);
-	    break;
-	case WM_LINE_TO:
-	    cairo_line_to (cr, e->x, e->y);
-	    break;
-	case WM_HLINE_TO:
-	    cairo_get_current_point (cr, &cx, &cy);
-	    cairo_line_to (cr, e->x, cy);
-	    break;
-	case WM_VLINE_TO:
-	    cairo_get_current_point (cr, &cx, &cy);
-	    cairo_line_to (cr, cx, e->y);
-	    break;
-	case WM_REL_LINE_TO:
-	    cairo_rel_line_to (cr, e->x, e->y);
-	    break;
+	e = &countries[0];
+	while (1) {
+	    switch (e->type) {
+	    case WM_NEW_PATH:
+	    case WM_END:
+		cairo_set_source_rgb (cr, .75, .75, .75); /* silver */
+		cairo_fill_preserve (cr);
+		cairo_set_source_rgb (cr, .50, .50, .50); /* gray */
+		cairo_stroke (cr);
+		cairo_move_to (cr, e->x, e->y);
+		break;
+	    case WM_MOVE_TO:
+		cairo_close_path (cr);
+		cairo_move_to (cr, e->x, e->y);
+		break;
+	    case WM_LINE_TO:
+		cairo_line_to (cr, e->x, e->y);
+		break;
+	    case WM_HLINE_TO:
+		cairo_get_current_point (cr, &cx, &cy);
+		cairo_line_to (cr, e->x, cy);
+		break;
+	    case WM_VLINE_TO:
+		cairo_get_current_point (cr, &cx, &cy);
+		cairo_line_to (cr, cx, e->y);
+		break;
+	    case WM_REL_LINE_TO:
+		cairo_rel_line_to (cr, e->x, e->y);
+		break;
+	    }
+	    if (e->type == WM_END)
+		break;
+	    e++;
 	}
-	if (e->type == WM_END)
-	    break;
-	e++;
     }
 
     cairo_perf_timer_stop ();
diff --git a/perf/zrusin.c b/perf/zrusin.c
index 9393932..d57c7c4 100644
--- a/perf/zrusin.c
+++ b/perf/zrusin.c
@@ -45,7 +45,7 @@ zrusin_another_path (cairo_t *cr)
 }
 
 static cairo_perf_ticks_t
-zrusin_another_tessellate (cairo_t *cr, int width, int height)
+zrusin_another_tessellate (cairo_t *cr, int width, int height, int loops)
 {
     zrusin_another_path (cr);
 
@@ -56,7 +56,8 @@ zrusin_another_tessellate (cairo_t *cr, int width, int height)
      * we'll have to be careful since cairo_in_fill might eventually
      * be optimized to have an implementation that doesn't necessarily
      * include tessellation. */
-    cairo_in_fill (cr, 50, 50);
+    while (loops--)
+	cairo_in_fill (cr, 50, 50);
 
     cairo_perf_timer_stop ();
 
@@ -66,14 +67,15 @@ zrusin_another_tessellate (cairo_t *cr, int width, int height)
 }
 
 static cairo_perf_ticks_t
-zrusin_another_fill (cairo_t *cr, int width, int height)
+zrusin_another_fill (cairo_t *cr, int width, int height, int loops)
 {
     zrusin_another_path (cr);
     cairo_set_source_rgb (cr, 0.0, 0.0, 0.8); /* blue */
 
     cairo_perf_timer_start ();
 
-    cairo_fill (cr);
+    while (loops--)
+	cairo_fill_preserve (cr);
 
     cairo_perf_timer_stop ();
 
commit 60c574ad062f3d8526056942bb7c9e71610a2773
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Aug 5 15:11:00 2009 +0100

    [surface] Protect against the user setting a fallback resolution of 0.
    
    Bug 23067 -- using clear drawing operator crashes printing
    http://bugs.freedesktop.org/show_bug.cgi?id=23067
    
    Here we were hitting an assert within the paginated surface after creating
    a zero sized fallback image, due to the paginated surface being created
    with an x fallback resolution of 0 dpi (by
    _gtk_printer_create_cairo_surface(), gtk/gtkprinter.c:924).
    
    Avoid the bug by guarding against bad input to
    cairo_surface_set_fallback_resolution() which also allows us to identity
    the invalid caller.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f656ed5..8c8b867 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1218,6 +1218,14 @@ cairo_surface_set_fallback_resolution (cairo_surface_t	*surface,
 	return;
     }
 
+    if (x_pixels_per_inch <= 0 || y_pixels_per_inch <= 0) {
+	/* XXX Could delay raising the error until we fallback, but throwing
+	 * the error here means that we can catch the real culprit.
+	 */
+	status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_MATRIX);
+	return;
+    }
+
     _cairo_surface_begin_modification (surface);
 
     surface->x_fallback_resolution = x_pixels_per_inch;
commit a3f393cf644d75065fe524e2fbb28f55844f43bf
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Aug 6 09:52:34 2009 +0100

    [configure] Also check for libiberty.h
    
    cairo-trace also uses the libiberty.h without checking for its presence --
    causing a build failure if bfd was installed but not that header.

diff --git a/configure.ac b/configure.ac
index 083b0cc..445cb67 100644
--- a/configure.ac
+++ b/configure.ac
@@ -618,6 +618,7 @@ AM_CONDITIONAL(BUILD_TRACE,
 AC_CHECK_LIB(bfd, bfd_openr,
 	 [AC_CHECK_HEADER(bfd.h, [have_bfd=yes],
 	 [have_bfd=no])], [have_bfd=no])
+AC_CHECK_HEADER(libiberty.h,, [have_bfd=no])
 if test "x$have_bfd" = "xyes"; then
     AC_DEFINE([HAVE_BFD], [1], [Define to 1 if you have the binutils development files installed])
     BFD_LIBS=-lbfd
commit 51bd27afa147f78c8f4f3778cee725b6444e7eb0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Aug 6 09:41:15 2009 +0100

    [boilerplate/test] Convert make-*-constructors to shell
    
    Remove the intermediate C program that was a nuisance whilst
    cross-compiling and replace it with a simple shell script that is just a
    combination of cat + sed.

diff --git a/boilerplate/Makefile.am b/boilerplate/Makefile.am
index c8b5d41..cb92c2b 100644
--- a/boilerplate/Makefile.am
+++ b/boilerplate/Makefile.am
@@ -48,21 +48,12 @@ endif
 
 libcairoboilerplate_la_LIBADD += $(CAIROBOILERPLATE_LIBS)
 
-# we need to workaround the introduction of CC_FOR_BUILD with older builds
-make-cairo-boilerplate-constructors$(EXEEXT): make-cairo-boilerplate-constructors.c
-	if test -n "$(CC_FOR_BUILD)"; then \
-		$(CC_FOR_BUILD) $^ -o $@; \
-	else \
-		$(CC) $^ -o $@; \
-	fi
-
-cairo-boilerplate-constructors.c: Makefile $(enabled_cairo_boilerplate_sources) make-cairo-boilerplate-constructors$(EXEEXT)
-	echo '(cd $(srcdir) && $(top_builddir)/boilerplate/make-cairo-boilerplate-constructors$(EXEEXT) $(enabled_cairo_boilerplate_sources)) > $@'
-	./make-cairo-boilerplate-constructors$(EXEEXT) $(srcdir) $(enabled_cairo_boilerplate_sources) > $@
+cairo-boilerplate-constructors.c: Makefile $(enabled_cairo_boilerplate_sources) make-cairo-boilerplate-constructors.sh
+	(cd $(srcdir) && sh ./make-cairo-boilerplate-constructors.sh $(enabled_cairo_boilerplate_sources)) > $@
 
 BUILT_SOURCES += cairo-boilerplate-constructors.c
-EXTRA_DIST += $(BUILT_SOURCES) make-cairo-boilerplate-constructors.c
-CLEANFILES += $(BUILT_SOURCES) make-cairo-boilerplate-constructors
+EXTRA_DIST += $(BUILT_SOURCES) make-cairo-boilerplate-constructors.sh
+CLEANFILES += $(BUILT_SOURCES)
 
 test: check
 
diff --git a/boilerplate/make-cairo-boilerplate-constructors.c b/boilerplate/make-cairo-boilerplate-constructors.c
deleted file mode 100644
index b954492..0000000
--- a/boilerplate/make-cairo-boilerplate-constructors.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright © 2009 Joonas Pihlaja
- * Copyright © 2009 Chris Wilson
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no representations
- * about the suitability of this software for any purpose.  It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- */
-/* Usage:
- *   ./make-cairo-boilerplate-constructors [sources.c...] >cairo-boilerplate-constructors.c
- *
- * Parses invocations of the CAIRO_BOILERPLATE macro from the source files
- * given on the command line, gathers names of targets, and outputs a C
- * file with one function _cairo_boilerplate_register_targets() which
- * calls the functions _register_<target>() in reverse order.
- */
-
-/* Keep this file ANSI compliant without any special needs. */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#define NAME "make-cairo-boilerplate-constructors.c"
-
-static struct name {
-    struct name *next;
-    char         name[1];
-} *head;
-
-static void *
-xmalloc (size_t n)
-{
-    void *bytes = malloc(n);
-    if (!bytes) {
-        fprintf (stderr, "Out of memory\n");
-        exit(2);
-    }
-    return bytes;
-}
-
-static void
-add_name (const char *name)
-{
-    struct name *node;
-    int len;
-
-    len = strlen (name);
-    node = xmalloc (sizeof (struct name) + len);
-    memcpy (node->name, name, len + 1);
-
-    node->next = head;
-    head = node;
-}
-
-static int
-scan_file (const char *filename,
-           FILE       *fp)
-{
-    int line_num = 0;
-    char linebuf[1024];
-    int fail = 0;
-
-    while (fgets (linebuf, sizeof (linebuf)-1, fp)) {
-        char *macro;
-        char *name;
-        size_t length;
-
-        line_num++;
-        linebuf[sizeof (linebuf)-1] = 0;
-
-        macro = strstr (linebuf, "CAIRO_BOILERPLATE");
-        if (!macro)
-            continue;
-        macro += strlen ("CAIRO_BOILERPLATE");
-
-        length = strspn (macro, " (");
-        if (length == 0)
-            continue;
-        name = macro + length;
-
-        length = strspn (name,
-                         "_"
-                         "abcdefghijklmnopqrstuvwxyz"
-                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                         "0123456789");
-        name[length] = 0;
-
-        if (length == 0) {
-            fprintf (stderr, "%s:%d: CAIRO_BOILERPLATE invocation "
-                     "can't be parsed by " NAME"\n",
-                     filename, line_num);
-            fail = 1;
-            continue;
-        }
-
-        add_name (name);
-    }
-
-    return fail;
-}
-
-int
-main (int argc, char **argv)
-{
-    char buf[PATH_MAX];
-    int i;
-    int fail = 0;
-    struct name *node;
-
-    for (i = 2; i < argc; i++) {
-        FILE *fp;
-
-	snprintf (buf, sizeof (buf), "%s/%s", argv[1], argv[i]);
-
-	fp = fopen (buf, "r");
-        if (fp != NULL) {
-            fail |= scan_file (argv[i], fp);
-            fclose (fp);
-        } else
-	    fail = 1;
-    }
-    if (fail)
-        exit(1);
-
-    puts ("/* WARNING: Autogenerated file - see " NAME "! */");
-    puts ("");
-    puts ("#include \"cairo-boilerplate-private.h\"");
-    puts ("");
-
-    for (node = head; node; node = node->next) {
-        printf ("extern void _register_%s (void);\n",
-               node->name);
-    }
-    puts("");
-
-    puts ("void _cairo_boilerplate_register_all (void);");
-    puts("");
-
-    puts ("void");
-    puts ("_cairo_boilerplate_register_all (void)");
-    puts ("{");
-    for (node = head; node; node = node->next) {
-        printf ("    _register_%s ();\n", node->name);
-    }
-    puts ("}");
-
-    return 0;
-}
diff --git a/boilerplate/make-cairo-boilerplate-constructors.sh b/boilerplate/make-cairo-boilerplate-constructors.sh
new file mode 100644
index 0000000..2c7fc85
--- /dev/null
+++ b/boilerplate/make-cairo-boilerplate-constructors.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+cat <<HERE
+/* WARNING: Autogenerated file - see $0! */
+
+#include "cairo-boilerplate-private.h"
+
+void _cairo_boilerplate_register_all (void);
+
+HERE
+
+cat "$@" |  sed '/^CAIRO_BOILERPLATE/!d; s/CAIRO_BOILERPLATE.*(\(.*\),.*/extern void _register_\1 (void);/'
+
+cat <<HERE
+
+void
+_cairo_boilerplate_register_all (void)
+{
+HERE
+
+cat "$@" |  sed '/^CAIRO_BOILERPLATE/!d; s/CAIRO_BOILERPLATE.*(\(.*\),.*/    _register_\1 ();/'
+
+echo "}"
+
diff --git a/build/configure.ac.tools b/build/configure.ac.tools
index 2fd0940..a24dbce 100644
--- a/build/configure.ac.tools
+++ b/build/configure.ac.tools
@@ -8,14 +8,6 @@ AC_PROG_CXX dnl required for BeOS (and cannot be a conditional dependency)
 AM_PROG_CC_C_O
 AC_C_INLINE
 
-# Set reasonable defaults for the tools in case we are cross-compiling
-if test "${build}" != "${host}" ; then
-    CC_FOR_BUILD=${CC_FOR_BUILD-cc}
-else
-    CC_FOR_BUILD=${CC}
-fi
-AC_SUBST(CC_FOR_BUILD)
-
 dnl ===========================================================================
 
 PKG_PROG_PKG_CONFIG()
diff --git a/test/Makefile.am b/test/Makefile.am
index 6e03910..a052393 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -69,11 +69,8 @@ test_sources += $(test)
 
 TESTS += cairo-test-suite$(EXEEXT)
 
-make-cairo-test-constructors$(EXEEXT): make-cairo-test-constructors.c
-	$(CC_FOR_BUILD) $^ -o $@
-
-cairo-test-constructors.c: Makefile $(test_sources) make-cairo-test-constructors$(EXEEXT)
-	./make-cairo-test-constructors$(EXEEXT) $(srcdir) $(test_sources) > $@
+cairo-test-constructors.c: Makefile $(test_sources) make-cairo-test-constructors.sh
+	(cd $(srcdir) && sh ./make-cairo-test-constructors.sh $(test_sources)) > $@
 
 cairo_test_suite_SOURCES = 		\
 	$(cairo_test_suite_sources)	\
@@ -121,8 +118,8 @@ cairo_test_trace_DEPENDENCIES = \
 endif
 
 BUILT_SOURCES += cairo-test-constructors.c
-EXTRA_DIST += $(BUILT_SOURCES) $(noinst_SCRIPTS) COPYING make-cairo-test-constructors.c
-CLEANFILES += $(BUILT_SOURCES) make-cairo-test-constructors
+EXTRA_DIST += $(BUILT_SOURCES) $(noinst_SCRIPTS) COPYING make-cairo-test-constructors.sh
+CLEANFILES += $(BUILT_SOURCES)
 
 # All tests which have a reference image go here.
 REFERENCE_IMAGES = \
diff --git a/test/make-cairo-test-constructors.c b/test/make-cairo-test-constructors.c
deleted file mode 100644
index 15c6470..0000000
--- a/test/make-cairo-test-constructors.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright © 2009 Joonas Pihlaja
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no representations
- * about the suitability of this software for any purpose.  It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- */
-/* Usage:
- *   ./make-cairo-test-constructors [tests.c...] >cairo-test-constructors.c
- *
- * Parses invocations of the CAIRO_TEST macro from the source files
- * given on the command line, gathers names of tests, and outputs a C
- * file with one function _cairo_test_runner_register_tests() which
- * calls the functions _register_<testname>() in reverse order.
- */
-
-/* Keep this file ANSI compliant without any special needs. */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#define NAME "make-cairo-test-constructors.c"
-
-static struct name {
-    struct name *next;
-    char         name[1];
-} *head;
-
-static void *
-xmalloc (size_t n)
-{
-    void *bytes = malloc(n);
-    if (!bytes) {
-        fprintf (stderr, "Out of memory\n");
-        exit(2);
-    }
-    return bytes;
-}
-
-static void
-add_name (const char *name)
-{
-    struct name *node;
-    int len;
-
-    len = strlen (name);
-    node = xmalloc (sizeof (struct name) + len);
-    memcpy (node->name, name, len + 1);
-
-    node->next = head;
-    head = node;
-}
-
-static int
-scan_file (const char   *filename,
-           FILE         *fp)
-{
-    int line_num = 0;
-    char linebuf[1024];
-    int fail = 0;
-
-    while (fgets (linebuf, sizeof (linebuf)-1, fp)) {
-        char *macro;
-        char *name;
-        size_t length;
-
-        line_num++;
-        linebuf[sizeof (linebuf)-1] = 0;
-
-        macro = strstr (linebuf, "CAIRO_TEST");
-        if (!macro)
-            continue;
-        macro += strlen ("CAIRO_TEST");
-
-        length = strspn (macro, " (");
-        if (length == 0)
-            continue;
-        name = macro + length;
-
-        length = strspn (name,
-                         "_"
-                         "abcdefghijklmnopqrstuvwxyz"
-                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                         "0123456789");
-        name[length] = 0;
-
-        if (length == 0) {
-            fprintf (stderr, "%s:%d: CAIRO_TEST invocation "
-                     "can't be parsed by " NAME "\n",
-                     filename, line_num);
-            fail = 1;
-            continue;
-        }
-
-        add_name (name);
-    }
-
-    return fail;
-}
-
-int
-main (int argc, char **argv)
-{
-    char buf[PATH_MAX];
-    int i;
-    int fail = 0;
-    struct name *node;
-
-    for (i = 2; i < argc; i++) {
-        FILE *fp;
-
-	snprintf (buf, sizeof (buf), "%s/%s", argv[1], argv[i]);
-
-	fp = fopen (buf, "r");
-        if (fp) {
-            fail |= scan_file (argv[i], fp);
-            fclose (fp);
-        } else
-	    fail = 1;
-    }
-    if (fail)
-        exit(1);
-
-    puts ("/* WARNING: Autogenerated file - see " NAME "! */");
-    puts ("");
-    puts ("#include \"cairo-test-private.h\"");
-    puts ("");
-
-    for (node = head; node; node = node->next) {
-        printf ("extern void _register_%s (void);\n",
-               node->name);
-    }
-    puts("");
-
-    puts ("void _cairo_test_runner_register_tests (void);");
-    puts("");
-
-    puts ("void");
-    puts ("_cairo_test_runner_register_tests (void)");
-    puts ("{");
-    for (node = head; node; node = node->next) {
-        printf ("    _register_%s ();\n", node->name);
-    }
-    puts ("}");
-
-    return 0;
-}
diff --git a/test/make-cairo-test-constructors.sh b/test/make-cairo-test-constructors.sh
new file mode 100644
index 0000000..d0325e8
--- /dev/null
+++ b/test/make-cairo-test-constructors.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+cat <<HERE
+/* WARNING: Autogenerated file - see $0! */
+
+#include "cairo-test-private.h"
+
+void _cairo_test_runner_register_tests (void);
+
+HERE
+
+cat "$@" |  sed '/^CAIRO_TEST/!d; s/CAIRO_TEST.*(\(.*\),.*/extern void _register_\1 (void);/'
+cat <<HERE
+
+void
+_cairo_test_runner_register_tests (void)
+{
+HERE
+
+cat "$@" |  sed '/^CAIRO_TEST/!d; s/CAIRO_TEST.*(\(.*\),.*/    _register_\1 ();/'
+
+echo "}"
+
+
commit 5dd29d7e2da8684ea46c8f1baba42e6dc64f1351
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Aug 6 09:55:43 2009 +0100

    [directfb] Conditionally use DSPF_BGR555
    
    Appears that this token is more recent than some of my headers, so check
    for its presence before use.

diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 967b044..8247fb9 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -246,7 +246,9 @@ _directfb_to_pixman_format (DFBSurfacePixelFormat format)
     case DSPF_LUT2: return PIXMAN_invalid;
     case DSPF_RGB444: return PIXMAN_x4r4g4b4;
     case DSPF_RGB555: return PIXMAN_x1r5g5b5;
+#if DFB_NUM_PIXELFORMATS >= 29
     case DSPF_BGR555: return PIXMAN_x1b5g5r5;
+#endif
     }
     return PIXMAN_invalid;
 }
@@ -269,7 +271,9 @@ _directfb_from_pixman_format (pixman_format_code_t format)
     case PIXMAN_a4: return DSPF_A4;
     case PIXMAN_x4r4g4b4: return DSPF_RGB444;
     case PIXMAN_x1r5g5b5: return DSPF_RGB555;
+#if DFB_NUM_PIXELFORMATS >= 29
     case PIXMAN_x1b5g5r5: return DSPF_BGR555;
+#endif
     default: return 0;
     }
 }


More information about the cairo-commit mailing list