Resolve the problem for box not to be displayed sometime on opening PD
[platform/framework/web/web-provider.git] / src / Plugin / AppBoxPlugin / AppBoxRenderView.cpp
1 /*
2  * Copyright (c) 2013 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    AppBoxRenderView.cpp
18  * @author  Yunchan Cho (yunchan.cho@samsung.com)
19  */
20 #include <string>
21 #include <Eina.h>
22 #include <Evas.h>
23 #include <Ecore.h>
24 #include <livebox-service.h>
25 #include <i_runnable_widget_object.h>
26 #include <core_module.h>
27 #include <dpl/fast_delegate.h>
28 #include <Core/View/IRenderView.h>
29 #include <Core/View/IPdHelper.h>
30 #include <Core/View/PdHelper.h>
31 #include <Core/Util/Log.h>
32 #include "AppBoxObserver.h"
33 #include "AppBoxRenderBuffer.h"
34 #include "AppBoxRenderView.h"
35
36 #define RENDER_MAX_TIME 10.0
37
38 AppBoxRenderView::AppBoxRenderView(
39         std::string boxId, std::string instanceId,
40         Evas_Object* boxWin, EwkContextPtr ewkContext)
41     : m_appId()
42     , m_boxId(boxId)
43     , m_instanceId(instanceId)
44     , m_boxWin(boxWin)
45     , m_baseWebView()
46     , m_snapshot()
47     , m_renderInfo()
48     , m_view()
49     , m_startUrl()
50     , m_fireRenderTimer()
51     , m_pdHelper()
52     , m_ewkContext(ewkContext)
53 {
54     LogD("enter");
55     m_appId = getAppId(m_boxId);
56     if (m_appId.empty()) {
57         throw; //exception throw!
58     }
59
60     evas_object_show(m_boxWin);
61     m_renderBuffer = AppBoxObserver::Instance()->getRenderBuffer(m_instanceId);
62     AppBoxObserver::Instance()->registerRenderView(m_instanceId, this);
63 }
64
65 AppBoxRenderView::~AppBoxRenderView()
66 {
67     LogD("enter");
68     evas_object_hide(m_boxWin);
69     AppBoxObserver::Instance()->unregisterRenderView(m_instanceId);
70 }
71
72 void AppBoxRenderView::showBox(RenderInfoPtr renderInfo)
73 {
74     LogD("enter");
75
76     // delete already running timer
77     deleteRenderTimer();
78
79     // stop touch timer
80     if (livebox_service_mouse_event(m_boxId.c_str())) {
81         m_renderBuffer->deleteTouchTimer();
82     }
83
84     // copy to url
85     m_startUrl = getStartUrl(URL_TYPE_BOX, renderInfo->defaultUrlParams);
86
87     if (!createView()) {
88         LogD("can't create view instance");
89         return;
90     }
91
92     // in case of showing box by request of pd open
93     if (m_pdHelper) {
94         m_pdHelper->setBaseWebView(m_baseWebView);
95     }
96
97     // resize webview fitted to width, height of Box
98     evas_object_resize(
99             m_baseWebView, 
100             renderInfo->width,
101             renderInfo->height);
102
103     clearSnapShot();
104     m_renderBuffer->startCanvasUpdate();
105     m_view->Show();
106     m_renderInfo = renderInfo;
107 }
108
109 bool AppBoxRenderView::createView()
110 {
111     LogD("enter");
112     
113     if (m_view) {
114         m_view->Hide();
115         m_view.reset();
116         m_baseWebView = NULL;
117     }
118
119     m_view = WRT::CoreModuleSingleton::
120                 Instance().getRunnableWidgetObject(m_appId);
121
122     // prepare webview
123     if (m_startUrl.empty()) {
124         LogD("no start url");
125         return false;
126     }
127     m_view->PrepareView(m_startUrl, m_boxWin, m_ewkContext.get());
128     m_view->CheckBeforeLaunch();
129
130     // set callback functions of RunnableWidgetObject
131     WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
132     cbs->loadStart = DPL::MakeDelegate(this, &AppBoxRenderView::startLoadCallback);
133     cbs->loadFinish = DPL::MakeDelegate(this, &AppBoxRenderView::finishLoadCallback);
134     cbs->bufferSet = DPL::MakeDelegate(this, &AppBoxRenderView::setBufferCallback);
135     cbs->bufferUnset = DPL::MakeDelegate(this, &AppBoxRenderView::unsetBufferCallback);
136     cbs->windowCreateBefore = DPL::MakeDelegate(this, &AppBoxRenderView::createWindowBeforeCallback);
137     cbs->windowCreateAfter = DPL::MakeDelegate(this, &AppBoxRenderView::createWindowAfterCallback);
138     m_view->SetUserDelegates(cbs);
139
140     // set base webview
141     m_baseWebView = m_view->GetCurrentWebview();
142
143     // To support transparent background
144     evas_object_color_set(m_baseWebView, 0, 0, 0, 0);
145     evas_object_layer_set(m_baseWebView, EVAS_LAYER_MAX);
146     return true;
147 }
148
149 bool AppBoxRenderView::destroyView()
150 {
151     LogD("enter");
152
153     m_renderBuffer->stopCanvasUpdate();
154     ecore_idler_add(destroyViewIdlerCallback, this);
155     return true;
156 }
157
158 void AppBoxRenderView::hideBox()
159 {
160     LogD("enter");
161     destroyView();
162 }
163
164 void AppBoxRenderView::pauseBox()
165 {
166     LogD("enter");
167 }
168
169 void AppBoxRenderView::resumeBox()
170 {
171     LogD("enter");
172 }
173
174 void AppBoxRenderView::showPd(Evas_Object* pdWin, RenderInfoPtr renderInfo)
175 {
176     LogD("enter");
177
178     // create pd helper
179     std::string pdStartUrl = getStartUrl(URL_TYPE_PD, renderInfo->defaultUrlParams);
180     m_pdHelper = PdHelper::create(pdWin, pdStartUrl, renderInfo);
181
182     // show pd window
183     evas_object_show(pdWin);
184     showBox(m_renderInfo);
185 }
186
187 void AppBoxRenderView::hidePd()
188 {
189     LogD("enter");
190
191     m_pdHelper->close();
192     m_pdHelper.reset();
193
194     // destory box webview to stop rendering
195     evas_object_show(getCurrentSnapShot());
196     destroyView();
197 }
198
199 std::string AppBoxRenderView::getAppId(std::string& boxId)
200 {
201     // TODO more exact and safe parsing is needed
202     std::string temp = std::string(boxId);
203     int found = temp.find_last_of(".");
204     if (found == std::string::npos) {
205         return std::string();
206     }
207
208     temp.assign(temp, 0, found);
209     return temp;
210 }
211
212 std::string AppBoxRenderView::getStartUrl(UrlType type, std::string& defaultParams)
213 {
214     std::string url;
215     switch (type) {
216     case URL_TYPE_BOX:
217         url = livebox_service_lb_script_path(m_boxId.c_str());
218         break;
219     case URL_TYPE_PD:
220         url = livebox_service_pd_script_path(m_boxId.c_str());
221         break;
222     default:
223         LogD("no available type");
224     }
225
226     // add default parameters to start url
227     url += defaultParams;
228
229     return url;
230 }
231
232 Evas_Object* AppBoxRenderView::getCurrentSnapShot() 
233 {
234     LogD("enter");
235     clearSnapShot();
236     m_snapshot = m_renderBuffer->getSnapshot();
237     //evas_object_layer_set(m_snapshot, EVAS_LAYER_MAX);
238
239     return m_snapshot;
240 }
241
242 void AppBoxRenderView::clearSnapShot() 
243 {
244     LogD("enter");
245     if (m_snapshot) {
246         evas_object_layer_set(m_snapshot, EVAS_LAYER_MIN);
247         //evas_object_hide(m_snapshot);
248         evas_object_del(m_snapshot);
249         m_snapshot = NULL;
250     }
251 }
252
253 void AppBoxRenderView::addRenderTimer()
254 {
255     LogD("enter");
256     if (m_fireRenderTimer) {
257         deleteRenderTimer();
258     }
259
260     m_fireRenderTimer = ecore_timer_add(
261                             RENDER_MAX_TIME, 
262                             fireRenderTimerCallback,
263                             this);
264 }
265
266 void AppBoxRenderView::deleteRenderTimer()
267 {
268     LogD("enter");
269     if (m_fireRenderTimer) {
270         ecore_timer_del(m_fireRenderTimer);
271         m_fireRenderTimer = NULL;
272     }
273 }
274
275 Eina_Bool AppBoxRenderView::fireRenderTimerCallback(void* data)
276 {
277     LogD("enter");
278
279     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
280     This->m_fireRenderTimer = NULL;
281
282     This->m_renderBuffer->stopCanvasUpdate();
283     if (livebox_service_mouse_event(This->m_boxId.c_str())) {
284         // stop touch timer
285         This->m_renderBuffer->deleteTouchTimer();
286         This->m_view->Suspend();
287     } else {
288         // Before webview should be removed,
289         // new evas object with last render data should be created
290         // otherwise, after webview is removed, box is white screen.
291         evas_object_show(This->getCurrentSnapShot());
292         ecore_idler_add(destroyViewIdlerCallback, This);
293     }
294
295     return ECORE_CALLBACK_CANCEL;
296 }
297
298 Eina_Bool AppBoxRenderView::destroyViewIdlerCallback(void* data)
299 {
300     LogD("enter");
301
302     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
303     if (This->m_view) {
304         This->m_view->Hide();
305         This->m_view.reset();
306         This->m_baseWebView = NULL;
307     }
308
309     return ECORE_CALLBACK_CANCEL;
310 }
311
312 Eina_Bool AppBoxRenderView::openPdIdlerCallback(void* data)
313 {
314     LogD("enter");
315     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
316     if (This && This->m_pdHelper) {
317         This->m_pdHelper->startOpen();
318     }
319     return ECORE_CALLBACK_CANCEL;
320 }
321
322
323 void AppBoxRenderView::startLoadCallback(Evas_Object* webview)
324 {
325     // start load
326 }
327
328 void AppBoxRenderView::finishLoadCallback(Evas_Object* webview)
329 {
330     LogD("enter");
331     ewk_view_visibility_set(webview, EINA_TRUE);
332
333     if (!m_pdHelper) {
334         // start render timer
335         addRenderTimer();
336     } else {
337         if (!(m_pdHelper->isPdOpened()) && 
338                 webview == m_pdHelper->getBaseWebView())
339         {
340             // open pd
341             ecore_idler_add(openPdIdlerCallback, this);
342         }
343     }
344 }
345
346 void AppBoxRenderView::createWindowBeforeCallback(Evas** canvas, Evas_Object* parent)
347 {
348     LogD("enter");
349
350     if (m_pdHelper) {
351         if (!(m_pdHelper->isPdOpened()) && 
352                 parent == m_pdHelper->getBaseWebView())
353         {
354             LogD("pd canvas is used");
355             *canvas = m_pdHelper->getPdCanvas();
356             return;
357         }
358     } 
359     
360     LogD("canvas of this webview is used");
361     *canvas = evas_object_evas_get(parent);
362 }
363
364 void AppBoxRenderView::createWindowAfterCallback(Evas_Object* parent, Evas_Object* child)
365 {
366     LogD("enter");
367
368     // To support transparent background
369     evas_object_color_set(child, 0, 0, 0, 0);
370
371     if (m_pdHelper) {
372         Evas* parentCanvas = evas_object_evas_get(parent);
373         Evas* childCanvas = evas_object_evas_get(child);
374
375         if (parentCanvas != childCanvas) {
376            evas_object_show(parent);
377            m_pdHelper->finishOpen(child); 
378         }
379     }
380
381     evas_object_show(child);
382 }
383
384 void AppBoxRenderView::setBufferCallback(Evas_Object* webview)
385 {
386     LogD("enter");
387     evas_object_show(webview);
388     evas_object_focus_set(webview, EINA_TRUE);
389 }
390
391 void AppBoxRenderView::unsetBufferCallback(Evas_Object* webview)
392 {
393     LogD("enter");
394     evas_object_hide(webview);
395 }