Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_x / xlib / ecore_x_image.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/ipc.h>
8 #include <sys/shm.h>
9
10 #include "ecore_x_private.h"
11 #include "Ecore_X.h"
12
13 #include <X11/extensions/XShm.h>
14 #include <X11/Xutil.h>
15
16 static int _ecore_x_image_shm_can = -1;
17 static int _ecore_x_image_err = 0;
18
19 static int
20 _ecore_x_image_error_handler(Display *d __UNUSED__,
21                              XErrorEvent *ev __UNUSED__)
22 {
23    _ecore_x_image_err = 1;
24    return 0;
25 }
26
27 static void
28 _ecore_x_image_shm_check(void)
29 {
30    XErrorHandler ph;
31    XShmSegmentInfo shminfo;
32    XImage *xim;
33
34    if (_ecore_x_image_shm_can != -1)
35      return;
36
37    XSync(_ecore_x_disp, False);
38    _ecore_x_image_err = 0;
39
40    xim = XShmCreateImage(_ecore_x_disp,
41                          DefaultVisual(_ecore_x_disp,
42                                        DefaultScreen(_ecore_x_disp)),
43                          DefaultDepth(_ecore_x_disp,
44                                       DefaultScreen(_ecore_x_disp)),
45                          ZPixmap, NULL,
46                          &shminfo, 1, 1);
47    if (!xim)
48      {
49         _ecore_x_image_shm_can = 0;
50         return;
51      }
52
53    shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height,
54                           IPC_CREAT | 0666);
55    if (shminfo.shmid == -1)
56      {
57         XDestroyImage(xim);
58         _ecore_x_image_shm_can = 0;
59         return;
60      }
61
62    shminfo.readOnly = False;
63    shminfo.shmaddr = shmat(shminfo.shmid, 0, 0);
64    xim->data = shminfo.shmaddr;
65
66    if (xim->data == (char *)-1)
67      {
68         XDestroyImage(xim);
69         _ecore_x_image_shm_can = 0;
70         return;
71      }
72
73    ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler);
74    XShmAttach(_ecore_x_disp, &shminfo);
75    XShmGetImage(_ecore_x_disp, DefaultRootWindow(_ecore_x_disp),
76                 xim, 0, 0, 0xffffffff);
77    XSync(_ecore_x_disp, False);
78    XSetErrorHandler((XErrorHandler)ph);
79    if (_ecore_x_image_err)
80      {
81         XShmDetach(_ecore_x_disp, &shminfo);
82         XDestroyImage(xim);
83         shmdt(shminfo.shmaddr);
84         shmctl(shminfo.shmid, IPC_RMID, 0);
85         _ecore_x_image_shm_can = 0;
86         return;
87      }
88
89    XShmDetach(_ecore_x_disp, &shminfo);
90    XDestroyImage(xim);
91    shmdt(shminfo.shmaddr);
92    shmctl(shminfo.shmid, IPC_RMID, 0);
93
94    _ecore_x_image_shm_can = 1;
95 }
96
97 struct _Ecore_X_Image
98 {
99    XShmSegmentInfo shminfo;
100    Ecore_X_Visual  vis;
101    XImage         *xim;
102    int             depth;
103    int             w, h;
104    int             bpl, bpp, rows;
105    unsigned char  *data;
106    Eina_Bool       shm : 1;
107 };
108
109 EAPI Ecore_X_Image *
110 ecore_x_image_new(int w,
111                   int h,
112                   Ecore_X_Visual vis,
113                   int depth)
114 {
115    Ecore_X_Image *im;
116
117    im = calloc(1, sizeof(Ecore_X_Image));
118    if (!im)
119      return NULL;
120
121    LOGFN(__FILE__, __LINE__, __FUNCTION__);
122    im->w = w;
123    im->h = h;
124    im->vis = vis;
125    im->depth = depth;
126    _ecore_x_image_shm_check();
127    im->shm = _ecore_x_image_shm_can;
128    return im;
129 }
130
131 EAPI void
132 ecore_x_image_free(Ecore_X_Image *im)
133 {
134    LOGFN(__FILE__, __LINE__, __FUNCTION__);
135    if (im->shm)
136      {
137         if (im->xim)
138           {
139              XShmDetach(_ecore_x_disp, &(im->shminfo));
140              XDestroyImage(im->xim);
141              shmdt(im->shminfo.shmaddr);
142              shmctl(im->shminfo.shmid, IPC_RMID, 0);
143           }
144      }
145    else if (im->xim)
146      {
147         free(im->xim->data);
148         im->xim->data = NULL;
149         XDestroyImage(im->xim);
150      }
151
152    free(im);
153 }
154
155 static void
156 _ecore_x_image_shm_create(Ecore_X_Image *im)
157 {
158    im->xim = XShmCreateImage(_ecore_x_disp, im->vis, im->depth,
159                              ZPixmap, NULL, &(im->shminfo),
160                              im->w, im->h);
161    if (!im->xim)
162      return;
163
164    im->shminfo.shmid = shmget(IPC_PRIVATE,
165                               im->xim->bytes_per_line * im->xim->height,
166                               IPC_CREAT | 0666);
167    if (im->shminfo.shmid == -1)
168      {
169         XDestroyImage(im->xim);
170         return;
171      }
172
173    im->shminfo.readOnly = False;
174    im->shminfo.shmaddr = shmat(im->shminfo.shmid, 0, 0);
175    im->xim->data = im->shminfo.shmaddr;
176    if ((im->xim->data == (char *)-1) ||
177        (!im->xim->data))
178      {
179         shmdt(im->shminfo.shmaddr);
180         shmctl(im->shminfo.shmid, IPC_RMID, 0);
181         XDestroyImage(im->xim);
182         return;
183      }
184
185    XShmAttach(_ecore_x_disp, &im->shminfo);
186
187    im->data = (unsigned char *)im->xim->data;
188
189    im->bpl = im->xim->bytes_per_line;
190    im->rows = im->xim->height;
191    if (im->xim->bits_per_pixel <= 8)
192      im->bpp = 1;
193    else if (im->xim->bits_per_pixel <= 16)
194      im->bpp = 2;
195    else
196      im->bpp = 4;
197 }
198
199 EAPI Eina_Bool
200 ecore_x_image_get(Ecore_X_Image *im,
201                   Ecore_X_Drawable draw,
202                   int x,
203                   int y,
204                   int sx,
205                   int sy,
206                   int w,
207                   int h)
208 {
209    Eina_Bool ret = EINA_TRUE;
210    XErrorHandler ph;
211
212    LOGFN(__FILE__, __LINE__, __FUNCTION__);
213    if (im->shm)
214      {
215         if (!im->xim)
216           _ecore_x_image_shm_create(im);
217
218         if (!im->xim)
219           return 0;
220
221         _ecore_x_image_err = 0;
222         
223         ecore_x_sync();
224         // optimised path
225         ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler);
226         if ((sx == 0) && (w == im->w))
227           {
228              im->xim->data = (char *)
229                im->data + (im->xim->bytes_per_line * sy) + (sx * im->bpp);
230              im->xim->width = w;
231              im->xim->height = h;
232              XGrabServer(_ecore_x_disp);
233              if (!XShmGetImage(_ecore_x_disp, draw, im->xim, x, y, 0xffffffff))
234                ret = EINA_FALSE;
235              XUngrabServer(_ecore_x_disp);
236              ecore_x_sync();
237           }
238         // unavoidable thanks to mit-shm get api - tmp shm buf + copy into it
239         else
240           {
241              Ecore_X_Image *tim;
242              unsigned char *spixels, *sp, *pixels, *p;
243              int bpp, bpl, rows, sbpp, sbpl, srows;
244              int r;
245
246              tim = ecore_x_image_new(w, h, im->vis, im->depth);
247              if (tim)
248                {
249                   ret = ecore_x_image_get(tim, draw, x, y, 0, 0, w, h);
250                   if (ret)
251                     {
252                        spixels = ecore_x_image_data_get(tim,
253                                                         &sbpl,
254                                                         &srows,
255                                                         &sbpp);
256                        pixels = ecore_x_image_data_get(im, &bpl, &rows, &bpp);
257                        if ((pixels) && (spixels))
258                          {
259                             p = pixels + (sy * bpl) + (sx * bpp);
260                             sp = spixels;
261                             for (r = srows; r > 0; r--)
262                               {
263                                  memcpy(p, sp, sbpl);
264                                  p += bpl;
265                                  sp += sbpl;
266                               }
267                          }
268                     }
269
270                   ecore_x_image_free(tim);
271                }
272           }
273
274         XSetErrorHandler((XErrorHandler)ph);
275         if (_ecore_x_image_err)
276           ret = EINA_FALSE;
277      }
278    else
279      {
280         printf("currently unimplemented ecore_x_image_get without shm\n");
281         ret = EINA_FALSE;
282      }
283
284    return ret;
285 }
286
287 EAPI void
288 ecore_x_image_put(Ecore_X_Image *im,
289                   Ecore_X_Drawable draw,
290                   Ecore_X_GC gc,
291                   int x,
292                   int y,
293                   int sx,
294                   int sy,
295                   int w,
296                   int h)
297 {
298    Ecore_X_GC tgc = 0;
299
300    LOGFN(__FILE__, __LINE__, __FUNCTION__);
301    if (!gc)
302      {
303         XGCValues gcv;
304         memset(&gcv, 0, sizeof(gcv));
305         gcv.subwindow_mode = IncludeInferiors;
306         tgc = XCreateGC(_ecore_x_disp, draw, GCSubwindowMode, &gcv);
307         gc = tgc;
308      }
309    if (!im->xim) _ecore_x_image_shm_create(im);
310    if (im->xim)
311      XShmPutImage(_ecore_x_disp, draw, gc, im->xim, sx, sy, x, y, w, h, False);
312    if (tgc) ecore_x_gc_free(tgc);
313 }
314
315 EAPI void *
316 ecore_x_image_data_get(Ecore_X_Image *im,
317                        int *bpl,
318                        int *rows,
319                        int *bpp)
320 {
321    LOGFN(__FILE__, __LINE__, __FUNCTION__);
322    if (!im->xim) _ecore_x_image_shm_create(im);
323    if (!im->xim) return NULL;
324    if (bpl) *bpl = im->bpl;
325    if (rows) *rows = im->rows;
326    if (bpp) *bpp = im->bpp;
327    return im->data;
328 }
329
330 EAPI Eina_Bool
331 ecore_x_image_is_argb32_get(Ecore_X_Image *im)
332 {
333    Visual *vis = im->vis;
334    if (!im->xim) _ecore_x_image_shm_create(im);
335    if (((vis->class == TrueColor) ||
336         (vis->class == DirectColor)) &&
337        (im->depth >= 24) &&
338        (vis->red_mask == 0xff0000) &&
339        (vis->green_mask == 0x00ff00) &&
340        (vis->blue_mask == 0x0000ff))
341      {
342 #ifdef WORDS_BIGENDIAN
343         if (im->xim->bitmap_bit_order == MSBFirst) return EINA_TRUE;
344 #else
345         if (im->xim->bitmap_bit_order == LSBFirst) return EINA_TRUE;
346 #endif
347      }
348    return EINA_FALSE;
349 }
350
351 EAPI Eina_Bool
352 ecore_x_image_to_argb_convert(void *src,
353                               int sbpp,
354                               int sbpl,
355                               Ecore_X_Colormap c,
356                               Ecore_X_Visual v,
357                               int x,
358                               int y,
359                               int w,
360                               int h,
361                               unsigned int *dst,
362                               int dbpl,
363                               int dx,
364                               int dy)
365 {
366    Visual *vis = v;
367    XColor *cols = NULL;
368    int n = 0, nret = 0, i, row;
369    unsigned int pal[256], r, g, b;
370    enum
371    {
372       rgbnone = 0,
373       rgb565,
374       bgr565,
375       rgbx555,
376       argbx888,
377       abgrx888,
378       rgba888x,
379       bgra888x,
380       argbx666
381    };
382    int mode = 0;
383
384    sbpp *= 8;
385
386    n = vis->map_entries;
387    if ((n <= 256) &&
388        ((vis->class == PseudoColor) ||
389         (vis->class == StaticColor) ||
390         (vis->class == GrayScale) ||
391         (vis->class == StaticGray)))
392      {
393         if (!c)
394           c = DefaultColormap(_ecore_x_disp,
395                               DefaultScreen(_ecore_x_disp));
396         cols = alloca(n * sizeof(XColor));
397         for (i = 0; i < n; i++)
398           {
399              cols[i].pixel = i;
400              cols[i].flags = DoRed | DoGreen | DoBlue;
401              cols[i].red = 0;
402              cols[i].green = 0;
403              cols[i].blue = 0;
404           }
405         XQueryColors(_ecore_x_disp, c, cols, n);
406         for (i = 0; i < n; i++)
407           {
408              pal[i] = 0xff000000 |
409                ((cols[i].red >> 8) << 16) |
410                ((cols[i].green >> 8) << 8) |
411                ((cols[i].blue >> 8));
412           }
413         nret = n;
414      }
415    else if ((vis->class == TrueColor) ||
416             (vis->class == DirectColor))
417      {
418         if ((vis->red_mask == 0x00ff0000) &&
419             (vis->green_mask == 0x0000ff00) &&
420             (vis->blue_mask == 0x000000ff))
421           mode = argbx888;
422         else if ((vis->red_mask == 0x000000ff) &&
423                  (vis->green_mask == 0x0000ff00) &&
424                  (vis->blue_mask == 0x00ff0000))
425           mode = abgrx888;
426         else if ((vis->red_mask == 0xff000000) &&
427                  (vis->green_mask == 0x00ff0000) &&
428                  (vis->blue_mask == 0x0000ff00))
429           mode = rgba888x;
430         else if ((vis->red_mask == 0x0000ff00) &&
431                  (vis->green_mask == 0x00ff0000) &&
432                  (vis->blue_mask == 0xff000000))
433           mode = bgra888x;
434         else if ((vis->red_mask == 0x0003f000) &&
435                  (vis->green_mask == 0x00000fc0) &&
436                  (vis->blue_mask == 0x0000003f))
437           mode = argbx666;
438         else if ((vis->red_mask == 0x0000f800) &&
439                  (vis->green_mask == 0x000007e0) &&
440                  (vis->blue_mask == 0x0000001f))
441           mode = rgb565;
442         else if ((vis->red_mask == 0x0000001f) &&
443                  (vis->green_mask == 0x000007e0) &&
444                  (vis->blue_mask == 0x0000f800))
445           mode = bgr565;
446         else if ((vis->red_mask == 0x00007c00) &&
447                  (vis->green_mask == 0x000003e0) &&
448                  (vis->blue_mask == 0x0000001f))
449           mode = rgbx555;
450         else
451           return EINA_FALSE;
452      }
453    for (row = 0; row < h; row++)
454      {
455         unsigned char *s8;
456         unsigned short *s16;
457         unsigned int *s32;
458         unsigned int *dp, *de;
459
460         dp = ((unsigned int *)(((unsigned char *)dst) +
461                                ((dy + row) * dbpl))) + dx;
462         de = dp + w;
463         switch (sbpp)
464           {
465            case 8:
466              s8 = ((unsigned char *)(((unsigned char *)src) + ((y + row) * sbpl))) + x;
467              if (nret > 0)
468                {
469                   while (dp < de)
470                     {
471                        *dp = pal[*s8];
472                        s8++; dp++;
473                     }
474                }
475              else
476                return EINA_FALSE;
477              break;
478
479            case 16:
480              s16 = ((unsigned short *)(((unsigned char *)src) + ((y + row) * sbpl))) + x;
481              switch (mode)
482                {
483                 case rgb565:
484                   while (dp < de)
485                     {
486                        r = (*s16 & 0xf800) << 8;
487                        g = (*s16 & 0x07e0) << 5;
488                        b = (*s16 & 0x001f) << 3;
489                        r |= (r >> 5) & 0xff0000;
490                        g |= (g >> 6) & 0x00ff00;
491                        b |= (b >> 5);
492                        *dp = 0xff000000 | r | g | b;
493                        s16++; dp++;
494                     }
495                   break;
496
497                 case bgr565:
498                   while (dp < de)
499                     {
500                        r = (*s16 & 0x001f) << 19;
501                        g = (*s16 & 0x07e0) << 5;
502                        b = (*s16 & 0xf800) >> 8;
503                        r |= (r >> 5) & 0xff0000;
504                        g |= (g >> 6) & 0x00ff00;
505                        b |= (b >> 5);
506                        *dp = 0xff000000 | r | g | b;
507                        s16++; dp++;
508                     }
509                   break;
510
511                 case rgbx555:
512                   while (dp < de)
513                     {
514                        r = (*s16 & 0x7c00) << 9;
515                        g = (*s16 & 0x03e0) << 6;
516                        b = (*s16 & 0x001f) << 3;
517                        r |= (r >> 5) & 0xff0000;
518                        g |= (g >> 5) & 0x00ff00;
519                        b |= (b >> 5);
520                        *dp = 0xff000000 | r | g | b;
521                        s16++; dp++;
522                     }
523                   break;
524
525                 default:
526                   return EINA_FALSE;
527                   break;
528                }
529              break;
530
531            case 24:
532            case 32:
533              s32 = ((unsigned int *)(((unsigned char *)src) + ((y + row) * sbpl))) + x;
534              switch (mode)
535                {
536                 case argbx888:
537                   while (dp < de)
538                     {
539                        *dp = 0xff000000 | *s32;
540                        s32++; dp++;
541                     }
542                   break;
543
544                 case abgrx888:
545                   while (dp < de)
546                     {
547                        r = *s32 & 0x000000ff;
548                        g = *s32 & 0x0000ff00;
549                        b = *s32 & 0x00ff0000;
550                        *dp = 0xff000000 | (r << 16) | (g) | (b >> 16);
551                        s32++; dp++;
552                     }
553                   break;
554
555                 case rgba888x:
556                   while (dp < de)
557                     {
558                        *dp = 0xff000000 | (*s32 >> 8);
559                        s32++; dp++;
560                     }
561                   break;
562
563                 case bgra888x:
564                   while (dp < de)
565                     {
566                        r = *s32 & 0x0000ff00;
567                        g = *s32 & 0x00ff0000;
568                        b = *s32 & 0xff000000;
569                        *dp = 0xff000000 | (r << 8) | (g >> 8) | (b >> 24);
570                        s32++; dp++;
571                     }
572                   break;
573
574                 case argbx666:
575                   while (dp < de)
576                     {
577                        r = (*s32 & 0x3f000) << 6;
578                        g = (*s32 & 0x00fc0) << 4;
579                        b = (*s32 & 0x0003f) << 2;
580                        r |= (r >> 6) & 0xff0000;
581                        g |= (g >> 6) & 0x00ff00;
582                        b |= (b >> 6);
583                        *dp = 0xff000000 | r | g | b;
584                        s32++; dp++;
585                     }
586                   break;
587
588                 default:
589                   return EINA_FALSE;
590                   break;
591                }
592              break;
593              break;
594
595            default:
596              return EINA_FALSE;
597              break;
598           }
599      }
600    return EINA_TRUE;
601 }
602