move around - flatter.
[profile/ivi/evas.git] / src / modules / engines / xrender_x11 / evas_engine_image.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3 #include "evas_engine.h"
4 #include "Evas_Engine_XRender_X11.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(Ximage_Info *xinf, const char *file, const char *key, Evas_Image_Load_Opts *lo)
70 {
71    XR_Image *im;
72    char buf[4096];
73
74    if (!file) return NULL;
75    if (!lo)
76      {
77         if (key)
78           snprintf(buf, sizeof(buf), "/@%p@%lx@/%s//://%s", xinf->disp, xinf->root, file, key);
79         else
80           snprintf(buf, sizeof(buf), "/@%p@%lx@/%s", xinf->disp, xinf->root, file);
81      }
82    else
83      {
84         if (key)
85           snprintf(buf, sizeof(buf), "//@/%i/%1.5f/%ix%i//@%p@%lx@/%s//://%s", lo->scale_down_by, lo->dpi, lo->w, lo->h, xinf->disp, xinf->root, file, key);
86         else
87           snprintf(buf, sizeof(buf), "//@/%i/%1.5f/%ix%i//@%p@%lx@/%s", lo->scale_down_by, lo->dpi, lo->w, lo->h, xinf->disp, xinf->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->xinf = xinf;
104    im->xinf->references++;
105    im->cs.space = EVAS_COLORSPACE_ARGB8888;
106    im->fkey = strdup(buf);
107    im->file = evas_stringshare_add(file);
108    if (key) im->key = evas_stringshare_add(key);
109    im->w = im->im->cache_entry.w;
110    im->h = im->im->cache_entry.h;
111    im->references = 1;
112    if (lo) im->load_opts = *lo;
113    if (im->im->info.comment) im->comment = evas_stringshare_add(im->im->info.comment);
114 //   if (im->im->info.format == 1) im->format = evas_stringshare_add("png");
115    if (im->im->cache_entry.flags.alpha) im->alpha = 1;
116    _xr_image_hash = evas_hash_direct_add(_xr_image_hash, im->fkey, im);
117    return im;
118 }
119
120 XR_Image *
121 _xre_image_new_from_data(Ximage_Info *xinf, int w, int h, void *data, int alpha, int cspace)
122 {
123    XR_Image *im;
124
125    im = calloc(1, sizeof(XR_Image));
126    if (!im) return NULL;
127    im->xinf = xinf;
128    im->xinf->references++;
129    im->cs.space = cspace;
130    im->w = w;
131    im->h = h;
132    im->references = 1;
133    switch (im->cs.space)
134      {
135       case EVAS_COLORSPACE_ARGB8888:
136         im->data = data;
137         im->alpha = alpha;
138         break;
139       case EVAS_COLORSPACE_YCBCR422P601_PL:
140       case EVAS_COLORSPACE_YCBCR422P709_PL:
141         im->cs.data = data;
142         im->cs.no_free = 1;
143         break;
144       default:
145         abort();
146         break;
147      }
148    im->dirty = 1;
149    __xre_image_dirty_hash_add(im);
150    return im;
151 }
152
153 XR_Image *
154 _xre_image_new_from_copied_data(Ximage_Info *xinf, int w, int h, void *data, int alpha, int cspace)
155 {
156    XR_Image *im;
157
158    im = calloc(1, sizeof(XR_Image));
159    if (!im) return NULL;
160    im->cs.space = cspace;
161    switch (im->cs.space)
162      {
163       case EVAS_COLORSPACE_ARGB8888:
164         im->data = malloc(w * h * 4);
165         if (!im->data)
166           {
167              free(im);
168              return NULL;
169           }
170         if (data)
171           {
172              Gfx_Func_Copy func;
173              
174              func = evas_common_draw_func_copy_get(w * h, 0);
175              if (func) func(data, im->data, w * h);
176              evas_common_cpu_end_opt();
177           }
178         im->alpha = alpha;
179         im->free_data = 1;
180         break;
181       case EVAS_COLORSPACE_YCBCR422P601_PL:
182       case EVAS_COLORSPACE_YCBCR422P709_PL:
183         im->cs.no_free = 0;
184         im->cs.data = calloc(1, h * sizeof(unsigned char *) * 2);
185         if ((data) && (im->cs.data))
186           memcpy(im->cs.data, data, h * sizeof(unsigned char *) * 2);
187         break;
188       default:
189         abort();
190         break;
191      }
192    im->w = w;
193    im->h = h;
194    im->references = 1;
195    im->xinf = xinf;
196    im->xinf->references++;
197    im->dirty = 1;
198    __xre_image_dirty_hash_add(im);
199    return im;
200 }
201
202 XR_Image *
203 _xre_image_new(Ximage_Info *xinf, int w, int h)
204 {
205    XR_Image *im;
206
207    im = calloc(1, sizeof(XR_Image));
208    if (!im) return NULL;
209    im->data = malloc(w * h * 4);
210    if (!im->data)
211      {
212         free(im);
213         return NULL;
214      }
215    im->w = w;
216    im->h = h;
217    im->references = 1;
218    im->cs.space = EVAS_COLORSPACE_ARGB8888;
219    im->xinf = xinf;
220    im->xinf->references++;
221    im->free_data = 1;
222    im->alpha = 1;
223    im->dirty = 1;
224    __xre_image_dirty_hash_add(im);
225    return im;
226 }
227
228 static void
229 __xre_image_real_free(XR_Image *im)
230 {
231    if (im->cs.data)
232      {
233         if (!im->cs.no_free) free(im->cs.data);
234      }
235    if (im->file) evas_stringshare_del(im->file);
236    if (im->key) evas_stringshare_del(im->key);
237    if (im->fkey) free(im->fkey);
238    if (im->im) evas_cache_image_drop(&im->im->cache_entry);
239    if ((im->data) && (im->dirty)) __xre_image_dirty_hash_del(im);
240    if ((im->free_data) && (im->data)) free(im->data);
241    if (im->surface) _xr_render_surface_free(im->surface);
242    if (im->format) evas_stringshare_del(im->format);
243    if (im->comment) evas_stringshare_del(im->comment);
244    if (im->updates) evas_common_tilebuf_free(im->updates);
245    _xr_image_info_free(im->xinf);
246    free(im);
247 }
248
249 void
250 _xre_image_free(XR_Image *im)
251 {
252    im->references--;
253    if (im->references != 0) return;
254    if (!im->dirty)
255      {
256         if (im->fkey)
257           _xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
258         _xr_image_cache = evas_list_prepend(_xr_image_cache, im);
259         _xr_image_cache_usage += (im->w * im->h * 4);
260         _xre_image_cache_set(_xr_image_cache_size);
261      }
262    else
263      {
264         __xre_image_real_free(im);
265      }
266 }
267
268 void
269 _xre_image_region_dirty(XR_Image *im, int x, int y, int w, int h)
270
271    if (!im->updates)
272      {
273         im->updates = evas_common_tilebuf_new(im->w, im->h);
274         if (im->updates) evas_common_tilebuf_set_tile_size(im->updates, 8, 8);
275      }
276    if (im->updates)
277      evas_common_tilebuf_add_redraw(im->updates, x, y, w, h);
278 }
279
280 void
281 _xre_image_dirty(XR_Image *im)
282 {
283    if (im->dirty) return;
284    if (im->fkey)
285      _xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
286    im->dirty = 1;
287    __xre_image_dirty_hash_add(im);
288 }
289
290 XR_Image *
291 _xre_image_copy(XR_Image *im)
292 {
293    XR_Image *im2;
294    void *data = NULL;
295
296    if (im->data) data = im->data;
297    else if (im->cs.data) data = im->cs.data;
298    else
299      {
300         if (!im->im)
301           im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
302         if (im->im)
303           {
304              evas_cache_image_load_data(&im->im->cache_entry);
305              data = im->im->image.data;
306           }
307      }
308    if (!data) return NULL;
309    im2 = _xre_image_new_from_copied_data(im->xinf, im->w, im->h, data, im->alpha, im->cs.space);
310    return im2;
311 }
312
313 void
314 _xre_image_resize(XR_Image *im, int w, int h)
315 {
316    if ((w == im->w) && (h == im->h)) return;
317    if (im->surface)
318      {
319         Xrender_Surface *old_surface;
320         old_surface = im->surface;
321         im->surface = _xr_render_surface_new(old_surface->xinf, w + 2, h + 2, old_surface->fmt, old_surface->alpha);
322         _xr_render_surface_free(old_surface);
323      }
324    switch (im->cs.space)
325      {
326       case EVAS_COLORSPACE_ARGB8888:
327         if (im->data)
328           {
329              if (im->free_data)
330                {
331                   if (im->data) free(im->data);
332                   im->data = malloc(w * h * 4);
333                }
334           }
335         else if (im->im)
336           {
337              evas_cache_image_drop(&im->im->cache_entry);
338              im->im = NULL;
339              if (im->free_data)
340                {
341                   if (im->data) free(im->data);
342                   im->data = malloc(w * h * 4);
343                }
344           }
345         else
346           {
347              im->data = malloc(w * h * 4);
348              im->free_data = 1;
349           }
350         break;
351       case EVAS_COLORSPACE_YCBCR422P601_PL:
352       case EVAS_COLORSPACE_YCBCR422P709_PL:
353         if (im->data)
354           {
355              if (im->free_data)
356                {
357                   if (im->data) free(im->data);
358                }
359              im->data = NULL;
360           }
361         if (im->im)
362           {
363              evas_cache_image_drop(&im->im->cache_entry);
364              im->im = NULL;
365           }
366         if (!im->cs.no_free)
367           {
368              if (im->cs.data) free(im->cs.data);
369              im->cs.data = calloc(1, h * sizeof(unsigned char *) * 2);
370           }
371         break;
372       default:
373         abort();
374         break;
375      }
376    __xre_image_dirty_hash_del(im);
377    __xre_image_dirty_hash_add(im);
378    im->w = w;
379    im->h = h;
380 }
381
382 void *
383 _xre_image_data_get(XR_Image *im)
384 {
385    void *data = NULL;
386    
387    if (im->data) data = im->data;
388    else if (im->cs.data) data = im->cs.data;
389    else
390      {
391         if (!im->im) im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
392         if (im->im)
393           {
394              evas_cache_image_load_data(&im->im->cache_entry);
395              data = im->im->image.data;
396           }
397      }
398    return data;
399 }
400
401 XR_Image *
402 _xre_image_data_find(void *data)
403 {
404    XR_Image *im;
405    
406    im = __xre_image_dirty_hash_find(data);
407    if (im) 
408      {
409         im->references++;
410      }
411    return im;
412 }
413
414 void
415 _xre_image_data_put(XR_Image *im, void *data)
416 {
417    if (!data) return;
418    switch (im->cs.space)
419      {
420       case EVAS_COLORSPACE_ARGB8888:
421         if (im->im)
422           {
423              if (data == im->im->image.data) return;
424              evas_cache_image_drop(&im->im->cache_entry);
425              im->im = NULL;
426           }
427         if (im->cs.data == data) return;
428         if (im->data)
429           {
430              if (im->data == data) return;
431              if (im->free_data) free(im->data);
432              im->free_data = 0;
433           }
434         im->data = data;
435         im->free_data = 0;
436         break;
437       case EVAS_COLORSPACE_YCBCR422P601_PL:
438       case EVAS_COLORSPACE_YCBCR422P709_PL:
439         if (im->data)
440           {
441              if (im->free_data) free(im->data);
442              im->data = NULL;
443           }
444         im->free_data = 0;
445         if (data == im->cs.data) return;
446         if (!im->cs.no_free)
447           {
448              if (im->cs.data) free(im->cs.data);
449           }
450         im->cs.data = data;
451         break;
452       default:
453         abort();
454         break;
455      }
456    __xre_image_dirty_hash_del(im);
457    __xre_image_dirty_hash_add(im);
458    if (im->surface)
459      {
460         _xr_render_surface_free(im->surface);
461         im->surface = NULL;
462      }
463    if (!im->dirty)
464      {
465         if (im->fkey)
466           _xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
467         im->dirty = 1;
468      }
469    if (im->updates)
470      {
471         evas_common_tilebuf_free(im->updates);
472         im->updates = NULL;
473      }
474 }
475
476 void
477 _xre_image_alpha_set(XR_Image *im, int alpha)
478 {
479    if (im->alpha == alpha) return;
480    switch (im->cs.space)
481      {
482       case EVAS_COLORSPACE_ARGB8888:
483         im->alpha = alpha;
484         if (im->surface)
485           {
486              Xrender_Surface *old_surface;
487              
488              old_surface = im->surface;
489              im->surface = NULL;
490              if (im->alpha)
491                im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmt32, 1);
492              else
493                {
494                   /* FIXME: if im->depth == 16, use xinf->fmtdef */
495                   if ((im->xinf->depth == 16) &&
496                       (im->xinf->vis->red_mask == 0xf800) &&
497                       (im->xinf->vis->green_mask == 0x07e0) &&
498                       (im->xinf->vis->blue_mask == 0x001f))
499                     im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmtdef, 0);
500                   else
501                     im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmt24, 0);
502                }
503              if (im->surface)
504                _xr_render_surface_copy(old_surface, im->surface, 0, 0, 0, 0, im->w + 2, im->h + 2);
505              _xr_render_surface_free(old_surface);
506           }
507         if (im->updates)
508           {
509              evas_common_tilebuf_free(im->updates);
510              im->updates = NULL;
511           }
512       default:
513         break;
514      }
515 }
516
517 int
518 _xre_image_alpha_get(XR_Image *im)
519 {
520    if (im->im)
521      {
522         if (im->im->cache_entry.space != EVAS_COLORSPACE_ARGB8888) return 0;
523      }
524    return im->alpha;
525 }
526
527 void
528 _xre_image_border_set(XR_Image *im, int l, int r, int t, int b)
529 {
530    if (!im) return;
531    _xre_image_surface_gen(im);
532    if (l < 1) l = 0;
533    if (r < 1) r = 0;
534    if (t < 1) t = 0;
535    if (b < 1) b = 0;
536    if (im->surface)
537      {
538         if (l | r | t | b)
539           im->surface->bordered = 1;
540         else
541           im->surface->bordered = 0;
542     }
543 }
544
545 void
546 _xre_image_border_get(XR_Image *im, int *l, int *r, int *t, int *b)
547 {
548 }
549
550 void
551 _xre_image_surface_gen(XR_Image *im)
552 {
553    void *data = NULL, *tdata = NULL;
554
555    if ((im->surface) && (!im->updates)) return;
556    if (im->data) data = im->data;
557    else
558      {
559         if (!im->im) im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
560         if (im->im)
561           {
562              evas_cache_image_load_data(&im->im->cache_entry);
563              data = im->im->image.data;
564           }
565      }
566    if (!data)
567      {
568         switch (im->cs.space)
569           {
570            case EVAS_COLORSPACE_ARGB8888:
571              return;
572              break;
573            case EVAS_COLORSPACE_YCBCR422P601_PL:
574            case EVAS_COLORSPACE_YCBCR422P709_PL:
575              if ((im->cs.data) && (*((unsigned char **)im->cs.data)))
576                {
577                   tdata = malloc(im->w * im->h * sizeof(DATA32));
578                   if (tdata)
579                     evas_common_convert_yuv_420p_601_rgba(im->cs.data, 
580                                                           tdata,
581                                                           im->w, im->h);
582                   data = tdata;
583                }
584              break;
585            default:
586              abort();
587              break;
588           }
589         if (!data) return;
590      }
591    if (im->surface)
592      {
593         if (im->updates)
594           {
595              Tilebuf_Rect *rects, *r;
596              
597              rects = evas_common_tilebuf_get_render_rects(im->updates);
598              if (rects)
599                {
600                   for (r = rects; r; r = (Tilebuf_Rect *)((Evas_Object_List *)r)->next)
601                     {
602                        int rx, ry, rw, rh;
603                        
604                        rx = r->x; ry = r->y; rw = r->w, rh = r->h;
605                        RECTS_CLIP_TO_RECT(rx, ry, rw, rh, 0, 0, im->w, im->h);
606                        if (im->alpha)
607                          _xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh, 1, 1);
608                        else
609                        /* FIXME: if im->depth == 16 - convert to 16bpp then
610                         * upload */
611                          _xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh, 1, 1);
612                     }
613                   evas_common_tilebuf_free_render_rects(rects);
614                }
615              evas_common_tilebuf_free(im->updates);
616              im->updates = NULL;
617           }
618         if (tdata) free(tdata);
619         return;
620      }
621    if (im->alpha)
622      {
623         im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmt32, 1);
624         _xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h, 1, 1);
625      }
626    else
627      {
628         /* FIXME: if im->xinf->depth == 16, use xinf->fmtdef */
629         if ((im->xinf->depth == 16) &&
630             (im->xinf->vis->red_mask == 0xf800) &&
631             (im->xinf->vis->green_mask == 0x07e0) &&
632             (im->xinf->vis->blue_mask == 0x001f))
633           im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmtdef, 0);
634         else
635           im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmt24, 0);
636         /* FIXME: if im->depth == 16 - convert to 16bpp then
637          * upload */
638         _xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h, 1, 1);
639      }
640    /* fill borders */
641    _xr_render_surface_copy(im->surface, im->surface, 
642                            1, 1, 
643                            0, 1, 
644                            1, im->h);
645    _xr_render_surface_copy(im->surface, im->surface, 
646                            0, 1, 
647                            0, 0, 
648                            im->w + 2, 1);
649    _xr_render_surface_copy(im->surface, im->surface, 
650                            im->w, 1, 
651                            im->w + 1, 1, 
652                            1, im->h);
653    _xr_render_surface_copy(im->surface, im->surface, 
654                            0, im->h, 
655                            0, im->h + 1, 
656                            im->w + 2, 1);
657    if ((im->im) && (!im->dirty))
658      {
659         evas_cache_image_drop(&im->im->cache_entry);
660         im->im = NULL;
661      }
662    if (tdata) free(tdata);
663 }
664
665 void
666 _xre_image_cache_set(int size)
667 {
668    _xr_image_cache_size = size;
669    while (_xr_image_cache_usage > _xr_image_cache_size)
670      {
671         Evas_List *l;
672         
673         l = evas_list_last(_xr_image_cache);
674         if (l)
675           {
676              XR_Image *im;
677              
678              im = l->data;
679              _xr_image_cache = evas_list_remove_list(_xr_image_cache, l);
680              _xr_image_cache_usage -= (im->w * im->h * 4);
681              __xre_image_real_free(im);
682           }
683      }
684 }
685
686 int
687 _xre_image_cache_get(void)
688 {
689    return _xr_image_cache_size;
690 }