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.
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)
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);
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;
/* 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);
// 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;
}
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?");
}
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);
_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.
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;
}
eina_stringshare_del(pgm->name);
- eina_hash_free(pgm->proxies);
free(pgm);
}
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 */
}
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;
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);
}
}
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)
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;
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) */
*/
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