[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