edje: Reduce duplicated item obj creations and deletions. 16/59116/1
authorYoungbok Shin <youngb.shin@samsung.com>
Tue, 12 Jan 2016 13:20:19 +0000 (13:20 +0000)
committerYoungbok Shin <youngb.shin@samsung.com>
Thu, 11 Feb 2016 01:56:47 +0000 (10:56 +0900)
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

Change-Id: I078e07432ba4f2cfda3f410db382d2b4e1c198a6

src/lib/edje/edje_entry.c

index 83b0839..7fc26e6 100644 (file)
@@ -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;
@@ -73,6 +75,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)
@@ -901,6 +911,89 @@ _edje_anchor_mouse_out_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA
 }
 
 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)
 {
    Eina_List *l, *ll, *range = NULL;
@@ -941,14 +1034,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;
                     }
                }
@@ -1049,6 +1135,8 @@ _anchors_update(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en)
                }
           }
      }
+
+   _unused_item_objs_free(en);
 }
 
 static void
@@ -1091,6 +1179,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);
@@ -1110,7 +1200,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);
           }
@@ -1120,6 +1210,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)
@@ -2722,6 +2815,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