Fix various build warnings
[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 <EWebKit2.h>
27 #include <ewk_view.h>
28 #include <ewk_context.h>
29 #include <ewk_settings.h>
30 #include <livebox-service.h>
31 #include <i_runnable_widget_object.h>
32 #include <core_module.h>
33 #include <dpl/fast_delegate.h>
34 #include <Core/BoxSchemeHandler.h>
35 #include <Core/View/IRenderView.h>
36 #include <Core/View/IPdHelper.h>
37 #include <Core/View/PdHelper.h>
38 #include <API/web_provider_livebox_info.h>
39 #include <Core/Util/Log.h>
40 #include <Core/Util/Util.h>
41 #include "AppBoxObserver.h"
42 #include "AppBoxRenderBuffer.h"
43 #include "AppBoxPdHelper.h"
44 #include "AppBoxRenderView.h"
45
46 #define RENDER_MAX_TIME 30.0
47 #define SNAPSHOT_REMOVE_TIME 1.0
48 #define WEB_DBOX_OBJ_MOVE_TO_OUTSIDE_POINT_VALUE -10000
49
50 // injection javascript file regarding creating js object used by box and pd
51 static const std::string injectionFile("/usr/share/web-provider/injection.js");
52
53 AppBoxRenderView::AppBoxRenderView(
54         std::string boxId, std::string instanceId,
55         EwkContextPtr ewkContext)
56     : m_appId()
57     , m_boxId(boxId)
58     , m_instanceId(instanceId)
59     , m_ewkContext(ewkContext)
60     , m_boxRenderInfo()
61     , m_boxWrt()
62     , m_pdWrt()
63     , m_snapshot()
64     , m_fireRenderTimer()
65     , m_removeSnapShotTimer()
66     , m_pdHelper()
67     , m_boxRenderBuffer()
68     , m_pdFastOpen(false)
69     , m_boxFinishLoad(false)
70     , m_boxFrameRendered(false)
71     , m_boxWrt_isSuspended(false)
72 {
73     LogD("enter");
74     m_appId = getAppId(m_boxId);
75     if (m_appId.empty()) {
76         throw; //exception throw!
77     }
78
79     m_boxRenderBuffer = AppBoxObserver::Instance()->getRenderBuffer(m_instanceId);
80
81     // use fastopen to default
82     // m_pdFastOpen = web_provider_livebox_get_pd_fast_open(m_boxId.c_str()) ? true : false;
83     m_pdFastOpen = true;
84     AppBoxObserver::Instance()->registerRenderView(m_instanceId, this);
85 }
86
87 AppBoxRenderView::~AppBoxRenderView()
88 {
89     LogD("enter");
90     AppBoxObserver::Instance()->unregisterRenderView(m_instanceId);
91 }
92
93 void AppBoxRenderView::showBox(RenderInfoPtr boxRenderInfo)
94 {
95     LogD("enter");
96
97     // stop updating render buffer
98     m_boxRenderBuffer->stopCanvasUpdate();
99
100     // clear snapshot if this is not the case of pd open
101     if (!m_pdHelper) {
102         clearSnapShot();
103     }
104
105     // delete already running timer
106     deleteTimer(&m_fireRenderTimer);
107
108     // delete touch timer
109     if (web_provider_livebox_get_mouse_event(m_boxId.c_str())) {
110         m_boxRenderBuffer->deleteTouchTimer();
111     }
112
113     // set boxFinishLoad and m_boxFrameRendered to false
114     m_boxFinishLoad = false;
115     m_boxFrameRendered = false;
116
117     // copy to url
118     std::string boxStartUrl = getStartUrl(URL_TYPE_BOX, boxRenderInfo->defaultUrlParams);
119     if (m_boxWrt) {
120         LogD("existing wrt core is removed");
121         destroyBoxWrtCore();
122     }
123
124     m_boxWrt = createWrtCore(
125                 URL_TYPE_BOX, boxStartUrl,
126                 boxRenderInfo->window, m_ewkContext);
127     m_boxWrt_isSuspended = false;
128
129     // in case of showing box by request of pd open
130     if (m_pdHelper) {
131         m_pdHelper->setBoxWebView(m_boxWrt->GetCurrentWebview());
132     }
133
134     // resize webview fitted to width, height of Box
135     evas_object_resize(
136             m_boxWrt->GetCurrentWebview(),
137             boxRenderInfo->width,
138             boxRenderInfo->height);
139
140
141     evas_object_show(m_boxWrt->GetCurrentWebview());
142     // webview window move to outside of viewport because of overlap issue with snapshot image
143     evas_object_move(m_boxWrt->GetCurrentWebview(), WEB_DBOX_OBJ_MOVE_TO_OUTSIDE_POINT_VALUE, WEB_DBOX_OBJ_MOVE_TO_OUTSIDE_POINT_VALUE);
144
145     m_boxWrt->Show();
146     m_boxRenderInfo = boxRenderInfo;
147 }
148
149 AppBoxRenderView::WrtCorePtr AppBoxRenderView::createWrtCore(
150         UrlType type, std::string& startUrl,
151         Evas_Object* win, EwkContextPtr ewkContext)
152 {
153     LogD("enter");
154
155     WrtCorePtr wrt;
156     wrt = WRT::CoreModuleSingleton::
157                 Instance().getRunnableWidgetObject(m_appId);
158     // prepare webview
159     if (startUrl.empty()) {
160         LogD("no start url");
161         return WrtCorePtr();
162     }
163     wrt->PrepareView(startUrl, win, ewkContext.get());
164     wrt->CheckBeforeLaunch();
165
166     // set callback functions of RunnableWidgetObject
167     WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
168     cbs->loadStart = DPL::MakeDelegate(this, &AppBoxRenderView::startLoadCallback);
169     if (type == URL_TYPE_BOX) {
170         cbs->loadFinish = DPL::MakeDelegate(this, &AppBoxRenderView::finishBoxLoadCallback);
171     } else {
172         cbs->loadFinish = DPL::MakeDelegate(this, &AppBoxRenderView::finishPdLoadCallback);
173     }
174
175     cbs->bufferSet = DPL::MakeDelegate(this, &AppBoxRenderView::setBufferCallback);
176     cbs->bufferUnset = DPL::MakeDelegate(this, &AppBoxRenderView::unsetBufferCallback);
177     if (!m_pdFastOpen) {
178         cbs->windowCreateBefore =
179             DPL::MakeDelegate(this, &AppBoxRenderView::createWindowBeforeCallback);
180         cbs->windowCreateAfter =
181             DPL::MakeDelegate(this, &AppBoxRenderView::createWindowAfterCallback);
182     }
183
184     cbs->navigationDecide =
185         DPL::MakeDelegate(this, &AppBoxRenderView::decideNavigationCallback);
186     cbs->webCrash = DPL::MakeDelegate(this, &AppBoxRenderView::crashWebProcessCallback);
187     wrt->SetUserDelegates(cbs);
188
189     // set basic webview setting
190     setWebViewBasicSetting(wrt->GetCurrentWebview());
191     return wrt;
192 }
193
194 void AppBoxRenderView::destroyBoxWrtCore()
195 {
196     LogD("enter");
197
198     m_boxRenderBuffer->stopCanvasUpdate();
199     deleteTimer(&m_fireRenderTimer);
200     deleteTimer(&m_removeSnapShotTimer);
201     destroyWrtCore(m_boxWrt);
202     m_boxWrt.reset();
203
204     // temp
205     m_boxWrt_isSuspended = false;
206 }
207
208 void AppBoxRenderView::destroyPdWrtCore()
209 {
210     LogD("enter");
211
212     destroyWrtCore(m_pdWrt);
213     m_pdWrt.reset();
214 }
215
216 void AppBoxRenderView::destroyWrtCore(WrtCorePtr wrt)
217 {
218     LogD("enter");
219
220     if (wrt) {
221         wrt->Hide();
222     }
223 }
224
225 void AppBoxRenderView::hideBox()
226 {
227     LogD("enter");
228     destroyBoxWrtCore();
229     if (m_boxRenderInfo->window) {
230         evas_object_hide(m_boxRenderInfo->window);
231     }
232 }
233
234 void AppBoxRenderView::pauseBox()
235 {
236     LogD("enter");
237 }
238
239 void AppBoxRenderView::resumeBox()
240 {
241     LogD("enter");
242 }
243
244 void AppBoxRenderView::showPd(RenderInfoPtr pdRenderInfo, RenderInfoPtr boxRenderInfo)
245 {
246     LogD("enter");
247
248     std::string pdStartUrl = getStartUrl(URL_TYPE_PD, pdRenderInfo->defaultUrlParams);
249     if (m_pdFastOpen) {
250         destroyPdWrtCore();
251         // if you want to launch new Web Process for PD, use the following line.
252         // EwkContextPtr pdContext = AppBoxObserver::Instance()->getPdEwkContext();
253         m_pdWrt = createWrtCore(URL_TYPE_PD, pdStartUrl, pdRenderInfo->window, m_ewkContext);
254         if (!m_pdWrt) {
255             LogD("no wrt core instance");
256             return;
257         }
258         m_pdHelper = AppBoxPdHelper::create(pdRenderInfo->window);
259
260         // resize webview fitted to width, height of pd
261         evas_object_resize(
262                 m_pdWrt->GetCurrentWebview(),
263                 pdRenderInfo->width,
264                 pdRenderInfo->height);
265         // show pd
266         m_pdWrt->Show();
267         m_pdHelper->finishOpen(m_pdWrt->GetCurrentWebview());
268     } else {
269         m_pdHelper = PdHelper::create(pdRenderInfo, pdStartUrl);
270     }
271
272     // show pd window
273     evas_object_show(pdRenderInfo->window);
274
275     // need to  create new snapshot when m_napshot is empty
276     if (!m_snapshot) {
277         evas_object_show(getCurrentSnapShot());
278     }
279
280     // show box
281     showBox(boxRenderInfo);
282
283     // start timer for clearing existing snapshot in case of only pd open
284     addTimer(&m_removeSnapShotTimer, SNAPSHOT_REMOVE_TIME, removeSnapShotTimerCallback);
285
286 }
287
288 void AppBoxRenderView::hidePd()
289 {
290     LogD("enter");
291
292     if (m_pdFastOpen) {
293         destroyPdWrtCore();
294     }
295     m_pdHelper->close();
296     m_pdHelper.reset();
297 }
298
299 Evas_Object* AppBoxRenderView::getBoxWebView()
300 {
301     if (!m_pdHelper) {
302         return m_boxWrt->GetCurrentWebview();
303     } else {
304         // Here, we can't use GetCurrentWebView() of wrt-core to get Box' webview,
305         // because in the non fast-open, GetCurrentWebview() returns PD's webview.
306         return m_pdHelper->getBoxWebView();
307     }
308 }
309
310 Evas_Object* AppBoxRenderView::getPdWebView()
311 {
312     if (!m_pdHelper) {
313         return NULL;
314     }
315
316     return m_pdHelper->getPdWebView();
317 }
318
319 std::string AppBoxRenderView::getAppId(std::string& boxId)
320 {
321     LogD("enter");
322
323     const char* appId = web_provider_livebox_get_app_id(boxId.c_str());
324     if (!appId) {
325         LogD("no appid of %s", boxId.c_str());
326         return std::string();
327     }
328
329     return std::string(appId);
330 }
331
332 std::string AppBoxRenderView::getStartUrl(UrlType type, std::string& defaultParams)
333 {
334     std::string url;
335     switch (type) {
336     case URL_TYPE_BOX:
337         url = livebox_service_lb_script_path(m_boxId.c_str());
338         break;
339     case URL_TYPE_PD:
340         url = livebox_service_pd_script_path(m_boxId.c_str());
341         break;
342     default:
343         LogD("no available type");
344     }
345
346     // add default parameters to start url
347     url += defaultParams;
348
349     return url;
350 }
351
352 Evas_Object* AppBoxRenderView::getCurrentSnapShot()
353 {
354     LogD("enter");
355     clearSnapShot();
356     m_snapshot = m_boxRenderBuffer->getSnapshot();
357
358     return m_snapshot;
359 }
360
361 void AppBoxRenderView::clearSnapShot()
362 {
363     LogD("enter");
364     if (m_snapshot) {
365         evas_object_del(m_snapshot);
366         m_snapshot = NULL;
367     }
368 }
369
370 void AppBoxRenderView::showSnapShot()
371 {
372     LogD("enter");
373     if (m_snapshot) {
374         evas_object_raise(m_snapshot);
375         evas_object_show(m_snapshot);
376     }
377 }
378
379 void AppBoxRenderView::hideSnapShot()
380 {
381     LogD("enter");
382     if (m_snapshot) {
383         evas_object_hide(m_snapshot);
384         evas_object_lower(m_snapshot);
385     }
386 }
387
388 void AppBoxRenderView::addTimer(Ecore_Timer** timer, double interval, Ecore_Task_Cb callback)
389 {
390     LogD("enter");
391     if (*timer) {
392         deleteTimer(timer);
393     }
394
395     *timer = ecore_timer_add(interval, callback, this);
396 }
397
398 void AppBoxRenderView::deleteTimer(Ecore_Timer** timer)
399 {
400     LogD("enter");
401     if (*timer) {
402         ecore_timer_del(*timer);
403         *timer = NULL;
404     }
405 }
406
407 void AppBoxRenderView::stopRenderBox()
408 {
409     deleteTimer(&m_fireRenderTimer);
410     m_boxRenderBuffer->stopCanvasUpdate();
411     if (web_provider_livebox_get_mouse_event(m_boxId.c_str())) {
412         // stop touch timer
413         m_boxRenderBuffer->deleteTouchTimer();
414
415         // temp condition
416         if (m_boxWrt_isSuspended == false)
417         {
418             m_boxWrt_isSuspended = true;
419             m_boxWrt->Suspend();
420         }
421     } else {
422         // Before webview should be removed,
423         // new evas object with last render data should be created
424         // otherwise, after webview is removed, box is white screen.
425         evas_object_show(getCurrentSnapShot());
426         destroyBoxWrtCore();
427     }
428 }
429
430 void AppBoxRenderView::setWebViewBasicSetting(Evas_Object* webview)
431 {
432     LogD("enter");
433
434     if (!webview) {
435         return;
436     }
437     Ewk_Settings* setting = ewk_view_settings_get(webview);
438     // To support transparent background
439     evas_object_color_set(webview, 0, 0, 0, 1);
440     ewk_view_visibility_set(webview, EINA_TRUE);
441
442     // To know starting point for updating buffer
443     evas_object_smart_callback_add(
444             webview,
445             "load,nonemptylayout,finished",
446             loadNonEmptyLayoutFinishedCallback,
447             this);
448     evas_object_smart_callback_add(
449             webview,
450             "frame,rendered",
451             frameRenderedCallback,
452             this);
453     // To set font type whenever font changed
454     ewk_view_use_settings_font(webview);
455 }
456
457 Eina_Bool AppBoxRenderView::fireRenderTimerCallback(void* data)
458 {
459     LogD("enter");
460
461     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
462     This->m_fireRenderTimer = NULL;
463     This->stopRenderBox();
464
465     return ECORE_CALLBACK_CANCEL;
466 }
467
468 Eina_Bool AppBoxRenderView::removeSnapShotTimerCallback(void* data)
469 {
470     LogD("enter");
471
472     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
473     if (!(This->m_boxFinishLoad && This->m_boxFrameRendered)) {
474         return ECORE_CALLBACK_RENEW;
475     }
476
477     // hide snapshot because valid frame has been prepared generally.
478     This->clearSnapShot();
479
480     // move to inside of viewport to prevent overlap with snapshot image
481     evas_object_move(This->m_boxWrt->GetCurrentWebview(), 0, 0);
482     evas_object_show(This->m_boxWrt->GetCurrentWebview());
483
484     This->m_removeSnapShotTimer = NULL;
485     return ECORE_CALLBACK_CANCEL;
486 }
487
488 Eina_Bool AppBoxRenderView::openPdIdlerCallback(void* data)
489 {
490     LogD("enter");
491     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
492     if (This && This->m_pdHelper) {
493         This->m_pdHelper->startOpen();
494     }
495     return ECORE_CALLBACK_CANCEL;
496 }
497
498 void AppBoxRenderView::executeScriptCallback(
499         Evas_Object* webview, const char* result, void* data)
500 {
501     LogD("enter");
502     UNUSED_PARAM(webview);
503     UNUSED_PARAM(data);
504
505     std::string resultStr(result ? result : "null");
506     LogD("result: %s", resultStr.c_str());
507 }
508
509 void AppBoxRenderView::startLoadCallback(Evas_Object* webview)
510 {
511     LogD("enter");
512     if(!webview) {
513         return;
514     }
515     // execute injection for creating js objects
516     std::ifstream jsFile(injectionFile);
517     std::string script((std::istreambuf_iterator<char>(jsFile)),
518                         std::istreambuf_iterator<char>());
519
520     LogD("injected js code: %s", script.c_str());
521     ewk_view_script_execute(webview, script.c_str(), executeScriptCallback, this);
522 }
523
524 void AppBoxRenderView::finishBoxLoadCallback(Evas_Object* webview)
525 {
526     LogD("enter");
527     if (!webview) {
528         return;
529     }
530
531     ewk_view_visibility_set(webview, EINA_TRUE);
532
533     if (!m_pdHelper) {
534         // start render timer
535         addTimer(&m_fireRenderTimer, RENDER_MAX_TIME, fireRenderTimerCallback);
536     } else {
537         if (!m_pdFastOpen) {
538             if (!(m_pdHelper->isPdOpened()) &&
539                     webview == m_pdHelper->getBoxWebView())
540             {
541                 // open pd
542                 ecore_idler_add(openPdIdlerCallback, this);
543             }
544         }
545     }
546
547     // set flag
548     m_boxFinishLoad = true;
549 }
550
551 void AppBoxRenderView::finishPdLoadCallback(Evas_Object* webview)
552 {
553     LogD("enter");
554     if (!webview) {
555         return;
556     }
557
558     ewk_view_visibility_set(webview, EINA_TRUE);
559 }
560
561 void AppBoxRenderView::createWindowBeforeCallback(Evas** canvas, Evas_Object* parent)
562 {
563     LogD("enter");
564
565     if (m_pdHelper) {
566         if (!(m_pdHelper->isPdOpened()) &&
567                 parent == m_pdHelper->getBoxWebView())
568         {
569             LogD("pd canvas is used");
570             *canvas = m_pdHelper->getPdCanvas();
571             return;
572         }
573     }
574
575     LogD("canvas of this webview is used");
576     *canvas = evas_object_evas_get(parent);
577 }
578
579 void AppBoxRenderView::createWindowAfterCallback(Evas_Object* parent, Evas_Object* child)
580 {
581     LogD("enter");
582     if (!parent) {
583         return;
584     }
585
586     if (m_pdHelper) {
587         Evas* parentCanvas = evas_object_evas_get(parent);
588         Evas* childCanvas = evas_object_evas_get(child);
589
590         if (parentCanvas != childCanvas) {
591            // wrt-core change visibility value to false internally
592            // So plugin should reset this value to true for painting parent webview
593            ewk_view_visibility_set(parent, EINA_TRUE);
594            evas_object_show(parent);
595            m_pdHelper->finishOpen(child);
596         }
597     }
598
599     setWebViewBasicSetting(child);
600     evas_object_show(child);
601 }
602
603 void AppBoxRenderView::setBufferCallback(Evas_Object* webview)
604 {
605     LogD("enter");
606     evas_object_show(webview);
607     evas_object_focus_set(webview, EINA_TRUE);
608 }
609
610 void AppBoxRenderView::unsetBufferCallback(Evas_Object* webview)
611 {
612     LogD("enter");
613     evas_object_hide(webview);
614 }
615
616 void AppBoxRenderView::decideNavigationCallback(Evas_Object* webview, std::string& uri)
617 {
618     LogD("enter");
619     UNUSED_PARAM(webview);
620
621     // navigation of box scheme should be ignored
622     if(BoxSchemeHandler::Instance()->isBoxScheme(uri)) {
623         LogD("box scheme");
624         BoxSchemeHandler::Instance()->process(m_instanceId, uri);
625     }
626 }
627
628 void AppBoxRenderView::crashWebProcessCallback()
629 {
630     LogD("enter");
631     ewk_shutdown();
632     elm_exit();
633 }
634
635 void AppBoxRenderView::loadNonEmptyLayoutFinishedCallback(
636         void* data, Evas_Object* webview, void* eventInfo)
637 {
638     LogD("enter");
639     UNUSED_PARAM(data);
640     UNUSED_PARAM(webview);
641     UNUSED_PARAM(eventInfo);
642 }
643
644 void AppBoxRenderView::frameRenderedCallback(
645         void* data, Evas_Object* webview, void* eventInfo)
646 {
647     LogD("enter");
648     UNUSED_PARAM(webview);
649     UNUSED_PARAM(eventInfo);
650
651     // start to update render buffer!
652     AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
653     This->m_boxRenderBuffer->startCanvasUpdate();
654
655     // set flag
656     This->m_boxFrameRendered = true;
657
658     // move to inside of viewport to prevent overlap with snapshot image
659     if (!This->m_removeSnapShotTimer) {
660         evas_object_move(This->m_boxWrt->GetCurrentWebview(), 0, 0);
661     }
662
663 }