Efl.Canvas.Vg.Object: Optimize Ector Surface Size

Summary:
The ector surface size was determined by the size of the vg object.
vg object is usually sized by the size of the container.
So, the ector surface is set unnecessarily large.
This patch sets the ector surface size to the path boundary.
And the path boundary refers to the stroke width and miterlimit.

Test Plan:
vector sample
{F3887634}
{F3887632}

[grey area is ector surface size]
{F3887633}

Reviewers: Hermet, kimcinoo, smohanty, herb

Reviewed By: Hermet

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D11865
This commit is contained in:
junsu choi 2020-06-03 11:37:23 +09:00 committed by Hermet Park
parent e94b5d014f
commit 442fae5c56
5 changed files with 87 additions and 16 deletions

View File

@ -654,8 +654,8 @@ _ector_renderer_software_shape_ector_renderer_draw(Eo *obj EINA_UNUSED,
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;
x = (int)pd->base->origin.x - pd->surface->x;
y = (int)pd->base->origin.y - pd->surface->y;
ector_software_rasterizer_clip_rect_set(pd->surface->rasterizer, clips);
ector_software_rasterizer_transform_set(pd->surface->rasterizer, pd->base->m);

View File

@ -3319,17 +3319,23 @@ _edje_vector_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3 EIN
}
else
{
Eina_Rect viewbox;
snprintf(dest_key, sizeof(dest_key), "edje/vectors/%i", new_id);
efl_file_simple_load(ep->object, ed->file->path, src_key);
src_root = efl_canvas_vg_object_root_node_get(ep->object);
efl_ref(src_root);
// Note: Assume that the viewboxes of two interpolation objects are the same.
viewbox = efl_canvas_vg_object_viewbox_get(ep->object);
efl_file_simple_load(ep->object, ed->file->path, dest_key);
dest_root = efl_canvas_vg_object_root_node_get(ep->object);
efl_ref(dest_root);
root = efl_duplicate(src_root);
efl_canvas_vg_object_viewbox_set(ep->object, viewbox);
if (!efl_gfx_path_interpolate(root, src_root, dest_root, pos))
ERR("Can't interpolate check the svg file");

View File

@ -280,15 +280,46 @@ _efl_canvas_vg_container_efl_gfx_path_bounds_get(const Eo *obj EINA_UNUSED,
EINA_LIST_FOREACH(pd->children, l, child)
{
Eina_Position2D pos = efl_gfx_entity_position_get(child);
double miterlimit = 0.0, stroke_gap = 0.0;
if (efl_isa(child, EFL_CANVAS_VG_SHAPE_CLASS))
{
miterlimit = efl_gfx_shape_stroke_miterlimit_get(child);
stroke_gap = efl_gfx_shape_stroke_width_get(child) * (miterlimit <= 0 ? 1 : miterlimit);
}
if (first)
{
efl_gfx_path_bounds_get(child, r);
first = EINA_FALSE;
if (r->size.w != 0 && r->size.h != 0)
{
r->pos.x += pos.x;
r->pos.y += pos.y;
if (stroke_gap > 1.0)
{
r->pos.x -= (int)(stroke_gap/2.0);
r->pos.y -= (int)(stroke_gap/2.0);
r->size.w += (int)(stroke_gap);
r->size.h += (int)(stroke_gap);
}
first = EINA_FALSE;
}
}
else
{
efl_gfx_path_bounds_get(child, &s);
eina_rectangle_union(&r->rect, &s.rect);
if (s.size.w != 0 && s.size.h != 0)
{
s.pos.x += pos.x;
s.pos.y += pos.y;
if (stroke_gap > 1.0)
{
s.pos.x -= (int)(stroke_gap/2.0);
s.pos.y -= (int)(stroke_gap/2.0);
s.size.w += (int)(stroke_gap);
s.size.h += (int)(stroke_gap);
}
eina_rectangle_union(&r->rect, &s.rect);
}
}
}
}

View File

@ -293,6 +293,11 @@ _efl_canvas_vg_object_efl_file_load(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd)
file, key,
obj->cur->geometry.w,
obj->cur->geometry.h, NULL);
// NOTE: Update object's viewbox. In this case, there is no need to update
// the root of tree. That's why We don't use viewbox_set.
pd->viewbox.rect = pd->vg_entry->vfd->view_box;
evas_object_change(eo_obj, obj);
pd->changed = EINA_TRUE;
@ -504,7 +509,7 @@ _evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
//renders a vg_tree to an offscreen buffer and push it to the cache.
static void *
_render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
void *engine, Efl_VG *root, int w, int h, void *buffer, void *ckey,
void *engine, Efl_VG *root, int x, int y, int w, int h, void *buffer, void *ckey,
Eina_Bool do_async)
{
Ector_Surface *ector;
@ -532,7 +537,7 @@ _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd
_evas_vg_render_pre(obj, root, engine, buffer, context, ector, NULL, 255, NULL, 0);
//Actual content drawing
if (!ENFN->ector_begin(engine, buffer, context, ector, 0, 0, do_async))
if (!ENFN->ector_begin(engine, buffer, context, ector, x, y, do_async))
{
ERR("Failed ector begin!");
return NULL;
@ -688,7 +693,7 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
if (!buffer)
{
buffer = _render_to_buffer(obj, pd, engine, root, w, h, NULL, key, do_async);
buffer = _render_to_buffer(obj, pd, engine, root, 0, 0, w, h, NULL, key, do_async);
}
else
{
@ -710,26 +715,52 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
int x, int y, int w, int h, Eina_Bool do_async)
{
Vg_User_Entry *user_entry = pd->user_entry;
Eina_Rect render_rect = EINA_RECT(x, y, w, h);
// Get changed boundary and fit the size.
Eina_Rect r;
if (pd->changed)
efl_gfx_path_bounds_get(user_entry->root, &user_entry->path_bounds);
EINA_RECTANGLE_SET(&r, user_entry->path_bounds.x,
user_entry->path_bounds.y,
user_entry->path_bounds.w,
user_entry->path_bounds.h);
if (pd->viewbox.w != 0 || pd->viewbox.h !=0)
{
double sx = 0, sy= 0;
sx = (double)render_rect.w / (double)pd->viewbox.w;
sy = (double)render_rect.h / (double)pd->viewbox.h;
r.pos.x = (r.pos.x - pd->viewbox.x) * sx;
r.pos.y = (r.pos.y - pd->viewbox.y) * sy;
r.size.w *= sx;
r.size.h *= sy;
}
if (render_rect.x < r.pos.x) render_rect.x = r.pos.x;
if (render_rect.y < r.pos.y) render_rect.y = r.pos.y;
if (render_rect.w > r.size.w) render_rect.w = r.size.w;
if (render_rect.h > r.size.h) render_rect.h = r.size.h;
//if the size doesn't match, drop previous cache surface.
if ((user_entry->w != w ) ||
(user_entry->h != h))
if ((user_entry->w != render_rect.w ) ||
(user_entry->h != render_rect.h))
{
ENFN->ector_surface_cache_drop(engine, user_entry->root);
user_entry->w = w;
user_entry->h = h;
ENFN->ector_surface_cache_drop(engine, user_entry->root);
user_entry->w = w;
user_entry->h = h;
}
//if the buffer is not created yet
void *buffer = NULL;
buffer = ENFN->ector_surface_cache_get(engine, user_entry->root);
buffer = ENFN->ector_surface_cache_get(engine, user_entry->root);
if (!buffer)
{
// render to the buffer
buffer = _render_to_buffer(obj, pd, engine, user_entry->root,
w, h, buffer, user_entry->root, do_async);
render_rect.x, render_rect.y, render_rect.w, render_rect.h, buffer, user_entry->root, do_async);
}
else
{
@ -737,7 +768,7 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
if (pd->changed)
buffer = _render_to_buffer(obj, pd, engine,
user_entry->root,
w, h, buffer, NULL,
render_rect.x, render_rect.y, render_rect.w, render_rect.h, buffer, NULL,
do_async);
//cache reference was increased when we get the cache.
ENFN->ector_surface_cache_drop(engine, user_entry->root);
@ -746,7 +777,9 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
_render_buffer_to_screen(obj,
engine, output, context, surface,
buffer,
x, y, w, h,
x + r.pos.x,
y + r.pos.y,
render_rect.w, render_rect.h,
do_async, EINA_TRUE);
}

View File

@ -35,6 +35,7 @@ typedef struct _Vg_User_Entry
{
int w; // current surface width
int h; // current surface height
Eina_Rect path_bounds;
Efl_VG *root;
} Vg_User_Entry;