[cairo-commit] 4 commits - doc/public src/cairo.h src/cairo-image-surface.c src/cairoint.h src/cairo-pattern.c src/cairo-pattern-private.h src/cairo-script-surface.c src/cairo-surface.c test/dithergradient.c test/meson.build test/reference
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Sat Sep 23 11:49:52 UTC 2023
doc/public/cairo-sections.txt | 3
src/cairo-image-surface.c | 23 +++++
src/cairo-pattern-private.h | 2
src/cairo-pattern.c | 46 +++++++++++
src/cairo-script-surface.c | 26 ++++++
src/cairo-surface.c | 11 ++
src/cairo.h | 33 ++++++++
src/cairoint.h | 1
test/dithergradient.c | 80 ++++++++++++++++++++
test/meson.build | 1
test/reference/dithergradient.image.argb32.ref.png |binary
test/reference/dithergradient.image.rgb24.ref.png |binary
test/reference/dithergradient.image16.rgb24.ref.png |binary
13 files changed, 223 insertions(+), 3 deletions(-)
New commits:
commit 900b713af14e3558c15b3b2d9f2b449d367003c9
Merge: 6f9dbdad8 ac1ac72ff
Author: Emmanuele Bassi <ebassi at gmail.com>
Date: Sat Sep 23 11:49:49 2023 +0000
Merge branch 'ebassi/dithering' into 'master'
Enable access to the pixman dithering path
See merge request cairo/cairo!511
commit ac1ac72ff155b9cffdc3e51513962d34a9daebfa
Author: Uli Schlachter <psychon at znc.in>
Date: Sat Sep 23 12:15:27 2023 +0100
tests: Add more dithering tests
Use operator add to add the same source over and over again, to make the
dithering more pronounced.
diff --git a/test/dithergradient.c b/test/dithergradient.c
index 112395603..1ad1aadc7 100644
--- a/test/dithergradient.c
+++ b/test/dithergradient.c
@@ -25,12 +25,8 @@
#include "cairo-test.h"
-/* History:
- *
- * 2023: v3 of a patch to use pixman dithering with cairo
- */
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
+static void
+set_dither_source (cairo_t *cr, int width)
{
cairo_pattern_t *gradient = cairo_pattern_create_linear (0, 0, width, 0);
cairo_pattern_add_color_stop_rgba (gradient, 0., 25./255, 25./255, 25./255, 1.0);
@@ -38,9 +34,34 @@ draw (cairo_t *cr, int width, int height)
cairo_set_source (cr, gradient);
cairo_pattern_set_dither (gradient, CAIRO_DITHER_BEST);
+ cairo_pattern_destroy (gradient);
+}
+
+/* History:
+ *
+ * 2023: v3 of a patch to use pixman dithering with cairo
+ */
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ set_dither_source (cr, width);
cairo_paint (cr);
- cairo_pattern_destroy (gradient);
+ return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+draw2 (cairo_t *cr, int width, int height)
+{
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_paint (cr);
+
+ set_dither_source (cr, width);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
+ for (int i = 0; i < 5; i++) {
+ cairo_paint (cr);
+ }
return CAIRO_TEST_SUCCESS;
}
@@ -51,3 +72,9 @@ CAIRO_TEST (dithergradient,
NULL, /* requirements */
400, 100,
NULL, draw)
+CAIRO_TEST (dithergradient2,
+ "Testing the creation of a dithered gradient (in argb32)",
+ "gradient, dither", /* keywords */
+ NULL, /* requirements */
+ 400, 100,
+ NULL, draw2)
commit ac26a16171326d542d10e5c017e60bc2c2248172
Author: Emmanuele Bassi <ebassi at gnome.org>
Date: Mon Aug 21 16:16:47 2023 +0100
Make Cairo dither to Pixman dither conversion static
We don't use it anywhere outside of the image surface, so there's no
need to make it a project-wide private function.
The name is also updated: it's a cairo function, so it should not abuse
the pixman namespace.
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 047acf133..fe64cd76c 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -250,20 +250,20 @@ _pixman_format_from_masks (cairo_format_masks_t *masks,
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,39,0)
/* Convenience function to convert #cairo_dither_t into #pixman_dither_t */
-pixman_dither_t
-_pixman_dither_from_cairo_dither (cairo_dither_t dither)
+static pixman_dither_t
+_cairo_dither_to_pixman_dither (cairo_dither_t dither)
{
- switch(dither) {
- default:
- case CAIRO_DITHER_NONE:
- case CAIRO_DITHER_DEFAULT:
- return PIXMAN_DITHER_NONE;
+ switch (dither) {
case CAIRO_DITHER_FAST:
return PIXMAN_DITHER_FAST;
case CAIRO_DITHER_GOOD:
return PIXMAN_DITHER_GOOD;
case CAIRO_DITHER_BEST:
return PIXMAN_DITHER_BEST;
+ case CAIRO_DITHER_NONE:
+ case CAIRO_DITHER_DEFAULT:
+ default:
+ return PIXMAN_DITHER_NONE;
}
}
#endif
@@ -951,7 +951,7 @@ _cairo_image_surface_paint (void *abstract_surface,
const cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
- pixman_dither_t pixman_dither = _pixman_dither_from_cairo_dither(source->dither);
+ pixman_dither_t pixman_dither = _cairo_dither_to_pixman_dither (source->dither);
pixman_image_set_dither (surface->pixman_image, pixman_dither);
TRACE ((stderr, "%s (surface=%d)\n",
diff --git a/src/cairoint.h b/src/cairoint.h
index 85636d826..cac7f56d4 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1606,11 +1606,6 @@ cairo_private cairo_bool_t
_pixman_format_to_masks (pixman_format_code_t pixman_format,
cairo_format_masks_t *masks);
-#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,39,0)
-cairo_private pixman_dither_t
-_pixman_dither_from_cairo_dither (cairo_dither_t dither);
-#endif
-
cairo_private void
_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
commit e6ab85712cfa4450da1a010828c48c3044e57af8
Author: Marc Jeanmougin <marc at jeanmougin.fr>
Date: Thu May 25 18:50:38 2023 +0200
Enable access to the pixman dithering path
Newer versions of Pixman allow choosing the dithering format.
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 81c18a2de..f6dc84813 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -409,6 +409,9 @@ cairo_pattern_get_type
cairo_pattern_get_reference_count
cairo_pattern_set_user_data
cairo_pattern_get_user_data
+cairo_dither_t
+cairo_set_dither
+cairo_get_dither
</SECTION>
<SECTION>
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 553e32605..047acf133 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -248,6 +248,27 @@ _pixman_format_from_masks (cairo_format_masks_t *masks,
return TRUE;
}
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,39,0)
+/* Convenience function to convert #cairo_dither_t into #pixman_dither_t */
+pixman_dither_t
+_pixman_dither_from_cairo_dither (cairo_dither_t dither)
+{
+ switch(dither) {
+ default:
+ case CAIRO_DITHER_NONE:
+ case CAIRO_DITHER_DEFAULT:
+ return PIXMAN_DITHER_NONE;
+ case CAIRO_DITHER_FAST:
+ return PIXMAN_DITHER_FAST;
+ case CAIRO_DITHER_GOOD:
+ return PIXMAN_DITHER_GOOD;
+ case CAIRO_DITHER_BEST:
+ return PIXMAN_DITHER_BEST;
+ }
+}
+#endif
+
+
/* A mask consisting of N bits set to 1. */
#define MASK(N) ((1UL << (N))-1)
@@ -930,6 +951,8 @@ _cairo_image_surface_paint (void *abstract_surface,
const cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
+ pixman_dither_t pixman_dither = _pixman_dither_from_cairo_dither(source->dither);
+ pixman_image_set_dither (surface->pixman_image, pixman_dither);
TRACE ((stderr, "%s (surface=%d)\n",
__FUNCTION__, surface->base.unique_id));
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index d061b39c4..0e69d0177 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -52,6 +52,7 @@ enum {
CAIRO_PATTERN_NOTIFY_FILTER = 0x2,
CAIRO_PATTERN_NOTIFY_EXTEND = 0x4,
CAIRO_PATTERN_NOTIFY_OPACITY = 0x9,
+ CAIRO_PATTERN_NOTIFY_DITHER = 0x12,
};
struct _cairo_pattern_observer {
@@ -73,6 +74,7 @@ struct _cairo_pattern {
cairo_extend_t extend;
cairo_bool_t has_component_alpha;
cairo_bool_t is_foreground_marker;
+ cairo_dither_t dither;
cairo_matrix_t matrix;
double opacity;
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 1933fb80a..23c43855c 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -77,6 +77,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil = {
CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */
FALSE, /* has component alpha */
FALSE, /* is_foreground_marker */
+ CAIRO_DITHER_DEFAULT, /* dither */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
}
@@ -94,6 +95,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */
FALSE, /* has component alpha */
FALSE, /* is_foreground_marker */
+ CAIRO_DITHER_DEFAULT, /* dither */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
}
@@ -111,6 +113,7 @@ const cairo_solid_pattern_t _cairo_pattern_black = {
CAIRO_EXTEND_REPEAT, /* extend */
FALSE, /* has component alpha */
FALSE, /* is_foreground_marker */
+ CAIRO_DITHER_DEFAULT, /* dither */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
},
@@ -129,6 +132,7 @@ const cairo_solid_pattern_t _cairo_pattern_clear = {
CAIRO_EXTEND_REPEAT, /* extend */
FALSE, /* has component alpha */
FALSE, /* is_foreground_marker */
+ CAIRO_DITHER_DEFAULT, /* dither */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
},
@@ -147,6 +151,7 @@ const cairo_solid_pattern_t _cairo_pattern_white = {
CAIRO_EXTEND_REPEAT, /* extend */
FALSE, /* has component alpha */
FALSE, /* is_foreground_marker */
+ CAIRO_DITHER_DEFAULT, /* dither */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
},
@@ -240,6 +245,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
pattern->has_component_alpha = FALSE;
pattern->is_foreground_marker = FALSE;
+ pattern->dither = CAIRO_DITHER_DEFAULT;
+
cairo_matrix_init_identity (&pattern->matrix);
cairo_list_init (&pattern->observers);
@@ -2090,6 +2097,45 @@ cairo_pattern_get_filter (cairo_pattern_t *pattern)
return pattern->filter;
}
+/**
+ * cairo_pattern_get_dither:
+ * @pattern: a #cairo_pattern_t
+ *
+ * Gets the current dithering mode, as set by
+ * cairo_pattern_set_dither().
+ *
+ * Return value: the current dithering mode.
+ *
+ * Since: 1.18
+ **/
+cairo_dither_t
+cairo_pattern_get_dither (cairo_pattern_t *pattern)
+{
+ return pattern->dither;
+}
+
+/**
+ * cairo_pattern_set_dither:
+ * @pattern: a #cairo_pattern_t
+ * @dither: a #cairo_dither_t describing the new dithering mode
+ *
+ * Set the dithering mode of the rasterizer used for drawing shapes.
+ * This value is a hint, and a particular backend may or may not support
+ * a particular value. At the current time, only pixman is supported.
+ *
+ * Since: 1.18
+ **/
+void
+cairo_pattern_set_dither (cairo_pattern_t *pattern, cairo_dither_t dither)
+{
+ if (pattern->status)
+ return;
+
+ pattern->dither = dither;
+ _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_DITHER);
+
+}
+
/**
* cairo_pattern_set_extend:
* @pattern: a #cairo_pattern_t
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 1175bd8f3..23d64cf93 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -370,6 +370,21 @@ _filter_to_string (cairo_filter_t filter)
return names[filter];
}
+static const char *
+_dither_to_string (cairo_dither_t dither)
+{
+ static const char *names[] = {
+ "DITHER_DEFAULT", /* CAIRO_FILTER_FAST */
+ "DITHER_NONE", /* CAIRO_FILTER_GOOD */
+ "DITHER_FAST", /* CAIRO_FILTER_BEST */
+ "DITHER_GOOD", /* CAIRO_FILTER_NEAREST */
+ "DITHER_BEST", /* CAIRO_FILTER_BILINEAR */
+ };
+ assert (dither < ARRAY_LENGTH (names));
+ return names[dither];
+}
+
+
static const char *
_fill_rule_to_string (cairo_fill_rule_t rule)
{
@@ -1731,6 +1746,17 @@ _emit_pattern (cairo_script_surface_t *surface,
" //%s set-filter\n ",
_filter_to_string (pattern->filter));
}
+ /* XXX need to discriminate the user explicitly setting the default */
+ if (pattern->dither != CAIRO_DITHER_DEFAULT) {
+ if (need_newline) {
+ _cairo_output_stream_puts (ctx->stream, "\n ");
+ need_newline = FALSE;
+ }
+
+ _cairo_output_stream_printf (ctx->stream,
+ " //%s set-dither\n ",
+ _dither_to_string (pattern->dither));
+ }
if (! is_default_extend ){
if (need_newline) {
_cairo_output_stream_puts (ctx->stream, "\n ");
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 9110edb1a..d0706cbb0 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -127,13 +127,18 @@ const cairo_surface_t name = { \
NULL, /* snapshot_detach */ \
{ NULL, NULL }, /* snapshots */ \
{ NULL, NULL }, /* snapshot */ \
- { CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \
+ { /* font options begin */\
+ CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \
CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \
CAIRO_LCD_FILTER_DEFAULT, /* lcd_filter */ \
CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \
CAIRO_HINT_METRICS_DEFAULT, /* hint_metrics */ \
- CAIRO_ROUND_GLYPH_POS_DEFAULT /* round_glyph_positions */ \
- }, /* font_options */ \
+ CAIRO_ROUND_GLYPH_POS_DEFAULT, /* round_glyph_positions */ \
+ NULL, /* variations */ \
+ CAIRO_COLOR_MODE_DEFAULT, /* color mode */ \
+ CAIRO_COLOR_PALETTE_DEFAULT, /* color palette */ \
+ NULL, 0, /* custom palette */ \
+ }, /* font_options end */ \
NULL, /* foreground_source */ \
FALSE, /* foreground_used */ \
}
diff --git a/src/cairo.h b/src/cairo.h
index f6028a243..cd529c26e 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -440,6 +440,39 @@ typedef enum _cairo_format {
CAIRO_FORMAT_RGBA128F = 7
} cairo_format_t;
+/**
+ * cairo_dither_t:
+ * @CAIRO_DITHER_NONE: No dithering.
+ * @CAIRO_DITHER_DEFAULT: Default choice at cairo compile time. Currently NONE.
+ * @CAIRO_DITHER_FAST: Fastest dithering algorithm supported by the backend
+ * @CAIRO_DITHER_GOOD: An algorithm with smoother dithering than FAST
+ * @CAIRO_DITHER_BEST: Best algorithm available in the backend
+ *
+ * Dither is an intentionally applied form of noise used to randomize
+ * quantization error, preventing large-scale patterns such as color banding
+ * in images (e.g. for gradients). Ordered dithering applies a precomputed
+ * threshold matrix to spread the errors smoothly.
+ *
+ * #cairo_dither_t is modeled on pixman dithering algorithm choice.
+ * As of Pixman 0.40, FAST corresponds to a 8x8 ordered bayer noise and GOOD
+ * and BEST use an ordered 64x64 precomputed blue noise.
+ *
+ * Since: 1.18
+ **/
+#define CAIRO_HAS_DITHER
+typedef enum _cairo_dither {
+ CAIRO_DITHER_NONE,
+ CAIRO_DITHER_DEFAULT,
+ CAIRO_DITHER_FAST,
+ CAIRO_DITHER_GOOD,
+ CAIRO_DITHER_BEST
+} cairo_dither_t;
+
+cairo_public void
+cairo_pattern_set_dither (cairo_pattern_t *pattern, cairo_dither_t dither);
+
+cairo_public cairo_dither_t
+cairo_pattern_get_dither (cairo_pattern_t *pattern);
/**
* cairo_write_func_t:
diff --git a/src/cairoint.h b/src/cairoint.h
index c906c25c1..85636d826 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1606,6 +1606,12 @@ cairo_private cairo_bool_t
_pixman_format_to_masks (pixman_format_code_t pixman_format,
cairo_format_masks_t *masks);
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,39,0)
+cairo_private pixman_dither_t
+_pixman_dither_from_cairo_dither (cairo_dither_t dither);
+#endif
+
+
cairo_private void
_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph);
diff --git a/test/dithergradient.c b/test/dithergradient.c
new file mode 100644
index 000000000..112395603
--- /dev/null
+++ b/test/dithergradient.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2023 Marc Jeanmougin
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Marc Jeanmougin <marc at jeanmougin.fr>
+ */
+
+#include "cairo-test.h"
+
+/* History:
+ *
+ * 2023: v3 of a patch to use pixman dithering with cairo
+ */
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_pattern_t *gradient = cairo_pattern_create_linear (0, 0, width, 0);
+ cairo_pattern_add_color_stop_rgba (gradient, 0., 25./255, 25./255, 25./255, 1.0);
+ cairo_pattern_add_color_stop_rgba (gradient, 1., 45./255, 45./255, 45./255, 1.0);
+
+ cairo_set_source (cr, gradient);
+ cairo_pattern_set_dither (gradient, CAIRO_DITHER_BEST);
+ cairo_paint (cr);
+
+ cairo_pattern_destroy (gradient);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (dithergradient,
+ "Testing the creation of a dithered gradient (in argb32)",
+ "gradient, dither", /* keywords */
+ NULL, /* requirements */
+ 400, 100,
+ NULL, draw)
diff --git a/test/meson.build b/test/meson.build
index 1d76d5daa..68fcee4c1 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -124,6 +124,7 @@ test_sources = [
'device-offset-fractional.c',
'device-offset-positive.c',
'device-offset-scale.c',
+ 'dithergradient.c',
'error-setters.c',
'extend-pad.c',
'extend-pad-border.c',
diff --git a/test/reference/dithergradient.image.argb32.ref.png b/test/reference/dithergradient.image.argb32.ref.png
new file mode 100644
index 000000000..c44e12380
Binary files /dev/null and b/test/reference/dithergradient.image.argb32.ref.png differ
diff --git a/test/reference/dithergradient.image.rgb24.ref.png b/test/reference/dithergradient.image.rgb24.ref.png
new file mode 100644
index 000000000..c44e12380
Binary files /dev/null and b/test/reference/dithergradient.image.rgb24.ref.png differ
diff --git a/test/reference/dithergradient.image16.rgb24.ref.png b/test/reference/dithergradient.image16.rgb24.ref.png
new file mode 100644
index 000000000..fa1950a88
Binary files /dev/null and b/test/reference/dithergradient.image16.rgb24.ref.png differ
More information about the cairo-commit
mailing list