[cairo-commit] 3 commits - build/aclocal.cairo.m4 build/configure.ac.features configure.ac src/cairo-atomic-private.h src/cairo.c src/cairo-mutex-impl-private.h src/cairo-pattern.c src/cairo-surface.c src/cairo-xlib-private.h src/cairo-xlib-screen.c test/cairo-test.c test/cairo-test-trace.c test/Makefile.am util/cairo-trace

Chris Wilson ickle at kemper.freedesktop.org
Thu Oct 15 05:07:34 PDT 2009


 build/aclocal.cairo.m4         |   10 ++
 build/configure.ac.features    |    1 
 configure.ac                   |    8 +
 src/cairo-atomic-private.h     |   41 ++++++++-
 src/cairo-mutex-impl-private.h |    2 
 src/cairo-pattern.c            |  184 ++++++++++++++++++++++++++++-------------
 src/cairo-surface.c            |    4 
 src/cairo-xlib-private.h       |    2 
 src/cairo-xlib-screen.c        |   16 ++-
 src/cairo.c                    |   10 +-
 test/Makefile.am               |    4 
 test/cairo-test-trace.c        |   10 +-
 test/cairo-test.c              |    6 -
 util/cairo-trace/Makefile.am   |    2 
 14 files changed, 211 insertions(+), 89 deletions(-)

New commits:
commit dac73d260a9b9a848bb97436ad84081c51629511
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Oct 15 12:18:47 2009 +0100

    [build] Link against pthread-stubs
    
    Avoid pulling in the real pthread library if the application is single
    threaded and not using pthreads, by linking against pthread-stubs
    instead.

diff --git a/build/configure.ac.features b/build/configure.ac.features
index b3b7b85..e057e2c 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -399,6 +399,7 @@ AC_DEFUN([CAIRO_REPORT],
 	echo "  cairo-script-interpreter:   $use_interpreter"
 	echo ""
 	echo "And the following internal features:"
+	echo "  pthread:       $use_pthread"
 	echo "  gtk-doc:       $enable_gtk_doc"
 	echo "  gcov support:  $use_gcov"
 	echo "  symbol-lookup: $use_symbol_lookup"
diff --git a/configure.ac b/configure.ac
index c38d2c4..12a56ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -485,7 +485,13 @@ AC_ARG_ENABLE(pthread,
 
 have_pthread=no
 if test "x$use_pthread" != "xno"; then
-  AC_CHECK_HEADERS([pthread.h], have_pthread=yes, have_pthread=no)
+  pthread_REQUIRES="pthread-stubs"
+  PKG_CHECK_MODULES(pthread, $pthread_REQUIRES,
+		    [use_pthread=yes; have_pthread=yes],
+		    [AC_CHECK_HEADERS([pthread.h], [use_pthread=yes; have_pthread=yes], [use_pthread="no (requires $pthread_REQUIRES)"])])
+  if test "x$have_pthread" = "xyes"; then
+    AC_DEFINE([CAIRO_HAS_PTHREAD], 1, [Define to 1 if we have pthread support])
+  fi
 fi
 AM_CONDITIONAL(HAVE_PTHREAD, test "x$have_pthread" = "xyes")
 if test "x$have_pthread" = xno -a "x$use_pthread" = xyes; then
diff --git a/src/cairo-mutex-impl-private.h b/src/cairo-mutex-impl-private.h
index f601db9..06938b5 100644
--- a/src/cairo-mutex-impl-private.h
+++ b/src/cairo-mutex-impl-private.h
@@ -216,7 +216,7 @@
 # define CAIRO_MUTEX_IMPL_FINI(mutex) delete (mutex)
 # define CAIRO_MUTEX_IMPL_NIL_INITIALIZER NULL
 
-#elif HAVE_PTHREAD_H /* and finally if there are no native mutexes ********/
+#elif CAIRO_HAS_PTHREAD /* and finally if there are no native mutexes ********/
 
 # include <pthread.h>
 
diff --git a/test/Makefile.am b/test/Makefile.am
index 2890917..a6e8be3 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -77,6 +77,7 @@ cairo_test_suite_SOURCES = 		\
 	$(cairo_test_suite_headers)	\
 	$(test_sources)			\
 	cairo-test-constructors.c
+cairo_test_suite_CFLAGS = $(AM_CFLAGS)
 cairo_test_suite_LDADD = 					\
 	$(top_builddir)/test/pdiff/libpdiff.la 			\
         $(top_builddir)/boilerplate/libcairoboilerplate.la	\
@@ -91,6 +92,7 @@ cairo_test_suite_DEPENDENCIES += \
 	any2ppm
 endif
 if HAVE_PTHREAD
+cairo_test_suite_CFLAGS += -pthread
 cairo_test_suite_LDADD += -lpthread
 endif
 
@@ -100,6 +102,7 @@ cairo_test_trace_SOURCES =		\
 	cairo-test-trace.c		\
 	buffer-diff.c			\
 	buffer-diff.h
+cairo_test_trace_CFLAGS = $(AM_CFLAGS)
 cairo_test_trace_LDADD =		\
 	$(top_builddir)/test/pdiff/libpdiff.la 			\
 	$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
@@ -108,6 +111,7 @@ cairo_test_trace_LDADD =		\
 	$(CAIRO_LDADD) \
 	$(SHM_LIBS)
 if HAVE_PTHREAD
+cairo_test_trace_CFLAGS += -pthread
 cairo_test_trace_LDADD += -lpthread
 endif
 cairo_test_trace_DEPENDENCIES = \
diff --git a/test/cairo-test-trace.c b/test/cairo-test-trace.c
index 1d12f53..2401d17 100644
--- a/test/cairo-test-trace.c
+++ b/test/cairo-test-trace.c
@@ -82,7 +82,7 @@
 #include <sys/un.h>
 #include <errno.h>
 #include <assert.h>
-#if HAVE_PTHREAD_H
+#if CAIRO_HAS_PTHREAD
 #include <pthread.h>
 #endif
 
@@ -162,7 +162,7 @@ struct surface_tag {
 };
 static const cairo_user_data_key_t surface_tag;
 
-#if HAVE_PTHREAD_H
+#if CAIRO_HAS_PTHREAD
 #define tr_die(t) t->is_meta ? pthread_exit(NULL) : exit(1)
 #else
 #define tr_die(t) exit(1)
@@ -245,7 +245,7 @@ send_meta_surface (test_runner_t *tr,
 		   int width, int height,
 		   struct context_closure *closure)
 {
-#if HAVE_PTHREAD_H
+#if CAIRO_HAS_PTHREAD
     const struct request_image rq = {
 	closure->id,
 	closure->start_line,
@@ -591,7 +591,7 @@ spawn_target (const char *socket_path,
     exit (0);
 }
 
-#if HAVE_PTHREAD_H
+#if CAIRO_HAS_PTHREAD
 static void
 cleanup_recorder (void *arg)
 {
@@ -1274,7 +1274,7 @@ _test_trace (test_trace_t *test,
 
     s = slaves = xcalloc (2*test->num_targets + 1, sizeof (struct slave));
 
-#if HAVE_PTHREAD_H
+#if CAIRO_HAS_PTHREAD
     /* set-up a meta-surface to reconstruct errors */
     slave = spawn_recorder (socket_path, trace);
     if (slave < 0) {
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 7228865..edc9ae5 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -47,7 +47,7 @@
 #if HAVE_FCFINI
 #include <fontconfig/fontconfig.h>
 #endif
-#if HAVE_PTHREAD_H
+#if CAIRO_HAS_PTHREAD
 #include <pthread.h>
 #endif
 #if HAVE_SYS_STAT_H
@@ -1785,7 +1785,7 @@ _cairo_test_context_run (cairo_test_context_t *ctx)
     return ret;
 }
 
-#if HAVE_PTHREAD_H
+#if CAIRO_HAS_PTHREAD
 typedef struct _cairo_test_thread {
     pthread_t thread;
     cairo_test_context_t *ctx;
@@ -1820,7 +1820,7 @@ cairo_test_expecting (const cairo_test_t *test)
     _cairo_test_init (&ctx, NULL, test, test->name);
     printf ("%s\n", test->description);
 
-#if HAVE_PTHREAD_H
+#if CAIRO_HAS_PTHREAD
     num_threads = 0;
     if (getenv ("CAIRO_TEST_NUM_THREADS"))
 	num_threads = atoi (getenv ("CAIRO_TEST_NUM_THREADS"));
diff --git a/util/cairo-trace/Makefile.am b/util/cairo-trace/Makefile.am
index 814a0f0..5b6e781 100644
--- a/util/cairo-trace/Makefile.am
+++ b/util/cairo-trace/Makefile.am
@@ -13,7 +13,7 @@ cairo_trace_la_CPPFLAGS = -DCAIRO_TRACE_OUTDIR="\"$(cairooutdir)\"" \
 cairo_trace_la_CFLAGS = $(CAIRO_CFLAGS)
 cairo_trace_la_LDFLAGS = -module -no-undefined
 
-cairo_trace_la_LIBADD = -lz
+cairo_trace_la_LIBADD = -lz $(pthread_LIBS)
 if CAIRO_HAS_DL
 cairo_trace_la_LIBADD += -ldl
 endif
commit ef9286751d8346ecb803bfb5916581ee4dfc84db
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Oct 13 16:10:39 2009 +0100

    [atomic] Fallback to libatomic-ops-dev
    
    Use libatomic-ops-dev in preference to mutex-based atomics, if we do not
    have the builtin atomic intrinsics available.

diff --git a/build/aclocal.cairo.m4 b/build/aclocal.cairo.m4
index 5eec262..e03fa1c 100644
--- a/build/aclocal.cairo.m4
+++ b/build/aclocal.cairo.m4
@@ -172,11 +172,21 @@ int atomic_cmpxchg(int i, int j, int k) { return __sync_val_compare_and_swap (&i
 ], [],
 		  cairo_cv_atomic_primitives="Intel"
 		  )
+
+		if test "x$cairo_cv_atomic_primitives" = "xnone"; then
+			AC_CHECK_HEADER([atomic_ops.h],
+					cairo_cv_atomic_primitives="libatomic-ops")
+		fi
 	])
 	if test "x$cairo_cv_atomic_primitives" = xIntel; then
 		AC_DEFINE(HAVE_INTEL_ATOMIC_PRIMITIVES, 1,
 			  [Enable if your compiler supports the Intel __sync_* atomic primitives])
 	fi
+
+	if test "x$cairo_cv_atomic_primitives" = "xlibatomic-ops"; then
+		AC_DEFINE(HAVE_LIB_ATOMIC_OPS, 1,
+			  [Enable if you have libatomic-ops-dev installed])
+	fi
 ])
 
 dnl Usage:
diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h
index bf79b7a..d2583a1 100644
--- a/src/cairo-atomic-private.h
+++ b/src/cairo-atomic-private.h
@@ -57,6 +57,9 @@ CAIRO_BEGIN_DECLS
 
 typedef int cairo_atomic_int_t;
 
+# define _cairo_atomic_int_get(x) (*x)
+# define _cairo_atomic_int_set(x, value) ((*x) = value)
+
 # define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
 # define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
 # define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
@@ -76,6 +79,35 @@ typedef long long cairo_atomic_intptr_t;
 
 #endif
 
+#if HAVE_LIB_ATOMIC_OPS
+#include <atomic_ops.h>
+
+#define HAS_ATOMIC_OPS 1
+
+typedef  AO_t cairo_atomic_int_t;
+
+# define _cairo_atomic_int_get(x) (AO_load_full (x))
+# define _cairo_atomic_int_set(x, value) (AO_store_full (x))
+
+# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
+# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
+# define _cairo_atomic_int_cmpxchg(x, oldv, newv) ((cairo_atomic_int_t) AO_compare_and_swap_full(x, oldv, newv))
+
+#if SIZEOF_VOID_P==SIZEOF_INT
+typedef unsigned int cairo_atomic_intptr_t;
+#elif SIZEOF_VOID_P==SIZEOF_LONG
+typedef unsigned long cairo_atomic_intptr_t;
+#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
+typedef unsigned long long cairo_atomic_intptr_t;
+#else
+#error No matching integer pointer type
+#endif
+
+# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
+    (void*) (cairo_atomic_intptr_t) _cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
+
+#endif
+
 
 #ifndef HAS_ATOMIC_OPS
 
@@ -93,9 +125,6 @@ _cairo_atomic_int_cmpxchg (int *x, int oldv, int newv);
 cairo_private void *
 _cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv);
 
-#endif
-
-
 #ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
 
 # include "cairo-compiler-private.h"
@@ -113,14 +142,16 @@ _cairo_atomic_int_set (int *x, int value);
 
 #endif
 
+#endif
+
 #define _cairo_atomic_uint_get(x) _cairo_atomic_int_get(x)
 #define _cairo_atomic_uint_cmpxchg(x, oldv, newv) \
-    _cairo_atomic_int_cmpxchg((int *)x, oldv, newv)
+    _cairo_atomic_int_cmpxchg((cairo_atomic_int_t *)x, oldv, newv)
 
 #define _cairo_status_set_error(status, err) do { \
     /* hide compiler warnings about cairo_status_t != int (gcc treats its as \
      * an unsigned integer instead, and about ignoring the return value. */  \
-    int ret__ = _cairo_atomic_int_cmpxchg ((int *) status, CAIRO_STATUS_SUCCESS, err); \
+    int ret__ = _cairo_atomic_int_cmpxchg ((cairo_atomic_int_t *) status, CAIRO_STATUS_SUCCESS, err); \
     (void) ret__; \
 } while (0)
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index fd4e01b..ab84bbf 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -193,14 +193,14 @@ slim_hidden_def (cairo_surface_status);
 static unsigned int
 _cairo_surface_allocate_unique_id (void)
 {
-    static unsigned int unique_id;
+    static cairo_atomic_int_t unique_id;
 
 #if CAIRO_NO_MUTEX
     if (++unique_id == 0)
 	unique_id = 1;
     return unique_id;
 #else
-    unsigned int old, id;
+    cairo_atomic_int_t old, id;
 
     do {
 	old = _cairo_atomic_uint_get (&unique_id);
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 33601e8..afdf6a6 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -85,7 +85,7 @@ struct _cairo_xlib_screen {
     cairo_font_options_t font_options;
 
     GC gc[4];
-    int gc_depths; /* 4 x uint8_t */
+    cairo_atomic_int_t gc_depths; /* 4 x uint8_t */
 
     cairo_array_t visuals;
 };
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 79d8c0d..fc2535b 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -269,7 +269,8 @@ _cairo_xlib_screen_close_display (cairo_xlib_screen_t *info)
 {
     cairo_xlib_visual_info_t **visuals;
     Display *dpy;
-    int i, old;
+    cairo_atomic_int_t old;
+    int i;
 
     CAIRO_MUTEX_LOCK (info->mutex);
 
@@ -277,7 +278,7 @@ _cairo_xlib_screen_close_display (cairo_xlib_screen_t *info)
 
 #if HAS_ATOMIC_OPS
     do {
-	old = info->gc_depths;
+	old = _cairo_atomic_int_get (&info->gc_depths);
     } while (_cairo_atomic_int_cmpxchg (&info->gc_depths, old, 0) != old);
 #else
     old = info->gc_depths;
@@ -384,7 +385,8 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
 			   Drawable drawable)
 {
     XGCValues gcv;
-    int i, new, old;
+    cairo_atomic_int_t old, new;
+    int i;
     GC gc;
 
     do {
@@ -393,13 +395,13 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
 	if (old == 0)
 	    break;
 
-	if (((old >> 0) & 0xff) == depth)
+	if (((old >> 0) & 0xff) == (unsigned) depth)
 	    i = 0;
-	else if (((old >> 8) & 0xff) == depth)
+	else if (((old >> 8) & 0xff) == (unsigned) depth)
 	    i = 1;
-	else if (((old >> 16) & 0xff) == depth)
+	else if (((old >> 16) & 0xff) == (unsigned) depth)
 	    i = 2;
-	else if (((old >> 24) & 0xff) == depth)
+	else if (((old >> 24) & 0xff) == (unsigned) depth)
 	    i = 3;
 	else
 	    break;
diff --git a/src/cairo.c b/src/cairo.c
index 2470b0d..383dc89 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -124,16 +124,16 @@ _cairo_set_error (cairo_t *cr, cairo_status_t status)
 #define CAIRO_STASH_SIZE 4
 static struct {
     cairo_t pool[CAIRO_STASH_SIZE];
-    int occupied;
+    cairo_atomic_int_t occupied;
 } _context_stash;
 
 static cairo_t *
 _context_get (void)
 {
-    int avail, old, new;
+    cairo_atomic_int_t avail, old, new;
 
     do {
-	old = _context_stash.occupied;
+	old = _cairo_atomic_int_get (&_context_stash.occupied);
 	avail = ffs (~old) - 1;
 	if (avail >= CAIRO_STASH_SIZE)
 	    return malloc (sizeof (cairo_t));
@@ -147,7 +147,7 @@ _context_get (void)
 static void
 _context_put (cairo_t *cr)
 {
-    int old, new, avail;
+    cairo_atomic_int_t old, new, avail;
 
     if (cr < &_context_stash.pool[0] ||
 	cr >= &_context_stash.pool[CAIRO_STASH_SIZE])
@@ -158,7 +158,7 @@ _context_put (cairo_t *cr)
 
     avail = ~(1 << (cr - &_context_stash.pool[0]));
     do {
-	old = _context_stash.occupied;
+	old = _cairo_atomic_int_get (&_context_stash.occupied);
 	new = old & avail;
     } while (_cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new) != old);
 }
commit d85eda97dd9116f51e0255b29652f4b52ba4f8e9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Oct 13 14:14:55 2009 +0100

    [pattern] Compute extents for gradients
    
    As noted in the comments we could also compute the pattern extents for
    gradients with CAIRO_EXTEND_NONE under certain circumstances, i.e.
    radial gradients and device axis aligned linear gradients.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 727b80e..2990e2a 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1878,13 +1878,13 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
  *      backends do currently (see bug #10508)
  */
 static cairo_filter_t
-_cairo_pattern_analyze_filter (const cairo_surface_pattern_t *pattern,
-			       double                        *pad_out)
+_cairo_pattern_analyze_filter (const cairo_pattern_t	*pattern,
+			       double			*pad_out)
 {
     double pad;
     cairo_filter_t optimized_filter;
 
-    switch (pattern->base.filter) {
+    switch (pattern->filter) {
     case CAIRO_FILTER_GOOD:
     case CAIRO_FILTER_BEST:
     case CAIRO_FILTER_BILINEAR:
@@ -1892,7 +1892,7 @@ _cairo_pattern_analyze_filter (const cairo_surface_pattern_t *pattern,
 	 * not need to filter (and do not want to filter, since it
 	 * will cause blurriness)
 	 */
-	if (_cairo_matrix_is_pixel_exact (&pattern->base.matrix)) {
+	if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) {
 	    pad = 0.;
 	    optimized_filter = CAIRO_FILTER_NEAREST;
 	} else {
@@ -1902,7 +1902,7 @@ _cairo_pattern_analyze_filter (const cairo_surface_pattern_t *pattern,
 	     * more would be defensive...
 	     */
 	    pad = 0.5;
-	    optimized_filter = pattern->base.filter;
+	    optimized_filter = pattern->filter;
 	}
 	break;
 
@@ -1911,7 +1911,7 @@ _cairo_pattern_analyze_filter (const cairo_surface_pattern_t *pattern,
     case CAIRO_FILTER_GAUSSIAN:
     default:
 	pad = 0.;
-	optimized_filter = pattern->base.filter;
+	optimized_filter = pattern->filter;
 	break;
     }
 
@@ -1956,7 +1956,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pat
     is_identity = FALSE;
     attr->matrix = pattern->base.matrix;
     attr->extend = pattern->base.extend;
-    attr->filter = _cairo_pattern_analyze_filter (pattern, &pad);
+    attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
 
     attr->x_offset = attr->y_offset = tx = ty = 0;
     if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
@@ -2443,62 +2443,130 @@ void
 _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
 			    cairo_rectangle_int_t         *extents)
 {
-    if (pattern->extend == CAIRO_EXTEND_NONE &&
-	pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
-    {
-	cairo_status_t status;
-	cairo_rectangle_int_t surface_extents;
-	const cairo_surface_pattern_t *surface_pattern =
-	    (const cairo_surface_pattern_t *) pattern;
-	cairo_surface_t *surface = surface_pattern->surface;
-	cairo_matrix_t imatrix;
-	double x1, y1, x2, y2;
-	double pad;
+    cairo_matrix_t imatrix;
+    double x1, y1, x2, y2;
+    cairo_status_t status;
 
-	if (! _cairo_surface_get_extents (surface, &surface_extents))
-	    goto UNBOUNDED;
+    if (pattern->extend != CAIRO_EXTEND_NONE)
+	goto UNBOUNDED;
 
-	/* The filter can effectively enlarge the extents of the
-	 * pattern, so extend as necessary.
-	 */
-	_cairo_pattern_analyze_filter (surface_pattern, &pad);
-	x1 = surface_extents.x - pad;
-	y1 = surface_extents.y - pad;
-	x2 = surface_extents.x + (int) surface_extents.width  + pad;
-	y2 = surface_extents.y + (int) surface_extents.height + pad;
-
-	imatrix = pattern->matrix;
-	status = cairo_matrix_invert (&imatrix);
-	/* cairo_pattern_set_matrix ensures the matrix is invertible */
-	assert (status == CAIRO_STATUS_SUCCESS);
-
-	_cairo_matrix_transform_bounding_box (&imatrix,
-					      &x1, &y1, &x2, &y2,
-					      NULL);
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	goto UNBOUNDED;
 
-	x1 = floor (x1);
-	if (x1 < CAIRO_RECT_INT_MIN)
-	    x1 = CAIRO_RECT_INT_MIN;
-	y1 = floor (y1);
-	if (y1 < CAIRO_RECT_INT_MIN)
-	    y1 = CAIRO_RECT_INT_MIN;
-
-	x2 = ceil (x2);
-	if (x2 > CAIRO_RECT_INT_MAX)
-	    x2 = CAIRO_RECT_INT_MAX;
-	y2 = ceil (y2);
-	if (y2 > CAIRO_RECT_INT_MAX)
-	    y2 = CAIRO_RECT_INT_MAX;
-
-	extents->x = x1; extents->width = x2 - x1;
-	extents->y = y1; extents->height = y2 - y1;
-	return;
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	{
+	    cairo_rectangle_int_t surface_extents;
+	    const cairo_surface_pattern_t *surface_pattern =
+		(const cairo_surface_pattern_t *) pattern;
+	    cairo_surface_t *surface = surface_pattern->surface;
+	    double pad;
+
+	    if (! _cairo_surface_get_extents (surface, &surface_extents))
+		goto UNBOUNDED;
+
+	    /* The filter can effectively enlarge the extents of the
+	     * pattern, so extend as necessary.
+	     */
+	    _cairo_pattern_analyze_filter (&surface_pattern->base, &pad);
+	    x1 = surface_extents.x - pad;
+	    y1 = surface_extents.y - pad;
+	    x2 = surface_extents.x + (int) surface_extents.width  + pad;
+	    y2 = surface_extents.y + (int) surface_extents.height + pad;
+	}
+	break;
+
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	{
+	    const cairo_radial_pattern_t *radial =
+		(const cairo_radial_pattern_t *) pattern;
+	    double cx1, cy1;
+	    double cx2, cy2;
+	    double r, D;
+
+	    cx1 = _cairo_fixed_to_double (radial->c1.x);
+	    cy1 = _cairo_fixed_to_double (radial->c1.y);
+	    r = _cairo_fixed_to_double (radial->r1);
+	    x1 = cx1 - r; x2 = cx1 + r;
+	    y1 = cy1 - r; y2 = cy1 + r;
+
+	    cx2 = _cairo_fixed_to_double (radial->c2.x);
+	    cy2 = _cairo_fixed_to_double (radial->c2.y);
+	    r = fabs (_cairo_fixed_to_double (radial->r2));
+
+	    /* We need to be careful, as if the circles are not
+	     * self-contained, then the solution is actually unbounded.
+	     */
+	    D = (cx1-cx2)*(cx1-cx2) + (cy1-cy2)*(cy1-cy2);
+	    if (D > r*r - 1e-5)
+		goto UNBOUNDED;
+
+	    if (cx2 - r < x1)
+		x1 = cx2 - r;
+	    if (cx2 + r > x2)
+		x2 = cx2 + r;
+
+	    if (cy2 - r < y1)
+		y1 = cy2 - r;
+	    if (cy2 + r > y2)
+		y2 = cy2 + r;
+	}
+	break;
+
+    case CAIRO_PATTERN_TYPE_LINEAR:
+	{
+	    const cairo_linear_pattern_t *linear =
+		(const cairo_linear_pattern_t *) pattern;
+
+	    if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.)
+		goto UNBOUNDED;
+
+	    if (linear->p1.x == linear->p2.x) {
+		x1 = -HUGE_VAL;
+		x2 = HUGE_VAL;
+		y1 = _cairo_fixed_to_double (MIN (linear->p1.y, linear->p2.y));
+		y2 = _cairo_fixed_to_double (MAX (linear->p1.y, linear->p2.y));
+	    } else if (linear->p1.y == linear->p2.y) {
+		x1 = _cairo_fixed_to_double (MIN (linear->p1.x, linear->p2.x));
+		x2 = _cairo_fixed_to_double (MAX (linear->p1.x, linear->p2.x));
+		y1 = -HUGE_VAL;
+		y2 = HUGE_VAL;
+	    } else {
+		goto  UNBOUNDED;
+	    }
+	}
+	break;
+
+    default:
+	ASSERT_NOT_REACHED;
     }
 
-    /* XXX: We could optimize gradients with pattern->extend of NONE
-     * here in some cases, (eg. radial gradients and 1 axis of
-     * horizontal/vertical linear gradients).
-     */
+    imatrix = pattern->matrix;
+    status = cairo_matrix_invert (&imatrix);
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    _cairo_matrix_transform_bounding_box (&imatrix,
+					  &x1, &y1, &x2, &y2,
+					  NULL);
+
+    x1 = floor (x1);
+    if (x1 < CAIRO_RECT_INT_MIN)
+	x1 = CAIRO_RECT_INT_MIN;
+    y1 = floor (y1);
+    if (y1 < CAIRO_RECT_INT_MIN)
+	y1 = CAIRO_RECT_INT_MIN;
+
+    x2 = ceil (x2);
+    if (x2 > CAIRO_RECT_INT_MAX)
+	x2 = CAIRO_RECT_INT_MAX;
+    y2 = ceil (y2);
+    if (y2 > CAIRO_RECT_INT_MAX)
+	y2 = CAIRO_RECT_INT_MAX;
+
+    extents->x = x1; extents->width  = x2 - x1;
+    extents->y = y1; extents->height = y2 - y1;
+    return;
 
   UNBOUNDED:
     /* unbounded patterns -> 'infinite' extents */


More information about the cairo-commit mailing list