Disable shadow effect on webview scrolling
[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 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    AppBoxRenderView.cpp
18  * @author  Yunchan Cho (yunchan.cho@samsung.com)
19  */
20 #include <string>
21 #include <fstream>
22 #include <streambuf>
23 #include <Eina.h>
24 #include <Evas.h>
25 #include <Ecore.h>
26 #include <ewk_view.h>
27 #include <ewk_context.h>
28 #include <ewk_settings.h>
29 #include <livebox-service.h>
30 #include <i_runnable_widget_object.h>
31 #include <core_module.h>
32 #include <dpl/fast_delegate.h>
33 #include <Core/BoxSchemeHandler.h>
34 #include <Core/View/IRenderView.h>
35 #include <Core/View/IPdHelper.h>
36 #include <Core/View/PdHelper.h>
37 #include <API/web_provider_livebox_info.h>
38 #include <Core/Util/Log.h>
39 #include "AppBoxObserver.h"
40 #include "AppBoxRenderBuffer.h"
41 #include "AppBoxPdHelper.h"
42 #include "AppBoxRenderView.h"
43
44 #define RENDER_MAX_TIME 10.0
45
46 // injection javascript file regarding creating js object used by box and pd
47 static const std::string injectionFile("/usr/share/web-provider/injection.js");
48
49 AppBoxRenderView::AppBoxRenderView(
50         std::string boxId, std::string instanceId,
51         Evas_Object* boxWin, EwkContextPtr ewkContext)
52     : m_appId()
53     , m_boxId(boxId)
54     , m_instanceId(instanceId)
55     , m_boxWin(boxWin)
56     , m_snapshot()
57     , m_renderInfo()
58     , m_boxWrt()
59     , m_boxWrt_isSuspended(false)
60     , m_pdWrt()
61     , m_fireRenderTimer()
62     , m_pdHelper()
63     , m_pdFastOpen(false)
64     , m_ewkContext(ewkContext)
65     , m_renderBuffer()
66 {
67     LogD("enter");
68     m_appId = getAppId(m_boxId);
69     if (m_appId.empty()) {
70         throw; //exception throw!
71     }
72
73     m_renderBuffer = AppBoxObserver::Instance()->getRenderBuffer(m_instanceId);
74     m_pdFastOpen = web_provider_livebox_get_pd_fast_open(m_boxId.c_str()) ? true : false;
75     AppBoxObserver::Instance()->registerRenderView(m_instanceId, this);
76 }
77
78 AppBoxRenderView::~AppBoxRenderView()
79 {
80     LogD("enter");
81     AppBoxObserver::Instance()->unregisterRenderView(m_instanceId);
82 }
83
84 void AppBoxRenderView::showBox(RenderInfoPtr renderInfo)
85 {
86     LogD("enter");
87
88     if (!m_boxWin) {
89         return;
90     }
91
92     // stop updating render buffer
93     m_renderBuffer->stopCanvasUpdate();
94     clearSnapShot();
95
96     // delete already running timer
97     deleteRenderTimer();
98
99     // stop touch timer
100     if (web_provider_livebox_get_mouse_event(m_boxId.c_str())) {
101         m_renderBuffer->deleteTouchTimer();
102     }
103
104     // copy to url
105     std::string boxStartUrl = getStartUrl(URL_TYPE_BOX, renderInfo->defaultUrlParams);
106     if (m_boxWrt) {
107         LogD("existing wrt core is removed");
108         destroyBoxWrtCore();
109     }
110
111     m_boxWrt = createWrtCore(boxStartUrl, m_boxWin, m_ewkContext); 
112     m_boxWrt_isSuspended = false;
113
114     // in case of showing box by request of pd open
115     if (m_pdHelper) {
116         m_pdHelper->setBoxWebView(m_boxWrt->GetCurrentWebview());
117     }
118
119     // resize webview fitted to width, height of Box
120     evas_object_resize(
121             m_boxWrt->GetCurrentWebview(), 
122             renderInfo->width,
123             renderInfo->height);
124
125
126     evas_object_show(m_boxWin);
127     m_boxWrt->Show();
128     m_renderInfo = renderInfo;
129 }
130
131 AppBoxRenderView::WrtCorePtr AppBoxRenderView::createWrtCore(
132         std::string& startUrl, Evas_Object* win, EwkContextPtr ewkContext)
133 {
134     LogD("enter");
135     
136     WrtCorePtr wrt;
137 #ifdef MULTIPROCESS_SERVICE_SUPPORT
138     wrt = WRT::CoreModuleSingleton::
139                 Instance().getRunnableWidgetObject(m_appId, DPL::Optional<unsigned>());
140 #else
141     wrt = WRT::CoreModuleSingleton::
142                 Instance().getRunnableWidgetObject(m_appId);
143 #endif
144     // prepare webview
145     if (startUrl.empty()) {
146         LogD("no start url");
147         return WrtCorePtr();
148     }
149     wrt->PrepareView(startUrl, win, ewkContext.get());
150     wrt->CheckBeforeLaunch();
151
152     // set callback functions of RunnableWidgetObject
153     WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
154     cbs->loadStart = DPL::MakeDelegate(this, &AppBoxRenderView::startLoadCallback);
155     cbs->loadFinish = DPL::MakeDelegate(this, &AppBoxRenderView::finishLoadCallback);
156     cbs->bufferSet = DPL::MakeDelegate(this, &AppBoxRenderView::setBufferCallback);
157     cbs->bufferUnset = DPL::MakeDelegate(this, &AppBoxRenderView::unsetBufferCallback);
158     if (!m_pdFastOpen) {
159         cbs->windowCreateBefore =
160             DPL::MakeDelegate(this, &AppBoxRenderView::createWindowBeforeCallback);
161         cbs->windowCreateAfter =
162             DPL::MakeDelegate(this, &AppBoxRenderView::createWindowAfterCallback);
163     }
164
165     cbs->navigationDecide =
166         DPL::MakeDelegate(this, &AppBoxRenderView::decideNavigationCallback);
167     cbs->webCrash = DPL::MakeDelegate(this, &AppBoxRenderView::crashWebProcessCallback);
168     wrt->SetUserDelegates(cbs);
169
170     // set basic webview setting
171     setWebViewBasicSetting(wrt->GetCurrentWebview());
172     // To know starting point for updating buffer
173     evas_object_smart_callback_add(
174             wrt->GetCurrentWebview(),
175             "load,nonemptylayout,finished",
176             //"frame,rendered", 
177             loadNonEmptyLayoutFinishedCallback,
178             this);
179
180     return wrt;
181 }
182
183 void AppBoxRenderView::destroyBoxWrtCore()
184 {
185     LogD("enter");
186
187     m_renderBuffer->stopCanvasUpdate();
188     deleteRenderTimer();
189     destroyWrtCore(m_boxWrt);
190     m_boxWrt.reset();
191
192     // temp
193     m_boxWrt_isSuspended = false;
194 }
195
196 void AppBoxRenderView::destroyPdWrtCore()
197 {
198     LogD("enter");
199
200     destroyWrtCore(m_pdWrt);
201     m_pdWrt.reset();
202 }
203
204 void AppBoxRenderView::destroyWrtCore(WrtCorePtr wrt)
205 {
206     LogD("enter");
207
208     if (wrt) {
209         wrt->Hide();
210     }
211 }
212
213 void AppBoxRenderView::hideBox()
214 {
215     LogD("enter");
216     destroyBoxWrtCore();
217     if (m_boxWin) {
218         evas_object_hide(m_boxWin);
219         m_boxWin = NULL;
220     }
221 }
222
223 void AppBoxRenderView::pauseBox()
224 {
225     LogD("enter");
226 }
227
228 void AppBoxRenderView::resumeBox()
229 {
230     LogD("enter");
231 }
232
233 void AppBoxRenderView::showPd(Evas_Object* pdWin, RenderInfoPtr renderInfo)
234 {
235     LogD("enter");
236
237     if (!pdWin) {
238         return;
239     }
240
241     // create pd helper
242     std::string pdStartUrl = getStartUrl(URL_TYPE_PD, renderInfo->defaultUrlParams);
243     if (m_pdFastOpen) {
244         destroyPdWrtCore();
245         // if needed, last param regarding ewk context can be set to new one.
246         m_pdWrt = createWrtCore(pdStartUrl, pdWin, m_ewkContext);
247         if (!m_pdWrt) {
248             LogD("no wrt core instance");
249             return;
250         }
251         m_pdHelper = AppBoxPdHelper::create(pdWin);
252
253         // resize webview fitted to width, height of pd
254         evas_object_resize(
255                 m_pdWrt->GetCurrentWebview(), 
256                 renderInfo->width,
257                 renderInfo->height);
258         // show pd
259         m_pdWrt->Show();
260         m_pdHelper->finishOpen(m_pdWrt->GetCurrentWebview());
261     } else {
262         m_pdHelper = PdHelper::create(pdWin, pdStartUrl, renderInfo);
263     }
264
265     // show pd window
266     evas_object_show(pdWin);
267     // set exiting box url query to new one
268     m_renderInfo->defaultUrlParams = renderInfo->defaultUrlParams;
269     showBox(m_renderInfo);
270 }
271
272 void AppBoxRenderView::hidePd()
273 {
274     LogD("enter");
275
276     if (m_pdFastOpen) {
277         destroyPdWrtCore();
278     }
279     m_pdHelper->close();
280     m_pdHelper.reset();
281
282     // stop box webview
283     stopRenderBox();
284 }
285
286 Evas_Object* AppBoxRenderView::getBoxWebView()
287 {
288     if (!m_pdHelper) {
289         return m_boxWrt->GetCurrentWebview();
290     } else {
291         // Here, we can't use GetCurrentWebView() of wrt-core to get Box' webview,
292         // because in the non fast-open, GetCurrentWebview() returns PD's webview.
293         return m_pdHelper->getBoxWebView();
294     }
295 }
296
297 Evas_Object* AppBoxRenderView::getPdWebView()
298 {
299     if (!m_pdHelper) {
300         return NULL;
301     }
302
303     return m_pdHelper->getPdWebView();
304 }
305
306 std::string AppBoxRenderView::getAppId(std::string& boxId)
307 {
308     LogD("enter");
309
310     const char* appId = web_provider_livebox_get_app_id(boxId.c_str());
311     if (!appId) {
312         LogD("no appid of %s", boxId.c_str());
313         return std::string();
314     }
315
316     return std::string(appId);
317 }
318
319 std::string AppBoxRenderView::getStartUrl(UrlType type, std::string& defaultParams)
320 {
321     std::string url;
322     switch (type) {
323     case URL_TYPE_BOX:
324         url = livebox_service_lb_script_path(m_boxId.c_str());
325         break;
326     case URL_TYPE_PD:
327         url = livebox_service_pd_script_path(m_boxId.c_str());
328         break;
329     default:
330         LogD("no available type");
331     }
332
333     // add default parameters to start url
334     url += defaultParams;
335
336     return url;
337 }
338
339 Evas_Object* AppBoxRenderView::getCurrentSnapShot() 
340 {
341     LogD("enter");
342     clearSnapShot();
343     m_snapshot = m_renderBuffer->getSnapshot();
344
345     return m_snapshot;
346 }
347
348 void AppBoxRenderView::clearSnapShot() 
349 {
350     LogD("enter");
351     if (m_snapshot) {
352         evas_object_del(m_snapshot);
353         m_snapshot = NULL;
354     }
355 }
356
357 void AppBoxRenderView::addRenderTimer()
358 {
359     LogD("enter");
360     if (m_fireRenderTimer) {
361         deleteRenderTimer();
362     }
363
364     m_fireRenderTimer = ecore_timer_add(
365                             RENDER_MAX_TIME, 
366                             fireRenderTimerCallback,
367                             this);
368 }
369
370 void AppBoxRenderView::deleteRenderTimer()
371 {
372     LogD("enter");
373     if (m_fireRenderTimer) {
374         ecore_timer_del(m_fireRenderTimer);
375         m_fireRenderTimer = NULL;
376     }
377 }
378
379 void AppBoxRenderView::stopRenderBox()
380 {
381     deleteRenderTimer();
382     m_renderBuffer->stopCanvasUpdate();
383     if (web_provider_livebox_get_mouse_event(m_boxId.c_str())) {
384         // stop touch timer
385         m_renderBuffer->deleteTouchTimer();
386
387         // temp condition
388         if (m_boxWrt_isSuspended == false)
389         {
390             m_boxWrt_isSuspended = true;
391             m_boxWrt->Suspend();
392         }
393     } else {
394         // Before webview should be removed,
395         // new evas object with last render data should be created
396         // otherwise, after webview is removed, box is white screen.
397         evas_object_show(getCurrentSnapShot());
398         destroyBoxWrtCore();
399     }
400 }
401
402 void AppBoxRenderView::setWebViewBasicSetting(Evas_Object* webview)
403 {
404     LogD("enter");
405
406     if (!webview) {
407         return;
408     }
409     Ewk_Settings* setting = ewk_view_settings_get(webview);
410     // disable shadow effect on scrolling
411     ewk_settings_edge_effect_enabled_set(setting, EINA_FALSE);
412     // To support transparent background
413     evas_object_color_set(webview, 0, 0, 0, 0);
414     ewk_view_visibility_set(webview, EINA_TRUE);
415 }
416
417 Eina_Bool AppBoxRenderView::fireRenderTimerCallback(void* data)
418 {
419     LogD("enter");
420
421     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
422     This->m_fireRenderTimer = NULL;
423     This->stopRenderBox();
424
425     return ECORE_CALLBACK_CANCEL;
426 }
427
428 Eina_Bool AppBoxRenderView::openPdIdlerCallback(void* data)
429 {
430     LogD("enter");
431     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
432     if (This && This->m_pdHelper) {
433         This->m_pdHelper->startOpen();
434     }
435     return ECORE_CALLBACK_CANCEL;
436 }
437
438 void AppBoxRenderView::executeScriptCallback(
439         Evas_Object* webview, const char* result, void* data)
440 {
441     LogD("enter");
442     std::string resultStr(result ? result : "null");
443     LogD("result: %s", resultStr.c_str());
444 }
445
446 void AppBoxRenderView::startLoadCallback(Evas_Object* webview)
447 {
448     LogD("enter");
449     // execute injection for creating js objects
450     std::ifstream jsFile(injectionFile);
451     std::string script((std::istreambuf_iterator<char>(jsFile)),
452                         std::istreambuf_iterator<char>());
453
454     LogD("injected js code: %s", script.c_str());
455     ewk_view_script_execute(webview, script.c_str(), executeScriptCallback, this);
456 }
457
458 void AppBoxRenderView::finishLoadCallback(Evas_Object* webview)
459 {
460     LogD("enter");
461     ewk_view_visibility_set(webview, EINA_TRUE);
462
463     if (!m_pdHelper) {
464         // start render timer
465         addRenderTimer();
466     } else {
467         if (!m_pdFastOpen) {
468             if (!(m_pdHelper->isPdOpened()) && 
469                     webview == m_pdHelper->getBoxWebView())
470             {
471                 // open pd
472                 ecore_idler_add(openPdIdlerCallback, this);
473             }
474         }
475     }
476 }
477
478 void AppBoxRenderView::createWindowBeforeCallback(Evas** canvas, Evas_Object* parent)
479 {
480     LogD("enter");
481
482     if (m_pdHelper) {
483         if (!(m_pdHelper->isPdOpened()) && 
484                 parent == m_pdHelper->getBoxWebView())
485         {
486             LogD("pd canvas is used");
487             *canvas = m_pdHelper->getPdCanvas();
488             return;
489         }
490     }
491     
492     LogD("canvas of this webview is used");
493     *canvas = evas_object_evas_get(parent);
494 }
495
496 void AppBoxRenderView::createWindowAfterCallback(Evas_Object* parent, Evas_Object* child)
497 {
498     LogD("enter");
499
500     if (m_pdHelper) {
501         Evas* parentCanvas = evas_object_evas_get(parent);
502         Evas* childCanvas = evas_object_evas_get(child);
503
504         if (parentCanvas != childCanvas) {
505            // wrt-core change visibility value to false internally
506            // So plugin should reset this value to true for painting parent webview
507            ewk_view_visibility_set(parent, EINA_TRUE);
508            evas_object_show(parent);
509            m_pdHelper->finishOpen(child); 
510         }
511     }
512
513     setWebViewBasicSetting(child);
514     evas_object_show(child);
515 }
516
517 void AppBoxRenderView::setBufferCallback(Evas_Object* webview)
518 {
519     LogD("enter");
520     evas_object_show(webview);
521     evas_object_focus_set(webview, EINA_TRUE);
522 }
523
524 void AppBoxRenderView::unsetBufferCallback(Evas_Object* webview)
525 {
526     LogD("enter");
527     evas_object_hide(webview);
528 }
529
530 void AppBoxRenderView::decideNavigationCallback(Evas_Object* webview, std::string& uri)
531 {
532     LogD("enter");
533
534     // navigation of box scheme should be ignored
535     if(BoxSchemeHandler::Instance()->isBoxScheme(uri)) {
536         LogD("box scheme");
537         BoxSchemeHandler::Instance()->process(m_instanceId, uri);
538     }
539 }
540
541 void AppBoxRenderView::crashWebProcessCallback()
542 {
543     LogD("enter");
544     ewk_shutdown();
545     elm_exit();
546 }
547
548 void AppBoxRenderView::loadNonEmptyLayoutFinishedCallback(
549         void* data, Evas_Object* webview, void* eventInfo)
550 {
551     LogD("enter");
552
553     // start to update render buffer!
554     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
555     This->m_renderBuffer->startCanvasUpdate();
556 }