From 6b12ae1e03e93a10b0120aa15d1ff40b022ec189 Mon Sep 17 00:00:00 2001 From: Youngbok Shin Date: Tue, 12 Jan 2016 13:20:19 +0000 Subject: [PATCH] edje: Reduce duplicated item obj creations and deletions. Summary: When text is changed, all of objects for item tag are deleted and recreated. It is unnecessary work and can cause performance issues. Actually, many of application developers wonder why item provider callback functions are called every text changes. @fix Test Plan: Run elementary_test -to "entry emoticon" When you make a very little change on text, 36 emoticon objects are recreated. Reviewers: woohyun, jaehwan, herdsman, tasn Reviewed By: tasn Subscribers: cedric, jpeg Differential Revision: https://phab.enlightenment.org/D3537 --- src/lib/edje/edje_entry.c | 112 +++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/src/lib/edje/edje_entry.c b/src/lib/edje/edje_entry.c index ffcbc11cdd..34f98a01f3 100644 --- a/src/lib/edje/edje_entry.c +++ b/src/lib/edje/edje_entry.c @@ -12,6 +12,7 @@ static Eina_Bool _edje_entry_imf_retrieve_selection_cb(void *data, Ecore_IMF_Con typedef struct _Entry Entry; typedef struct _Sel Sel; typedef struct _Anchor Anchor; +typedef struct _Item_Obj Item_Obj; static void _edje_entry_imf_cursor_location_set(Entry *en); static void _edje_entry_imf_cursor_info_set(Entry *en); @@ -35,6 +36,7 @@ struct _Entry Eina_List *anchorlist; Eina_List *itemlist; Eina_List *seq; + Item_Obj *item_objs; char *selection; Edje_Input_Panel_Lang input_panel_lang; Eina_Bool composing : 1; @@ -70,6 +72,14 @@ struct _Anchor Eina_Bool item : 1; }; +struct _Item_Obj +{ + EINA_INLIST; + Anchor *an; + char *name; + Evas_Object *obj; +}; + #ifdef HAVE_ECORE_IMF static void _preedit_clear(Entry *en) @@ -913,6 +923,89 @@ _edje_anchor_mouse_out_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA ev->event_flags |= rp->part->mask_flags; } +static void +_item_obj_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Item_Obj *io = data; + Anchor *an = io->an; + Entry *en; + + if (!an) + { + ERR("Failed to free item object struct. Anchor is NULL!"); + return; + } + + en = an->en; + en->item_objs = (Item_Obj *)eina_inlist_remove(EINA_INLIST_GET(en->item_objs), + EINA_INLIST_GET(io)); + io->an = NULL; + free(io->name); + free(io); +} + +static Evas_Object * +_item_obj_get(Anchor *an, Evas_Object *o, Evas_Object *smart, Evas_Object *clip) +{ + Evas_Object *obj; + Item_Obj *io; + Entry *en = an->en; + Edje *ed = en->ed; + + EINA_INLIST_FOREACH(en->item_objs, io) + { + if (!io->an && io->name && !strcmp(an->name, io->name)) + { + io->an = an; + return io->obj; + } + } + + io = calloc(1, sizeof(Item_Obj)); + + obj = ed->item_provider.func + (ed->item_provider.data, smart, + en->rp->part->name, an->name); + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _item_obj_del_cb, io); + evas_object_smart_member_add(obj, smart); + evas_object_stack_above(obj, o); + evas_object_clip_set(obj, clip); + evas_object_pass_events_set(obj, EINA_TRUE); + evas_object_show(obj); + + io->an = an; + io->name = strdup(an->name); + io->obj = obj; + en->item_objs = (Item_Obj *)eina_inlist_append(EINA_INLIST_GET(en->item_objs), + EINA_INLIST_GET(io)); + + return io->obj; +} + +static void +_unused_item_objs_free(Entry *en) +{ + Item_Obj *io; + Eina_Inlist *l; + + EINA_INLIST_FOREACH_SAFE(en->item_objs, l, io) + { + if (!io->an) + { + if (io->obj) + { + evas_object_event_callback_del_full(io->obj, EVAS_CALLBACK_DEL, _item_obj_del_cb, io); + evas_object_del(io->obj); + } + + en->item_objs = (Item_Obj *)eina_inlist_remove(EINA_INLIST_GET(en->item_objs), + EINA_INLIST_GET(io)); + free(io->name); + free(io); + } + } +} + static void _anchors_update(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en) { @@ -944,14 +1037,7 @@ _anchors_update(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en) if (ed->item_provider.func) { - ob = ed->item_provider.func - (ed->item_provider.data, smart, - en->rp->part->name, an->name); - evas_object_smart_member_add(ob, smart); - evas_object_stack_above(ob, o); - evas_object_clip_set(ob, clip); - evas_object_pass_events_set(ob, EINA_TRUE); - evas_object_show(ob); + ob = _item_obj_get(an, o, smart, clip); sel->obj = ob; } } @@ -1058,6 +1144,8 @@ _anchors_update(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en) } } } + + _unused_item_objs_free(en); } static void @@ -1100,6 +1188,8 @@ _anchors_need_update(Edje_Real_Part *rp) static void _anchors_clear(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en) { + Item_Obj *io; + while (en->anchorlist) { free(en->anchorlist->data); @@ -1119,7 +1209,7 @@ _anchors_clear(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Sel *sel = an->sel->data; if (sel->obj_bg) evas_object_del(sel->obj_bg); if (sel->obj_fg) evas_object_del(sel->obj_fg); - if (sel->obj) evas_object_del(sel->obj); + if (!an->item && sel->obj) evas_object_del(sel->obj); free(sel); an->sel = eina_list_remove_list(an->sel, an->sel); } @@ -1129,6 +1219,9 @@ _anchors_clear(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, free(an); en->anchors = eina_list_remove_list(en->anchors, en->anchors); } + + EINA_INLIST_FOREACH(en->item_objs, io) + io->an = NULL; } /* FIXME: This is horrible. It's just a copy&paste (with some adjustments) @@ -2671,6 +2764,7 @@ _edje_entry_real_part_shutdown(Edje *ed, Edje_Real_Part *rp) rp->typedata.text->entry_data = NULL; _sel_clear(ed, en->cursor, rp->object, en); _anchors_clear(en->cursor, rp->object, en); + _unused_item_objs_free(en); #ifdef HAVE_ECORE_IMF _preedit_clear(en); #endif