diff options
author | Andrea Canciani <ranma42@gmail.com> | 2011-03-05 10:59:22 +0100 |
---|---|---|
committer | Andrea Canciani <ranma42@gmail.com> | 2011-03-18 09:48:56 +0100 |
commit | 6521bab6e8d8c44e8a790ec6e10ae160ecaf8bc9 (patch) | |
tree | e6285460f371aef9689794791e54b5b08a236daf | |
parent | 426fe6fadffc50f1845b114fc3f41c27f96e8e79 (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.c | 29 | ||||
-rw-r--r-- | src/cairo-xcb-surface-render.c | 8 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 6 | ||||
-rw-r--r-- | src/cairoint.h | 3 |
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); |