move around - flatter.
[profile/ivi/evas.git] / src / modules / engines / xrender_xcb / evas_engine_image.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3 #include "evas_engine.h"
4 #include "Evas_Engine_XRender_Xcb.h"
5
6 static Evas_Hash *_xr_image_hash        = NULL;
7 static int        _xr_image_cache_size  = 0;
8 static int        _xr_image_cache_usage = 0;
9 static Evas_List *_xr_image_cache       = NULL;
10 static Evas_Hash *_xr_image_dirty_hash  = NULL;
11
12 static void
13 __xre_image_dirty_hash_add(XR_Image *im)
14 {
15    char buf[64];
16    
17    if (!im->data) return;
18    snprintf(buf, sizeof(buf), "%p", im->data);
19    _xr_image_dirty_hash = evas_hash_add(_xr_image_dirty_hash, buf, im);
20 }
21
22 static void
23 __xre_image_dirty_hash_del(XR_Image *im)
24 {
25    char buf[64];
26    
27    if (!im->data) return;
28    snprintf(buf, sizeof(buf), "%p", im->data);
29    _xr_image_dirty_hash = evas_hash_del(_xr_image_dirty_hash, buf, im);
30 }
31
32 static XR_Image *
33 __xre_image_dirty_hash_find(void *data)
34 {
35    char buf[64];
36    
37    snprintf(buf, sizeof(buf), "%p", data);
38    return evas_hash_find(_xr_image_dirty_hash, buf);
39 }
40
41 static XR_Image *
42 __xre_image_find(char *fkey)
43 {
44    XR_Image *im;
45    
46    im = evas_hash_find(_xr_image_hash, fkey);
47    if (!im)
48      {
49         Evas_List *l;
50         
51         for (l = _xr_image_cache; l; l = l->next)
52           {
53              im = l->data;
54              if (!strcmp(im->fkey, fkey))
55                {
56                   _xr_image_cache = evas_list_remove_list(_xr_image_cache, l);
57                   _xr_image_hash = evas_hash_add(_xr_image_hash, im->fkey, im);
58                   _xr_image_cache_usage -= (im->w * im->h * 4);
59                   break;
60                }
61              im = NULL;
62           }
63      }
64    if (im) im->references++;
65    return im;
66 }
67
68 XR_Image *
69 _xre_image_load(Xcb_Image_Info *xcbinf, const char *file, const char *key, Evas_Image_Load_Opts *lo)
70 {
71    char      buf[4096];
72    XR_Image *im;
73
74    if (!file) return NULL;
75    if (!lo)
76      {
77         if (key)
78           snprintf(buf, sizeof(buf), "/@%p@%x@/%s//://%s", xcbinf->conn, xcbinf->root, file, key);
79         else
80           snprintf(buf, sizeof(buf), "/@%p@%x@/%s", xcbinf->conn, xcbinf->root, file);
81      }
82    else
83      {
84         if (key)
85           snprintf(buf, sizeof(buf), "//@/%i/%1.5f/%ix%i//@%p@%x@/%s//://%s", lo->scale_down_by, lo->dpi, lo->w, lo->h, xcbinf->conn, xcbinf->root, file, key);
86         else
87           snprintf(buf, sizeof(buf), "//@/%i/%1.5f/%ix%i//@%p@%x@/%s", lo->scale_down_by, lo->dpi, lo->w, lo->h, xcbinf->conn, xcbinf->root, file);
88      }
89    im = __xre_image_find(buf);
90    if (im)
91      {
92         return im;
93      }
94    
95    im = calloc(1, sizeof(XR_Image));
96    if (!im) return NULL;
97    im->im = evas_common_load_image_from_file(file, key, lo);
98    if (!im->im)
99      {
100         free(im);
101         return NULL;
102      }
103    im->xcbinf = xcbinf;
104    im->xcbinf->references++;
105    im->fkey = strdup(buf);
106    im->file = (char *)evas_stringshare_add(file);
107    if (key) im->key = (char *)evas_stringshare_add(key);
108    im->w = im->im->cache_entry.w;
109    im->h = im->im->cache_entry.h;
110    im->references = 1;
111    if (lo) im->load_opts = *lo;
112    if (im->im->info.comment) im->comment = (char *)evas_stringshare_add(im->im->info.comment);
113 /*    if (im->im->info.format == 1) im->format = evas_stringshare_add("png"); */
114    if (im->im->cache_entry.flags.alpha) im->alpha = 1;
115    _xr_image_hash = evas_hash_direct_add(_xr_image_hash, im->fkey, im);
116    return im;
117 }
118
119 XR_Image *
120 _xre_image_new_from_data(Xcb_Image_Info *xcbinf, int w, int h, void *data)
121 {
122    XR_Image *im;
123
124    im = calloc(1, sizeof(XR_Image));
125    if (!im) return NULL;
126    im->xcbinf = xcbinf;
127    im->xcbinf->references++;
128    im->w = w;
129    im->h = h;
130    im->references = 1;
131    im->data = data;
132    im->alpha = 1;
133    im->dirty = 1;
134    __xre_image_dirty_hash_add(im);
135    return im;
136 }
137
138 XR_Image *
139 _xre_image_new_from_copied_data(Xcb_Image_Info *xcbinf, int w, int h, void *data)
140 {
141    XR_Image *im;
142
143    im = calloc(1, sizeof(XR_Image));
144    if (!im) return NULL;
145    im->data = malloc(w * h * 4);
146    if (!im->data)
147      {
148         free(im);
149         return NULL;
150      }
151    if (data)
152      {
153         Gfx_Func_Copy func;
154         
155         func = evas_common_draw_func_copy_get(w * h, 0);
156         if (func) func(data, im->data, w * h);
157         evas_common_cpu_end_opt();
158      }
159    im->w = w;
160    im->h = h;
161    im->references = 1;
162    im->xcbinf = xcbinf;
163    im->xcbinf->references++;
164    im->free_data = 1;
165    im->alpha = 1;
166    im->dirty = 1;
167    __xre_image_dirty_hash_add(im);
168    return im;
169 }
170
171 XR_Image *
172 _xre_image_new(Xcb_Image_Info *xcbinf, int w, int h)
173 {
174    XR_Image *im;
175
176    im = calloc(1, sizeof(XR_Image));
177    if (!im) return NULL;
178    im->data = malloc(w * h * 4);
179    if (!im->data)
180      {
181         free(im);
182         return NULL;
183      }
184    im->w = w;
185    im->h = h;
186    im->references = 1;
187    im->xcbinf = xcbinf;
188    im->xcbinf->references++;
189    im->free_data = 1;
190    im->alpha = 1;
191    im->dirty = 1;
192    __xre_image_dirty_hash_add(im);
193    return im;
194 }
195
196 static void
197 __xre_image_real_free(XR_Image *im)
198 {
199    if (im->file) evas_stringshare_del(im->file);
200    if (im->key) evas_stringshare_del(im->key);
201    if (im->fkey) free(im->fkey);
202    if (im->im) evas_cache_image_drop(&im->im->cache_entry);
203    if ((im->data) && (im->dirty)) __xre_image_dirty_hash_del(im);
204    if ((im->free_data) && (im->data)) free(im->data);
205    if (im->surface) _xr_render_surface_free(im->surface);
206    if (im->format) evas_stringshare_del(im->format);
207    if (im->comment) evas_stringshare_del(im->comment);
208    if (im->updates) evas_common_tilebuf_free(im->updates);
209    _xr_image_info_free(im->xcbinf);
210    free(im);
211 }
212
213 void
214 _xre_image_free(XR_Image *im)
215 {
216    im->references--;
217    if (im->references != 0) return;
218    if (!im->dirty)
219      {
220         if (im->fkey)
221           _xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
222         _xr_image_cache = evas_list_prepend(_xr_image_cache, im);
223         _xr_image_cache_usage += (im->w * im->h * 4);
224         _xre_image_cache_set(_xr_image_cache_size);
225      }
226    else
227      {
228         __xre_image_real_free(im);
229      }
230 }
231
232 void
233 _xre_image_region_dirty(XR_Image *im, int x, int y, int w, int h)
234
235    if (!im->updates)
236      {
237         im->updates = evas_common_tilebuf_new(im->w, im->h);
238         if (im->updates) evas_common_tilebuf_set_tile_size(im->updates, 8, 8);
239      }
240    if (im->updates)
241      evas_common_tilebuf_add_redraw(im->updates, x, y, w, h);
242 }
243
244 void
245 _xre_image_dirty(XR_Image *im)
246 {
247    if (im->dirty) return;
248    if (im->fkey)
249      _xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
250    im->dirty = 1;
251    __xre_image_dirty_hash_add(im);
252 }
253
254 XR_Image *
255 _xre_image_copy(XR_Image *im)
256 {
257    XR_Image *im2;
258    void     *data = NULL;
259
260    if (im->data) data = im->data;
261    else
262      {
263         if (!im->im) im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
264         if (im->im)
265           {
266              evas_cache_image_load_data(&im->im->cache_entry);
267              data = im->im->image.data;
268           }
269      }
270    if (!data) return NULL;
271    im2 = _xre_image_new_from_copied_data(im->xcbinf, im->w, im->h, data);
272    if (im2) im2->alpha = im->alpha;
273    if ((im->im) && (!im->dirty))
274      {
275         evas_cache_image_drop(&im->im->cache_entry);
276         im->im = NULL;
277      }
278    return im2;
279 }
280
281 void
282 _xre_image_resize(XR_Image *im, int w, int h)
283 {
284    if ((w == im->w) && (h == im->h)) return;
285    if (im->surface)
286      {
287         Xcb_Render_Surface *old_surface;
288         int                 x = 0, y = 0, ww, hh;
289         
290         ww = w; hh = h;
291         RECTS_CLIP_TO_RECT(x, y, ww, hh, 0, 0, im->w, im->h);
292         old_surface = im->surface;
293         im->surface = _xr_render_surface_new(old_surface->xcbinf,
294                                              w + 1, h + 1, old_surface->fmt, old_surface->alpha);
295         if (im->surface)
296           _xr_render_surface_copy(old_surface, im->surface, 0, 0, 0, 0, ww, hh);
297         _xr_render_surface_free(old_surface);
298      }
299    if (im->data)
300      {
301         Gfx_Func_Copy func;
302         int           x = 0, y = 0, ww, hh;
303         unsigned int *sp, *dp;
304         void         *data;
305         
306         data = malloc(w * h * 4);
307         if (!data)
308           {
309              if (im->surface)
310                {
311                   _xr_render_surface_free(im->surface);
312                   im->surface = NULL;
313                }
314              return;
315           }
316         ww = w; hh = h;
317         
318         RECTS_CLIP_TO_RECT(x, y, ww, hh, 0, 0, im->w, im->h);
319         func = evas_common_draw_func_copy_get(w * h, 0);
320         if (func)
321           {
322              for (y = 0; y < hh; y++)
323                {
324                   sp = ((unsigned int *)im->data) + (y * im->w);
325                   dp = ((unsigned int *)data) + (y * w);
326                   func(sp, dp, ww);
327                }
328              evas_common_cpu_end_opt();
329           }
330         __xre_image_dirty_hash_del(im);
331         free(im->data);
332         im->data = data;
333         __xre_image_dirty_hash_add(im);
334      }
335    else if (im->im)
336      {
337         RGBA_Image *im_old;
338
339         im_old = im->im;
340         im->im = (RGBA_Image*) evas_cache_image_empty(evas_common_image_cache_get());
341         if (!im->im)
342           {
343              im->im = im_old;
344              if (im->surface)
345                {
346                   _xr_render_surface_free(im->surface);
347                   im->surface = NULL;
348                }
349              return;
350           }
351         evas_cache_image_load_data(&im->im->cache_entry);
352         if (im_old->image.data)
353           {
354              int x = 0, y = 0, ww, hh;
355
356              ww = w; hh = h;
357              RECTS_CLIP_TO_RECT(x, y, ww, hh, 0, 0, im->w, im->h);
358              evas_common_blit_rectangle(im_old, im->im, 0, 0, ww, hh, 0, 0);
359              evas_common_cpu_end_opt();
360           }
361         im->free_data = 1;
362         /* FIXME: Hum ? */
363         im->data = im->im->image.data;
364         im->im->image.data = NULL;
365         evas_cache_image_drop(&im->im->cache_entry);
366         im->im = NULL;
367         evas_cache_image_drop(&im_old->cache_entry);
368         __xre_image_dirty_hash_add(im);
369      }
370    else
371      {
372         im->data = malloc(w * h * 4);
373         im->free_data = 1;
374         __xre_image_dirty_hash_add(im);
375      }
376    im->w = w;
377    im->h = h;
378 }
379
380 void *
381 _xre_image_data_get(XR_Image *im)
382 {
383    void *data = NULL;
384    
385    if (im->data) data = im->data;
386    else
387      {
388         if (!im->im) im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
389         if (im->im)
390           {
391              evas_cache_image_load_data(&im->im->cache_entry);
392              data = im->im->image.data;
393           }
394      }
395    return data;
396 }
397
398 XR_Image *
399 _xre_image_data_find(void *data)
400 {
401    XR_Image *im;
402    
403    im = __xre_image_dirty_hash_find(data);
404    if (im) 
405      {
406         im->references++;
407      }
408    return im;
409 }
410
411 void
412 _xre_image_data_put(XR_Image *im, void *data)
413 {
414    void *imdata = NULL;
415
416    if (!data) return;
417    if (im->data)
418      {
419         imdata = im->data;
420         if (data == imdata) return;
421         __xre_image_dirty_hash_del(im);
422         if (im->free_data) free(im->data);
423      }
424    else
425      {
426         if (im->im) imdata = im->im->image.data;
427         if (data == imdata) return;
428         if (im->im)
429           {
430              evas_cache_image_drop(&im->im->cache_entry);
431              im->im = NULL;
432           }
433      }
434    im->data = data;
435    __xre_image_dirty_hash_add(im);
436    im->free_data = 0;
437    if (im->surface)
438      {
439         _xr_render_surface_free(im->surface);
440         im->surface = NULL;
441      }
442    if (!im->dirty)
443      {
444         if (im->fkey)
445           _xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
446         im->dirty = 1;
447      }
448    if (im->updates)
449      {
450         evas_common_tilebuf_free(im->updates);
451         im->updates = NULL;
452      }
453 }
454
455 void
456 _xre_image_alpha_set(XR_Image *im, int alpha)
457 {
458    if (im->alpha == alpha) return;
459    im->alpha = alpha;
460    if (im->surface)
461      {
462         Xcb_Render_Surface *old_surface;
463         
464         old_surface = im->surface;
465         im->surface = NULL;
466         if (im->alpha)
467           im->surface = _xr_render_surface_new(im->xcbinf,
468                                                im->w + 1, im->h + 1, im->xcbinf->fmt32, 1);
469         else
470           im->surface = _xr_render_surface_new(im->xcbinf,
471                                                im->w + 1, im->h + 1, im->xcbinf->fmt24, 0);
472         if (im->surface)
473           _xr_render_surface_copy(old_surface,
474                                   im->surface, 0, 0, 0, 0, im->w + 1, im->h + 1);
475         _xr_render_surface_free(old_surface);
476      }
477    if (im->updates)
478      {
479         evas_common_tilebuf_free(im->updates);
480         im->updates = NULL;
481      }
482 }
483
484 int
485 _xre_image_alpha_get(XR_Image *im)
486 {
487    return im->alpha;
488 }
489
490 void
491 _xre_image_border_set(XR_Image *im, int l, int r, int t, int b)
492 {
493    if (!im) return;
494    _xre_image_surface_gen(im);
495    if (l < 1) l = 0;
496    if (r < 1) r = 0;
497    if (t < 1) t = 0;
498    if (b < 1) b = 0;
499    if (im->surface)
500      {
501         if (l | r | t | b)
502           im->surface->bordered = 1;
503         else
504           im->surface->bordered = 0;
505     }
506 }
507
508 void
509 _xre_image_border_get(XR_Image *im, int *l, int *r, int *t, int *b)
510 {
511 }
512
513 void
514 _xre_image_surface_gen(XR_Image *im)
515 {
516    void *data = NULL;
517
518    if ((im->surface) && (!im->updates)) return;
519    if (im->data) data = im->data;
520    else
521      {
522         if (!im->im) im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
523         if (im->im)
524           {
525              evas_cache_image_load_data(&im->im->cache_entry);
526              data = im->im->image.data;
527           }
528      }
529    if (!data) return;
530    if (im->surface)
531      {
532         if (im->updates)
533           {
534              Tilebuf_Rect *rects, *r;
535              
536              rects = evas_common_tilebuf_get_render_rects(im->updates);
537              if (rects)
538                {
539                   for (r = rects; r; r = (Tilebuf_Rect *)((Evas_Object_List *)r)->next)
540                     {
541                        int rx, ry, rw, rh;
542                        
543                        rx = r->x; ry = r->y; rw = r->w, rh = r->h;
544                        RECTS_CLIP_TO_RECT(rx, ry, rw, rh, 0, 0, im->w, im->h);
545                        if (im->alpha)
546                          _xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh);
547                        else
548                          _xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh);
549                     }
550                   evas_common_tilebuf_free_render_rects(rects);
551                }
552              evas_common_tilebuf_free(im->updates);
553              im->updates = NULL;
554           }
555         return;
556      }
557    if (im->alpha)
558      {
559         im->surface = _xr_render_surface_new(im->xcbinf,
560                                              im->w + 1, im->h + 1, im->xcbinf->fmt32, 1);
561         _xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h);
562      }
563    else
564      {
565         im->surface = _xr_render_surface_new(im->xcbinf,
566                                              im->w + 1, im->h + 1, im->xcbinf->fmt24, 0);
567         _xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h);
568       }
569    /* fill right and bottom pixel so interpolation works right */
570    _xr_render_surface_copy(im->surface, im->surface,
571                           im->w - 1, 0,
572                           im->w, 0,
573                           1, im->h);
574    _xr_render_surface_copy(im->surface, im->surface,
575                           0, im->h - 1,
576                           0, im->h,
577                           im->w, 1);
578    _xr_render_surface_copy(im->surface, im->surface,
579                           im->w - 1, im->h - 1,
580                           im->w, im->h,
581                           1, 1);
582    if ((im->im) && (!im->dirty))
583      {
584         evas_cache_image_drop(&im->im->cache_entry);
585         im->im = NULL;
586      }
587 }
588
589 void
590 _xre_image_cache_set(int size)
591 {
592    _xr_image_cache_size = size;
593    while (_xr_image_cache_usage > _xr_image_cache_size)
594      {
595         Evas_List *l;
596         
597         l = evas_list_last(_xr_image_cache);
598         if (l)
599           {
600              XR_Image *im;
601              
602              im = l->data;
603              _xr_image_cache = evas_list_remove_list(_xr_image_cache, l);
604              _xr_image_cache_usage -= (im->w * im->h * 4);
605              __xre_image_real_free(im);
606           }
607      }
608 }
609
610 int
611 _xre_image_cache_get(void)
612 {
613    return _xr_image_cache_size;
614 }