efl/src/lib/ector/software/ector_renderer_software_sha...

843 lines
27 KiB
C

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <math.h>
#include <float.h>
#include <Eina.h>
#include <Ector.h>
#include <software/Ector_Software.h>
#include "ector_private.h"
#include "ector_software_private.h"
#define MY_CLASS ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS
typedef struct _Ector_Renderer_Software_Shape_Data Ector_Renderer_Software_Shape_Data;
typedef struct _Ector_Software_Shape_Task Ector_Software_Shape_Task;
struct _Ector_Software_Shape_Task
{
Ector_Renderer_Software_Shape_Data *pd;
const Efl_Gfx_Path_Command *cmds;
const double *pts;
Efl_Gfx_Fill_Rule fill_rule;
};
struct _Ector_Renderer_Software_Shape_Data
{
Efl_Gfx_Shape_Public *public_shape;
Ector_Software_Surface_Data *surface;
Ector_Renderer_Shape_Data *shape;
Ector_Renderer_Data *base;
Shape_Rle_Data *shape_data;
Shape_Rle_Data *outline_data;
Ector_Buffer *comp;
Efl_Gfx_Vg_Composite_Method comp_method;
Ector_Software_Shape_Task *task;
Eina_Bool done;
};
typedef struct _Outline
{
SW_FT_Outline ft_outline;
int points_alloc;
int contours_alloc;
} Outline;
#define TO_FT_COORD(x) ((x) * 64) // to freetype 26.6 coordinate.
static inline void
_grow_outline_contour(Outline *outline, int num)
{
if ( outline->ft_outline.n_contours + num > outline->contours_alloc)
{
outline->contours_alloc += 5;
outline->ft_outline.contours = (short *) realloc(outline->ft_outline.contours,
outline->contours_alloc * sizeof(short));
}
}
static inline void
_grow_outline_points(Outline *outline, int num)
{
if ( outline->ft_outline.n_points + num > outline->points_alloc)
{
outline->points_alloc += 50;
outline->ft_outline.points = (SW_FT_Vector *) realloc(outline->ft_outline.points,
outline->points_alloc * sizeof(SW_FT_Vector));
outline->ft_outline.tags = (char *) realloc(outline->ft_outline.tags,
outline->points_alloc * sizeof(char));
}
}
static Outline *
_outline_create()
{
Outline *outline = (Outline *) calloc(1, sizeof(Outline));
outline->points_alloc = 0;
outline->contours_alloc = 0;
_grow_outline_contour(outline, 1);
_grow_outline_points(outline, 1);
return outline;
}
static
void _outline_destroy(Outline *outline)
{
if (outline)
{
free(outline->ft_outline.points);
free(outline->ft_outline.tags);
free(outline->ft_outline.contours);
free(outline);
}
}
static void
_outline_move_to(Outline *outline, double x, double y)
{
SW_FT_Outline *ft_outline = &outline->ft_outline;
_grow_outline_points(outline, 1);
ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
if (ft_outline->n_points)
{
_grow_outline_contour(outline, 1);
ft_outline->contours[ft_outline->n_contours] = ft_outline->n_points - 1;
ft_outline->n_contours++;
}
ft_outline->n_points++;
}
static void
_outline_end(Outline *outline)
{
SW_FT_Outline *ft_outline = &outline->ft_outline;
_grow_outline_contour(outline, 1);
if (ft_outline->n_points)
{
ft_outline->contours[ft_outline->n_contours] = ft_outline->n_points - 1;
ft_outline->n_contours++;
}
}
static void _outline_line_to(Outline *outline, double x, double y)
{
SW_FT_Outline *ft_outline = &outline->ft_outline;
_grow_outline_points(outline, 1);
ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
ft_outline->n_points++;
}
static Eina_Bool
_outline_close_path(Outline *outline)
{
SW_FT_Outline *ft_outline = &outline->ft_outline;
int index ;
if (ft_outline->n_contours)
{
index = ft_outline->contours[ft_outline->n_contours - 1] + 1;
}
else
{
// First path
index = 0;
}
// Make sure there is at least one point in the current path
if (ft_outline->n_points == index) return EINA_FALSE;
// Close the path
_grow_outline_points(outline, 1);
ft_outline->points[ft_outline->n_points].x = ft_outline->points[index].x;
ft_outline->points[ft_outline->n_points].y = ft_outline->points[index].y;
ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
ft_outline->n_points++;
return EINA_TRUE;
}
static void _outline_cubic_to(Outline *outline, double cx1, double cy1,
double cx2, double cy2, double x, double y)
{
SW_FT_Outline *ft_outline = &outline->ft_outline;
_grow_outline_points(outline, 3);
ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(cx1);
ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(cy1);
ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_CUBIC;
ft_outline->n_points++;
ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(cx2);
ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(cy2);
ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_CUBIC;
ft_outline->n_points++;
ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
ft_outline->n_points++;
}
static void _outline_transform(Outline *outline, Eina_Matrix3 *m)
{
int i;
double x, y;
SW_FT_Outline *ft_outline = &outline->ft_outline;
if (m && (eina_matrix3_type_get(m) != EINA_MATRIX_TYPE_IDENTITY))
{
for (i = 0; i < ft_outline->n_points; i++)
{
eina_matrix3_point_transform(m,
ft_outline->points[i].x/64.0,/* convert back to normal coord.*/
ft_outline->points[i].y/64.0,/* convert back to normal coord.*/
&x, &y);
ft_outline->points[i].x = TO_FT_COORD(x);
ft_outline->points[i].y = TO_FT_COORD(y);
}
}
}
static Eina_Bool
_generate_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline)
{
Eina_Bool close_path = EINA_FALSE;
for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
{
switch (*cmds)
{
case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
_outline_move_to(outline, pts[0], pts[1]);
pts += 2;
break;
case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
_outline_line_to(outline, pts[0], pts[1]);
pts += 2;
break;
case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
_outline_cubic_to(outline,
pts[0], pts[1], pts[2], pts[3], // control points
pts[4], pts[5]); // destination point
pts += 6;
break;
case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
close_path = _outline_close_path(outline);
break;
case EFL_GFX_PATH_COMMAND_TYPE_LAST:
case EFL_GFX_PATH_COMMAND_TYPE_END:
break;
}
}
_outline_end(outline);
return close_path;
}
typedef struct _Line
{
double x1;
double y1;
double x2;
double y2;
}Line;
static void
_line_value_set(Line *l, double x1, double y1, double x2, double y2)
{
l->x1 = x1;
l->y1 = y1;
l->x2 = x2;
l->y2 = y2;
}
// approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
// With alpha = 1, beta = 3/8, giving results with the largest error less
// than 7% compared to the exact value.
static double
_line_length(Line *l)
{
double x = l->x2 - l->x1;
double y = l->y2 - l->y1;
x = x < 0 ? -x : x;
y = y < 0 ? -y : y;
return (x > y ? x + 0.375 * y : y + 0.375 * x);
}
static void
_line_split_at_length(Line *l, double length, Line *left, Line *right)
{
double len = _line_length(l);
double dx = ((l->x2 - l->x1)/len) *length;
double dy = ((l->y2 - l->y1)/len) *length;
left->x1 = l->x1;
left->y1 = l->y1;
left->x2 = left->x1 + dx;
left->y2 = left->y1 + dy;
right->x1 = left->x2;
right->y1 = left->y2;
right->x2 = l->x2;
right->y2 = l->y2;
}
typedef struct _Dash_Stroker
{
Efl_Gfx_Dash *dash;
int dash_len;
Outline *outline;
int cur_dash_index;
double cur_dash_length;
Eina_Bool cur_op_gap;
double start_x, start_y;
double cur_x, cur_y;
}Dash_Stroker;
static void
_dasher_line_to(Dash_Stroker *dasher, double x, double y)
{
Line l, left, right;
double line_len = 0.0;
_line_value_set(&l, dasher->cur_x, dasher->cur_y, x, y);
line_len = _line_length(&l);
if (line_len < dasher->cur_dash_length)
{
dasher->cur_dash_length -= line_len;
if (!dasher->cur_op_gap)
{
_outline_move_to(dasher->outline, dasher->cur_x, dasher->cur_y);
_outline_line_to(dasher->outline, x, y);
}
}
else
{
while (line_len > dasher->cur_dash_length)
{
line_len -= dasher->cur_dash_length;
_line_split_at_length(&l, dasher->cur_dash_length, &left, &right);
if (!dasher->cur_op_gap)
{
_outline_move_to(dasher->outline, left.x1, left.y1);
_outline_line_to(dasher->outline, left.x2, left.y2);
dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
}
else
{
dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
}
dasher->cur_op_gap = !dasher->cur_op_gap;
l = right;
dasher->cur_x = l.x1;
dasher->cur_y = l.y1;
}
// remainder
dasher->cur_dash_length -= line_len;
if (!dasher->cur_op_gap)
{
_outline_move_to(dasher->outline, l.x1, l.y1);
_outline_line_to(dasher->outline, l.x2, l.y2);
}
if (dasher->cur_dash_length < 1.0)
{
// move to next dash
if (!dasher->cur_op_gap)
{
dasher->cur_op_gap = EINA_TRUE;
dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
}
else
{
dasher->cur_op_gap = EINA_FALSE;
dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
}
}
}
dasher->cur_x = x;
dasher->cur_y = y;
}
static void
_dasher_cubic_to(Dash_Stroker *dasher, double cx1 , double cy1, double cx2, double cy2, double x, double y)
{
Eina_Bezier b, left, right;
double bez_len = 0.0;
eina_bezier_values_set(&b, dasher->cur_x, dasher->cur_y, cx1, cy1, cx2, cy2, x, y);
bez_len = eina_bezier_length_get(&b);
if (bez_len < dasher->cur_dash_length)
{
dasher->cur_dash_length -= bez_len;
if (!dasher->cur_op_gap)
{
_outline_move_to(dasher->outline, dasher->cur_x, dasher->cur_y);
_outline_cubic_to(dasher->outline, cx1, cy1, cx2, cy2, x, y);
}
}
else
{
while (bez_len > dasher->cur_dash_length)
{
bez_len -= dasher->cur_dash_length;
eina_bezier_split_at_length(&b, dasher->cur_dash_length, &left, &right);
if (!dasher->cur_op_gap)
{
_outline_move_to(dasher->outline, left.start.x, left.start.y);
_outline_cubic_to(dasher->outline, left.ctrl_start.x, left.ctrl_start.y, left.ctrl_end.x, left.ctrl_end.y, left.end.x, left.end.y);
dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
}
else
{
dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
}
dasher->cur_op_gap = !dasher->cur_op_gap;
b = right;
dasher->cur_x = b.start.x;
dasher->cur_y = b.start.y;
}
// remainder
dasher->cur_dash_length -= bez_len;
if (!dasher->cur_op_gap)
{
_outline_move_to(dasher->outline, b.start.x, b.start.y);
_outline_cubic_to(dasher->outline, b.ctrl_start.x, b.ctrl_start.y, b.ctrl_end.x, b.ctrl_end.y, b.end.x, b.end.y);
}
if (dasher->cur_dash_length < 1.0)
{
// move to next dash
if (!dasher->cur_op_gap)
{
dasher->cur_op_gap = EINA_TRUE;
dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
}
else
{
dasher->cur_op_gap = EINA_FALSE;
dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
}
}
}
dasher->cur_x = x;
dasher->cur_y = y;
}
static Eina_Bool
_generate_dashed_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline, Efl_Gfx_Dash *dash, int dash_len)
{
Dash_Stroker dasher;
dasher.dash = dash;
dasher.dash_len = dash_len;
dasher.outline = outline;
dasher.cur_dash_length = 0.0;
dasher.cur_dash_index = 0;
dasher.cur_op_gap = EINA_FALSE;
dasher.start_x = 0.0;
dasher.start_y = 0.0;
dasher.cur_x = 0.0;
dasher.cur_y = 0.0;
for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
{
switch (*cmds)
{
case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
{
// reset the dash
dasher.cur_dash_index = 0;
dasher.cur_dash_length = dasher.dash[0].length;
dasher.cur_op_gap = EINA_FALSE;
dasher.start_x = pts[0];
dasher.start_y = pts[1];
dasher.cur_x = pts[0];
dasher.cur_y = pts[1];
pts += 2;
}
break;
case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
_dasher_line_to(&dasher, pts[0], pts[1]);
pts += 2;
break;
case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
_dasher_cubic_to(&dasher, pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
pts += 6;
break;
case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
_dasher_line_to(&dasher, dasher.start_x, dasher.start_y);
break;
case EFL_GFX_PATH_COMMAND_TYPE_LAST:
case EFL_GFX_PATH_COMMAND_TYPE_END:
break;
}
}
_outline_end(outline);
return EINA_FALSE;
}
static Eina_Bool
_generate_stroke_data(Ector_Renderer_Software_Shape_Data *pd)
{
if (pd->outline_data) return EINA_FALSE;
if (!pd->shape->stroke.fill &&
((pd->public_shape->stroke.color.a == 0) ||
(pd->public_shape->stroke.width < 0.01)))
return EINA_FALSE;
return EINA_TRUE;
}
static Eina_Bool
_generate_shape_data(Ector_Renderer_Software_Shape_Data *pd)
{
if (pd->shape_data) return EINA_FALSE;
if (!pd->shape->fill && (pd->base->color.a == 0)) return EINA_FALSE;
return EINA_TRUE;
}
static Ector_Software_Shape_Task *
_need_update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
{
Ector_Software_Shape_Task *r;
const Efl_Gfx_Path_Command *cmds;
const double *pts;
Efl_Gfx_Fill_Rule fill_rule;
if (!pd->done && pd->task) return pd->task;
if (!_generate_stroke_data(pd) &&
!_generate_shape_data(pd))
return NULL;
efl_gfx_path_get(obj, &cmds, &pts);
fill_rule = efl_gfx_shape_fill_rule_get(obj);
if (!cmds) return NULL;
r = pd->task;
if (!r) r = malloc(sizeof (Ector_Software_Shape_Task));
if (!r) return NULL;
r->pd = pd;
r->cmds = cmds;
r->pts = pts;
r->fill_rule = fill_rule;
pd->done = EINA_FALSE;
pd->task = r;
return r;
}
static void
_done_rle(void *data)
{
Ector_Software_Shape_Task *task = data;
if (task && task->pd)
task->pd->done = EINA_TRUE;
}
static void
_update_rle(void *data, Ector_Software_Thread *thread)
{
Ector_Software_Shape_Task *task = data;
Eina_Bool close_path;
Outline *outline, *dash_outline;
outline = _outline_create();
close_path = _generate_outline(task->cmds, task->pts, outline);
if (task->fill_rule == EFL_GFX_FILL_RULE_ODD_EVEN)
outline->ft_outline.flags = SW_FT_OUTLINE_EVEN_ODD_FILL;
else
outline->ft_outline.flags = SW_FT_OUTLINE_NONE; // default is winding fill
_outline_transform(outline, task->pd->base->m);
//shape data generation
if (_generate_shape_data(task->pd))
task->pd->shape_data = ector_software_rasterizer_generate_rle_data(thread,
task->pd->surface->rasterizer,
&outline->ft_outline);
//stroke data generation
if (_generate_stroke_data(task->pd))
{
ector_software_rasterizer_stroke_set(thread, task->pd->surface->rasterizer,
(task->pd->public_shape->stroke.width *
task->pd->public_shape->stroke.scale),
task->pd->public_shape->stroke.cap,
task->pd->public_shape->stroke.join,
task->pd->base->m,
task->pd->public_shape->stroke.miterlimit);
if (task->pd->public_shape->stroke.dash)
{
dash_outline = _outline_create();
close_path = _generate_dashed_outline(task->cmds, task->pts, dash_outline,
task->pd->public_shape->stroke.dash,
task->pd->public_shape->stroke.dash_length);
_outline_transform(dash_outline, task->pd->base->m);
task->pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(thread,
task->pd->surface->rasterizer,
&dash_outline->ft_outline,
close_path);
_outline_destroy(dash_outline);
}
else
{
task->pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(thread,
task->pd->surface->rasterizer,
&outline->ft_outline,
close_path);
}
}
_outline_destroy(outline);
}
static Eina_Bool
_ector_renderer_software_shape_ector_renderer_prepare(Eo *obj,
Ector_Renderer_Software_Shape_Data *pd)
{
Ector_Software_Shape_Task *task;
// FIXME: shouldn't this be moved to the software base object?
if (!pd->surface)
pd->surface = efl_data_xref(pd->base->surface, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
// Asynchronously lazy build of the RLE data for this shape
task = _need_update_rle(obj, pd);
if (task) ector_software_schedule(_update_rle, _done_rle, task);
return EINA_TRUE;
}
static Eina_Bool
_ector_renderer_software_shape_ector_renderer_draw(Eo *obj,
Ector_Renderer_Software_Shape_Data *pd,
Efl_Gfx_Render_Op op, Eina_Array *clips,
unsigned int mul_col)
{
Ector_Software_Shape_Task *task;
int x, y;
// check if RLE data are ready
task = _need_update_rle(obj, pd);
if (task) ector_software_wait(_update_rle, _done_rle, task);
// adjust the offset
x = pd->surface->x + (int)pd->base->origin.x;
y = pd->surface->y + (int)pd->base->origin.y;
ector_software_rasterizer_clip_rect_set(pd->surface->rasterizer, clips);
ector_software_rasterizer_transform_set(pd->surface->rasterizer, pd->base->m);
// fill the span_data structure
if (pd->shape->fill)
{
ector_renderer_software_op_fill(pd->shape->fill);
ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
x, y, mul_col, op,
pd->shape_data,
pd->comp,
pd->comp_method);
}
else
{
if (pd->base->color.a > 0)
{
ector_software_rasterizer_color_set(pd->surface->rasterizer,
pd->base->color.r,
pd->base->color.g,
pd->base->color.b,
pd->base->color.a);
ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
x, y, mul_col, op,
pd->shape_data,
pd->comp,
pd->comp_method);
}
}
if (!pd->outline_data) return EINA_TRUE;
if (pd->shape->stroke.fill)
{
ector_renderer_software_op_fill(pd->shape->stroke.fill);
ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
x, y, mul_col, op,
pd->outline_data,
pd->comp,
pd->comp_method);
}
else
{
if (pd->public_shape->stroke.color.a > 0)
{
ector_software_rasterizer_color_set(pd->surface->rasterizer,
pd->public_shape->stroke.color.r,
pd->public_shape->stroke.color.g,
pd->public_shape->stroke.color.b,
pd->public_shape->stroke.color.a);
ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
x, y, mul_col, op,
pd->outline_data,
pd->comp,
pd->comp_method);
}
}
return EINA_TRUE;
}
static Eina_Bool
_ector_renderer_software_shape_ector_renderer_software_op_fill(Eo *obj EINA_UNUSED,
Ector_Renderer_Software_Shape_Data *pd 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 software.
return EINA_FALSE;
}
EOLIAN static void
_ector_renderer_software_shape_efl_gfx_path_commit(Eo *obj EINA_UNUSED,
Ector_Renderer_Software_Shape_Data *pd)
{
if (pd->shape_data)
{
ector_software_rasterizer_destroy_rle_data(pd->shape_data);
pd->shape_data = NULL;
}
if (pd->outline_data)
{
ector_software_rasterizer_destroy_rle_data(pd->outline_data);
pd->outline_data = NULL;
}
}
static Eo *
_ector_renderer_software_shape_efl_object_constructor(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
if (!obj) return NULL;
pd->task = NULL;
pd->done = EINA_FALSE;
pd->public_shape = efl_data_xref(obj, EFL_GFX_SHAPE_MIXIN, obj);
pd->shape = efl_data_xref(obj, ECTOR_RENDERER_SHAPE_MIXIN, obj);
pd->base = efl_data_xref(obj, ECTOR_RENDERER_CLASS, obj);
return obj;
}
static void
_ector_renderer_software_shape_efl_object_destructor(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
{
// FIXME: As base class, destructor can't call destructor of mixin class.
// Call explicit API to free shape data.
if (!pd->done && pd->task)
ector_software_wait(_update_rle, _done_rle, pd->task);
efl_gfx_path_reset(obj);
if (pd->shape_data) ector_software_rasterizer_destroy_rle_data(pd->shape_data);
if (pd->outline_data) ector_software_rasterizer_destroy_rle_data(pd->outline_data);
free(pd->task);
efl_data_xunref(pd->base->surface, pd->surface, obj);
efl_data_xunref(obj, pd->base, obj);
efl_data_xunref(obj, pd->shape, obj);
efl_data_xunref(obj, pd->public_shape, obj);
efl_destructor(efl_super(obj, MY_CLASS));
}
unsigned int
_ector_renderer_software_shape_ector_renderer_crc_get(const Eo *obj,
Ector_Renderer_Software_Shape_Data *pd)
{
unsigned int crc;
crc = ector_renderer_crc_get(efl_super(obj, MY_CLASS));
crc = eina_crc((void*) &pd->shape->stroke.marker,
sizeof (pd->shape->stroke.marker),
crc, EINA_FALSE);
crc = eina_crc((void*) &pd->public_shape->stroke.scale,
sizeof (pd->public_shape->stroke.scale) * 3,
crc, EINA_FALSE); // scale, width, centered
crc = eina_crc((void*) &pd->public_shape->stroke.color,
sizeof (pd->public_shape->stroke.color),
crc, EINA_FALSE);
crc = eina_crc((void*) &pd->public_shape->stroke.cap,
sizeof (pd->public_shape->stroke.cap),
crc, EINA_FALSE);
crc = eina_crc((void*) &pd->public_shape->stroke.join,
sizeof (pd->public_shape->stroke.join),
crc, EINA_FALSE);
if (pd->shape->fill)
crc = _renderer_crc_get(pd->shape->fill, crc);
if (pd->shape->stroke.fill)
crc = _renderer_crc_get(pd->shape->stroke.fill, crc);
if (pd->shape->stroke.marker)
crc = _renderer_crc_get(pd->shape->stroke.marker, crc);
if (pd->public_shape->stroke.dash_length)
{
crc = eina_crc((void*) pd->public_shape->stroke.dash,
sizeof (Efl_Gfx_Dash) * pd->public_shape->stroke.dash_length,
crc, EINA_FALSE);
}
return crc;
}
static void
_ector_renderer_software_shape_ector_renderer_comp_method_set(Eo *obj EINA_UNUSED,
Ector_Renderer_Software_Shape_Data *pd,
Ector_Buffer *comp,
Efl_Gfx_Vg_Composite_Method method)
{
//Use ref/unref.
pd->comp = comp;
pd->comp_method = method;
}
#include "ector_renderer_software_shape.eo.c"