2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://floralicense.org/license/
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.
17 * @file AppBoxRenderView.cpp
18 * @author Yunchan Cho (yunchan.cho@samsung.com)
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"
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
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");
53 AppBoxRenderView::AppBoxRenderView(
54 std::string boxId, std::string instanceId,
55 EwkContextPtr ewkContext)
58 , m_instanceId(instanceId)
59 , m_ewkContext(ewkContext)
65 , m_removeSnapShotTimer()
69 , m_boxFinishLoad(false)
70 , m_boxFrameRendered(false)
71 , m_boxWrt_isSuspended(false)
74 m_appId = getAppId(m_boxId);
75 if (m_appId.empty()) {
76 throw; //exception throw!
79 m_boxRenderBuffer = AppBoxObserver::Instance()->getRenderBuffer(m_instanceId);
81 // use fastopen to default
82 // m_pdFastOpen = web_provider_livebox_get_pd_fast_open(m_boxId.c_str()) ? true : false;
84 AppBoxObserver::Instance()->registerRenderView(m_instanceId, this);
87 AppBoxRenderView::~AppBoxRenderView()
90 AppBoxObserver::Instance()->unregisterRenderView(m_instanceId);
93 void AppBoxRenderView::showBox(RenderInfoPtr boxRenderInfo)
97 // stop updating render buffer
98 m_boxRenderBuffer->stopCanvasUpdate();
100 // clear snapshot if this is not the case of pd open
105 // delete already running timer
106 deleteTimer(&m_fireRenderTimer);
108 // delete touch timer
109 if (web_provider_livebox_get_mouse_event(m_boxId.c_str())) {
110 m_boxRenderBuffer->deleteTouchTimer();
113 // set boxFinishLoad and m_boxFrameRendered to false
114 m_boxFinishLoad = false;
115 m_boxFrameRendered = false;
118 std::string boxStartUrl = getStartUrl(URL_TYPE_BOX, boxRenderInfo->defaultUrlParams);
120 LogD("existing wrt core is removed");
124 m_boxWrt = createWrtCore(
125 URL_TYPE_BOX, boxStartUrl,
126 boxRenderInfo->window, m_ewkContext);
127 m_boxWrt_isSuspended = false;
129 // in case of showing box by request of pd open
131 m_pdHelper->setBoxWebView(m_boxWrt->GetCurrentWebview());
134 // resize webview fitted to width, height of Box
136 m_boxWrt->GetCurrentWebview(),
137 boxRenderInfo->width,
138 boxRenderInfo->height);
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);
146 m_boxRenderInfo = boxRenderInfo;
149 AppBoxRenderView::WrtCorePtr AppBoxRenderView::createWrtCore(
150 UrlType type, std::string& startUrl,
151 Evas_Object* win, EwkContextPtr ewkContext)
156 wrt = WRT::CoreModuleSingleton::
157 Instance().getRunnableWidgetObject(m_appId);
159 if (startUrl.empty()) {
160 LogD("no start url");
163 wrt->PrepareView(startUrl, win, ewkContext.get());
164 wrt->CheckBeforeLaunch();
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);
172 cbs->loadFinish = DPL::MakeDelegate(this, &AppBoxRenderView::finishPdLoadCallback);
175 cbs->bufferSet = DPL::MakeDelegate(this, &AppBoxRenderView::setBufferCallback);
176 cbs->bufferUnset = DPL::MakeDelegate(this, &AppBoxRenderView::unsetBufferCallback);
178 cbs->windowCreateBefore =
179 DPL::MakeDelegate(this, &AppBoxRenderView::createWindowBeforeCallback);
180 cbs->windowCreateAfter =
181 DPL::MakeDelegate(this, &AppBoxRenderView::createWindowAfterCallback);
184 cbs->navigationDecide =
185 DPL::MakeDelegate(this, &AppBoxRenderView::decideNavigationCallback);
186 cbs->webCrash = DPL::MakeDelegate(this, &AppBoxRenderView::crashWebProcessCallback);
187 wrt->SetUserDelegates(cbs);
189 // set basic webview setting
190 setWebViewBasicSetting(wrt->GetCurrentWebview());
194 void AppBoxRenderView::destroyBoxWrtCore()
198 m_boxRenderBuffer->stopCanvasUpdate();
199 deleteTimer(&m_fireRenderTimer);
200 deleteTimer(&m_removeSnapShotTimer);
201 destroyWrtCore(m_boxWrt);
205 m_boxWrt_isSuspended = false;
208 void AppBoxRenderView::destroyPdWrtCore()
212 destroyWrtCore(m_pdWrt);
216 void AppBoxRenderView::destroyWrtCore(WrtCorePtr wrt)
225 void AppBoxRenderView::hideBox()
229 if (m_boxRenderInfo->window) {
230 evas_object_hide(m_boxRenderInfo->window);
234 void AppBoxRenderView::pauseBox()
239 void AppBoxRenderView::resumeBox()
244 void AppBoxRenderView::showPd(RenderInfoPtr pdRenderInfo, RenderInfoPtr boxRenderInfo)
248 std::string pdStartUrl = getStartUrl(URL_TYPE_PD, pdRenderInfo->defaultUrlParams);
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);
255 LogD("no wrt core instance");
258 m_pdHelper = AppBoxPdHelper::create(pdRenderInfo->window);
260 // resize webview fitted to width, height of pd
262 m_pdWrt->GetCurrentWebview(),
264 pdRenderInfo->height);
267 m_pdHelper->finishOpen(m_pdWrt->GetCurrentWebview());
269 m_pdHelper = PdHelper::create(pdRenderInfo, pdStartUrl);
273 evas_object_show(pdRenderInfo->window);
275 // need to create new snapshot when m_napshot is empty
277 evas_object_show(getCurrentSnapShot());
281 showBox(boxRenderInfo);
283 // start timer for clearing existing snapshot in case of only pd open
284 addTimer(&m_removeSnapShotTimer, SNAPSHOT_REMOVE_TIME, removeSnapShotTimerCallback);
288 void AppBoxRenderView::hidePd()
299 Evas_Object* AppBoxRenderView::getBoxWebView()
302 return m_boxWrt->GetCurrentWebview();
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();
310 Evas_Object* AppBoxRenderView::getPdWebView()
316 return m_pdHelper->getPdWebView();
319 std::string AppBoxRenderView::getAppId(std::string& boxId)
323 const char* appId = web_provider_livebox_get_app_id(boxId.c_str());
325 LogD("no appid of %s", boxId.c_str());
326 return std::string();
329 return std::string(appId);
332 std::string AppBoxRenderView::getStartUrl(UrlType type, std::string& defaultParams)
337 url = livebox_service_lb_script_path(m_boxId.c_str());
340 url = livebox_service_pd_script_path(m_boxId.c_str());
343 LogD("no available type");
346 // add default parameters to start url
347 url += defaultParams;
352 Evas_Object* AppBoxRenderView::getCurrentSnapShot()
356 m_snapshot = m_boxRenderBuffer->getSnapshot();
361 void AppBoxRenderView::clearSnapShot()
365 evas_object_del(m_snapshot);
370 void AppBoxRenderView::showSnapShot()
374 evas_object_raise(m_snapshot);
375 evas_object_show(m_snapshot);
379 void AppBoxRenderView::hideSnapShot()
383 evas_object_hide(m_snapshot);
384 evas_object_lower(m_snapshot);
388 void AppBoxRenderView::addTimer(Ecore_Timer** timer, double interval, Ecore_Task_Cb callback)
395 *timer = ecore_timer_add(interval, callback, this);
398 void AppBoxRenderView::deleteTimer(Ecore_Timer** timer)
402 ecore_timer_del(*timer);
407 void AppBoxRenderView::stopRenderBox()
409 deleteTimer(&m_fireRenderTimer);
410 m_boxRenderBuffer->stopCanvasUpdate();
411 if (web_provider_livebox_get_mouse_event(m_boxId.c_str())) {
413 m_boxRenderBuffer->deleteTouchTimer();
416 if (m_boxWrt_isSuspended == false)
418 m_boxWrt_isSuspended = true;
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());
430 void AppBoxRenderView::setWebViewBasicSetting(Evas_Object* webview)
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);
442 // To know starting point for updating buffer
443 evas_object_smart_callback_add(
445 "load,nonemptylayout,finished",
446 loadNonEmptyLayoutFinishedCallback,
448 evas_object_smart_callback_add(
451 frameRenderedCallback,
453 // To set font type whenever font changed
454 ewk_view_use_settings_font(webview);
457 Eina_Bool AppBoxRenderView::fireRenderTimerCallback(void* data)
461 AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
462 This->m_fireRenderTimer = NULL;
463 This->stopRenderBox();
465 return ECORE_CALLBACK_CANCEL;
468 Eina_Bool AppBoxRenderView::removeSnapShotTimerCallback(void* data)
472 AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
473 if (!(This->m_boxFinishLoad && This->m_boxFrameRendered)) {
474 return ECORE_CALLBACK_RENEW;
477 // hide snapshot because valid frame has been prepared generally.
478 This->clearSnapShot();
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());
484 This->m_removeSnapShotTimer = NULL;
485 return ECORE_CALLBACK_CANCEL;
488 Eina_Bool AppBoxRenderView::openPdIdlerCallback(void* data)
491 AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
492 if (This && This->m_pdHelper) {
493 This->m_pdHelper->startOpen();
495 return ECORE_CALLBACK_CANCEL;
498 void AppBoxRenderView::executeScriptCallback(
499 Evas_Object* webview, const char* result, void* data)
502 UNUSED_PARAM(webview);
505 std::string resultStr(result ? result : "null");
506 LogD("result: %s", resultStr.c_str());
509 void AppBoxRenderView::startLoadCallback(Evas_Object* webview)
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>());
520 LogD("injected js code: %s", script.c_str());
521 ewk_view_script_execute(webview, script.c_str(), executeScriptCallback, this);
524 void AppBoxRenderView::finishBoxLoadCallback(Evas_Object* webview)
531 ewk_view_visibility_set(webview, EINA_TRUE);
534 // start render timer
535 addTimer(&m_fireRenderTimer, RENDER_MAX_TIME, fireRenderTimerCallback);
538 if (!(m_pdHelper->isPdOpened()) &&
539 webview == m_pdHelper->getBoxWebView())
542 ecore_idler_add(openPdIdlerCallback, this);
548 m_boxFinishLoad = true;
551 void AppBoxRenderView::finishPdLoadCallback(Evas_Object* webview)
558 ewk_view_visibility_set(webview, EINA_TRUE);
561 void AppBoxRenderView::createWindowBeforeCallback(Evas** canvas, Evas_Object* parent)
566 if (!(m_pdHelper->isPdOpened()) &&
567 parent == m_pdHelper->getBoxWebView())
569 LogD("pd canvas is used");
570 *canvas = m_pdHelper->getPdCanvas();
575 LogD("canvas of this webview is used");
576 *canvas = evas_object_evas_get(parent);
579 void AppBoxRenderView::createWindowAfterCallback(Evas_Object* parent, Evas_Object* child)
587 Evas* parentCanvas = evas_object_evas_get(parent);
588 Evas* childCanvas = evas_object_evas_get(child);
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);
599 setWebViewBasicSetting(child);
600 evas_object_show(child);
603 void AppBoxRenderView::setBufferCallback(Evas_Object* webview)
606 evas_object_show(webview);
607 evas_object_focus_set(webview, EINA_TRUE);
610 void AppBoxRenderView::unsetBufferCallback(Evas_Object* webview)
613 evas_object_hide(webview);
616 void AppBoxRenderView::decideNavigationCallback(Evas_Object* webview, std::string& uri)
619 UNUSED_PARAM(webview);
621 // navigation of box scheme should be ignored
622 if(BoxSchemeHandler::Instance()->isBoxScheme(uri)) {
624 BoxSchemeHandler::Instance()->process(m_instanceId, uri);
628 void AppBoxRenderView::crashWebProcessCallback()
635 void AppBoxRenderView::loadNonEmptyLayoutFinishedCallback(
636 void* data, Evas_Object* webview, void* eventInfo)
640 UNUSED_PARAM(webview);
641 UNUSED_PARAM(eventInfo);
644 void AppBoxRenderView::frameRenderedCallback(
645 void* data, Evas_Object* webview, void* eventInfo)
648 UNUSED_PARAM(webview);
649 UNUSED_PARAM(eventInfo);
651 // start to update render buffer!
652 AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
653 This->m_boxRenderBuffer->startCanvasUpdate();
656 This->m_boxFrameRendered = true;
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);