summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Spitzak <spitzak@gmail.com>2014-08-12 15:48:04 -0700
committerBryce Harrington <bryce@osg.samsung.com>2014-08-14 12:59:07 -0700
commit1d9f4ae5208d86843a6001d10c9cb5b16df2b785 (patch)
treed748f49ab8803505747b8ebfffc45ba096a4c49f
parent7d44f8d47e7c4389cf6a3baefc7fee7b5dffbb21 (diff)
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>
-rw-r--r--src/cairo-matrix.c37
-rw-r--r--src/cairo-pattern.c2
-rw-r--r--src/cairo-xcb-surface-render.c7
3 files changed, 26 insertions, 20 deletions
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index ba975beae..ae498f515 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -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
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e104440c3..6905e15a3 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -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:
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 3f2fc436f..a1270009e 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -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;
}