cedric pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=4d75e359ff8cd0c434b784fd22ce56bac2438a16
commit 4d75e359ff8cd0c434b784fd22ce56bac2438a16 Author: Cedric BAIL <ced...@osg.samsung.com> Date: Tue Sep 15 07:36:00 2015 +0200 ector: fix cairo backend to properly multiply gradient color. @fix --- src/lib/ector/cairo/ector_cairo_private.h | 26 +++++ src/lib/ector/cairo/ector_renderer_cairo_base.c | 4 + src/lib/ector/cairo/ector_renderer_cairo_base.eo | 3 + .../cairo/ector_renderer_cairo_gradient_linear.c | 97 +++++++++--------- .../cairo/ector_renderer_cairo_gradient_radial.c | 112 +++++++++++---------- src/lib/ector/cairo/ector_renderer_cairo_shape.c | 7 +- src/lib/ector/software/ector_drawhelper_private.h | 2 +- 7 files changed, 144 insertions(+), 107 deletions(-) diff --git a/src/lib/ector/cairo/ector_cairo_private.h b/src/lib/ector/cairo/ector_cairo_private.h index b5782ff..5a27708 100644 --- a/src/lib/ector/cairo/ector_cairo_private.h +++ b/src/lib/ector/cairo/ector_cairo_private.h @@ -72,4 +72,30 @@ _ector_cairo_symbol_get(Eo *obj, const char *name) return sym; } +extern void (*cairo_pattern_add_color_stop_rgba)(cairo_pattern_t *pattern, double offset, + double red, double green, double blue, double alpha); + +static inline void +_ector_renderer_cairo_gradient_prepare(Eo *obj, + cairo_pattern_t *pat, + Ector_Renderer_Generic_Gradient_Data *src, + unsigned int mul_col) +{ + unsigned int i; + + USE(obj, cairo_pattern_add_color_stop_rgba, ); + + for (i = 0; i < src->colors_count; i++) + { + int r,g,b,a; + + r = ((src->colors[i].r * R_VAL(&mul_col)) >> 8); + g = ((src->colors[i].g * G_VAL(&mul_col)) >> 8); + b = ((src->colors[i].b * B_VAL(&mul_col)) >> 8); + a = ((src->colors[i].a * A_VAL(&mul_col)) >> 8); + ector_color_argb_unpremul(a, &r, &g, &b); + cairo_pattern_add_color_stop_rgba(pat, src->colors[i].offset, r/255.0, g/255.0, b/255.0, a/255.0); + } +} + #endif diff --git a/src/lib/ector/cairo/ector_renderer_cairo_base.c b/src/lib/ector/cairo/ector_renderer_cairo_base.c index 4f25b9e..420ce1f 100644 --- a/src/lib/ector/cairo/ector_renderer_cairo_base.c +++ b/src/lib/ector/cairo/ector_renderer_cairo_base.c @@ -65,6 +65,10 @@ static void (*cairo_rectangle)(cairo_t *cr, double x, double y, double width, do static void (*cairo_clip)(cairo_t *cr) = NULL; static void (*cairo_device_to_user)(cairo_t *cr, double *x, double *y) = NULL; +// This one is used by both gradient, so sharing it here. +void (*cairo_pattern_add_color_stop_rgba)(cairo_pattern_t *pattern, double offset, + double red, double green, double blue, double alpha) = NULL; + static cairo_matrix_t identity; // Cairo need unpremul color, so force unpremul here diff --git a/src/lib/ector/cairo/ector_renderer_cairo_base.eo b/src/lib/ector/cairo/ector_renderer_cairo_base.eo index c34b9a8..43efa72 100644 --- a/src/lib/ector/cairo/ector_renderer_cairo_base.eo +++ b/src/lib/ector/cairo/ector_renderer_cairo_base.eo @@ -4,6 +4,9 @@ abstract Ector.Renderer.Cairo.Base (Ector.Renderer.Generic.Base) methods { fill { return: bool; + params { + @in mul_col: uint; + } } } implements { diff --git a/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.c b/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.c index 15b4e42..2eece58 100644 --- a/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.c +++ b/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.c @@ -16,8 +16,6 @@ static void (*cairo_fill)(cairo_t *cr) = NULL; static void (*cairo_rectangle)(cairo_t *cr, double x, double y, double width, double height) = NULL; -static void (*cairo_pattern_add_color_stop_rgba)(cairo_pattern_t *pattern, double offset, - double red, double green, double blue, double alpha) = NULL; static void (*cairo_pattern_destroy)(cairo_pattern_t *pattern) = NULL; static void (*cairo_pattern_set_extend)(cairo_pattern_t *pattern, cairo_extend_t extend) = NULL; @@ -26,43 +24,34 @@ typedef struct _Ector_Renderer_Cairo_Gradient_Linear_Data Ector_Renderer_Cairo_G struct _Ector_Renderer_Cairo_Gradient_Linear_Data { Ector_Cairo_Surface_Data *parent; - cairo_pattern_t *pat; }; -static Eina_Bool -_ector_renderer_cairo_gradient_linear_ector_renderer_generic_base_prepare(Eo *obj, - Ector_Renderer_Cairo_Gradient_Linear_Data *pd) +static cairo_pattern_t * +_ector_renderer_cairo_gradient_linear_prepare(Eo *obj, + Ector_Renderer_Generic_Gradient_Linear_Data *gld, + Ector_Renderer_Generic_Gradient_Data *gd, + unsigned int mul_col) { - Ector_Renderer_Generic_Gradient_Linear_Data *gld; - Ector_Renderer_Generic_Gradient_Data *gd; - unsigned int i; - - eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, ector_renderer_prepare()); - - if (pd->pat) return EINA_FALSE; - - gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN); - gd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN); - if (!gld || !gd) return EINA_FALSE; + cairo_pattern_t *pat; USE(obj, cairo_pattern_create_linear, EINA_FALSE); - USE(obj, cairo_pattern_add_color_stop_rgba, EINA_FALSE); - pd->pat = cairo_pattern_create_linear(gld->start.x, gld->start.y, + pat = cairo_pattern_create_linear(gld->start.x, gld->start.y, gld->end.x, gld->end.y); - int r,g,b,a; - for (i = 0; i < gd->colors_count; i++) - { - r = gd->colors[i].r; - g = gd->colors[i].g; - b = gd->colors[i].b; - a = gd->colors[i].a; - ector_color_argb_unpremul(a, &r, &g, &b); - cairo_pattern_add_color_stop_rgba(pd->pat, gd->colors[i].offset, r/255.0, g/255.0, b/255.0, a/255.0); - } + if (!pat) return NULL; + _ector_renderer_cairo_gradient_prepare(obj, pat, gd, mul_col); USE(obj, cairo_pattern_set_extend, EINA_FALSE); - cairo_pattern_set_extend(pd->pat, _ector_cairo_extent_get(gd->s)); + cairo_pattern_set_extend(pat, _ector_cairo_extent_get(gd->s)); + + return pat; +} + +static Eina_Bool +_ector_renderer_cairo_gradient_linear_ector_renderer_generic_base_prepare(Eo *obj, + Ector_Renderer_Cairo_Gradient_Linear_Data *pd) +{ + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, ector_renderer_prepare()); if (!pd->parent) { @@ -81,37 +70,56 @@ _ector_renderer_cairo_gradient_linear_ector_renderer_generic_base_draw(Eo *obj, Ector_Renderer_Cairo_Gradient_Linear_Data *pd, Ector_Rop op, Eina_Array *clips, unsigned int mul_col) { - if (pd->pat) return EINA_FALSE; - Ector_Renderer_Generic_Gradient_Linear_Data *gld; + Ector_Renderer_Generic_Gradient_Data *gd; + cairo_pattern_t *pat; // FIXME: don't ignore clipping ! gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN); - if (!pd->pat || !gld) return EINA_FALSE; + gd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN); + if (!gd || !gld) return EINA_FALSE; + + pat = _ector_renderer_cairo_gradient_linear_prepare(obj, gld, gd, mul_col); + if (!pat) return EINA_FALSE; eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, ector_renderer_draw(op, clips, mul_col)); USE(obj, cairo_rectangle, EINA_FALSE); USE(obj, cairo_fill, EINA_FALSE); + USE(obj, cairo_pattern_destroy, EINA_FALSE); + USE(obj, cairo_set_source, EINA_FALSE); cairo_rectangle(pd->parent->cairo, gld->start.x, gld->start.y, gld->end.x - gld->start.x, gld->end.y - gld->start.y); - eo_do(obj, ector_renderer_cairo_base_fill()); + cairo_set_source(pd->parent->cairo, pat); cairo_fill(pd->parent->cairo); + cairo_pattern_destroy(pat); return EINA_TRUE; } static Eina_Bool _ector_renderer_cairo_gradient_linear_ector_renderer_cairo_base_fill(Eo *obj, - Ector_Renderer_Cairo_Gradient_Linear_Data *pd) + Ector_Renderer_Cairo_Gradient_Linear_Data *pd, + unsigned int mul_col) { - if (!pd->pat) return EINA_FALSE; + Ector_Renderer_Generic_Gradient_Linear_Data *gld; + Ector_Renderer_Generic_Gradient_Data *gd; + cairo_pattern_t *pat; + + gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN); + gd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN); + if (!gd || !gld) return EINA_FALSE; + + pat = _ector_renderer_cairo_gradient_linear_prepare(obj, gld, gd, mul_col); + if (!pat) return EINA_FALSE; USE(obj, cairo_set_source, EINA_FALSE); + USE(obj, cairo_pattern_destroy, EINA_FALSE); - cairo_set_source(pd->parent->cairo, pd->pat); + cairo_set_source(pd->parent->cairo, pat); + cairo_pattern_destroy(pat); return EINA_TRUE; } @@ -139,11 +147,6 @@ _ector_renderer_cairo_gradient_linear_eo_base_destructor(Eo *obj, { Eo *parent; - USE(obj, cairo_pattern_destroy, ); - - if (pd->pat) cairo_pattern_destroy(pd->pat); - pd->pat = NULL; - eo_do(obj, parent = eo_parent_get()); eo_data_xunref(parent, pd->parent, obj); @@ -151,13 +154,11 @@ _ector_renderer_cairo_gradient_linear_eo_base_destructor(Eo *obj, } void -_ector_renderer_cairo_gradient_linear_efl_gfx_gradient_base_stop_set(Eo *obj, Ector_Renderer_Cairo_Gradient_Linear_Data *pd, const Efl_Gfx_Gradient_Stop *colors, unsigned int length) +_ector_renderer_cairo_gradient_linear_efl_gfx_gradient_base_stop_set(Eo *obj, + Ector_Renderer_Cairo_Gradient_Linear_Data *pd EINA_UNUSED, + const Efl_Gfx_Gradient_Stop *colors, + unsigned int length) { - USE(obj, cairo_pattern_destroy, ); - - if (pd->pat) cairo_pattern_destroy(pd->pat); - pd->pat = NULL; - eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, efl_gfx_gradient_stop_set(colors, length)); } diff --git a/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.c b/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.c index 34a6d70..508632b 100644 --- a/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.c +++ b/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.c @@ -19,8 +19,6 @@ static void (*cairo_arc)(cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2) = NULL; -static void (*cairo_pattern_add_color_stop_rgba)(cairo_pattern_t *pattern, double offset, - double red, double green, double blue, double alpha) = NULL; static void (*cairo_pattern_destroy)(cairo_pattern_t *pattern) = NULL; static void (*cairo_pattern_set_extend)(cairo_pattern_t *pattern, cairo_extend_t extend) = NULL; @@ -31,44 +29,13 @@ typedef struct _Ector_Renderer_Cairo_Gradient_Radial_Data Ector_Renderer_Cairo_G struct _Ector_Renderer_Cairo_Gradient_Radial_Data { Ector_Cairo_Surface_Data *parent; - cairo_pattern_t *pat; }; static Eina_Bool _ector_renderer_cairo_gradient_radial_ector_renderer_generic_base_prepare(Eo *obj, Ector_Renderer_Cairo_Gradient_Radial_Data *pd) { - Ector_Renderer_Generic_Gradient_Radial_Data *grd; - Ector_Renderer_Generic_Gradient_Data *gd; - unsigned int i; - eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_RADIAL_CLASS, ector_renderer_prepare()); - if (pd->pat) return EINA_FALSE; - - grd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN); - gd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN); - if (!grd || !gd) return EINA_FALSE; - - USE(obj, cairo_pattern_create_radial, EINA_FALSE); - USE(obj, cairo_pattern_add_color_stop_rgba, EINA_FALSE); - - pd->pat = cairo_pattern_create_radial(grd->focal.x, grd->focal.y, 0, - grd->radial.x, grd->radial.y, grd->radius); - - int r,g,b,a; - for (i = 0; i < gd->colors_count; i++) - { - r = gd->colors[i].r; - g = gd->colors[i].g; - b = gd->colors[i].b; - a = gd->colors[i].a; - ector_color_argb_unpremul(a, &r, &g, &b); - cairo_pattern_add_color_stop_rgba(pd->pat, gd->colors[i].offset, r/255.0, g/255.0, b/255.0, a/255.0); - } - - USE(obj, cairo_pattern_set_extend, EINA_FALSE); - cairo_pattern_set_extend(pd->pat, _ector_cairo_extent_get(gd->s)); - if (!pd->parent) { Eo *parent; @@ -81,42 +48,84 @@ _ector_renderer_cairo_gradient_radial_ector_renderer_generic_base_prepare(Eo *ob return EINA_FALSE; } +static cairo_pattern_t * +_ector_renderer_cairo_gradient_radial_prepare(Eo *obj, + Ector_Renderer_Generic_Gradient_Radial_Data *grd, + Ector_Renderer_Generic_Gradient_Data *gd, + unsigned int mul_col) +{ + cairo_pattern_t *pat; + + USE(obj, cairo_pattern_create_radial, EINA_FALSE); + + pat = cairo_pattern_create_radial(grd->focal.x, grd->focal.y, 0, + grd->radial.x, grd->radial.y, grd->radius); + if (!pat) return NULL; + + _ector_renderer_cairo_gradient_prepare(obj, pat, gd, mul_col); + + USE(obj, cairo_pattern_set_extend, EINA_FALSE); + cairo_pattern_set_extend(pat, _ector_cairo_extent_get(gd->s)); + + return pat; +} + // Clearly duplicated and should be in a common place... static Eina_Bool _ector_renderer_cairo_gradient_radial_ector_renderer_generic_base_draw(Eo *obj, Ector_Renderer_Cairo_Gradient_Radial_Data *pd, Ector_Rop op, Eina_Array *clips, unsigned int mul_col) { - if (pd->pat) return EINA_FALSE; + Ector_Renderer_Generic_Gradient_Radial_Data *grd; + Ector_Renderer_Generic_Gradient_Data *gd; + cairo_pattern_t *pat; - Ector_Renderer_Generic_Gradient_Radial_Data *gld; + // FIXME: Handle clipping and generally make it work :-) + grd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN); + gd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN); + if (!grd || !gd) return EINA_FALSE; - // FIXME: don't ignore clipping ! - gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN); - if (!pd->pat || !gld) return EINA_FALSE; + pat = _ector_renderer_cairo_gradient_radial_prepare(obj, grd, gd, mul_col); + if (!pat) return EINA_FALSE; eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_RADIAL_CLASS, ector_renderer_draw(op, clips, mul_col)); USE(obj, cairo_arc, EINA_FALSE); USE(obj, cairo_fill, EINA_FALSE); + USE(obj, cairo_set_source, EINA_FALSE); + USE(obj, cairo_pattern_destroy, EINA_FALSE); cairo_arc(pd->parent->cairo, - gld->radial.x, gld->radial.y, - gld->radius, + grd->radial.x, grd->radial.y, + grd->radius, 0, 2 * M_PI); - eo_do(obj, ector_renderer_cairo_base_fill()); + cairo_set_source(pd->parent->cairo, pat); cairo_fill(pd->parent->cairo); + cairo_pattern_destroy(pat); return EINA_TRUE; } // Clearly duplicated and should be in a common place... static Eina_Bool -_ector_renderer_cairo_gradient_radial_ector_renderer_cairo_base_fill(Eo *obj, Ector_Renderer_Cairo_Gradient_Radial_Data *pd) +_ector_renderer_cairo_gradient_radial_ector_renderer_cairo_base_fill(Eo *obj, + Ector_Renderer_Cairo_Gradient_Radial_Data *pd, + unsigned int mul_col) { - if (!pd->pat) return EINA_FALSE; + Ector_Renderer_Generic_Gradient_Radial_Data *grd; + Ector_Renderer_Generic_Gradient_Data *gd; + cairo_pattern_t *pat; + + grd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN); + gd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN); + if (!grd || !gd) return EINA_FALSE; + + pat = _ector_renderer_cairo_gradient_radial_prepare(obj, grd, gd, mul_col); + if (!pat) return EINA_FALSE; USE(obj, cairo_set_source, EINA_FALSE); + USE(obj, cairo_pattern_destroy, EINA_FALSE); - cairo_set_source(pd->parent->cairo, pd->pat); + cairo_set_source(pd->parent->cairo, pat); + cairo_pattern_destroy(pat); return EINA_TRUE; } @@ -143,11 +152,6 @@ _ector_renderer_cairo_gradient_radial_eo_base_destructor(Eo *obj, { Eo *parent; - USE(obj, cairo_pattern_destroy, ); - - if (pd->pat) cairo_pattern_destroy(pd->pat); - pd->pat = NULL; - eo_do(obj, parent = eo_parent_get()); eo_data_xunref(parent, pd->parent, obj); @@ -155,13 +159,11 @@ _ector_renderer_cairo_gradient_radial_eo_base_destructor(Eo *obj, } void -_ector_renderer_cairo_gradient_radial_efl_gfx_gradient_base_stop_set(Eo *obj, Ector_Renderer_Cairo_Gradient_Radial_Data *pd, const Efl_Gfx_Gradient_Stop *colors, unsigned int length) +_ector_renderer_cairo_gradient_radial_efl_gfx_gradient_base_stop_set(Eo *obj, + Ector_Renderer_Cairo_Gradient_Radial_Data *pd EINA_UNUSED, + const Efl_Gfx_Gradient_Stop *colors, + unsigned int length) { - USE(obj, cairo_pattern_destroy, ); - - if (pd->pat) cairo_pattern_destroy(pd->pat); - pd->pat = NULL; - eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_RADIAL_CLASS, efl_gfx_gradient_stop_set(colors, length)); } diff --git a/src/lib/ector/cairo/ector_renderer_cairo_shape.c b/src/lib/ector/cairo/ector_renderer_cairo_shape.c index c06802b..ac06da0 100644 --- a/src/lib/ector/cairo/ector_renderer_cairo_shape.c +++ b/src/lib/ector/cairo/ector_renderer_cairo_shape.c @@ -181,7 +181,7 @@ _ector_renderer_cairo_shape_ector_renderer_generic_base_draw(Eo *obj, Ector_Rend cairo_append_path(pd->parent->cairo, pd->path); if (pd->shape->fill) - eo_do(pd->shape->fill, ector_renderer_cairo_base_fill()); + eo_do(pd->shape->fill, ector_renderer_cairo_base_fill(mul_col)); if (pd->shape->stroke.fill || pd->shape->stroke.color.a > 0) { @@ -195,7 +195,7 @@ _ector_renderer_cairo_shape_ector_renderer_generic_base_draw(Eo *obj, Ector_Rend cairo_fill_preserve(pd->parent->cairo); if (pd->shape->stroke.fill) - eo_do(pd->shape->stroke.fill, ector_renderer_cairo_base_fill()); + eo_do(pd->shape->stroke.fill, ector_renderer_cairo_base_fill(mul_col)); else { r = (((pd->shape->stroke.color.r * R_VAL(&mul_col)) + 0xff) >> 8); @@ -236,7 +236,8 @@ _ector_renderer_cairo_shape_ector_renderer_generic_base_draw(Eo *obj, Ector_Rend static Eina_Bool _ector_renderer_cairo_shape_ector_renderer_cairo_base_fill(Eo *obj EINA_UNUSED, - Ector_Renderer_Cairo_Shape_Data *pd EINA_UNUSED) + Ector_Renderer_Cairo_Shape_Data *pd EINA_UNUSED, + unsigned int mul_col EINA_UNUSED) { // FIXME: let's find out how to fill a shape with a shape later. // I need to read SVG specification and see how to map that with cairo. diff --git a/src/lib/ector/software/ector_drawhelper_private.h b/src/lib/ector/software/ector_drawhelper_private.h index 007ef53..e446ed2 100644 --- a/src/lib/ector/software/ector_drawhelper_private.h +++ b/src/lib/ector/software/ector_drawhelper_private.h @@ -75,7 +75,7 @@ _ector_memfill(uint *dest, int length, uint value) } } -static inline uint +static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; --