diff options
author | Andrea Canciani <ranma42@gmail.com> | 2010-06-01 19:39:02 +0200 |
---|---|---|
committer | Andrea Canciani <ranma42@gmail.com> | 2010-06-10 16:07:42 +0200 |
commit | 561625ee3bd2732457eaaf28937edf557ee7661d (patch) | |
tree | 523d897aedffaaab8ad16e8de0fcfeac815612bd /src | |
parent | baaf312e047a9bea6f54e63cd6534c2ed7448523 (diff) |
pattern: improve clear/opaque check functions
_cairo_pattern_is_opaque was missing some checks about the extend type.
Conversely _cairo_pattern_is_clear was being too strict about gradients.
Diffstat (limited to 'src')
-rw-r--r-- | src/cairo-pattern.c | 112 | ||||
-rw-r--r-- | src/cairoint.h | 4 |
2 files changed, 108 insertions, 8 deletions
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 27a7a801..2aa80d5e 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -1726,6 +1726,69 @@ _cairo_pattern_reset_solid_surface_cache (void) CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock); } +static void +_extents_to_linear_parameter (const cairo_linear_pattern_t *linear, + const cairo_rectangle_int_t *extents, + double t[2]) +{ + double t0, tdx, tdy; + double p1x, p1y, pdx, pdy, invsqnorm; + + p1x = _cairo_fixed_to_double (linear->p1.x); + p1y = _cairo_fixed_to_double (linear->p1.y); + pdx = _cairo_fixed_to_double (linear->p2.x) - p1x; + pdy = _cairo_fixed_to_double (linear->p2.y) - p1y; + invsqnorm = 1.0 / (pdx * pdx + pdy * pdy); + pdx *= invsqnorm; + pdy *= invsqnorm; + + t0 = (extents->x - p1x) * pdx + (extents->y - p1y) * pdy; + tdx = extents->width * pdx; + tdy = extents->height * pdy; + + t[0] = t[1] = t0; + if (tdx < 0) + t[0] += tdx; + else + t[1] += tdx; + + if (tdy < 0) + t[0] += tdy; + else + t[1] += tdy; +} + +static cairo_bool_t +_gradient_is_clear (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents) +{ + unsigned int i; + + /* Check if the extents intersect the drawn part of the pattern. + * TODO: radial gradients, other linear extend modes. + */ + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + if (gradient->base.extend == CAIRO_EXTEND_NONE) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y) + return TRUE; + + if (extents != NULL) { + double t[2]; + _extents_to_linear_parameter (linear, extents, t); + if ((t[0] <= 0.0 && t[1] <= 0.0) || (t[0] >= 1.0 && t[1] >= 1.0)) + return TRUE; + } + } + } + + for (i = 0; i < gradient->n_stops; i++) + if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color)) + return FALSE; + + return TRUE; +} + /** * _cairo_pattern_is_opaque_solid * @@ -1779,13 +1842,46 @@ _surface_is_opaque (const cairo_surface_pattern_t *pattern, } static cairo_bool_t -_gradient_is_opaque (const cairo_gradient_pattern_t *gradient) +_surface_is_clear (const cairo_surface_pattern_t *pattern) +{ + cairo_rectangle_int_t extents; + + if (_cairo_surface_get_extents (pattern->surface, &extents) && + (extents.width == 0 || extents.height == 0)) + return TRUE; + + return pattern->surface->is_clear && + pattern->surface->content & CAIRO_CONTENT_ALPHA; +} + +static cairo_bool_t +_gradient_is_opaque (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents) { unsigned int i; if (gradient->n_stops == 0) return FALSE; + /* TODO: radial gradients, degenerate linear gradients */ + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y) + return FALSE; + + if (gradient->base.extend == CAIRO_EXTEND_NONE) { + double t[2]; + + if (extents == NULL) + return FALSE; + + _extents_to_linear_parameter (linear, extents, t); + if (t[0] < 0.0 || t[1] > 1.0) + return FALSE; + } + } else + return FALSE; + for (i = 0; i < gradient->n_stops; i++) if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color)) return FALSE; @@ -1819,7 +1915,7 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern, return _surface_is_opaque (&pattern->surface, extents); case CAIRO_PATTERN_TYPE_LINEAR: case CAIRO_PATTERN_TYPE_RADIAL: - return _gradient_is_opaque (&pattern->gradient.base); + return _gradient_is_opaque (&pattern->gradient.base, extents); } ASSERT_NOT_REACHED; @@ -1837,16 +1933,16 @@ _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern) pattern = (cairo_pattern_union_t *) abstract_pattern; switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: - return pattern->solid.color.alpha_short == 0x0000; + return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color); case CAIRO_PATTERN_TYPE_SURFACE: - return pattern->surface.surface->is_clear && - pattern->surface.surface->content & CAIRO_CONTENT_ALPHA; - default: - ASSERT_NOT_REACHED; + return _surface_is_clear (&pattern->surface); case CAIRO_PATTERN_TYPE_LINEAR: case CAIRO_PATTERN_TYPE_RADIAL: - return pattern->gradient.base.n_stops == 0; + return _gradient_is_clear (&pattern->gradient.base, NULL); } + + ASSERT_NOT_REACHED; + return FALSE; } /** diff --git a/src/cairoint.h b/src/cairoint.h index 22ff16da..59af6844 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -145,10 +145,14 @@ do { \ #define COMPILE_TIME_ASSERT0(condition, line) COMPILE_TIME_ASSERT1(condition, line) #define COMPILE_TIME_ASSERT(condition) COMPILE_TIME_ASSERT0(condition, __LINE__) +#define CAIRO_ALPHA_IS_CLEAR(alpha) ((alpha) <= ((double)0x00ff / (double)0xffff)) +#define CAIRO_ALPHA_SHORT_IS_CLEAR(alpha) ((alpha) <= 0x00ff) + #define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff)) #define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00) #define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0) +#define CAIRO_COLOR_IS_CLEAR(color) CAIRO_ALPHA_SHORT_IS_CLEAR ((color)->alpha_short) #define CAIRO_COLOR_IS_OPAQUE(color) CAIRO_ALPHA_SHORT_IS_OPAQUE ((color)->alpha_short) /* Reverse the bits in a byte with 7 operations (no 64-bit): |