forked from enlightenment/efl
Evas clip: Fix rare crash in _render_pre_clipper_change
Use delete callback instead of direct call to clip_unset, which lets us know that clip_unset() is called during the clipper's deletion, as opposed to a simple call. We can then make sure that the previous object state does not point to invalid data anymore. Here is a scenario that could have crashed: - load and show an edje object, hide it - change its theme or style - show it again @fix
This commit is contained in:
parent
cbf2aa2bf9
commit
100a7006b8
|
@ -213,6 +213,8 @@ _evas_object_clip_mask_unset(Evas_Object_Protected_Data *obj)
|
|||
extern const char *o_rect_type;
|
||||
extern const char *o_image_type;
|
||||
|
||||
static Eina_Bool _clipper_del_cb(void *data, Eo *eo_clip, const Eo_Event_Description *desc EINA_UNUSED, void *info EINA_UNUSED);
|
||||
|
||||
EOLIAN void
|
||||
_evas_object_clip_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object *eo_clip)
|
||||
{
|
||||
|
@ -281,6 +283,8 @@ _evas_object_clip_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object *
|
|||
}
|
||||
if (obj->cur->clipper)
|
||||
{
|
||||
Evas_Object_Protected_Data *old_clip = obj->cur->clipper;
|
||||
|
||||
/* unclip */
|
||||
obj->cur->clipper->clip.cache_clipees_answer = eina_list_free(obj->cur->clipper->clip.cache_clipees_answer);
|
||||
obj->cur->clipper->clip.clipees = eina_list_remove(obj->cur->clipper->clip.clipees, obj);
|
||||
|
@ -320,10 +324,10 @@ _evas_object_clip_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object *
|
|||
evas_object_change(eo_obj, obj);
|
||||
|
||||
EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
|
||||
{
|
||||
state_write->clipper = NULL;
|
||||
}
|
||||
state_write->clipper = NULL;
|
||||
EINA_COW_STATE_WRITE_END(obj, state_write, cur);
|
||||
if (obj->prev->clipper != old_clip)
|
||||
eo_do(old_clip->object, eo_event_callback_del(EO_BASE_EVENT_DEL, _clipper_del_cb, eo_obj));
|
||||
}
|
||||
|
||||
/* image object clipper */
|
||||
|
@ -350,11 +354,12 @@ _evas_object_clip_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object *
|
|||
clip->cur->geometry.w, clip->cur->geometry.h);
|
||||
*/
|
||||
}
|
||||
|
||||
EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
|
||||
{
|
||||
state_write->clipper = clip;
|
||||
}
|
||||
state_write->clipper = clip;
|
||||
EINA_COW_STATE_WRITE_END(obj, state_write, cur);
|
||||
if (obj->prev->clipper != clip)
|
||||
eo_do(clip->object, eo_event_callback_add(EO_BASE_EVENT_DEL, _clipper_del_cb, eo_obj));
|
||||
|
||||
clip->clip.cache_clipees_answer = eina_list_free(clip->clip.cache_clipees_answer);
|
||||
clip->clip.clipees = eina_list_append(clip->clip.clipees, obj);
|
||||
|
@ -401,7 +406,6 @@ EOLIAN void
|
|||
_evas_object_clip_unset(Eo *eo_obj, Evas_Object_Protected_Data *obj)
|
||||
{
|
||||
if (!obj->cur->clipper) return;
|
||||
|
||||
evas_object_async_block(obj);
|
||||
obj->clip.cache_clipees_answer = eina_list_free(obj->clip.cache_clipees_answer);
|
||||
|
||||
|
@ -413,6 +417,8 @@ _evas_object_clip_unset(Eo *eo_obj, Evas_Object_Protected_Data *obj)
|
|||
}
|
||||
if (obj->cur->clipper)
|
||||
{
|
||||
Evas_Object_Protected_Data *old_clip = obj->cur->clipper;
|
||||
|
||||
obj->cur->clipper->clip.clipees = eina_list_remove(obj->cur->clipper->clip.clipees, obj);
|
||||
if (!obj->cur->clipper->clip.clipees)
|
||||
{
|
||||
|
@ -445,12 +451,13 @@ _evas_object_clip_unset(Eo *eo_obj, Evas_Object_Protected_Data *obj)
|
|||
_evas_object_clip_mask_unset(obj->cur->clipper);
|
||||
}
|
||||
evas_object_change(obj->cur->clipper->object, obj->cur->clipper);
|
||||
|
||||
EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
|
||||
state_write->clipper = NULL;
|
||||
EINA_COW_STATE_WRITE_END(obj, state_write, cur);
|
||||
if (obj->prev->clipper != old_clip)
|
||||
eo_do(old_clip->object, eo_event_callback_del(EO_BASE_EVENT_DEL, _clipper_del_cb, eo_obj));
|
||||
}
|
||||
EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
|
||||
{
|
||||
state_write->clipper = NULL;
|
||||
}
|
||||
EINA_COW_STATE_WRITE_END(obj, state_write, cur);
|
||||
|
||||
evas_object_change(eo_obj, obj);
|
||||
evas_object_clip_dirty(eo_obj, obj);
|
||||
|
@ -470,6 +477,43 @@ _evas_object_clip_unset(Eo *eo_obj, Evas_Object_Protected_Data *obj)
|
|||
evas_object_clip_across_check(eo_obj, obj);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_clipper_del_cb(void *data, Eo *eo_clip, const Eo_Event_Description *desc EINA_UNUSED, void *info EINA_UNUSED)
|
||||
{
|
||||
Evas_Object *eo_obj = data;
|
||||
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
|
||||
|
||||
if (!obj) return EO_CALLBACK_CONTINUE;
|
||||
|
||||
_evas_object_clip_unset(eo_obj, obj);
|
||||
if (obj->prev->clipper && (obj->prev->clipper->object == eo_clip))
|
||||
{
|
||||
// not removing cb since it's the del cb... it can't be called again!
|
||||
EINA_COW_STATE_WRITE_BEGIN(obj, state_write, prev)
|
||||
state_write->clipper = NULL;
|
||||
EINA_COW_STATE_WRITE_END(obj, state_write, prev);
|
||||
}
|
||||
|
||||
return EO_CALLBACK_CONTINUE;
|
||||
}
|
||||
|
||||
void
|
||||
_evas_object_clip_prev_reset(Evas_Object_Protected_Data *obj, Eina_Bool cur_prev)
|
||||
{
|
||||
if (obj->prev->clipper)
|
||||
{
|
||||
Evas_Object_Protected_Data *clip = obj->prev->clipper;
|
||||
if (!cur_prev)
|
||||
{
|
||||
EINA_COW_STATE_WRITE_BEGIN(obj->prev->clipper, state_write, prev)
|
||||
state_write->clipper = NULL;
|
||||
EINA_COW_STATE_WRITE_END(obj->prev->clipper, state_write, prev);
|
||||
}
|
||||
if (clip != obj->cur->clipper)
|
||||
eo_do(clip->object, eo_event_callback_del(EO_BASE_EVENT_DEL, _clipper_del_cb, obj->object));
|
||||
}
|
||||
}
|
||||
|
||||
EOLIAN Eina_List *
|
||||
_evas_object_clipees_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj)
|
||||
{
|
||||
|
|
|
@ -159,6 +159,7 @@ evas_object_cur_prev(Evas_Object *eo_obj)
|
|||
map_write->prev = map_write->cur;
|
||||
EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
|
||||
}
|
||||
_evas_object_clip_prev_reset(obj, EINA_TRUE);
|
||||
eina_cow_memcpy(evas_object_state_cow, (const Eina_Cow_Data **) &obj->prev, obj->cur);
|
||||
}
|
||||
|
||||
|
@ -704,13 +705,18 @@ _evas_object_eo_base_destructor(Eo *eo_obj, Evas_Object_Protected_Data *obj)
|
|||
goto end;
|
||||
}
|
||||
evas_object_grabs_cleanup(eo_obj, obj);
|
||||
/* "while" should be used for null check of obj->clip.clipees,
|
||||
because evas_objct_clip_unset can set null to obj->clip.clipees */
|
||||
while (obj->clip.clipees)
|
||||
if (obj->clip.clipees)
|
||||
{
|
||||
Evas_Object_Protected_Data *tmp;
|
||||
tmp = eina_list_data_get(obj->clip.clipees);
|
||||
evas_object_clip_unset(tmp->object);
|
||||
ERR("object %p still has %d clippees after del callback",
|
||||
eo_obj, eina_list_count(obj->clip.clipees));
|
||||
/* "while" should be used for null check of obj->clip.clipees,
|
||||
because evas_objct_clip_unset can set null to obj->clip.clipees */
|
||||
while (obj->clip.clipees)
|
||||
{
|
||||
Evas_Object_Protected_Data *tmp;
|
||||
tmp = eina_list_data_get(obj->clip.clipees);
|
||||
evas_object_clip_unset(tmp->object);
|
||||
}
|
||||
}
|
||||
EINA_LIST_FOREACH_SAFE(obj->proxy->proxies, l, l2, proxy)
|
||||
{
|
||||
|
@ -734,6 +740,8 @@ _evas_object_eo_base_destructor(Eo *eo_obj, Evas_Object_Protected_Data *obj)
|
|||
}
|
||||
|
||||
if (obj->cur->clipper) evas_object_clip_unset(eo_obj);
|
||||
_evas_object_clip_prev_reset(obj, EINA_FALSE);
|
||||
|
||||
evas_object_map_set(eo_obj, NULL);
|
||||
if (obj->is_smart) evas_object_smart_del(eo_obj);
|
||||
_evas_object_event_new();
|
||||
|
|
|
@ -1650,6 +1650,7 @@ void _above_get(Eo *obj, void *_pd, va_list *list);
|
|||
void _below_get(Eo *obj, void *_pd, va_list *list);
|
||||
void _smart_move_children_relative(Eo *obj, void *_pd, va_list *list);
|
||||
void _smart_clipped_clipper_get(Eo *obj, void *_pd, va_list *list);
|
||||
void _evas_object_clip_prev_reset(Evas_Object_Protected_Data *obj, Eina_Bool cur_prev);
|
||||
|
||||
void _canvas_event_default_flags_set(Eo *e, void *_pd, va_list *list);
|
||||
void _canvas_event_default_flags_get(Eo *e, void *_pd, va_list *list);
|
||||
|
|
Loading…
Reference in New Issue