forked from enlightenment/efl
Evas filters: Fix proxy usage (source unset)
Proxy sources & objects were not properly unset. This results either in crashes (especially in the Edje tests) or dangling objects with tons of references. Remove the refcount increase/decrease, as it is redundant. Store pairs proxy+source instead of just the source in all hashes, so we can unset the is_proxy flag on the proxy when there are no sources anymore.
This commit is contained in:
parent
a25b212bac
commit
9d821a402a
|
@ -622,6 +622,8 @@ _destructor(Eo *eo_obj, void *_pd, va_list *list EINA_UNUSED)
|
|||
MAGIC_CHECK_END();
|
||||
Evas_Object_Protected_Data *obj = _pd;
|
||||
Evas_Object_Protected_Data *tmp;
|
||||
Evas_Object *proxy;
|
||||
Eina_List *l, *l2;
|
||||
|
||||
evas_object_hide(eo_obj);
|
||||
if (obj->focused)
|
||||
|
@ -654,8 +656,8 @@ _destructor(Eo *eo_obj, void *_pd, va_list *list EINA_UNUSED)
|
|||
evas_object_grabs_cleanup(eo_obj, obj);
|
||||
EINA_LIST_FREE(obj->clip.clipees, tmp)
|
||||
evas_object_clip_unset(tmp->object);
|
||||
while (obj->proxy->proxies)
|
||||
evas_object_image_source_unset(obj->proxy->proxies->data);
|
||||
EINA_LIST_FOREACH_SAFE(obj->proxy->proxies, l, l2, proxy)
|
||||
evas_object_image_source_unset(proxy);
|
||||
if (obj->cur->clipper) evas_object_clip_unset(eo_obj);
|
||||
evas_object_map_set(eo_obj, NULL);
|
||||
if (obj->is_smart) evas_object_smart_del(eo_obj);
|
||||
|
|
|
@ -49,7 +49,8 @@ struct _Evas_Object_Text
|
|||
struct {
|
||||
Eina_Stringshare *code;
|
||||
Evas_Filter_Program *chain;
|
||||
Eina_Hash *sources;
|
||||
Eina_Hash *sources; // Evas_Filter_Proxy_Binding
|
||||
int sources_count;
|
||||
void *output;
|
||||
Eina_Bool changed : 1;
|
||||
} filter;
|
||||
|
@ -1977,13 +1978,15 @@ evas_object_text_free(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
|
|||
|
||||
/* free filter output */
|
||||
if (o->cur.filter.output)
|
||||
{
|
||||
ENFN->image_free(ENDT, o->cur.filter.output);
|
||||
o->cur.filter.output = NULL;
|
||||
}
|
||||
ENFN->image_free(ENDT, o->cur.filter.output);
|
||||
eina_hash_free(o->cur.filter.sources);
|
||||
evas_filter_program_del(o->cur.filter.chain);
|
||||
eina_stringshare_del(o->cur.filter.code);
|
||||
o->cur.filter.output = NULL;
|
||||
o->cur.filter.chain = NULL;
|
||||
o->cur.filter.sources = NULL;
|
||||
o->cur.filter.code = NULL;
|
||||
o->cur.filter.sources_count = 0;
|
||||
|
||||
/* free obj */
|
||||
_evas_object_text_items_clear(o);
|
||||
|
@ -2156,14 +2159,14 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
|
|||
// Scan proxies to find if any changed
|
||||
if (!redraw && o->cur.filter.sources)
|
||||
{
|
||||
Evas_Filter_Proxy_Binding *pb;
|
||||
Evas_Object_Protected_Data *source;
|
||||
Evas_Object *eo_source;
|
||||
Eina_Iterator *it;
|
||||
|
||||
it = eina_hash_iterator_data_new(o->cur.filter.sources);
|
||||
EINA_ITERATOR_FOREACH(it, eo_source)
|
||||
EINA_ITERATOR_FOREACH(it, pb)
|
||||
{
|
||||
source = eo_data_scope_get(eo_source, EVAS_OBJ_CLASS);
|
||||
source = eo_data_scope_get(pb->eo_source, EVAS_OBJ_CLASS);
|
||||
if (source->changed)
|
||||
{
|
||||
redraw = EINA_TRUE;
|
||||
|
@ -2187,7 +2190,7 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
|
|||
}
|
||||
|
||||
filter = evas_filter_context_new(obj->layer->evas, do_async);
|
||||
ok = evas_filter_context_program_use(filter, eo_obj, o->cur.filter.chain);
|
||||
ok = evas_filter_context_program_use(filter, o->cur.filter.chain);
|
||||
if (!filter || !ok)
|
||||
{
|
||||
ERR("Parsing failed?");
|
||||
|
@ -2729,42 +2732,92 @@ _filter_program_set(Eo *eo_obj, void *_pd, va_list *list)
|
|||
evas_object_inform_call_resize(eo_obj);
|
||||
}
|
||||
|
||||
static void
|
||||
_filter_source_hash_free_cb(void *data)
|
||||
{
|
||||
Evas_Filter_Proxy_Binding *pb = data;
|
||||
Evas_Object_Protected_Data *proxy, *source;
|
||||
Evas_Object_Text *o;
|
||||
|
||||
proxy = eo_data_scope_get(pb->eo_proxy, EVAS_OBJ_CLASS);
|
||||
source = eo_data_scope_get(pb->eo_source, EVAS_OBJ_CLASS);
|
||||
|
||||
if (source)
|
||||
{
|
||||
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy,
|
||||
Evas_Object_Proxy_Data, source_write)
|
||||
source_write->proxies = eina_list_remove(source_write->proxies, pb->eo_proxy);
|
||||
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, source_write)
|
||||
}
|
||||
|
||||
o = eo_data_scope_get(pb->eo_proxy, MY_CLASS);
|
||||
|
||||
if (o && proxy)
|
||||
{
|
||||
o->cur.filter.sources_count--;
|
||||
if (!o->cur.filter.sources_count)
|
||||
{
|
||||
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, proxy->proxy,
|
||||
Evas_Object_Proxy_Data, proxy_write)
|
||||
proxy_write->is_proxy = EINA_FALSE;
|
||||
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_write)
|
||||
}
|
||||
}
|
||||
|
||||
eina_stringshare_del(pb->name);
|
||||
free(pb);
|
||||
}
|
||||
|
||||
static void
|
||||
_filter_source_set(Eo *eo_obj, void *_pd, va_list *list)
|
||||
{
|
||||
Evas_Object_Text *o = _pd;
|
||||
Evas_Object_Protected_Data *obj;
|
||||
Evas_Filter_Program *pgm = NULL;
|
||||
Evas_Filter_Program *pgm = o->cur.filter.chain;
|
||||
const char *name = va_arg(list, const char *);
|
||||
Evas_Object *proxy = va_arg(list, Evas_Object *);
|
||||
Evas_Object *eo_source = va_arg(list, Evas_Object *);
|
||||
Evas_Filter_Proxy_Binding *pb, *pb_old = NULL;
|
||||
Evas_Object_Protected_Data *source;
|
||||
|
||||
pgm = o->cur.filter.chain;
|
||||
if (!pgm)
|
||||
if (!o->cur.filter.sources)
|
||||
{
|
||||
Evas_Object *old;
|
||||
if (!proxy) return;
|
||||
if (!o->cur.filter.sources)
|
||||
{
|
||||
o->cur.filter.sources = eina_hash_string_small_new
|
||||
(EINA_FREE_CB(evas_object_unref));
|
||||
}
|
||||
else
|
||||
{
|
||||
old = eina_hash_find(o->cur.filter.sources, name);
|
||||
if (old == proxy) return;
|
||||
if (old) eina_hash_del(o->cur.filter.sources, name, old);
|
||||
}
|
||||
evas_object_ref(proxy);
|
||||
eina_hash_add(o->cur.filter.sources, name, proxy);
|
||||
o->cur.filter.changed = EINA_TRUE;
|
||||
return;
|
||||
o->cur.filter.sources = eina_hash_string_small_new
|
||||
(EINA_FREE_CB(_filter_source_hash_free_cb));
|
||||
}
|
||||
else
|
||||
{
|
||||
pb_old = eina_hash_find(o->cur.filter.sources, name);
|
||||
if (pb_old && (pb_old->eo_source == eo_source)) return;
|
||||
eina_hash_del(o->cur.filter.sources, name, pb_old);
|
||||
}
|
||||
|
||||
evas_filter_program_source_set(pgm, name, proxy);
|
||||
o->cur.filter.changed = EINA_TRUE;
|
||||
obj = eo_data_scope_get(eo_obj, EVAS_OBJ_CLASS);
|
||||
source = eo_data_scope_get(eo_source, EVAS_OBJ_CLASS);
|
||||
if (!source) return;
|
||||
|
||||
pb = calloc(1, sizeof(*pb));
|
||||
pb->eo_proxy = eo_obj;
|
||||
pb->eo_source = eo_source;
|
||||
pb->name = eina_stringshare_add(name);
|
||||
|
||||
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy,
|
||||
Evas_Object_Proxy_Data, source_write)
|
||||
if (!eina_list_data_find(source_write->proxies, eo_obj))
|
||||
source_write->proxies = eina_list_append(source_write->proxies, eo_obj);
|
||||
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, source_write)
|
||||
|
||||
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy,
|
||||
Evas_Object_Proxy_Data, proxy_write)
|
||||
proxy_write->is_proxy = EINA_TRUE;
|
||||
EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy, proxy_write)
|
||||
|
||||
eina_hash_add(o->cur.filter.sources, pb->name, pb);
|
||||
o->cur.filter.sources_count++;
|
||||
|
||||
evas_filter_program_source_set_all(pgm, o->cur.filter.sources);
|
||||
|
||||
// Update object
|
||||
obj = eo_data_scope_get(eo_obj, EVAS_OBJ_CLASS);
|
||||
o->cur.filter.changed = EINA_TRUE;
|
||||
_evas_object_text_items_clear(o);
|
||||
o->changed = 1;
|
||||
_evas_object_text_recalc(eo_obj, o->cur.text);
|
||||
|
|
|
@ -120,41 +120,6 @@ _filter_buffer_backing_free(Evas_Filter_Buffer *fb)
|
|||
_backing_free(fb->ctx, backing);
|
||||
}
|
||||
|
||||
/** @hidden private bind proxy to context */
|
||||
void
|
||||
evas_filter_context_source_set(Evas_Filter_Context *ctx, Evas_Object *eo_proxy,
|
||||
Evas_Object *eo_source, int bufid,
|
||||
Eina_Stringshare *name)
|
||||
{
|
||||
Evas_Object_Protected_Data *proxy = eo_data_scope_get(eo_proxy, EVAS_OBJ_CLASS);
|
||||
Evas_Object_Protected_Data *source = eo_data_scope_get(eo_source, EVAS_OBJ_CLASS);
|
||||
Evas_Filter_Buffer *fb;
|
||||
|
||||
fb = _filter_buffer_get(ctx, bufid);
|
||||
EINA_SAFETY_ON_NULL_RETURN(fb);
|
||||
|
||||
if (fb->source == eo_source) return;
|
||||
evas_object_unref(fb->source);
|
||||
eina_stringshare_del(fb->source_name);
|
||||
fb->source = eo_source;
|
||||
if (!fb->source) return;
|
||||
fb->source_name = eina_stringshare_ref(name);
|
||||
|
||||
evas_object_ref(eo_source);
|
||||
|
||||
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, proxy->proxy, Evas_Object_Proxy_Data, proxy_write)
|
||||
proxy_write->is_proxy = EINA_TRUE;
|
||||
EINA_COW_WRITE_END(evas_object_proxy_cow, proxy->proxy, proxy_write);
|
||||
|
||||
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy, Evas_Object_Proxy_Data, proxy_src_write)
|
||||
{
|
||||
if (!eina_list_data_find(source->proxy->proxies, eo_proxy))
|
||||
proxy_src_write->proxies = eina_list_append(proxy_src_write->proxies, eo_proxy);
|
||||
proxy_src_write->redraw = EINA_TRUE;
|
||||
}
|
||||
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_src_write);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render the source object when a proxy is set.
|
||||
|
|
|
@ -103,7 +103,7 @@ struct _Evas_Filter_Instruction
|
|||
struct _Evas_Filter_Program
|
||||
{
|
||||
Eina_Stringshare *name; // Optional for now
|
||||
Eina_Hash /* const char * : Evas_Object */ *proxies;
|
||||
Eina_Hash /* const char * : Evas_Filter_Proxy_Binding */ *proxies;
|
||||
Eina_Inlist /* Evas_Filter_Instruction */ *instructions;
|
||||
Eina_Inlist /* Buffer */ *buffers;
|
||||
Eina_Bool valid : 1;
|
||||
|
@ -1181,7 +1181,6 @@ evas_filter_program_del(Evas_Filter_Program *pgm)
|
|||
}
|
||||
|
||||
eina_stringshare_del(pgm->name);
|
||||
eina_hash_free(pgm->proxies);
|
||||
free(pgm);
|
||||
}
|
||||
|
||||
|
@ -1375,64 +1374,19 @@ evas_filter_program_new(const char *name)
|
|||
pgm = calloc(1, sizeof(Evas_Filter_Program));
|
||||
if (!pgm) return NULL;
|
||||
pgm->name = eina_stringshare_add(name);
|
||||
pgm->proxies = eina_hash_string_small_new(EINA_FREE_CB(evas_object_unref));
|
||||
_buffer_add(pgm, "input", EINA_TRUE, NULL);
|
||||
_buffer_add(pgm, "output", EINA_FALSE, NULL);
|
||||
|
||||
return pgm;
|
||||
}
|
||||
|
||||
/** Bind an object for proxy rendering */
|
||||
|
||||
void
|
||||
evas_filter_program_source_set(Evas_Filter_Program *pgm,
|
||||
const char *name, Evas_Object *object)
|
||||
{
|
||||
Evas_Object *old;
|
||||
|
||||
old = eina_hash_find(pgm->proxies, name);
|
||||
if (old == object) return;
|
||||
if (old) eina_hash_del(pgm->proxies, name, old);
|
||||
|
||||
evas_object_ref(object);
|
||||
eina_hash_add(pgm->proxies, name, object);
|
||||
}
|
||||
|
||||
/** Bind objects for proxy rendering */
|
||||
void
|
||||
evas_filter_program_source_set_all(Evas_Filter_Program *pgm,
|
||||
Eina_Hash *proxies)
|
||||
{
|
||||
Eina_Hash_Tuple *tuple;
|
||||
Eina_Iterator *it;
|
||||
Evas_Object *old;
|
||||
|
||||
if (!pgm || !proxies) return;
|
||||
|
||||
it = eina_hash_iterator_tuple_new(proxies);
|
||||
EINA_ITERATOR_FOREACH(it, tuple)
|
||||
{
|
||||
Eina_Stringshare *name = tuple->key;
|
||||
Eo *source = tuple->data;
|
||||
|
||||
old = eina_hash_find(pgm->proxies, name);
|
||||
if (old)
|
||||
{
|
||||
INF("Buffer %s already exists, skipping proxy source.", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
INF("Binding object %p as '%s'", source, name);
|
||||
evas_filter_program_source_set(pgm, name, source);
|
||||
}
|
||||
eina_iterator_free(it);
|
||||
}
|
||||
|
||||
/** Get object used for proxy rendering */
|
||||
|
||||
Evas_Object *
|
||||
evas_filter_program_source_get(Evas_Filter_Program *pgm, const char *name)
|
||||
{
|
||||
return (Evas_Object *) eina_hash_find(pgm->proxies, name);
|
||||
if (!pgm) return;
|
||||
pgm->proxies = proxies;
|
||||
}
|
||||
|
||||
/** Glue with Evas' filters */
|
||||
|
@ -1851,7 +1805,7 @@ _command_from_instruction(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
|
|||
}
|
||||
|
||||
Eina_Bool
|
||||
evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Object *eo_obj,
|
||||
evas_filter_context_program_use(Evas_Filter_Context *ctx,
|
||||
Evas_Filter_Program *pgm)
|
||||
{
|
||||
Buffer *buf;
|
||||
|
@ -1873,8 +1827,16 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Object *eo_obj,
|
|||
buf->cid = evas_filter_buffer_empty_new(ctx, buf->alpha);
|
||||
if (buf->proxy)
|
||||
{
|
||||
Eo *eo_source = evas_filter_program_source_get(pgm, buf->proxy);
|
||||
evas_filter_context_source_set(ctx, eo_obj, eo_source, buf->cid, buf->proxy);
|
||||
Evas_Filter_Proxy_Binding *pb;
|
||||
Evas_Filter_Buffer *fb;
|
||||
|
||||
pb = eina_hash_find(pgm->proxies, buf->proxy);
|
||||
if (!pb) continue;
|
||||
|
||||
fb = _filter_buffer_get(ctx, buf->cid);
|
||||
fb->proxy = pb->eo_proxy;
|
||||
fb->source = pb->eo_source;
|
||||
fb->source_name = eina_stringshare_ref(pb->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,8 @@ struct _Evas_Filter_Buffer
|
|||
void *glimage;
|
||||
int w, h;
|
||||
|
||||
Evas_Object *proxy;
|
||||
|
||||
Eina_Bool alpha_only : 1; // 1 channel (A) instead of 4 (RGBA)
|
||||
Eina_Bool allocated : 1; // allocated on demand, belongs to this context
|
||||
Eina_Bool transient : 1; // temporary buffer (automatic allocation)
|
||||
|
|
|
@ -9,6 +9,7 @@ typedef struct _Evas_Filter_Command Evas_Filter_Command;
|
|||
typedef struct _Evas_Filter_Program Evas_Filter_Program;
|
||||
typedef struct _Evas_Filter_Instruction Evas_Filter_Instruction;
|
||||
typedef struct _Evas_Filter_Buffer Evas_Filter_Buffer;
|
||||
typedef struct _Evas_Filter_Proxy_Binding Evas_Filter_Proxy_Binding;
|
||||
typedef enum _Evas_Filter_Mode Evas_Filter_Mode;
|
||||
typedef enum _Evas_Filter_Blur_Type Evas_Filter_Blur_Type;
|
||||
typedef enum _Evas_Filter_Channel Evas_Filter_Channel;
|
||||
|
@ -93,11 +94,10 @@ enum _Evas_Filter_Transform_Flags
|
|||
Evas_Filter_Program *evas_filter_program_new(const char *name);
|
||||
Eina_Bool evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str);
|
||||
void evas_filter_program_del(Evas_Filter_Program *pgm);
|
||||
Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Object *eo_obj, Evas_Filter_Program *pgm);
|
||||
Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm);
|
||||
Eina_Bool evas_filter_program_padding_get(Evas_Filter_Program *pgm, int *l, int *r, int *t, int *b);
|
||||
void evas_filter_program_source_set(Evas_Filter_Program *pgm, const char *name, Evas_Object *object);
|
||||
//void evas_filter_program_source_set(Evas_Filter_Program *pgm, const char *name, Evas_Object *object);
|
||||
void evas_filter_program_source_set_all(Evas_Filter_Program *pgm, Eina_Hash *sources);
|
||||
Evas_Object *evas_filter_program_source_get(Evas_Filter_Program *pgm, const char *name);
|
||||
void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, Eina_Bool do_async);
|
||||
|
||||
/* Filter context (low level) */
|
||||
|
@ -240,5 +240,13 @@ int evas_filter_command_bump_map_add(Evas_Filter_Context *c
|
|||
*/
|
||||
int evas_filter_command_transform_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, Evas_Filter_Transform_Flags flags, int ox, int oy);
|
||||
|
||||
/* Simple binding between a filter object and its sources */
|
||||
struct _Evas_Filter_Proxy_Binding
|
||||
{
|
||||
Evas_Object *eo_proxy;
|
||||
Evas_Object *eo_source;
|
||||
Eina_Stringshare *name;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue