mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-02 21:18:05 +02:00
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.
This commit is contained in:
parent
baaf312e04
commit
561625ee3b
2 changed files with 108 additions and 8 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue