vg_common: property apply "objectBoundingBox" morphings to radial gradient

When objectBoundingBox flag is set up, all gradients should morphed into
multiple gradients for every entity that has gradient to be applied on
This commit is contained in:
Vitalii Vorobiov 2017-03-16 14:53:49 +02:00 committed by Jean-Philippe Andre
parent 6bf5d9d96e
commit d98e2323ad
3 changed files with 84 additions and 8 deletions

View File

@ -22,6 +22,11 @@ static void (*cairo_arc)(cairo_t *cr,
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;
static void (*cairo_pattern_set_matrix)(cairo_t *cr, cairo_matrix_t *matrix) = NULL;
static void (*cairo_matrix_init)(cairo_matrix_t *matrix,
double xx, double yx,
double xy, double yy,
double x0, double y0) = NULL;
// FIXME: as long as it is not possible to directly access the parent structure
// this will be duplicated from the linear gradient renderer
@ -48,12 +53,14 @@ _ector_renderer_cairo_gradient_radial_ector_renderer_prepare(Eo *obj, Ector_Rend
}
static cairo_pattern_t *
_ector_renderer_cairo_gradient_radial_prepare(Eo *obj EINA_UNUSED,
_ector_renderer_cairo_gradient_radial_prepare(Eo *obj,
Ector_Renderer_Gradient_Radial_Data *grd,
Ector_Renderer_Gradient_Data *gd,
unsigned int mul_col)
{
Ector_Renderer_Data *pd = efl_data_scope_get(obj, ECTOR_RENDERER_CLASS);
cairo_pattern_t *pat;
cairo_matrix_t *pd_m;
pat = cairo_pattern_create_radial(grd->focal.x, grd->focal.y, 0,
grd->radial.x, grd->radial.y, grd->radius);
@ -63,6 +70,16 @@ _ector_renderer_cairo_gradient_radial_prepare(Eo *obj EINA_UNUSED,
cairo_pattern_set_extend(pat, _ector_cairo_extent_get(gd->s));
pd_m = malloc(sizeof (cairo_matrix_t));
if (pd->m)
{
cairo_matrix_init(pd_m,
pd->m->xx, pd->m->yx,
pd->m->xy, pd->m->yy,
pd->m->xz, pd->m->yz);
cairo_pattern_set_matrix(pat, pd_m);
}
return pat;
}
@ -148,9 +165,11 @@ _ector_renderer_cairo_gradient_radial_efl_object_finalize(Eo *obj, Ector_Rendere
USE(base, cairo_pattern_destroy, NULL);
USE(base, cairo_arc, NULL);
USE(base, cairo_fill, NULL);
USE(base, cairo_matrix_init, NULL);
USE(base, cairo_set_source, NULL);
USE(base, cairo_pattern_destroy, NULL);
USE(base, cairo_pattern_set_extend, NULL);
USE(base, cairo_pattern_set_matrix, NULL);
USE(base, cairo_pattern_create_radial, NULL);
USE(base, cairo_pattern_add_color_stop_rgba, NULL);

View File

@ -1790,6 +1790,14 @@ _create_radialGradient(const char *buf, unsigned buflen)
grad->type = SVG_RADIAL_GRADIENT;
grad->user_space = EINA_TRUE;
grad->radial = calloc(1, sizeof(Svg_Radial_Gradient));
/**
* Default values of gradient
*/
grad->radial->cx = 0.5;
grad->radial->cy = 0.5;
grad->radial->fx = 0.5;
grad->radial->fy = 0.5;
grad->radial->r = 0.5;
svg_parse.gradient.fx_parsed = EINA_FALSE;
svg_parse.gradient.fy_parsed = EINA_FALSE;

View File

@ -553,7 +553,10 @@ _apply_gradient_property(Svg_Style_Gradient *g, Efl_VG *vg, Vg_File_Data *vg_dat
Efl_Gfx_Gradient_Stop *stops, *stop;
int stop_count = 0, i = 0;
Eina_List *l;
Eina_Rect r = { 0, 0, 1, 1 };
Eina_Matrix3 m; //for bbox translation
Eina_Rect r = EINA_RECT( 0, 0, 1, 1 );
Eina_Rect grad_geom = EINA_RECT(0, 0, 0, 0);
int radius;
//TODO: apply actual sizes (imporve bounds_get function?)...
//for example with figures and paths
@ -573,16 +576,62 @@ _apply_gradient_property(Svg_Style_Gradient *g, Efl_VG *vg, Vg_File_Data *vg_dat
}
else if (g->type == SVG_RADIAL_GRADIENT)
{
/**
* That is according to Units in here
*
* https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html
*/
int radius = sqrt(pow(r.h, 2) + pow(r.w, 2)) / sqrt(2.0);
radius = sqrt(pow(r.w, 2) + pow(r.h, 2)) / sqrt(2.0);
if (!g->user_space)
{
/**
* That is according to Units in here
*
* https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html
*/
int min = (r.h > r.w) ? r.w : r.h;
radius = sqrt(pow(min, 2) + pow(min, 2)) / sqrt(2.0);
}
grad_obj = evas_vg_gradient_radial_add(NULL);
evas_vg_gradient_radial_center_set(grad_obj, g->radial->cx * r.w + r.x, g->radial->cy * r.h + r.y);
evas_vg_gradient_radial_radius_set(grad_obj, g->radial->r * radius);
evas_vg_gradient_radial_focal_set(grad_obj, g->radial->fx * r.w + r.x, g->radial->fy * r.h + r.y);
/* in case of objectBoundingBox it need proper scaling */
if (!g->user_space)
{
double scale_X = 1.0, scale_reversed_X = 1.0;
double scale_Y = 1.0, scale_reversed_Y = 1.0;
/* check the smallest size, find the scale value */
if (r.h > r.w)
{
scale_Y = ((double) r.w) / r.h;
scale_reversed_Y = ((double) r.h) / r.w;
}
else
{
scale_X = ((double) r.h) / r.w;
scale_reversed_X = ((double) r.w) / r.h;
}
evas_vg_node_bounds_get(grad_obj, &grad_geom);
double cy = grad_geom.h / 2 + grad_geom.y;
double cy_scaled = (grad_geom.h / 2) * scale_reversed_Y;
double cx = grad_geom.w / 2 + grad_geom.x;
double cx_scaled = (grad_geom.w / 2) * scale_reversed_X;
/* matrix tranformation of gradient figure:
* 0. we remember size of gradient and it's center point
* 1. move all gradients to point {0;0}
* (so scale wont increase starting point)
* 2. scale properly only according to the bigger size of entity
* 3. move back so new center point would stay on position
* it had previously
*/
eina_matrix3_identity(&m);
eina_matrix3_translate(&m, grad_geom.x, grad_geom.y);
eina_matrix3_scale(&m, scale_X, scale_Y);
eina_matrix3_translate(&m, cx_scaled - cx, cy_scaled - cy);
efl_vg_transformation_set(grad_obj, &m);
}
}
else
{