From 0e8f890dfbdb188d02857b2bcf64d35089f3a297 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Mon, 22 Jun 2015 21:52:16 +0900 Subject: [PATCH] Edje & evas filters: Add extra data from EDC to Lua program This also supports color classes (really rough implementation for now, but the API should remain stable). @feature --- src/bin/edje/edje_cc_handlers.c | 52 ++++++++++++++++++++++++++ src/lib/edje/edje_calc.c | 61 +++++++++++++++++++++++++++++++ src/lib/edje/edje_data.c | 2 + src/lib/edje/edje_private.h | 1 + src/lib/efl/interfaces/efl_gfx_filter.eo | 9 +++++ src/lib/evas/canvas/evas_filter_mixin.c | 30 +++++++++++++++ src/lib/evas/canvas/evas_object_main.c | 2 +- src/lib/evas/filters/evas_filter_parser.c | 26 +++++++++++++ src/lib/evas/include/evas_filter.h | 1 + src/lib/evas/include/evas_private.h | 1 + 10 files changed, 184 insertions(+), 1 deletion(-) diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c index 8954f08..f6458f8 100644 --- a/src/bin/edje/edje_cc_handlers.c +++ b/src/bin/edje/edje_cc_handlers.c @@ -396,6 +396,7 @@ static void st_collections_group_parts_part_description_mesh_assembly(void); static void st_collections_group_parts_part_description_mesh_geometry(void); static void st_collections_group_parts_part_description_filter_code(void); static void st_collections_group_parts_part_description_filter_source(void); +static void st_collections_group_parts_part_description_filter_data(void); #ifdef HAVE_EPHYSICS static void st_collections_group_parts_part_description_physics_mass(void); @@ -849,6 +850,7 @@ New_Statement_Handler statement_handlers[] = {"collections.group.parts.part.description.mesh.geometry", st_collections_group_parts_part_description_mesh_geometry}, {"collections.group.parts.part.description.filter.code", st_collections_group_parts_part_description_filter_code}, {"collections.group.parts.part.description.filter.source", st_collections_group_parts_part_description_filter_source}, + {"collections.group.parts.part.description.filter.data", st_collections_group_parts_part_description_filter_data}, #ifdef HAVE_EPHYSICS {"collections.group.parts.part.description.physics.mass", st_collections_group_parts_part_description_physics_mass}, @@ -11649,6 +11651,56 @@ st_collections_group_parts_part_description_filter_source(void) free(name); } +/** + @page edcref + + @property + filter.data + @parameters + [name] [content] + @effect + Pass extra data to the Lua filter program. This can be used to pass + extra colors from a color_class using the following syntax: + filter.data: "mycc" "color_class('my_color_class')"; + If not a color class, the data will simply be set as a string attached + to the global variable 'name' in the Lua program. + For more information, please refer to the page "Evas filters reference". + @see evasfiltersref + @endproperty +*/ +static void +st_collections_group_parts_part_description_filter_data(void) +{ + Edje_Part_Description_Spec_Filter *filter; + char *name, *value; + + if (current_part->type == EDJE_PART_TYPE_TEXT) + filter = &(((Edje_Part_Description_Text *)current_desc)->text.filter); + else if (current_part->type == EDJE_PART_TYPE_IMAGE) + filter = &(((Edje_Part_Description_Image *)current_desc)->image.filter); + else + { + ERR("parse error %s:%i. filter set for non-TEXT and non-IMAGE part.", + file_in, line - 1); + exit(-1); + } + + check_arg_count(2); + + if (!filter->data) + filter->data = eina_hash_string_small_new(EINA_FREE_CB(free)); + + name = parse_str(0); + value = parse_str(1); + if (eina_hash_find(filter->data, name)) + { + ERR("parse error %s:%i. filter.data '%s' already exists in this context", + file_in, line - 1, name); + exit(-1); + } + + eina_hash_add(filter->data, name, value); +} /** @edcsubsection{collections_group_parts_descriptions_params, * Group.Parts.Part.Description.Params} */ diff --git a/src/lib/edje/edje_calc.c b/src/lib/edje/edje_calc.c index 48a4d81..b506ef1 100644 --- a/src/lib/edje/edje_calc.c +++ b/src/lib/edje/edje_calc.c @@ -2535,6 +2535,67 @@ _edje_part_recalc_single_filter(Edje *ed, efl_gfx_filter_state_set(chosen_desc->state.name, chosen_desc->state.value, NULL, 0.0, pos); } + /* pass extra data items */ + if (filter->data) + { + Eina_Iterator *it = eina_hash_iterator_tuple_new(filter->data); + Eina_Hash_Tuple *tup; + EINA_ITERATOR_FOREACH(it, tup) + { + const char *name = tup->key; + char *value = tup->data; + if (!value) + { + efl_gfx_filter_data_set(name, NULL); + } + else if (!strncmp(value, "color_class('", sizeof("color_class('") - 1)) + { + /* special handling for color classes even tho they're not that great */ + char *ccname, *buffer, *r; + Edje_Color_Class *cc; + + ccname = strdup(value + sizeof("color_class('") - 1); + if (ccname) + { + r = strchr(ccname, '\''); + if (r) + { + *r = '\0'; + cc = _edje_color_class_find(ed, ccname); + if (cc) + { + static const char *fmt = + "%s={r=%d,g=%d,b=%d,a=%d," + "r2=%d,g2=%d,b2=%d,a2=%d," + "r3=%d,g3=%d,b3=%d,a3=%d}"; + int len = sizeof(fmt); + len += strlen(ccname); + buffer = alloca(len); + snprintf(buffer, len - 1, fmt, ccname, + cc->r, cc->g, cc->b, cc->a, + cc->r2, cc->g2, cc->b2, cc->a2, + cc->r3, cc->g3, cc->b3, cc->a3); + efl_gfx_filter_data_set(name, buffer); + } + else + { + ERR("Unknown color class: %s", ccname); + eina_hash_del(filter->data, tup->key, tup->data); + } + } + else + { + ERR("Failed to parse color class: %s", value); + eina_hash_del(filter->data, tup->key, tup->data); + } + free(ccname); + } + } + else + efl_gfx_filter_data_set(name, value); + } + eina_iterator_free(it); + } ); } diff --git a/src/lib/edje/edje_data.c b/src/lib/edje/edje_data.c index c85dcd8..d6a08f7 100644 --- a/src/lib/edje/edje_data.c +++ b/src/lib/edje/edje_data.c @@ -959,6 +959,7 @@ _edje_edd_init(void) EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_image, Edje_Part_Description_Image, "image.fill.type", image.fill.type, EET_T_CHAR); EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_image, Edje_Part_Description_Image, "image.filter.code", image.filter.code, EET_T_STRING); EET_DATA_DESCRIPTOR_ADD_LIST_STRING(_edje_edd_edje_part_description_image, Edje_Part_Description_Image, "image.filter.sources", image.filter.sources); + EET_DATA_DESCRIPTOR_ADD_HASH_STRING(_edje_edd_edje_part_description_image, Edje_Part_Description_Image, "image.filter.data", image.filter.data); EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Description_Proxy); eddc.func.mem_free = mem_free_proxy; @@ -1017,6 +1018,7 @@ _edje_edd_init(void) EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_text, Edje_Part_Description_Text, "text.ellipsis", text.ellipsis, EET_T_DOUBLE); EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_text, Edje_Part_Description_Text, "text.filter", text.filter.code, EET_T_STRING); EET_DATA_DESCRIPTOR_ADD_LIST_STRING(_edje_edd_edje_part_description_text, Edje_Part_Description_Text, "text.filter_sources", text.filter.sources); + EET_DATA_DESCRIPTOR_ADD_HASH_STRING(_edje_edd_edje_part_description_text, Edje_Part_Description_Text, "text.filter.data", text.filter.data); // @since 1.15 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Description_Text); eddc.func.mem_free = mem_free_textblock; diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h index fcc463c..21d156c 100644 --- a/src/lib/edje/edje_private.h +++ b/src/lib/edje/edje_private.h @@ -1283,6 +1283,7 @@ struct _Edje_Part_Description_Spec_Filter const char *code; const char *name; Eina_List *sources; /* "part" or "buffer:part" */ + Eina_Hash *data; /* "name" --> "data" */ Eina_Bool checked_data : 1; // checked whether this is a data item or embedded string Eina_Bool no_free : 1; }; diff --git a/src/lib/efl/interfaces/efl_gfx_filter.eo b/src/lib/efl/interfaces/efl_gfx_filter.eo index ed8bedc..2140acf 100644 --- a/src/lib/efl/interfaces/efl_gfx_filter.eo +++ b/src/lib/efl/interfaces/efl_gfx_filter.eo @@ -70,5 +70,14 @@ interface Efl.Gfx.Filter @out source: Efl.Gfx.Base*; [[object used as a proxy source]] } } + data_set { + [[Pass extra data to the filter program. + + This sets a global value as a string.]] + params { + @in name: const(char)*; [[name of the global variable]] + @in value: const(char)*; [[string value to use as data]] + } + } } } diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index 87454a7..5a76b1e 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -123,6 +123,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Filter_Program *pgm; pgm = evas_filter_program_new(fcow->name, alpha); evas_filter_program_source_set_all(pgm, fcow->sources); + evas_filter_program_data_set_all(pgm, fcow->data); evas_filter_program_state_set(pgm, eo_obj, obj, fcow->state.cur.name, fcow->state.cur.value, fcow->state.next.name, fcow->state.next.value, @@ -274,6 +275,7 @@ _evas_filter_efl_gfx_filter_program_set(Eo *eo_obj, Evas_Filter_Data *pd, alpha = eo_do_ret(eo_obj, alpha, evas_filter_input_alpha()); pgm = evas_filter_program_new(fcow->name, alpha); evas_filter_program_source_set_all(pgm, fcow->sources); + evas_filter_program_data_set_all(pgm, fcow->data); evas_filter_program_state_set(pgm, eo_obj, obj, fcow->state.cur.name, fcow->state.cur.value, fcow->state.next.name, fcow->state.next.value, @@ -377,6 +379,7 @@ _evas_filter_efl_gfx_filter_source_set(Eo *eo_obj, Evas_Filter_Data *pd, eina_hash_add(fcow->sources, pb->name, pb); evas_filter_program_source_set_all(fcow->chain, fcow->sources); + evas_filter_program_data_set_all(fcow->chain, fcow->data); // Update object update: @@ -497,9 +500,36 @@ _evas_filter_destructor(Eo *eo_obj, Evas_Filter_Data *pd) if (pd->data->output) ENFN->image_free(ENDT, pd->data->output); eina_hash_free(pd->data->sources); + eina_hash_free(pd->data->data); evas_filter_program_del(pd->data->chain); eina_stringshare_del(pd->data->code); eina_cow_free(evas_object_filter_cow, (const Eina_Cow_Data **) &pd->data); } +EOLIAN void +_evas_filter_efl_gfx_filter_data_set(Eo *obj EINA_UNUSED, Evas_Filter_Data *pd, + const char *name, const char *value) +{ + const char *check = NULL; + + if (!pd->data) return; + + if (pd->data->data && ((check = eina_hash_find(pd->data->data, name)) != NULL)) + { + if (!strcmp(check, value)) + return; + } + + EINA_COW_WRITE_BEGIN(evas_object_filter_cow, fcow, Evas_Object_Filter_Data, fcow) + { + if (!fcow->data) + fcow->data = eina_hash_string_small_new(free); + eina_hash_set(fcow->data, name, value ? strdup(value) : NULL); + if (fcow->chain) + evas_filter_program_data_set_all(fcow->chain, fcow->data); + fcow->changed = 1; + } + EINA_COW_WRITE_END(evas_object_filter_cow, fcow, fcow); +} + #include "evas_filter.eo.c" diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c index 8330f2e..936e54d 100644 --- a/src/lib/evas/canvas/evas_object_main.c +++ b/src/lib/evas/canvas/evas_object_main.c @@ -33,7 +33,7 @@ static const Evas_Object_Protected_State default_state = { 1.0, 0, EVAS_RENDER_BLEND, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE }; static const Evas_Object_Filter_Data default_filter = { - NULL, NULL, NULL, NULL, NULL, { { "default", 0.0 }, { "default", 0.0 }, 0.0 }, EINA_FALSE, EINA_FALSE + NULL, NULL, NULL, NULL, NULL, NULL, { { "default", 0.0 }, { "default", 0.0 }, 0.0 }, EINA_FALSE, EINA_FALSE }; const void * const evas_object_filter_cow_default = &default_filter; static const Evas_Object_Mask_Data default_mask = { diff --git a/src/lib/evas/filters/evas_filter_parser.c b/src/lib/evas/filters/evas_filter_parser.c index f25f82a..6b4b8d3 100644 --- a/src/lib/evas/filters/evas_filter_parser.c +++ b/src/lib/evas/filters/evas_filter_parser.c @@ -341,6 +341,7 @@ struct _Evas_Filter_Program int l, r, t, b; } pad; Evas_Filter_Program_State state; + Eina_Hash /* str -> str */ *data; lua_State *L; int lua_func; int last_bufid; @@ -2620,6 +2621,24 @@ _filter_program_state_set(Evas_Filter_Program *pgm) } lua_setglobal(L, "state"); + /* now push all extra data */ + if (pgm->data) + { + Eina_Iterator *it = eina_hash_iterator_tuple_new(pgm->data); + Eina_Hash_Tuple *tup; + EINA_ITERATOR_FOREACH(it, tup) + { + const char *name = tup->key; + const char *value = tup->data; + if (value) + lua_pushstring(L, value); + else + lua_pushnil(L); + lua_setglobal(L, name); + } + eina_iterator_free(it); + } + #undef JOINC #undef SETFIELD #undef SETCOLOR @@ -2905,6 +2924,13 @@ evas_filter_program_source_set_all(Evas_Filter_Program *pgm, pgm->proxies = proxies; } +void +evas_filter_program_data_set_all(Evas_Filter_Program *pgm, Eina_Hash *data) +{ + if (!pgm) return; + pgm->data = data; +} + /** Glue with Evas' filters */ #define CA(color) ((color >> 24) & 0xFF) diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index e72738a..6784a0d 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h @@ -133,6 +133,7 @@ Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ct EAPI Eina_Bool evas_filter_program_padding_get(Evas_Filter_Program *pgm, int *l, int *r, int *t, int *b); EAPI void evas_filter_program_source_set_all(Evas_Filter_Program *pgm, Eina_Hash *sources); void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, Eina_Bool do_async); +void evas_filter_program_data_set_all(Evas_Filter_Program *pgm, Eina_Hash *data); /* Filter context (low level) */ Evas_Filter_Context *evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async); diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 925aa52..c94c5ed 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -1178,6 +1178,7 @@ struct _Evas_Object_Filter_Data Eina_Stringshare *code; Evas_Filter_Program *chain; Eina_Hash *sources; // Evas_Filter_Proxy_Binding + Eina_Hash *data; // str -> str void *output; struct { struct { -- 2.7.4