Fix pre-multiplied alpha issue
[platform/framework/native/shell.git] / src / FShell_AppWidgetLayer.cpp
1 //
2 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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                FShell_AppWidgetLayer.cpp
18  * @brief               This is the implementation file for the _AppWidgetLayer class.
19  */
20
21 #include <new>
22 #include <errno.h>
23 #include <string.h>
24 #include <sys/shm.h>
25 #include <X11/Xlib.h>
26 #include <X11/extensions/XShm.h>
27 #include <X11/Xutil.h>
28 #include <Evas.h>
29 #include <Ecore_X.h>
30 #include <provider.h>
31 #include <provider_buffer.h>
32 #include <FBaseSysLog.h>
33 #include <FBase_StringConverter.h>
34 #include <FGrpRectangle.h>
35 #include "FUi_Window.h"
36 #include "FShell_AppWidgetBuffer.h"
37 #include "FShell_AppWidgetLayer.h"
38 #include "FShell_AppWidgetProviderManagerImpl.h"
39
40 //#define _BUFFER_TEST
41
42 using namespace std;
43 using namespace Tizen::Base;
44 using namespace Tizen::Graphics;
45 using namespace Tizen::Ui::Animations;
46 using namespace Tizen::Ui;
47 using namespace Tizen::Shell;
48
49 namespace
50 {
51
52 void*
53 AllocRenderBuffer(void* pData, int size)
54 {
55         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
56         SysTryReturn(NID_SHELL, pAppWidgetLayer, null, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
57
58         return pAppWidgetLayer->AllocCanvas(size);
59 }
60
61 void
62 FreeRenderBuffer(void* pData, void* pCanvas)
63 {
64         SysTryReturnVoidResult(NID_SHELL, pCanvas, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
65
66         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
67         SysTryReturnVoidResult(NID_SHELL, pAppWidgetLayer, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
68
69         pAppWidgetLayer->FreeCanvas(pCanvas);
70 }
71
72 void
73 PostRender(void* pData, Evas* pEvas, void* pEventInfo)
74 {
75         SysLog(NID_SHELL, "ENTER");
76
77         _AppWidgetLayer* pAppWidgetLayer = static_cast<_AppWidgetLayer*>(pData);
78         SysTryReturnVoidResult(NID_SHELL, pAppWidgetLayer, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
79
80         pAppWidgetLayer->OnRendered();
81 }
82
83 }
84
85 namespace Tizen { namespace Shell
86 {
87
88 _AppWidgetLayer::_AppWidgetLayer(const Tizen::Base::String& providerId, const FloatDimension& size)
89         : __isReleased(false)
90         , __size(size)
91         , __pEcoreEvas(null)
92         , __pEvasObject(null)
93         , __providerId(providerId)
94         , __pRenderBuffer(null)
95         , __pTempBuffer(null)
96         , __bufferSize(0)
97         , __pixmapId(-1)
98         , __pAppWidgetBuffer(new (std::nothrow) _AppWidgetBuffer)
99 {
100 }
101
102 _AppWidgetLayer::~_AppWidgetLayer(void)
103 {
104         __pRenderBuffer = null;
105         __pTempBuffer = null;
106         __pixmapId = -1;
107 }
108
109 result
110 _AppWidgetLayer::OnConstructed(void)
111 {
112         result r = E_SUCCESS;
113
114         __pAppWidgetBuffer->Initialize();
115
116         unique_ptr<Ecore_Evas, _EcoreEvasDeleter> pEcoreEvas(ecore_evas_buffer_allocfunc_new(__size.width, __size.height, AllocRenderBuffer, FreeRenderBuffer, this));
117         SysTryReturn(NID_SHELL, pEcoreEvas, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
118
119         ecore_evas_alpha_set(pEcoreEvas.get(), EINA_TRUE);
120         ecore_evas_manual_render_set(pEcoreEvas.get(), EINA_FALSE);
121         ecore_evas_resize(pEcoreEvas.get(), __size.width, __size.height);
122         ecore_evas_activate(pEcoreEvas.get());
123
124         Evas* pEvas = ecore_evas_get(pEcoreEvas.get());
125         SysTryReturn(NID_SHELL, pEvas, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
126
127 //      evas_event_callback_add(pEvas, EVAS_CALLBACK_RENDER_POST, PostRender, this);
128
129         unique_ptr<Evas_Object, _EvasObjectDeleter> pEvasObject(evas_object_rectangle_add(pEvas));
130         SysTryReturn(NID_SHELL, pEvasObject, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
131
132         evas_object_resize(pEvasObject.get(), __size.width, __size.height);
133         evas_object_color_set(pEvasObject.get(), 0, 0, 0, 255);
134
135         r = Initialize(pEvasObject.get());
136         SysTryReturn(NID_SHELL, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
137
138         __pEcoreEvas = move(pEcoreEvas);
139         __pEvasObject = move(pEvasObject);
140
141         ecore_evas_alpha_set(__pEcoreEvas.get(), EINA_TRUE);
142         evas_object_color_set(__pEvasObject.get(), 0, 0, 0, 0);
143
144         if (!__providerId.IsEmpty())
145         {
146                 r = RegisterTouchEventListener();
147                 SysTryReturn(NID_SHELL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
148         }
149
150         return r;
151 }
152
153 result
154 _AppWidgetLayer::SetProviderId(const String& providerId)
155 {
156         __providerId = providerId;
157
158         __pixmapId = AcquirePixmap();
159         SysTryReturn(NID_SHELL, __pixmapId != -1, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
160
161         SysLog(NID_SHELL, "pixmapId (%d)", __pixmapId);
162
163         result r = RegisterTouchEventListener();
164         SysTryReturn(NID_SHELL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
165
166         return r;
167 }
168
169 String
170 _AppWidgetLayer::GetProviderId(void) const
171 {
172         return __providerId;
173 }
174
175 int
176 _AppWidgetLayer::GetPixmapId(void) const
177 {
178         return __pixmapId;
179 }
180
181 void
182 _AppWidgetLayer::SetLayerBounds(const FloatRectangle& bounds)
183 {
184         __size = FloatDimension(bounds.width, bounds.height);
185
186         ecore_evas_resize(__pEcoreEvas.get(), __size.width, __size.height);
187
188         SetBounds(bounds);
189 }
190
191 void*
192 _AppWidgetLayer::AllocCanvas(int size)
193 {
194         SysTryReturn(NID_SHELL, size > 0, null, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
195
196         __bufferSize = size;
197         void* pBuffer = null;
198
199         if (__providerId.IsEmpty())
200         {
201                 __pTempBuffer =  malloc(__bufferSize);
202                 SysTryReturn(NID_SHELL, __pTempBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
203                 
204                 pBuffer = __pTempBuffer;
205         }
206         else
207         {
208                 if (__pixmapId == -1)
209                 {
210                         __pixmapId = AcquirePixmap();
211                         SysTryReturn(NID_SHELL, __pixmapId != -1, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
212                 }
213
214                 __pRenderBuffer = __pAppWidgetBuffer->AllocBuffer(__pixmapId, __size);
215                 pBuffer = __pRenderBuffer;
216                 __pAppWidgetBuffer->UnlockBuffer();
217         }
218
219         SysLog(NID_SHELL, "buffer (0x%x 0x%x) size (%d) pixmap (%d)", __pTempBuffer, __pRenderBuffer, __bufferSize, __pixmapId);
220
221         __isReleased = false;
222
223         return pBuffer;
224 }
225
226 void
227 _AppWidgetLayer::FreeCanvas(void* pCanvas)
228 {
229         SysLog(NID_SHELL, "buffer (0x%x 0x%x 0x%x) size (%d)", __pTempBuffer, __pRenderBuffer, pCanvas, __bufferSize);
230
231         if (__pTempBuffer)
232         {
233                 free(__pTempBuffer);
234                 __pTempBuffer = null;
235         }
236         else
237         {
238                 if (__pAppWidgetBuffer)
239                 {
240                         __pAppWidgetBuffer->DeallocBuffer();
241                 }
242         }
243
244         if (!__isReleased)
245         {
246                 ReleasePixmap();
247                 __isReleased = true;
248         }
249
250         __pixmapId = -1;
251         __pRenderBuffer = null;
252 }
253
254 result
255 _AppWidgetLayer::SyncPixmap(const FloatDimension& size)
256 {
257         SysTryReturn(NID_SHELL, __pRenderBuffer, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
258         SysTryReturn(NID_SHELL, __pAppWidgetBuffer, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
259
260         SysLog(NID_SHELL, "buffer (0x%x) size (%d) pixmapId (%d) width(%f) height(%f)", __pRenderBuffer, __bufferSize, __pixmapId, size.width, size.height);
261
262         XShmPutImage(__pAppWidgetBuffer->GetDisplay(), static_cast<Pixmap>(__pixmapId), __pAppWidgetBuffer->GetGc(), __pAppWidgetBuffer->GetXImage(), 0, 0, 0, 0, size.width, size.height, False);
263         XSync(__pAppWidgetBuffer->GetDisplay(), False);
264
265         return E_SUCCESS;
266 }
267
268 void
269 _AppWidgetLayer::OnRendered(void)
270 {
271         result r = E_SUCCESS;
272
273         if (!__pAppWidgetBuffer->IsGemBufferEnabled())
274         {
275                 if (__pixmapId == -1)
276                 {
277                         __pixmapId = AcquirePixmap();
278                         SysTryReturnVoidResult(NID_SHELL, __pixmapId >= 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
279                 }
280
281                 r = SyncPixmap(__size);
282                 SysTryReturnVoidResult(NID_SHELL, r == E_SUCCESS, r, "[%s] Propagating.", GetErrorMessage(r));
283         }
284
285         r = Sync(__size);
286         SysTryReturnVoidResult(NID_SHELL, r == E_SUCCESS, r, "[%s] Propagating.", GetErrorMessage(r));
287 }
288
289 result
290 _AppWidgetLayer::RegisterTouchEventListener(void)
291 {
292         result r = _AppWidgetProviderManagerImpl::GetInstance()->SetAppWidgetTouchEventListener(__providerId, *this);
293         SysTryReturn(NID_SHELL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
294
295         return r;
296 }
297
298 int
299 _AppWidgetLayer::AcquirePixmap(void)
300 {
301         SysTryReturn(NID_SHELL, !__providerId.IsEmpty(), -1, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
302
303         int pixmapId = -1;
304
305         result r = _AppWidgetProviderManagerImpl::GetInstance()->RequestSharedMemoryId(__providerId, __size.width, __size.height, pixmapId);
306         SysTryReturn(NID_SHELL, r == E_SUCCESS, -1, r, "[%s] Propagating.", GetErrorMessage(r));
307
308         SysLog(NID_SHELL, "pixmapId(%d) size(%f %f)", pixmapId, __size.width, __size.height);
309
310         return pixmapId;
311 }
312
313 result
314 _AppWidgetLayer::Sync(const FloatDimension& size)
315 {
316         SysTryReturn(NID_SHELL, !__providerId.IsEmpty(), E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
317
318         result r = _AppWidgetProviderManagerImpl::GetInstance()->RequestSyncSharedMemory(__providerId, size.width, size.height);
319         SysTryReturn(NID_SHELL, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
320
321         return r;
322 }
323
324 void
325 _AppWidgetLayer::ReleasePixmap(void)
326 {
327         SysTryReturnVoidResult(NID_SHELL, !__providerId.IsEmpty(), E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
328
329         _AppWidgetProviderManagerImpl::GetInstance()->RequestReleaseSharedMemory(__providerId);
330 }
331
332 int
333 _AppWidgetLayer::OnTouchEventRecevied(int eventType, double timestamp, double x, double y)
334 {
335         SysLog(NID_SHELL, "eventType (%d) timestamp (%f) (%f, %f)", eventType, timestamp, x, y);
336
337         int xPos = __size.width * x;
338         int yPos = __size.height * y;
339
340         Evas* pEvas = ecore_evas_get(__pEcoreEvas.get());
341         SysTryReturn(NID_SHELL, pEvas, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
342
343         switch (eventType)
344         {
345         case BUFFER_EVENT_ENTER:
346                 evas_event_feed_mouse_in(pEvas, timestamp, null);
347                 break;
348
349         case BUFFER_EVENT_LEAVE:
350                 evas_event_feed_mouse_out(pEvas, timestamp, null);
351                 break;
352
353         case BUFFER_EVENT_DOWN:
354                 evas_event_feed_mouse_in(pEvas, timestamp, null);
355                 evas_event_feed_mouse_move(pEvas, xPos, yPos, timestamp + 0.01f, null);
356                 evas_event_feed_mouse_down(pEvas, 1, EVAS_BUTTON_NONE, timestamp + 0.02f, null);
357                 break;
358
359         case BUFFER_EVENT_MOVE:
360                 evas_event_feed_mouse_move(pEvas, xPos, yPos, timestamp, null);
361                 break;
362
363         case BUFFER_EVENT_UP:
364                 evas_event_feed_mouse_up(pEvas, 1, EVAS_BUTTON_NONE, timestamp, null);
365                 evas_event_feed_mouse_out(pEvas, timestamp + 0.01f, null);
366                 break;
367
368         default:
369                 break;
370         }
371
372         return 0;
373 }
374
375 void
376 _AppWidgetLayer::Flush(void)
377 {
378         SysLog(NID_SHELL, "ENTER");
379
380         bool needed = IsFlushNeeded();
381
382         if (needed)
383         {
384                 __pAppWidgetBuffer->LockBuffer();
385
386                 Evas* pEvas = ecore_evas_get(__pEcoreEvas.get());
387                 SysTryReturnVoidResult(NID_SHELL, pEvas, E_OUT_OF_MEMORY, "[%s] Propagating.", GetErrorMessage(E_OUT_OF_MEMORY));
388
389                 evas_damage_rectangle_add(pEvas, 0, 0, __size.width, __size.height);
390         }
391
392         _EflLayer::Flush();
393
394         if (needed)
395         {\r
396                 void* pBuffer = const_cast<void*>(ecore_evas_buffer_pixels_get(__pEcoreEvas.get()));\r
397                 SysTryReturnVoidResult(NID_SHELL, pBuffer, E_OUT_OF_MEMORY, "[%s] Propagating.", GetErrorMessage(E_OUT_OF_MEMORY));\r
398 \r
399                 evas_data_argb_unpremul(static_cast<unsigned int*>(pBuffer), __size.width * __size.height);
400
401                 OnRendered();
402
403                 __pAppWidgetBuffer->UnlockBuffer();
404         }
405 }
406
407 }} // Tizen::Shell