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