9bae32a151c9158f1256dc4c882e41e2976aeb96
[platform/framework/web/web-provider.git] / src / Core / Buffer / RenderBuffer.cpp
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
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    RenderBuffer.cpp
18  * @author  Yunchan Cho (yunchan.cho@samsung.com)
19  */
20 #include <string>
21 #include <Evas.h>
22 #include <Ecore.h>
23 #include <Ecore_Evas.h>
24 #include <provider.h>
25 #include <provider_buffer.h>
26 #include <Core/Util/Log.h>
27 #include "IRenderBuffer.h"
28 #include "RenderBuffer.h"
29
30 RenderBuffer::RenderBuffer()
31     : m_bufferAddr(NULL)
32     , m_bufferInfo(NULL)
33 {
34 }
35
36 RenderBuffer::~RenderBuffer()
37 {
38 }
39
40 bool RenderBuffer::allocate()
41 {
42     LogD("enter");
43     if (m_bufferAddr) {
44         free();
45         m_bufferAddr = NULL;
46     }
47
48     Ecore_Evas* ee = 
49         ecore_evas_buffer_allocfunc_new( 
50                 getWidth(), getHeight(), 
51                 allocateCallback, freeCallback, 
52                 this);
53     LogD("Using %s engine!", ecore_evas_engine_name_get(ee));
54
55     if (!ee) {
56         LogD("invalid ecore evas object");
57         return false;
58     }
59
60     LogD("evas ecore setting");
61
62     // alpha_set function access the canvas buffer directly, 
63     //  without pre/post render callback.
64     provider_buffer_pre_render(m_bufferInfo);
65     ecore_evas_alpha_set(ee, EINA_TRUE);
66     provider_buffer_post_render(m_bufferInfo);
67     ecore_evas_manual_render_set(ee, EINA_FALSE);
68
69     // resize function will invoke the freeCallback and allocateCallback again. (internally)
70     ecore_evas_resize(ee, getWidth(), getHeight());
71     ecore_evas_show(ee);
72     ecore_evas_activate(ee);
73
74     LogD("Using %s engine!", ecore_evas_engine_name_get(ee));
75
76     Evas* e = ecore_evas_get(ee);
77     Evas_Object *eo = evas_object_rectangle_add(e);
78     evas_object_size_hint_weight_set(eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
79     evas_object_color_set(eo, 0, 0, 0, 0);
80     evas_object_resize(eo, getWidth(), getHeight());
81
82     m_canvas = e;
83     m_win = eo;
84
85     startCanvasUpdate();
86     return true;
87 }
88
89 bool RenderBuffer::reallocate(int width, int height)
90 {
91     LogD("enter");
92     stopCanvasUpdate();
93
94     // TODO This function should be implemented due to box resize operation
95     setWidth(width);
96     setHeight(height);
97
98     Ecore_Evas* ee = ecore_evas_ecore_evas_get(m_canvas);
99     // resize function will invoke the freeCallback and allocateCallback again. (internally)
100     ecore_evas_resize(ee, getWidth(), getHeight());
101     evas_object_resize(m_win, getWidth(), getHeight());
102     startCanvasUpdate();
103     return true;
104 }
105
106 bool RenderBuffer::free()
107 {
108     if (!m_canvas) {
109         return false;
110     }
111
112     stopCanvasUpdate();
113     ecore_evas_free(ecore_evas_ecore_evas_get(m_canvas));
114     m_canvas = NULL;
115     m_win = NULL;
116
117     return true;
118 }
119
120 void RenderBuffer::startCanvasUpdate()
121 {
122     LogD("enter");
123     evas_event_callback_del(
124             m_canvas,
125             EVAS_CALLBACK_RENDER_PRE,
126             preRenderCallback);
127
128     evas_event_callback_del( 
129             m_canvas, 
130             EVAS_CALLBACK_RENDER_POST, 
131             postRenderCallback);
132
133     evas_event_callback_add(
134             m_canvas,
135             EVAS_CALLBACK_RENDER_PRE,
136             preRenderCallback, this);
137
138     evas_event_callback_add( 
139             m_canvas, 
140             EVAS_CALLBACK_RENDER_POST, 
141             postRenderCallback, this);
142
143 }
144
145 void RenderBuffer::stopCanvasUpdate()
146 {
147     LogD("enter");
148     evas_event_callback_del(
149             m_canvas,
150             EVAS_CALLBACK_RENDER_PRE,
151             preRenderCallback);
152
153     evas_event_callback_del( 
154             m_canvas, 
155             EVAS_CALLBACK_RENDER_POST, 
156             postRenderCallback);
157 }
158
159 Evas_Object* RenderBuffer::getWindow()
160 {
161     return m_win;
162 }
163
164 void RenderBuffer::preRenderCallback(void* data, Evas* canvas, void *eventInfo)
165 {
166     LogD("enter");
167     RenderBuffer *buffer = static_cast<RenderBuffer*>(data);
168     if (!provider_buffer_pixmap_is_support_hw(buffer->m_bufferInfo)) {
169         LogD("not hw backend");
170         return;
171     }
172
173     provider_buffer_pre_render(buffer->m_bufferInfo);
174     evas_damage_rectangle_add(canvas, 0, 0, buffer->getWidth(), buffer->getHeight());
175 }
176
177 void RenderBuffer::postRenderCallback(void* data, Evas* canvas, void* eventInfo)
178 {
179     LogD("enter");
180     RenderBuffer* buffer = static_cast<RenderBuffer*>(data);
181
182     evas_data_argb_unpremul(static_cast<unsigned int*>(buffer->m_bufferAddr), buffer->getWidth() * buffer->getHeight());
183 #ifdef RENDER_BUFFER_VERIFY_SHOT
184     {
185         FILE *fp;
186         static int idx = 0;
187         char filename[256];
188         snprintf(filename, sizeof(filename) - 1, "/tmp/render%d-%dx%d.raw", idx++, buffer->getWidth(), buffer->getHeight());
189         fp = fopen(filename, "w+");
190         if (fp) {
191             LogD("RenderShot: %s(%d)\n", filename, buffer->getWidth() * buffer->getHeight() * sizeof(int));
192             fwrite(buffer->m_bufferAddr, buffer->getWidth() * buffer->getHeight() * sizeof(int), 1, fp);
193             fclose(fp);
194         } else {
195             LogD("Failed to open a file: %s", filename);
196         }
197     }
198 #endif
199
200     if (!provider_buffer_pixmap_is_support_hw(buffer->m_bufferInfo)) {
201         provider_buffer_sync(buffer->m_bufferInfo);
202         buffer->updateBuffer();
203     } else {
204         provider_buffer_post_render(buffer->m_bufferInfo);
205         buffer->updateBuffer();
206     }
207 }
208
209 void RenderBuffer::paintColor(unsigned int color)
210 {
211     LogD("enter");
212
213     if (!provider_buffer_pixmap_is_support_hw(m_bufferInfo)) {
214         memset(m_bufferAddr, color, getWidth() * getHeight() * 4);
215         provider_buffer_sync(m_bufferInfo);
216         updateBuffer();
217     } else {
218         provider_buffer_pre_render(m_bufferInfo);
219         memset(m_bufferAddr, color, getWidth() * getHeight() * 4);
220         provider_buffer_post_render(m_bufferInfo);
221         updateBuffer();
222     }
223 }
224
225 Evas* RenderBuffer::getCanvas()
226 {
227     return m_canvas;
228 }
229
230 void* RenderBuffer::allocateCallback(void* data, int size)
231 {
232     LogD("enter");
233     RenderBuffer* buffer = static_cast<RenderBuffer*>(data);
234
235     if (buffer->m_bufferInfo) {
236         freeCallback(data, NULL);
237     }
238
239     buffer->m_bufferInfo = buffer->acquireBuffer();
240     if (!buffer->m_bufferInfo) {
241         return NULL;
242     }
243     
244     // set buffer address
245     if (!provider_buffer_pixmap_is_support_hw(buffer->m_bufferInfo)) {
246         LogD("s/w evas backend");
247         buffer->m_bufferAddr = provider_buffer_ref(buffer->m_bufferInfo);
248     } else {
249         LogD("h/w evas backend");
250         int ret = provider_buffer_pixmap_create_hw(buffer->m_bufferInfo);
251         if (ret < 0) {
252             LogD("can't create hw pixmap");
253         }
254         buffer->m_bufferAddr = provider_buffer_pixmap_hw_addr(buffer->m_bufferInfo);
255     }
256
257     LogD("success to allocate buffer");
258     return buffer->m_bufferAddr;
259 }
260
261 void RenderBuffer::freeCallback(void* data, void *pix)
262 {
263     LogD("enter");
264     RenderBuffer* buffer = static_cast<RenderBuffer*>(data);
265     
266     // destroy buffer
267     if (!provider_buffer_pixmap_is_support_hw(buffer->m_bufferInfo)) {
268         provider_buffer_unref(buffer->m_bufferAddr);
269     } else {
270         provider_buffer_pixmap_destroy_hw(buffer->m_bufferInfo);
271     }
272
273     provider_buffer_release(buffer->m_bufferInfo);
274
275     buffer->m_bufferInfo = NULL;
276     buffer->m_bufferAddr = NULL;
277
278     LogD("success to free buffer");
279     return;
280 }
281
282 Evas_Object *RenderBuffer::getSnapshot(void)
283 {
284     LogD("enter");
285     Evas_Object *snapshot;
286     void *tmpBuffer;
287
288     snapshot = evas_object_image_add(m_canvas);
289     if (!snapshot)
290         return NULL;
291     evas_object_image_data_set(snapshot, NULL);
292     evas_object_image_colorspace_set(snapshot, EVAS_COLORSPACE_ARGB8888);
293     evas_object_image_alpha_set(snapshot, EINA_TRUE);
294     evas_object_image_size_set(snapshot, getWidth(), getHeight());
295  
296     tmpBuffer = malloc(getWidth() * getHeight() * sizeof(int));
297     if (tmpBuffer) {
298         memcpy(tmpBuffer, m_bufferAddr, getWidth() * getHeight() * sizeof(int));
299         evas_data_argb_premul(
300                 static_cast<unsigned int*>(tmpBuffer), 
301                 getWidth() * getHeight());
302         evas_object_image_data_set(snapshot, tmpBuffer);
303     } else {
304         LogD("Failed to allocate heap");
305     }
306
307     evas_object_image_data_update_add(snapshot, 0, 0, getWidth(), getHeight());
308     evas_object_image_fill_set(snapshot, 0, 0, getWidth(), getHeight());
309     evas_object_resize(snapshot, getWidth(), getHeight());
310
311     return snapshot;
312 }