V5: Use NEAREST filter when possible

(changed to use determinant funciton and remove debug printf)

Modifies _cairo_matrix_has_unity_scale to return true for 90 degree rotations
by allowing error caused by inaccuracy in trig functions.

This fails after 14 additions of M_PI_2 to itself as a float argument to
cairo_rotate, but the failure is in the detection of the integer translate,
not in the trig components. I believe this is due to the matrix inversion,
which may need similar rounding.

Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
This commit is contained in:
Bill Spitzak 2014-08-12 15:48:04 -07:00 committed by Bryce Harrington
parent 7d44f8d47e
commit 1d9f4ae520
3 changed files with 26 additions and 20 deletions

View file

@ -748,23 +748,32 @@ _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
return FALSE;
}
#define SCALING_EPSILON _cairo_fixed_to_double(1)
/* This only returns true if the matrix is 90 degree rotations or
* flips. It appears calling code is relying on this. It will return
* false for other rotations even if the scale is one. Approximations
* are allowed to handle matricies filled in using trig functions
* such as sin(M_PI_2).
*/
cairo_bool_t
_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix)
{
if (matrix->xy == 0.0 && matrix->yx == 0.0) {
if (! (matrix->xx == 1.0 || matrix->xx == -1.0))
return FALSE;
if (! (matrix->yy == 1.0 || matrix->yy == -1.0))
return FALSE;
} else if (matrix->xx == 0.0 && matrix->yy == 0.0) {
if (! (matrix->xy == 1.0 || matrix->xy == -1.0))
return FALSE;
if (! (matrix->yx == 1.0 || matrix->yx == -1.0))
return FALSE;
} else
return FALSE;
return TRUE;
/* check that the determinant is near +/-1 */
double det = _cairo_matrix_compute_determinant (matrix);
if (fabs (det * det - 1.0) < SCALING_EPSILON) {
/* check that one axis is close to zero */
if (fabs (matrix->xy) < SCALING_EPSILON &&
fabs (matrix->yx) < SCALING_EPSILON)
return TRUE;
if (fabs (matrix->xx) < SCALING_EPSILON &&
fabs (matrix->yy) < SCALING_EPSILON)
return TRUE;
/* If rotations are allowed then it must instead test for
* orthogonality. This is xx*xy+yx*yy ~= 0.
*/
}
return FALSE;
}
/* By pixel exact here, we mean a matrix that is composed only of

View file

@ -3363,6 +3363,7 @@ _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
case CAIRO_FILTER_GOOD:
case CAIRO_FILTER_BEST:
case CAIRO_FILTER_BILINEAR:
case CAIRO_FILTER_FAST:
/* If source pixels map 1:1 onto destination pixels, we do
* not need to filter (and do not want to filter, since it
* will cause blurriness)
@ -3381,7 +3382,6 @@ _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
}
break;
case CAIRO_FILTER_FAST:
case CAIRO_FILTER_NEAREST:
case CAIRO_FILTER_GAUSSIAN:
default:

View file

@ -414,8 +414,7 @@ _pattern_is_supported (uint32_t flags,
cairo_filter_t filter;
filter = pattern->filter;
if (_cairo_matrix_has_unity_scale (&pattern->matrix) &&
_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
if (_cairo_matrix_is_pixel_exact (&pattern->matrix))
{
filter = CAIRO_FILTER_NEAREST;
}
@ -1033,9 +1032,7 @@ _cairo_xcb_surface_setup_surface_picture(cairo_xcb_picture_t *picture,
filter = pattern->base.filter;
if (filter != CAIRO_FILTER_NEAREST &&
_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
_cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.x0)) &&
_cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.y0)))
_cairo_matrix_is_pixel_exact (&pattern->base.matrix))
{
filter = CAIRO_FILTER_NEAREST;
}