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