efl_unref(child);
}
+#ifndef HAVE_THORVG
static void
_draw_comp(Evas_Object_Protected_Data *obj, Efl_VG *node,
Ector_Surface *ector, void *engine, void *output,
ENFN->ector_renderer_draw(engine, output, context, nd->renderer, NULL, EINA_FALSE);
}
}
+#endif
static Ector_Buffer *
_prepare_comp(Evas_Object_Protected_Data *obj, //vector object
Ector_Buffer *comp,
Efl_Gfx_Vg_Composite_Method comp_method)
{
+
Efl_Canvas_Vg_Container_Data *pd = efl_data_scope_get(comp_target, MY_CLASS);
Efl_Canvas_Vg_Node_Data *nd =
efl_data_scope_get(comp_target, EFL_CANVAS_VG_NODE_CLASS);
ector_buffer_pixels_set(surface, pd->comp.pixels, size.w, size.h, pd->comp.stride,
EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
ector_surface_reference_point_set(surface, 0, 0);
+#ifndef HAVE_THORVG
_draw_comp(obj, comp_target, surface, engine, output, context);
+#endif
return pd->comp.buffer;
}
//Container may have composite target.
//FIXME : _prepare_comp() should only work in cases with matte or masking.
// This condition is valid because the masking use same type as matte.
+#ifndef HAVE_THORVG
if (pd->comp_target &&
(pd->comp.method == EFL_GFX_VG_COMPOSITE_METHOD_MATTE_ALPHA ||
pd->comp.method == EFL_GFX_VG_COMPOSITE_METHOD_MATTE_ALPHA_INVERSE))
engine, output, context, surface,
ptransform, ctransform, p_opacity, c_a, comp, comp_method);
}
+#endif
//If the container has transparency, it internally alpha blends with ector buffer.
//So ector buffer must be created synchronously.
static Eo *
_efl_canvas_vg_container_efl_object_constructor(Eo *obj,
- Efl_Canvas_Vg_Container_Data *pd)
+ Efl_Canvas_Vg_Container_Data *pd)
{
Efl_Canvas_Vg_Node_Data *nd;
pd->names = eina_hash_stringshared_new(NULL);
-
obj = efl_constructor(efl_super(obj, MY_CLASS));
nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+
nd->render_pre = _efl_canvas_vg_container_render_pre;
+
nd->data = pd;
nd->flags = EFL_GFX_CHANGE_FLAG_ALL;
efl_gfx_color_set(obj, 255, 255, 255, 255);
-
return obj;
}
{
efl_canvas_vg_container_blend_buffer_clear(obj, pd);
+#ifdef HAVE_THORVG
//Destroy comp surface
if (pd->comp.buffer)
{
ector_buffer_unmap(pd->comp.buffer, pd->comp.pixels, pd->comp.length);
efl_unref(pd->comp.buffer);
}
+#endif
efl_unref(pd->comp_target);
eina_list_free(pd->comp.src);
void
efl_canvas_vg_container_blend_buffer_clear(Efl_VG *obj EINA_UNUSED, Efl_Canvas_Vg_Container_Data *cd)
{
+#ifndef HAVE_THORV
if (!cd->blend.buffer) return;
if (cd->blend.pixels)
}
if (cd->blend.buffer) efl_unref(cd->blend.buffer);
cd->blend.buffer = NULL;
+#endif
}
EAPI Evas_Vg_Container *
#define MY_CLASS EFL_CANVAS_VG_GRADIENT_CLASS
+#ifdef HAVE_THORVG
+
+static void
+_gradient_stop_set(Evas_Vg_Gradient *obj, const Efl_Gfx_Gradient_Stop *colors, unsigned int length)
+{
+ Tvg_Color_Stop *color_stops = NULL;
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+
+ unsigned int i = 0;
+
+ if (!obj) return;
+
+ gd = efl_data_scope_get(obj, MY_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ color_stops = malloc(sizeof(Tvg_Color_Stop) * length);
+ if (color_stops == NULL) return;
+
+ for (i = 0; i < length; ++i)
+ {
+ color_stops[i].offset = colors[i].offset;
+ color_stops[i].r = colors[i].r;
+ color_stops[i].g = colors[i].g;
+ color_stops[i].b = colors[i].b;
+ color_stops[i].a = colors[i].a;
+ }
+
+ tvg_gradient_set_color_stops(gd->gradient, color_stops, length);
+ free(color_stops);
+}
+
+static void
+_gradient_stop_get(Evas_Vg_Gradient *obj, Efl_Gfx_Gradient_Stop **colors, unsigned int *length)
+{
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ gd = efl_data_scope_get(obj, MY_CLASS);
+ const Tvg_Color_Stop *stop = NULL;
+ uint32_t len = 0;
+ unsigned int i = 0;
+
+ if (!obj || !colors || !length) return;
+
+ gd = efl_data_scope_get(obj, MY_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ tvg_gradient_get_color_stops(gd->gradient, &stop, &len);
+
+ *colors = malloc(sizeof(Efl_Gfx_Gradient_Stop) * len);
+ for (i = 0; i < len; ++i)
+ {
+ (*colors)[i].offset = stop[i].offset;
+ (*colors)[i].a = stop[i].a;
+ (*colors)[i].r = stop[i].r;
+ (*colors)[i].g = stop[i].g;
+ (*colors)[i].b = stop[i].b;
+ }
+}
+#endif
+
static void
_efl_canvas_vg_gradient_efl_gfx_gradient_stop_set(Eo *obj EINA_UNUSED,
Efl_Canvas_Vg_Gradient_Data *pd,
static void
_efl_canvas_vg_gradient_efl_object_destructor(Eo *obj, Efl_Canvas_Vg_Gradient_Data *pd)
{
- if (pd->colors)
- {
- free(pd->colors);
- pd->colors = NULL;
- }
- pd->colors_count = 0;
-
+#ifdef HAVE_THORVG
+#endif
+ if (pd->colors) free(pd->colors);
efl_destructor(efl_super(obj, MY_CLASS));
}
EAPI void
evas_vg_gradient_stop_set(Evas_Vg_Gradient *obj, const Evas_Vg_Gradient_Stop *colors, unsigned int length)
{
+#ifdef HAVE_THORVG
+ _gradient_stop_set(obj, (const Efl_Gfx_Gradient_Stop *)colors, length);
+#else
efl_gfx_gradient_stop_set(obj, (const Efl_Gfx_Gradient_Stop *)colors, length);
+#endif
}
EAPI void
evas_vg_gradient_stop_get(Evas_Vg_Gradient *obj, const Evas_Vg_Gradient_Stop **colors, unsigned int *length)
{
+#ifdef HAVE_THORVG
+ _gradient_stop_get(obj, (Efl_Gfx_Gradient_Stop **)colors, length);
+#else
efl_gfx_gradient_stop_get(obj, (const Efl_Gfx_Gradient_Stop **)colors, length);
+#endif
}
EAPI void
evas_vg_gradient_spread_set(Evas_Vg_Gradient *obj, Evas_Vg_Gradient_Spread s)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ if (!obj) return;
+ gd = efl_data_scope_get(obj, MY_CLASS);
+ tvg_gradient_set_spread(gd->gradient, (Tvg_Stroke_Fill)s);
+#else
efl_gfx_gradient_spread_set(obj, (Efl_Gfx_Gradient_Spread)s);
+#endif
}
EAPI Evas_Vg_Gradient_Spread
evas_vg_gradient_spread_get(Evas_Vg_Gradient *obj)
{
+#ifdef HAVE_THORVG
+ Tvg_Stroke_Fill fill = TVG_STROKE_FILL_PAD;
+ Efl_Canvas_Vg_Gradient_Data *gd;
+
+ if (!obj) return EVAS_VG_GRADIENT_SPREAD_LAST;
+ gd = efl_data_scope_get(obj, MY_CLASS);
+ if (!gd || !gd->gradient) return EVAS_VG_GRADIENT_SPREAD_LAST;
+
+ tvg_gradient_get_spread(gd->gradient, &fill);
+ return (Evas_Vg_Gradient_Spread)fill;
+#else
return (Evas_Vg_Gradient_Spread)efl_gfx_gradient_spread_get(obj);
+#endif
}
#include "efl_canvas_vg_gradient.eo.c"
if (y) *y = pd->end.y;
}
+#ifndef HAVE_THORVG
static void
_efl_canvas_vg_gradient_linear_render_pre(Evas_Object_Protected_Data *vg_pd EINA_UNUSED,
Efl_VG *obj,
ector_renderer_prepare(nd->renderer);
ector_renderer_comp_method_set(nd->renderer, comp, comp_method);
}
+#else
+static void
+_gradient_linear_render_pre_tvg(Efl_Canvas_Vg_Node *nd EINA_UNUSED,
+ Efl_Canvas_Vg_Gradient_Data *gd,
+ Tvg_Paint *shape)
+{
+ if (!gd || !shape) return;
+ tvg_shape_set_linear_gradient(shape, gd->gradient);
+}
+#endif
static Eo *
_efl_canvas_vg_gradient_linear_efl_object_constructor(Eo *obj,
Efl_Canvas_Vg_Gradient_Linear_Data *pd)
{
Efl_Canvas_Vg_Node_Data *nd;
-
+ Efl_Canvas_Vg_Gradient_Data *gd;
obj = efl_constructor(efl_super(obj, MY_CLASS));
-
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+#ifndef HAVE_THORVG
nd->render_pre = _efl_canvas_vg_gradient_linear_render_pre;
+#else
+ gd->gradient_render_pre_tvg = _gradient_linear_render_pre_tvg;
+ gd->shape = NULL;
+ gd->spread = EFL_GFX_GRADIENT_SPREAD_PAD;
+ //removed by tvg_canvas_destroy()
+ gd->gradient = tvg_linear_gradient_new();
+#endif
nd->data = pd;
return obj;
EAPI void
evas_vg_gradient_linear_start_set(Evas_Vg_Gradient_Linear *obj, double x, double y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ float x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0;
+
+ if (!obj) return;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ tvg_linear_gradient_get(gd->gradient, &x1, &y1, &x2, &y2);
+ tvg_linear_gradient_set(gd->gradient, x, y, x2, y2);
+#else
efl_gfx_gradient_linear_start_set(obj, x, y);
+#endif
}
EAPI void
evas_vg_gradient_linear_start_get(Evas_Vg_Gradient_Linear *obj, double *x, double *y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ float x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0;
+
+ if (!obj) return;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ tvg_linear_gradient_get(gd->gradient, &x1, &y1, &x2, &y2);
+ if (x) *x = x1;
+ if (y) *y = y1;
+
+#else
efl_gfx_gradient_linear_start_get(obj, x, y);
+#endif
}
EAPI void
evas_vg_gradient_linear_end_set(Evas_Vg_Gradient_Linear *obj, double x, double y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ float x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0;
+
+ if (!obj) return;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ tvg_linear_gradient_get(gd->gradient, &x1, &y1, &x2, &y2);
+ tvg_linear_gradient_set(gd->gradient, x1, y1, x, y);
+#else
efl_gfx_gradient_linear_end_set(obj, x, y);
+#endif
}
EAPI void
evas_vg_gradient_linear_end_get(Evas_Vg_Gradient_Linear *obj, double *x, double *y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ float x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0;
+
+ if (!obj) return;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ tvg_linear_gradient_get(gd->gradient, &x1, &y1, &x2, &y2);
+ if (x) *x = x1;
+ if (y) *y = y1;
+#else
efl_gfx_gradient_linear_end_get(obj, x, y);
+#endif
}
EAPI Evas_Vg_Gradient_Linear *
double radius;
};
+
static void
_efl_canvas_vg_gradient_radial_efl_gfx_gradient_radial_center_set(Eo *obj EINA_UNUSED,
Efl_Canvas_Vg_Gradient_Radial_Data *pd,
if (y) *y = pd->focal.y;
}
+#ifndef HAVE_THORVG
static void
_efl_canvas_vg_gradient_radial_render_pre(Evas_Object_Protected_Data *vg_pd EINA_UNUSED,
Efl_VG *obj,
ector_renderer_prepare(nd->renderer);
ector_renderer_comp_method_set(nd->renderer, comp, comp_method);
}
+#else
+static void
+_gradient_radial_render_pre_tvg(Efl_Canvas_Vg_Node *nd EINA_UNUSED,
+ Efl_Canvas_Vg_Gradient_Data *gd,
+ Tvg_Paint *shape)
+{
+ if (!gd || !gd->gradient || !shape) return;
+ tvg_shape_set_radial_gradient(shape, gd->gradient);
+}
+#endif
static Eo *
_efl_canvas_vg_gradient_radial_efl_object_constructor(Eo *obj, Efl_Canvas_Vg_Gradient_Radial_Data *pd)
{
Efl_Canvas_Vg_Node_Data *nd;
-
obj = efl_constructor(efl_super(obj, MY_CLASS));
-
nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+#ifndef HAVE_THORVG
nd->render_pre = _efl_canvas_vg_gradient_radial_render_pre;
+#else
+ Efl_Canvas_Vg_Gradient_Data *gd;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ gd->gradient_render_pre_tvg = _gradient_radial_render_pre_tvg;
+ gd->shape = NULL;
+ gd->spread = EFL_GFX_GRADIENT_SPREAD_PAD;
+ gd->gradient = tvg_radial_gradient_new();
+#endif
nd->data = pd;
return obj;
EAPI void
evas_vg_gradient_radial_center_set(Evas_Vg_Gradient_Radial *obj, double x, double y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ float r = 0.0f;
+
+ if (!obj) return;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ tvg_radial_gradient_get(gd->gradient, NULL, NULL, &r);
+ tvg_radial_gradient_set(gd->gradient, x, y, r);
+#else
efl_gfx_gradient_radial_center_set(obj, x, y);
+#endif
}
EAPI void
evas_vg_gradient_radial_center_get(Evas_Vg_Gradient_Radial *obj, double *x, double *y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+
+ if (!obj) return;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ tvg_radial_gradient_get(gd->gradient, (float*)x, (float*)y, NULL);
+#else
efl_gfx_gradient_radial_center_get(obj, x, y);
+#endif
}
EAPI void
evas_vg_gradient_radial_radius_set(Evas_Vg_Gradient_Radial *obj, double r)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ float x = 0.0f, y = 0.0f;
+
+ if (!obj) return;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ if (!gd || !gd->gradient) return;
+
+ tvg_radial_gradient_get(gd->gradient, &x, &y, NULL);
+ tvg_radial_gradient_set(gd->gradient, x, y, r);
+#else
efl_gfx_gradient_radial_radius_set(obj, r);
+#endif
}
EAPI double
evas_vg_gradient_radial_radius_get(Evas_Vg_Gradient_Radial *obj)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+ float r = 0.0f;
+ if (!obj) return 0.0;
+ gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
+ if (!gd || !gd->gradient) return 0.0;
+ tvg_radial_gradient_get(gd->gradient, NULL, NULL, &r);
+ return r;
+#else
return efl_gfx_gradient_radial_radius_get(obj);
+#endif
}
EAPI void
typedef struct _Efl_Canvas_Vg_Image_Data Efl_Canvas_Vg_Image_Data;
struct _Efl_Canvas_Vg_Image_Data
{
+#ifndef HAVE_THORVG
Ector_Buffer *buffer;
void *image;
+#endif
int w;
int h;
};
nd->flags = EFL_GFX_CHANGE_FLAG_NONE;
+#ifndef HAVE_THORVG
EFL_CANVAS_VG_COMPUTE_MATRIX(ctransform, ptransform, nd);
EFL_CANVAS_VG_COMPUTE_ALPHA(c_r, c_g, c_b, c_a, p_opacity, nd);
ector_renderer_visibility_set(nd->renderer, nd->visibility);
ector_renderer_comp_method_set(nd->renderer, comp, comp_method);
ector_renderer_prepare(nd->renderer);
+#else
+ //TODO: implement using thorvg
+#endif
}
static Eo *
_efl_canvas_vg_image_efl_object_constructor(Eo *obj, Efl_Canvas_Vg_Image_Data *pd)
{
Efl_Canvas_Vg_Node_Data *nd;
-
obj = efl_constructor(efl_super(obj, MY_CLASS));
nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
nd->render_pre = _efl_canvas_vg_image_render_pre;
nd->data = pd;
+#ifndef HAVE_THORVG
efl_gfx_color_set(obj , 255, 255, 255, 255);
+#else
+ //TODO: implement using thorvg
+#endif
return obj;
}
_efl_canvas_vg_image_efl_object_destructor(Eo *obj, Efl_Canvas_Vg_Image_Data *pd EINA_UNUSED)
{
efl_destructor(efl_super(obj, MY_CLASS));
+
+#ifndef HAVE_THORVG
if (pd->buffer)
{
efl_unref(pd->buffer);
pd->buffer = NULL;
}
+#endif
}
static void
if (!data || size.w <= 0 || size.h <= 0)
return;
+#ifndef HAVE_THORVG
if ((pd->image != data || pd->w != size.w || pd->h != size.h) && pd->buffer)
{
efl_unref(pd->buffer);
}
pd->image = data;
+#endif
+
pd->w = size.w;
pd->h = size.h;
}
Eina_Bool v)
{
pd->visibility = v;
-
_node_change(obj, pd);
}
}
static void
+#ifdef HAVE_THORVG
+_efl_canvas_vg_node_efl_object_invalidate(Eo *obj, Efl_Canvas_Vg_Node_Data *pd EINA_UNUSED)
+#else
_efl_canvas_vg_node_efl_object_invalidate(Eo *obj, Efl_Canvas_Vg_Node_Data *pd)
+#endif
{
+#ifndef HAVE_THORVG
if (pd->renderer)
{
efl_unref(pd->renderer);
pd->renderer = NULL;
}
+#endif
efl_invalidate(efl_super(obj, MY_CLASS));
}
if (eina_list_data_get(eina_list_last(cd->children)) == obj) return;
cd->children = eina_list_remove(cd->children, obj);
cd->children = eina_list_append(cd->children, obj);
+
_node_change(parent, efl_data_scope_get(parent, MY_CLASS));
}
if (eina_list_data_get(cd->children) == obj) return;
cd->children = eina_list_remove(cd->children, obj);
cd->children = eina_list_prepend(cd->children, obj);
+
_node_change(parent, efl_data_scope_get(parent, MY_CLASS));
}
tod = efl_data_scope_get(to, MY_CLASS);
from_map = 1.0 - pos_map;
+#ifndef HAVE_THORVG
efl_unref(pd->renderer);
pd->renderer = NULL;
+#endif
//Interpolates Node Transform Matrix
if (fromd->m || tod->m)
// detach/free the old root_node
if (pd->user_entry && pd->user_entry->root)
{
+#ifndef HAVE_THORVG
// drop any surface cache attached to it.
ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->user_entry->root);
+#endif
efl_canvas_vg_node_vg_obj_set(pd->user_entry->root, NULL, NULL);
efl_replace(&pd->user_entry->root, NULL);
}
if (pd->user_entry)
{
- Vg_User_Entry *user_entry = pd->user_entry;
- ENFN->ector_surface_cache_drop(ENC, user_entry->root);
+#ifndef HAVE_THORVG
+ ENFN->ector_surface_cache_drop(ENC, pd->user_entry->root);
+#endif
if (pd->user_entry->root) efl_unref(pd->user_entry->root);
free(pd->user_entry);
}
//Drop cache buffers
if (pd->vg_entry)
{
+#ifndef HAVE_THORVG
if (pd->ckeys[0])
ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->ckeys[0]);
if (pd->ckeys[1])
ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->ckeys[1]);
+#endif
}
evas_cache_vg_entry_del(pd->vg_entry);
+#ifdef HAVE_THORVG
+ if (pd->im)
+ {
+ ENFN->image_free(_evas_engine_context(obj->layer->evas), pd->im);
+ pd->im = NULL;
+ }
+
+ if (pd->tvg_buffer)
+ {
+ free(pd->tvg_buffer);
+ pd->tvg_buffer = NULL;
+ }
+
+ if (pd->tvg_canvas)
+ {
+ tvg_canvas_destroy(pd->tvg_canvas);
+ pd->tvg_canvas = NULL;
+ }
+#endif
efl_invalidate(efl_super(eo_obj, MY_CLASS));
}
/* default root node */
pd->obj = obj;
pd->root = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
-
pd->sync_render = EINA_FALSE;
eina_array_step_set(&pd->cleanup, sizeof(pd->cleanup), 8);
-
return eo_obj;
}
return obj;
}
+#ifdef HAVE_THORVG
+static void
+_evas_vg_render_tvg(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
+ void *engine, void *output, void *context, Efl_VG *node,
+ Eina_Array *clips, int w, int h, void *canvas, Eina_Bool do_async)
+{
+ Efl_Canvas_Vg_Node_Data *nd = efl_data_scope_get(node, EFL_CANVAS_VG_NODE_CLASS);
+
+ if (efl_isa(node, EFL_CANVAS_VG_CONTAINER_CLASS)) {
+ Efl_VG *child = NULL;
+ Eina_List *l = NULL;
+
+ Efl_Canvas_Vg_Container_Data *cd = efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS);
+
+ // Draw child node to changed buffer
+ EINA_LIST_FOREACH(cd->children, l, child)
+ _evas_vg_render_tvg(obj, pd, engine, output, context, child, clips, w, h, canvas, do_async);
+
+ } else {
+ if (!efl_isa(node, EFL_CANVAS_VG_GRADIENT_CLASS))
+ nd->render_pre_tvg(obj, node, nd, canvas);
+ }
+}
+
+static void
+_render_to_buffer_tvg(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
+ void *engine, Efl_VG *root, int w, int h, Eina_Bool do_async)
+{
+ _evas_vg_render_tvg(obj, pd, engine, NULL, NULL, root, NULL, w, h, pd->tvg_canvas, do_async);
+
+ if (tvg_canvas_draw(pd->tvg_canvas) == TVG_RESULT_SUCCESS)
+ {
+ tvg_canvas_sync(pd->tvg_canvas);
+ }
+}
+
+static void
+_render_tvg_buffer_to_screen(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
+ void *engine, void *output, void *context, void *surface,
+ void *buffer, int x, int y, int w, int h, Eina_Bool do_async)
+{
+ if (!obj || !pd || !buffer) return;
+
+ if (!pd->im)
+ {
+ pd->im = ENFN->image_new_from_data(engine, w, h, buffer, 255,
+ EVAS_COLORSPACE_ARGB8888);
+ }
+ else
+ {
+ pd->im = ENFN->image_data_put(engine, pd->im, buffer);
+ }
+
+ ENFN->image_dirty_region(engine, pd->im, 0, 0, w, h);
+ ENFN->image_draw(engine, output, context, surface,
+ pd->im, 0, 0, w, h, x, y, w, h,
+ EINA_TRUE, do_async);
+}
+
+#else
+
static void
_evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
void *engine, void *output, void *context, Efl_VG *node,
do_async, EINA_TRUE);
}
+#endif
+
static void
_efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
{
Efl_Canvas_Vg_Object_Data *pd = type_private_data;
- /* render object to surface with context, and offxet by x,y */
ENFN->context_color_set(engine, context, 255, 255, 255, 255);
ENFN->context_multiplier_set(engine, context,
obj->cur->cache.clip.r,
ENFN->context_anti_alias_set(engine, context, obj->cur->anti_alias);
ENFN->context_render_op_set(engine, context, obj->cur->render_op);
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Eina_Size2D size;
+ Eina_Rect render_rect;
+
+ int w = 0, h = 0;
+
+ if (!pd || !pd->root || !pd->user_entry) return;
+ if (!obj || !obj->cur) return;
+
+ nd = efl_data_scope_get(pd->root, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return;
+
+ size.w = obj->cur->geometry.w;
+ size.h = obj->cur->geometry.h;
+
+ if (size.w == 0 || size.h == 0) return;
+
+ if (pd->tvg_canvas_size.w != size.w || pd->tvg_canvas_size.h != size.h)
+ {
+ pd->tvg_buffer = realloc(pd->tvg_buffer, size.w * size.h * sizeof(uint32_t));
+ pd->tvg_canvas_size.w = size.w;
+ pd->tvg_canvas_size.h = size.h;
+
+ if (!pd->tvg_canvas) pd->tvg_canvas = tvg_swcanvas_create();
+
+ tvg_swcanvas_set_target(pd->tvg_canvas, pd->tvg_buffer,
+ size.w, size.w, size.h,
+ TVG_COLORSPACE_ARGB8888);
+
+ //if size is changed im handle also should be deleted
+ if (pd->im)
+ {
+ ENFN->image_free(engine, pd->im);
+ pd->im = NULL;
+ }
+ }
+
+ _render_to_buffer_tvg(obj, pd, NULL,
+ pd->user_entry->root,
+ obj->cur->geometry.w,
+ obj->cur->geometry.h,
+ do_async);
+
+ render_rect = EINA_RECT(x, y, size.w, size.h);
+
+ if (nd && nd->render_tvg)
+ nd->render_tvg(obj, pd->root, nd, pd->tvg_canvas);
+
+ if (pd->viewbox.w != 0 && pd->viewbox.h !=0)
+ {
+ double sx = 0, sy= 0;
+ sx = (double)w / (double)pd->viewbox.w;
+ sy = (double)h / (double)pd->viewbox.h;
+ render_rect.x = (render_rect.x - pd->viewbox.x) * sx;
+ render_rect.y = (render_rect.y - pd->viewbox.y) * sy;
+ render_rect.w *= sx;
+ render_rect.h *= sy;
+ }
+
+ _render_tvg_buffer_to_screen(obj, pd, engine, output, context, surface,
+ pd->tvg_buffer, x + render_rect.x,
+ y + render_rect.y,
+ render_rect.w, render_rect.h,
+ do_async);
+#else
//Cache surface?
Eina_Bool cacheable = EINA_FALSE;
obj->cur->geometry.x + x, obj->cur->geometry.y + y,
obj->cur->geometry.w, obj->cur->geometry.h, do_async);
}
+#endif
+
pd->changed = EINA_FALSE;
}
if (obj->cur->clipper)
{
if (obj->cur->cache.clip.dirty)
- evas_object_clip_recalc(obj->cur->clipper);
+ evas_object_clip_recalc(obj->cur->clipper);
+
obj->cur->clipper->func->render_pre(obj->cur->clipper->object,
obj->cur->clipper,
obj->cur->clipper->private_data);
}
+
/* now figure what changed and add draw rects */
/* if it just became visible or invisible */
is_v = evas_object_is_visible(obj);
y + obj->layer->evas->framespace.y,
w, h);
}
-
done:
evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, eo_obj, is_v, was_v);
}
return EINA_TRUE;
}
-//TIZEN_ONLY(200717):Efl.Gfx.Frame_Contoller: Add sector_list property
+//TIZEN_ONLY(200717):Efl.Gfx.Frame.Contoller: Add sector_list property
EOLIAN static Eina_Iterator *
_efl_canvas_vg_object_efl_gfx_frame_controller_sector_list_get(const Eo *obj EINA_UNUSED,
Efl_Canvas_Vg_Object_Data *pd)
#define MY_CLASS EFL_CANVAS_VG_SHAPE_CLASS
+#ifdef HAVE_THORVG
+#include "evas_tvg_path_helpers.h"
+#endif
+
+#ifdef HAVE_THORVG
+
+#define SVG_PATH_NUM_LEN 7
+#define DASH_PATTERN_EL_SIZE 2
+#define PTS_COUNT_LINE_MOVE 2
+#define PTS_COUNT_CUBIC 4
+
+typedef enum
+{
+ EFL_TVG_PATH_CMD_TYPE_NO_BEZIER = 0, /**< For svg path commands other than listed below */
+ EFL_TVG_PATH_CMD_TYPE_BEZIER_CUBIC, /**< For svg path commands S/s/C/c */
+ EFL_TVG_PATH_CMD_TYPE_BEZIER_QUADRATIC /**< For svg path commands T/t/Q/q */
+} Efl_Tvg_Path_Cmd_Type;
+
+typedef struct _Tvg_Color Tvg_Color;
+struct _Tvg_Color
+{
+ uint8_t r, g, b, a;
+};
+
+#endif
+
typedef struct _Efl_Canvas_Vg_Shape_Data Efl_Canvas_Vg_Shape_Data;
+
struct _Efl_Canvas_Vg_Shape_Data
{
Efl_Canvas_Vg_Node *fill;
Efl_Canvas_Vg_Node *fill;
Efl_Canvas_Vg_Node *marker;
} stroke;
+
+#ifdef HAVE_THORVG
+ Tvg_Paint *shape;
+
+ //Variables need by cubic, squbic and arc_to. Used to recreate properly svg_path
+ Tvg_Point curr_ctrl;
+ Tvg_Point curr;
+ Tvg_Point start;
+ Efl_Tvg_Path_Cmd_Type cmd_prev;
+
+ //Stroke scale is not supported by TVG. Scale variable is used to implement stroke
+ //scaling using scale * width
+ double scale;
+
+ //thorvg don't supported visibility, implementation is based on alpha change for stroke
+ //and fill, but color have to be saved here to recreate it when visibility will be changed back
+ Tvg_Color stroke_color;
+ Tvg_Color fill_color;
+
+ //Flag indicates if shape was pushed to canvas. Shape has access to canvas only in
+ //render function which may be called multiple times, and shape should be pushed
+ //only once.
+ Eina_Bool pushed;
+
+ //Flag indicates if shape was started. It is used to store start position
+ //and keep shape current point valid when shape close API is called.
+ Eina_Bool started;
+
+ //Used to compare it with node data. Don't call visibility change if it has the same value
+ Eina_Bool visibility;
+
+#endif
};
+#ifdef HAVE_THORVG
+
+static inline double
+_interpolate(double from, double to, double pos_map)
+{
+ return (from * (1.0 - pos_map)) + (to * pos_map);
+}
+
+static Tvg_Paint*
+_get_tvg_shape(Evas_Vg_Shape *obj)
+{
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return NULL;
+
+ sd = nd->data;
+ if (!sd) return NULL;
+
+ return sd->shape;
+}
+
+static Efl_Canvas_Vg_Shape_Data*
+_get_shape_data(Evas_Vg_Shape *obj)
+{
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return NULL;
+
+ return nd->data;
+}
+
+static void
+_assign_current_point(Efl_Canvas_Vg_Shape_Data *sd, void *cmd EINA_UNUSED, double x, double y)
+{
+ if (!sd) return;
+ /* Assign current point of shape's svg path. If it's first append command
+ function additionally assign passed x,y as start point of shape's path */
+ sd->curr.x = x;
+ sd->curr.y = y;
+
+ if (sd->started == EINA_FALSE)
+ {
+ sd->start.x = x;
+ sd->start.y = y;
+ }
+}
+
+static void
+_assign_current_ctrl_point(Efl_Canvas_Vg_Shape_Data *sd, double x, double y)
+{
+ if (!sd) return;
+ sd->curr_ctrl.x = x;
+ sd->curr_ctrl.y = y;
+}
+
+static void
+_assign_command(Efl_Canvas_Vg_Shape_Data *sd, Efl_Tvg_Path_Cmd_Type c_prev)
+{
+ if (!sd) return;
+ sd->cmd_prev = c_prev;
+}
+
+
+static void
+_append_scubic_to(Evas_Vg_Shape *obj, double x, double y,
+ double ctrl_x1, double ctrl_y1)
+{
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+ double ctrl_x0, ctrl_y0;
+
+ if (!obj) return;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return;
+ sd = nd->data;
+ if (!sd) return;
+
+ if (sd->cmd_prev == EFL_TVG_PATH_CMD_TYPE_BEZIER_CUBIC)
+ {
+ ctrl_x0 = 2 * sd->curr.x - sd->curr_ctrl.x;
+ ctrl_y0 = 2 * sd->curr.y - sd->curr_ctrl.y;
+ }
+ else
+ {
+ ctrl_x0 = sd->curr.x;
+ ctrl_y0 = sd->curr.y;
+ }
+
+ evas_vg_shape_append_cubic_to(obj, x, y, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1);
+}
+
+static void
+_append_quadratic(Evas_Vg_Shape *obj, double x, double y, double ctrl_x, double ctrl_y)
+{
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+ double ctrl_x0, ctrl_y0;
+ double ctrl_x1, ctrl_y1;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return;
+ sd = nd->data;
+ if (!sd) return;
+
+ // Convert quadratic bezier to cubic
+ ctrl_x0 = (sd->curr.x + 2 * ctrl_x) * (1.0 / 3.0);
+ ctrl_y0 = (sd->curr.y + 2 * ctrl_y) * (1.0 / 3.0);
+ ctrl_x1 = (x + 2 * ctrl_x) * (1.0 / 3.0);
+ ctrl_y1 = (y + 2 * ctrl_y) * (1.0 / 3.0);
+
+ evas_vg_shape_append_cubic_to(obj, x, y, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1);
+ _assign_current_ctrl_point(sd, ctrl_x, ctrl_y);
+ _assign_command(sd, EFL_TVG_PATH_CMD_TYPE_BEZIER_QUADRATIC);
+}
+
+static void
+_append_squadratic(Evas_Vg_Shape *obj, double x, double y)
+{
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ double ctrl_x, ctrl_y;
+ double ctrl_x0, ctrl_y0;
+ double ctrl_x1, ctrl_y1;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return;
+ sd = nd->data;
+ if (!sd) return;
+
+ if (sd->cmd_prev == EFL_TVG_PATH_CMD_TYPE_BEZIER_QUADRATIC)
+ {
+ ctrl_x = 2 * sd->curr.x - sd->curr_ctrl.x;
+ ctrl_y = 2 * sd->curr.y - sd->curr_ctrl.y;
+ }
+ else
+ {
+ ctrl_x = sd->curr.x;
+ ctrl_y = sd->curr.y;
+ }
+
+ // Convert quadratic bezier to cubic
+ ctrl_x0 = (sd->curr.x + 2 * ctrl_x) * (1.0 / 3.0);
+ ctrl_y0 = (sd->curr.y + 2 * ctrl_y) * (1.0 / 3.0);
+ ctrl_x1 = (x + 2 * ctrl_x) * (1.0 / 3.0);
+ ctrl_y1 = (y + 2 * ctrl_y) * (1.0 / 3.0);
+
+ evas_vg_shape_append_cubic_to(obj, x, y, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1);
+ _assign_current_ctrl_point(sd, ctrl_x, ctrl_y);
+ _assign_command(sd, EFL_TVG_PATH_CMD_TYPE_BEZIER_QUADRATIC);
+}
+
+// code based on enesim/moonlight sources
+static void
+_append_arc_to(Evas_Vg_Shape *obj, double x, double y,
+ double rx, double ry, double angle,
+ Eina_Bool large_arc, Eina_Bool sweep)
+{
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ Arc_To_Init_Variables var;
+ double sx, sy, ex, ey;
+ double c1x, c1y, c2x, c2y;
+ double theta2;
+ double cos_theta2, sin_theta2;
+ int i;
+
+ if (!obj) return;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return;
+ sd = nd->data;
+ if (!sd) return;
+
+ sx = ex = sd->curr.x;
+ sy = ey = sd->curr.y;
+
+ // if start and end points are identical, then no arc is drawn
+ if ((fabs(x - sx) < (1 / 256.0)) && (fabs(y - sy) < (1 / 256.0)))
+ return;
+ rx = fabs(rx);
+ ry = fabs(ry);
+ if ((rx < 0.5) || (ry < 0.5))
+ {
+ evas_vg_shape_append_line_to(obj, x, y);
+ return;
+ }
+
+ _arc_to_variables_initialization(x, y, rx, ry, angle, large_arc, sweep,
+ sx, sy, &var);
+
+ for (i = 0; i < var.segments; ++i)
+ {
+ // end angle (for this segment) = current + delta
+ theta2 = var.theta1 + var.delta;
+ cos_theta2 = cos(theta2);
+ sin_theta2 = sin(theta2);
+
+ // first control point (based on start point sx,sy)
+ c1x = sx - var.bcp * (var.cos_phi_rx * var.sin_theta1 +
+ var.sin_phi_ry * var.cos_theta1);
+ c1y = sy + var.bcp * (var.cos_phi_ry * var.cos_theta1 -
+ var.sin_phi_rx * var.sin_theta1);
+
+ // end point (for this segment)
+ ex = var.cx + (var.cos_phi_rx * cos_theta2 -
+ var.sin_phi_ry * sin_theta2);
+ ey = var.cy + (var.sin_phi_rx * cos_theta2 +
+ var.cos_phi_ry * sin_theta2);
+
+ // second control point (based on end point ex,ey)
+ c2x = ex + var.bcp * (var.cos_phi_rx * sin_theta2 +
+ var.sin_phi_ry * cos_theta2);
+ c2y = ey + var.bcp * (var.sin_phi_rx * sin_theta2 -
+ var.cos_phi_ry * cos_theta2);
+
+ evas_vg_shape_append_cubic_to(obj, ex, ey, c1x, c1y, c2x, c2y);
+
+ // next start point is the current end point (same for angle)
+ sx = ex;
+ sy = ey;
+ var.theta1 = theta2;
+ // avoid recomputations
+ var.cos_theta1 = cos_theta2;
+ var.sin_theta1 = sin_theta2;
+ }
+ _assign_current_ctrl_point(sd, ex, ey);
+ _assign_command(sd, EFL_TVG_PATH_CMD_TYPE_NO_BEZIER);
+}
+
+static void
+_shape_reset(Evas_Vg_Shape *obj)
+{
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ sd = nd->data;
+
+ sd->curr_ctrl.x = sd->curr_ctrl.y = 0;
+ sd->curr.x = sd->curr.y = 0;
+ sd->cmd_prev = 0;
+ sd->start.x = sd->start.y = 0;
+
+ if (sd->fill != NULL)
+ {
+ efl_del(sd->fill);
+ sd->fill = NULL;
+ }
+
+ tvg_shape_reset(sd->shape);
+}
+
+static void
+_shape_dup(Evas_Vg_Shape *obj, Evas_Vg_Shape *dup_from)
+{
+ Efl_Canvas_Vg_Node_Data *nd_from = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd_from = NULL;
+
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj || !dup_from) return;
+
+ nd_from = efl_data_scope_get(dup_from, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd_from) return;
+
+ sd_from = nd_from->data;
+ if (!sd_from) return;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return;
+
+ sd = nd->data;
+ if (!sd) return;
+
+ if (sd->shape) tvg_paint_del(sd->shape);
+ sd->shape = tvg_paint_duplicate(sd_from->shape);
+
+ sd->curr_ctrl.x = sd_from->curr_ctrl.x;
+ sd->curr_ctrl.y = sd_from->curr_ctrl.y;
+
+ sd->curr.x = sd_from->curr.x;
+ sd->curr.y = sd_from->curr.y;
+
+ sd->cmd_prev = sd_from->cmd_prev;
+
+ sd->start.x = sd_from->start.x;
+ sd->start.y = sd_from->start.y;
+ return;
+}
+
+static void
+_dash_set(Evas_Vg_Shape *obj, const Evas_Vg_Dash *dash, unsigned int length)
+{
+ float *dash_pattern = malloc(sizeof(float) * length * DASH_PATTERN_EL_SIZE);
+ unsigned int i = 0;
+
+ for (i = 0; i < length; ++i)
+ {
+ dash_pattern[DASH_PATTERN_EL_SIZE * i] = dash[i].length;
+ dash_pattern[DASH_PATTERN_EL_SIZE * i + 1] = dash[i].gap;
+ }
+
+ tvg_shape_set_stroke_dash(_get_tvg_shape(obj), dash_pattern, length * DASH_PATTERN_EL_SIZE);
+ free(dash_pattern);
+}
+
+static Eina_Bool
+_shape_properties_interpolate(Evas_Vg_Shape *obj,
+ const Evas_Vg_Shape *from,
+ const Evas_Vg_Shape *to,
+ double pos_map)
+{
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+ const Efl_Canvas_Vg_Shape_Data *sd_from = NULL;
+ const Efl_Canvas_Vg_Shape_Data *sd_to = NULL;
+
+ unsigned int i = 0;
+ int a = 0, r = 0, g = 0, b = 0;
+ int to_a = 0, to_r = 0, to_g = 0, to_b = 0;
+
+ float *dash = NULL, *dash_to = NULL;
+ uint32_t dash_cnt = 0, dash_to_cnt = 0;
+
+ Tvg_Stroke_Cap cap, cap_to;
+ Tvg_Stroke_Join join, join_to;
+ float width, width_to;
+
+ if (!obj || !from || !to) return EINA_FALSE;
+
+ sd = _get_shape_data(obj);
+ sd_from = _get_shape_data((Evas_Vg_Shape*)from);
+ sd_to = _get_shape_data((Evas_Vg_Shape*)to);
+
+ efl_gfx_color_get((const Eo*)from, &r, &g, &b, &a);
+ efl_gfx_color_get((const Eo*)to, &to_r, &to_g, &to_b, &to_a);
+
+ a = _interpolate(a, to_a, pos_map);
+ r = _interpolate(r, to_r, pos_map);
+ g = _interpolate(g, to_g, pos_map);
+ b = _interpolate(b, to_b, pos_map);
+ efl_gfx_color_set((Eo*)obj, r, g, b, a);
+
+ // Stroke - color
+ tvg_shape_get_stroke_color(sd_from->shape, (uint8_t*)&r, (uint8_t*)&g, (uint8_t*)&b, (uint8_t*)&a);
+ tvg_shape_get_stroke_color(sd_from->shape, (uint8_t*)&to_r, (uint8_t*)&to_g, (uint8_t*)&to_b, (uint8_t*)&to_a);
+ a = _interpolate(a, to_a, pos_map);
+ r = _interpolate(r, to_r, pos_map);
+ g = _interpolate(g, to_g, pos_map);
+ b = _interpolate(b, to_b, pos_map);
+ tvg_shape_set_stroke_color(sd->shape, r, g, b, a);
+
+ // Stroke - width (scale)
+ tvg_shape_get_stroke_width(sd_from->shape, &width);
+ tvg_shape_get_stroke_width(sd_to->shape, &width_to);
+ sd->scale = _interpolate(sd_from->scale, sd_to->scale, pos_map);
+ width = _interpolate(width, width_to, pos_map) * sd->scale;
+ tvg_shape_set_stroke_width(sd->shape, width);
+
+ // Stroke - dash
+ tvg_shape_get_stroke_dash(sd->shape, (const float**)&dash, &dash_cnt);
+ tvg_shape_get_stroke_dash(sd_to->shape, (const float**)&dash_to, &dash_to_cnt);
+
+ if (dash && dash_to && dash_cnt > 0 && dash_cnt == dash_to_cnt)
+ {
+ for (i = 0; i < dash_cnt; ++i)
+ {
+ dash[i] = _interpolate(dash[i], dash_to[i], pos_map);
+ }
+ }
+
+ tvg_shape_set_stroke_dash(sd->shape, dash, dash_cnt);
+
+ // Stroke - cap
+ tvg_shape_get_stroke_cap(sd->shape, &cap);
+ tvg_shape_get_stroke_cap(sd_to->shape, &cap_to);
+ (pos_map < 0.5) ? tvg_shape_set_stroke_cap(sd->shape, cap) : tvg_shape_set_stroke_cap(sd->shape, cap_to);
+
+ // Stroke - join
+ tvg_shape_get_stroke_join(sd->shape, &join);
+ tvg_shape_get_stroke_join(sd_to->shape, &join_to);
+ (pos_map < 0.5) ? tvg_shape_set_stroke_join(sd->shape, join) : tvg_shape_set_stroke_join(sd->shape, join_to);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_shape_interpolate(Evas_Vg_Shape *obj,
+ const Evas_Vg_Shape *from,
+ const Evas_Vg_Shape *to,
+ double pos_map)
+{
+ evas_vg_shape_reset(obj);
+
+ Tvg_Paint *tvg_dest = NULL;
+ Tvg_Paint *tvg_from = NULL;
+ Tvg_Paint *tvg_to = NULL;
+
+ Tvg_Path_Command *path_commands_from = NULL;
+ Tvg_Point *path_coords_from = NULL;
+
+ uint32_t cmds_count_from = 0;
+ uint32_t pts_count_from = 0;
+
+ Tvg_Path_Command *path_commands_to = NULL;
+ Tvg_Point *path_coords_to = NULL;
+
+ uint32_t cmds_count_to = 0;
+ uint32_t pts_count_to = 0;
+
+ Tvg_Point *path_coords_dest = NULL;
+ unsigned int i = 0;
+
+ if (!obj || !from || !to) return EINA_FALSE;
+
+ tvg_dest = _get_tvg_shape(obj);
+ tvg_from = _get_tvg_shape((Evas_Vg_Shape*)from);
+ tvg_to = _get_tvg_shape((Evas_Vg_Shape*)to);
+
+ if (!tvg_dest || !tvg_from || !tvg_to) return EINA_FALSE;
+
+ tvg_shape_get_path_commands(tvg_from, (const Tvg_Path_Command**)&path_commands_from, &cmds_count_from);
+ tvg_shape_get_path_coords(tvg_from, (const Tvg_Point**)&path_coords_from, &pts_count_from);
+ tvg_shape_get_path_commands(tvg_to, (const Tvg_Path_Command**)&path_commands_to, &cmds_count_to);
+ tvg_shape_get_path_coords(tvg_to, (const Tvg_Point**)&path_coords_to, &pts_count_to);
+
+ path_coords_dest = (Tvg_Point*)malloc(sizeof(Tvg_Point) * pts_count_from);
+ for (i = 0; i < pts_count_from; ++i)
+ {
+ path_coords_dest[i].x = _interpolate(path_coords_from[i].x, path_coords_to[i].x, pos_map);
+ path_coords_dest[i].y = _interpolate(path_coords_from[i].y, path_coords_to[i].y, pos_map);
+ }
+
+ _shape_properties_interpolate(obj, from, to, pos_map);
+ tvg_shape_append_path(tvg_dest, path_commands_from, cmds_count_from, path_coords_dest, pts_count_from);
+
+ return EINA_TRUE;
+}
+#endif
// FIXME: Use the renderer bounding box when it has been created instead of an estimation
static void
Efl_Canvas_Vg_Node *f)
{
if (pd->fill == f) return;
-
+#ifdef HAVE_THORVG
+ if (efl_isa(pd->fill, EFL_CANVAS_VG_GRADIENT_CLASS))
+ {
+ efl_del(pd->fill);
+ pd->fill = NULL;
+ }
+#endif
Efl_Canvas_Vg_Node *tmp = pd->fill;
-
pd->fill = efl_ref(f);
efl_unref(tmp);
}
return pd->stroke.marker;
}
+#ifndef HAVE_THORVG
static void
_efl_canvas_vg_shape_render_pre(Evas_Object_Protected_Data *vg_pd,
Efl_VG *obj,
ector_renderer_prepare(nd->renderer);
ector_renderer_comp_method_set(nd->renderer, comp, comp_method);
}
+#endif
+
+#ifdef HAVE_THORVG
+static void
+_visibility_set(Efl_Canvas_Vg_Node_Data *nd)
+{
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!nd || !nd->data) return;
+ sd = nd->data;
+
+ if (sd->visibility == nd->visibility) return;
+ sd->visibility = nd->visibility;
+
+ if (nd->visibility == EINA_FALSE)
+ {
+ tvg_shape_get_stroke_color(sd->shape,
+ &sd->stroke_color.r,
+ &sd->stroke_color.g,
+ &sd->stroke_color.b,
+ &sd->stroke_color.a);
+
+ tvg_shape_get_fill_color(sd->shape,
+ &sd->fill_color.r,
+ &sd->fill_color.g,
+ &sd->fill_color.b,
+ &sd->fill_color.a);
+
+ tvg_shape_set_stroke_color(sd->shape, 0, 0, 0, 0);
+ tvg_shape_set_fill_color(sd->shape, 0, 0, 0, 0);
+ }
+ else
+ {
+ tvg_shape_set_stroke_color(sd->shape,
+ sd->stroke_color.r,
+ sd->stroke_color.g,
+ sd->stroke_color.b,
+ sd->stroke_color.a);
+
+ tvg_shape_set_fill_color(sd->shape,
+ sd->fill_color.r,
+ sd->fill_color.g,
+ sd->fill_color.b,
+ sd->fill_color.a);
+ }
+}
+static void
+_convert_eina_to_tvg_mat(const Eina_Matrix3 *eina_mat, Tvg_Matrix *tvg_mat)
+{
+ if (!eina_mat || !tvg_mat) return;
+
+ tvg_mat->e11 = eina_mat->xx;
+ tvg_mat->e12 = eina_mat->xy;
+ tvg_mat->e13 = eina_mat->xz;
+
+ tvg_mat->e21 = eina_mat->yx;
+ tvg_mat->e22 = eina_mat->yy;
+ tvg_mat->e23 = eina_mat->yz;
+
+ tvg_mat->e31 = eina_mat->zx;
+ tvg_mat->e32 = eina_mat->zy;
+ tvg_mat->e33 = eina_mat->zz;
+}
+
+static void
+_efl_canvas_vg_shape_render_pre_tvg(EINA_UNUSED Evas_Object_Protected_Data *vg_pd,
+ Efl_VG *obj,
+ Efl_Canvas_Vg_Node_Data *nd,
+ void *canvas)
+{
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+ Efl_Canvas_Vg_Gradient_Data *gd = NULL;
+
+ Tvg_Matrix trans_mat = { 0 };
+ const Eina_Matrix3 *m = NULL;
+
+ int r = 0, g = 0, b = 0, a = 0;
+
+ if (!nd || !nd->data) return;
+ sd = nd->data;
+
+ nd->flags = EFL_GFX_CHANGE_FLAG_NONE;
+ tvg_paint_translate(sd->shape, nd->x, nd->y);
+
+ // set color fill
+ if (sd->fill != NULL && efl_isa(sd->fill, EFL_CANVAS_VG_GRADIENT_CLASS))
+ {
+ gd = efl_data_scope_get(sd->fill, EFL_CANVAS_VG_GRADIENT_CLASS);
+ gd->shape = obj;
+ gd->gradient_render_pre_tvg(sd->fill, gd, sd->shape);
+ }
+
+ m = evas_vg_node_transformation_get(obj);
+ if (m)
+ {
+ _convert_eina_to_tvg_mat(m, &trans_mat);
+ trans_mat.e13 += nd->x;
+ trans_mat.e23 += nd->y;
+
+ tvg_paint_scale(sd->shape, trans_mat.e11);
+ tvg_paint_transform(sd->shape, &trans_mat);
+ }
+
+ _visibility_set(nd);
+
+ if (sd->pushed == EINA_FALSE)
+ {
+ tvg_canvas_push((Tvg_Canvas *) canvas, sd->shape);
+ sd->pushed = EINA_TRUE;
+ }
+
+ //get fill color and set it
+ efl_gfx_color_get(obj, &r, &g, &b, &a);
+ tvg_shape_set_fill_color(sd->shape, r, g, b, a);
+ tvg_canvas_update_paint((Tvg_Canvas *) canvas, sd->shape);
+}
+#endif
static Eo *
_efl_canvas_vg_shape_efl_object_constructor(Eo *obj, Efl_Canvas_Vg_Shape_Data *pd)
Efl_Canvas_Vg_Node_Data *nd;
obj = efl_constructor(efl_super(obj, MY_CLASS));
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+#ifndef HAVE_THORVG
efl_gfx_shape_stroke_scale_set(obj, 1);
efl_gfx_shape_stroke_location_set(obj, 0.5);
efl_gfx_shape_stroke_cap_set(obj, EFL_GFX_CAP_BUTT);
// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit
efl_gfx_shape_stroke_miterlimit_set(obj, 4);
- nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
nd->render_pre = _efl_canvas_vg_shape_render_pre;
- nd->data = pd;
+#else
+ nd->render_pre_tvg = _efl_canvas_vg_shape_render_pre_tvg;
+ pd->shape = tvg_shape_new();
+ pd->visibility = EINA_TRUE;
+ pd->scale = 1.0;
+#endif
+ nd->data = pd;
return obj;
}
if (pd->stroke.fill) efl_unref(pd->stroke.fill);
if (pd->stroke.marker) efl_unref(pd->stroke.marker);
+#ifdef HAVE_THORVG
+ //tvg_canvas_destroy is called before and it frees all shapes so there is no need to
+ //call tvg_paint_del API.
+ pd->shape = NULL;
+#else
efl_gfx_path_reset(obj);
+#endif
+
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Efl_Canvas_Vg_Node *
_efl_canvas_vg_shape_efl_duplicate_duplicate(const Eo *obj, Efl_Canvas_Vg_Shape_Data *pd)
{
+ //TODO: implement me!
Efl_Canvas_Vg_Node *node;
Efl_Canvas_Vg_Shape_Data *sd;
}
efl_gfx_path_copy_from(node, obj);
-
return node;
}
EAPI double
evas_vg_shape_stroke_scale_get(Evas_Vg_Shape *obj)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return 0.0;
+
+ sd = _get_shape_data(obj);
+ if (!sd) return 0.0;
+
+ return sd->scale;
+#else
return efl_gfx_shape_stroke_scale_get(obj);
+#endif
}
EAPI void
evas_vg_shape_stroke_scale_set(Evas_Vg_Shape *obj, double s)
{
+#ifdef HAVE_THORVG
+ float width = 0;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+ if (!obj) return;
+
+ sd = _get_shape_data(obj);
+ if (!sd) return;
+
+ tvg_shape_get_stroke_width(sd->shape, &width);
+ width = width * s;
+ sd->scale = s;
+
+ tvg_shape_set_stroke_width(sd->shape, width);
+#else
efl_gfx_shape_stroke_scale_set(obj, s);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_stroke_color_get(Evas_Vg_Shape *obj, int *r, int *g, int *b, int *a)
{
+#ifdef HAVE_THORVG
+ tvg_shape_get_stroke_color(_get_tvg_shape(obj),
+ (uint8_t*)r,
+ (uint8_t*)g,
+ (uint8_t*)b,
+ (uint8_t*)a);
+ evas_color_argb_premul(*a, r, g, b);
+#else
efl_gfx_shape_stroke_color_get(obj, r, g, b, a);
+#endif
}
EAPI void
evas_vg_shape_stroke_color_set(Evas_Vg_Shape *obj, int r, int g, int b, int a)
{
+#ifdef HAVE_THORVG
+ evas_color_argb_unpremul(a, &r, &g, &b);
+ tvg_shape_set_stroke_color(_get_tvg_shape(obj), r, g, b, a);
+#else
efl_gfx_shape_stroke_color_set(obj, r, g, b, a);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI double
evas_vg_shape_stroke_width_get(Evas_Vg_Shape *obj)
{
+#ifdef HAVE_THORVG
+ float w = 0.0;
+ tvg_shape_get_stroke_width(_get_tvg_shape(obj), &w);
+ return w;
+#else
return efl_gfx_shape_stroke_width_get(obj);
+#endif
}
EAPI void
evas_vg_shape_stroke_width_set(Evas_Vg_Shape *obj, double w)
{
+#ifdef HAVE_THORVG
+ tvg_shape_set_stroke_width(_get_tvg_shape(obj), w);
+#else
efl_gfx_shape_stroke_width_set(obj, w);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI double
evas_vg_shape_stroke_location_get(Evas_Vg_Shape *obj)
{
+ //TODO: implement
return efl_gfx_shape_stroke_location_get(obj);
}
EAPI void
evas_vg_shape_stroke_location_set(Evas_Vg_Shape *obj, double centered)
{
+ //TODO: implement
efl_gfx_shape_stroke_location_set(obj, centered);
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_stroke_dash_get(Evas_Vg_Shape *obj, const Evas_Vg_Dash **dash, unsigned int *length)
{
+#ifdef HAVE_THORVG
+ const float *dashPattern;
+ uint32_t cnt = 0;
+
+ Evas_Vg_Dash *d = NULL;
+
+ unsigned int i = 0;
+ if (!dash || !length) return;
+
+ tvg_shape_get_stroke_dash(_get_tvg_shape(obj), &dashPattern, &cnt);
+ if (!cnt) return;
+
+ d = malloc(sizeof(Evas_Vg_Dash) * cnt / DASH_PATTERN_EL_SIZE);
+ if (!d) return;
+
+ for (i = 0; i < cnt; i += DASH_PATTERN_EL_SIZE)
+ {
+ d[i].length = dashPattern[i];
+ d[i].gap = dashPattern[i+1];
+ }
+
+ *dash = d;
+ *length = cnt;
+#else
efl_gfx_shape_stroke_dash_get(obj, (const Efl_Gfx_Dash **)dash, length);
+#endif
}
EAPI void
evas_vg_shape_stroke_dash_set(Evas_Vg_Shape *obj, const Evas_Vg_Dash *dash, unsigned int length)
{
+#ifdef HAVE_THORVG
+ _dash_set(obj, dash, length);
+#else
efl_gfx_shape_stroke_dash_set(obj, (const Efl_Gfx_Dash *)dash, length);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI Evas_Vg_Cap
evas_vg_shape_stroke_cap_get(Evas_Vg_Shape *obj)
{
+#ifdef HAVE_THORVG
+ Tvg_Stroke_Cap cap;
+ tvg_shape_get_stroke_cap(_get_tvg_shape(obj), &cap);
+ return (Evas_Vg_Cap)cap;
+#else
return (Evas_Vg_Cap)efl_gfx_shape_stroke_cap_get(obj);
+#endif
}
EAPI void
evas_vg_shape_stroke_cap_set(Evas_Vg_Shape *obj, Evas_Vg_Cap c)
{
+#ifdef HAVE_THORVG
+ tvg_shape_set_stroke_cap(_get_tvg_shape(obj), (Tvg_Stroke_Cap) c);
+#else
efl_gfx_shape_stroke_cap_set(obj, (Efl_Gfx_Cap)c);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI Evas_Vg_Join
evas_vg_shape_stroke_join_get(Evas_Vg_Shape *obj)
{
+#ifdef HAVE_THORVG
+ Tvg_Stroke_Join join;
+ tvg_shape_get_stroke_join(_get_tvg_shape(obj), &join);
+ return (Evas_Vg_Join)join;
+#else
return (Evas_Vg_Join)efl_gfx_shape_stroke_join_get(obj);
+#endif
}
EAPI void
evas_vg_shape_stroke_join_set(Evas_Vg_Shape *obj, Evas_Vg_Join j)
{
+#ifdef HAVE_THORVG
+ tvg_shape_set_stroke_join(_get_tvg_shape(obj), (Tvg_Stroke_Join) j);
+#else
efl_gfx_shape_stroke_join_set(obj, (Efl_Gfx_Join)j);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_path_set(Evas_Vg_Shape *obj, const Evas_Vg_Path_Command *op, const double *points)
{
+ //TODO: implement
efl_gfx_path_set(obj, (const Efl_Gfx_Path_Command *)op, points);
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_path_get(Evas_Vg_Shape *obj, const Evas_Vg_Path_Command **op, const double **points)
{
+ //TODO: implement
efl_gfx_path_get(obj, (const Efl_Gfx_Path_Command **)op, points);
}
EAPI void
evas_vg_shape_path_length_get(Evas_Vg_Shape *obj, unsigned int *commands, unsigned int *points)
{
+ //TODO: implement
efl_gfx_path_length_get(obj, commands, points);
}
EAPI void
evas_vg_shape_current_get(Evas_Vg_Shape *obj, double *x, double *y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return;
+ sd = nd->data;
+ if (!sd) return;
+
+ if (x) *x = sd->curr.x;
+ if (y) *y = sd->curr.y;
+#else
efl_gfx_path_current_get(obj, x, y);
+#endif
}
EAPI void
evas_vg_shape_current_ctrl_get(Evas_Vg_Shape *obj, double *x, double *y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Node_Data *nd = NULL;
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+
+ nd = efl_data_scope_get(obj, EFL_CANVAS_VG_NODE_CLASS);
+ if (!nd) return;
+ sd = nd->data;
+ if (!sd) return;
+
+ if (x) *x = sd->curr_ctrl.x;
+ if (y) *y = sd->curr_ctrl.y;
+#else
efl_gfx_path_current_ctrl_get(obj, x, y);
+#endif
}
EAPI void
evas_vg_shape_dup(Evas_Vg_Shape *obj, Evas_Vg_Shape *dup_from)
{
+#ifdef HAVE_THORVG
+ _shape_dup(obj, dup_from);
+#else
efl_gfx_path_copy_from(obj, dup_from);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_reset(Evas_Vg_Shape *obj)
{
+#ifdef HAVE_THORVG
+ _shape_reset(obj);
+#else
efl_gfx_path_reset(obj);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_move_to(Evas_Vg_Shape *obj, double x, double y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+ sd = _get_shape_data(obj);
+ if (!sd || !sd->shape) return;
+
+ tvg_shape_move_to(sd->shape, x, y);
+ _assign_current_point(sd, NULL, x, y);
+ _assign_command(sd, EFL_TVG_PATH_CMD_TYPE_NO_BEZIER);
+#else
efl_gfx_path_append_move_to(obj, x, y);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_line_to(Evas_Vg_Shape *obj, double x, double y)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+ sd = _get_shape_data(obj);
+ if (!sd || !sd->shape) return;
+
+ tvg_shape_line_to(sd->shape, x, y);
+ _assign_current_point(sd, NULL, x, y);
+ _assign_command(sd, EFL_TVG_PATH_CMD_TYPE_NO_BEZIER);
+#else
efl_gfx_path_append_line_to(obj, x, y);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_quadratic_to(Evas_Vg_Shape *obj, double x, double y, double ctrl_x, double ctrl_y)
{
+#ifdef HAVE_THORVG
+ _append_quadratic(obj, x, y, ctrl_x, ctrl_y);
+#else
efl_gfx_path_append_quadratic_to(obj, x, y, ctrl_x, ctrl_y);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_squadratic_to(Evas_Vg_Shape *obj, double x, double y)
{
+#ifdef HAVE_THORVG
+ _append_squadratic(obj, x, y);
+#else
efl_gfx_path_append_squadratic_to(obj, x, y);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_cubic_to(Evas_Vg_Shape *obj, double x, double y, double ctrl_x0, double ctrl_y0, double ctrl_x1, double ctrl_y1)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+ sd = _get_shape_data(obj);
+ if (!sd || !sd->shape) return;
+
+ tvg_shape_cubic_to(sd->shape, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1, x, y);
+ _assign_current_point(sd, NULL, x, y);
+ _assign_current_ctrl_point(sd, ctrl_x1, ctrl_y1);
+ _assign_command(sd, EFL_TVG_PATH_CMD_TYPE_BEZIER_CUBIC);
+#else
efl_gfx_path_append_cubic_to(obj, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1, x, y);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_scubic_to(Evas_Vg_Shape *obj, double x, double y, double ctrl_x, double ctrl_y)
{
+#ifdef HAVE_THORVG
+ _append_scubic_to(obj, x, y, ctrl_x, ctrl_y);
+#else
efl_gfx_path_append_scubic_to(obj, x, y, ctrl_x, ctrl_y);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_arc_to(Evas_Vg_Shape *obj, double x, double y, double rx, double ry, double angle, Eina_Bool large_arc, Eina_Bool sweep)
{
+#ifdef HAVE_THORVG
+ _append_arc_to(obj, x, y, rx, ry, angle, large_arc, sweep);
+#else
efl_gfx_path_append_arc_to(obj, x, y, rx, ry, angle, large_arc, sweep);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_arc(Evas_Vg_Shape *obj, double x, double y, double w, double h, double start_angle, double sweep_length)
{
+#ifndef HAVE_THORVG
efl_gfx_path_append_arc(obj, x, y, w, h, start_angle, sweep_length);
+#else
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+ sd = _get_shape_data(obj);
+ if (!sd || !sd->shape) return;
+
+ float radius = fmin(w / 2.0f, h / 2.0f);
+ float cx = x + (w / 2.0f);
+ float cy = y + (h / 2.0f);
+
+ tvg_shape_append_arc(sd->shape, cx, cy, radius, start_angle, sweep_length, 0);
+ _assign_current_point(sd, NULL, cx, cy);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_close(Evas_Vg_Shape *obj)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Shape_Data *sd = _get_shape_data(obj);
+ if (!sd) return;
+
+ tvg_shape_close(sd->shape);
+
+ sd->curr.x = sd->start.x;
+ sd->curr.y = sd->start.y;
+#else
efl_gfx_path_append_close(obj);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_circle(Evas_Vg_Shape *obj, double x, double y, double radius)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+ sd = _get_shape_data(obj);
+ if (!sd || !sd->shape) return;
+
+ tvg_shape_append_circle(sd->shape, x, y, radius, radius);
+ _assign_current_point(sd, NULL, x, y - radius);
+#else
efl_gfx_path_append_circle(obj, x, y, radius);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_rect(Evas_Vg_Shape *obj, double x, double y, double w, double h, double rx, double ry)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Shape_Data *sd = NULL;
+
+ if (!obj) return;
+ sd = _get_shape_data(obj);
+ if (!sd || !sd->shape) return;
+
+ tvg_shape_append_rect(sd->shape, x, y, w, h, rx, ry);
+ _assign_current_point(sd, NULL, x, y);
+#else
efl_gfx_path_append_rect(obj, x, y, w, h, rx, ry);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI void
evas_vg_shape_append_svg_path(Evas_Vg_Shape *obj, const char *svg_path_data)
{
+#ifdef HAVE_THORVG
+ Efl_Canvas_Vg_Shape_Data *sd = _get_shape_data(obj);
+ Efl_Tvg_Shape_Svg_Path svg_path = { 0 };
+
+ double number_array[SVG_PATH_NUM_LEN] = {0};
+ int number_count = 0;
+ double cur_x = 0, cur_y = 0;
+ double cur_ctl_x = 0, cur_ctl_y = 0;
+
+ char pth_cmd = 0;
+ Eina_Bool is_quadratic = EINA_FALSE;
+ char *path = (char*) svg_path_data;
+
+ if (!sd) return;
+
+ while (path[0] != '\0')
+ {
+ path = _next_command(path, &pth_cmd, number_array, &number_count);
+
+ if (!path) break;
+ _process_command(&svg_path, pth_cmd, number_array,
+ &number_count, &cur_x, &cur_y,
+ &cur_ctl_x, &cur_ctl_y, &is_quadratic);
+ }
+
+ tvg_shape_append_path(sd->shape, svg_path.cmds, svg_path.cmds_cnt, svg_path.pts, svg_path.pts_cnt);
+
+ if (svg_path.cmds) free(svg_path.cmds);
+ if (svg_path.pts) free(svg_path.pts);
+#else
efl_gfx_path_append_svg_path(obj, svg_path_data);
+#endif
efl_canvas_vg_node_change(obj);
}
EAPI Eina_Bool
evas_vg_shape_interpolate(Evas_Vg_Shape *obj, const Evas_Vg_Shape *from, const Evas_Vg_Shape *to, double pos_map)
{
- Eina_Bool ret = efl_gfx_path_interpolate(obj, from, to, pos_map);
+ Eina_Bool ret = EINA_FALSE;
+#ifdef HAVE_THORVG
+ if (!evas_vg_shape_equal_commands((Evas_Vg_Shape*)from, (Evas_Vg_Shape*)to)) return EINA_FALSE;
+ ret = _shape_interpolate(obj, from, to, pos_map);
+#else
+ ret = efl_gfx_path_interpolate(obj, from, to, pos_map);
+#endif
efl_canvas_vg_node_change(obj);
return ret;
}
EAPI Eina_Bool
evas_vg_shape_equal_commands(Evas_Vg_Shape *obj, const Evas_Vg_Shape *with)
{
+#ifdef HAVE_THORVG
+ const Tvg_Path_Command *cmds = NULL;
+ const Tvg_Path_Command *cmds_with = NULL;
+
+ uint32_t cmds_count = 0;
+ uint32_t cmds_count_with = 0;
+
+ unsigned int i = 0;
+
+ tvg_shape_get_path_commands(_get_tvg_shape(obj), &cmds, &cmds_count);
+ tvg_shape_get_path_commands(_get_tvg_shape((Evas_Vg_Shape*)with), &cmds_with, &cmds_count_with);
+
+ if (!cmds || !cmds_count) return EINA_FALSE;
+ if (cmds_count != cmds_count_with) return EINA_FALSE;
+
+ for (i = 0; i < cmds_count; ++i)
+ {
+ if (cmds[i] != cmds_with[i]) return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+#else
return efl_gfx_path_equal_commands(obj, with);
+#endif
}
EAPI Efl_Canvas_Vg_Shape*
--- /dev/null
+#ifndef _EVAS_TVG_PATH_HELPERS_H_
+#define _EVAS_TVG_PATH_HELPERS_H_
+
+/*
+ * structs and functions used by evas_vg_shape_append_svg_path/arc_to API,
+ * which will be deprecated at some point
+ */
+
+typedef struct _Efl_Tvg_Shape_Svg_Path Efl_Tvg_Shape_Svg_Path;
+typedef struct _Arc_To_Init_Variables Arc_To_Init_Variables;
+
+struct _Efl_Tvg_Shape_Svg_Path {
+ char *svg_path_data;
+ Tvg_Path_Command *cmds;
+ Tvg_Point *pts;
+ uint32_t cmds_cnt;
+ uint32_t pts_cnt;
+ uint32_t cmds_reserved;
+ uint32_t pts_reserved;
+};
+
+struct _Arc_To_Init_Variables {
+ double cx, cy;
+ double theta1;
+ double delta, bcp;
+ double cos_phi_rx, cos_phi_ry;
+ double sin_phi_rx, sin_phi_ry;
+ double cos_theta1, sin_theta1;
+ int segments;
+};
+
+static char *
+_skipcomma(const char *content)
+{
+ while (*content && isspace(*content)) content++;
+ if (*content == ',') return (char*) content + 1;
+ return (char*) content;
+}
+
+static inline Eina_Bool
+_parse_number(char **content, double *number)
+{
+ char *end = NULL;
+ *number = strtod(*content, &end);
+ if ((*content) == end) return EINA_FALSE;
+ *content = _skipcomma(end);
+ return EINA_TRUE;
+}
+
+static inline Eina_Bool
+_parse_flag(char **content, int *number)
+{
+ char *end = NULL;
+ char *end_test = NULL;
+ char content_test[strlen(*content) + 1];
+ int number_test;
+
+ strcpy(content_test,*content);
+ *number = strtol(*content, &end, 10) ? 1 : 0;
+ if ((*content) == end) return EINA_FALSE;
+ number_test = (int)strtof(content_test, &end_test);
+
+ if ((*number != number_test) || (*end != *end_test))
+ return EINA_FALSE;
+
+ *content = _skipcomma(end);
+ return EINA_TRUE;
+}
+
+static int
+_number_count(char cmd)
+{
+ int count = 0;
+ switch (cmd)
+ {
+ case 'M':
+ case 'm':
+ case 'L':
+ case 'l':
+ case 'T':
+ case 't':
+ {
+ count = 2;
+ break;
+ }
+ case 'C':
+ case 'c':
+ case 'E':
+ case 'e':
+ {
+ count = 6;
+ break;
+ }
+ case 'H':
+ case 'h':
+ case 'V':
+ case 'v':
+ {
+ count = 1;
+ break;
+ }
+ case 'S':
+ case 's':
+ case 'Q':
+ case 'q':
+ {
+ count = 4;
+ break;
+ }
+ case 'A':
+ case 'a':
+ {
+ count = 7;
+ break;
+ }
+ default:
+ break;
+ }
+ return count;
+}
+
+static char*
+_next_command(char *path, char *cmd, double *arr, int *count)
+{
+ int i = 0, large, sweep;
+
+ path = _skipcomma(path);
+ if (isalpha(*path))
+ {
+ *cmd = *path;
+ path++;
+ *count = _number_count(*cmd);
+ }
+ else
+ {
+ if (*cmd == 'm')
+ *cmd = 'l';
+ else if (*cmd == 'M')
+ *cmd = 'L';
+ }
+
+ if (*count == 7)
+ {
+ // special case for arc command
+ if (_parse_number(&path, &arr[0]) &&
+ _parse_number(&path, &arr[1]) &&
+ _parse_number(&path, &arr[2]) &&
+ _parse_flag(&path, &large) &&
+ _parse_flag(&path, &sweep) &&
+ _parse_number(&path, &arr[5]) &&
+ _parse_number(&path, &arr[6]))
+ {
+ arr[3] = large;
+ arr[4] = sweep;
+ return path;
+ }
+ *count = 0;
+ return NULL;
+ }
+
+ for (i = 0; i < *count; i++)
+ {
+ if (!_parse_number(&path, &arr[i]))
+ {
+ *count = 0;
+ return NULL;
+ }
+ path = _skipcomma(path);
+ }
+
+ return path;
+}
+
+/*
+ * code adapted from enesim which was adapted from moonlight sources
+ */
+static void
+_arc_to_variables_initialization(double x, double y, double rx, double ry,
+ double angle, Eina_Bool large_arc, Eina_Bool sweep,
+ double sx, double sy, Arc_To_Init_Variables *var)
+{
+ double cxp, cyp;
+ double cos_phi, sin_phi;
+ double dx2, dy2;
+ double x1p, y1p;
+ double x1p2, y1p2;
+ double rx2, ry2;
+ double lambda;
+ double c;
+ double at;
+ double delta_theta;
+ double nat;
+
+ angle = angle * M_PI / 180.0;
+ cos_phi = cos(angle);
+ sin_phi = sin(angle);
+ dx2 = (sx - x) / 2.0;
+ dy2 = (sy - y) / 2.0;
+ x1p = cos_phi * dx2 + sin_phi * dy2;
+ y1p = cos_phi * dy2 - sin_phi * dx2;
+ x1p2 = x1p * x1p;
+ y1p2 = y1p * y1p;
+ rx2 = rx * rx;
+ ry2 = ry * ry;
+ lambda = (x1p2 / rx2) + (y1p2 / ry2);
+
+ // Correction of out-of-range radii, see F6.6.2 (step 4)
+ if (lambda > 1.0)
+ {
+ // see F6.6.3
+ double lambda_root = sqrt(lambda);
+
+ rx *= lambda_root;
+ ry *= lambda_root;
+ // update rx2 and ry2
+ rx2 = rx * rx;
+ ry2 = ry * ry;
+ }
+
+ c = (rx2 * ry2) - (rx2 * y1p2) - (ry2 * x1p2);
+
+ // check if there is no possible solution
+ // (i.e. we can't do a square root of a negative value)
+ if (c < 0.0)
+ {
+ // scale uniformly until we have a single solution
+ // (see F6.2) i.e. when c == 0.0
+ double scale = sqrt(1.0 - c / (rx2 * ry2));
+ rx *= scale;
+ ry *= scale;
+ // update rx2 and ry2
+ rx2 = rx * rx;
+ ry2 = ry * ry;
+
+ // step 2 (F6.5.2) - simplified since c == 0.0
+ cxp = 0.0;
+ cyp = 0.0;
+ // step 3 (F6.5.3 first part) - simplified since cxp and cyp == 0.0
+ var->cx = 0.0;
+ var->cy = 0.0;
+ }
+ else
+ {
+ // complete c calculation
+ c = sqrt(c / ((rx2 * y1p2) + (ry2 * x1p2)));
+ // inverse sign if Fa == Fs
+ if (large_arc == sweep)
+ c = -c;
+
+ // step 2 (F6.5.2)
+ cxp = c * ( rx * y1p / ry);
+ cyp = c * (-ry * x1p / rx);
+
+ // step 3 (F6.5.3 first part)
+ var->cx = cos_phi * cxp - sin_phi * cyp;
+ var->cy = sin_phi * cxp + cos_phi * cyp;
+ }
+
+ // step 3 (F6.5.3 second part) we now have the center point of the ellipse
+ var->cx += (sx + x) / 2.0;
+ var->cy += (sy + y) / 2.0;
+
+ // step 4 (F6.5.4)
+ // we don't use arccos (as per w3c doc), see
+ // http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
+ // note: atan2 (0.0, 1.0) == 0.0
+ at = atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx));
+ var->theta1 = (at < 0.0) ? 2.0 * M_PI + at : at;
+
+ nat = atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
+ delta_theta = (nat < at) ? 2.0 * M_PI - at + nat : nat - at;
+
+ if (sweep)
+ {
+ // ensure delta theta < 0 or else add 360 degrees
+ if (delta_theta < 0.0)
+ delta_theta += 2.0 * M_PI;
+ }
+ else
+ {
+ // ensure delta theta > 0 or else substract 360 degrees
+ if (delta_theta > 0.0)
+ delta_theta -= 2.0 * M_PI;
+ }
+
+ // add several cubic bezier to approximate the arc
+ // (smaller than 90 degrees)
+ // we add one extra segment because we want something
+ // smaller than 90deg (i.e. not 90 itself)
+ var->segments = (int) (fabs(delta_theta / M_PI_2)) + 1;
+ var->delta = delta_theta / var->segments;
+
+ // http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt (section 2.13)
+ var->bcp = 4.0 / 3 * (1 - cos(var->delta / 2)) / sin(var->delta / 2);
+
+ var->cos_phi_rx = cos_phi * rx;
+ var->cos_phi_ry = cos_phi * ry;
+ var->sin_phi_rx = sin_phi * rx;
+ var->sin_phi_ry = sin_phi * ry;
+
+ var->cos_theta1 = cos(var->theta1);
+ var->sin_theta1 = sin(var->theta1);
+}
+
+static Eina_Bool
+_svg_path_grow(Efl_Tvg_Shape_Svg_Path *svg_path, int command_length)
+{
+ if (svg_path->pts_cnt + command_length > svg_path->pts_reserved)
+ {
+ Tvg_Point *pts_tmp = realloc(svg_path->pts, sizeof(Tvg_Point) *
+ (svg_path->pts_cnt + command_length) * 2);
+ if (!pts_tmp) return EINA_FALSE;
+ svg_path->pts_reserved = (svg_path->pts_cnt + command_length) * 2;
+ svg_path->pts = pts_tmp;
+ }
+
+ if (svg_path->cmds_cnt + 1 > svg_path->cmds_reserved)
+ {
+ Tvg_Path_Command *cmds_tmp = realloc(svg_path->cmds, sizeof(Tvg_Path_Command) *
+ (svg_path->cmds_cnt + 1) * 2);
+ if (!cmds_tmp) return EINA_FALSE;
+ svg_path->cmds_reserved = (svg_path->cmds_cnt + 1) * 2;
+ svg_path->cmds = cmds_tmp;
+ }
+
+ svg_path->pts_cnt += command_length;
+ svg_path->cmds_cnt++;
+
+ return EINA_TRUE;
+}
+
+static void
+_process_command(Efl_Tvg_Shape_Svg_Path *svg_path, char c, double *pts,
+ int *number_array, double *cur_x, double *cur_y,
+ double *cur_ctl_x, double *cur_ctl_y, Eina_Bool *is_quadratic)
+{
+ int i;
+ switch (c)
+ {
+ case 'm':
+ case 'l':
+ case 'c':
+ case 's':
+ case 'q':
+ case 't':
+ {
+ for(i = 0; i < *number_array - 1; i += 2)
+ {
+ pts[i] += *cur_x;
+ pts[i+1] += *cur_y;
+ }
+ break;
+ }
+ case 'h':
+ {
+ pts[0] += *cur_x;
+ break;
+ }
+ case 'v':
+ {
+ pts[0] += *cur_y;
+ break;
+ }
+ case 'a':
+ {
+ pts[5] += *cur_x;
+ pts[6] += *cur_y;
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (c)
+ {
+ case 'm':
+ case 'M':
+ {
+ if (!_svg_path_grow(svg_path, 1)) break;
+ svg_path->pts[svg_path->pts_cnt-1].x = pts[0];
+ svg_path->pts[svg_path->pts_cnt-1].y = pts[1];
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_MOVE_TO;
+ *cur_x = pts[0];
+ *cur_y = pts[1];
+ break;
+ }
+ case 'l':
+ case 'L':
+ {
+ if (!_svg_path_grow(svg_path, 1)) break;
+ svg_path->pts[svg_path->pts_cnt-1].x = pts[0];
+ svg_path->pts[svg_path->pts_cnt-1].y = pts[1];
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_LINE_TO;
+ *cur_x = pts[0];
+ *cur_y = pts[1];
+ break;
+ }
+ case 'c':
+ case 'C':
+ {
+ if (!_svg_path_grow(svg_path, 3)) break;
+ svg_path->pts[svg_path->pts_cnt-3].x = pts[0];
+ svg_path->pts[svg_path->pts_cnt-3].y = pts[1];
+ svg_path->pts[svg_path->pts_cnt-2].x = pts[2];
+ svg_path->pts[svg_path->pts_cnt-2].y = pts[3];
+ svg_path->pts[svg_path->pts_cnt-1].x = pts[4];
+ svg_path->pts[svg_path->pts_cnt-1].y = pts[5];
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_CUBIC_TO;
+ *cur_ctl_x = pts[2];
+ *cur_ctl_y = pts[3];
+ *cur_x = pts[4];
+ *cur_y = pts[5];
+ *is_quadratic = EINA_FALSE;
+ break;
+ }
+ case 's':
+ case 'S':
+ {
+ double ctrl_x, ctrl_y;
+ if ((svg_path->cmds_cnt > 1) && (svg_path->cmds[svg_path->cmds_cnt - 1] ==
+ TVG_PATH_COMMAND_CUBIC_TO) && !(*is_quadratic))
+ {
+ ctrl_x = *cur_x * 2 - *cur_ctl_x;
+ ctrl_y = *cur_y * 2 - *cur_ctl_y;
+ }
+ else
+ {
+ ctrl_x = *cur_x;
+ ctrl_y = *cur_y;
+ }
+ if (!_svg_path_grow(svg_path, 3)) break;
+ svg_path->pts[svg_path->pts_cnt-3].x = ctrl_x;
+ svg_path->pts[svg_path->pts_cnt-3].y = ctrl_y;
+ svg_path->pts[svg_path->pts_cnt-2].x = pts[0];
+ svg_path->pts[svg_path->pts_cnt-2].y = pts[1];
+ svg_path->pts[svg_path->pts_cnt-1].x = pts[2];
+ svg_path->pts[svg_path->pts_cnt-1].y = pts[3];
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_CUBIC_TO;
+ *cur_ctl_x = pts[0];
+ *cur_ctl_y = pts[1];
+ *cur_x = pts[2];
+ *cur_y = pts[3];
+ *is_quadratic = EINA_FALSE;
+ break;
+ }
+ case 'q':
+ case 'Q':
+ {
+ float ctrl_x0 = (*cur_x + 2 * pts[0]) * (1.0 / 3.0);
+ float ctrl_y0 = (*cur_y + 2 * pts[1]) * (1.0 / 3.0);
+ float ctrl_x1 = (pts[2] + 2 * pts[0]) * (1.0 / 3.0);
+ float ctrl_y1 = (pts[3] + 2 * pts[1]) * (1.0 / 3.0);
+ if (!_svg_path_grow(svg_path, 3)) break;
+ svg_path->pts[svg_path->pts_cnt-3].x = ctrl_x0;
+ svg_path->pts[svg_path->pts_cnt-3].y = ctrl_y0;
+ svg_path->pts[svg_path->pts_cnt-2].x = ctrl_x1;
+ svg_path->pts[svg_path->pts_cnt-2].y = ctrl_y1;
+ svg_path->pts[svg_path->pts_cnt-1].x = pts[2];
+ svg_path->pts[svg_path->pts_cnt-1].y = pts[3];
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_CUBIC_TO;
+ *cur_ctl_x = pts[0];
+ *cur_ctl_y = pts[1];
+ *cur_x = pts[2];
+ *cur_y = pts[3];
+ *is_quadratic = EINA_TRUE;
+ break;
+ }
+ case 't':
+ case 'T':
+ {
+ double ctrl_x, ctrl_y, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1;
+ if ((svg_path->cmds_cnt > 1) && (svg_path->cmds[svg_path->cmds_cnt - 1] ==
+ TVG_PATH_COMMAND_CUBIC_TO) && *is_quadratic)
+ {
+ ctrl_x = *cur_x * 2 - *cur_ctl_x;
+ ctrl_y = *cur_y * 2 - *cur_ctl_y;
+ }
+ else
+ {
+ ctrl_x = *cur_x;
+ ctrl_y = *cur_y;
+ }
+ ctrl_x0 = (*cur_x + 2 * ctrl_x) * (1.0 / 3.0);
+ ctrl_y0 = (*cur_y + 2 * ctrl_y) * (1.0 / 3.0);
+ ctrl_x1 = (pts[0] + 2 * ctrl_x) * (1.0 / 3.0);
+ ctrl_y1 = (pts[1] + 2 * ctrl_y) * (1.0 / 3.0);
+ if (!_svg_path_grow(svg_path, 3)) break;
+ svg_path->pts[svg_path->pts_cnt-3].x = ctrl_x0;
+ svg_path->pts[svg_path->pts_cnt-3].y = ctrl_y0;
+ svg_path->pts[svg_path->pts_cnt-2].x = ctrl_x1;
+ svg_path->pts[svg_path->pts_cnt-2].y = ctrl_y1;
+ svg_path->pts[svg_path->pts_cnt-1].x = pts[0];
+ svg_path->pts[svg_path->pts_cnt-1].y = pts[1];
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_CUBIC_TO;
+ *cur_ctl_x = ctrl_x;
+ *cur_ctl_y = ctrl_y;
+ *cur_x = pts[0];
+ *cur_y = pts[1];
+ *is_quadratic = EINA_TRUE;
+ break;
+ }
+ case 'h':
+ case 'H':
+ {
+ if (!_svg_path_grow(svg_path, 1)) break;
+ svg_path->pts[svg_path->pts_cnt-1].x = pts[0];
+ svg_path->pts[svg_path->pts_cnt-1].y = *cur_y;
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_LINE_TO;
+ *cur_x = pts[0];
+ break;
+ }
+ case 'v':
+ case 'V':
+ {
+ if (!_svg_path_grow(svg_path, 1)) break;
+ svg_path->pts[svg_path->pts_cnt-1].x = *cur_x;
+ svg_path->pts[svg_path->pts_cnt-1].y = pts[0];
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_LINE_TO;
+ *cur_y = pts[0];
+ break;
+ }
+ case 'a':
+ case 'A':
+ {
+ Arc_To_Init_Variables var;
+ double x, y, rx, ry;
+ double sx, sy, ex, ey;
+ double c1x, c1y, c2x, c2y;
+ double theta2;
+ double cos_theta2, sin_theta2;
+ int i;
+
+ x = pts[5];
+ y = pts[6];
+ rx = pts[0];
+ ry = pts[1];
+ sx = *cur_x;
+ sy = *cur_y;
+
+ // if start and end points are identical, then no arc is drawn
+ if ((fabs(x - sx) < (1 / 256.0)) && (fabs(y - sy) < (1 / 256.0)))
+ break;
+ rx = fabs(rx);
+ ry = fabs(ry);
+ if ((rx < 0.5) || (ry < 0.5))
+ {
+ _svg_path_grow(svg_path, 1);
+ svg_path->pts[svg_path->pts_cnt-1].x = x;
+ svg_path->pts[svg_path->pts_cnt-1].y = y;
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_LINE_TO;
+ *cur_x = x;
+ *cur_y = y;
+ break;
+ }
+
+ _arc_to_variables_initialization(x, y, rx, ry, pts[2], pts[3], pts[4],
+ sx, sy, &var);
+
+ for (i = 0; i < var.segments; ++i)
+ {
+ // end angle (for this segment) = current + delta
+ theta2 = var.theta1 + var.delta;
+ cos_theta2 = cos(theta2);
+ sin_theta2 = sin(theta2);
+
+ // first control point (based on start point sx,sy)
+ c1x = sx - var.bcp * (var.cos_phi_rx * var.sin_theta1 +
+ var.sin_phi_ry * var.cos_theta1);
+ c1y = sy + var.bcp * (var.cos_phi_ry * var.cos_theta1 -
+ var.sin_phi_rx * var.sin_theta1);
+
+ // end point (for this segment)
+ ex = var.cx + (var.cos_phi_rx * cos_theta2 -
+ var.sin_phi_ry * sin_theta2);
+ ey = var.cy + (var.sin_phi_rx * cos_theta2 +
+ var.cos_phi_ry * sin_theta2);
+
+ // second control point (based on end point ex,ey)
+ c2x = ex + var.bcp * (var.cos_phi_rx * sin_theta2 +
+ var.sin_phi_ry * cos_theta2);
+ c2y = ey + var.bcp * (var.sin_phi_rx * sin_theta2 -
+ var.cos_phi_ry * cos_theta2);
+
+ _svg_path_grow(svg_path, 3);
+ svg_path->pts[svg_path->pts_cnt-3].x = c1x;
+ svg_path->pts[svg_path->pts_cnt-3].y = c1y;
+ svg_path->pts[svg_path->pts_cnt-2].x = c2x;
+ svg_path->pts[svg_path->pts_cnt-2].y = c2y;
+ svg_path->pts[svg_path->pts_cnt-1].x = ex;
+ svg_path->pts[svg_path->pts_cnt-1].y = ey;
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_CUBIC_TO;
+
+ // next start point is the current end point (same for angle)
+ sx = ex;
+ sy = ey;
+ var.theta1 = theta2;
+ // avoid recomputations
+ var.cos_theta1 = cos_theta2;
+ var.sin_theta1 = sin_theta2;
+ }
+ *cur_ctl_x = ex;
+ *cur_ctl_y = ey;
+ *cur_x = ex;
+ *cur_y = ey;
+ *is_quadratic = EINA_FALSE;
+ break;
+ }
+ case 'z':
+ case 'Z':
+ {
+ if (!_svg_path_grow(svg_path, 0)) break;
+ svg_path->cmds[svg_path->cmds_cnt-1] = TVG_PATH_COMMAND_CLOSE;
+ break;
+ }
+ default:
+ break;
+ }
+}
+#endif
#ifndef EVAS_VG_PRIVATE_H_
# define EVAS_VG_PRIVATE_H_
-//TODO: Parametrize this include
-#include <Ector.h>
-
#ifdef HAVE_THORVG
#include <thorvg_capi.h>
+#else
+#include <Ector.h>
#endif
typedef struct _Efl_Canvas_Vg_Node_Data Efl_Canvas_Vg_Node_Data;
#ifdef HAVE_THORVG
Tvg_Canvas *tvg_canvas;
+ Eina_Size2D tvg_canvas_size;
uint32_t *tvg_buffer;
+ RGBA_Image *im;
#endif
};
Eina_Matrix3 *m;
Efl_Canvas_Vg_Interpolation *intp;
+#ifndef HAVE_THORVG
Ector_Renderer *renderer;
+#endif
Efl_VG *vg_obj;
Efl_Canvas_Vg_Object_Data *vd;
#ifdef HAVE_THORVG
void (*render_pre_tvg)(Evas_Object_Protected_Data *vg_pd, Efl_VG *node, Efl_Canvas_Vg_Node_Data *nd, void *canvas);
void (*render_tvg)(Evas_Object_Protected_Data *vg_pd, Efl_VG *node, Efl_Canvas_Vg_Node_Data *nd, void *canvas);
- void (*set_color)(Efl_Canvas_Vg_Node_Data *nd, int r, int g, int b, int a);
#endif
void *data;
unsigned int colors_count;
Efl_Gfx_Gradient_Spread spread;
+#ifdef HAVE_THORVG
+ Tvg_Gradient *gradient;
+ Evas_Vg_Shape *shape; // we need handle to shape to call node_change with it
+ void (*gradient_render_pre_tvg)(Efl_Canvas_Vg_Node *nd, Efl_Canvas_Vg_Gradient_Data *gd, Tvg_Paint *shape);
+#endif
};
struct _Efl_Canvas_Vg_Interpolation
if (nd) nd->render_pre(vg_pd, child, nd,
engine, output, context, surface,
transform, opacity, comp, comp_method, nd->data);
-#ifdef HAVE_THORVG
- //TODO: This function probably is not called when HAVE_THORVG is defined
- if (nd && nd->render_pre_tvg) nd->render_pre_tvg(vg_pd, child, nd, NULL);
-#endif
return nd;
}