ector: fix cairo backend to properly multiply gradient color.

@fix
This commit is contained in:
Cedric BAIL 2015-09-15 07:36:00 +02:00
parent e7b2cf56cf
commit 4d75e359ff
7 changed files with 146 additions and 109 deletions

View File

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

View File

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

View File

@ -4,6 +4,9 @@ abstract Ector.Renderer.Cairo.Base (Ector.Renderer.Generic.Base)
methods {
fill {
return: bool;
params {
@in mul_col: uint;
}
}
}
implements {

View File

@ -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,44 +24,35 @@ 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 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)
{
cairo_pattern_t *pat;
USE(obj, cairo_pattern_create_linear, EINA_FALSE);
pat = cairo_pattern_create_linear(gld->start.x, gld->start.y,
gld->end.x, gld->end.y);
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;
}
static Eina_Bool
_ector_renderer_cairo_gradient_linear_ector_renderer_generic_base_prepare(Eo *obj,
Ector_Renderer_Cairo_Gradient_Linear_Data *pd)
{
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;
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,
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);
}
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,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));
}

View File

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

View File

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

View File

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