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
This commit is contained in:
Jean-Philippe Andre 2017-03-06 23:01:07 +09:00
parent 500401364d
commit aacd25ef6b
2 changed files with 49 additions and 32 deletions

View File

@ -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);

View File

@ -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);
obj->layer = smart->layer;
EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
if (obj->layer != smart->layer)
{
state_write->layer = obj->layer->layer;
if (obj->in_layer)
evas_object_release(eo_obj, obj, 1);
else if ((--obj->layer->usage) == 0)
evas_layer_del(obj->layer);
}
EINA_COW_STATE_WRITE_END(obj, state_write, cur);
else if (obj->in_layer)
{
evas_object_release(eo_obj, obj, 1);
}
obj->layer = smart->layer;
obj->layer->usage++;
if (obj->layer->layer != obj->cur->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);
}
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);