/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
*
- * Licensed under the Flora License, Version 1.0 (the "License");
+ * Licensed under the Flora License, Version 1.1 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://floralicense.org
+ * http://floralicense.org/license/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* @author Yunchan Cho (yunchan.cho@samsung.com)
*/
#include <string>
+#include <fstream>
+#include <streambuf>
#include <Eina.h>
#include <Evas.h>
#include <Ecore.h>
+#include <EWebKit2.h>
+#include <ewk_view.h>
+#include <ewk_context.h>
+#include <ewk_settings.h>
#include <livebox-service.h>
#include <i_runnable_widget_object.h>
#include <core_module.h>
#include <dpl/fast_delegate.h>
+#include <Core/BoxSchemeHandler.h>
#include <Core/View/IRenderView.h>
#include <Core/View/IPdHelper.h>
#include <Core/View/PdHelper.h>
#include <Core/Util/Log.h>
#include "AppBoxObserver.h"
#include "AppBoxRenderBuffer.h"
+#include "AppBoxPdHelper.h"
#include "AppBoxRenderView.h"
-#define RENDER_MAX_TIME 10.0
+#define RENDER_MAX_TIME 30.0
+#define SNAPSHOT_REMOVE_TIME 1.0
+
+// injection javascript file regarding creating js object used by box and pd
+static const std::string injectionFile("/usr/share/web-provider/injection.js");
AppBoxRenderView::AppBoxRenderView(
std::string boxId, std::string instanceId,
- Evas_Object* boxWin, EwkContextPtr ewkContext)
+ EwkContextPtr ewkContext)
: m_appId()
, m_boxId(boxId)
, m_instanceId(instanceId)
- , m_boxWin(boxWin)
- , m_baseWebView()
+ , m_ewkContext(ewkContext)
+ , m_boxRenderInfo()
+ , m_boxWrt()
+ , m_pdWrt()
, m_snapshot()
- , m_renderInfo()
- , m_view()
- , m_startUrl()
, m_fireRenderTimer()
+ , m_removeSnapShotTimer()
, m_pdHelper()
- , m_ewkContext(ewkContext)
+ , m_boxRenderBuffer()
+ , m_pdFastOpen(false)
+ , m_boxFinishLoad(false)
+ , m_boxWrt_isSuspended(false)
{
LogD("enter");
m_appId = getAppId(m_boxId);
throw; //exception throw!
}
- evas_object_show(m_boxWin);
- m_renderBuffer = AppBoxObserver::Instance()->getRenderBuffer(m_instanceId);
+ m_boxRenderBuffer = AppBoxObserver::Instance()->getRenderBuffer(m_instanceId);
+
+ // use fastopen to default
+ // m_pdFastOpen = web_provider_livebox_get_pd_fast_open(m_boxId.c_str()) ? true : false;
+ m_pdFastOpen = true;
AppBoxObserver::Instance()->registerRenderView(m_instanceId, this);
}
AppBoxRenderView::~AppBoxRenderView()
{
LogD("enter");
- evas_object_hide(m_boxWin);
AppBoxObserver::Instance()->unregisterRenderView(m_instanceId);
}
-void AppBoxRenderView::showBox(RenderInfoPtr renderInfo)
+void AppBoxRenderView::showBox(RenderInfoPtr boxRenderInfo)
{
LogD("enter");
+ // stop updating render buffer
+ m_boxRenderBuffer->stopCanvasUpdate();
+
+ // clear snapshot if this is not the case of pd open
+ if (!m_pdHelper) {
+ clearSnapShot();
+ }
+
// delete already running timer
- deleteRenderTimer();
+ deleteTimer(&m_fireRenderTimer);
- // stop touch timer
- if (livebox_service_mouse_event(m_boxId.c_str())) {
- m_renderBuffer->deleteTouchTimer();
+ // delete touch timer
+ if (web_provider_livebox_get_mouse_event(m_boxId.c_str())) {
+ m_boxRenderBuffer->deleteTouchTimer();
}
- // copy to url
- m_startUrl = getStartUrl(URL_TYPE_BOX, renderInfo->defaultUrlParams);
+ // set boxFinishLoad to false
+ m_boxFinishLoad = false;
- if (!createView()) {
- LogD("can't create view instance");
- return;
+ // copy to url
+ std::string boxStartUrl = getStartUrl(URL_TYPE_BOX, boxRenderInfo->defaultUrlParams);
+ if (m_boxWrt) {
+ LogD("existing wrt core is removed");
+ destroyBoxWrtCore();
}
+ m_boxWrt = createWrtCore(
+ URL_TYPE_BOX, boxStartUrl,
+ boxRenderInfo->window, m_ewkContext);
+ m_boxWrt_isSuspended = false;
+
// in case of showing box by request of pd open
if (m_pdHelper) {
- m_pdHelper->setBaseWebView(m_baseWebView);
+ m_pdHelper->setBoxWebView(m_boxWrt->GetCurrentWebview());
}
// resize webview fitted to width, height of Box
evas_object_resize(
- m_baseWebView,
- renderInfo->width,
- renderInfo->height);
+ m_boxWrt->GetCurrentWebview(),
+ boxRenderInfo->width,
+ boxRenderInfo->height);
- clearSnapShot();
- m_renderBuffer->startCanvasUpdate();
- m_view->Show();
- m_renderInfo = renderInfo;
+
+ evas_object_show(boxRenderInfo->window);
+ m_boxWrt->Show();
+ m_boxRenderInfo = boxRenderInfo;
}
-bool AppBoxRenderView::createView()
+AppBoxRenderView::WrtCorePtr AppBoxRenderView::createWrtCore(
+ UrlType type, std::string& startUrl,
+ Evas_Object* win, EwkContextPtr ewkContext)
{
LogD("enter");
- if (m_view) {
- m_view->Hide();
- m_view.reset();
- m_baseWebView = NULL;
- }
-#ifdef MULTIPROCESS_SERVICE_SUPPORT
- m_view = WRT::CoreModuleSingleton::
- Instance().getRunnableWidgetObject(m_appId, DPL::Optional<unsigned>());
-#else
- m_view = WRT::CoreModuleSingleton::
+ WrtCorePtr wrt;
+ wrt = WRT::CoreModuleSingleton::
Instance().getRunnableWidgetObject(m_appId);
-#endif
// prepare webview
- if (m_startUrl.empty()) {
+ if (startUrl.empty()) {
LogD("no start url");
- return false;
+ return WrtCorePtr();
}
- m_view->PrepareView(m_startUrl, m_boxWin, m_ewkContext.get());
- m_view->CheckBeforeLaunch();
+ wrt->PrepareView(startUrl, win, ewkContext.get());
+ wrt->CheckBeforeLaunch();
// set callback functions of RunnableWidgetObject
WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
cbs->loadStart = DPL::MakeDelegate(this, &AppBoxRenderView::startLoadCallback);
- cbs->loadFinish = DPL::MakeDelegate(this, &AppBoxRenderView::finishLoadCallback);
+ if (type == URL_TYPE_BOX) {
+ cbs->loadFinish = DPL::MakeDelegate(this, &AppBoxRenderView::finishBoxLoadCallback);
+ } else {
+ cbs->loadFinish = DPL::MakeDelegate(this, &AppBoxRenderView::finishPdLoadCallback);
+ }
+
cbs->bufferSet = DPL::MakeDelegate(this, &AppBoxRenderView::setBufferCallback);
cbs->bufferUnset = DPL::MakeDelegate(this, &AppBoxRenderView::unsetBufferCallback);
- cbs->windowCreateBefore = DPL::MakeDelegate(this, &AppBoxRenderView::createWindowBeforeCallback);
- cbs->windowCreateAfter = DPL::MakeDelegate(this, &AppBoxRenderView::createWindowAfterCallback);
- m_view->SetUserDelegates(cbs);
+ if (!m_pdFastOpen) {
+ cbs->windowCreateBefore =
+ DPL::MakeDelegate(this, &AppBoxRenderView::createWindowBeforeCallback);
+ cbs->windowCreateAfter =
+ DPL::MakeDelegate(this, &AppBoxRenderView::createWindowAfterCallback);
+ }
- // set base webview
- m_baseWebView = m_view->GetCurrentWebview();
+ cbs->navigationDecide =
+ DPL::MakeDelegate(this, &AppBoxRenderView::decideNavigationCallback);
+ cbs->webCrash = DPL::MakeDelegate(this, &AppBoxRenderView::crashWebProcessCallback);
+ wrt->SetUserDelegates(cbs);
- // To support transparent background
- evas_object_color_set(m_baseWebView, 0, 0, 0, 0);
- evas_object_layer_set(m_baseWebView, EVAS_LAYER_MAX);
- return true;
+ // set basic webview setting
+ setWebViewBasicSetting(wrt->GetCurrentWebview());
+ return wrt;
}
-bool AppBoxRenderView::destroyView()
+void AppBoxRenderView::destroyBoxWrtCore()
{
LogD("enter");
- m_renderBuffer->stopCanvasUpdate();
- deleteRenderTimer();
- if (m_view) {
- m_view->Hide();
- m_view.reset();
- m_baseWebView = NULL;
- }
+ m_boxRenderBuffer->stopCanvasUpdate();
+ deleteTimer(&m_fireRenderTimer);
+ deleteTimer(&m_removeSnapShotTimer);
+ destroyWrtCore(m_boxWrt);
+ m_boxWrt.reset();
+
+ // temp
+ m_boxWrt_isSuspended = false;
+}
+
+void AppBoxRenderView::destroyPdWrtCore()
+{
+ LogD("enter");
+
+ destroyWrtCore(m_pdWrt);
+ m_pdWrt.reset();
+}
- return true;
+void AppBoxRenderView::destroyWrtCore(WrtCorePtr wrt)
+{
+ LogD("enter");
+
+ if (wrt) {
+ wrt->Hide();
+ }
}
void AppBoxRenderView::hideBox()
{
LogD("enter");
- destroyView();
+ destroyBoxWrtCore();
+ if (m_boxRenderInfo->window) {
+ evas_object_hide(m_boxRenderInfo->window);
+ }
}
void AppBoxRenderView::pauseBox()
LogD("enter");
}
-void AppBoxRenderView::showPd(Evas_Object* pdWin, RenderInfoPtr renderInfo)
+void AppBoxRenderView::showPd(RenderInfoPtr pdRenderInfo, RenderInfoPtr boxRenderInfo)
{
LogD("enter");
- // create pd helper
- std::string pdStartUrl = getStartUrl(URL_TYPE_PD, renderInfo->defaultUrlParams);
- m_pdHelper = PdHelper::create(pdWin, pdStartUrl, renderInfo);
+ std::string pdStartUrl = getStartUrl(URL_TYPE_PD, pdRenderInfo->defaultUrlParams);
+ if (m_pdFastOpen) {
+ destroyPdWrtCore();
+ // if you want to launch new Web Process for PD, use the following line.
+ // EwkContextPtr pdContext = AppBoxObserver::Instance()->getPdEwkContext();
+ m_pdWrt = createWrtCore(URL_TYPE_PD, pdStartUrl, pdRenderInfo->window, m_ewkContext);
+ if (!m_pdWrt) {
+ LogD("no wrt core instance");
+ return;
+ }
+ m_pdHelper = AppBoxPdHelper::create(pdRenderInfo->window);
+
+ // resize webview fitted to width, height of pd
+ evas_object_resize(
+ m_pdWrt->GetCurrentWebview(),
+ pdRenderInfo->width,
+ pdRenderInfo->height);
+ // show pd
+ m_pdWrt->Show();
+ m_pdHelper->finishOpen(m_pdWrt->GetCurrentWebview());
+ } else {
+ m_pdHelper = PdHelper::create(pdRenderInfo, pdStartUrl);
+ }
// show pd window
- evas_object_show(pdWin);
- showBox(m_renderInfo);
+ evas_object_show(pdRenderInfo->window);
+
+ // show box
+ showBox(boxRenderInfo);
+
+ // start timer for clearing existing snapshot in case of only pd open
+ addTimer(&m_removeSnapShotTimer, SNAPSHOT_REMOVE_TIME, removeSnapShotTimerCallback);
+
}
void AppBoxRenderView::hidePd()
{
LogD("enter");
+ if (m_pdFastOpen) {
+ destroyPdWrtCore();
+ }
m_pdHelper->close();
m_pdHelper.reset();
- // stop box webview after render timer
- addRenderTimer();
+ // stop box webview
+ stopRenderBox();
+}
+
+Evas_Object* AppBoxRenderView::getBoxWebView()
+{
+ if (!m_pdHelper) {
+ return m_boxWrt->GetCurrentWebview();
+ } else {
+ // Here, we can't use GetCurrentWebView() of wrt-core to get Box' webview,
+ // because in the non fast-open, GetCurrentWebview() returns PD's webview.
+ return m_pdHelper->getBoxWebView();
+ }
+}
+
+Evas_Object* AppBoxRenderView::getPdWebView()
+{
+ if (!m_pdHelper) {
+ return NULL;
+ }
+
+ return m_pdHelper->getPdWebView();
}
std::string AppBoxRenderView::getAppId(std::string& boxId)
{
LogD("enter");
clearSnapShot();
- m_snapshot = m_renderBuffer->getSnapshot();
- //evas_object_layer_set(m_snapshot, EVAS_LAYER_MAX);
+ m_snapshot = m_boxRenderBuffer->getSnapshot();
return m_snapshot;
}
-void AppBoxRenderView::clearSnapShot()
+void AppBoxRenderView::clearSnapShot()
{
LogD("enter");
if (m_snapshot) {
- evas_object_layer_set(m_snapshot, EVAS_LAYER_MIN);
- //evas_object_hide(m_snapshot);
evas_object_del(m_snapshot);
m_snapshot = NULL;
}
}
-void AppBoxRenderView::addRenderTimer()
+void AppBoxRenderView::showSnapShot()
{
LogD("enter");
- if (m_fireRenderTimer) {
- deleteRenderTimer();
+ if (m_snapshot) {
+ evas_object_raise(m_snapshot);
+ evas_object_show(m_snapshot);
}
-
- m_fireRenderTimer = ecore_timer_add(
- RENDER_MAX_TIME,
- fireRenderTimerCallback,
- this);
}
-void AppBoxRenderView::deleteRenderTimer()
+void AppBoxRenderView::hideSnapShot()
{
LogD("enter");
- if (m_fireRenderTimer) {
- ecore_timer_del(m_fireRenderTimer);
- m_fireRenderTimer = NULL;
+ if (m_snapshot) {
+ evas_object_hide(m_snapshot);
+ evas_object_lower(m_snapshot);
}
}
-Eina_Bool AppBoxRenderView::fireRenderTimerCallback(void* data)
+void AppBoxRenderView::addTimer(Ecore_Timer** timer, double interval, Ecore_Task_Cb callback)
{
LogD("enter");
+ if (*timer) {
+ deleteTimer(timer);
+ }
- AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
- This->m_fireRenderTimer = NULL;
+ *timer = ecore_timer_add(interval, callback, this);
+}
+
+void AppBoxRenderView::deleteTimer(Ecore_Timer** timer)
+{
+ LogD("enter");
+ if (*timer) {
+ ecore_timer_del(*timer);
+ *timer = NULL;
+ }
+}
- This->m_renderBuffer->stopCanvasUpdate();
- if (livebox_service_mouse_event(This->m_boxId.c_str())) {
+void AppBoxRenderView::stopRenderBox()
+{
+ deleteTimer(&m_fireRenderTimer);
+ m_boxRenderBuffer->stopCanvasUpdate();
+ if (web_provider_livebox_get_mouse_event(m_boxId.c_str())) {
// stop touch timer
- This->m_renderBuffer->deleteTouchTimer();
- This->m_view->Suspend();
+ m_boxRenderBuffer->deleteTouchTimer();
+
+ // temp condition
+ if (m_boxWrt_isSuspended == false)
+ {
+ m_boxWrt_isSuspended = true;
+ m_boxWrt->Suspend();
+ }
} else {
// Before webview should be removed,
// new evas object with last render data should be created
// otherwise, after webview is removed, box is white screen.
- evas_object_show(This->getCurrentSnapShot());
- This->destroyView();
+ evas_object_show(getCurrentSnapShot());
+ destroyBoxWrtCore();
+ }
+}
+
+void AppBoxRenderView::setWebViewBasicSetting(Evas_Object* webview)
+{
+ LogD("enter");
+
+ if (!webview) {
+ return;
+ }
+ Ewk_Settings* setting = ewk_view_settings_get(webview);
+ // To support transparent background
+ evas_object_color_set(webview, 0, 0, 0, 1);
+ ewk_view_visibility_set(webview, EINA_TRUE);
+
+ // To know starting point for updating buffer
+ evas_object_smart_callback_add(
+ webview,
+ "load,nonemptylayout,finished",
+ loadNonEmptyLayoutFinishedCallback,
+ this);
+ evas_object_smart_callback_add(
+ webview,
+ "frame,rendered",
+ frameRenderedCallback,
+ this);
+}
+
+Eina_Bool AppBoxRenderView::fireRenderTimerCallback(void* data)
+{
+ LogD("enter");
+
+ AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
+ This->m_fireRenderTimer = NULL;
+ This->stopRenderBox();
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+Eina_Bool AppBoxRenderView::removeSnapShotTimerCallback(void* data)
+{
+ LogD("enter");
+
+ AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
+ if (!(This->m_boxFinishLoad)) {
+ return ECORE_CALLBACK_RENEW;
}
+ // hide snapshot because valid frame has been prepared generally.
+ This->clearSnapShot();
+
+ This->m_removeSnapShotTimer = NULL;
return ECORE_CALLBACK_CANCEL;
}
return ECORE_CALLBACK_CANCEL;
}
+void AppBoxRenderView::executeScriptCallback(
+ Evas_Object* webview, const char* result, void* data)
+{
+ LogD("enter");
+
+ std::string resultStr(result ? result : "null");
+ LogD("result: %s", resultStr.c_str());
+}
void AppBoxRenderView::startLoadCallback(Evas_Object* webview)
{
- // start load
+ LogD("enter");
+ if(!webview) {
+ return;
+ }
+ // execute injection for creating js objects
+ std::ifstream jsFile(injectionFile);
+ std::string script((std::istreambuf_iterator<char>(jsFile)),
+ std::istreambuf_iterator<char>());
+
+ LogD("injected js code: %s", script.c_str());
+ ewk_view_script_execute(webview, script.c_str(), executeScriptCallback, this);
}
-void AppBoxRenderView::finishLoadCallback(Evas_Object* webview)
+void AppBoxRenderView::finishBoxLoadCallback(Evas_Object* webview)
{
LogD("enter");
+ if (!webview) {
+ return;
+ }
+
ewk_view_visibility_set(webview, EINA_TRUE);
if (!m_pdHelper) {
// start render timer
- addRenderTimer();
+ addTimer(&m_fireRenderTimer, RENDER_MAX_TIME, fireRenderTimerCallback);
} else {
- if (!(m_pdHelper->isPdOpened()) &&
- webview == m_pdHelper->getBaseWebView())
- {
- // open pd
- ecore_idler_add(openPdIdlerCallback, this);
+ if (!m_pdFastOpen) {
+ if (!(m_pdHelper->isPdOpened()) &&
+ webview == m_pdHelper->getBoxWebView())
+ {
+ // open pd
+ ecore_idler_add(openPdIdlerCallback, this);
+ }
}
}
+
+ // set flag
+ m_boxFinishLoad = true;
+}
+
+void AppBoxRenderView::finishPdLoadCallback(Evas_Object* webview)
+{
+ LogD("enter");
+ if (!webview) {
+ return;
+ }
+
+ ewk_view_visibility_set(webview, EINA_TRUE);
}
void AppBoxRenderView::createWindowBeforeCallback(Evas** canvas, Evas_Object* parent)
if (m_pdHelper) {
if (!(m_pdHelper->isPdOpened()) &&
- parent == m_pdHelper->getBaseWebView())
+ parent == m_pdHelper->getBoxWebView())
{
LogD("pd canvas is used");
*canvas = m_pdHelper->getPdCanvas();
return;
}
- }
+ }
LogD("canvas of this webview is used");
*canvas = evas_object_evas_get(parent);
void AppBoxRenderView::createWindowAfterCallback(Evas_Object* parent, Evas_Object* child)
{
LogD("enter");
-
- // To support transparent background
- evas_object_color_set(child, 0, 0, 0, 0);
+ if (!parent) {
+ return;
+ }
if (m_pdHelper) {
Evas* parentCanvas = evas_object_evas_get(parent);
}
}
- ewk_view_visibility_set(child, EINA_TRUE);
+ setWebViewBasicSetting(child);
evas_object_show(child);
}
LogD("enter");
evas_object_hide(webview);
}
+
+void AppBoxRenderView::decideNavigationCallback(Evas_Object* webview, std::string& uri)
+{
+ LogD("enter");
+
+ // navigation of box scheme should be ignored
+ if(BoxSchemeHandler::Instance()->isBoxScheme(uri)) {
+ LogD("box scheme");
+ BoxSchemeHandler::Instance()->process(m_instanceId, uri);
+ }
+}
+
+void AppBoxRenderView::crashWebProcessCallback()
+{
+ LogD("enter");
+ ewk_shutdown();
+ elm_exit();
+}
+
+void AppBoxRenderView::loadNonEmptyLayoutFinishedCallback(
+ void* data, Evas_Object* webview, void* eventInfo)
+{
+ LogD("enter");
+}
+
+void AppBoxRenderView::frameRenderedCallback(
+ void* data, Evas_Object* webview, void* eventInfo)
+{
+ LogD("enter");
+
+ // start to update render buffer!
+ AppBoxRenderView* This = static_cast<AppBoxRenderView*>(data);
+ This->m_boxRenderBuffer->startCanvasUpdate();
+}