[cairo] [PATCH] Support image filtering in xlib and xcb backends

Bryce Harrington bryce at osg.samsung.com
Thu Aug 14 16:30:01 PDT 2014


On Tue, Aug 12, 2014 at 08:06:35PM -0700, Bill Spitzak wrote:
> _cairo_pattern_analyze_filter() will change GOOD to BILINEAR if
> it thinks bilinear is acceptable. Removed the equivalent test
> from _pixman_image_set_properties.
> 
> The xlib and xcb backends will use the image fallback for GOOD
> and BEST so that the convolution can be done.
> 
> Notes:
> 
> - I did not test the xcb changes.
> 
> - I am assuming other backends treat bilinear and good identically,
> at least for scales larger than 1/1.35.
> 
> - A CAIRO_RENDER option maybe should be added in case pixman ever
> supports GOOD/BEST.

Should the above notes be taken care of before this is merged?

Functionally this looks good, and I gather this is outcome from recent
discussions with Chris and others.  I'd appreciate a third set of eyes
on this just for sanity checking, but otherwise:

Reviewed-by: Bryce Harrington <b.harrington at samsung.com>

> ---
>  src/cairo-image-source.c       |   22 +++++++++-------------
>  src/cairo-pattern.c            |   32 ++++++++++++++++++++++++--------
>  src/cairo-xcb-surface-render.c |   12 ++++--------
>  src/cairo-xlib-source.c        |    5 +++++
>  4 files changed, 42 insertions(+), 29 deletions(-)
> 
> diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
> index b6b6b9f..9cb3533 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;
> +	    /* Match the bilinear filter for dimension scaling up: */
> +	    else if (dx < 1.35) dx = 1.0;
> +	    if (dy > 16.0) dy = 16.0;
> +	    else if (dy < 1.35) 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 6905e15..b40eaa1 100644
> --- a/src/cairo-pattern.c
> +++ b/src/cairo-pattern.c
> @@ -3371,15 +3371,31 @@ _cairo_pattern_analyze_filter (const cairo_pattern_t	*pattern,
>  	if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) {
>  	    pad = 0.;
>  	    optimized_filter = CAIRO_FILTER_NEAREST;
> -	} else {
> -	    /* 0.5 is enough for a bilinear filter. It's possible we
> -	     * should defensively use more for CAIRO_FILTER_BEST, but
> -	     * without a single example, it's hard to know how much
> -	     * more would be defensive...
> -	     */
> -	    pad = 0.5;
> -	    optimized_filter = pattern->filter;
> +	    break;
> +	}
> +	optimized_filter = pattern->filter;
> +	/* Use BILINEAR for any scale greater than 1/1.35 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.
> +	 */
> +	if (pattern->filter == CAIRO_FILTER_GOOD) {
> +	    double h;
> +	    h = pattern->matrix.xx * pattern->matrix.xx +
> +		pattern->matrix.xy * pattern->matrix.xy;
> +	    if (h < 1.35 * 1.35) {
> +		h = pattern->matrix.yx * pattern->matrix.yx +
> +		    pattern->matrix.yy * pattern->matrix.yy;
> +		if (h < 1.35 * 1.35)
> +		    optimized_filter = CAIRO_FILTER_BILINEAR;
> +	    }
>  	}
> +	/* 0.5 is enough for a bilinear filter. It's possible we
> +	 * should defensively use more for CAIRO_FILTER_BEST, but
> +	 * without a single example, it's hard to know how much
> +	 * more would be defensive...
> +	 */
> +	pad = 0.5;
>  	break;
>  
>      case CAIRO_FILTER_NEAREST:
> diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
> index a127000..64bd1c5 100644
> --- a/src/cairo-xcb-surface-render.c
> +++ b/src/cairo-xcb-surface-render.c
> @@ -411,17 +411,13 @@ _pattern_is_supported (uint32_t flags,
>      }
>  
>      if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
> -	cairo_filter_t filter;
> -
> -	filter = pattern->filter;
> -	if (_cairo_matrix_is_pixel_exact (&pattern->matrix))
> -	{
> -	    filter = CAIRO_FILTER_NEAREST;
> -	}
> -
> +	cairo_filter_t filter = pattern->filter;
>  	if (! (filter == CAIRO_FILTER_NEAREST || filter == CAIRO_FILTER_FAST)) {
>  	    if ((flags & CAIRO_XCB_RENDER_HAS_FILTERS) == 0)
>  		return FALSE;
> +            /* Filter matrix is not supported in XRender */
> +	    if (filter == CAIRO_FILTER_GOOD || filter == CAIRO_FILTER_BEST)
> +		return FALSE;
>  	}
>      } else { /* gradient */
>  	if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
> diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
> index 8275da3..4326a6f 100644
> --- a/src/cairo-xlib-source.c
> +++ b/src/cairo-xlib-source.c
> @@ -1102,6 +1102,11 @@ pattern_is_supported (cairo_xlib_display_t *display,
>  	    /* No filters implies no transforms, so we optimise away BILINEAR */
>      }
>  
> +    /* Filter matrix is not supported in XRender */
> +    if (pattern->filter == CAIRO_FILTER_GOOD ||
> +	pattern->filter == CAIRO_FILTER_BEST)
> +	return FALSE;
> +
>      return TRUE;
>  }
>  cairo_surface_t *
> -- 
> 1.7.9.5
> 
> -- 
> cairo mailing list
> cairo at cairographics.org
> http://lists.cairographics.org/mailman/listinfo/cairo


More information about the cairo mailing list