summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Canciani <ranma42@gmail.com>2011-03-05 10:59:22 +0100
committerAndrea Canciani <ranma42@gmail.com>2011-03-18 09:48:56 +0100
commit6521bab6e8d8c44e8a790ec6e10ae160ecaf8bc9 (patch)
treee6285460f371aef9689794791e54b5b08a236daf
parent426fe6fadffc50f1845b114fc3f41c27f96e8e79 (diff)
xcb,xlib: Fallback upon generic radial gradients
The RENDER specification requires radial gradients to have the first circle completely inside the second one, but the error is not actually generated. The implementation produces the expected results if either circle contains the other one, so only fall back in these cases.
-rw-r--r--src/cairo-pattern.c29
-rw-r--r--src/cairo-xcb-surface-render.c8
-rw-r--r--src/cairo-xlib-surface.c6
-rw-r--r--src/cairoint.h3
4 files changed, 46 insertions, 0 deletions
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 000b1ee4..5663a9b4 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2631,6 +2631,35 @@ _extend_range (double range[2], double value, cairo_bool_t valid)
return TRUE;
}
+/**
+ * _cairo_radial_pattern_focus_is_inside
+ *
+ * Returns %TRUE if and only if the focus point exists and is
+ * contained in one of the two extreme circles. This condition is
+ * equivalent to one of the two extreme circles being completely
+ * contained in the other one.
+ *
+ * Note: if the focus is on the border of one of the two circles (in
+ * which case the circles are tangent in the focus point), it is not
+ * considered as contained in the circle, hence this function returns
+ * %FALSE.
+ *
+ **/
+cairo_bool_t
+_cairo_radial_pattern_focus_is_inside (const cairo_radial_pattern_t *radial)
+{
+ double cx, cy, cr, dx, dy, dr;
+
+ cx = radial->cd1.center.x;
+ cy = radial->cd1.center.y;
+ cr = radial->cd1.radius;
+ dx = radial->cd2.center.x - cx;
+ dy = radial->cd2.center.y - cy;
+ dr = radial->cd2.radius - cr;
+
+ return dx*dx + dy*dy < dr*dr;
+}
+
static void
_cairo_radial_pattern_box_to_parameter (const cairo_radial_pattern_t *radial,
double x0, double y0,
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index c7fcaa48..9c377e35 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -379,6 +379,14 @@ _pattern_is_supported (uint32_t flags,
} else { /* gradient */
if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
return FALSE;
+
+ /* The RENDER specification says that the inner circle has to be
+ * completely contained inside the outer one. */
+ if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL &&
+ ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) pattern))
+ {
+ return FALSE;
+ }
}
return pattern->type != CAIRO_PATTERN_TYPE_MESH;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index a0ad14a4..3f5d0ead 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2105,6 +2105,12 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
if (dst->buggy_gradients)
break;
+ /* The RENDER specification says that the inner circle has
+ * to be completely contained inside the outer one. */
+ if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL &&
+ ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) gradient))
+ break;
+
assert (gradient->n_stops > 0);
n_stops = MAX (gradient->n_stops, 2);
diff --git a/src/cairoint.h b/src/cairoint.h
index 1aaca2a8..0bfea8f4 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2247,6 +2247,9 @@ _cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
cairo_matrix_t *out_matrix,
cairo_circle_double_t out_circle[2]);
+cairo_bool_t
+_cairo_radial_pattern_focus_is_inside (const cairo_radial_pattern_t *radial);
+
cairo_private cairo_bool_t
_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);