#include "ector_software_private.h"
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;
+ Efl_Gfx_Shape_Public *public_shape;
- Ector_Software_Surface_Data *surface;
+ Ector_Software_Surface_Data *surface;
Ector_Renderer_Shape_Data *shape;
- Ector_Renderer_Data *base;
+ Ector_Renderer_Data *base;
- Shape_Rle_Data *shape_data;
- Shape_Rle_Data *outline_data;
+ Shape_Rle_Data *shape_data;
+ Shape_Rle_Data *outline_data;
+
+ Ector_Software_Shape_Task *task;
+
+ Eina_Bool done;
};
typedef struct _Outline
return EINA_TRUE;
}
-static void
-_update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
+static Ector_Software_Shape_Task *
+_need_update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
{
- const Efl_Gfx_Path_Command *cmds = NULL;
- const double *pts = NULL;
- Eina_Bool close_path;
+ Ector_Software_Shape_Task *r;
+ const Efl_Gfx_Path_Command *cmds;
+ const double *pts;
Efl_Gfx_Fill_Rule fill_rule;
- Outline *outline, *dash_outline;
+
+ 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 && (_generate_stroke_data(pd) || _generate_shape_data(pd)))
- {
- outline = _outline_create();
- close_path = _generate_outline(cmds, pts, outline);
- if (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, pd->base->m);
+ 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;
- //shape data generation
- if (_generate_shape_data(pd))
- pd->shape_data = ector_software_rasterizer_generate_rle_data(pd->surface->rasterizer,
- &outline->ft_outline);
+ return r;
+}
+
+static void
+_done_rle(void *data)
+{
+ Ector_Software_Shape_Task *task = data;
+
+ task->pd->done = EINA_TRUE;
+}
- //stroke data generation
- if ( _generate_stroke_data(pd))
+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);
+
+ if (task->pd->public_shape->stroke.dash)
{
- ector_software_rasterizer_stroke_set(pd->surface->rasterizer,
- (pd->public_shape->stroke.width *
- pd->public_shape->stroke.scale),
- pd->public_shape->stroke.cap,
- pd->public_shape->stroke.join,
- pd->base->m);
-
- if (pd->public_shape->stroke.dash)
- {
- dash_outline = _outline_create();
- close_path = _generate_dashed_outline(cmds, pts, dash_outline,
- pd->public_shape->stroke.dash,
- pd->public_shape->stroke.dash_length);
- _outline_transform(dash_outline, pd->base->m);
- pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->rasterizer,
- &dash_outline->ft_outline,
- close_path);
- _outline_destroy(dash_outline);
- }
- else
- {
- pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->rasterizer,
- &outline->ft_outline,
- close_path);
- }
+ 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);
}
+ _outline_destroy(outline);
}
static Eina_Bool
_ector_renderer_software_shape_ector_renderer_prepare(Eo *obj,
- Ector_Renderer_Software_Shape_Data *pd)
+ Ector_Renderer_Software_Shape_Data *pd)
{
+ Ector_Software_Shape_Task *task;
+
// FIXME: shouldn't this be part of the shape generic implementation?
if (pd->shape->fill)
ector_renderer_prepare(pd->shape->fill);
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_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;
- // do lazy creation of rle
- _update_rle(obj, pd);
+ // 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;
_ector_renderer_software_shape_path_changed(void *data, const Efl_Event *event EINA_UNUSED)
{
Ector_Renderer_Software_Shape_Data *pd = data;
-
+
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);
-
+
pd->shape_data = NULL;
pd->outline_data = NULL;
}
obj = efl_constructor(efl_super(obj, ECTOR_RENDERER_SOFTWARE_SHAPE_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);
{
// 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->shape, obj);
}
}
-void ector_software_rasterizer_init(Software_Rasterizer *rasterizer)
+void ector_software_thread_init(Ector_Software_Thread *thread)
{
// initialize the rasterizer and stroker
- sw_ft_grays_raster.raster_new(&rasterizer->raster);
+ sw_ft_grays_raster.raster_new(&thread->raster);
- SW_FT_Stroker_New(&rasterizer->stroker);
- SW_FT_Stroker_Set(rasterizer->stroker, 1<<6,SW_FT_STROKER_LINECAP_BUTT,SW_FT_STROKER_LINEJOIN_MITER,0);
+ SW_FT_Stroker_New(&thread->stroker);
+ SW_FT_Stroker_Set(thread->stroker, 1 << 6,
+ SW_FT_STROKER_LINECAP_BUTT, SW_FT_STROKER_LINEJOIN_MITER, 0);
+}
+void ector_software_rasterizer_init(Software_Rasterizer *rasterizer)
+{
//initialize the span data.
rasterizer->fill_data.clip.enabled = EINA_FALSE;
rasterizer->fill_data.unclipped_blend = 0;
ector_software_gradient_init();
}
-void ector_software_rasterizer_done(Software_Rasterizer *rasterizer)
+void ector_software_thread_shutdown(Ector_Software_Thread *thread)
{
- sw_ft_grays_raster.raster_done(rasterizer->raster);
- SW_FT_Stroker_Done(rasterizer->stroker);
+ sw_ft_grays_raster.raster_done(thread->raster);
+ SW_FT_Stroker_Done(thread->stroker);
}
-void ector_software_rasterizer_stroke_set(Software_Rasterizer *rasterizer, double width,
+void ector_software_rasterizer_stroke_set(Ector_Software_Thread *thread,
+ Software_Rasterizer *rasterizer EINA_UNUSED, double width,
Efl_Gfx_Cap cap_style, Efl_Gfx_Join join_style,
Eina_Matrix3 *m)
{
join = SW_FT_STROKER_LINEJOIN_MITER;
break;
}
- SW_FT_Stroker_Set(rasterizer->stroker, stroke_width, cap, join, 0);
+ SW_FT_Stroker_Set(thread->stroker, stroke_width, cap, join, 0);
}
static void
}
Shape_Rle_Data *
-ector_software_rasterizer_generate_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline)
+ector_software_rasterizer_generate_rle_data(Ector_Software_Thread *thread,
+ Software_Rasterizer *rasterizer EINA_UNUSED,
+ SW_FT_Outline *outline)
{
int i, rle_size;
int l = 0, t = 0, r = 0, b = 0;
params.user = rle_data;
params.source = outline;
- sw_ft_grays_raster.raster_render(rasterizer->raster, ¶ms);
+ sw_ft_grays_raster.raster_render(thread->raster, ¶ms);
// update RLE bounding box.
span = rle_data->spans;
}
Shape_Rle_Data *
-ector_software_rasterizer_generate_stroke_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline, Eina_Bool closePath)
+ector_software_rasterizer_generate_stroke_rle_data(Ector_Software_Thread *thread,
+ Software_Rasterizer *rasterizer,
+ SW_FT_Outline *outline,
+ Eina_Bool closePath)
{
uint32_t points,contors;
Shape_Rle_Data *rle_data;
SW_FT_Outline strokeOutline = { 0, 0, NULL, NULL, NULL, 0 };
- SW_FT_Stroker_ParseOutline(rasterizer->stroker, outline, !closePath);
- SW_FT_Stroker_GetCounts(rasterizer->stroker,&points, &contors);
+ SW_FT_Stroker_ParseOutline(thread->stroker, outline, !closePath);
+ SW_FT_Stroker_GetCounts(thread->stroker,&points, &contors);
strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector));
strokeOutline.tags = (char *) calloc(points, sizeof(char));
strokeOutline.contours = (short *) calloc(contors, sizeof(short));
- SW_FT_Stroker_Export(rasterizer->stroker, &strokeOutline);
+ SW_FT_Stroker_Export(thread->stroker, &strokeOutline);
- rle_data = ector_software_rasterizer_generate_rle_data(rasterizer, &strokeOutline);
+ rle_data = ector_software_rasterizer_generate_rle_data(thread, rasterizer, &strokeOutline);
// cleanup the outline data.
free(strokeOutline.points);