[cairo] [PATCH 1/6] image: Move filter decision to _cairo_pattern_analyze_filter

Bill Spitzak spitzak at gmail.com
Thu Oct 9 19:46:11 PDT 2014


The analysis to deterimine if the GOOD filter can be replaced with
the BILINEAR filter is moved to this function so it can be used
by backends other than the image backend.
---
 src/cairo-image-source.c |   22 +++++++++-------------
 src/cairo-pattern.c      |   36 +++++++++++++++++++++++++++++++++++-
 2 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index b6b6b9f..950053d 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -941,21 +941,17 @@ _pixman_image_set_properties (pixman_image_t *pixman_image,
 	    pixman_filter = PIXMAN_FILTER_FAST;
 	    break;
 	case CAIRO_FILTER_GOOD:
-	    pixman_filter = PIXMAN_FILTER_GOOD;
-	    if (dx > 1.35 || dy > 1.35) {
-		pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION;
-		kernel = KERNEL_BOX;
-		/* Clip the filter size to prevent extreme slowness. This
-		   value could be raised if 2-pass filtering is done */
-		if (dx > 16.0) dx = 16.0;
-		/* Match the bilinear filter for dimension scaling up: */
-		else if (dx < 1.0) dx = 1.0;
-		if (dy > 16.0) dy = 16.0;
-		else if (dy < 1.0) dy = 1.0;
-	    }
+	    pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION;
+	    kernel = KERNEL_BOX;
+	    /* Clip the filter size to prevent extreme slowness. This
+	       value could be raised if 2-pass filtering is done */
+	    if (dx > 16.0) dx = 16.0;
+	    if (dy > 16.0) dy = 16.0;
+	    /* Match the bilinear filter for scales > .75: */
+	    if (dx < 1.0/0.75) dx = 1.0;
+	    if (dy < 1.0/0.75) dy = 1.0;
 	    break;
 	case CAIRO_FILTER_BEST:
-	    pixman_filter = PIXMAN_FILTER_BEST;
 	    pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION;
 	    kernel = KERNEL_CATMULL_ROM; /* LANCZOS3 is better but not much */
 	    /* Clip the filter size to prevent extreme slowness. This
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e6fdae6..1a93d2b 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -3339,6 +3339,26 @@ _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
 }
 
 /**
+ * Will given row of back-translation matrix work with bilinear scale?
+ * This is true for scales larger than 1. Also it was judged acceptable
+ * for scales larger than .75. And if there is integer translation
+ * then a scale of exactly .5 works.
+ */
+static int
+use_bilinear(double x, double y, double t)
+{
+    /* This is the inverse matrix! */
+    double h = x*x + y*y;
+    if (h < 1.0 / (0.75 * 0.75))
+	return TRUE; /* scale > .75 */
+    if ((h > 3.99 && h < 4.01) /* scale is 1/2 */
+	&& !_cairo_fixed_from_double(x*y) /* parallel to an axis */
+	&& _cairo_fixed_is_integer (_cairo_fixed_from_double (t)))
+	return TRUE;
+    return FALSE;
+}
+
+/**
  * _cairo_pattern_analyze_filter:
  * @pattern: surface pattern
  * @pad_out: location to store necessary padding in the source image, or %NULL
@@ -3378,7 +3398,21 @@ _cairo_pattern_analyze_filter (const cairo_pattern_t	*pattern,
 	     * more would be defensive...
 	     */
 	    pad = 0.5;
-	    optimized_filter = pattern->filter;
+	    /* Use BILINEAR for any scale greater than .75 instead
+	     * of GOOD. For scales of 1 and larger this is identical,
+	     * for the smaller sizes it was judged that the artifacts
+	     * were not worse than the artifacts from a box filer.
+	     * BILINEAR can also be used if the scale is exactly .5
+	     * and the translation in that direction is an integer.
+	     */
+	    if (pattern->filter == CAIRO_FILTER_GOOD &&
+		use_bilinear (pattern->matrix.xx, pattern->matrix.xy,
+			      pattern->matrix.x0) &&
+		use_bilinear (pattern->matrix.yx, pattern->matrix.yy,
+			      pattern->matrix.y0))
+		optimized_filter = CAIRO_FILTER_BILINEAR;
+	    else
+		optimized_filter = pattern->filter;
 	}
 	break;
 
-- 
1.7.9.5



More information about the cairo mailing list