1 #include "edje_private.h"
2 
3 Eina_Hash *_edje_file_hash = NULL;
4 Eina_Hash *_edje_id_hash = NULL;
5 
6 static Eina_Hash *_edje_requires_pending;
7 static int _edje_file_cache_size = 16;
8 static Eina_List *_edje_file_cache = NULL;
9 
10 static int _edje_collection_cache_size = 16;
11 
12 EAPI void
edje_cache_emp_alloc(Edje_Part_Collection_Directory_Entry * ce)13 edje_cache_emp_alloc(Edje_Part_Collection_Directory_Entry *ce)
14 {
15    /* Init Eina Mempools this is also used in edje_pick.c */
16    char *buffer;
17    ce->mp = calloc(1, sizeof(Edje_Part_Collection_Directory_Entry_Mp));
18    if (!ce->mp) return;
19 
20 #define INIT_EMP(Tp, Sz, Ce) \
21   buffer = alloca(strlen(ce->entry) + strlen(#Tp) + 2); \
22   sprintf(buffer, "%s/%s", ce->entry, #Tp); \
23   Ce->mp->mp.Tp = eina_mempool_add("one_big", buffer, NULL, sizeof (Sz), Ce->count.Tp); \
24   _emp_##Tp = Ce->mp->mp.Tp;
25 
26 #define INIT_EMP_BOTH(Tp, Sz, Ce) \
27   INIT_EMP(Tp, Sz, Ce) \
28   Ce->mp->mp_rtl.Tp = eina_mempool_add("one_big", buffer, NULL, \
29                                        sizeof(Sz), Ce->count.Tp);
30 
31   INIT_EMP_BOTH(RECTANGLE, Edje_Part_Description_Common, ce);
32   INIT_EMP_BOTH(TEXT, Edje_Part_Description_Text, ce);
33   INIT_EMP_BOTH(IMAGE, Edje_Part_Description_Image, ce);
34   INIT_EMP_BOTH(PROXY, Edje_Part_Description_Proxy, ce);
35   INIT_EMP_BOTH(SWALLOW, Edje_Part_Description_Common, ce);
36   INIT_EMP_BOTH(TEXTBLOCK, Edje_Part_Description_Text, ce);
37   INIT_EMP_BOTH(GROUP, Edje_Part_Description_Common, ce);
38   INIT_EMP_BOTH(BOX, Edje_Part_Description_Box, ce);
39   INIT_EMP_BOTH(TABLE, Edje_Part_Description_Table, ce);
40   INIT_EMP_BOTH(EXTERNAL, Edje_Part_Description_External, ce);
41   INIT_EMP_BOTH(SPACER, Edje_Part_Description_Common, ce);
42   INIT_EMP_BOTH(SNAPSHOT, Edje_Part_Description_Snapshot, ce);
43   INIT_EMP_BOTH(VECTOR, Edje_Part_Description_Vector, ce);
44   INIT_EMP(part, Edje_Part, ce);
45 }
46 
47 EAPI void
edje_cache_emp_free(Edje_Part_Collection_Directory_Entry * ce)48 edje_cache_emp_free(Edje_Part_Collection_Directory_Entry *ce)
49 {  /* Free Eina Mempools this is also used in edje_pick.c */
50    /* Destroy all part and description. */
51    ce->ref = NULL;
52 
53    if (!ce->mp) return;
54    eina_mempool_del(ce->mp->mp.RECTANGLE);
55    eina_mempool_del(ce->mp->mp.TEXT);
56    eina_mempool_del(ce->mp->mp.IMAGE);
57    eina_mempool_del(ce->mp->mp.PROXY);
58    eina_mempool_del(ce->mp->mp.SWALLOW);
59    eina_mempool_del(ce->mp->mp.TEXTBLOCK);
60    eina_mempool_del(ce->mp->mp.GROUP);
61    eina_mempool_del(ce->mp->mp.BOX);
62    eina_mempool_del(ce->mp->mp.TABLE);
63    eina_mempool_del(ce->mp->mp.EXTERNAL);
64    eina_mempool_del(ce->mp->mp.SPACER);
65    eina_mempool_del(ce->mp->mp.SNAPSHOT);
66    eina_mempool_del(ce->mp->mp.VECTOR);
67    eina_mempool_del(ce->mp->mp.part);
68    memset(&ce->mp->mp, 0, sizeof(ce->mp->mp));
69 
70    eina_mempool_del(ce->mp->mp_rtl.RECTANGLE);
71    eina_mempool_del(ce->mp->mp_rtl.TEXT);
72    eina_mempool_del(ce->mp->mp_rtl.IMAGE);
73    eina_mempool_del(ce->mp->mp_rtl.PROXY);
74    eina_mempool_del(ce->mp->mp_rtl.SWALLOW);
75    eina_mempool_del(ce->mp->mp_rtl.TEXTBLOCK);
76    eina_mempool_del(ce->mp->mp_rtl.GROUP);
77    eina_mempool_del(ce->mp->mp_rtl.BOX);
78    eina_mempool_del(ce->mp->mp_rtl.TABLE);
79    eina_mempool_del(ce->mp->mp_rtl.EXTERNAL);
80    eina_mempool_del(ce->mp->mp_rtl.SPACER);
81    eina_mempool_del(ce->mp->mp_rtl.SNAPSHOT);
82    eina_mempool_del(ce->mp->mp_rtl.VECTOR);
83    memset(&ce->mp->mp_rtl, 0, sizeof(ce->mp->mp_rtl));
84 
85    free(ce->mp);
86 }
87 
88 void
_edje_programs_patterns_init(Edje_Part_Collection * edc)89 _edje_programs_patterns_init(Edje_Part_Collection *edc)
90 {
91    Edje_Signals_Sources_Patterns *ssp = &edc->patterns.programs;
92    Edje_Program **all;
93    unsigned int i, j;
94 
95    if (ssp->signals_patterns)
96      return;
97 
98    static signed char dump_programs = -1;
99 
100    if (dump_programs == -1)
101      {
102         if (getenv("EDJE_DUMP_PROGRAMS")) dump_programs = 1;
103         else dump_programs = 0;
104      }
105    if (dump_programs == 1)
106      {
107         INF("Group '%s' programs:", edc->part);
108 #define EDJE_DUMP_PROGRAM(Section)                    \
109   for (i = 0; i < edc->programs.Section##_count; i++) \
110     INF(#Section " for ('%s', '%s')", edc->programs.Section[i]->signal, edc->programs.Section[i]->source);
111 
112         EDJE_DUMP_PROGRAM(strcmp);
113         EDJE_DUMP_PROGRAM(strncmp);
114         EDJE_DUMP_PROGRAM(strrncmp);
115         EDJE_DUMP_PROGRAM(fnmatch);
116         EDJE_DUMP_PROGRAM(nocmp);
117      }
118 
119    edje_match_program_hash_build(edc->programs.strcmp,
120                                  edc->programs.strcmp_count,
121                                  &ssp->exact_match);
122 
123    j = edc->programs.strncmp_count
124      + edc->programs.strrncmp_count
125      + edc->programs.fnmatch_count
126      + edc->programs.nocmp_count;
127    if (j == 0) return;
128 
129    all = malloc(sizeof (Edje_Program *) * j);
130    if (!all) return;
131    j = 0;
132 
133    /* FIXME: Build specialized data type for each case */
134 #define EDJE_LOAD_PROGRAMS_ADD(Array, Edc, It, Git, All)                \
135    for (It = 0; It < Edc->programs.Array##_count; ++It, ++Git)          \
136      All[Git] = Edc->programs.Array[It];
137 
138    EDJE_LOAD_PROGRAMS_ADD(fnmatch, edc, i, j, all);
139    EDJE_LOAD_PROGRAMS_ADD(strncmp, edc, i, j, all);
140    EDJE_LOAD_PROGRAMS_ADD(strrncmp, edc, i, j, all);
141    /* FIXME: Do a special pass for that one */
142    EDJE_LOAD_PROGRAMS_ADD(nocmp, edc, i, j, all);
143 
144    ssp->u.programs.globing = all;
145    ssp->u.programs.count = j;
146    ssp->signals_patterns = edje_match_programs_signal_init(all, j);
147    ssp->sources_patterns = edje_match_programs_source_init(all, j);
148 }
149 
150 static inline void
_edje_part_collection_fix(Edje_Part_Collection * edc)151 _edje_part_collection_fix(Edje_Part_Collection *edc)
152 {
153    if (edc->checked) return;
154 
155    edc->checked = 1;
156 
157    unsigned int j;
158    Edje_Part *ep;
159    Eina_Array hist;
160 
161    eina_array_step_set(&hist, sizeof(Eina_Array), 5);
162 
163    for (j = 0; j < edc->parts_count; ++j)
164      {
165         Edje_Part *ep2;
166         ep = edc->parts[j];
167 
168         /* Register any color classes in this parts descriptions. */
169         eina_array_push(&hist, ep);
170         ep2 = ep;
171         while (ep2->dragable.confine_id >= 0)
172           {
173              if (ep2->dragable.confine_id >= (int)edc->parts_count)
174                {
175                   ERR("confine_to above limit. invalidating it.");
176                   ep2->dragable.confine_id = -1;
177                   break;
178                }
179 
180              ep2 = edc->parts[ep2->dragable.confine_id];
181              if (eina_array_find(&hist, ep2, NULL))
182                {
183                   ERR("confine_to loops. invalidating loop.");
184                   ep2->dragable.confine_id = -1;
185                   break;
186                }
187              eina_array_push(&hist, ep2);
188           }
189         eina_array_clean(&hist);
190 
191         eina_array_push(&hist, ep);
192         ep2 = ep;
193         while (ep2->dragable.event_id >= 0)
194           {
195              Edje_Part *prev;
196 
197              if (ep2->dragable.event_id >= (int)edc->parts_count)
198                {
199                   ERR("event_id above limit. invalidating it.");
200                   ep2->dragable.event_id = -1;
201                   break;
202                }
203              prev = ep2;
204 
205              ep2 = edc->parts[ep2->dragable.event_id];
206              /* events_to may be used only with dragable */
207              if (!ep2->dragable.x && !ep2->dragable.y)
208                {
209                   prev->dragable.event_id = -1;
210                   break;
211                }
212 
213              if (eina_array_find(&hist, ep2, NULL))
214                {
215                   ERR("events_to loops. invalidating loop.");
216                   ep2->dragable.event_id = -1;
217                   break;
218                }
219              eina_array_push(&hist, ep2);
220           }
221         eina_array_clean(&hist);
222 
223         eina_array_push(&hist, ep);
224         ep2 = ep;
225         while (ep2->clip_to_id >= 0)
226           {
227              if (ep2->clip_to_id >= (int)edc->parts_count)
228                {
229                   ERR("clip_to_id above limit. invalidating it.");
230                   ep2->clip_to_id = -1;
231                   break;
232                }
233 
234              ep2 = edc->parts[ep2->clip_to_id];
235              if (eina_array_find(&hist, ep2, NULL))
236                {
237                   ERR("clip_to loops. invalidating loop.");
238                   ep2->clip_to_id = -1;
239                   break;
240                }
241              eina_array_push(&hist, ep2);
242           }
243         eina_array_clean(&hist);
244      }
245      eina_array_flush(&hist);
246 }
247 
248 static Edje_Part_Collection *
_edje_file_coll_open(Edje_File * edf,const char * coll)249 _edje_file_coll_open(Edje_File *edf, const char *coll)
250 {
251    Edje_Part_Collection *edc = NULL;
252    Edje_Part_Collection_Directory_Entry *ce;
253    int id = -1, size = 0;
254    unsigned int n;
255    Eina_List *l;
256    char buf[256];
257    void *data;
258 
259    ce = eina_hash_find(edf->collection, coll);
260    if (!ce) return NULL;
261 
262    if (ce->ref)
263      {
264         ce->ref->references++;
265         return ce->ref;
266      }
267 
268    EINA_LIST_FOREACH(edf->collection_cache, l, edc)
269      {
270         if (!strcmp(edc->part, coll))
271           {
272              edc->references = 1;
273              ce->ref = edc;
274 
275              edf->collection_cache = eina_list_remove_list(edf->collection_cache, l);
276              return ce->ref;
277           }
278      }
279 
280    id = ce->id;
281    if (id < 0) return NULL;
282 
283    edje_cache_emp_alloc(ce);
284    snprintf(buf, sizeof(buf), "edje/collections/%i", id);
285    edc = eet_data_read(edf->ef, _edje_edd_edje_part_collection, buf);
286    if (!edc) return NULL;
287 
288    edc->references = 1;
289    edc->part = ce->entry;
290 
291    /* For Edje file build with Edje 1.0 */
292    if (edf->version <= 3 && edf->minor <= 1)
293      {
294         /* This will preserve previous rendering */
295         unsigned int i;
296 
297         /* people expect signal to not be broadcasted */
298         edc->broadcast_signal = EINA_FALSE;
299 
300         /* people expect text.align to be 0.0 0.0 */
301         for (i = 0; i < edc->parts_count; ++i)
302           {
303              if (edc->parts[i]->type == EDJE_PART_TYPE_TEXTBLOCK)
304                {
305                   Edje_Part_Description_Text *text;
306                   unsigned int j;
307 
308                   text = (Edje_Part_Description_Text *)edc->parts[i]->default_desc;
309                   text->text.align.x = TO_DOUBLE(0.0);
310                   text->text.align.y = TO_DOUBLE(0.0);
311 
312                   for (j = 0; j < edc->parts[i]->other.desc_count; ++j)
313                     {
314                        text = (Edje_Part_Description_Text *)edc->parts[i]->other.desc[j];
315                        text->text.align.x = TO_DOUBLE(0.0);
316                        text->text.align.y = TO_DOUBLE(0.0);
317                     }
318                }
319           }
320      }
321 
322    snprintf(buf, sizeof(buf), "edje/scripts/embryo/compiled/%i", id);
323    data = eet_read(edf->ef, buf, &size);
324 
325    if (data)
326      {
327         edc->script = embryo_program_new(data, size);
328         _edje_embryo_script_init(edc);
329         free(data);
330      }
331 
332    snprintf(buf, sizeof(buf), "edje/scripts/lua/%i", id);
333    data = eet_read(edf->ef, buf, &size);
334 
335    if (data)
336      {
337         _edje_lua2_script_load(edc, data, size);
338         free(data);
339      }
340 
341    ce->ref = edc;
342 
343    _edje_programs_patterns_init(edc);
344 
345    n = edc->programs.fnmatch_count +
346      edc->programs.strcmp_count +
347      edc->programs.strncmp_count +
348      edc->programs.strrncmp_count +
349      edc->programs.nocmp_count;
350 
351    if (n > 0)
352      {
353         Edje_Program *pr;
354         unsigned int i;
355 
356         edc->patterns.table_programs = malloc(sizeof(Edje_Program *) * n);
357         if (edc->patterns.table_programs)
358           {
359              edc->patterns.table_programs_size = n;
360 
361 #define EDJE_LOAD_BUILD_TABLE(Array, Edc, It, Tmp)                      \
362              for (It = 0; It < Edc->programs.Array##_count; ++It)       \
363                {                                                        \
364                   Tmp = Edc->programs.Array[It];                        \
365                   Edc->patterns.table_programs[Tmp->id] = Tmp;          \
366                   if (!Edc->need_seat && Tmp->signal && !strncmp(Tmp->signal, "seat,", 5)) \
367                     Edc->need_seat = EINA_TRUE;                         \
368                }
369 
370              EDJE_LOAD_BUILD_TABLE(fnmatch, edc, i, pr);
371              EDJE_LOAD_BUILD_TABLE(strcmp, edc, i, pr);
372              EDJE_LOAD_BUILD_TABLE(strncmp, edc, i, pr);
373              EDJE_LOAD_BUILD_TABLE(strrncmp, edc, i, pr);
374              EDJE_LOAD_BUILD_TABLE(nocmp, edc, i, pr);
375           }
376      }
377 
378    /* Search for the use of allowed seat used by part if we still do not know if seat are needed. */
379    if (!edc->need_seat)
380      {
381         unsigned int i;
382 
383         for (i = 0; i < edc->parts_count; i++)
384           {
385              Edje_Part *part = edc->parts[i];
386 
387              if (part->allowed_seats)
388                {
389                   edc->need_seat = EINA_TRUE;
390                   break;
391                }
392           }
393      }
394 
395    _edje_part_collection_fix(edc);
396 
397    return edc;
398 }
399 
400 void
_edje_extract_mo_files(Edje_File * edf)401 _edje_extract_mo_files(Edje_File *edf)
402 {
403    Eina_Strbuf *mo_id_str;
404    const void *data;
405    const char *cache_path;
406    const char *filename;
407    unsigned int crc;
408    time_t t;
409    size_t sz;
410    unsigned int i;
411    int len;
412 
413    cache_path = efreet_cache_home_get();
414 
415    t = eina_file_mtime_get(edf->f);
416    sz = eina_file_size_get(edf->f);
417    filename = eina_file_filename_get(edf->f);
418    crc = eina_crc(filename, strlen(filename), 0xffffffff, EINA_TRUE);
419 
420    snprintf(edf->fid, sizeof(edf->fid), "%lld-%lld-%x",
421             (long long int)t,
422             (long long int)sz,
423             crc);
424 
425    mo_id_str = eina_strbuf_new();
426 
427    for (i = 0; i < edf->mo_dir->mo_entries_count; i++)
428      {
429         Edje_Mo *mo_entry;
430         char out[PATH_MAX + PATH_MAX + 128];
431         char outdir[PATH_MAX];
432         char *sub_str;
433         char *mo_src;
434 
435         mo_entry = &edf->mo_dir->mo_entries[i];
436 
437         eina_strbuf_append_printf(mo_id_str,
438                                   "edje/mo/%i/%s/LC_MESSAGES",
439                                   mo_entry->id,
440                                   mo_entry->locale);
441         data = eet_read_direct(edf->ef,
442                                eina_strbuf_string_get(mo_id_str),
443                                &len);
444 
445         if (data)
446           {
447              snprintf(outdir, sizeof(outdir),
448                       "%s/edje/%s/LC_MESSAGES",
449                       cache_path, mo_entry->locale);
450              ecore_file_mkpath(outdir);
451              mo_src = strdup(mo_entry->mo_src);
452              sub_str = strstr(mo_src, ".po");
453 
454              if (sub_str)
455                sub_str[1] = 'm';
456 
457              snprintf(out, sizeof(out), "%s/%s-%s",
458                       outdir, edf->fid, mo_src);
459              if (ecore_file_exists(out))
460                {
461                   if (edf->mtime > ecore_file_mod_time(out))
462                     ecore_file_remove(out);
463                }
464              if (!ecore_file_exists(out))
465                {
466                   FILE *f;
467 
468                   f = fopen(out, "wb");
469                   if (f)
470                     {
471                        if (fwrite(data, len, 1, f) != 1)
472                          ERR("Could not write mo: %s: %s", out, strerror(errno));
473                        fclose(f);
474                     }
475                   else
476                     ERR("Could not open for writing mo: %s: %s", out, strerror(errno));
477                }
478              free(mo_src);
479           }
480 
481         eina_strbuf_reset(mo_id_str);
482      }
483 
484    eina_strbuf_free(mo_id_str);
485 }
486 
487 // XXX: this is not pretty. some oooooold edje files do not store strings
488 // in their dictionary for hashes. this works around crashes loading such
489 // files
490 extern size_t  _edje_data_string_mapping_size;
491 extern void   *_edje_data_string_mapping;
492 
493 static Edje_File *
_edje_file_open(const Eina_File * f,int * error_ret,time_t mtime,Eina_Bool coll)494 _edje_file_open(const Eina_File *f, int *error_ret, time_t mtime, Eina_Bool coll)
495 {
496    Edje_Color_Tree_Node *ctn;
497    Edje_Color_Class *cc;
498    Edje_Text_Class *tc;
499    Edje_Size_Class *sc;
500    Edje_Style      *stl;
501    Edje_File *edf;
502    Eina_List *l, *ll;
503    Eet_File *ef;
504    char *name;
505    void *mapping;
506    size_t mapping_size;
507 
508    ef = eet_mmap(f);
509    if (!ef)
510      {
511         *error_ret = EDJE_LOAD_ERROR_UNKNOWN_FORMAT;
512         return NULL;
513      }
514    // XXX: ancient edje file workaround
515    mapping = eina_file_map_all((Eina_File *)f, EINA_FILE_SEQUENTIAL);
516    if (mapping)
517      {
518         mapping_size = eina_file_size_get(f);
519         _edje_data_string_mapping = mapping;
520         _edje_data_string_mapping_size = mapping_size;
521      }
522    edf = eet_data_read(ef, _edje_edd_edje_file, "edje/file");
523    // XXX: ancient edje file workaround
524    if (mapping)
525      {
526         eina_file_map_free((Eina_File *)f, mapping);
527         _edje_data_string_mapping = NULL;
528      }
529    if (!edf)
530      {
531         *error_ret = EDJE_LOAD_ERROR_CORRUPT_FILE;
532         eet_close(ef);
533         return NULL;
534      }
535 
536    edf->f = eina_file_dup(f);
537    edf->ef = ef;
538    edf->mtime = mtime;
539 
540    if (edf->version != EDJE_FILE_VERSION)
541      {
542         *error_ret = EDJE_LOAD_ERROR_INCOMPATIBLE_FILE;
543         _edje_file_free(edf);
544         return NULL;
545      }
546    if (!edf->collection && coll)
547      {
548         *error_ret = EDJE_LOAD_ERROR_CORRUPT_FILE;
549         _edje_file_free(edf);
550         return NULL;
551      }
552 
553    if (edf->minor > EDJE_FILE_MINOR)
554      {
555         WRN("`%s` may use feature from a newer edje and could not show up as expected.",
556             eina_file_filename_get(f));
557      }
558    if (edf->base_scale <= ZERO)
559      {
560         edf->base_scale = FROM_INT(1);
561         WRN("The base_scale can not be a 0.0. It is changed the default value(1.0)");
562      }
563 
564    /* Set default efl_version if there is no version information */
565    if ((edf->efl_version.major == 0) && (edf->efl_version.minor == 0))
566      {
567         edf->efl_version.major = 1;
568         edf->efl_version.minor = 18;
569      }
570 
571    edf->path = eina_stringshare_add(eina_file_filename_get(f));
572    edf->references = 1;
573 
574    /* This should be done at edje generation time */
575    _edje_file_textblock_style_parse_and_fix(edf);
576 
577    edf->style_hash = eina_hash_string_small_new(NULL);
578    EINA_LIST_FOREACH(edf->styles, l, stl)
579      if (stl->name)
580        eina_hash_direct_add(edf->style_hash, stl->name, stl);
581 
582    edf->color_tree_hash = eina_hash_string_small_new(NULL);
583    EINA_LIST_FOREACH(edf->color_tree, l, ctn)
584      EINA_LIST_FOREACH(ctn->color_classes, ll, name)
585        eina_hash_add(edf->color_tree_hash, name, ctn);
586 
587    edf->color_hash = eina_hash_string_small_new(NULL);
588    EINA_LIST_FOREACH(edf->color_classes, l, cc)
589      if (cc->name)
590        eina_hash_direct_add(edf->color_hash, cc->name, cc);
591 
592    edf->text_hash = eina_hash_string_small_new(NULL);
593    EINA_LIST_FOREACH(edf->text_classes, l, tc)
594      {
595         if (tc->name)
596           eina_hash_direct_add(edf->text_hash, tc->name, tc);
597 
598         if (tc->font)
599           tc->font = eina_stringshare_add(tc->font);
600      }
601 
602    edf->size_hash = eina_hash_string_small_new(NULL);
603    EINA_LIST_FOREACH(edf->size_classes, l, sc)
604      if (sc->name)
605        eina_hash_direct_add(edf->size_hash, sc->name, sc);
606 
607    if (edf->requires_count)
608      {
609         unsigned int i;
610         Edje_File *required_edf;
611         char **requires = (char**)edf->requires;
612 
613         /* EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING returns an mmapped blob, not stringshares */
614         edf->requires = malloc(edf->requires_count * sizeof(char*));
615         for (i = 0; i < edf->requires_count; i++)
616           {
617              char *str = (char*)requires[i];
618 
619              edf->requires[i] = eina_stringshare_add(str);
620              required_edf = eina_hash_find(_edje_id_hash, edf->requires[i]);
621              if (required_edf)
622                {
623                   required_edf->references++;
624                   continue;
625                }
626              ERR("edje file '%s' REQUIRES file '%s' which is not loaded", edf->path, edf->requires[i]);
627              if (!_edje_requires_pending)
628                _edje_requires_pending = eina_hash_stringshared_new(NULL);
629              eina_hash_list_append(_edje_requires_pending, edf->requires[i], edf);
630           }
631         free(requires);
632      }
633    if (_edje_requires_pending && edf->id)
634      {
635         l = eina_hash_set(_edje_requires_pending, edf->id, NULL);
636 
637         edf->references += eina_list_count(l);
638         eina_list_free(l);
639 
640         if (!eina_hash_population(_edje_requires_pending))
641           {
642              eina_hash_free(_edje_requires_pending);
643              _edje_requires_pending = NULL;
644           }
645      }
646 
647    if (edf->external_dir)
648      {
649         unsigned int i;
650 
651         for (i = 0; i < edf->external_dir->entries_count; ++i)
652           edje_module_load(edf->external_dir->entries[i].entry);
653      }
654 
655    // this call is unnecessary as we are doing same opeartion
656    // inside _edje_textblock_style_parse_and_fix() function
657    // remove ??
658    //_edje_textblock_style_all_update(ed);
659 
660    if (edf->mo_dir)
661      _edje_extract_mo_files(edf);
662 
663    return edf;
664 }
665 
666 #if 0
667 // FIXME: find a way to remove dangling file earlier
668 static void
669 _edje_file_dangling(Edje_File *edf)
670 {
671    if (edf->dangling) return;
672    edf->dangling = EINA_TRUE;
673 
674    eina_hash_del(_edje_file_hash, &edf->f, edf);
675    if (!eina_hash_population(_edje_file_hash))
676      {
677         eina_hash_free(_edje_file_hash);
678         _edje_file_hash = NULL;
679      }
680 }
681 
682 #endif
683 
684 static inline void
_edje_file_cache_init()685 _edje_file_cache_init()
686 {
687    if (!_edje_id_hash)
688      _edje_id_hash = eina_hash_stringshared_new(NULL);
689    if (!_edje_file_hash)
690      _edje_file_hash = eina_hash_pointer_new(NULL);
691 }
692 
693 static inline Edje_File*
_edje_file_cache_trash_pop(const Eina_File * file)694 _edje_file_cache_trash_pop(const Eina_File *file)
695 {
696    Edje_File *edf;
697    Eina_List *l;
698 
699    EINA_LIST_FOREACH(_edje_file_cache, l, edf)
700      {
701         if (edf->f == file)
702           {
703              edf->references = 1;
704              _edje_file_cache = eina_list_remove_list(_edje_file_cache, l);
705              eina_hash_direct_add(_edje_file_hash, &edf->f, edf);
706              return edf;
707           }
708      }
709    return NULL;
710 }
711 
712 Edje_File*
_edje_file_cache_find(const Eina_File * file)713 _edje_file_cache_find(const Eina_File *file)
714 {
715    Edje_File *edf;
716 
717    // initialize cache.
718    _edje_file_cache_init();
719 
720    // serach in the file_hash.
721    edf = eina_hash_find(_edje_file_hash, &file);
722    if (edf)
723      {
724         edf->references++;
725         return edf;
726      }
727 
728    // search in the trash list
729    return _edje_file_cache_trash_pop(file);
730 }
731 
732 static inline void
_edje_file_cache_add(Edje_File * edf)733 _edje_file_cache_add(Edje_File *edf)
734 {
735    eina_hash_direct_add(_edje_file_hash, &edf->f, edf);
736    if (edf->id)
737      eina_hash_list_append(_edje_id_hash, edf->id, edf);
738 }
739 
740 Edje_File *
_edje_cache_file_coll_open(const Eina_File * file,const char * coll,int * error_ret,Edje_Part_Collection ** edc_ret,Edje * ed EINA_UNUSED)741 _edje_cache_file_coll_open(const Eina_File *file, const char *coll, int *error_ret, Edje_Part_Collection **edc_ret, Edje *ed EINA_UNUSED)
742 {
743    Edje_File *edf;
744    Edje_Part_Collection *edc;
745 
746    edf = _edje_file_cache_find(file);
747 
748    if (!edf)
749      {
750         edf = _edje_file_open(file, error_ret, eina_file_mtime_get(file), !!coll);
751         if (!edf) return NULL;
752         _edje_file_cache_add(edf);
753      }
754 
755    if (!coll)
756      return edf;
757 
758    edc = _edje_file_coll_open(edf, coll);
759    if (!edc)
760      *error_ret = EDJE_LOAD_ERROR_UNKNOWN_COLLECTION;
761 
762    if (edc_ret) *edc_ret = edc;
763 
764    return edf;
765 }
766 
767 void
_edje_cache_coll_clean(Edje_File * edf)768 _edje_cache_coll_clean(Edje_File *edf)
769 {
770    while ((edf->collection_cache) &&
771           (eina_list_count(edf->collection_cache) > (unsigned int)_edje_collection_cache_size))
772      {
773         Edje_Part_Collection_Directory_Entry *ce;
774         Edje_Part_Collection *edc;
775 
776         edc = eina_list_data_get(eina_list_last(edf->collection_cache));
777         edf->collection_cache = eina_list_remove_list(edf->collection_cache, eina_list_last(edf->collection_cache));
778 
779         ce = eina_hash_find(edf->collection, edc->part);
780         _edje_collection_free(edf, edc, ce);
781      }
782 }
783 
784 void
_edje_cache_coll_flush(Edje_File * edf)785 _edje_cache_coll_flush(Edje_File *edf)
786 {
787    while (edf->collection_cache)
788      {
789         Edje_Part_Collection_Directory_Entry *ce;
790         Edje_Part_Collection *edc;
791         Eina_List *last;
792 
793         last = eina_list_last(edf->collection_cache);
794         edc = eina_list_data_get(last);
795         edf->collection_cache = eina_list_remove_list(edf->collection_cache,
796                                                       last);
797 
798         ce = eina_hash_find(edf->collection, edc->part);
799         _edje_collection_free(edf, edc, ce);
800      }
801 }
802 
803 void
_edje_cache_coll_unref(Edje_File * edf,Edje_Part_Collection * edc)804 _edje_cache_coll_unref(Edje_File *edf, Edje_Part_Collection *edc)
805 {
806    Edje_Part_Collection_Directory_Entry *ce;
807 
808    edc->references--;
809    if (edc->references != 0) return;
810 
811    ce = eina_hash_find(edf->collection, edc->part);
812    if (!ce)
813      {
814         ERR("Something is wrong with reference count of '%s'.", edc->part);
815      }
816    else if (ce->ref)
817      {
818         ce->ref = NULL;
819 
820         if (edf->dangling)
821           {
822              /* No need to keep the collection around if the file is dangling */
823              _edje_collection_free(edf, edc, ce);
824              _edje_cache_coll_flush(edf);
825           }
826         else
827           {
828              edf->collection_cache = eina_list_prepend(edf->collection_cache, edc);
829              _edje_cache_coll_clean(edf);
830           }
831      }
832 }
833 
834 static void
_edje_cache_file_clean(void)835 _edje_cache_file_clean(void)
836 {
837    int count;
838 
839    count = eina_list_count(_edje_file_cache);
840    while ((_edje_file_cache) && (count > _edje_file_cache_size))
841      {
842         Eina_List *last;
843         Edje_File *edf;
844 
845         last = eina_list_last(_edje_file_cache);
846         edf = eina_list_data_get(last);
847         _edje_file_cache = eina_list_remove_list(_edje_file_cache, last);
848         _edje_file_free(edf);
849         count = eina_list_count(_edje_file_cache);
850      }
851 }
852 
853 EAPI void
_edje_cache_file_unref(Edje_File * edf)854 _edje_cache_file_unref(Edje_File *edf)
855 {
856    edf->references--;
857    if (edf->references != 0) return;
858 
859    if (edf->requires_count)
860      {
861         unsigned int i;
862 
863         for (i = 0; i < edf->requires_count; i++)
864           {
865              Edje_File *required_edf = eina_hash_find(_edje_id_hash, edf->requires[i]);
866 
867              if (required_edf)
868                _edje_cache_file_unref(edf);
869              else if (_edje_requires_pending)
870                {
871                   eina_hash_list_remove(_edje_requires_pending, edf->requires[i], edf);
872                   if (!eina_hash_population(_edje_requires_pending))
873                     {
874                        eina_hash_free(_edje_requires_pending);
875                        _edje_requires_pending = NULL;
876                     }
877                }
878           }
879      }
880 
881    if (edf->dangling)
882      {
883         _edje_file_free(edf);
884         return;
885      }
886 
887    if (edf->id)
888      eina_hash_list_remove(_edje_id_hash, edf->id, edf);
889    if (!eina_hash_population(_edje_id_hash))
890      {
891         eina_hash_free(_edje_id_hash);
892         _edje_id_hash = NULL;
893      }
894    eina_hash_del(_edje_file_hash, &edf->f, edf);
895    if (!eina_hash_population(_edje_file_hash))
896      {
897         eina_hash_free(_edje_file_hash);
898         _edje_file_hash = NULL;
899      }
900    _edje_file_cache = eina_list_prepend(_edje_file_cache, edf);
901    _edje_cache_file_clean();
902 }
903 
904 void
_edje_file_cache_shutdown(void)905 _edje_file_cache_shutdown(void)
906 {
907    edje_file_cache_flush();
908 }
909 
910 /*============================================================================*
911 *                                 Global                                     *
912 *============================================================================*/
913 
914 /*============================================================================*
915 *                                   API                                      *
916 *============================================================================*/
917 
918 EAPI void
edje_file_cache_set(int count)919 edje_file_cache_set(int count)
920 {
921    if (count < 0) count = 0;
922    _edje_file_cache_size = count;
923    _edje_cache_file_clean();
924 }
925 
926 EAPI int
edje_file_cache_get(void)927 edje_file_cache_get(void)
928 {
929    return _edje_file_cache_size;
930 }
931 
932 EAPI void
edje_file_cache_flush(void)933 edje_file_cache_flush(void)
934 {
935    int ps;
936 
937    ps = _edje_file_cache_size;
938    _edje_file_cache_size = 0;
939    _edje_cache_file_clean();
940    _edje_file_cache_size = ps;
941 }
942 
943 EAPI void
edje_collection_cache_set(int count)944 edje_collection_cache_set(int count)
945 {
946    Eina_List *l;
947    Edje_File *edf;
948 
949    if (count < 0) count = 0;
950    _edje_collection_cache_size = count;
951    EINA_LIST_FOREACH(_edje_file_cache, l, edf)
952      _edje_cache_coll_clean(edf);
953    /* FIXME: freach in file hash too! */
954 }
955 
956 EAPI int
edje_collection_cache_get(void)957 edje_collection_cache_get(void)
958 {
959    return _edje_collection_cache_size;
960 }
961 
962 EAPI void
edje_collection_cache_flush(void)963 edje_collection_cache_flush(void)
964 {
965    int ps;
966    Eina_List *l;
967    Edje_File *edf;
968 
969    ps = _edje_collection_cache_size;
970    _edje_collection_cache_size = 0;
971    EINA_LIST_FOREACH(_edje_file_cache, l, edf)
972      _edje_cache_coll_flush(edf);
973    /* FIXME: freach in file hash too! */
974    _edje_collection_cache_size = ps;
975 }
976 
977