Edje/evas filters: Add filter.source support

This should preserve ABI stability with earlier versions of
edje_cc while still providing more advanced control over
proxy bindings for evas filters from EDC.

Also fix proxy binding for filters.

@feature
This commit is contained in:
Jean-Philippe Andre 2015-06-16 14:50:43 +09:00
parent 0e11e0a6dc
commit d00378edcf
5 changed files with 201 additions and 108 deletions

View File

@ -362,6 +362,7 @@ static void st_collections_group_parts_part_description_text_source(void);
static void st_collections_group_parts_part_description_text_text_source(void);
static void st_collections_group_parts_part_description_text_ellipsis(void);
static void st_collections_group_parts_part_description_text_filter(void);
static void st_collections_group_parts_part_description_text_filter_source(void);
static void st_collections_group_parts_part_description_box_layout(void);
static void st_collections_group_parts_part_description_box_align(void);
static void st_collections_group_parts_part_description_box_padding(void);
@ -814,6 +815,8 @@ New_Statement_Handler statement_handlers[] =
{"collections.group.parts.part.description.text.elipsis", st_collections_group_parts_part_description_text_ellipsis},
{"collections.group.parts.part.description.text.ellipsis", st_collections_group_parts_part_description_text_ellipsis},
{"collections.group.parts.part.description.text.filter", st_collections_group_parts_part_description_text_filter},
{"collections.group.parts.part.description.text.filter.code", st_collections_group_parts_part_description_text_filter}, /* dup */
{"collections.group.parts.part.description.text.filter.source", st_collections_group_parts_part_description_text_filter_source},
{"collections.group.parts.part.description.box.layout", st_collections_group_parts_part_description_box_layout},
{"collections.group.parts.part.description.box.align", st_collections_group_parts_part_description_box_align},
{"collections.group.parts.part.description.box.padding", st_collections_group_parts_part_description_box_padding},
@ -6696,15 +6699,18 @@ st_collections_group_parts_part_description_inherit(void)
ted->text.domain = STRDUP(ted->text.domain);
ted->text.text_class = STRDUP(ted->text.text_class);
ted->text.font.str = STRDUP(ted->text.font.str);
ted->text.filter.code = STRDUP(ted->text.filter.code);
{
Eina_List *l;
Eina_Stringshare *name;
static int part_key = 0;
EINA_LIST_FOREACH(ted->text.filter.sources, l, name)
data_queue_part_lookup(pc, name, &part_key);
}
/* Filters stuff */
ted->text.filter.code = STRDUP(ted->text.filter.code);
if (ted->text.filter.code)
{
Eina_List *list, *l;
const char *name;
list = ted->text.filter.sources;
ted->text.filter.sources = NULL;
EINA_LIST_FOREACH(list, l, name)
ted->text.filter.sources = eina_list_append(ted->text.filter.sources, STRDUP(name));
}
data_queue_copied_part_nest_lookup(pc, &(tparent->text.id_source), &(ted->text.id_source), &ted->text.id_source_part);
data_queue_copied_part_nest_lookup(pc, &(tparent->text.id_text_source), &(ted->text.id_text_source), &ted->text.id_text_source_part);
@ -8979,29 +8985,41 @@ st_collections_group_parts_part_description_text_ellipsis(void)
/**
@page edcref
@context
part {
type: TEXT; // or IMAGE
description {
..
text {
..
filter {
code: "blend {} -- ..."
source: "part1" "buf";
source: "part2" "otherbuf";
source: "part3";
}
// or as short form:
filter: "blend {} -- ..."
}
..
}
}
@property
filter
filter.code
@parameters
[filter program as a string]
@effect
Applies a series of filtering operations to the text.
EXPERIMENTAL FEATURE. TO BE DOCUMENTED.
Applies a series of image filters to a TEXT or IMAGE part. The argument
to this field is the source code of a Lua program invoking various
filter operations. For more information, please refer to the page
"Evas filters reference".
@see evasfiltersref
@endproperty
*/
static void
st_collections_group_parts_part_description_text_filter(void)
{
Edje_Part_Description_Text *ed;
Eina_List *sources = NULL;
Eina_Stringshare *name;
char *token, *code;
Eina_Bool valid = EINA_TRUE;
Edje_Part_Collection *pc;
static int part_key = 0;
static const char *allowed_name_chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHJIKLMNOPQRSTUVWXYZ0123456789_";
check_arg_count(1);
@ -9013,73 +9031,101 @@ st_collections_group_parts_part_description_text_filter(void)
}
ed = (Edje_Part_Description_Text*) current_desc;
pc = eina_list_data_get(eina_list_last(edje_collections));
if (ed->text.filter.code)
{
EINA_LIST_FREE(ed->text.filter.sources, name)
{
part_lookup_delete(pc, name, &part_key, NULL);
eina_stringshare_del(name);
}
free((void*)ed->text.filter.code);
}
ed->text.filter.sources = NULL;
free((void*) ed->text.filter.code);
ed->text.filter.code = parse_str(0);
if (!ed->text.filter.code) return;
}
// Parse list of buffers that have a source
// note: does not support comments
code = strdup(ed->text.filter.code);
for (token = strtok(code, ";"); token; token = strtok(NULL, ";"))
/**
@page edcref
@property
filter.source
@parameters
[another part's name] [(optional) buffer name for filter program]
@effect
Binds another part as an image source (like a proxy source) for a
text or image filter operation. Optionally, a buffer name may be
specified, so the same filter code can be used with different sources.
For more information, please refer to the page "Evas filters reference".
@see evasfiltersref
@endproperty
*/
static void
st_collections_group_parts_part_description_text_filter_source(void)
{
Edje_Part_Description_Text *ed;
Edje_Part_Collection *pc;
char *name = NULL, *part, *str;
size_t sn = 0, sp;
int *part_key;
static const char *allowed_name_chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHJIKLMNOPQRSTUVWXYZ0123456789_";
/* 1 or 2 args only */
check_min_arg_count(1);
if (get_arg_count() > 1)
check_arg_count(2);
if (current_part->type != EDJE_PART_TYPE_TEXT)
{
size_t len;
ERR("parse error %s:%i. text attributes in non-TEXT part.",
file_in, line - 1);
exit(-1);
}
len = strspn(token, " \n\t");
token += len;
ed = (Edje_Part_Description_Text*) current_desc;
pc = eina_list_data_get(eina_list_last(edje_collections));
if (!strncasecmp("buffer", token, 6))
part = parse_str(0);
sp = strlen(part);
if (get_arg_count() > 1)
{
name = parse_str(1);
if (name) sn = strlen(name);
if (!name || (strspn(name, allowed_name_chars) != sn))
{
// note: a valid string won't necessary compile at runtime
token = strchr(token, ':');
if (!token)
{
valid = EINA_FALSE;
break;
}
token = strchr(token, '(');
if (!token)
{
valid = EINA_FALSE;
break;
}
token = strcasestr(token, "src");
if (!token) continue;
token += 3;
len = strspn(token, " =\n\t");
if (!len || !token[len])
{
valid = EINA_FALSE;
break;
}
token += len;
len = strspn(token, allowed_name_chars);
if (!len || !token[len])
{
valid = EINA_FALSE;
break;
}
token[len] = '\0';
name = eina_stringshare_add(token);
sources = eina_list_append(sources, name);
data_queue_part_lookup(pc, name, &part_key);
ERR("parse error %s:%i. invalid name for a filter buffer: %s",
file_in, line - 1, name);
exit(-1);
}
}
free(code);
if (valid) ed->text.filter.sources = sources;
if (!name && (strspn(part, allowed_name_chars) == sp))
str = strdup(part);
else
{
if (!name)
{
// name = part so we replace all invalid chars by '_'
size_t k;
name = strdup(part);
sn = strlen(name);
for (k = 0; k < sn; k++)
{
if (!index(allowed_name_chars, name[k]))
name[k] = '_';
}
}
sn += sp + 1;
str = malloc(sn + 1);
if (!str) exit(-1);
strncpy(str, name, sn);
strncat(str, ":", sn);
strncat(str, part, sn);
str[sn] = '\0';
}
ed->text.filter.sources = eina_list_append(ed->text.filter.sources, str);
// note: this is leaked. not a big deal.
part_key = malloc(sizeof(int));
*part_key = -1;
data_queue_part_lookup(pc, part, part_key);
free(part);
free(name);
}

View File

@ -1281,7 +1281,7 @@ struct _Edje_Part_Description_Spec_Border
struct _Edje_Part_Description_Spec_Filter
{
const char *code;
Eina_List *sources;
Eina_List *sources; /* "part" or "buffer:part" */
};
struct _Edje_Part_Description_Spec_Image

View File

@ -204,8 +204,8 @@ _edje_text_recalc_apply(Edje *ed, Edje_Real_Part *ep,
char *font2 = NULL;
char *sfont = NULL;
int size;
const char *filter, *source_name;
Eina_List *filter_sources = NULL, *prev_sources = NULL, *li;
const char *filter;
Eina_List *filter_sources = NULL, *prev_sources = NULL;
Evas_Coord tw, th;
Evas_Coord sw, sh;
int inlined_font = 0, free_text = 0;
@ -531,15 +531,60 @@ arrange_text:
/* filters */
if (filter)
{
eo_do(ep->object,
EINA_LIST_FOREACH(prev_sources, li, source_name)
evas_obj_text_filter_source_set(source_name, NULL);
const char *src1, *src2, *part;
Eina_List *li1, *li2;
EINA_LIST_FOREACH(filter_sources, li, source_name)
eo_do(ep->object,
evas_obj_text_filter_program_set(filter);
/* update sources. really not optimal. lots of strxxx and loops */
if (prev_sources != filter_sources)
{
Edje_Real_Part *rp = _edje_real_part_get(ed, source_name);
evas_obj_text_filter_source_set(source_name, rp ? rp->object : NULL);
};
/* remove sources that are not there anymore
* this O(n^2) loop assumes a very small number of sources */
EINA_LIST_FOREACH(prev_sources, li1, src1)
{
Eina_Bool found = 0;
EINA_LIST_FOREACH(filter_sources, li2, src2)
{
if (!strcmp(src1, src2))
{
found = 1;
break;
}
}
if (!found)
{
part = strchr(src1, ':');
if (!part)
evas_obj_text_filter_source_set(src1, NULL);
else
{
char *name = strdup(src1);
name[part - src1] = 0;
evas_obj_text_filter_source_set(name, NULL);
free(name);
}
}
}
/* add all sources by part name */
EINA_LIST_FOREACH(filter_sources, li1, src1)
{
Edje_Real_Part *rp;
char *name = NULL;
if ((part = strchr(src1, ':')) != NULL)
{
name = strdup(src1);
name[part - src1] = 0;
part++;
}
else
part = src1;
rp = _edje_real_part_get(ed, part);
evas_obj_text_filter_source_set(name ? name : part, rp ? rp->object : NULL);
free(name);
}
}
/* pass edje state for transitions */
if (ep->param2)
{
evas_obj_text_filter_state_set(chosen_desc->common.state.name, chosen_desc->common.state.value,
@ -551,7 +596,7 @@ arrange_text:
evas_obj_text_filter_state_set(chosen_desc->common.state.name, chosen_desc->common.state.value,
NULL, 0.0, state_val);
}
evas_obj_text_filter_program_set(filter));
);
}
else
eo_do(ep->object, evas_obj_text_filter_program_set(NULL));

View File

@ -2495,6 +2495,12 @@ _evas_text_filter_source_set(Eo *eo_obj, Evas_Text_Data *o, const char *name, Ev
if (!source && !o->cur.filter->sources)
return;
if (o->cur.filter->sources)
{
pb_old = eina_hash_find(o->cur.filter->sources, name);
if (pb_old && (pb_old->eo_source == eo_source)) return;
}
fcow = eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&o->cur.filter);
if (!fcow->sources)
@ -2502,15 +2508,8 @@ _evas_text_filter_source_set(Eo *eo_obj, Evas_Text_Data *o, const char *name, Ev
fcow->sources = eina_hash_string_small_new
(EINA_FREE_CB(_filter_source_hash_free_cb));
}
else
{
pb_old = eina_hash_find(fcow->sources, name);
if (pb_old)
{
if (pb_old->eo_source == eo_source) goto update;
eina_hash_del(fcow->sources, name, pb_old);
}
}
else if (pb_old)
eina_hash_del(fcow->sources, name, pb_old);
if (!source)
{
@ -2530,16 +2529,19 @@ _evas_text_filter_source_set(Eo *eo_obj, Evas_Text_Data *o, const char *name, Ev
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)
if (!eina_list_data_find(source->proxy->proxies, eo_obj))
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy, Evas_Object_Proxy_Data, source_write)
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)
if (!obj->proxy->is_proxy)
{
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(fcow->sources, pb->name, pb);
evas_filter_program_source_set_all(fcow->chain, fcow->sources);

View File

@ -856,7 +856,7 @@ _lua_buffer_new(lua_State *L)
instr->type = EVAS_FILTER_MODE_BUFFER;
instr->parse_run = _buffer_instruction_parse_run;
_instruction_param_seq_add(instr, "type", VT_STRING, "rgba");
_instruction_param_seq_add(instr, "src", VT_BUFFER, NULL);
_instruction_param_seq_add(instr, "src", VT_STRING, NULL);
// drop "buffer" metatable
_lua_implicit_metatable_drop(L, _lua_buffer_meta);