tizen 2.3.1 release
[framework/web/mobile/wrt.git] / src / wrt-launchpad-daemon / src / web_app_core_tskmgr_util.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file    web_app_core_tskmgr_util.cpp
18  * @author  Prathmesh Manurkar (prathmesh.m@samsung.com)
19  */
20
21 #include "web_app_core_tskmgr_util.h"
22
23 #include <sys/shm.h>
24
25 #include <dpl/log/wrt_log.h>
26 #include <Ecore_Evas.h>
27 #include <Ecore_X.h>
28 #include <Elementary.h>
29 #include <X11/extensions/Xcomposite.h>
30 #include <X11/extensions/XShm.h>
31 #include <X11/Xatom.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34
35 #define QUALITY_N_COMPRESS "quality=100 compress=1"
36
37 static Evas *createVirtualCanvas(int w, int h)
38 {
39     Ecore_Evas *internal_ee;
40     Evas *internal_e;
41
42     // Create virtual canvas
43     internal_ee = ecore_evas_buffer_new(w, h);
44     if (!internal_ee) {
45         WrtLogW("Failed to create a new canvas buffer");
46         return NULL;
47     }
48
49     ecore_evas_alpha_set(internal_ee, EINA_TRUE);
50     ecore_evas_manual_render_set(internal_ee, EINA_TRUE);
51
52     // Get the "Evas" object from a virtual canvas
53     internal_e = ecore_evas_get(internal_ee);
54     if (!internal_e) {
55         ecore_evas_free(internal_ee);
56         WrtLogW("Faield to get Evas object");
57         return NULL;
58     }
59
60     return internal_e;
61 }
62
63
64
65 static bool flushDataToFile(Evas *e, void *data, const char *filename, int w, int h)
66 {
67     Evas_Object *output;
68
69     output = evas_object_image_add(e);
70     if (!output) {
71         WrtLogW("Failed to create an image object");
72         return false;
73     }
74
75     evas_object_image_data_set(output, NULL);
76     evas_object_image_colorspace_set(output, EVAS_COLORSPACE_ARGB8888);
77     evas_object_image_alpha_set(output, EINA_TRUE);
78     evas_object_image_size_set(output, w, h);
79     evas_object_image_smooth_scale_set(output, EINA_TRUE);
80     evas_object_image_data_set(output, data);
81     evas_object_image_data_update_add(output, 0, 0, w, h);
82
83     if (evas_object_image_save(output, filename, NULL, QUALITY_N_COMPRESS) == EINA_FALSE) {
84         evas_object_del(output);
85         WrtLogW("Faild to save a captured image (%s)", filename);
86         return false;
87     }
88
89     evas_object_del(output);
90
91     if (access(filename, F_OK) != 0) {
92         WrtLogW("File %s is not found", filename);
93         return false;
94     }
95
96     return true;
97 }
98
99
100
101 static bool flushVirtualCanvasToFile(Evas *e, const char *filename, int w, int h)
102 {
103     void *data;
104     Ecore_Evas *internal_ee;
105
106     internal_ee = ecore_evas_ecore_evas_get(e);
107     if (!internal_ee) {
108         WrtLogW("Failed to get ecore evas");
109         return false;
110     }
111
112     ecore_evas_manual_render(internal_ee);
113
114     // Get a pointer of a buffer of the virtual canvas
115     data = (void *) ecore_evas_buffer_pixels_get(internal_ee);
116     if (!data) {
117         WrtLogW("Failed to get pixel data");
118         return false;
119     }
120
121     return flushDataToFile(e, data, filename, w, h);
122 }
123
124
125
126 static bool destroyVirtualCanvas(Evas *e)
127 {
128     Ecore_Evas *ee;
129
130     ee = ecore_evas_ecore_evas_get(e);
131     if (!ee) {
132         WrtLogW("Failed to ecore evas object");
133         return false;
134     }
135
136     ecore_evas_free(ee);
137     return true;
138 }
139
140 static Window getParentWindow(Window id)
141 {
142     Window root;
143     Window parent;
144     Window *children;
145     unsigned int num;
146
147     if (!XQueryTree((Display*)ecore_x_display_get(), id, &root, &parent, &children, &num)) {
148         return 0;
149     }
150
151     if (children) {
152         XFree(children);
153     }
154
155     return parent;
156 }
157
158 static Window findCaptureWindow(Window id, Visual **visual, int *depth, int *width, int *height)
159 {
160     XWindowAttributes attr;
161     Window parent = id;
162     Window orig_id = id;
163
164     if (id == 0) {
165         return (Window)-1;
166     }
167
168     do {
169         id = parent;
170
171         if (!XGetWindowAttributes((Display*)ecore_x_display_get(), id, &attr)) {
172             return (Window)-1;
173         }
174
175         parent = getParentWindow(id);
176
177         if (attr.map_state == IsViewable
178             && attr.override_redirect == true
179             && attr.c_class == InputOutput && parent == attr.root) {
180             *depth = attr.depth;
181             *width = attr.width;
182             *height = attr.height;
183             *visual = attr.visual;
184             return id;
185         }
186     } while (parent != attr.root && parent != 0);
187
188     XGetWindowAttributes((Display*)ecore_x_display_get(), orig_id, &attr);
189     *depth = attr.depth;
190     *width = attr.width;
191     *height = attr.height;
192     *visual = attr.visual;
193
194     return (Window) 0;
195
196 }
197
198 static char *captureWindow(Window id, Visual *visual, int width, int height, int depth, int *size)
199 {
200     XShmSegmentInfo si;
201     XImage *xim;
202     int img_size;
203     char *captured_img = NULL;
204
205     /* (depth >> 3) + 1 == 4 byte */
206     si.shmid =
207         shmget(IPC_PRIVATE, width * height * ((depth >> 3) + 1),
208            IPC_CREAT | 0666);
209
210     if (si.shmid < 0) {
211         WrtLogW("shmget");
212         return NULL;
213     }
214
215     si.readOnly = False;
216     si.shmaddr = (char*)shmat(si.shmid, NULL, 0);
217
218     if (si.shmaddr == (char *)-1) {
219         shmdt(si.shmaddr);
220         shmctl(si.shmid, IPC_RMID, 0);
221         return NULL;
222     }
223
224     xim = XShmCreateImage((Display*)ecore_x_display_get(), visual, depth, ZPixmap, NULL, &si,
225                 width, height);
226
227     if (xim == 0) {
228         shmdt(si.shmaddr);
229         shmctl(si.shmid, IPC_RMID, 0);
230
231         return NULL;
232     }
233
234     img_size = xim->bytes_per_line * xim->height;
235     xim->data = si.shmaddr;
236
237     XSync((Display*)ecore_x_display_get(), False);
238     XShmAttach((Display*)ecore_x_display_get(), &si);
239     XShmGetImage((Display*)ecore_x_display_get(), id, xim, 0, 0, 0xFFFFFFFF);
240     XSync((Display*)ecore_x_display_get(), False);
241
242     captured_img = (char*)calloc(1, img_size);
243     if (captured_img) {
244         memcpy(captured_img, xim->data, img_size);
245     } else {
246         WrtLogD("calloc");
247     }
248
249     XShmDetach((Display*)ecore_x_display_get(), &si);
250     XDestroyImage(xim);
251
252
253     shmdt(si.shmaddr);
254     shmctl(si.shmid, IPC_RMID, 0);
255
256     *size = img_size;
257
258     return captured_img;
259 }
260
261 #define _WND_REQUEST_ANGLE_IDX 0
262 int getAngle(Ecore_X_Window win)
263 {
264     WrtLogD("getAngle called");
265
266     int after = -1;
267
268     do {
269         int ret, count;
270         int angle[2] = {-1, -1};
271         unsigned char* prop_data = NULL;
272
273         ret = ecore_x_window_prop_property_get(win,
274                 ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
275                 ECORE_X_ATOM_CARDINAL,
276                 32,
277                 &prop_data,
278                 &count);
279         if (ret <= 0) {
280             if (prop_data) free(prop_data);
281             break;
282         }
283
284         if (prop_data) {
285             memcpy(&angle, prop_data, sizeof (int) *count);
286             free(prop_data);
287         }
288
289         after = angle[_WND_REQUEST_ANGLE_IDX];
290     } while (0);
291
292     if (-1 == after) after = 0;
293
294     return after;
295 }
296
297 static void rotateImg(Evas_Object *image_object, int angle, int cx, int cy)
298 {
299     Evas_Map *em;
300
301     if (NULL == image_object)
302         return;
303
304     em = evas_map_new(4);
305     if(NULL == em)
306         return;
307
308     evas_map_util_points_populate_from_object(em, image_object);
309     evas_map_util_rotate(em, (double) angle, cx, cy);
310
311     evas_object_map_set(image_object, em);
312     evas_object_map_enable_set(image_object, EINA_TRUE);
313
314     evas_map_free(em);
315 }
316
317 #define EXTENSION_LEN 128
318 #define CAPTURE_FILE_PATH "/opt/usr/share/app_capture"
319 static bool makeCaptureFile(const char *package, int width, int height, char *img, int angle)
320 {
321     int len;
322     char *filename;
323     Evas *e;
324     Evas_Object *image_object;
325     int canvas_width, canvas_height;
326     int cx = 0, cy = 0;
327     int mx = 0;
328
329     if (NULL == package)
330         return false;
331
332     len = strlen(package) + EXTENSION_LEN;
333     filename = (char*)malloc(len);
334     if(NULL == filename)
335         return false;
336
337     snprintf(filename, len, CAPTURE_FILE_PATH"/%s.jpg", package);
338
339     if (90 == angle || 270 == angle) {
340         canvas_width = height;
341         canvas_height = width;
342     } else {
343         canvas_width = width;
344         canvas_height = height;
345     }
346
347     e = createVirtualCanvas(canvas_width, canvas_height);
348     if (NULL == e)
349         goto error;
350
351     image_object = evas_object_image_add(e);
352     if (NULL == image_object)
353         goto error;
354
355     evas_object_image_size_set(image_object, width, height);
356     evas_object_image_data_set(image_object, img);
357     evas_object_image_data_update_add(image_object, 0, 0, width, height);
358     evas_object_resize(image_object, width, height);
359     evas_object_image_filled_set(image_object, EINA_TRUE);
360     switch (angle) {
361         case 90:
362             cx = canvas_width - width / 2;
363             cy = canvas_height / 2;
364             mx = canvas_width - width;
365             break;
366         case 180:
367             cx = width / 2;
368             cy = height / 2;
369             break;
370         case 270:
371             cx = width / 2;
372             cy = canvas_height / 2;
373             break;
374         default:
375             break;
376     }
377     evas_object_move(image_object, mx, 0);
378     rotateImg(image_object, angle, cx, cy);
379     evas_object_show(image_object);
380
381     if (access(CAPTURE_FILE_PATH, F_OK) != 0) {
382         mkdir(CAPTURE_FILE_PATH, 0777);
383     }
384     if(false == flushVirtualCanvasToFile(e, filename, canvas_width, canvas_height))
385         goto error;
386
387     evas_object_del(image_object);
388     destroyVirtualCanvas(e);
389     free(filename);
390
391     return true;
392
393 error:
394     do {
395         free(filename);
396
397         if (!e) break;
398         destroyVirtualCanvas(e);
399
400         if (!image_object) break;
401         evas_object_del(image_object);
402     } while (0);
403
404     return false;
405 }
406
407 static int resizeTo8888(const char* pDataIn, char* pDataOut, int inWidth, int inHeight, int outWidth, int outHeight)
408 {
409     int scaleX = 0;
410     int scaleY = 0;
411     int i = 0;
412     int j = 0;
413     int iRow = 0;
414     int iIndex = 0;
415     char* pOutput = pDataOut;
416     char* pOut = pDataOut;
417     const char* pIn = NULL;
418     int *pColLUT = (int*)malloc(sizeof(int) * outWidth);
419
420     /* Calculate X Scale factor */
421     scaleX = inWidth * 256 / outWidth;
422     /* Calculate Y Scale factor, aspect ratio is not maintained */
423     scaleY = inHeight * 256 / outHeight;
424     for (j = 0; j < outWidth; j++) {
425         /* Get input index based on column scale factor */
426         /* To get more optimization, this is calculated once and
427         * is placed in a LUT and used for indexing
428         */
429         pColLUT [j] = ((j * scaleX) >> 8) * 4;
430     }
431     pOut = pOutput;
432     for (i = 0; i < outHeight; i++) {
433         /* Get input routWidth index based on routWidth scale factor */
434         iRow = (i * scaleY >> 8) * inWidth * 4;
435         /* Loop could be unrolled for more optimization */
436         for (j = 0; j < (outWidth); j++) {
437             /* Get input index based on column scale factor */
438             iIndex = iRow + pColLUT [j];
439             pIn = pDataIn + iIndex;
440             *pOut++ = *pIn++;
441             *pOut++ = *pIn++;
442             *pOut++ = *pIn++;
443             *pOut++ = *pIn++;
444         }
445     }
446
447     free(pColLUT);
448     return 0;
449 }
450
451 void captureAndMakeFileForTaskMgr(Ecore_X_Window win, const char *package)
452 {
453     Visual *visual;
454     Window redirected_id;
455
456     int width, height, depth;
457     int width_out, height_out;
458     int size = 0;
459     int angle;
460
461     char *img;
462
463     redirected_id = findCaptureWindow(win, &visual, &depth, &width, &height);
464     if (redirected_id == (Window) -1 || redirected_id == (Window) 0) {
465         return;
466     }
467
468     WrtLogD("Capture : win[%x] -> redirected win[%x] for %s", win, redirected_id, package);
469
470     img = captureWindow(redirected_id, visual, width, height, depth, &size);
471     if (NULL == img) {
472         return;
473     }
474
475     width_out = width/2;
476     height_out = height/2;
477
478     if ( width_out < 1 || height_out < 1 ) {
479         free(img);
480         return;
481     }
482
483     resizeTo8888(img, img, width, height, width_out, height_out);
484
485     angle = getAngle(win);
486     if (false == makeCaptureFile(package, width_out, height_out, img, angle)) {
487         WrtLogW("cannot a capture file for the package of [%s]", package);
488     }
489
490     free(img);
491 }