diff options
author | Vincent Torri <vincent.torri@gmail.com> | 2012-11-04 11:51:42 +0000 |
---|---|---|
committer | Vincent Torri <vincent.torri@gmail.com> | 2012-11-04 11:51:42 +0000 |
commit | c15e9c6575c3b5f39ded167dda5259de3de96151 (patch) | |
tree | 5115d7ae3620af24c2bc094cd062575af7adeda9 /src/lib/evas/cache2 | |
parent | a5ac6a987caec5a7f7596a25d0a065b9cc94c50c (diff) |
merge: and now Evas
I've tested make -j 3 install and it works nicely
I've tested expedite with software and opengl xlib,
and it works. Not tested other engines, so please
report any problems (engines or other) on the ML.
TODO: examples and tests, I'll add them later
ISSUE: Eina_Unicode size check. It indirectly depends on
eina_config.h, which is created at the end of the
configure script. So its size is always 0. I don't
know how that size is used, so I can't do a lot,
for now.
SVN revision: 78895
Diffstat (limited to 'src/lib/evas/cache2')
-rw-r--r-- | src/lib/evas/cache2/evas_cache2.c | 958 | ||||
-rw-r--r-- | src/lib/evas/cache2/evas_cache2.h | 87 |
2 files changed, 1045 insertions, 0 deletions
diff --git a/src/lib/evas/cache2/evas_cache2.c b/src/lib/evas/cache2/evas_cache2.c new file mode 100644 index 0000000000..1b9d05cbd8 --- /dev/null +++ b/src/lib/evas/cache2/evas_cache2.c | |||
@@ -0,0 +1,958 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | #include <assert.h> | ||
7 | #include <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <errno.h> | ||
10 | |||
11 | #ifdef HAVE_EVIL | ||
12 | # include <Evil.h> | ||
13 | #endif | ||
14 | |||
15 | #include "evas_common.h" | ||
16 | #include "evas_private.h" | ||
17 | #include "evas_cache2.h" | ||
18 | #include "evas_cs2.h" | ||
19 | #include "evas_cs2_private.h" | ||
20 | |||
21 | #define FREESTRC(Var) \ | ||
22 | if (Var) \ | ||
23 | { \ | ||
24 | eina_stringshare_del(Var); \ | ||
25 | Var = NULL; \ | ||
26 | } | ||
27 | |||
28 | static void _evas_cache_image_dirty_add(Image_Entry *im); | ||
29 | static void _evas_cache_image_dirty_del(Image_Entry *im); | ||
30 | static void _evas_cache_image_activ_add(Image_Entry *im); | ||
31 | static void _evas_cache_image_activ_del(Image_Entry *im); | ||
32 | static void _evas_cache_image_lru_add(Image_Entry *im); | ||
33 | static void _evas_cache_image_lru_del(Image_Entry *im); | ||
34 | static void _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target); | ||
35 | // static void _evas_cache_image_lru_nodata_add(Image_Entry *im); | ||
36 | // static void _evas_cache_image_lru_nodata_del(Image_Entry *im); | ||
37 | |||
38 | static void | ||
39 | _evas_cache_image_dirty_add(Image_Entry *im) | ||
40 | { | ||
41 | if (im->flags.dirty) return; | ||
42 | _evas_cache_image_activ_del(im); | ||
43 | _evas_cache_image_lru_del(im); | ||
44 | // _evas_cache_image_lru_nodata_del(im); | ||
45 | im->flags.dirty = 1; | ||
46 | im->flags.cached = 1; | ||
47 | im->cache2->dirty = eina_inlist_prepend(im->cache2->dirty, EINA_INLIST_GET(im)); | ||
48 | if (im->cache_key) | ||
49 | { | ||
50 | eina_stringshare_del(im->cache_key); | ||
51 | im->cache_key = NULL; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | static void | ||
56 | _evas_cache_image_dirty_del(Image_Entry *im) | ||
57 | { | ||
58 | if (!im->flags.dirty) return; | ||
59 | if (!im->cache2) return; | ||
60 | im->flags.dirty = 0; | ||
61 | im->flags.cached = 0; | ||
62 | im->cache2->dirty = eina_inlist_remove(im->cache2->dirty, EINA_INLIST_GET(im)); | ||
63 | } | ||
64 | |||
65 | static void | ||
66 | _evas_cache_image_activ_add(Image_Entry *im) | ||
67 | { | ||
68 | if (im->flags.activ) return; | ||
69 | _evas_cache_image_dirty_del(im); | ||
70 | _evas_cache_image_lru_del(im); | ||
71 | // _evas_cache_image_lru_nodata_del(im); | ||
72 | if (!im->cache_key) return; | ||
73 | im->flags.activ = 1; | ||
74 | im->flags.cached = 1; | ||
75 | eina_hash_direct_add(im->cache2->activ, im->cache_key, im); | ||
76 | } | ||
77 | |||
78 | static void | ||
79 | _evas_cache_image_activ_del(Image_Entry *im) | ||
80 | { | ||
81 | if (!im->flags.activ) return; | ||
82 | if (!im->cache_key) return; | ||
83 | im->flags.activ = 0; | ||
84 | im->flags.cached = 0; | ||
85 | eina_hash_del(im->cache2->activ, im->cache_key, im); | ||
86 | } | ||
87 | |||
88 | static void | ||
89 | _evas_cache_image_lru_add(Image_Entry *im) | ||
90 | { | ||
91 | if (im->flags.lru) return; | ||
92 | _evas_cache_image_dirty_del(im); | ||
93 | _evas_cache_image_activ_del(im); | ||
94 | // _evas_cache_image_lru_nodata_del(im); | ||
95 | if (!im->cache_key) return; | ||
96 | im->flags.lru = 1; | ||
97 | im->flags.cached = 1; | ||
98 | eina_hash_direct_add(im->cache2->inactiv, im->cache_key, im); | ||
99 | im->cache2->lru = eina_inlist_prepend(im->cache2->lru, EINA_INLIST_GET(im)); | ||
100 | im->cache2->usage += im->cache2->func.mem_size_get(im); | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | _evas_cache_image_lru_del(Image_Entry *im) | ||
105 | { | ||
106 | if (!im->flags.lru) return; | ||
107 | if (!im->cache_key) return; | ||
108 | im->flags.lru = 0; | ||
109 | im->flags.cached = 0; | ||
110 | eina_hash_del(im->cache2->inactiv, im->cache_key, im); | ||
111 | im->cache2->lru = eina_inlist_remove(im->cache2->lru, EINA_INLIST_GET(im)); | ||
112 | im->cache2->usage -= im->cache2->func.mem_size_get(im); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | static void | ||
117 | _evas_cache_image_lru_nodata_add(Image_Entry *im) | ||
118 | { | ||
119 | if (im->flags.lru_nodata) return; | ||
120 | _evas_cache_image_dirty_del(im); | ||
121 | _evas_cache_image_activ_del(im); | ||
122 | _evas_cache_image_lru_del(im); | ||
123 | im->flags.lru = 1; | ||
124 | im->flags.cached = 1; | ||
125 | im->cache2->lru_nodata = eina_inlist_prepend(im->cache2->lru_nodata, EINA_INLIST_GET(im)); | ||
126 | } | ||
127 | |||
128 | static void | ||
129 | _evas_cache_image_lru_nodata_del(Image_Entry *im) | ||
130 | { | ||
131 | if (!im->flags.lru_nodata) return; | ||
132 | im->flags.lru = 0; | ||
133 | im->flags.cached = 0; | ||
134 | im->cache2->lru_nodata = eina_inlist_remove(im->cache2->lru_nodata, EINA_INLIST_GET(im)); | ||
135 | } | ||
136 | */ | ||
137 | |||
138 | static Eina_Bool | ||
139 | _timestamp_compare(Image_Timestamp *tstamp, struct stat *st) | ||
140 | { | ||
141 | if (tstamp->mtime != st->st_mtime) return EINA_FALSE; | ||
142 | if (tstamp->size != st->st_size) return EINA_FALSE; | ||
143 | if (tstamp->ino != st->st_ino) return EINA_FALSE; | ||
144 | #ifdef _STAT_VER_LINUX | ||
145 | #if (defined __USE_MISC && defined st_mtime) | ||
146 | if (tstamp->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec) | ||
147 | return EINA_FALSE; | ||
148 | #else | ||
149 | if (tstamp->mtime_nsec != (unsigned long int)st->st_mtimensec) | ||
150 | return EINA_FALSE; | ||
151 | #endif | ||
152 | #endif | ||
153 | return EINA_TRUE; | ||
154 | } | ||
155 | |||
156 | static void | ||
157 | _timestamp_build(Image_Timestamp *tstamp, struct stat *st) | ||
158 | { | ||
159 | tstamp->mtime = st->st_mtime; | ||
160 | tstamp->size = st->st_size; | ||
161 | tstamp->ino = st->st_ino; | ||
162 | #ifdef _STAT_VER_LINUX | ||
163 | #if (defined __USE_MISC && defined st_mtime) | ||
164 | tstamp->mtime_nsec = (unsigned long int)st->st_mtim.tv_nsec; | ||
165 | #else | ||
166 | tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec; | ||
167 | #endif | ||
168 | #endif | ||
169 | } | ||
170 | |||
171 | static void | ||
172 | _evas_cache_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie) | ||
173 | { | ||
174 | if (!ie) return; | ||
175 | |||
176 | if (ie->flags.delete_me == 1) | ||
177 | return; | ||
178 | |||
179 | if (ie->preload_rid) | ||
180 | { | ||
181 | ie->flags.delete_me = 1; | ||
182 | _evas_cache2_image_entry_preload_remove(ie, NULL); | ||
183 | return; | ||
184 | } | ||
185 | |||
186 | _evas_cache_image_dirty_del(ie); | ||
187 | _evas_cache_image_activ_del(ie); | ||
188 | _evas_cache_image_lru_del(ie); | ||
189 | // _evas_cache_image_lru_nodata_del(ie); | ||
190 | |||
191 | |||
192 | if (ie->data1) | ||
193 | { | ||
194 | evas_cserve2_image_unload(ie); | ||
195 | evas_cache2_image_unload_data(ie); | ||
196 | evas_cserve2_image_free(ie); | ||
197 | } | ||
198 | else | ||
199 | { | ||
200 | if (cache) | ||
201 | cache->func.surface_delete(ie); | ||
202 | } | ||
203 | |||
204 | FREESTRC(ie->cache_key); | ||
205 | FREESTRC(ie->file); | ||
206 | FREESTRC(ie->key); | ||
207 | ie->cache2 = NULL; | ||
208 | |||
209 | evas_common_rgba_image_scalecache_shutdown(ie); | ||
210 | |||
211 | free(ie); | ||
212 | } | ||
213 | |||
214 | static Image_Entry * | ||
215 | _evas_cache_image_entry_new(Evas_Cache2 *cache, | ||
216 | const char *hkey, | ||
217 | Image_Timestamp *tstamp, | ||
218 | const char *file, | ||
219 | const char *key, | ||
220 | RGBA_Image_Loadopts *lo, | ||
221 | int *error) | ||
222 | { | ||
223 | Image_Entry *ie; | ||
224 | RGBA_Image *im; | ||
225 | |||
226 | // ie = cache->func.alloc(); | ||
227 | im = calloc(1, sizeof(RGBA_Image)); | ||
228 | if (!im) | ||
229 | { | ||
230 | *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; | ||
231 | return NULL; | ||
232 | } | ||
233 | |||
234 | im->flags = RGBA_IMAGE_NOTHING; | ||
235 | im->ref = 1; | ||
236 | evas_common_rgba_image_scalecache_init(&im->cache_entry); | ||
237 | |||
238 | ie = &im->cache_entry; | ||
239 | |||
240 | ie->cache2 = cache; | ||
241 | if (hkey) ie->cache_key = eina_stringshare_add(hkey); | ||
242 | ie->flags.need_data = 1; | ||
243 | ie->space = EVAS_COLORSPACE_ARGB8888; | ||
244 | ie->w = -1; | ||
245 | ie->h = -1; | ||
246 | ie->scale = 1; | ||
247 | if (file) ie->file = eina_stringshare_add(file); | ||
248 | if (key) ie->key = eina_stringshare_add(key); | ||
249 | if (tstamp) ie->tstamp = *tstamp; | ||
250 | else memset(&ie->tstamp, 0, sizeof(Image_Timestamp)); | ||
251 | |||
252 | if (lo) ie->load_opts = *lo; | ||
253 | if (ie->file) | ||
254 | { | ||
255 | if (!evas_cserve2_image_load(ie, ie->file, ie->key, &(ie->load_opts))) | ||
256 | { | ||
257 | ERR("couldn't load '%s' '%s' with cserve2!", | ||
258 | ie->file, ie->key ? ie->key : ""); | ||
259 | _evas_cache_image_entry_delete(cache, ie); | ||
260 | return NULL; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | if (ie->cache_key) _evas_cache_image_activ_add(ie); | ||
265 | else _evas_cache_image_dirty_add(ie); | ||
266 | return ie; | ||
267 | } | ||
268 | |||
269 | EAPI void | ||
270 | evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h) | ||
271 | { | ||
272 | Evas_Cache2 *cache = ie->cache2; | ||
273 | int wmin = w > 0 ? w : 1; | ||
274 | int hmin = h > 0 ? h : 1; | ||
275 | |||
276 | if (cache->func.surface_alloc(ie, wmin, hmin)) | ||
277 | { | ||
278 | wmin = 0; | ||
279 | hmin = 0; | ||
280 | } | ||
281 | |||
282 | ie->w = wmin; | ||
283 | ie->h = hmin; | ||
284 | ie->allocated.w = wmin; | ||
285 | ie->allocated.h = hmin; | ||
286 | ie->flags.loaded = EINA_TRUE; | ||
287 | } | ||
288 | |||
289 | static void | ||
290 | _evas_cache2_image_preloaded_cb(void *data, Eina_Bool success) | ||
291 | { | ||
292 | Image_Entry *ie = data; | ||
293 | Evas_Cache_Target *tmp; | ||
294 | |||
295 | ie->cache2->preload = eina_list_remove(ie->cache2->preload, ie); | ||
296 | ie->flags.preload_done = success; | ||
297 | |||
298 | while ((tmp = ie->targets)) | ||
299 | { | ||
300 | ie->targets = (Evas_Cache_Target *) | ||
301 | eina_inlist_remove(EINA_INLIST_GET(ie->targets), | ||
302 | EINA_INLIST_GET(ie->targets)); | ||
303 | if (!ie->flags.delete_me) | ||
304 | evas_object_inform_call_image_preloaded((Evas_Object *) tmp->target); | ||
305 | free(tmp); | ||
306 | } | ||
307 | |||
308 | if (ie->flags.delete_me) | ||
309 | _evas_cache_image_entry_delete(ie->cache2, ie); | ||
310 | } | ||
311 | |||
312 | static Eina_Bool | ||
313 | _evas_cache2_image_entry_preload_add(Image_Entry *ie, const void *target) | ||
314 | { | ||
315 | Evas_Cache_Target *tg; | ||
316 | |||
317 | if (ie->flags.preload_done) | ||
318 | return EINA_FALSE; | ||
319 | |||
320 | tg = malloc(sizeof(Evas_Cache_Target)); | ||
321 | if (!tg) | ||
322 | return EINA_TRUE; | ||
323 | |||
324 | tg->target = target; | ||
325 | ie->targets = (Evas_Cache_Target *) | ||
326 | eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg)); | ||
327 | |||
328 | if (!ie->preload_rid) | ||
329 | { | ||
330 | ie->cache2->preload = eina_list_append(ie->cache2->preload, ie); | ||
331 | evas_cserve2_image_preload(ie, _evas_cache2_image_preloaded_cb); | ||
332 | } | ||
333 | |||
334 | return EINA_TRUE; | ||
335 | } | ||
336 | |||
337 | static void | ||
338 | _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target) | ||
339 | { | ||
340 | if (target) | ||
341 | { | ||
342 | Evas_Cache_Target *tg; | ||
343 | |||
344 | EINA_INLIST_FOREACH(ie->targets, tg) | ||
345 | { | ||
346 | if (tg->target == target) | ||
347 | { | ||
348 | ie->targets = (Evas_Cache_Target *) | ||
349 | eina_inlist_remove(EINA_INLIST_GET(ie->targets), | ||
350 | EINA_INLIST_GET(tg)); | ||
351 | free(tg); | ||
352 | break; | ||
353 | } | ||
354 | } | ||
355 | } | ||
356 | else | ||
357 | { | ||
358 | Evas_Cache_Target *tg; | ||
359 | |||
360 | while (ie->targets) | ||
361 | { | ||
362 | tg = ie->targets; | ||
363 | ie->targets = (Evas_Cache_Target *) | ||
364 | eina_inlist_remove(EINA_INLIST_GET(ie->targets), | ||
365 | EINA_INLIST_GET(tg)); | ||
366 | free(tg); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | // FIXME: Should also send message to the server to cancel the request. | ||
371 | } | ||
372 | |||
373 | EAPI Image_Entry * | ||
374 | evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace) | ||
375 | { | ||
376 | Image_Entry *im; | ||
377 | |||
378 | if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) || | ||
379 | (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) || | ||
380 | (cspace == EVAS_COLORSPACE_YCBCR422601_PL)) | ||
381 | w &= ~0x1; | ||
382 | |||
383 | im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL); | ||
384 | if (!im) | ||
385 | return NULL; | ||
386 | |||
387 | im->space = cspace; | ||
388 | im->flags.alpha = alpha; | ||
389 | evas_cache2_image_surface_alloc(im, w, h); | ||
390 | if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0) | ||
391 | { | ||
392 | _evas_cache_image_entry_delete(cache, im); | ||
393 | return NULL; | ||
394 | } | ||
395 | |||
396 | im->references = 1; | ||
397 | im->flags.loaded = EINA_TRUE; | ||
398 | if (cache->func.debug) cache->func.debug("copied-data", im); | ||
399 | |||
400 | return im; | ||
401 | } | ||
402 | |||
403 | EAPI Image_Entry * | ||
404 | evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace) | ||
405 | { | ||
406 | Image_Entry *im; | ||
407 | |||
408 | if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) || | ||
409 | (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) || | ||
410 | (cspace == EVAS_COLORSPACE_YCBCR422601_PL)) | ||
411 | w &= ~0x1; | ||
412 | |||
413 | im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL); | ||
414 | if (!im) return NULL; | ||
415 | im->w = w; | ||
416 | im->h = h; | ||
417 | im->flags.alpha = alpha; | ||
418 | im->flags.loaded = 1; | ||
419 | if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0) | ||
420 | { | ||
421 | _evas_cache_image_entry_delete(cache, im); | ||
422 | return NULL; | ||
423 | } | ||
424 | im->references = 1; | ||
425 | if (cache->func.debug) cache->func.debug("data", im); | ||
426 | return im; | ||
427 | } | ||
428 | |||
429 | EAPI Image_Entry * | ||
430 | evas_cache2_image_empty(Evas_Cache2 *cache) | ||
431 | { | ||
432 | Image_Entry *im; | ||
433 | |||
434 | im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL); | ||
435 | if (!im) | ||
436 | return NULL; | ||
437 | |||
438 | im->references = 1; | ||
439 | return im; | ||
440 | } | ||
441 | |||
442 | EAPI Image_Entry * | ||
443 | evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h) | ||
444 | { | ||
445 | Evas_Cache2 *cache; | ||
446 | Image_Entry *im2 = NULL; | ||
447 | int error; | ||
448 | |||
449 | if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) || | ||
450 | (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) || | ||
451 | (im->space == EVAS_COLORSPACE_YCBCR422601_PL)) | ||
452 | w &= ~0x1; | ||
453 | |||
454 | if ((im->w == w) && (im->h == h)) return im; | ||
455 | |||
456 | cache = im->cache2; | ||
457 | im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, | ||
458 | NULL); | ||
459 | if (!im2) goto on_error; | ||
460 | |||
461 | im2->flags.alpha = im->flags.alpha; | ||
462 | im2->space = im->space; | ||
463 | im2->load_opts = im->load_opts; | ||
464 | evas_cache2_image_surface_alloc(im2, w, h); | ||
465 | error = cache->func.size_set(im2, im, w, h); | ||
466 | if (error != 0) goto on_error; | ||
467 | |||
468 | im2->references = 1; | ||
469 | |||
470 | evas_cache2_image_close(im); | ||
471 | return im2; | ||
472 | |||
473 | on_error: | ||
474 | if (im2) | ||
475 | _evas_cache_image_entry_delete(cache, im2); | ||
476 | return NULL; | ||
477 | } | ||
478 | |||
479 | EAPI Evas_Cache2 * | ||
480 | evas_cache2_init(const Evas_Cache2_Image_Func *cb) | ||
481 | { | ||
482 | Evas_Cache2 *cache = calloc(1, sizeof(Evas_Cache2)); | ||
483 | |||
484 | cache->func = *cb; | ||
485 | cache->activ = eina_hash_string_superfast_new(NULL); | ||
486 | cache->inactiv = eina_hash_string_superfast_new(NULL); | ||
487 | |||
488 | return cache; | ||
489 | } | ||
490 | |||
491 | static Eina_Bool | ||
492 | _evas_cache_image_free_cb(EINA_UNUSED const Eina_Hash *hash, EINA_UNUSED const void *key, void *data, void *fdata) | ||
493 | { | ||
494 | Eina_List **delete_list = fdata; | ||
495 | *delete_list = eina_list_prepend(*delete_list, data); | ||
496 | return EINA_TRUE; | ||
497 | } | ||
498 | |||
499 | EAPI void | ||
500 | evas_cache2_shutdown(Evas_Cache2 *cache) | ||
501 | { | ||
502 | Eina_List *delete_list; | ||
503 | Image_Entry *im; | ||
504 | |||
505 | while (cache->lru) | ||
506 | { | ||
507 | im = (Image_Entry *)cache->lru; | ||
508 | _evas_cache_image_entry_delete(cache, im); | ||
509 | } | ||
510 | /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */ | ||
511 | while (cache->dirty) | ||
512 | { | ||
513 | im = (Image_Entry *)cache->dirty; | ||
514 | _evas_cache_image_entry_delete(cache, im); | ||
515 | } | ||
516 | |||
517 | delete_list = NULL; | ||
518 | eina_hash_foreach(cache->activ, _evas_cache_image_free_cb, &delete_list); | ||
519 | while (delete_list) | ||
520 | { | ||
521 | _evas_cache_image_entry_delete(cache, eina_list_data_get(delete_list)); | ||
522 | delete_list = eina_list_remove_list(delete_list, delete_list); | ||
523 | } | ||
524 | |||
525 | eina_hash_free(cache->activ); | ||
526 | eina_hash_free(cache->inactiv); | ||
527 | |||
528 | free(cache); | ||
529 | } | ||
530 | |||
531 | static void | ||
532 | _create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, RGBA_Image_Loadopts *lo) | ||
533 | { | ||
534 | const char *ckey = "(null)"; | ||
535 | size_t size; | ||
536 | |||
537 | /* generate hkey from file+key+load opts */ | ||
538 | memcpy(hkey, path, pathlen); | ||
539 | size = pathlen; | ||
540 | memcpy(hkey + size, "//://", 5); | ||
541 | size += 5; | ||
542 | if (key) ckey = key; | ||
543 | memcpy(hkey + size, ckey, keylen); | ||
544 | size += keylen; | ||
545 | if (lo) | ||
546 | { | ||
547 | memcpy(hkey + size, "//@/", 4); | ||
548 | size += 4; | ||
549 | size += eina_convert_xtoa(lo->scale_down_by, hkey + size); | ||
550 | hkey[size] = '/'; | ||
551 | size += 1; | ||
552 | size += eina_convert_dtoa(lo->dpi, hkey + size); | ||
553 | hkey[size] = '/'; | ||
554 | size += 1; | ||
555 | size += eina_convert_xtoa(lo->w, hkey + size); | ||
556 | hkey[size] = 'x'; | ||
557 | size += 1; | ||
558 | size += eina_convert_xtoa(lo->h, hkey + size); | ||
559 | hkey[size] = '/'; | ||
560 | size += 1; | ||
561 | size += eina_convert_xtoa(lo->region.x, hkey + size); | ||
562 | hkey[size] = '+'; | ||
563 | size += 1; | ||
564 | size += eina_convert_xtoa(lo->region.y, hkey + size); | ||
565 | hkey[size] = '.'; | ||
566 | size += 1; | ||
567 | size += eina_convert_xtoa(lo->region.w, hkey + size); | ||
568 | hkey[size] = 'x'; | ||
569 | size += 1; | ||
570 | size += eina_convert_xtoa(lo->region.h, hkey + size); | ||
571 | |||
572 | if (lo->orientation) | ||
573 | { | ||
574 | hkey[size] = '/'; | ||
575 | size += 1; | ||
576 | hkey[size] = 'o'; | ||
577 | size += 1; | ||
578 | } | ||
579 | } | ||
580 | hkey[size] = '\0'; | ||
581 | } | ||
582 | |||
583 | EAPI Image_Entry * | ||
584 | evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, RGBA_Image_Loadopts *lo, int *error) | ||
585 | { | ||
586 | size_t size; | ||
587 | size_t pathlen; | ||
588 | size_t keylen; | ||
589 | char *hkey; | ||
590 | Image_Entry *im; | ||
591 | int stat_done = 0, stat_failed = 0; | ||
592 | struct stat st; | ||
593 | Image_Timestamp tstamp; | ||
594 | Evas_Image_Load_Opts prevent = { 0, 0.0, 0, 0, 0, { 0, 0, 0, 0 }, EINA_FALSE }; | ||
595 | |||
596 | if ((!path) || ((!path) && (!key))) | ||
597 | { | ||
598 | *error = EVAS_LOAD_ERROR_GENERIC; | ||
599 | return NULL; | ||
600 | } | ||
601 | |||
602 | pathlen = strlen(path); | ||
603 | keylen = key ? strlen(key) : 6; | ||
604 | size = pathlen + keylen + 132; | ||
605 | hkey = alloca(sizeof(char) * size); | ||
606 | |||
607 | _create_hash_key(hkey, path, pathlen, key, keylen, lo); | ||
608 | DBG("Looking at the hash for key '%s'", hkey); | ||
609 | |||
610 | /* use local var to copy default load options to the image entry */ | ||
611 | if ((!lo) || | ||
612 | (lo && | ||
613 | (lo->scale_down_by == 0) && | ||
614 | (lo->dpi == 0.0) && | ||
615 | ((lo->w == 0) || (lo->h == 0)) && | ||
616 | ((lo->region.w == 0) || (lo->region.h == 0)) && | ||
617 | (lo->orientation == 0) | ||
618 | )) | ||
619 | { | ||
620 | lo = &prevent; | ||
621 | } | ||
622 | |||
623 | im = eina_hash_find(cache->activ, hkey); | ||
624 | |||
625 | if (im) | ||
626 | { | ||
627 | int ok = 1; | ||
628 | DBG("Found entry on active hash for key: '%s'", hkey); | ||
629 | |||
630 | stat_done = 1; | ||
631 | if (stat(path, &st) < 0) | ||
632 | { | ||
633 | stat_failed = 1; | ||
634 | ok = 0; | ||
635 | } | ||
636 | else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0; | ||
637 | if (ok) goto on_ok; | ||
638 | /* image we found doesn't match what's on disk (stat info wise) | ||
639 | * so dirty the active cache entry so we never find it again. this | ||
640 | * also implicitly guarantees that we only have 1 active copy | ||
641 | * of an image at a given key. we wither find it and keep re-reffing | ||
642 | * it or we dirty it and get it out */ | ||
643 | DBG("Entry on inactive hash was invalid (file changed or deleted)."); | ||
644 | _evas_cache_image_dirty_add(im); | ||
645 | im = NULL; | ||
646 | } | ||
647 | |||
648 | im = eina_hash_find(cache->inactiv, hkey); | ||
649 | |||
650 | if (im) | ||
651 | { | ||
652 | int ok = 1; | ||
653 | DBG("Found entry on inactive hash for key: '%s'", hkey); | ||
654 | |||
655 | if (!stat_done) | ||
656 | { | ||
657 | stat_done = 1; | ||
658 | if (stat(path, &st) < 0) | ||
659 | { | ||
660 | stat_failed = 1; | ||
661 | ok = 0; | ||
662 | } | ||
663 | else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0; | ||
664 | } | ||
665 | else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0; | ||
666 | |||
667 | if (ok) | ||
668 | { | ||
669 | /* remove from lru and make it active again */ | ||
670 | _evas_cache_image_lru_del(im); | ||
671 | _evas_cache_image_activ_add(im); | ||
672 | goto on_ok; | ||
673 | } | ||
674 | DBG("Entry on inactive hash was invalid (file changed or deleted)."); | ||
675 | /* as avtive cache find - if we match in lru and its invalid, dirty */ | ||
676 | _evas_cache_image_dirty_add(im); | ||
677 | /* this image never used, so it have to be deleted */ | ||
678 | _evas_cache_image_entry_delete(cache, im); | ||
679 | im = NULL; | ||
680 | } | ||
681 | if (stat_failed) goto on_stat_error; | ||
682 | |||
683 | if (!stat_done) | ||
684 | { | ||
685 | if (stat(path, &st) < 0) goto on_stat_error; | ||
686 | } | ||
687 | _timestamp_build(&tstamp, &st); | ||
688 | DBG("Creating a new entry for key '%s'.", hkey); | ||
689 | im = _evas_cache_image_entry_new(cache, hkey, &tstamp, path, key, | ||
690 | lo, error); | ||
691 | if (!im) goto on_stat_error; | ||
692 | |||
693 | on_ok: | ||
694 | *error = EVAS_LOAD_ERROR_NONE; | ||
695 | DBG("Using entry on hash for key '%s'", hkey); | ||
696 | |||
697 | im->references++; | ||
698 | |||
699 | return im; | ||
700 | |||
701 | on_stat_error: | ||
702 | #ifndef _WIN32 | ||
703 | if ((errno == ENOENT) || (errno == ENOTDIR) || | ||
704 | (errno == ENAMETOOLONG) || (errno == ELOOP)) | ||
705 | #else | ||
706 | if (errno == ENOENT) | ||
707 | #endif | ||
708 | *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; | ||
709 | #ifndef _WIN32 | ||
710 | else if ((errno == ENOMEM) || (errno == EOVERFLOW)) | ||
711 | #else | ||
712 | else if (errno == ENOMEM) | ||
713 | #endif | ||
714 | *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; | ||
715 | else if (errno == EACCES) | ||
716 | *error = EVAS_LOAD_ERROR_PERMISSION_DENIED; | ||
717 | else | ||
718 | *error = EVAS_LOAD_ERROR_GENERIC; | ||
719 | |||
720 | if (im) _evas_cache_image_entry_delete(cache, im); | ||
721 | return NULL; | ||
722 | } | ||
723 | |||
724 | EAPI int | ||
725 | evas_cache2_image_open_wait(Image_Entry *im) | ||
726 | { | ||
727 | DBG("Wait for open image '%s' '%s'", im->file, im->key); | ||
728 | if (evas_cserve2_image_load_wait(im) != CSERVE2_NONE) | ||
729 | return EVAS_LOAD_ERROR_GENERIC; | ||
730 | |||
731 | return EVAS_LOAD_ERROR_NONE; | ||
732 | } | ||
733 | |||
734 | EAPI void | ||
735 | evas_cache2_image_close(Image_Entry *im) | ||
736 | { | ||
737 | Evas_Cache2 *cache; | ||
738 | int references; | ||
739 | |||
740 | im->references--; | ||
741 | if (im->references < 0) | ||
742 | { | ||
743 | ERR("image with negative references: %d", im->references); | ||
744 | im->references = 0; | ||
745 | } | ||
746 | |||
747 | references = im->references; | ||
748 | cache = im->cache2; | ||
749 | |||
750 | if (references > 0) | ||
751 | return; | ||
752 | |||
753 | if (im->flags.dirty) | ||
754 | { | ||
755 | _evas_cache_image_entry_delete(cache, im); | ||
756 | return; | ||
757 | } | ||
758 | |||
759 | _evas_cache_image_lru_add(im); | ||
760 | if (cache) | ||
761 | evas_cache2_flush(cache); | ||
762 | } | ||
763 | |||
764 | EAPI int | ||
765 | evas_cache2_image_load_data(Image_Entry *ie) | ||
766 | { | ||
767 | int error = EVAS_LOAD_ERROR_NONE; | ||
768 | |||
769 | if ((ie->flags.loaded) && (!ie->flags.animated)) | ||
770 | return error; | ||
771 | |||
772 | ie->flags.in_progress = EINA_TRUE; | ||
773 | |||
774 | DBG("try cserve2 image data '%s' '%s'", | ||
775 | ie->file, ie->key ? ie->key : ""); | ||
776 | if (evas_cserve2_image_data_load(ie)) | ||
777 | { | ||
778 | evas_cserve2_image_load_data_wait(ie); | ||
779 | RGBA_Image *im = (RGBA_Image *)ie; | ||
780 | DBG("try cserve2 image data '%s' '%s' loaded!", | ||
781 | ie->file, ie->key ? ie->key : ""); | ||
782 | if (im->image.data) | ||
783 | { | ||
784 | error = EVAS_LOAD_ERROR_NONE; | ||
785 | } | ||
786 | else | ||
787 | { | ||
788 | ERR("Failed to load data for image '%s' '%s'.", | ||
789 | ie->file, ie->key ? ie->key : ""); | ||
790 | error = EVAS_LOAD_ERROR_GENERIC; | ||
791 | } | ||
792 | } | ||
793 | else | ||
794 | { | ||
795 | ERR("Couldn't send LOAD message to cserve2."); | ||
796 | error = EVAS_LOAD_ERROR_GENERIC; | ||
797 | } | ||
798 | |||
799 | ie->flags.in_progress = EINA_FALSE; | ||
800 | ie->flags.loaded = 1; | ||
801 | |||
802 | if (error != EVAS_LOAD_ERROR_NONE) | ||
803 | ie->flags.loaded = 0; | ||
804 | |||
805 | return error; | ||
806 | } | ||
807 | |||
808 | EAPI void | ||
809 | evas_cache2_image_unload_data(Image_Entry *im) | ||
810 | { | ||
811 | // FIXME: This function seems pretty useless, since we always have | ||
812 | // to send an UNLOAD message to the server when closing an image, | ||
813 | // even if we didn't send a LOAD message before, because the SETOPTS | ||
814 | // message increases the image refcount. | ||
815 | if (im->flags.in_progress) | ||
816 | return; | ||
817 | |||
818 | if ((!im->file)) | ||
819 | return; | ||
820 | |||
821 | if (!im->flags.loaded) | ||
822 | return; | ||
823 | } | ||
824 | |||
825 | EAPI void | ||
826 | evas_cache2_image_preload_data(Image_Entry *im, const void *target) | ||
827 | { | ||
828 | RGBA_Image *img = (RGBA_Image *)im; | ||
829 | |||
830 | if ((im->flags.loaded) && (img->image.data)) | ||
831 | { | ||
832 | evas_object_inform_call_image_preloaded((Evas_Object *)target); | ||
833 | return; | ||
834 | } | ||
835 | |||
836 | if (!_evas_cache2_image_entry_preload_add(im, target)) | ||
837 | evas_object_inform_call_image_preloaded((Evas_Object *)target); | ||
838 | } | ||
839 | |||
840 | EAPI void | ||
841 | evas_cache2_image_preload_cancel(Image_Entry *im, const void *target) | ||
842 | { | ||
843 | if (!target) | ||
844 | return; | ||
845 | |||
846 | _evas_cache2_image_entry_preload_remove(im, target); | ||
847 | } | ||
848 | |||
849 | EAPI DATA32 * | ||
850 | evas_cache2_image_pixels(Image_Entry *im) | ||
851 | { | ||
852 | return im->cache2->func.surface_pixels(im); | ||
853 | } | ||
854 | |||
855 | EAPI Image_Entry * | ||
856 | evas_cache2_image_writable(Image_Entry *im) | ||
857 | { | ||
858 | Evas_Cache2 *cache = im->cache2; | ||
859 | Image_Entry *im2 = NULL; | ||
860 | |||
861 | if (!im->cache_key) | ||
862 | { | ||
863 | if (!im->flags.dirty) | ||
864 | _evas_cache_image_dirty_add(im); | ||
865 | return im; | ||
866 | } | ||
867 | |||
868 | im2 = evas_cache2_image_copied_data(cache, im->w, im->h, | ||
869 | evas_cache2_image_pixels(im), | ||
870 | im->flags.alpha, im->space); | ||
871 | if (!im2) | ||
872 | goto on_error; | ||
873 | |||
874 | evas_cache2_image_close(im); | ||
875 | return im2; | ||
876 | |||
877 | on_error: | ||
878 | if (im2) | ||
879 | _evas_cache_image_entry_delete(cache, im2); | ||
880 | return NULL; | ||
881 | } | ||
882 | |||
883 | EAPI Image_Entry * | ||
884 | evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h) | ||
885 | { | ||
886 | Evas_Cache2 *cache = im->cache2; | ||
887 | Image_Entry *im2 = NULL; | ||
888 | |||
889 | if (!im->cache_key) | ||
890 | { | ||
891 | if (!im->flags.dirty) | ||
892 | _evas_cache_image_dirty_add(im); | ||
893 | im2 = im; | ||
894 | } | ||
895 | else | ||
896 | { | ||
897 | im2 = evas_cache2_image_copied_data(cache, im->w, im->h, | ||
898 | evas_cache2_image_pixels(im), | ||
899 | im->flags.alpha, im->space); | ||
900 | if (!im2) | ||
901 | goto on_error; | ||
902 | |||
903 | evas_cache2_image_close(im); | ||
904 | } | ||
905 | |||
906 | if (cache->func.dirty_region) | ||
907 | cache->func.dirty_region(im2, x, y, w, h); | ||
908 | |||
909 | return im2; | ||
910 | |||
911 | on_error: | ||
912 | if (im2) | ||
913 | _evas_cache_image_entry_delete(cache, im2); | ||
914 | evas_cache2_image_close(im); | ||
915 | return NULL; | ||
916 | } | ||
917 | |||
918 | EAPI int | ||
919 | evas_cache2_flush(Evas_Cache2 *cache) | ||
920 | { | ||
921 | if (cache->limit == -1) return -1; | ||
922 | |||
923 | while ((cache->lru) && (cache->limit < cache->usage)) | ||
924 | { | ||
925 | Image_Entry *im; | ||
926 | |||
927 | im = (Image_Entry *)cache->lru->last; | ||
928 | DBG("Remove unused entry from cache."); | ||
929 | _evas_cache_image_entry_delete(cache, im); | ||
930 | } | ||
931 | |||
932 | return cache->usage; | ||
933 | } | ||
934 | |||
935 | EAPI void | ||
936 | evas_cache2_limit_set(Evas_Cache2 *cache, int limit) | ||
937 | { | ||
938 | if (cache->limit == limit) | ||
939 | return; | ||
940 | |||
941 | DBG("Cache2 limit set to %d", limit); | ||
942 | |||
943 | cache->limit = limit; | ||
944 | |||
945 | evas_cache2_flush(cache); | ||
946 | } | ||
947 | |||
948 | EAPI int | ||
949 | evas_cache2_limit_get(Evas_Cache2 *cache) | ||
950 | { | ||
951 | return cache->limit; | ||
952 | } | ||
953 | |||
954 | EAPI int | ||
955 | evas_cache2_usage_get(Evas_Cache2 *cache) | ||
956 | { | ||
957 | return cache->usage; | ||
958 | } | ||
diff --git a/src/lib/evas/cache2/evas_cache2.h b/src/lib/evas/cache2/evas_cache2.h new file mode 100644 index 0000000000..7028338e7b --- /dev/null +++ b/src/lib/evas/cache2/evas_cache2.h | |||
@@ -0,0 +1,87 @@ | |||
1 | #ifndef _EVAS_CACHE2_H | ||
2 | #define _EVAS_CACHE2_H | ||
3 | |||
4 | typedef struct _Evas_Cache2_Image_Func Evas_Cache2_Image_Func; | ||
5 | typedef struct _Evas_Cache2 Evas_Cache2; | ||
6 | |||
7 | struct _Evas_Cache2_Image_Func | ||
8 | { | ||
9 | // Image_Entry *(*alloc)(void); | ||
10 | // void (*dealloc)(Image_Entry *im); | ||
11 | |||
12 | /* The cache provide some helpers for surface manipulation. */ | ||
13 | int (*surface_alloc)(Image_Entry *im, unsigned int w, unsigned int h); | ||
14 | void (*surface_delete)(Image_Entry *im); | ||
15 | DATA32 *(*surface_pixels)(Image_Entry *im); | ||
16 | |||
17 | /* The cache is doing the allocation and deallocation, you must just do the rest. */ | ||
18 | // int (*constructor)(Image_Entry *im); /**< return is EVAS_LOAD_ERROR_* or EVAS_LOAD_ERROR_NONE! */ | ||
19 | // void (*destructor)(Image_Entry *im); | ||
20 | |||
21 | void (*dirty_region)(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h); | ||
22 | /* Only called when references > 0. Need to provide a fresh copie of im. */ | ||
23 | /* The destination surface does have a surface, but no allocated pixel data. */ | ||
24 | int (*dirty)(Image_Entry *dst, const Image_Entry *src); | ||
25 | /* Only called when references == 1. We will call drop on `im'. */ | ||
26 | /* The destination surface does not have any surface. */ | ||
27 | int (*size_set)(Image_Entry *dst, const Image_Entry *src, unsigned int w, unsigned int h); | ||
28 | |||
29 | /* The destination surface does not have any surface. */ | ||
30 | int (*copied_data)(Image_Entry *dst, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace); | ||
31 | /* The destination surface does not have any surface. */ | ||
32 | int (*data)(Image_Entry *dst, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace); | ||
33 | int (*color_space)(Image_Entry *dst, int cspace); | ||
34 | |||
35 | /* This function need to update im->w and im->h. */ | ||
36 | // int (*load)(Image_Entry *im); /**< return is EVAS_LOAD_ERROR_* or EVAS_LOAD_ERROR_NONE! */ | ||
37 | int (*mem_size_get)(Image_Entry *im); | ||
38 | void (*debug)(const char *context, Image_Entry *im); | ||
39 | }; | ||
40 | |||
41 | struct _Evas_Cache2 | ||
42 | { | ||
43 | Evas_Cache2_Image_Func func; | ||
44 | |||
45 | Eina_List *preload; | ||
46 | |||
47 | Eina_Hash *inactiv; | ||
48 | Eina_Hash *activ; | ||
49 | Eina_Inlist *dirty; | ||
50 | Eina_Inlist *lru; | ||
51 | int usage; | ||
52 | int limit; | ||
53 | }; | ||
54 | |||
55 | #ifdef __cplusplus | ||
56 | extern "C" { | ||
57 | #endif | ||
58 | |||
59 | EAPI Evas_Cache2* evas_cache2_init(const Evas_Cache2_Image_Func *cb); | ||
60 | EAPI void evas_cache2_shutdown(Evas_Cache2 *cache); | ||
61 | EAPI Image_Entry * evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, RGBA_Image_Loadopts *lo, int *error); | ||
62 | EAPI int evas_cache2_image_open_wait(Image_Entry *im); | ||
63 | EAPI void evas_cache2_image_close(Image_Entry *im); | ||
64 | EAPI int evas_cache2_image_load_data(Image_Entry *ie); | ||
65 | EAPI void evas_cache2_image_unload_data(Image_Entry *im); | ||
66 | EAPI void evas_cache2_image_preload_data(Image_Entry *im, const void *target); | ||
67 | |||
68 | EAPI DATA32 * evas_cache2_image_pixels(Image_Entry *im); | ||
69 | EAPI Image_Entry * evas_cache2_image_writable(Image_Entry *im); | ||
70 | EAPI Image_Entry * evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace); | ||
71 | EAPI Image_Entry * evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace); | ||
72 | EAPI Image_Entry * evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h); | ||
73 | EAPI Image_Entry * evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h); | ||
74 | EAPI Image_Entry * evas_cache2_image_empty(Evas_Cache2 *cache); | ||
75 | EAPI void evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h); | ||
76 | |||
77 | EAPI int evas_cache2_flush(Evas_Cache2 *cache); | ||
78 | EAPI void evas_cache2_limit_set(Evas_Cache2 *cache, int limit); | ||
79 | EAPI int evas_cache2_limit_get(Evas_Cache2 *cache); | ||
80 | EAPI int evas_cache2_usage_get(Evas_Cache2 *cache); | ||
81 | |||
82 | #ifdef __cplusplus | ||
83 | } | ||
84 | #endif | ||
85 | |||
86 | |||
87 | #endif /* _EVAS_CACHE2_H */ | ||