diff --git a/legacy/edje/src/lib/Makefile.am b/legacy/edje/src/lib/Makefile.am index c069ebe299..4f938c10d0 100644 --- a/legacy/edje/src/lib/Makefile.am +++ b/legacy/edje/src/lib/Makefile.am @@ -34,6 +34,7 @@ edje_container.h \ edje_message_queue.c \ edje_private.h \ edje_cache.c \ +edje_match.c \ edje_textblock_styles.c libedje_la_LIBADD = -lm @EDJE_LIBS@ @fnmatch_libs@ diff --git a/legacy/edje/src/lib/edje_load.c b/legacy/edje/src/lib/edje_load.c index e883007d12..4f6a285775 100644 --- a/legacy/edje/src/lib/edje_load.c +++ b/legacy/edje/src/lib/edje_load.c @@ -158,15 +158,16 @@ edje_file_group_exists(const char *file, const char *glob) { if (edf->collection_dir) { - Evas_List *l; + Edje_Patterns *patterns; - for (l = edf->collection_dir->entries; l; l = l->next) - { - Edje_Part_Collection_Directory_Entry *ce; - - ce = l->data; - if (_edje_glob_match(ce->entry, glob)) return 1; - } + patterns = edje_match_collection_dir_init(edf->collection_dir->entries); + if (edje_match_collection_dir_exec(patterns, + glob)) + { + edje_match_patterns_free(patterns); + return 1; + } + edje_match_patterns_free(patterns); } _edje_cache_file_unref(edf); } diff --git a/legacy/edje/src/lib/edje_match.c b/legacy/edje/src/lib/edje_match.c new file mode 100644 index 0000000000..640f8c41c1 --- /dev/null +++ b/legacy/edje/src/lib/edje_match.c @@ -0,0 +1,570 @@ +#include +#include +#include + +#include "Edje.h" +#include "edje_private.h" + +/* States manipulations. */ + +typedef struct _Edje_State Edje_State; +struct _Edje_State +{ + size_t idx; + size_t pos; +}; + +typedef struct _Edje_States Edje_States; +struct _Edje_States +{ + size_t size; + Edje_State *states; + _Bool *has; +}; + +static void +_edje_match_states_free(Edje_States *states, + size_t states_size) +{ + (void) states_size; + free(states); +} + +#define ALIGN(Size) \ + { \ + Size--; \ + Size |= sizeof (void*) - 1; \ + Size++; \ + }; + +static Edje_States* +_edje_match_states_alloc(size_t n, + size_t patterns_size, + size_t patterns_max_length) +{ + Edje_States *l; + + const size_t array_len = (patterns_max_length + 1) * patterns_size; + + size_t states_size; + size_t has_size; + size_t states_has_size; + size_t struct_size; + + unsigned char *states; + unsigned char *has; + + size_t i; + + states_size = sizeof (*l->states) * array_len; + ALIGN(states_size); + + has_size = sizeof (*l->has) * array_len; + ALIGN(has_size); + + states_has_size = states_size + has_size; + + struct_size = sizeof (*l); + ALIGN(struct_size); + struct_size += states_has_size; + + l = malloc(n * struct_size); + if (!l) return NULL; + + states = (unsigned char *) (l + n); + has = states + states_size; + + for (i = 0; i < n; ++i) + { + l[i].states = (Edje_State *) states; + l[i].has = (_Bool *) has; + states += states_has_size; + has += states_has_size; + } + + return l; +} + +static void +_edje_match_states_insert(Edje_States *list, + size_t patterns_max_length, + size_t idx, + size_t pos) +{ + { + const size_t i = idx * (patterns_max_length + 1) + pos; + + if (list->has[i]) return; + list->has[i] = 1; + } + + const size_t i = list->size; + + list->states[i].idx = idx; + list->states[i].pos = pos; + ++list->size; +} + +static void +_edje_match_states_clear(Edje_States *list, + size_t patterns_size, + size_t patterns_max_length) +{ + list->size = 0; + memset(list->has, 0, patterns_size * (patterns_max_length + 1) * sizeof (*list->has)); +} + +/* Token manipulation. */ + +enum status + { + patterns_not_found = 0, + patterns_found = 1, + patterns_syntax_error = 2 + }; + +static size_t +_edje_match_patterns_exec_class_token(enum status *status, + const char *cl_tok, + char c) +{ + if (! *cl_tok) + { + *status = patterns_syntax_error; + return 0; + } + else if (cl_tok[1] == '-' && cl_tok[2] != ']') + { + if (*cl_tok <= c && c <= cl_tok[2]) + *status = patterns_found; + return 3; + } + else + { + if (c == *cl_tok) + *status = patterns_found; + return 1; + } +} + +static Edje_Match_Error +_edje_match_patterns_exec_class_complement(const char *cl_tok, size_t *ret) +{ + switch (*cl_tok) + { + case 0: + return EDJE_MATCH_SYNTAX_ERROR; + + case '!': + *ret = 1; + return EDJE_MATCH_OK; + + default: + *ret = 0; + return EDJE_MATCH_OK; + } +} + +static Edje_Match_Error +_edje_match_patterns_exec_class(const char *cl, + char c, + size_t *ret) +{ + enum status status = patterns_not_found; + int pos = 1; + size_t neg; + + if (_edje_match_patterns_exec_class_complement(cl + 1, &neg) != EDJE_MATCH_OK) + return EDJE_MATCH_SYNTAX_ERROR; + + pos += neg; + + do + pos += _edje_match_patterns_exec_class_token(&status, cl + pos, c); + while (cl[pos] && cl[pos] != ']'); + + if (status == patterns_syntax_error || ! cl[pos]) + return EDJE_MATCH_SYNTAX_ERROR; + + if (status == patterns_found) + *ret = neg ? 0 : pos + 1; + else + *ret = neg ? pos + 1 : 0; + + return EDJE_MATCH_OK; +} + +static Edje_Match_Error +_edje_match_patterns_exec_token(const char *tok, + char c, + size_t *ret) +{ + switch (*tok) + { + case '\\': + if (tok[1]) + { + *ret = tok[1] == c ? 2 : 0; + return EDJE_MATCH_OK; + } + return EDJE_MATCH_SYNTAX_ERROR; + + case '?': + *ret = 1; + return EDJE_MATCH_OK; + + case '[': + return _edje_match_patterns_exec_class(tok, c, ret); + + default: + *ret = *tok == c ? 1 : 0; + return EDJE_MATCH_OK; + } +} + +static void +_edje_match_patterns_exec_init_states(Edje_States *states, + size_t patterns_size, + size_t patterns_max_length) +{ + size_t i; + + states->size = patterns_size; + + memset(states->has, + 0, + patterns_size * (patterns_max_length + 1) * sizeof (*states->has)); + for (i = 0; i < patterns_size; ++i) + { + states->states[i].idx = i; + states->states[i].pos = 0; + states->has[i * (patterns_max_length + 1)] = 1; + } +} + +/* Exported function. */ + +#define EDJE_MATCH_INIT(Func, Type, Source, Show) \ + Edje_Patterns* \ + Func(Evas_List *lst) \ + { \ + Edje_Patterns *r; \ + size_t i; \ + \ + if (!lst || evas_list_count(lst) <= 0) \ + return NULL; \ + \ + r = malloc(sizeof (Edje_Patterns) + \ + evas_list_count(lst) \ + * sizeof (*r->finals) \ + * sizeof(*r->patterns)); \ + if (!r) return NULL; \ + \ + r->patterns_size = evas_list_count(lst); \ + r->max_length = 0; \ + r->patterns = (const char **) r->finals + r->patterns_size + 1; \ + \ + for (i = 0; lst; ++i) \ + { \ + const char *str; \ + Type *data; \ + size_t j; \ + \ + data = evas_list_data(lst); \ + if (!data) \ + { \ + free(r); \ + return NULL; \ + } \ + \ + str = data->Source; \ + if (!str) str = ""; \ + r->patterns[i] = str; \ + \ + if (Show) \ + fprintf(stderr, "%i [%s]\n", i, str); \ + \ + r->finals[i] = 0; \ + for (j = 0; str[j]; ++j) \ + if (str[j] != '*') \ + r->finals[i] = j + 1; \ + \ + if (j > r->max_length) \ + r->max_length = j; \ + \ + lst = evas_list_next(lst); \ + } \ + \ + return r; \ + } + +EDJE_MATCH_INIT(edje_match_collection_dir_init, + Edje_Part_Collection_Directory_Entry, + entry, 0); +EDJE_MATCH_INIT(edje_match_programs_signal_init, + Edje_Program, + signal, 0); +EDJE_MATCH_INIT(edje_match_programs_source_init, + Edje_Program, + source, 0); +EDJE_MATCH_INIT(edje_match_callback_signal_init, + Edje_Signal_Callback, + signal, 0); +EDJE_MATCH_INIT(edje_match_callback_source_init, + Edje_Signal_Callback, + source, 0); + +static int +_edje_match_collection_dir_exec_finals(const size_t *finals, + const Edje_States *states) +{ + size_t i; + + for (i = 0; i < states->size; ++i) + if (states->states[i].pos >= finals[states->states[i].idx]) + return 1; + return 0; +} + +static int +edje_match_programs_exec_check_finals(const size_t *signal_finals, + const size_t *source_finals, + const Edje_States *signal_states, + const Edje_States *source_states, + Evas_List *programs, + int (*func)(Edje_Program *pr, void *data), + void *data) +{ + size_t i; + size_t j; + + for (i = 0; i < signal_states->size; ++i) + if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx]) + for (j = 0; j < source_states->size; ++j) + if (signal_states->states[i].idx == source_states->states[j].idx + && source_states->states[j].pos >= source_finals[source_states->states[j].idx]) + { + Edje_Program *pr; + + pr = evas_list_nth(programs, signal_states->states[i].idx); + if (pr) + { + if (func(pr, data)) + return 0; + } + } + + return 1; +} + +static int +edje_match_callback_exec_check_finals(const size_t *signal_finals, + const size_t *source_finals, + const Edje_States *signal_states, + const Edje_States *source_states, + const char *signal, + const char *source, + Evas_List *callbacks, + Edje *ed) +{ + size_t i; + size_t j; + int r = 1; + + for (i = 0; i < signal_states->size; ++i) + if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx]) + for (j = 0; j < source_states->size; ++j) + if (signal_states->states[i].idx == source_states->states[j].idx + && source_states->states[j].pos >= source_finals[source_states->states[j].idx]) + { + Edje_Signal_Callback *escb; + + escb = evas_list_nth(callbacks, signal_states->states[i].idx); + if (escb) + { + if ((!escb->just_added) + && (!escb->delete_me)) + { + escb->func(escb->data, ed->obj, signal, source); + r = 2; + } + if (_edje_block_break(ed)) + return 0; + } + } + + return r; +} + + +static Edje_States* +_edje_match_fn(const Edje_Patterns *ppat, + const char *string, + Edje_States *states) +{ + Edje_States *new_states = states + 1; + const char *c; + + for (c = string; *c && states->size; ++c) + { + size_t i; + + _edje_match_states_clear(new_states, ppat->patterns_size, ppat->max_length); + + for (i = 0; i < states->size; ++i) + { + const size_t idx = states->states[i].idx; + const size_t pos = states->states[i].pos; + + if (!ppat->patterns[idx][pos]) + continue; + else if (ppat->patterns[idx][pos] == '*') + { + _edje_match_states_insert(states, ppat->max_length, idx, pos + 1); + _edje_match_states_insert(new_states, ppat->max_length, idx, pos); + } + else + { + size_t m; + + if (_edje_match_patterns_exec_token(ppat->patterns[idx] + pos, + *c, + &m) != EDJE_MATCH_OK) + return NULL; + + if (m) + _edje_match_states_insert(new_states, ppat->max_length, idx, pos + m); + } + } + { + Edje_States *tmp = states; + + states = new_states; + new_states = tmp; + } + } + + return states; +} + +int +edje_match_collection_dir_exec(const Edje_Patterns *ppat, + const char *string) +{ + Edje_States *states = _edje_match_states_alloc(2, + ppat->patterns_size, + ppat->max_length); + Edje_States *result; + int r = 0; + + if (!states) + return 0; + _edje_match_patterns_exec_init_states(states, ppat->patterns_size, ppat->max_length); + + result = _edje_match_fn(ppat, string, states); + + if (result) + r = _edje_match_collection_dir_exec_finals(ppat->finals, result); + + _edje_match_states_free(states, 2); + return r; +} + +int +edje_match_programs_exec(const Edje_Patterns *ppat_signal, + const Edje_Patterns *ppat_source, + const char *signal, + const char *source, + Evas_List *programs, + int (*func)(Edje_Program *pr, void *data), + void *data) +{ + Edje_States *signal_states = _edje_match_states_alloc(2, + ppat_signal->patterns_size, + ppat_signal->max_length); + Edje_States *source_states = _edje_match_states_alloc(2, + ppat_source->patterns_size, + ppat_source->max_length); + Edje_States *signal_result; + Edje_States *source_result; + int r = 0; + + if (!signal_states || !source_states) + return 0; + + _edje_match_patterns_exec_init_states(signal_states, + ppat_signal->patterns_size, + ppat_signal->max_length); + _edje_match_patterns_exec_init_states(source_states, + ppat_source->patterns_size, + ppat_source->max_length); + + signal_result = _edje_match_fn(ppat_signal, signal, signal_states); + source_result = _edje_match_fn(ppat_source, source, source_states); + + if (signal_result && source_result) + r = edje_match_programs_exec_check_finals(ppat_signal->finals, + ppat_source->finals, + signal_result, + source_result, + programs, + func, + data); + + _edje_match_states_free(source_states, 2); + _edje_match_states_free(signal_states, 2); + return r; +} + +int +edje_match_callback_exec(const Edje_Patterns *ppat_signal, + const Edje_Patterns *ppat_source, + const char *signal, + const char *source, + Evas_List *callbacks, + Edje *ed) +{ + Edje_States *signal_states = _edje_match_states_alloc(2, + ppat_signal->patterns_size, + ppat_signal->max_length); + Edje_States *source_states = _edje_match_states_alloc(2, + ppat_source->patterns_size, + ppat_source->max_length); + Edje_States *signal_result; + Edje_States *source_result; + int r = 0; + + if (!signal_states || !source_states) + return 0; + + _edje_match_patterns_exec_init_states(signal_states, + ppat_signal->patterns_size, + ppat_signal->max_length); + _edje_match_patterns_exec_init_states(source_states, + ppat_source->patterns_size, + ppat_source->max_length); + + signal_result = _edje_match_fn(ppat_signal, signal, signal_states); + source_result = _edje_match_fn(ppat_source, source, source_states); + + if (signal_result && source_result) + r = edje_match_callback_exec_check_finals(ppat_signal->finals, + ppat_source->finals, + signal_result, + source_result, + signal, + source, + callbacks, + ed); + + _edje_match_states_free(source_states, 2); + _edje_match_states_free(signal_states, 2); + return r; +} + +void +edje_match_patterns_free(Edje_Patterns *ppat) +{ + free(ppat); +} + diff --git a/legacy/edje/src/lib/edje_private.h b/legacy/edje/src/lib/edje_private.h index 30ce241f7a..f064a91307 100644 --- a/legacy/edje/src/lib/edje_private.h +++ b/legacy/edje/src/lib/edje_private.h @@ -906,6 +906,48 @@ typedef enum _Edje_Fill EDJE_FILL_TYPE_TILE } Edje_Fill; +typedef enum _Edje_Match_Error +{ + EDJE_MATCH_OK, + EDJE_MATCH_ALLOC_ERROR, + EDJE_MATCH_SYNTAX_ERROR + +} Edje_Match_Error; + +typedef struct _Edje_Patterns Edje_Patterns; +struct _Edje_Patterns +{ + const char **patterns; + size_t patterns_size; + size_t max_length; + size_t finals[]; + +}; + +Edje_Patterns *edje_match_collection_dir_init(Evas_List *lst); +Edje_Patterns *edje_match_programs_signal_init(Evas_List *lst); +Edje_Patterns *edje_match_programs_source_init(Evas_List *lst); +Edje_Patterns *edje_match_callback_signal_init(Evas_List *lst); +Edje_Patterns *edje_match_callback_source_init(Evas_List *lst); + +int edje_match_collection_dir_exec(const Edje_Patterns *ppat, + const char *string); +int edje_match_programs_exec(const Edje_Patterns *ppat_signal, + const Edje_Patterns *ppat_source, + const char *signal, + const char *source, + Evas_List *programs, + int (*func)(Edje_Program *pr, void *data), + void *data); +int edje_match_callback_exec(const Edje_Patterns *ppat_signal, + const Edje_Patterns *ppat_source, + const char *signal, + const char *source, + Evas_List *callbacks, + Edje *ed); + +void edje_match_patterns_free(Edje_Patterns *ppat); + EAPI extern Eet_Data_Descriptor *_edje_edd_edje_file; EAPI extern Eet_Data_Descriptor *_edje_edd_edje_style; EAPI extern Eet_Data_Descriptor *_edje_edd_edje_style_tag; @@ -998,7 +1040,6 @@ void _edje_text_class_members_free(void); void _edje_text_class_hash_free(void); Edje *_edje_fetch(Evas_Object *obj); -int _edje_glob_match(const char *str, const char *glob); int _edje_freeze(Edje *ed); int _edje_thaw(Edje *ed); int _edje_block(Edje *ed); diff --git a/legacy/edje/src/lib/edje_program.c b/legacy/edje/src/lib/edje_program.c index 545622999a..ab5b5c74ff 100644 --- a/legacy/edje/src/lib/edje_program.c +++ b/legacy/edje/src/lib/edje_program.c @@ -823,12 +823,46 @@ _edje_emit(Edje *ed, const char *sig, const char *src) _edje_message_send(ed, EDJE_QUEUE_SCRIPT, EDJE_MESSAGE_SIGNAL, 0, &emsg); } +struct _Edje_Program_Data +{ +#ifdef EDJE_PROGRAM_CACHE + Evas_List *matches; + int matched; +#endif + Edje *ed; + const char *signal; + const char *source; +}; + +static int _edje_glob_callback(Edje_Program *pr, void *dt) +{ + struct _Edje_Program_Data *data = dt; + +#ifdef EDJE_PROGRAM_CACHE + data->matched++; +#endif + + _edje_program_run(data->ed, pr, 0, data->signal, data->source); + if (_edje_block_break(data->ed)) + { +#ifdef EDJE_PROGRAM_CACHE + evas_list_free(data->matches); + data->matches = NULL; +#endif + return 1; + } + +#ifdef EDJE_PROGRAM_CACHE + data->matches = evas_list_append(data->matches, pr); +#endif + + return 0; +} + /* FIXME: what if we delete the evas object??? */ void _edje_emit_handle(Edje *ed, const char *sig, const char *src) { - Evas_List *l; - if (ed->delete_me) return; if (!sig) sig = ""; if (!src) src = ""; @@ -883,35 +917,40 @@ _edje_emit_handle(Edje *ed, const char *sig, const char *src) #endif if (!done) { -#ifdef EDJE_PROGRAM_CACHE - int matched = 0; - Evas_List *matches = NULL; -#endif + struct _Edje_Program_Data data; - for (l = ed->collection->programs; l; l = l->next) - { - Edje_Program *pr; + data.ed = ed; + data.source = src; + data.signal = sig; +#ifdef EDJE_PROGRAM_CACHE + data.matched = 0; + data.matches = NULL; +#endif + Edje_Patterns *signals_patterns; + Edje_Patterns *sources_patterns; + + if (ed->collection->programs) + { + signals_patterns = edje_match_programs_signal_init(ed->collection->programs); + sources_patterns = edje_match_programs_source_init(ed->collection->programs); + + if (edje_match_programs_exec(signals_patterns, + sources_patterns, + sig, + src, + ed->collection->programs, + _edje_glob_callback, + &data) == 0) + { + edje_match_patterns_free(signals_patterns); + edje_match_patterns_free(sources_patterns); + goto break_prog; + } + + edje_match_patterns_free(signals_patterns); + edje_match_patterns_free(sources_patterns); + } - pr = l->data; - if ((_edje_glob_match(sig, pr->signal)) && - (_edje_glob_match(src, pr->source))) - { -#ifdef EDJE_PROGRAM_CACHE - matched++; -#endif - _edje_program_run(ed, pr, 0, sig, src); - if (_edje_block_break(ed)) - { -#ifdef EDJE_PROGRAM_CACHE - evas_list_free(matches); -#endif - goto break_prog; - } -#ifdef EDJE_PROGRAM_CACHE - matches = evas_list_append(matches, pr); -#endif - } - } #ifdef EDJE_PROGRAM_CACHE if (tmps) { @@ -920,7 +959,7 @@ _edje_emit_handle(Edje *ed, const char *sig, const char *src) evas_hash_add(ec->prog_cache.no_matches, tmps, ed); else ec->prog_cache.matches = - evas_hash_add(ec->prog_cache.matches, tmps, matches); + evas_hash_add(ec->prog_cache.matches, tmps, data.matches); } #endif } @@ -940,25 +979,41 @@ _edje_emit_handle(Edje *ed, const char *sig, const char *src) static void _edje_emit_cb(Edje *ed, const char *sig, const char *src) { - Evas_List *l; + Edje_Patterns *signals_patterns; + Edje_Patterns *sources_patterns; + Evas_List *l; if (ed->delete_me) return; _edje_ref(ed); _edje_freeze(ed); _edje_block(ed); ed->walking_callbacks = 1; - for (l = ed->callbacks; l; l = l->next) - { - Edje_Signal_Callback *escb; - escb = l->data; - if ((!escb->just_added) && - (!escb->delete_me) && - (_edje_glob_match(sig, escb->signal)) && - (_edje_glob_match(src, escb->source))) - escb->func(escb->data, ed->obj, sig, src); - if (_edje_block_break(ed)) goto break_prog; + if (ed->callbacks) + { + int r; + + signals_patterns = edje_match_callback_signal_init(ed->callbacks); + sources_patterns = edje_match_callback_source_init(ed->callbacks); + + r = edje_match_callback_exec(signals_patterns, + sources_patterns, + sig, + src, + ed->callbacks, + ed); + + if (!r) + { + edje_match_patterns_free(signals_patterns); + edje_match_patterns_free(sources_patterns); + goto break_prog; + } + + edje_match_patterns_free(signals_patterns); + edje_match_patterns_free(sources_patterns); } + ed->walking_callbacks = 0; if ((ed->delete_callbacks) || (ed->just_added_callbacks)) { diff --git a/legacy/edje/src/lib/edje_util.c b/legacy/edje/src/lib/edje_util.c index 7201805eb6..6b4fad70b6 100644 --- a/legacy/edje/src/lib/edje_util.c +++ b/legacy/edje/src/lib/edje_util.c @@ -1950,20 +1950,6 @@ _edje_fetch(Evas_Object *obj) return ed; } -int -_edje_glob_match(const char *str, const char *glob) -{ - if ((!glob) || (glob[0] == 0)) - { - if ((!str) || (str[0] == 0)) return 1; - if ((glob) && (glob[0] == '*')) return 1; - return 0; - } - if (glob[0] == '*') return 1; - if ((glob) && (str) && (!fnmatch(glob, str, 0))) return 1; - return 0; -} - int _edje_freeze(Edje *ed) {