hermet pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=442fae5c5621636bf52c3467d6d4c7147fd53a5a
commit 442fae5c5621636bf52c3467d6d4c7147fd53a5a Author: JunsuChoi <jsuya.c...@samsung.com> Date: Wed Jun 3 11:37:23 2020 +0900 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 --- .../ector/software/ector_renderer_software_shape.c | 4 +- src/lib/edje/edje_calc.c | 6 +++ src/lib/evas/canvas/efl_canvas_vg_container.c | 35 ++++++++++++- src/lib/evas/canvas/efl_canvas_vg_object.c | 57 +++++++++++++++++----- src/lib/evas/canvas/evas_vg_private.h | 1 + 5 files changed, 87 insertions(+), 16 deletions(-) diff --git a/src/lib/ector/software/ector_renderer_software_shape.c b/src/lib/ector/software/ector_renderer_software_shape.c index d8d804db22..be024ff5d1 100644 --- a/src/lib/ector/software/ector_renderer_software_shape.c +++ b/src/lib/ector/software/ector_renderer_software_shape.c @@ -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); diff --git a/src/lib/edje/edje_calc.c b/src/lib/edje/edje_calc.c index 93a99254bf..5d3f42344b 100644 --- a/src/lib/edje/edje_calc.c +++ b/src/lib/edje/edje_calc.c @@ -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"); diff --git a/src/lib/evas/canvas/efl_canvas_vg_container.c b/src/lib/evas/canvas/efl_canvas_vg_container.c index 61bd74e7c3..4516b34ba0 100644 --- a/src/lib/evas/canvas/efl_canvas_vg_container.c +++ b/src/lib/evas/canvas/efl_canvas_vg_container.c @@ -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); + } } } } diff --git a/src/lib/evas/canvas/efl_canvas_vg_object.c b/src/lib/evas/canvas/efl_canvas_vg_object.c index 3a3ba1c346..d05bfc551d 100644 --- a/src/lib/evas/canvas/efl_canvas_vg_object.c +++ b/src/lib/evas/canvas/efl_canvas_vg_object.c @@ -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); } diff --git a/src/lib/evas/canvas/evas_vg_private.h b/src/lib/evas/canvas/evas_vg_private.h index dcd5cb0356..c20ed2a1eb 100644 --- a/src/lib/evas/canvas/evas_vg_private.h +++ b/src/lib/evas/canvas/evas_vg_private.h @@ -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; --