[cairo] [PATCH] Support image filtering in xlib and xcb backends
Bill Spitzak
spitzak at gmail.com
Tue Aug 12 20:06:35 PDT 2014
_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.
---
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
More information about the cairo
mailing list