jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=aacd25ef6b2ebc67d588781b4e1ea6534ac5cb0e

commit aacd25ef6b2ebc67d588781b4e1ea6534ac5cb0e
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Mon Mar 6 23:01:07 2017 +0900

    evas: Fix layer usage count and deletion
    
    When using smart objects (quite likely, isn't it?), the internal
    layer usage count was not perfectly tracked. This was especially
    true if layer_set() was called on a (top-level) smart object.
    As a consequence, there could be no objects in the layer but the
    usage would still be > 0. Thus, the layer was not deleted, not
    removed from the inlist of layers, and efl_gfx_stack_above_get()
    could return NULL as the layer above a certain object was empty.
    
    Fixes T5201
---
 src/lib/evas/canvas/evas_layer.c        | 37 +++++++++++++----------------
 src/lib/evas/canvas/evas_object_smart.c | 42 +++++++++++++++++++++++++--------
 2 files changed, 48 insertions(+), 31 deletions(-)

diff --git a/src/lib/evas/canvas/evas_layer.c b/src/lib/evas/canvas/evas_layer.c
index a92f6d7..5295b30 100644
--- a/src/lib/evas/canvas/evas_layer.c
+++ b/src/lib/evas/canvas/evas_layer.c
@@ -1,8 +1,6 @@
 #include "evas_common_private.h"
 #include "evas_private.h"
 
-static void _evas_layer_free(Evas_Layer *lay);
-
 void
 evas_object_inject(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas 
*e)
 {
@@ -44,7 +42,6 @@ evas_object_release(Evas_Object *eo_obj, 
Evas_Object_Protected_Data *obj, int cl
              if (obj->layer->usage <= 0)
                {
                   evas_layer_del(obj->layer);
-                  _evas_layer_free(obj->layer);
                }
           }
         obj->layer = NULL;
@@ -66,12 +63,6 @@ evas_layer_new(Evas *eo_e)
    return lay;
 }
 
-static void
-_evas_layer_free(Evas_Layer *lay)
-{
-   free(lay);
-}
-
 void
 _evas_layer_flush_removes(Evas_Layer *lay)
 {
@@ -90,7 +81,6 @@ _evas_layer_flush_removes(Evas_Layer *lay)
    if (lay->usage <= 0)
      {
         evas_layer_del(lay);
-        _evas_layer_free(lay);
      }
 }
 
@@ -130,7 +120,6 @@ evas_layer_clean(Evas *eo_e)
      {
         tmp = e->layers;
         evas_layer_del(tmp);
-        _evas_layer_free(tmp);
      }
 }
 
@@ -172,20 +161,26 @@ evas_layer_del(Evas_Layer *lay)
 
    e = lay->evas;
    e->layers = (Evas_Layer *)eina_inlist_remove(EINA_INLIST_GET(e->layers), 
EINA_INLIST_GET(lay));
-
    efl_data_unref(e->evas, e);
-   lay->evas = NULL;
+   eina_freeq_ptr_main_add(lay, free, sizeof(*lay));
 }
 
 static void
-_evas_object_layer_set_child(Evas_Object *eo_obj, Evas_Object *par, short l)
+_evas_object_layer_set_child(Evas_Object_Protected_Data *obj, 
Evas_Object_Protected_Data *par_obj, short l)
 {
-   Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, 
EFL_CANVAS_OBJECT_CLASS);
-   Evas_Object_Protected_Data *par_obj = efl_data_scope_get(par, 
EFL_CANVAS_OBJECT_CLASS);
-
    if (obj->delete_me) return;
    if (obj->cur->layer == l) return;
-   evas_object_release(eo_obj, obj, 1);
+   if (EINA_UNLIKELY(obj->in_layer))
+     {
+        ERR("Invalid internal state of object %p (child marked as being a "
+            "top-level object)!", obj->object);
+        evas_object_release(obj->object, obj, 1);
+     }
+   else if ((--obj->layer->usage) == 0)
+     {
+        evas_layer_del(obj->layer);
+     }
+
    EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
      {
        state_write->layer = l;
@@ -199,10 +194,10 @@ _evas_object_layer_set_child(Evas_Object *eo_obj, 
Evas_Object *par, short l)
         Eina_Inlist *contained;
         Evas_Object_Protected_Data *member;
 
-        contained = (Eina_Inlist 
*)evas_object_smart_members_get_direct(eo_obj);
+        contained = (Eina_Inlist 
*)evas_object_smart_members_get_direct(obj->object);
         EINA_INLIST_FOREACH(contained, member)
           {
-             _evas_object_layer_set_child(member->object, eo_obj, l);
+             _evas_object_layer_set_child(member, obj, l);
           }
      }
 }
@@ -260,7 +255,7 @@ _efl_canvas_object_efl_gfx_stack_layer_set(Eo *eo_obj, 
Evas_Object_Protected_Dat
         contained = (Eina_Inlist 
*)evas_object_smart_members_get_direct(eo_obj);
         EINA_INLIST_FOREACH(contained, member)
           {
-            _evas_object_layer_set_child(member->object, eo_obj, l);
+            _evas_object_layer_set_child(member, obj, l);
           }
      }
    evas_object_inform_call_restack(eo_obj);
diff --git a/src/lib/evas/canvas/evas_object_smart.c 
b/src/lib/evas/canvas/evas_object_smart.c
index 870955b..d2f0a83 100644
--- a/src/lib/evas/canvas/evas_object_smart.c
+++ b/src/lib/evas/canvas/evas_object_smart.c
@@ -253,16 +253,27 @@ _efl_canvas_group_group_member_add(Eo *smart_obj, 
Evas_Smart_Data *o, Evas_Objec
    evas_object_async_block(obj);
    if (obj->smart.parent) evas_object_smart_member_del(eo_obj);
 
-   o->member_count++;
-   evas_object_release(eo_obj, obj, 1);
+   if (obj->layer != smart->layer)
+     {
+        if (obj->in_layer)
+          evas_object_release(eo_obj, obj, 1);
+        else if ((--obj->layer->usage) == 0)
+          evas_layer_del(obj->layer);
+     }
+   else if (obj->in_layer)
+     {
+        evas_object_release(eo_obj, obj, 1);
+     }
    obj->layer = smart->layer;
-   EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
+   obj->layer->usage++;
+   if (obj->layer->layer != obj->cur->layer)
      {
-       state_write->layer = obj->layer->layer;
+        EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
+          state_write->layer = obj->layer->layer;
+        EINA_COW_STATE_WRITE_END(obj, state_write, cur);
      }
-   EINA_COW_STATE_WRITE_END(obj, state_write, cur);
 
-   obj->layer->usage++;
+   o->member_count++;
    obj->smart.parent = smart_obj;
    obj->smart.parent_data = o;
    obj->smart.parent_object_data = smart;
@@ -324,13 +335,13 @@ _efl_canvas_group_group_member_del(Eo *smart_obj, 
Evas_Smart_Data *_pd EINA_UNUS
    o->member_count--;
    obj->smart.parent = NULL;
    evas_object_smart_member_cache_invalidate(eo_obj, EINA_TRUE, EINA_TRUE, 
EINA_TRUE);
-   obj->layer->usage--;
 
-   EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
+   if (obj->layer->layer != obj->cur->layer)
      {
-       state_write->layer = obj->layer->layer;
+        EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
+          state_write->layer = obj->layer->layer;
+        EINA_COW_STATE_WRITE_END(obj, state_write, cur);
      }
-   EINA_COW_STATE_WRITE_END(obj, state_write, cur);
 
    if (obj->is_smart)
      {
@@ -344,6 +355,17 @@ _efl_canvas_group_group_member_del(Eo *smart_obj, 
Evas_Smart_Data *_pd EINA_UNUS
           }
      }
 
+   if (EINA_UNLIKELY(obj->in_layer))
+     {
+        ERR("Invalid internal state of object %p (child marked as being a"
+            "top-level object)!", obj->object);
+        evas_object_release(obj->object, obj, 1);
+     }
+   else
+     {
+        // Layer usage shouldn't reach 0 here (as parent is still in layer)
+        obj->layer->usage--;
+     }
    evas_object_inject(eo_obj, obj, obj->layer->evas->evas);
    obj->restack = 1;
    evas_object_change(eo_obj, obj);

-- 


Reply via email to