[cairo] [PATCH] Use NEAREST filter when possible

Bill Spitzak spitzak at gmail.com
Mon Aug 11 20:22:17 PDT 2014


(this replaces the previous patch I posted for NEAREST filter)

Previous version failed to detect most 90 degree rotations due to
inaccuracy in the trig functions. And this can be used for BEST
transforms as well.
---
 src/cairo-matrix.c             |   29 ++++++++++++++++-------------
 src/cairo-pattern.c            |    2 +-
 src/cairo-xcb-surface-render.c |    7 ++-----
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index ba975be..ba73b53 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -748,23 +748,26 @@ _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
     return FALSE;
 }
 
+/* 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;
+    /* check that the determinant is near +/-1 */
+    double v = matrix->xx * matrix->yy - matrix->xy * matrix->yx;
+    v = v * v;
+    if (v < 0.99999 || v > 1.00001) return FALSE;
 
-    return TRUE;
+    /* check that one axis is close to zero */
+    if (fabs (matrix->xy) < 0.0001  &&  fabs (matrix->yx) < 0.0001)
+	return TRUE;
+    if (fabs (matrix->xx) < 0.0001  &&  fabs (matrix->yy) < 0.0001)
+	return TRUE;
+    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 e104440..6905e15 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 3f2fc43..a127000 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;
     }
-- 
1.7.9.5



More information about the cairo mailing list