Enable access to the pixman dithering path

Newer versions of Pixman allow choosing the dithering format.
This commit is contained in:
Marc Jeanmougin 2023-05-25 18:50:38 +02:00 committed by Emmanuele Bassi
parent 7380d3dd7d
commit e6ab85712c
13 changed files with 201 additions and 3 deletions

View file

@ -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>

View file

@ -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));

View file

@ -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;

View file

@ -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

View file

@ -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 ");

View file

@ -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 */ \
}

View file

@ -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:

View file

@ -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);

53
test/dithergradient.c Normal file
View file

@ -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@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)

View file

@ -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',

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB