[cairo-commit] 8 commits - perf/cairo-perf-compare-backends.c perf/cairo-perf-cover.c perf/cairo-perf-diff-files.c perf/cairo-perf-graph-files.c perf/cairo-perf.h perf/cairo-perf-report.c perf/dragon.c perf/.gitignore perf/Makefile.am src/cairo-scaled-font.c test/fill-image.c test/fill-image.ref.png test/huge-linear.c test/huge-linear.ps3.ref.png test/huge-linear.ref.png test/huge-pattern.c test/huge-pattern.pdf.argb32.ref.png test/huge-pattern.pdf.ref.png test/huge-pattern.pdf.rgb24.ref.png test/huge-pattern.ps3.ref.png test/huge-pattern.ref.png test/huge-radial.c test/huge-radial.ps3.ref.png test/huge-radial.ref.png test/large-source-roi.c test/Makefile.am

Chris Wilson ickle at kemper.freedesktop.org
Wed Jan 14 08:53:16 PST 2009


 dev/null                           |binary
 perf/.gitignore                    |    1 
 perf/Makefile.am                   |    8 
 perf/cairo-perf-compare-backends.c |  393 +++++++++++++++++++++++++++++++++++++
 perf/cairo-perf-cover.c            |   80 +++++++
 perf/cairo-perf-diff-files.c       |    2 
 perf/cairo-perf-graph-files.c      |    2 
 perf/cairo-perf-report.c           |   43 +++-
 perf/cairo-perf.h                  |    9 
 perf/dragon.c                      |   42 +++
 src/cairo-scaled-font.c            |   63 +++--
 test/Makefile.am                   |   13 -
 test/fill-image.c                  |   83 +++++++
 test/fill-image.ref.png            |binary
 test/huge-linear.c                 |   67 ++++++
 test/huge-linear.ps3.ref.png       |binary
 test/huge-linear.ref.png           |binary
 test/huge-pattern.c                |   65 ------
 test/huge-radial.c                 |   69 ++++++
 test/huge-radial.ps3.ref.png       |binary
 test/huge-radial.ref.png           |binary
 test/large-source-roi.c            |   28 +-
 22 files changed, 853 insertions(+), 115 deletions(-)

New commits:
commit 6801f28f6dfeb21eec44052e75156e9d2b82422e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jan 14 13:59:28 2009 +0000

    [perf] Add a utility to compare backends.
    
    A minor variation on cairo-perf-diff-files that compares tests with the
    same name for multiple backends.

diff --git a/perf/.gitignore b/perf/.gitignore
index 29ec88d..a5d452f 100644
--- a/perf/.gitignore
+++ b/perf/.gitignore
@@ -1,6 +1,7 @@
 TAGS
 tags
 cairo-perf
+cairo-perf-compare-backends
 cairo-perf-diff-files
 cairo-perf-graph-files
 valgrind-log
diff --git a/perf/Makefile.am b/perf/Makefile.am
index 5dcc0ab..5927199 100644
--- a/perf/Makefile.am
+++ b/perf/Makefile.am
@@ -7,7 +7,10 @@ AM_CPPFLAGS =					\
 	-I$(top_builddir)/src			\
 	$(CAIRO_CFLAGS)
 
-EXTRA_PROGRAMS += cairo-perf cairo-perf-diff-files cairo-perf-graph-files
+EXTRA_PROGRAMS += cairo-perf \
+		  cairo-perf-diff-files \
+		  cairo-perf-compare-backends \
+		  cairo-perf-graph-files
 EXTRA_DIST += cairo-perf-diff COPYING
 EXTRA_LTLIBRARIES += libcairoperf.la
 
@@ -70,6 +73,9 @@ libcairoperf_la_SOURCES = \
 cairo_perf_diff_files_SOURCES =	\
 	cairo-perf-diff-files.c
 
+cairo_perf_compare_backends_SOURCES =	\
+	cairo-perf-compare-backends.c
+
 cairo_perf_graph_files_SOURCES = \
 	cairo-perf-graph.h \
 	cairo-perf-graph-files.c \
diff --git a/perf/cairo-perf-compare-backends.c b/perf/cairo-perf-compare-backends.c
new file mode 100644
index 0000000..e6ab37f
--- /dev/null
+++ b/perf/cairo-perf-compare-backends.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright © 2006 Red Hat, Inc.
+ * 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.
+ *
+ * Authors: Carl Worth <cworth at cworth.org>
+ *          Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-perf.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <math.h>
+#include <assert.h>
+
+typedef struct _cairo_perf_report_options {
+    double min_change;
+    int use_utf;
+    int print_change_bars;
+    int use_ms;
+} cairo_perf_report_options_t;
+
+typedef struct _cairo_perf_diff_files_args {
+    const char **filenames;
+    int num_filenames;
+    cairo_perf_report_options_t options;
+} cairo_perf_diff_files_args_t;
+
+static int
+test_diff_cmp (const void *a, const void *b)
+{
+    const test_diff_t *a_diff = a;
+    const test_diff_t *b_diff = b;
+
+    /* Reverse sort by magnitude of change so larger changes come
+     * first */
+    if (a_diff->change > b_diff->change)
+	return -1;
+
+    if (a_diff->change < b_diff->change)
+	return 1;
+
+    return 0;
+}
+
+#define CHANGE_BAR_WIDTH 70
+static void
+print_change_bar (double change, double max_change, int use_utf)
+{
+    int units_per_cell = (int) ceil (max_change / CHANGE_BAR_WIDTH);
+    static char const *ascii_boxes[8] = {
+	"****","***" ,"***", "**",
+	"**",  "*",   "*",   ""
+    };
+    static char const *utf_boxes[8] = {
+	"â–ˆ", "â–‰", "â–Š", "â–‹",
+	"▌", "▍", "▎", "▏"
+    };
+    char const **boxes = use_utf ? utf_boxes : ascii_boxes;
+
+    /* For a 1.0x speedup we want a zero-size bar to show "no
+     * change". */
+    change -= 1.0;
+
+    while (change > units_per_cell) {
+	printf ("%s", boxes[0]);
+	change -= units_per_cell;
+    }
+
+    change /= units_per_cell;
+
+    if (change > 7.5/8.0)
+	printf ("%s", boxes[0]);
+    else if (change > 6.5/8.0)
+	printf ("%s", boxes[1]);
+    else if (change > 5.5/8.0)
+	printf ("%s", boxes[2]);
+    else if (change > 4.5/8.0)
+	printf ("%s", boxes[3]);
+    else if (change > 3.5/8.0)
+	printf ("%s", boxes[4]);
+    else if (change > 2.5/8.0)
+	printf ("%s", boxes[5]);
+    else if (change > 1.5/8.0)
+	printf ("%s", boxes[6]);
+    else if (change > 0.5/8.0)
+	printf ("%s", boxes[7]);
+
+    printf ("\n");
+}
+
+static void
+test_diff_print (test_diff_t			*diff,
+		 double				 max_change,
+		 cairo_perf_report_options_t	*options)
+{
+    int i;
+    double test_time;
+    double change;
+
+    printf ("(%s, size: %d)\n",
+	    diff->tests[0]->name,
+	    diff->tests[0]->size);
+
+    for (i = 0; i < diff->num_tests; i++) {
+	test_time = diff->tests[i]->stats.min_ticks;
+	if (options->use_ms)
+	    test_time /= diff->tests[i]->stats.ticks_per_ms;
+	change = diff->max / test_time;
+	printf ("%8s-%s-%s\t%6.2f: %5.2fx ",
+		diff->tests[i]->backend,
+		diff->tests[i]->content,
+		diff->tests[i]->configuration,
+		diff->tests[i]->stats.min_ticks / diff->tests[i]->stats.ticks_per_ms,
+		change);
+
+	if (options->print_change_bars)
+	    print_change_bar (change, max_change, options->use_utf);
+    }
+
+    printf("\n");
+}
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+static void
+cairo_perf_reports_compare (cairo_perf_report_t		*reports,
+			    int				 num_reports,
+			    cairo_perf_report_options_t	*options)
+{
+    int i;
+    test_report_t **tests, *min_test;
+    test_diff_t *diff, *diffs;
+    int num_diffs, max_diffs;
+    double max_change;
+    double test_time;
+    int seen_non_null;
+
+    tests = xmalloc (num_reports * sizeof (test_report_t *));
+
+    max_diffs = reports[0].tests_count;
+    for (i = 0; i < num_reports; i++) {
+	tests[i] = reports[i].tests;
+	if (reports[i].tests_count > max_diffs)
+	    max_diffs = reports[i].tests_count;
+    }
+
+    diff = diffs = xmalloc (max_diffs * sizeof (test_diff_t));
+
+    num_diffs = 0;
+    while (1) {
+	int num_tests;
+
+	/* We expect iterations values of 0 when multiple raw reports
+	 * for the same test have been condensed into the stats of the
+	 * first. So we just skip these later reports that have no
+	 * stats. */
+	seen_non_null = 0;
+	for (i = 0; i < num_reports; i++) {
+	    while (tests[i]->name && tests[i]->stats.iterations == 0)
+		tests[i]++;
+	    if (tests[i]->name)
+		seen_non_null++;
+	}
+	if (! seen_non_null)
+	    break;
+
+	/* Find the minimum of all current tests, (we have to do this
+	 * in case some reports don't have a particular test). */
+	for (i = 0; i < num_reports; i++) {
+	    if (tests[i]->name) {
+		min_test = tests[i];
+		break;
+	    }
+	}
+	for (++i; i < num_reports; i++) {
+	    if (tests[i]->name && test_report_cmp_name (tests[i], min_test) < 0)
+		min_test = tests[i];
+	}
+
+	num_tests = 0;
+	for (i = 0; i < num_reports; i++) {
+	    test_report_t *test;
+	    int n = 0;
+
+	    test = tests[i];
+	    while (test[n].name &&
+		    test_report_cmp_name (&test[n], min_test) == 0)
+	    {
+		n++;
+	    }
+
+	    num_tests += n;
+	}
+
+	/* For each report that has the current test, record it into
+	 * the diff structure. */
+	diff->num_tests = 0;
+	diff->tests = xmalloc (num_tests * sizeof (test_diff_t));
+	for (i = 0; i < num_reports; i++) {
+	    while (tests[i]->name &&
+		    test_report_cmp_name (tests[i], min_test) == 0)
+	    {
+		test_time = tests[i]->stats.min_ticks;
+		if (options->use_ms)
+		    test_time /= tests[i]->stats.ticks_per_ms;
+		if (diff->num_tests == 0) {
+		    diff->min = test_time;
+		    diff->max = test_time;
+		} else {
+		    if (test_time < diff->min)
+			diff->min = test_time;
+		    if (test_time > diff->max)
+			diff->max = test_time;
+		}
+		diff->tests[diff->num_tests++] = tests[i];
+		tests[i]++;
+	    }
+	}
+	diff->change = diff->max / diff->min;
+
+	diff++;
+	num_diffs++;
+    }
+    if (num_diffs < 2)
+	goto DONE;
+
+    qsort (diffs, num_diffs, sizeof (test_diff_t), test_diff_cmp);
+
+    max_change = 1.0;
+    for (i = 0; i < num_diffs; i++) {
+	if (fabs (diffs[i].change) > max_change)
+	    max_change = fabs (diffs[i].change);
+    }
+
+    for (i = 0; i < num_diffs; i++) {
+	diff = &diffs[i];
+
+	/* Discard as uninteresting a change which is less than the
+	 * minimum change required, (default may be overriden on
+	 * command-line). */
+	if (fabs (diff->change) - 1.0 < options->min_change)
+	    continue;
+
+	test_diff_print (diff, max_change, options);
+    }
+
+ DONE:
+    for (i = 0; i < num_diffs; i++)
+	free (diffs[i].tests);
+    free (diffs);
+    free (tests);
+}
+
+static void
+usage (const char *argv0)
+{
+    char const *basename = strrchr(argv0, '/');
+    basename = basename ? basename+1 : argv0;
+    fprintf (stderr,
+	     "Usage: %s [options] file [...]\n\n",
+	     basename);
+    fprintf (stderr,
+	     "Computes significant performance differences for cairo performance reports.\n"
+	     "Each file should be the output of the cairo-perf program (or \"make perf\").\n"
+	     "The following options are available:\n"
+	     "\n"
+	     "--no-utf    Use ascii stars instead of utf-8 change bars.\n"
+	     "            Four stars are printed per factor of speedup.\n"
+	     "\n"
+	     "--no-bars   Don't display change bars at all.\n\n"
+	     "\n"
+	     "--use-ms    Use milliseconds to calculate differences.\n"
+	     "            (instead of ticks which are hardware dependant)\n"
+	     "\n"
+	     "--min-change threshold[%%]\n"
+	     "            Suppress all changes below the given threshold.\n"
+	     "            The default threshold of 0.05 or 5%% ignores any\n"
+	     "            speedup or slowdown of 1.05 or less. A threshold\n"
+	     "            of 0 will cause all output to be reported.\n"
+	);
+    exit(1);
+}
+
+static void
+parse_args(int				  argc,
+	   char const			**argv,
+	   cairo_perf_diff_files_args_t  *args)
+{
+    int i;
+
+    for (i = 1; i < argc; i++) {
+	if (strcmp (argv[i], "--no-utf") == 0) {
+	    args->options.use_utf = 0;
+	}
+	else if (strcmp (argv[i], "--no-bars") == 0) {
+	    args->options.print_change_bars = 0;
+	}
+	else if (strcmp (argv[i], "--use-ms") == 0) {
+	    args->options.use_ms = 1;
+	}
+	else if (strcmp (argv[i], "--min-change") == 0) {
+	    char *end = NULL;
+	    i++;
+	    if (i >= argc)
+		usage (argv[0]);
+	    args->options.min_change = strtod (argv[i], &end);
+	    if (*end) {
+		if (*end == '%') {
+		    args->options.min_change /= 100;
+		} else {
+		    usage (argv[0]);
+		}
+	    }
+	}
+	else {
+	    args->num_filenames++;
+	    args->filenames = xrealloc (args->filenames,
+					args->num_filenames * sizeof (char *));
+	    args->filenames[args->num_filenames - 1] = argv[i];
+	}
+    }
+}
+
+int
+main (int argc, const char *argv[])
+{
+    cairo_perf_diff_files_args_t args = {
+	NULL,			/* filenames */
+	0,			/* num_filenames */
+	{
+	    0.05,		/* min change */
+	    1,			/* use UTF-8? */
+	    1,			/* display change bars? */
+	}
+    };
+    cairo_perf_report_t *reports;
+    test_report_t *t;
+    int i;
+
+    parse_args (argc, argv, &args);
+
+    if (args.num_filenames < 1)
+	usage (argv[0]);
+
+    reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t));
+
+    for (i = 0; i < args.num_filenames; i++) {
+	cairo_perf_report_load (&reports[i], args.filenames[i],
+		                test_report_cmp_name);
+	printf ("loaded: %s\n", args.filenames[i]);
+    }
+
+    cairo_perf_reports_compare (reports, args.num_filenames, &args.options);
+
+    /* Pointless memory cleanup, (would be a great place for talloc) */
+    free (args.filenames);
+    for (i = 0; i < args.num_filenames; i++) {
+	for (t = reports[i].tests; t->name; t++) {
+	    free (t->samples);
+	    free (t->backend);
+	    free (t->name);
+	}
+	free (reports[i].tests);
+	free (reports[i].configuration);
+    }
+    free (reports);
+
+    return 0;
+}
diff --git a/perf/cairo-perf-diff-files.c b/perf/cairo-perf-diff-files.c
index 9b9f5f9..adbe69a 100644
--- a/perf/cairo-perf-diff-files.c
+++ b/perf/cairo-perf-diff-files.c
@@ -449,7 +449,7 @@ main (int argc, const char *argv[])
     reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t));
 
     for (i = 0; i < args.num_filenames; i++ )
-	cairo_perf_report_load (&reports[i], args.filenames[i]);
+	cairo_perf_report_load (&reports[i], args.filenames[i], NULL);
 
     cairo_perf_reports_compare (reports, args.num_filenames, &args.options);
 
diff --git a/perf/cairo-perf-graph-files.c b/perf/cairo-perf-graph-files.c
index 04235d6..0adfabd 100644
--- a/perf/cairo-perf-graph-files.c
+++ b/perf/cairo-perf-graph-files.c
@@ -565,7 +565,7 @@ main (int argc, char *argv[])
 
     reports = xmalloc ((argc-1) * sizeof (cairo_perf_report_t));
     for (i = 1; i < argc; i++ )
-	cairo_perf_report_load (&reports[i-1], argv[i]);
+	cairo_perf_report_load (&reports[i-1], argv[i], NULL);
 
     cases = test_cases_from_reports (reports, argc-1);
 
diff --git a/perf/cairo-perf-report.c b/perf/cairo-perf-report.c
index 2f748f4..8a99b9d 100644
--- a/perf/cairo-perf-report.c
+++ b/perf/cairo-perf-report.c
@@ -337,15 +337,47 @@ test_report_cmp_backend_then_name (const void *a, const void *b)
     return 0;
 }
 
+int
+test_report_cmp_name (const void *a, const void *b)
+{
+    const test_report_t *a_test = a;
+    const test_report_t *b_test = b;
+
+    int cmp;
+
+    /* A NULL name is a list-termination marker, so force it last. */
+    if (a_test->name == NULL)
+	if (b_test->name == NULL)
+	    return 0;
+	else
+	    return 1;
+    else if (b_test->name == NULL)
+	return -1;
+
+    cmp = strcmp (a_test->name, b_test->name);
+    if (cmp)
+	return cmp;
+
+    if (a_test->size < b_test->size)
+	return -1;
+    if (a_test->size > b_test->size)
+	return 1;
+
+    return 0;
+}
+
 void
-cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report)
+cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report,
+	                                  int (*cmp) (const void*, const void*))
 {
     test_report_t *base, *next, *last, *t;
 
+    if (cmp == NULL)
+	cmp = test_report_cmp_backend_then_name;
+
     /* First we sort, since the diff needs both lists in the same
      * order */
-    qsort (report->tests, report->tests_count, sizeof (test_report_t),
-	   test_report_cmp_backend_then_name);
+    qsort (report->tests, report->tests_count, sizeof (test_report_t), cmp);
 
     /* The sorting also brings all related raw reports together so we
      * can condense them and compute the stats.
@@ -384,7 +416,8 @@ cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report)
 
 void
 cairo_perf_report_load (cairo_perf_report_t *report,
-	                const char *filename)
+	                const char *filename,
+			int (*cmp) (const void *, const void *))
 {
     FILE *file;
     test_report_status_t status;
@@ -444,7 +477,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
 
     fclose (file);
 
-    cairo_perf_report_sort_and_compute_stats (report);
+    cairo_perf_report_sort_and_compute_stats (report, cmp);
 
     /* Add one final report with a NULL name to terminate the list. */
     if (report->tests_count == report->tests_size) {
diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h
index 3affcb8..8c44c9a 100644
--- a/perf/cairo-perf.h
+++ b/perf/cairo-perf.h
@@ -144,14 +144,19 @@ typedef enum {
 
 void
 cairo_perf_report_load (cairo_perf_report_t *report,
-	                const char *filename);
+	                const char *filename,
+			int (*cmp) (const void *, const void *));
 
 void
-cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report);
+cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report,
+	                                  int (*cmp) (const void *, const void *));
 
 int
 test_report_cmp_backend_then_name (const void *a, const void *b);
 
+int
+test_report_cmp_name (const void *a, const void *b);
+
 #define CAIRO_PERF_DECL(func) void (func) (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 
 CAIRO_PERF_DECL (fill);
commit 4c79cd480db1cf10b6018bce3ea966587efc6081
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jan 13 12:52:52 2009 +0000

    [perf] Tweak dragon to hit fill_rectangles().
    
    Add a second dragon path that is pixel-aligned and uses a solid pattern,
    so that it can be drawn using fill-rectangles.

diff --git a/perf/dragon.c b/perf/dragon.c
index 6d0328e..a6167cb 100644
--- a/perf/dragon.c
+++ b/perf/dragon.c
@@ -65,7 +65,6 @@ direction (int i)
     return ! direction (2 * pivot - i);
 }
 
-
 static void
 path (cairo_t *cr, int step, int dir, int iterations)
 {
@@ -159,8 +158,49 @@ do_dragon (cairo_t *cr, int width, int height)
     return cairo_perf_timer_elapsed ();
 }
 
+static cairo_perf_ticks_t
+do_dragon_solid (cairo_t *cr, int width, int height)
+{
+    double cx, cy, r;
+
+    cx = cy = .5 * MAX (width, height);
+    r = .5 * MIN (width, height);
+
+    cairo_perf_timer_start ();
+
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_paint (cr);
+
+    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, 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, 3, 2048);
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_stroke(cr);
+
+    cairo_perf_timer_stop ();
+
+    return cairo_perf_timer_elapsed ();
+}
+
 void
 dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
+    cairo_perf_run (perf, "dragon-solid", do_dragon_solid);
     cairo_perf_run (perf, "dragon", do_dragon);
 }
commit de9e6b5a3f4e4752e0f99e3ae20ac263a5aae4bb
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jan 12 01:00:30 2009 +0000

    [perf] Cover linear gradient with 3 stops.
    
    The i915 is able to special case gradients with just 2 color stops to
    avoid creating temporary gradient textures, so add a 3 stop linear
    gradient to compare the speed difference.

diff --git a/perf/cairo-perf-cover.c b/perf/cairo-perf-cover.c
index eb77ccd..975c766 100644
--- a/perf/cairo-perf-cover.c
+++ b/perf/cairo-perf-cover.c
@@ -225,6 +225,40 @@ set_source_linear_rgba (cairo_t *cr,
 }
 
 static void
+set_source_linear3_rgb (cairo_t *cr,
+		       int	width,
+		       int	height)
+{
+    cairo_pattern_t *linear;
+
+    linear = cairo_pattern_create_linear (0.0, 0.0, width, height);
+    cairo_pattern_add_color_stop_rgb (linear, 0.0, 1, 0, 0); /* red */
+    cairo_pattern_add_color_stop_rgb (linear, 0.5, 0, 1, 0); /* green */
+    cairo_pattern_add_color_stop_rgb (linear, 1.0, 0, 0, 1); /* blue */
+
+    cairo_set_source (cr, linear);
+
+    cairo_pattern_destroy (linear);
+}
+
+static void
+set_source_linear3_rgba (cairo_t *cr,
+			int	width,
+			int	height)
+{
+    cairo_pattern_t *linear;
+
+    linear = cairo_pattern_create_linear (0.0, 0.0, width, height);
+    cairo_pattern_add_color_stop_rgba (linear, 0.0, 1, 0, 0, 0.5); /* 50% red */
+    cairo_pattern_add_color_stop_rgba (linear, 0.5, 0, 1, 0, 0.0); /*  0% green */
+    cairo_pattern_add_color_stop_rgba (linear, 1.0, 0, 0, 1, 0.5); /*  50% blue */
+
+    cairo_set_source (cr, linear);
+
+    cairo_pattern_destroy (linear);
+}
+
+static void
 set_source_radial_rgb (cairo_t *cr,
 		       int	width,
 		       int	height)
@@ -282,6 +316,8 @@ cairo_perf_cover_sources_and_operators (cairo_perf_t		*perf,
 	{ set_source_similar_surface_rgba_min, "similar_rgba_min" },
 	{ set_source_linear_rgb, "linear_rgb" },
 	{ set_source_linear_rgba, "linear_rgba" },
+	{ set_source_linear3_rgb, "linear3_rgb" },
+	{ set_source_linear3_rgba, "linear3_rgba" },
 	{ set_source_radial_rgb, "radial_rgb" },
 	{ set_source_radial_rgba, "radial_rgba" }
     };
commit 7cbc55f21624159dfa58a9a50ec004af9368ab3d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jan 10 00:12:06 2009 +0000

    [perf] Add scaled similar surface sources.
    
    Cover the similar source with min/mag scale factors as well, so we can
    compare the performance impact with scaled image sources. This is useful
    to distinguish between transport overhead and transform cost.

diff --git a/perf/cairo-perf-cover.c b/perf/cairo-perf-cover.c
index 30942d2..eb77ccd 100644
--- a/perf/cairo-perf-cover.c
+++ b/perf/cairo-perf-cover.c
@@ -98,8 +98,8 @@ set_source_image_surface_rgba (cairo_t	*cr,
 
 static void
 set_source_image_surface_rgba_mag (cairo_t	*cr,
-				   int	 	width,
-				   int	 	height)
+				   int		width,
+				   int		height)
 {
     cairo_surface_t *source;
 
@@ -114,8 +114,8 @@ set_source_image_surface_rgba_mag (cairo_t	*cr,
 
 static void
 set_source_image_surface_rgba_min (cairo_t	*cr,
-				   int	 	width,
-				   int	 	height)
+				   int		width,
+				   int		height)
 {
     cairo_surface_t *source;
 
@@ -159,6 +159,40 @@ set_source_similar_surface_rgba (cairo_t	*cr,
 }
 
 static void
+set_source_similar_surface_rgba_mag (cairo_t	*cr,
+				     int	width,
+				     int	height)
+{
+    cairo_surface_t *source;
+
+    source = cairo_surface_create_similar (cairo_get_group_target (cr),
+					   CAIRO_CONTENT_COLOR_ALPHA,
+					   width/2, height/2);
+    cairo_scale(cr, 2.1, 2.1);
+    init_and_set_source_surface (cr, source, width/2, height/2);
+    cairo_scale(cr, 1/2.1, 1/2.1);
+
+    cairo_surface_destroy (source);
+}
+
+static void
+set_source_similar_surface_rgba_min (cairo_t	*cr,
+				     int	width,
+				     int	height)
+{
+    cairo_surface_t *source;
+
+    source = cairo_surface_create_similar (cairo_get_group_target (cr),
+					   CAIRO_CONTENT_COLOR_ALPHA,
+					   width*2, height*2);
+    cairo_scale(cr, 1/1.9, 1/1.9);
+    init_and_set_source_surface (cr, source, width*2, height*2);
+    cairo_scale(cr, 1.9, 1.9);
+
+    cairo_surface_destroy (source);
+}
+
+static void
 set_source_linear_rgb (cairo_t *cr,
 		       int	width,
 		       int	height)
@@ -244,6 +278,8 @@ cairo_perf_cover_sources_and_operators (cairo_perf_t		*perf,
 	{ set_source_image_surface_rgba_min, "image_rgba_min" },
 	{ set_source_similar_surface_rgb, "similar_rgb" },
 	{ set_source_similar_surface_rgba, "similar_rgba" },
+	{ set_source_similar_surface_rgba_mag, "similar_rgba_mag" },
+	{ set_source_similar_surface_rgba_min, "similar_rgba_min" },
 	{ set_source_linear_rgb, "linear_rgb" },
 	{ set_source_linear_rgba, "linear_rgba" },
 	{ set_source_radial_rgb, "radial_rgb" },
commit afce1cfe987eeec6516aed1eb8fd97c2d3b9b07b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 9 14:22:36 2009 +0000

    [scaled-font] Avoid repeated lookup of the same unicode during text->glyphs
    
    Performing the unicode to index is quite expensive, the
    FcFreeTypeCharIndex() taking over 12% in the cairo-perf text benchmarks.
    By adding a simple cache of translated unicode indices, we save around 25%
    of the lookups during benchmarks, with a relative reduction in runtime.

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 013d680..1d5798f 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1534,6 +1534,12 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
     cairo_status_t status;
     cairo_glyph_t *orig_glyphs;
     cairo_text_cluster_t *orig_clusters;
+    struct glyph_lut_elt {
+	uint32_t unicode;
+	unsigned long index;
+	double x_advance;
+	double y_advance;
+    } glyph_lut[256];
 
     status = scaled_font->status;
     if (unlikely (status))
@@ -1608,17 +1614,13 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
     orig_clusters = clusters ? *clusters : NULL;
 
     if (scaled_font->backend->text_to_glyphs) {
-
 	status = scaled_font->backend->text_to_glyphs (scaled_font, x, y,
 						       utf8, utf8_len,
 						       glyphs, num_glyphs,
 						       clusters, num_clusters,
 						       cluster_flags);
-
         if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
-
 	    if (status == CAIRO_STATUS_SUCCESS) {
-
 	        /* The checks here are crude; we only should do them in
 		 * user-font backend, but they don't hurt here.  This stuff
 		 * can be hard to get right. */
@@ -1633,7 +1635,6 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 		}
 
 		if (clusters) {
-
 		    if (*num_clusters < 0) {
 			status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
 			goto DONE;
@@ -1643,11 +1644,12 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 			goto DONE;
 		    }
 
-		    /* Dont trust the backend, validate clusters! */
-		    status = _cairo_validate_text_clusters (utf8, utf8_len,
-							    *glyphs, *num_glyphs,
-							    *clusters, *num_clusters,
-							    *cluster_flags);
+		    /* Don't trust the backend, validate clusters! */
+		    status =
+			_cairo_validate_text_clusters (utf8, utf8_len,
+						       *glyphs, *num_glyphs,
+						       *clusters, *num_clusters,
+						       *cluster_flags);
 		}
 	    }
 
@@ -1675,34 +1677,51 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 	*num_clusters = num_chars;
     }
 
+    for (i = 0; i < ARRAY_LENGTH (glyph_lut); i++)
+	glyph_lut[i].unicode = ~0U;
+
     p = utf8;
     for (i = 0; i < num_chars; i++) {
 	int num_bytes;
 	uint32_t unicode;
 	cairo_scaled_glyph_t *scaled_glyph;
+	struct glyph_lut_elt *glyph_slot;
 
 	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
 	p += num_bytes;
 
-        (*glyphs)[i].index = (*scaled_font->backend->ucs4_to_index) (scaled_font, unicode);
 	(*glyphs)[i].x = x;
 	(*glyphs)[i].y = y;
 
+	glyph_slot = &glyph_lut[unicode % ARRAY_LENGTH (glyph_lut)];
+	if (glyph_slot->unicode == unicode) {
+	    (*glyphs)[i].index = glyph_slot->index;
+	    x += glyph_slot->x_advance;
+	    y += glyph_slot->y_advance;
+	} else {
+	    (*glyphs)[i].index =
+		(*scaled_font->backend->ucs4_to_index) (scaled_font, unicode);
+
+	    status = _cairo_scaled_glyph_lookup (scaled_font,
+						 (*glyphs)[i].index,
+						 CAIRO_SCALED_GLYPH_INFO_METRICS,
+						 &scaled_glyph);
+	    if (unlikely (status))
+		goto DONE;
+
+	    x += scaled_glyph->metrics.x_advance;
+	    y += scaled_glyph->metrics.y_advance;
+
+	    glyph_slot->unicode = unicode;
+	    glyph_slot->index = (*glyphs)[i].index;
+	    glyph_slot->x_advance = scaled_glyph->metrics.x_advance;
+	    glyph_slot->y_advance = scaled_glyph->metrics.y_advance;
+	}
+
 	if (clusters) {
 	    (*clusters)[i].num_bytes  = num_bytes;
 	    (*clusters)[i].num_glyphs = 1;
 	}
-
-	status = _cairo_scaled_glyph_lookup (scaled_font,
-					     (*glyphs)[i].index,
-					     CAIRO_SCALED_GLYPH_INFO_METRICS,
-					     &scaled_glyph);
-	if (unlikely (status)) {
-	    goto DONE;
-	}
-
-        x += scaled_glyph->metrics.x_advance;
-        y += scaled_glyph->metrics.y_advance;
     }
 
  DONE: /* error that should be logged on scaled_font happened */
commit 49eca78a4265432e285af58435219e8b804b38bb
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jan 12 12:42:46 2009 +0000

    [test] Add a huge-radial test case.
    
    Also test the handling of radial gradients with large radii.

diff --git a/test/Makefile.am b/test/Makefile.am
index 2afda68..8c849ba 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -85,7 +85,8 @@ test_sources = \
 	gradient-constant-alpha.c			\
 	gradient-zero-stops.c				\
 	group-paint.c					\
-	huge-pattern.c					\
+	huge-linear.c					\
+	huge-radial.c					\
 	image-surface-source.c				\
 	infinite-join.c					\
 	in-fill-empty-trapezoid.c			\
@@ -610,10 +611,10 @@ REFERENCE_IMAGES = \
 	gradient-zero-stops.ref.png	\
 	gradient-zero-stops.rgb24.ref.png	\
 	group-paint.ref.png	\
-	huge-pattern.ref.png	\
-	huge-pattern.ps3.ref.png	\
-	huge-pattern.pdf.ref.png	\
-	huge-pattern.pdf.rgb24.ref.png	\
+	huge-linear.ref.png	\
+	huge-linear.ps3.ref.png	\
+	huge-radial.ref.png	\
+	huge-radial.ps3.ref.png	\
 	image-surface-source.ref.png \
 	image-surface-source.ps2.ref.png \
 	image-surface-source.ps3.ref.png \
diff --git a/test/huge-linear.c b/test/huge-linear.c
new file mode 100644
index 0000000..304cac4
--- /dev/null
+++ b/test/huge-linear.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2006 Benjamin Otte
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Benjamin Otte <otte at gnome.org>
+ */
+
+#include "cairo-test.h"
+
+/* set this to 0.1 to make this test work */
+#define FACTOR 1
+
+/* XXX poppler-cairo doesn't handle gradients very well... */
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_pattern_t *pattern;
+    cairo_matrix_t mat = {
+	0, -4.5254285714285709 * FACTOR,
+	-2.6398333333333333 * FACTOR, 0,
+	0, 0
+    };
+
+    pattern = cairo_pattern_create_linear (-16384 * FACTOR, 0,
+					    16384 * FACTOR, 0);
+    cairo_pattern_add_color_stop_rgba (pattern,
+				       0, 0.376471, 0.533333, 0.27451, 1);
+    cairo_pattern_add_color_stop_rgba (pattern, 1, 1, 1, 1, 1);
+    cairo_pattern_set_matrix (pattern, &mat);
+
+    cairo_scale (cr, 0.05, 0.05);
+    cairo_translate (cr, 6000, 3500);
+
+    cairo_set_source (cr, pattern);
+    cairo_rectangle (cr, -6000, -3500, 12000, 7000);
+    cairo_pattern_destroy (pattern);
+    cairo_fill (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (huge_linear,
+	    "Test huge linear patterns",
+	    "XFAIL=pdf gradient, linear", /* keywords */
+	    NULL, /* requirements */
+	    600, 350,
+	    NULL, draw)
diff --git a/test/huge-linear.ps3.ref.png b/test/huge-linear.ps3.ref.png
new file mode 100644
index 0000000..d55239b
Binary files /dev/null and b/test/huge-linear.ps3.ref.png differ
diff --git a/test/huge-linear.ref.png b/test/huge-linear.ref.png
new file mode 100644
index 0000000..68f86b4
Binary files /dev/null and b/test/huge-linear.ref.png differ
diff --git a/test/huge-pattern.c b/test/huge-pattern.c
deleted file mode 100644
index 9a74337..0000000
--- a/test/huge-pattern.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright © 2006 Benjamin Otte
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Author: Benjamin Otte <otte at gnome.org>
- */
-
-#include "cairo-test.h"
-
-/* set this to 0.1 to make this test work */
-#define FACTOR 1
-
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
-{
-    cairo_pattern_t *pattern;
-    cairo_matrix_t mat = {
-	0, -4.5254285714285709 * FACTOR,
-	-2.6398333333333333 * FACTOR, 0,
-	0, 0
-    };
-
-    pattern = cairo_pattern_create_linear (-16384 * FACTOR, 0,
-					    16384 * FACTOR, 0);
-    cairo_pattern_add_color_stop_rgba (pattern,
-				       0, 0.376471, 0.533333, 0.27451, 1);
-    cairo_pattern_add_color_stop_rgba (pattern, 1, 1, 1, 1, 1);
-    cairo_pattern_set_matrix (pattern, &mat);
-
-    cairo_scale (cr, 0.05, 0.05);
-    cairo_translate (cr, 6000, 3500);
-
-    cairo_set_source (cr, pattern);
-    cairo_rectangle (cr, -6000, -3500, 12000, 7000);
-    cairo_pattern_destroy (pattern);
-    cairo_fill (cr);
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (huge_pattern,
-	    "Test huge linear patterns",
-	    "gradient", /* keywords */
-	    NULL, /* requirements */
-	    600, 350,
-	    NULL, draw)
diff --git a/test/huge-pattern.pdf.argb32.ref.png b/test/huge-pattern.pdf.argb32.ref.png
deleted file mode 100644
index 005d4a6..0000000
Binary files a/test/huge-pattern.pdf.argb32.ref.png and /dev/null differ
diff --git a/test/huge-pattern.pdf.ref.png b/test/huge-pattern.pdf.ref.png
deleted file mode 100644
index dfa8c5b..0000000
Binary files a/test/huge-pattern.pdf.ref.png and /dev/null differ
diff --git a/test/huge-pattern.pdf.rgb24.ref.png b/test/huge-pattern.pdf.rgb24.ref.png
deleted file mode 100644
index a950f8b..0000000
Binary files a/test/huge-pattern.pdf.rgb24.ref.png and /dev/null differ
diff --git a/test/huge-pattern.ps3.ref.png b/test/huge-pattern.ps3.ref.png
deleted file mode 100644
index d55239b..0000000
Binary files a/test/huge-pattern.ps3.ref.png and /dev/null differ
diff --git a/test/huge-pattern.ref.png b/test/huge-pattern.ref.png
deleted file mode 100644
index 68f86b4..0000000
Binary files a/test/huge-pattern.ref.png and /dev/null differ
diff --git a/test/huge-radial.c b/test/huge-radial.c
new file mode 100644
index 0000000..0e5aca1
--- /dev/null
+++ b/test/huge-radial.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2006 Benjamin Otte
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Benjamin Otte <otte at gnome.org>
+ *         Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+/* set this to 0.1 to make this test work */
+#define FACTOR 1
+
+/* XXX poppler-cairo doesn't handle gradients very well... */
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_pattern_t *pattern;
+    cairo_matrix_t mat = {
+	0, -4.5254285714285709 * FACTOR,
+	-2.6398333333333333 * FACTOR, 0,
+	0, 0
+    };
+
+    pattern = cairo_pattern_create_radial (0, 0, 0,
+					   0, 0, 16384 * FACTOR);
+    cairo_pattern_add_color_stop_rgba (pattern,
+				       0, 0.376471, 0.533333, 0.27451, 1);
+    cairo_pattern_add_color_stop_rgba (pattern, 1, 1, 1, 1, 1);
+    cairo_pattern_set_matrix (pattern, &mat);
+
+    cairo_scale (cr, 0.05, 0.05);
+    cairo_translate (cr, 6000, 3500);
+
+    cairo_set_source (cr, pattern);
+    cairo_rectangle (cr, -6000, -3500, 12000, 7000);
+    cairo_pattern_destroy (pattern);
+    cairo_fill (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (huge_radial,
+	    "Test huge radial patterns",
+	    "XFAIL=pdf gradient, radial", /* keywords */
+	    NULL, /* requirements */
+	    600, 350,
+	    NULL, draw)
diff --git a/test/huge-radial.ps3.ref.png b/test/huge-radial.ps3.ref.png
new file mode 100644
index 0000000..c231948
Binary files /dev/null and b/test/huge-radial.ps3.ref.png differ
diff --git a/test/huge-radial.ref.png b/test/huge-radial.ref.png
new file mode 100644
index 0000000..541bb30
Binary files /dev/null and b/test/huge-radial.ref.png differ
commit 7709d1d9d43a42dd8f9293f18141c57c76ca0970
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jan 7 21:12:21 2009 +0000

    [test] Add fill-image.
    
    A filled equivalent of stroke-image, that checks that the pattern
    matrices are applied correctly during fills - useful with the
    segregation between fills and strokes introduced by spans.

diff --git a/test/Makefile.am b/test/Makefile.am
index 3c0972c..2afda68 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -66,6 +66,7 @@ test_sources = \
 	fill-and-stroke-alpha.c				\
 	fill-and-stroke-alpha-add.c			\
 	fill-degenerate-sort-order.c			\
+	fill-image.c				        \
 	fill-missed-stop.c				\
 	fill-rule.c					\
 	filter-bilinear-extents.c			\
@@ -519,6 +520,7 @@ REFERENCE_IMAGES = \
 	fill-degenerate-sort-order.quartz.rgb24.ref.png	\
 	fill-degenerate-sort-order.ref.png	\
 	fill-degenerate-sort-order.rgb24.ref.png	\
+	fill-image.ref.png \
 	fill-missed-stop.ps2.argb32.ref.png	\
 	fill-missed-stop.ps3.argb32.ref.png	\
 	fill-missed-stop.ps2.rgb24.ref.png	\
diff --git a/test/fill-image.c b/test/fill-image.c
new file mode 100644
index 0000000..24ee031
--- /dev/null
+++ b/test/fill-image.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2006 Mozilla Corporation
+ *
+ * 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
+ * Mozilla Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Mozilla Corporation makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION 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.
+ *
+ * Author: Vladimir Vukicevic <vladimir at pobox.com>
+ */
+
+#include "cairo-test.h"
+
+#define PAD 10
+#define SIZE 100
+#define IMAGE_SIZE (SIZE-PAD*2)
+#define LINE_WIDTH 10
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *image;
+    cairo_t *cr_image;
+
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_paint (cr);
+
+    image = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+	                                IMAGE_SIZE, IMAGE_SIZE);
+    cr_image = cairo_create (image);
+    cairo_surface_destroy (image);
+
+    /* Create the image */
+    cairo_set_source_rgb (cr_image, 0, 0, 0);
+    cairo_paint (cr_image);
+
+    cairo_set_source_rgb (cr_image, 0, 1, 0);
+    cairo_new_sub_path (cr_image);
+    cairo_arc (cr_image, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2 - LINE_WIDTH, 0, M_PI * 2.0);
+    cairo_close_path (cr_image);
+    cairo_new_sub_path (cr_image);
+    cairo_arc_negative (cr_image, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2, 0, -M_PI * 2.0);
+    cairo_close_path (cr_image);
+    cairo_fill (cr_image);
+
+    /* Now stroke^Wfill with it */
+    cairo_translate (cr, PAD, PAD);
+
+    cairo_set_source_surface (cr, cairo_get_target (cr_image), 0, 0);
+    cairo_destroy (cr_image);
+
+    cairo_new_sub_path (cr);
+    cairo_arc (cr, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2 - LINE_WIDTH, 0, M_PI * 2.0);
+    cairo_close_path (cr);
+    cairo_new_sub_path (cr);
+    cairo_arc_negative (cr, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2, 0, -M_PI * 2.0);
+    cairo_close_path (cr);
+
+    cairo_fill (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (fill_image,
+	    "Test filling with an image source, with a non-identity CTM",
+	    "fill, image, transform", /* keywords */
+	    NULL, /* requirements */
+	    SIZE, SIZE,
+	    NULL, draw)
diff --git a/test/fill-image.ref.png b/test/fill-image.ref.png
new file mode 100644
index 0000000..4e4f450
Binary files /dev/null and b/test/fill-image.ref.png differ
commit 5605e4bfcd0b6e3e34eed3785bc8ae51b24a7385
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jan 4 11:26:45 2009 +0000

    [test] Propagate failure from painting large-source-roi
    
    Use cairo_get_target() to propagate any failure when creating the
    large-source.

diff --git a/test/large-source-roi.c b/test/large-source-roi.c
index 097390f..226d97f 100644
--- a/test/large-source-roi.c
+++ b/test/large-source-roi.c
@@ -25,6 +25,24 @@
 /* This test attempts to trigger failures in those clone_similar
  * backend methods that have size restrictions. */
 
+static cairo_surface_t *
+create_large_source (int width, int height)
+{
+    cairo_surface_t *surface;
+    cairo_t *cr;
+
+    surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+    cr = cairo_create (surface);
+    cairo_surface_destroy (surface);
+
+    cairo_set_source_rgb (cr, 1,0,0); /* red */
+    cairo_paint (cr);
+    surface = cairo_surface_reference (cairo_get_target (cr));
+    cairo_destroy (cr);
+
+    return surface;
+}
+
 static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
@@ -35,13 +53,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_paint (cr);
 
     /* Create an excessively wide source image, all red. */
-    source = cairo_image_surface_create (CAIRO_FORMAT_RGB24, source_width, height);
-    {
-	cairo_t *cr2 = cairo_create (source);
-	cairo_set_source_rgb (cr2, 1,0,0); /* red */
-	cairo_paint (cr2);
-	cairo_destroy (cr2);
-    }
+    source = create_large_source (source_width, height);
 
     /* Set a transform so that the source is scaled down to fit in the
      * destination horizontally and then paint the entire source to
@@ -58,7 +70,7 @@ draw (cairo_t *cr, int width, int height)
 
 CAIRO_TEST (large_source_roi,
 	    "Uses a all of a large source image.",
-	    "stress, source", /* keywords */
+	    "XFAIL stress, source", /* keywords */
 	    NULL, /* requirements */
 	    20, 20,
 	    NULL, draw)


More information about the cairo-commit mailing list