Implement certificate confirm popup
[platform/framework/web/wrt.git] / src / view / webkit / view_logic.cpp
1 /*
2  * Copyright (c) 2011 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    view_logic.cpp
18  * @author  Pawel Sikorski (p.sikorsk@samsung.com)
19  * @author  Lukasz Wrzosek (l.wrzosek@samsung.com)
20  * @author  Yunchan Cho (yunchan.cho@samsung.com)
21  * @brief   View logic for Webkit2
22  */
23 #include "view_logic.h"
24
25 #include <cstring>
26 #include <string>
27 #include <dpl/assert.h>
28 #include <dpl/log/log.h>
29 #include <dpl/optional.h>
30 #include <dpl/string.h>
31 #include <dpl/foreach.h>
32
33 #include <pcrecpp.h>
34 #include <vconf.h>
35 #include <sysman.h>
36 #include <widget_model.h>
37 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
38 #include <dpl/wrt-dao-ro/vconf_config.h>
39 #include <dpl/utils/wrt_global_settings.h>
40
41 #include <common/application_data.h>
42 #include <common/application_launcher.h>
43 #include <common/scheme.h>
44
45 #include <common/view_logic_apps_support.h>
46 #include <common/view_logic_custom_header_support.h>
47 #include <common/view_logic_password_support.h>
48 #include <common/view_logic_security_support.h>
49 #include <common/view_logic_security_origin_support.h>
50 #include <common/view_logic_certificate_support.h>
51 #include <common/view_logic_storage_support.h>
52 #include <common/view_logic_uri_support.h>
53 #include <common/view_logic_user_agent_support.h>
54 #include <common/view_logic_vibration_support.h>
55 #include <view_logic_authentication_challenge_support.h>
56 #include <view_logic_scheme_support.h>
57 #include <view_logic_geolocation_support_webkit2.h>
58 #include <view_logic_usermedia_support.h>
59 #include <view_logic_web_notification_support.h>
60
61 #include <view_logic_certificate_confirm_support.h>
62 #include "bundles/plugin_module_support.h"
63 #include <popup-runner/PopupInvoker.h>
64
65 #include <EWebKit2.h>
66 #include <js_overlay_types.h>
67 #include <i_runnable_widget_object.h>
68 #include <profiling_util.h>
69 #include <wrt-commons/custom-handler-dao-ro/common_dao_types.h>
70 #include <wrt-commons/custom-handler-dao-ro/CustomHandlerDatabase.h>
71 #include <wrt-commons/custom-handler-dao-ro/custom_handler_dao_read_only.h>
72 #include <wrt-commons/custom-handler-dao-rw/custom_handler_dao.h>
73 #include <popup-runner/PopupInvoker.h>
74
75 #include <appsvc/appsvc.h>
76
77 namespace {
78 const char * const bundlePath = "/usr/lib/wrt-wk2-bundles/libwrt-wk2-bundle.so";
79 const char * const uriBlockedMessageName = "uri_blocked_msg";
80 const char * const uriChangedMessageName = "uri_changed_msg";
81 const char * const URICHANGE_PLUGIN_STOP_ONLY = "plugin_stop_only";
82 const char * const URICHANGE_PLUGIN_RESTART = "plugin_restart";
83 const char * const URICHANGE_PLUGIN_NO_CHANGE = "plugin_no_change";
84 const char * const URICHANGE_BLOCKED_URL = "null";
85 const char* PATTERN_URI_CHANGE = "^(([^:/\\?#]+)://[^\\?#]*)";
86 const int MAX_NUM_CONTEXT_MENU_ITEMS = 10;
87 // IME State value
88 const char * const IME_STATE_ON = "on";
89 const char * const IME_STATE_OFF = "off";
90
91 const char PROTOCOL_HANDLER_ASK_MSG[] = "Add protocol?";
92 const char PROTOCOL_HANDLER_ASK_TITLE[] = "Add protocol";
93 const char PROTOCOL_HANDLER_ASK_REMEMBER[] = "Remember dicision";
94 const char CONTENT_HANDLER_ASK_MSG[] = "Add content?";
95 const char CONTENT_HANDLER_ASK_TITLE[] = "Add content";
96 const char CONTENT_HANDLER_AKS_REMEMBER[] = "Remember dicision";
97 const char * const CERTIFICATE_CONFIRM_REQUEST_ASK_TITLE =
98     "Certification Info";
99 const char * const CERTIFICATE_CONFIRM_REQUEST_ASK_BODY =
100     "This site's security certificate is not trusted! Do you acess this site?";
101
102 const wchar_t* BACKGROUND_ENABLED = L"background_enabled";
103 } // anonymous namespace
104
105 std::map<const std::string,
106          const Evas_Smart_Cb> ViewLogic::m_ewkCallbacksMap = {
107     { "load,started", &ViewLogic::loadStartedCallback },
108     { "load,finished", &ViewLogic::loadFinishedCallback },
109     { "title,changed", &ViewLogic::titleChangedCallback },
110     { "load,progress", &ViewLogic::loadProgressCallback },
111     { "load,progress,finished", &ViewLogic::loadProgressFinishedCallback },
112     { "process,crashed", &ViewLogic::processCrashedCallback },
113     // WKPageUIClient
114     { "create,window", &ViewLogic::createWindowCallback },
115     { "close,window", &ViewLogic::closeWindowCallback },
116     // WKPagePolicyClient
117     { "policy,navigation,decide", &ViewLogic::policyNavigationDecideCallback },
118     { "policy,newwindow,decide", &ViewLogic::policyNewWindowDecideCallback },
119     { "policy,response,decide", &ViewLogic::pageResponseDecideCallback },
120     // WKPageContextMenuClient
121     { "contextmenu,customize", &ViewLogic::contextmenuCustomizeCallback },
122     // WKPageFormClient
123     { "form,submit", &ViewLogic::formSubmitCallback },
124     // EWK Geolocation Callback
125     { "geolocation,permission,request",
126       &ViewLogic::geolocationPermissionRequestCallback },
127     // EWK Notification Callback
128     { "notification,show", &ViewLogic::notificationShowCallback },
129     { "notification,cancel", &ViewLogic::notificationCancelCallback },
130     { "notification,permission,request",
131       &ViewLogic::notificationPermissionRequestCallback },
132
133     { "fullscreen,enterfullscreen", &ViewLogic::enterFullscreenCallback },
134     { "fullscreen,exitfullscreen", &ViewLogic::exitFullscreenCallback },
135     // IME Callback
136     // when ime start to be showed on the webview,
137     // this callback will be called
138     { "inputmethod,changed", &ViewLogic::imeChangedCallback },
139     // this callback will be called
140     //  when ime finishes to be showed on the webview
141     // "event_info" arg of this callback is always NULL point
142     // if web content should know size of ime,
143     //  use "inputmethod,changed" instead of this.
144     //
145     { "editorclient,ime,opened", &ViewLogic::imeOpenedCallback },
146     // when ime finished to be hidden,
147     // this callback will be called
148     { "editorclient,ime,closed", &ViewLogic::imeClosedCallback },
149     // EWK Usermedia Callback
150     { "usermedia,permission,request",
151       &ViewLogic::usermediaPermissionRequestCallback },
152     // Custom handlers
153     { "protocolhandler,registration,requested",
154       &ViewLogic::protocolHandlerRegistrationCallback },
155     { "protocolhandler,isregistered",
156       &ViewLogic::protocolHandlerIsRegisteredCallback },
157     { "protocolhandler,unregistration,requested",
158       &ViewLogic::protocolHandlerUnregistrationCallback },
159     { "contenthandler,registration,requested",
160       &ViewLogic::contentHandlerRegistrationCallback },
161     { "contenthandler,isregistered",
162       &ViewLogic::contentHandlerIsRegisteredCallback },
163     { "contenthandler,unregistration,requested",
164       &ViewLogic::contentHandlerUnregistrationCallback },
165     { "request,certificate,confirm",
166       &ViewLogic::certificateConfirmRequestCallback },
167     { "authentication,challenge",
168       &ViewLogic::authenticationChallengeRequestCallback }
169 };
170
171 ViewLogic::ViewLogic() :
172     m_ewkContext(0),
173     m_attachedToCustomHandlerDao(false),
174     m_currentEwkView(0),
175     m_closedEwkView(NULL),
176     m_window(NULL),
177     m_model(0),
178     m_cbs(new WRT::UserDelegates),
179     m_imeWidth(0),
180     m_imeHeight(0),
181     m_isBackgroundReload(false),
182     m_isBackgroundSupport(false),
183     m_appsSupport(new ViewModule::AppsSupport()),
184     m_vibrationSupport(new ViewModule::VibrationSupport())
185 {
186     ApplicationLauncherSingleton::Instance().Touch();
187 }
188
189 ViewLogic::~ViewLogic()
190 {
191     detachFromCustomHandlersDao();
192 }
193
194 bool ViewLogic::createWebView(Ewk_Context* context,
195                               Evas_Object* window)
196 {
197     LogDebug("enter");
198     if (!context || !window) {
199         return false;
200     }
201
202     // theme setting
203     const char *theme = elm_theme_get(NULL);
204     if (theme) {
205         m_theme = theme;
206         LogInfo("theme is " << m_theme);
207     }
208
209     // set members
210     m_ewkContext = context;
211     m_window = window;
212
213     Evas* canvas = evas_object_evas_get(m_window);
214     return createEwkView(canvas);
215 }
216
217 void ViewLogic::prepareView(WidgetModel* m, const std::string &startUrl)
218 {
219     LogDebug("View prepare");
220
221     Assert(m);
222     m_model = m;
223     m_startUrl = startUrl;
224     Assert(NULL != m_ewkContext);
225     Assert(m_window);
226
227     ADD_PROFILING_POINT("initializeSupport", "start");
228     initializeSupport();
229     ADD_PROFILING_POINT("initializeSupport", "stop");
230     setStartPage();
231     ewkClientInit(m_currentEwkView);
232     ADD_PROFILING_POINT("prepareEwkView", "start");
233     prepareEwkView(m_currentEwkView);
234     ADD_PROFILING_POINT("prepareEwkView", "stop");
235     initializePluginLoading();
236 }
237
238 void ViewLogic::showWidget()
239 {
240     LogDebug("showing widget");
241     Assert(NULL != m_currentEwkView && "ewk_view not created at this point");
242     if (m_currentUri.empty()) {
243         LogError("Localized current URI doesn't exist");
244         return;
245     }
246
247     LogInfo("m_currentUri: " << m_currentUri);
248
249     // load page
250     ewk_view_url_set(m_currentEwkView, m_currentUri.c_str());
251
252     if (!m_cbs->bufferSet.empty()) {
253         m_cbs->bufferSet(m_currentEwkView);
254     }
255 }
256
257 void ViewLogic::hideWidget()
258 {
259     LogDebug("hiding widget");
260     ViewModule::StorageSupport::deinitializeStorage(m_model);
261     m_appsSupport->deinitialize();
262
263     m_vibrationSupport->deinitialize();
264
265     while (!m_ewkViewList.empty()) {
266         LogInfo("pop webview: " << m_ewkViewList.back());
267         removeEwkView(m_ewkViewList.back());
268     }
269     m_ewkViewList.clear();
270 }
271
272 void ViewLogic::suspendWidget()
273 {
274     LogInfo("Pausing widget");
275     Assert(m_model);
276
277     if (!m_currentEwkView) {
278         LogWarning("Cannot suspend widget without view");
279     } else {
280         setEwkViewInvisible(m_currentEwkView);
281         if (!m_isBackgroundSupport) {
282             suspendWebkit(m_currentEwkView);
283         }
284     }
285
286     evas_object_focus_set(m_currentEwkView, EINA_FALSE);
287
288     // call user callback
289     if (!m_cbs->suspend.empty()) {
290         m_cbs->suspend(true);
291     }
292 }
293
294 void ViewLogic::resumeWidget()
295 {
296     LogInfo("Resume widget");
297     Assert(m_model);
298
299     if (m_currentEwkView) {
300         setEwkViewVisible(m_currentEwkView);
301         if (!m_isBackgroundSupport) {
302             resumeWebkit(m_currentEwkView);
303         }
304     }
305
306     /* window system team recomend removing this win_raise code. */
307     /*
308      * if (m_window) {
309      *  elm_win_raise(m_window);
310      * }
311      */
312     evas_object_focus_set(m_currentEwkView, EINA_TRUE);
313
314     // call user callback
315     if (!m_cbs->resume.empty()) {
316         m_cbs->resume(true);
317     }
318 }
319
320 void ViewLogic::resetWidget()
321 {
322     LogInfo("Resetting Widget");
323
324     // destory all webview
325     while (!m_ewkViewList.empty()) {
326         LogInfo("pop webview: " << m_ewkViewList.back());
327         removeEwkView(m_ewkViewList.back());
328     }
329     m_ewkViewList.clear();
330
331     // create new webview
332     createEwkView(evas_object_evas_get(m_window));
333     setStartPage();
334     ewkClientInit(m_currentEwkView);
335     prepareEwkView(m_currentEwkView);
336
337     // check if current url is service url for this tizen service
338     std::string requestedUri =
339         ViewModule::UriSupport::getUri(m_model, m_startUrl);
340     DPL::OptionalString servicedUri = ViewModule::UriSupport::localizeURI(
341             DPL::FromUTF8String(requestedUri.c_str()),
342             m_model);
343
344     initializePluginLoading();
345
346     // webview activated
347     m_currentUri = DPL::ToUTF8String(*servicedUri);
348     ewk_view_url_set(m_currentEwkView, m_currentUri.c_str());
349     elm_win_activate(m_window);
350     evas_object_focus_set(m_currentEwkView, EINA_TRUE);
351
352     // call user callback
353     if (!m_cbs->reset.empty()) {
354         m_cbs->reset(true);
355     }
356     if (!m_cbs->bufferSet.empty()) {
357         m_cbs->bufferSet(m_currentEwkView);
358     }
359 }
360
361 void ViewLogic::backward()
362 {
363     if (ewk_view_back_possible(m_currentEwkView)) {
364         ewk_view_back(m_currentEwkView);
365     } else {
366         if (1 >= m_ewkViewList.size()) {
367             // If there is no previous page, widget move to backgroud.
368             LogInfo("Widget move to backgroud");
369             elm_win_lower(m_window);
370         } else {
371             // Back to previous webview
372             LogInfo("Widget move to previous webview");
373             m_closedEwkView = m_currentEwkView;
374             ecore_idler_add(windowCloseIdlerCallback, this);
375         }
376     }
377 }
378
379 void ViewLogic::reloadStartPage()
380 {
381     LogInfo("Reload Start Page");
382     // prevent fail to load plugin bundle side
383     m_isBackgroundReload = true;
384
385     if (!m_ewkViewList.empty()) {
386         while (!m_ewkViewList.empty()) {
387             if (!m_cbs->bufferUnset.empty()) {
388                 m_cbs->bufferUnset(m_currentEwkView);
389             }
390             removeEwkView(m_currentEwkView);
391         }
392     }
393
394     // create new webview
395     createEwkView(evas_object_evas_get(m_window));
396     ewkClientInit(m_currentEwkView);
397
398     setStartPage();
399     prepareEwkView(m_currentEwkView);
400     initializePluginLoading();
401
402     // load page
403     ewk_view_url_set(m_currentEwkView, m_currentUri.c_str());
404
405     // show ewkView
406     if (!m_cbs->bufferSet.empty()) {
407         m_cbs->bufferSet(m_currentEwkView);
408     }
409     LogInfo("Reloading Start Page is done!");
410 }
411
412 Evas_Object* ViewLogic::getCurrentWebview()
413 {
414     LogInfo("get current webview");
415     return m_currentEwkView;
416 }
417
418 void ViewLogic::fireJavascriptEvent(int event, void* data)
419 {
420     PluginModuleSupport::dispatchJavaScriptEvent(
421         m_ewkContext,
422         static_cast<WrtPlugins::W3C::CustomEventType>(event),
423         data);
424 }
425
426 void ViewLogic::setUserCallbacks(const WRT::UserDelegatesPtr& cbs)
427 {
428     m_cbs = cbs;
429 }
430
431 void ViewLogic::checkSyncMessageFromBundle(
432         const char* name,
433         const char* body,
434         char** returnData)
435 {
436     LogDebug("didReceiveSynchronousMessage called");
437     Assert(name);
438     Assert(returnData);
439
440     if (!body) {
441         LogDebug("body is empty");
442         *returnData = NULL;
443         return;
444     }
445
446     LogDebug("received : " << name);
447     std::string result;
448     if (!strcmp(name, uriBlockedMessageName)) {
449         // Currently WebProcess informs obly about blocked
450         // URI - URI localization and security chekcs are
451         // done by WebProcess itself (see: wrt-wk2-bundle.cpp
452         // and bundle_uri_handling.cpp)
453         result = requestUrlBlocked(std::string(body));
454     } else if (!strcmp(name, uriChangedMessageName)) {
455         result = requestUrlChanged(std::string(body));
456     }
457
458     *returnData = strdup(result.c_str());
459 }
460
461 void ViewLogic::downloadData(const char* url)
462 {
463     LogInfo("enter");
464     if (!url) {
465         return;
466     }
467
468     m_appsSupport->downloadRequest(url, NULL, NULL);
469 }
470
471 void ViewLogic::activateVibration(bool on, uint64_t time)
472 {
473     LogInfo("enter");
474     if (on) {
475         m_vibrationSupport->startVibration(static_cast<long>(time));
476     } else {
477         m_vibrationSupport->stopVibration();
478     }
479 }
480
481 void ViewLogic::initializeSupport()
482 {
483     // background support
484     if (m_model->SettingList.Get().getBackgroundSupport()
485         == BackgroundSupport_Enable)
486     {
487         LogDebug("Background support enabled, set process active");
488         pid_t pid = getpid();
489         sysman_inform_active(pid);
490         m_isBackgroundSupport = true;
491     }
492 #ifndef DEPRECATED_SETTING_STRING
493     else {
494         WrtDB::WidgetDAOReadOnly dao(m_model->TizenId);
495         WrtDB::PropertyDAOReadOnly::WidgetPropertyValue bgEnableValue =
496             dao.getPropertyValue(DPL::String(BACKGROUND_ENABLED));
497
498         if (!bgEnableValue.IsNull() && !bgEnableValue->compare(L"true")) {
499             //skip suspendWidget
500             LogDebug("Background support enabled, set process active");
501             pid_t pid = getpid();
502             sysman_inform_active(pid);
503             m_isBackgroundSupport = true;
504         }
505     }
506 #endif
507
508     m_schemeSupport.reset(new SchemeSupport(m_model->Type.Get().appType));
509     ViewModule::StorageSupport::initializeStorage(m_model);
510     m_appsSupport->initialize(m_model);
511     m_securityOriginSupport.reset(new ViewModule::SecurityOriginSupport(m_model));
512     m_certificateSupport.reset(new ViewModule::CertificateSupport(m_model));
513
514     m_vibrationSupport->initialize();
515 }
516
517 void ViewLogic::initializePluginLoading()
518 {
519     // inform wrt information for plugin loading to web process
520     PluginModuleSupport::start(
521         m_ewkContext,
522         m_model->TizenId,
523         elm_config_scale_get(),
524         ApplicationDataSingleton::Instance().getEncodedBundle(),
525         m_theme.c_str(),
526         m_model->SettingList.Get().isEncrypted());
527 }
528
529 void ViewLogic::ewkClientInit(Evas_Object *wkView)
530 {
531     Assert(NULL != wkView && "ewk_view not created at this point");
532
533     FOREACH(it, m_ewkCallbacksMap) {
534         evas_object_smart_callback_add(
535             wkView,
536             it->first.c_str(),
537             it->second,
538             this);
539     }
540     // EWK Orientation Callback
541     ewk_view_orientation_lock_callback_set(
542         wkView,
543         orientationLockCallback,
544         this);
545 }
546
547 void ViewLogic::ewkClientDeinit(Evas_Object *wkView)
548 {
549     LogDebug("ewkClientDeinit");
550     Assert(NULL != wkView && "ewk_view not created at this point");
551
552     FOREACH(it, m_ewkCallbacksMap) {
553         evas_object_smart_callback_del(
554             wkView,
555             it->first.c_str(),
556             it->second);
557     }
558     ewk_view_orientation_lock_callback_set(
559         wkView,
560         NULL,
561         NULL);
562 }
563
564 bool ViewLogic::createEwkView(Evas* canvas)
565 {
566     LogDebug("createEwkVeiw");
567     Assert(canvas);
568     ADD_PROFILING_POINT("ewk_view_add_with_context", "start");
569     Evas_Object* newEwkView = ewk_view_add_with_context(
570             canvas,
571             m_ewkContext);
572     ADD_PROFILING_POINT("ewk_view_add_with_context", "stop");
573
574     if (!newEwkView) {
575         LogError("View creation failed");
576         Wrt::Popup::PopupInvoker().showInfo(
577             "Info", "View creation failed", "close");
578         return false;
579     }
580
581     // set cookie policy
582     // even arguments pass the ewkContext, this API should be called
583     // after webkit Evas_Object is created
584     Ewk_Cookie_Manager *ewkCookieManager;
585     ewkCookieManager =
586         ewk_context_cookie_manager_get(m_ewkContext);
587     ewk_cookie_manager_accept_policy_set(ewkCookieManager,
588                                          EWK_COOKIE_ACCEPT_POLICY_ALWAYS);
589
590     if (m_currentEwkView) {
591         setEwkViewInvisible(m_currentEwkView);
592     }
593
594     LogInfo("push webview: " << newEwkView);
595     m_ewkViewList.push_back(newEwkView);
596     m_currentEwkView = newEwkView;
597     return true;
598 }
599
600 void ViewLogic::setStartPage()
601 {
602     /* Start URI (as other uris) is now localized
603      * on WebProcess side */
604     m_currentUri = ViewModule::UriSupport::getUri(m_model, m_startUrl);
605 }
606
607 void ViewLogic::prepareEwkView(Evas_Object *wkView)
608 {
609     LogDebug("prepareEwkView called");
610     Assert(wkView);
611     Ewk_Settings* settings = ewk_view_settings_get(wkView);
612
613     // set user agent
614     std::string customUserAgent = m_model->SettingList.Get().getUserAgent();
615     if (customUserAgent.empty()) {
616         auto userAgentString =
617             ViewModule::UserAgentSupport::getUserAgentFromVconf();
618         if (!userAgentString.empty()) {
619             LogDebug("Setting user agent as: " << userAgentString);
620             ewk_view_user_agent_set(wkView, userAgentString.c_str());
621         }
622     } else {
623         LogDebug("Setting  custom user agent as: " << customUserAgent);
624         ewk_view_user_agent_set(wkView, customUserAgent.c_str());
625     }
626
627     // set custom header : language
628     using namespace ViewModule::CustomHeaderSupport;
629     std::string customHeaderString = getValueByField(ACCEPT_LANGUAGE);
630     if (!customHeaderString.empty()) {
631         LogDebug("custom field=[" << ACCEPT_LANGUAGE << "]");
632         LogDebug("custom value=[" << customHeaderString << "]");
633         ewk_view_custom_header_add(wkView,
634                                    ACCEPT_LANGUAGE.c_str(),
635                                    customHeaderString.c_str());
636     }
637
638     // webkit NPAPI plugins is always on in wrt
639     ewk_settings_plugins_enabled_set(settings, EINA_TRUE);
640
641     // The followings are not implemeted yet by webkit2
642     //      ewk_view_setting_accelerated_compositing_enable_set(EINA_TRUE);
643     //      ewk_view_mode_set();
644     //      ewk_view_setting_enable_specified_plugin_set(EINA_TRUE,
645     // FLASH_MIME_TYPE);
646     //      ewk_view_setting_html5video_external_player_enable_set(EINA_FALSE);
647     //      ewk_view_show_ime_on_autofocus_set(EINA_TRUE);
648     //      elm_webview_show_magnifier_set(EINA_FALSE);
649     ewk_settings_javascript_enabled_set(settings, EINA_TRUE);
650     ewk_settings_loads_images_automatically_set(settings, EINA_TRUE);
651     // WRT should not fit web contents to device width automatically as default.
652     // Fitting to device width should be handled by web content using viewport meta tag.
653     ewk_settings_auto_fitting_set(settings, EINA_FALSE);
654
655     // disable zoom option when user click the input field
656     // this option is useful with the normal website
657     // for the make user friendly, disable auto zoom in the webapp
658     // The followings are not implemeted yet by webkit2
659     //      elm_webview_input_field_zoom_set(EINA_FALSE);
660
661     // set cookie database path
662     // The followings are not implemeted yet by webkit2
663     //      ewk_cookies_file_set(dao.getCookieDatabasePath().c_str()));
664
665     // set visibility to WebCore. This value will be used for html5.
666     // also, this value will be changed in the suspend, resume
667     // or create window, close window.
668     ewk_view_page_visibility_state_set(wkView,
669                                        EWK_PAGE_VISIBILITY_STATE_VISIBLE,
670                                        EINA_TRUE);
671 }
672
673 void ViewLogic::removeEwkView(Evas_Object *wkView)
674 {
675     LogInfo("removeEwkView called");
676     Assert(wkView);
677     Assert(0 != m_ewkViewList.size());
678
679     // unregister webview callbacks
680     ewkClientDeinit(wkView);
681
682     // suspend NPAPI plugin - Not implemented by Webkit2
683     //    ewk_view_pause_or_resume_plugins();
684     evas_object_del(wkView);
685     m_ewkViewList.remove(wkView);
686 }
687
688 void ViewLogic::resumeEwkView(Evas_Object *wkView)
689 {
690     LogInfo("resumeEwkView called");
691     Assert(wkView);
692
693     // register webview callback
694     ewkClientInit(wkView);
695
696     // resume webkit
697     resumeWebkit(wkView);
698
699     return;
700 }
701
702 void ViewLogic::suspendEwkView(Evas_Object *wkView)
703 {
704     LogInfo("suspendEwkView called");
705     Assert(wkView);
706
707     // suspend webkit
708     suspendWebkit(wkView);
709
710     // unregister webview callbacks
711     ewkClientDeinit(wkView);
712
713     return;
714 }
715
716 void ViewLogic::setEwkViewInvisible(Evas_Object *wkView)
717 {
718     LogInfo("setEwkViewInvisible called");
719     Assert(wkView);
720
721     ewk_view_page_visibility_state_set(wkView,
722                                        EWK_PAGE_VISIBILITY_STATE_HIDDEN,
723                                        EINA_FALSE);
724     ewk_view_visibility_set(wkView, EINA_FALSE);
725 }
726
727 void ViewLogic::setEwkViewVisible(Evas_Object *wkView)
728 {
729     LogInfo("setEwkViewVisible called");
730     Assert(wkView);
731
732     ewk_view_page_visibility_state_set(wkView,
733                                        EWK_PAGE_VISIBILITY_STATE_VISIBLE,
734                                        EINA_FALSE);
735     ewk_view_visibility_set(wkView, EINA_TRUE);
736 }
737
738 void ViewLogic::resumeWebkit(Evas_Object *wkView)
739 {
740     LogDebug("resumeWebkit");
741     Assert(wkView);
742
743     // resume NPAPI plugin
744     // The followings are not implemeted yet by webkit2
745     //      ewk_view_pause_or_resume_plugins(false);
746     //      ewk_view_pause_or_resume_video_audio(false);
747     //      ewk_view_javascript_resume();
748     //      ewk_view_enable_render();
749     //      ewk_view_reduce_plugins_frame_rate(false);
750     ewk_view_resume(wkView);
751
752     return;
753 }
754
755 void ViewLogic::suspendWebkit(Evas_Object *wkView)
756 {
757     LogDebug("suspendWebkit");
758     Assert(wkView);
759
760     // suspend the followings
761     // The followings are not implemeted yet by webkit2
762     //      ewk_view_pause_or_resume_plugins(true);
763     //      ewk_view_pause_or_resume_video_audio(true);
764     ewk_view_suspend(wkView);
765
766     return;
767 }
768
769 void ViewLogic::loadStartedCallback(
770     void* data,
771     Evas_Object* obj,
772     void* /*eventInfo*/)
773 {
774     LogDebug("loadStartedCallback called");
775     Assert(data);
776     ViewLogic* This = static_cast<ViewLogic*>(data);
777     evas_object_focus_set(This->m_currentEwkView, EINA_TRUE);
778
779     // call loadFinish callback to wrt-client
780     if (!This->m_cbs->loadStart.empty()) {
781         This->m_cbs->loadStart(obj);
782     }
783 }
784
785 void ViewLogic::loadFinishedCallback(
786     void* data,
787     Evas_Object* obj,
788     void* /*eventInfo*/)
789 {
790     LogDebug("loadFinishedCallback called");
791     Assert(data);
792     ViewLogic* This = static_cast<ViewLogic*>(data);
793
794     // Fill id/password
795     const char* url = ewk_view_url_get(This->m_currentEwkView);
796     if (NULL == url || strlen(url) == 0) {
797         LogError("url is empty");
798         return;
799     }
800
801     // check if this loading is for blocked url
802     if (This->m_blockedUri == url) {
803         if (ewk_view_back_possible(This->m_currentEwkView)) {
804             // go back to previous page
805             LogDebug("go to previous page");
806             ewk_view_back(This->m_currentEwkView);
807         } else {
808             // stop current page
809             LogDebug("remove current page");
810             ewk_view_stop(This->m_currentEwkView);
811             ecore_idler_add(windowCloseIdlerCallback, This);
812         }
813         This->m_blockedUri = std::string();
814         return;
815     }
816
817     DPL::OptionalString jsOptionalString =
818         ViewModule::PasswordSupport::jsForAutoFillData(url);
819     if (jsOptionalString.IsNull()) {
820         LogError("Fail to get JS String");
821     } else {
822         std::string jsStr = DPL::ToUTF8String(*jsOptionalString).c_str();
823
824         if (EINA_FALSE == ewk_view_script_execute(
825                 This->m_currentEwkView,
826                 jsStr.c_str(),
827                 didRunJavaScriptCallback,
828                 This))
829         {
830             LogError("JS for auto fill data failed.");
831         }
832     }
833
834     // call loadFinish callback to wrt-client
835     if (!This->m_cbs->loadFinish.empty()) {
836         This->m_cbs->loadFinish(obj);
837     }
838
839     // set only encoded bundle
840     double scale = elm_config_scale_get();
841     PluginModuleSupport::setCustomProperties(
842         This->m_ewkContext,
843         &scale,
844         ApplicationDataSingleton::Instance().getEncodedBundle());
845     // check if 'appsevice' event is registed at the current frames.
846     // If so, dispatch the event to frames.
847     PluginModuleSupport::dispatchJavaScriptEvent(
848         This->m_ewkContext,
849         WrtPlugins::W3C::ServiceCustomEvent,
850         NULL);
851
852     // In this case, widget is reloaded in the background.
853     // After finished load, bundle should disconnent callback.
854     if (This->m_isBackgroundReload) {
855         ewk_view_suspend(This->m_currentEwkView);
856         This->m_isBackgroundReload = false;
857     }
858 }
859
860 void ViewLogic::titleChangedCallback(
861     void* data,
862     Evas_Object* /*obj*/,
863     void* eventInfo)
864 {
865     LogDebug("titleChangedCallback called");
866     Assert(data);
867     ViewLogic* This = static_cast<ViewLogic*>(data);
868     Assert(eventInfo);
869     const char* title = static_cast<char*>(eventInfo);
870
871     if (0 == strlen(title)) {
872         LogDebug("title data is empty");
873         return;
874     }
875     LogDebug("Title = [" << title << "]");
876     This->m_schemeSupport->HandleTizenScheme(title,
877                                              This->m_window,
878                                              This->m_currentEwkView);
879 }
880
881 void ViewLogic::loadProgressCallback(
882     void* /*data*/,
883     Evas_Object* /*obj*/,
884     void* eventInfo)
885 {
886     double* progress = static_cast<double*>(eventInfo);
887     LogDebug("didChangeProgressCallback progress = " << *progress);
888 }
889
890 void ViewLogic::loadProgressFinishedCallback(
891     void* data,
892     Evas_Object* /*obj*/,
893     void* /*eventInfo*/)
894 {
895     LogDebug("didFinishProgressCallback");
896     Assert(data);
897     ViewLogic const * const view = static_cast<ViewLogic const * const>(data);
898     if (!view->m_cbs->progressFinish.empty()) {
899         view->m_cbs->progressFinish();
900     }
901 }
902
903 void ViewLogic::processCrashedCallback(
904     void* data,
905     Evas_Object* /*obj*/,
906     void* eventInfo)
907 {
908     LogInfo("processCrashedCallback");
909     Assert(data);
910     ViewLogic const * const view =
911         static_cast<ViewLogic const * const>(data);
912     if (!view->m_cbs->webCrash.empty()) {
913         view->m_cbs->webCrash();
914     }
915     // This flag will be prevented exit() call in the Webkit side
916     if (NULL != eventInfo) {
917         *(static_cast<Eina_Bool*>(eventInfo)) = EINA_TRUE;
918     }
919 }
920
921 void ViewLogic::createWindowCallback(
922     void* data,
923     Evas_Object* obj,
924     void* eventInfo)
925 {
926     LogDebug("createWindowCallback");
927     Assert(data);
928     ViewLogic* This = static_cast<ViewLogic*>(data);
929
930     // First, current webview should be handled by user callback
931     if (!This->m_cbs->bufferUnset.empty()) {
932         This->m_cbs->bufferUnset(obj);
933     }
934
935     // this can be set by executable for specific purpose
936     Evas* canvas = NULL;
937     if (!This->m_cbs->windowCreateBefore.empty()) {
938         // 'obj' is parent webview object
939         This->m_cbs->windowCreateBefore(&canvas, obj);
940     }
941     if (!canvas) {
942         canvas = evas_object_evas_get(This->m_window);
943     }
944
945     // create new ewkview
946     This->createEwkView(canvas);
947     Evas_Object* newEwkView = This->m_currentEwkView;
948
949     // initialize new ewkview
950     This->setStartPage();
951     This->ewkClientInit(newEwkView);
952     This->prepareEwkView(newEwkView);
953
954     // Specific jobs of child, parent webview are handled by each executable
955     if (!This->m_cbs->windowCreateAfter.empty()) {
956         // 'obj' is parent webview, 'newEwkView' is child webview
957         This->m_cbs->windowCreateAfter(obj, newEwkView);
958     }
959
960     // Lastly, new webview should be handled by user callback
961     if (!This->m_cbs->bufferSet.empty()) {
962         This->m_cbs->bufferSet(newEwkView);
963     }
964     *(static_cast<Evas_Object **>(eventInfo)) = newEwkView;
965 }
966
967 void ViewLogic::closeWindowCallback(
968     void* data,
969     Evas_Object* obj,
970     void* /*eventInfo*/)
971 {
972     LogDebug("closeWindowCallback");
973     ViewLogic* This = static_cast<ViewLogic*>(data);
974     This->m_closedEwkView = obj;
975     ecore_idler_add(windowCloseIdlerCallback, This);
976 }
977
978 void ViewLogic::policyNavigationDecideCallback(
979     void* data,
980     Evas_Object* /*obj*/,
981     void* eventInfo)
982 {
983     LogDebug("policyNavigationDecideCallback called");
984     Assert(data);
985     ViewLogic* This = static_cast<ViewLogic*>(data);
986     Assert(eventInfo);
987     Ewk_Policy_Decision* policyDecision =
988         static_cast<Ewk_Policy_Decision*>(eventInfo);
989
990     if (This->m_schemeSupport->filterURIByScheme(policyDecision,
991                                                  false,
992                                                  This->m_model,
993                                                  This->m_window,
994                                                  This->m_currentEwkView))
995     {
996         LogDebug("use");
997         ewk_policy_decision_use(policyDecision);
998     } else {
999         // check whether this is new empty window
1000         const char* activeUrl = ewk_view_url_get(This->m_currentEwkView);
1001         if (!activeUrl || 0 == strlen(activeUrl)) {
1002             /*
1003              * The view is empty and scheme has been handled externally. When
1004              * user gets back from the external application he'd see blank page
1005              * and won't be able to navigate back. This happens when window.open
1006              * is used to handle schemes like sms/mms/mailto (for example in
1007              * WAC web standards tests: WS-15XX).
1008              *
1009              * To solve the problem, the empty view is removed from the stack
1010              * and the previous one is shown. This is not an elegant solution
1011              * but we don't have a better one.
1012              */
1013             LogInfo("Scheme has been handled externally. Removing empty view.");
1014             if (ewk_view_back_possible(This->m_currentEwkView)) {
1015                 // go back to previous WKPage
1016                 ewk_view_back(This->m_currentEwkView);
1017             } else {
1018                 // stop current WKPage
1019                 ewk_view_stop(This->m_currentEwkView);
1020                 ecore_idler_add(windowCloseIdlerCallback, This);
1021             }
1022         }
1023
1024         LogDebug("ignore");
1025         ewk_policy_decision_ignore(policyDecision);
1026     }
1027 }
1028
1029 void ViewLogic::policyNewWindowDecideCallback(
1030     void* data,
1031     Evas_Object* /*obj*/,
1032     void* eventInfo)
1033 {
1034     LogDebug("policyNewWindowDecideCallback called");
1035     Assert(data);
1036     ViewLogic* This = static_cast<ViewLogic*>(data);
1037     Assert(eventInfo);
1038     Ewk_Policy_Decision* policyDecision =
1039         static_cast<Ewk_Policy_Decision*>(eventInfo);
1040
1041     if (This->m_schemeSupport->filterURIByScheme(policyDecision,
1042                                                  true,
1043                                                  This->m_model,
1044                                                  This->m_window,
1045                                                  This->m_currentEwkView))
1046     {
1047         ewk_policy_decision_use(policyDecision);
1048     } else {
1049         // scheme handled
1050         ewk_policy_decision_ignore(policyDecision);
1051     }
1052 }
1053
1054 void ViewLogic::pageResponseDecideCallback(
1055     void* data,
1056     Evas_Object* /*obj*/,
1057     void* eventInfo)
1058 {
1059     LogDebug("pageResponseDecideCallback called");
1060     Assert(data);
1061     ViewLogic* This = static_cast<ViewLogic*>(data);
1062     Assert(eventInfo);
1063     Ewk_Policy_Decision* policyDecision =
1064         static_cast<Ewk_Policy_Decision*>(eventInfo);
1065     Ewk_Policy_Decision_Type policyDecisionType =
1066         ewk_policy_decision_type_get(policyDecision);
1067
1068     if (policyDecisionType == EWK_POLICY_DECISION_USE) {
1069         LogDebug("use");
1070         ewk_policy_decision_use(policyDecision);
1071     } else if (policyDecisionType == EWK_POLICY_DECISION_DOWNLOAD) {
1072         LogDebug("download");
1073         ewk_policy_decision_suspend(policyDecision);
1074
1075         // get uri information
1076         const char* url = ewk_policy_decision_url_get(policyDecision);
1077         if (NULL == url || strlen(url) == 0) {
1078             LogDebug("url data is empty");
1079             ewk_policy_decision_use(policyDecision);
1080             return;
1081         }
1082         LogDebug("url = [" << url << "]");
1083
1084         // get content information
1085         const char* content =
1086             ewk_policy_decision_response_mime_get(policyDecision);
1087         LogDebug("content type = [" << content << "]");
1088
1089         // get cookie information
1090         const char* cookie = ewk_policy_decision_cookie_get(policyDecision);
1091         LogDebug("cookie = [" << cookie << "]");
1092
1093         LogDebug("Content not supported, will be opened in external app");
1094         This->m_appsSupport->downloadRequest(
1095             url,
1096             content,
1097             cookie);
1098         ewk_policy_decision_ignore(policyDecision);
1099     } else if (policyDecisionType == EWK_POLICY_DECISION_IGNORE) {
1100         LogDebug("ignore");
1101         ewk_policy_decision_ignore(policyDecision);
1102     } else {
1103         LogDebug("Type isn't handled");
1104         ewk_policy_decision_ignore(policyDecision);
1105     }
1106 }
1107
1108 void ViewLogic::contextmenuCustomizeCallback(
1109     void* data,
1110     Evas_Object* /*obj*/,
1111     void* eventInfo)
1112 {
1113     LogDebug("contextmenuCustomizeCallback called");
1114     Assert(data);
1115     Assert(eventInfo);
1116     ViewLogic* This = static_cast<ViewLogic*>(const_cast<void*>(data));
1117     Ewk_Context_Menu* menu = static_cast<Ewk_Context_Menu*>(eventInfo);
1118     if ((This->m_model->Type.Get().appType == WrtDB::APP_TYPE_TIZENWEBAPP) &&
1119         (This->m_model->SettingList.Get().getContextMenu()
1120          == ContextMenu_Disable))
1121     {
1122         LogDebug("ContextMenu Disable!!");
1123         for (unsigned int idx = 0; idx < ewk_context_menu_item_count(menu);) {
1124             Ewk_Context_Menu_Item* item = ewk_context_menu_nth_item_get(menu,
1125                                                                         idx);
1126             Assert(item);
1127             ewk_context_menu_item_remove(menu, item);
1128         }
1129     } else {
1130         LogDebug("ContextMenu Enable!!");
1131         unsigned int menu_num = ewk_context_menu_item_count(menu);
1132         unsigned int idx = 0;
1133         do {
1134             Ewk_Context_Menu_Item* item = ewk_context_menu_nth_item_get(menu,
1135                                                                         idx);
1136             if (!item) {
1137                 idx++;
1138                 continue;
1139             }
1140             Ewk_Context_Menu_Item_Tag tag = ewk_context_menu_item_tag_get(item);
1141
1142             switch (tag) {
1143             case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_IMAGE_IN_NEW_WINDOW:
1144                 ewk_context_menu_item_remove(menu, item);
1145                 continue;
1146
1147             case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_LINK_IN_NEW_WINDOW:
1148                 ewk_context_menu_item_remove(menu, item);
1149                 continue;
1150
1151             case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_FRAME_IN_NEW_WINDOW:
1152                 ewk_context_menu_item_remove(menu, item);
1153                 continue;
1154
1155             case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_MEDIA_IN_NEW_WINDOW:
1156                 ewk_context_menu_item_remove(menu, item);
1157                 continue;
1158
1159             case EWK_CONTEXT_MENU_ITEM_TAG_SEARCH_WEB:
1160                 ewk_context_menu_item_remove(menu, item);
1161                 continue;
1162
1163             default:
1164                 idx++;
1165                 break;
1166             }
1167         } while (idx < menu_num);
1168     }
1169 }
1170
1171 void ViewLogic::formSubmitCallback(
1172     void* /*data*/,
1173     Evas_Object* /*obj*/,
1174     void* eventInfo)
1175 {
1176     LogDebug("formSubmitCallback called");
1177     Assert(eventInfo);
1178     Ewk_Form_Data* formData = static_cast<Ewk_Form_Data*>(eventInfo);
1179
1180     const char* uri = ewk_form_data_url_get(formData);
1181     if (!uri) {
1182         LogError("URL is empty");
1183         return;
1184     }
1185
1186     Eina_Hash* userData = ewk_form_data_values_get(formData);
1187     ViewModule::PasswordSupport::submitClicked(uri, userData);
1188 }
1189
1190 void ViewLogic::geolocationPermissionRequestCallback(
1191     void* data,
1192     Evas_Object* /*obj*/,
1193     void* eventInfo)
1194 {
1195     Assert(data);
1196     ViewLogic* This = static_cast<ViewLogic*>(data);
1197     Assert(eventInfo);
1198     Ewk_Geolocation_Permission_Request* permissionRequest =
1199         static_cast<Ewk_Geolocation_Permission_Request*>(eventInfo);
1200
1201     if (This->m_securityOriginSupport->isNeedPermissionCheck(
1202             SecurityOriginDB::FEATURE_GEOLOCATION)
1203         == WrtDB::SETTINGS_TYPE_OFF)
1204     {
1205         ewk_geolocation_permission_request_set(permissionRequest, EINA_FALSE);
1206         return;
1207     }
1208     ViewModule::GeolocationSupport::Webkit2::geolocationPermissionRequest(
1209         This->m_window,
1210         This->m_securityOriginSupport->getSecurityOriginDAO(),
1211         eventInfo);
1212 }
1213
1214 void ViewLogic::notificationShowCallback(
1215     void* data,
1216     Evas_Object* /*obj*/,
1217     void* eventInfo)
1218 {
1219     LogDebug("notificationShowCallback called");
1220     Assert(data);
1221     ViewLogic* This = static_cast<ViewLogic*>(data);
1222
1223     Assert(eventInfo);
1224     Ewk_Notification* noti = static_cast<Ewk_Notification*>(eventInfo);
1225
1226     using namespace ViewModule::WebNotification;
1227
1228     WebNotificationDataPtr notiData(
1229         new WebNotificationData(
1230             This->m_model,
1231             ewk_notification_id_get(noti)));
1232
1233     DPL::OptionalString string =
1234         DPL::FromUTF8String(ewk_notification_icon_url_get(noti));
1235     if (!string.IsNull()) {
1236         notiData->m_iconURL = DPL::ToUTF8String(*string);
1237     }
1238     string = DPL::FromUTF8String(ewk_notification_title_get(noti));
1239     if (!string.IsNull()) {
1240         notiData->m_title = DPL::ToUTF8String(*string);
1241     }
1242     string = DPL::FromUTF8String(ewk_notification_body_get(noti));
1243     if (!string.IsNull()) {
1244         notiData->m_body = DPL::ToUTF8String(*string);
1245     }
1246
1247     LogInfo("notification id : " << notiData->m_id);
1248     LogInfo("notification iconURL : " << notiData->m_iconURL);
1249     LogInfo("notification title : " << notiData->m_title);
1250     LogInfo("notification body : " << notiData->m_body);
1251
1252     showWebNotification(notiData);
1253     ewk_notification_showed(This->m_ewkContext, ewk_notification_id_get(noti));
1254 }
1255
1256 void ViewLogic::notificationCancelCallback(
1257     void* /*data*/,
1258     Evas_Object* /*obj*/,
1259     void* /*eventInfo*/)
1260 {
1261     LogDebug("notificationCancelCallback called");
1262 }
1263
1264 void ViewLogic::notificationPermissionRequestCallback(
1265     void* data,
1266     Evas_Object* /*obj*/,
1267     void* eventInfo)
1268 {
1269     LogDebug("notificationPermissionRequestCallback called");
1270     Assert(data);
1271     ViewLogic* This = static_cast<ViewLogic*>(data);
1272     if (This->m_securityOriginSupport->isNeedPermissionCheck(
1273             SecurityOriginDB::FEATURE_WEB_NOTIFICATION)
1274         == WrtDB::SETTINGS_TYPE_OFF)
1275     {
1276         Ewk_Notification_Permission_Request* request =
1277             static_cast<Ewk_Notification_Permission_Request*>(eventInfo);
1278         ewk_notification_permission_request_set(
1279             request,
1280             EINA_FALSE);
1281         return;
1282     }
1283
1284     Assert(eventInfo);
1285     ViewModule::WebNotification::webNotificationPermissionRequest(
1286         This->m_window,
1287         This->m_securityOriginSupport->getSecurityOriginDAO(),
1288         eventInfo);
1289     return;
1290 }
1291
1292 // EWK Orientation Callback
1293 Eina_Bool ViewLogic::orientationLockCallback(
1294     Evas_Object* obj,
1295     Eina_Bool /*needLock*/,
1296     int orientation,
1297     void* data)
1298 {
1299     LogDebug("orientationLockCallback called");
1300     Assert(data);
1301     ViewLogic* This = static_cast<ViewLogic*>(data);
1302
1303     if (orientation & EWK_SCREEN_ORIENTATION_PORTRAIT_PRIMARY) {
1304         LogDebug("orientation is portrait-primary");
1305         elm_win_rotation_with_resize_set(This->m_window, 0);
1306         ewk_view_orientation_send(obj, 0);
1307     } else if (orientation & EWK_SCREEN_ORIENTATION_LANDSCAPE_PRIMARY) {
1308         LogDebug("orientation is landscape-primary");
1309         elm_win_rotation_with_resize_set(This->m_window, 270);
1310         ewk_view_orientation_send(obj, 90);
1311     } else if (orientation & EWK_SCREEN_ORIENTATION_PORTRAIT_SECONDARY) {
1312         LogDebug("orientation is portrait-secondary");
1313         elm_win_rotation_with_resize_set(This->m_window, 180);
1314         ewk_view_orientation_send(obj, 180);
1315     } else if (orientation & EWK_SCREEN_ORIENTATION_LANDSCAPE_SECONDARY) {
1316         LogDebug("orientation is landscape-secondary");
1317         elm_win_rotation_with_resize_set(This->m_window, 90);
1318         ewk_view_orientation_send(obj, -90);
1319     } else {
1320         LogDebug("Wrong orientation is set");
1321         return EINA_FALSE;
1322     }
1323     return EINA_TRUE;
1324 }
1325
1326 // Fullscreen API callbacks
1327 void ViewLogic::enterFullscreenCallback(
1328     void* data,
1329     Evas_Object* /*obj*/,
1330     void* /*eventInfo*/)
1331 {
1332     LogInfo("enterFullscreenCallback called");
1333     Assert(data);
1334     ViewLogic* This = static_cast<ViewLogic*>(data);
1335     if (!This->m_cbs->toggleFullscreen.empty()) {
1336         This->m_cbs->toggleFullscreen(true);
1337     }
1338 }
1339 void ViewLogic::exitFullscreenCallback(
1340     void* data,
1341     Evas_Object* /*obj*/,
1342     void* /*eventInfo*/)
1343 {
1344     LogInfo("exitFullscreenCallback called");
1345     Assert(data);
1346     ViewLogic* This = static_cast<ViewLogic*>(data);
1347     if (!This->m_cbs->toggleFullscreen.empty()) {
1348         This->m_cbs->toggleFullscreen(false);
1349     }
1350 }
1351
1352 void ViewLogic::imeChangedCallback(
1353     void* data,
1354     Evas_Object* /*obj*/,
1355     void* eventInfo)
1356 {
1357     LogDebug("enter");
1358     Assert(data);
1359     Assert(eventInfo);
1360     ViewLogic* This = static_cast<ViewLogic*>(data);
1361     Eina_Rectangle *rect = static_cast<Eina_Rectangle *>(eventInfo);
1362     This->m_imeWidth = rect->w;
1363     This->m_imeHeight = rect->h;
1364 }
1365
1366 void ViewLogic::imeOpenedCallback(
1367     void* data,
1368     Evas_Object* /*obj*/,
1369     void* /*eventInfo*/)
1370 {
1371     LogDebug("enter");
1372     Assert(data);
1373     ViewLogic* This = static_cast<ViewLogic*>(data);
1374
1375     using namespace WrtPlugins::W3C;
1376     SoftKeyboardChangeArgs args;
1377     args.state = IME_STATE_ON;
1378     args.width = This->m_imeWidth;
1379     args.height = This->m_imeHeight;
1380     This->fireJavascriptEvent(
1381         static_cast<int>(SoftKeyboardChangeCustomEvent),
1382         &args);
1383 }
1384
1385 void ViewLogic::imeClosedCallback(
1386     void* data,
1387     Evas_Object* /*obj*/,
1388     void* /*eventInfo*/)
1389 {
1390     LogDebug("enter");
1391     Assert(data);
1392     ViewLogic* This = static_cast<ViewLogic*>(data);
1393
1394     using namespace WrtPlugins::W3C;
1395     SoftKeyboardChangeArgs args;
1396     args.state = IME_STATE_OFF;
1397
1398     This->fireJavascriptEvent(
1399         static_cast<int>(SoftKeyboardChangeCustomEvent),
1400         &args);
1401 }
1402
1403 void ViewLogic::usermediaPermissionRequestCallback(
1404     void* data,
1405     Evas_Object* /*obj*/,
1406     void* eventInfo)
1407 {
1408     LogDebug("usermediaPermissionRequestCallback called");
1409     Assert(data);
1410     ViewLogic* This = static_cast<ViewLogic*>(data);
1411     ViewModule::UsermediaSupport::usermediaPermissionRequest(This->m_window,
1412                                                              eventInfo);
1413 }
1414
1415 // helper method
1416 CustomHandlerDB::CustomHandlerPtr getCustomHandlerFromData(void* data)
1417 {
1418     Assert(data);
1419     Ewk_Custom_Handlers_Data* handler =
1420         static_cast<Ewk_Custom_Handlers_Data*>(data);
1421     CustomHandlerDB::CustomHandlerPtr customHandler(
1422         new CustomHandlerDB::CustomHandler());
1423     const char* base_url = ewk_custom_handlers_data_base_url_get(handler);
1424     if (base_url) {
1425         LogDebug("base url: " << base_url);
1426         customHandler->base_url = DPL::FromASCIIString(string(base_url));
1427     }
1428     const char* url = ewk_custom_handlers_data_url_get(handler);
1429     if (url) {
1430         LogDebug("url: " << url);
1431         customHandler->url = DPL::FromASCIIString(string(url));
1432     }
1433     const char* target = ewk_custom_handlers_data_target_get(handler);
1434     if (target) {
1435         LogDebug("target: " << target);
1436         customHandler->target = DPL::FromASCIIString(string(target));
1437     }
1438     const char* title = ewk_custom_handlers_data_title_get(handler);
1439     if (title) {
1440         LogDebug("title: " << title);
1441         customHandler->title = DPL::FromASCIIString(string(title));
1442     }
1443     return customHandler;
1444 }
1445
1446 void ViewLogic::attachToCustomHandlersDao()
1447 {
1448     if (!m_attachedToCustomHandlerDao) {
1449         CustomHandlerDB::Interface::attachDatabaseRW();
1450     }
1451 }
1452
1453 void ViewLogic::detachFromCustomHandlersDao()
1454 {
1455     if (m_attachedToCustomHandlerDao) {
1456         CustomHandlerDB::Interface::detachDatabase();
1457     }
1458 }
1459
1460 const int protocolWhiteListLenth = 15;
1461 char const * const protocolWhiteList[protocolWhiteListLenth] = {
1462     "irc",
1463     "geo",
1464     "mailto",
1465     "magnet",
1466     "mms",
1467     "news",
1468     "nntp",
1469     "sip",
1470     "sms",
1471     "smsto",
1472     "ssh",
1473     "tel",
1474     "urn",
1475     "webcal",
1476     "xmpp"
1477 };
1478
1479 const int contentBlackListLenth = 14;
1480 char const * const contentBlackList[contentBlackListLenth] = {
1481     "application/x-www-form-urlencoded",
1482     "application/xhtml+xml",
1483     "application/xml",
1484     "image/gif",
1485     "image/jpeg",
1486     "image/png",
1487     "image/svg+xml",
1488     "multipart/x-mixed-replace",
1489     "text/cache-manifest",
1490     "text/css",
1491     "text/html",
1492     "text/ping",
1493     "text/plain",
1494     "text/xml"
1495 };
1496
1497 /**
1498  * Saves user's response from popup to custom handler. Saves Yes/No and remember
1499  * state.
1500  * @param response
1501  * @param customHandler
1502  */
1503 void saveUserResponse(Wrt::Popup::PopupResponse response,
1504                       CustomHandlerDB::CustomHandlerPtr customHandler)
1505 {
1506     switch (response) {
1507     case Wrt::Popup::YES_DO_REMEMBER:
1508         LogDebug("User allowed, remember");
1509         customHandler->user_decision =
1510             static_cast<CustomHandlerDB::HandlerState>
1511             (CustomHandlerDB::Agreed | CustomHandlerDB::DecisionSaved);
1512         break;
1513     case Wrt::Popup::YES_DONT_REMEMBER:
1514         LogDebug("User allowed, don't remember");
1515         customHandler->user_decision = CustomHandlerDB::Agreed;
1516         break;
1517     case Wrt::Popup::NO_DO_REMEMBER:
1518         LogDebug("User didn't allow, remember");
1519         customHandler->user_decision =
1520             static_cast<CustomHandlerDB::HandlerState>
1521             (CustomHandlerDB::Declined | CustomHandlerDB::DecisionSaved);
1522         break;
1523     case Wrt::Popup::NO_DONT_REMEMBER:
1524         LogDebug("User didn't allow, don't remember");
1525         customHandler->user_decision = CustomHandlerDB::Declined;
1526         break;
1527     }
1528 }
1529
1530 //TODO registration, checking if registered and unregistration can be done in
1531 //common functions for both types of handlers. Only white and black lists
1532 //have to be separated
1533 //TODO attach database only one at the start (not in every callback?)
1534 void ViewLogic::protocolHandlerRegistrationCallback(void* data,
1535                                                     Evas_Object* /*obj*/,
1536                                                     void* eventInfo)
1537 {
1538     Assert(data);
1539     LogDebug("enter");
1540     CustomHandlerDB::CustomHandlerPtr customHandler =
1541         getCustomHandlerFromData(eventInfo);
1542
1543     std::string scheme = DPL::ToUTF8String(customHandler->target);
1544     if (scheme.empty()) {
1545         LogError("No scheme provided");
1546         //TODO what about securityError?
1547         return;
1548     }
1549     bool matched = false;
1550     //scheme on whiteList
1551     for (int i = 0; i < protocolWhiteListLenth; ++i) {
1552         if (0 == strcmp(protocolWhiteList[i], scheme.c_str())) {
1553             LogDebug("Match found, protocol can be handled");
1554             matched = true;
1555         }
1556     }
1557     if (!matched) {
1558         //starts with web+ and have at least 5 chars (lowercase ASCII)
1559         if (strncmp("web+", scheme.c_str(), 4) || scheme.length() < 5) {
1560             LogWarning("Scheme neither on whitelist nor starts with \"web+\"");
1561             //throw SecurityException
1562             return;
1563         }
1564         int l = 4;
1565         char c = scheme[l];
1566         while (c != '\0') {
1567             if (c < 'a' || c > 'z') {
1568                 LogWarning("Wrong char inside scheme. "
1569                            << "Only lowercase ASCII letters accepted");
1570                 //throw SecurityException
1571                 return;
1572             }
1573             c = scheme[++l];
1574         }
1575     }
1576
1577     ViewLogic* This = static_cast<ViewLogic*>(data);
1578     LogDebug("Creating handlers dao");
1579     This->attachToCustomHandlersDao();
1580     CustomHandlerDB::CustomHandlerDAO handlersDao(This->m_model->TizenId);
1581     CustomHandlerDB::CustomHandlerPtr handler =
1582         handlersDao.getProtocolHandler(customHandler->target,
1583                                        customHandler->url,
1584                                        customHandler->base_url);
1585     if (handler && (handler->user_decision & CustomHandlerDB::DecisionSaved)) {
1586         LogDebug("Protocol already registered - nothing to do");
1587     } else {
1588         LogDebug("Protocol handler not found");
1589         Wrt::Popup::PopupResponse response =
1590             GlobalSettings::PopupsTestModeEnabled() ? Wrt::Popup::
1591                 YES_DO_REMEMBER :
1592             Wrt::Popup::PopupInvoker().askYesNoCheckbox(
1593                 PROTOCOL_HANDLER_ASK_TITLE,
1594                 PROTOCOL_HANDLER_ASK_MSG,
1595                 PROTOCOL_HANDLER_ASK_REMEMBER);
1596         saveUserResponse(response, customHandler);
1597         if (customHandler->user_decision == CustomHandlerDB::Declined) {
1598             return;
1599         }
1600         handlersDao.registerProtocolHandler(*(customHandler.get()));
1601         if (customHandler->user_decision & CustomHandlerDB::Agreed) {
1602             //TODO remove old default handler somehow from appsvc
1603             LogDebug("Registering appservice entry");
1604             int ret = appsvc_set_defapp(APPSVC_OPERATION_VIEW,
1605                                         NULL,
1606                                         DPL::ToUTF8String(
1607                                             customHandler->target).c_str(),
1608                                         DPL::ToUTF8String(This->m_model->
1609                                                               TizenId).c_str());
1610             if (APPSVC_RET_OK != ret) {
1611                 LogWarning("Appsvc entry failed: " << ret);
1612             }
1613         }
1614         LogDebug("Protocal saved");
1615     }
1616
1617     This->detachFromCustomHandlersDao();
1618 }
1619
1620 void ViewLogic::protocolHandlerIsRegisteredCallback(void* data,
1621                                                     Evas_Object* /*obj*/,
1622                                                     void* eventInfo)
1623 {
1624     LogDebug("enter");
1625     CustomHandlerDB::CustomHandlerPtr customHandler = getCustomHandlerFromData(
1626             eventInfo);
1627     ViewLogic* This = static_cast<ViewLogic*>(data);
1628     LogDebug("Creating handlers dao");
1629     This->attachToCustomHandlersDao();
1630     CustomHandlerDB::CustomHandlerDAO handlersDao(This->m_model->TizenId);
1631     CustomHandlerDB::CustomHandlerPtr handler =
1632         handlersDao.getProtocolHandler(customHandler->target,
1633                                        customHandler->url,
1634                                        customHandler->base_url);
1635     if (handler) {
1636         if (handler->user_decision & CustomHandlerDB::Agreed) {
1637             ewk_custom_handlers_data_result_set(
1638                 static_cast<Ewk_Custom_Handlers_Data*>(data),
1639                 EWK_CUSTOM_HANDLERS_REGISTERED);
1640         } else {
1641             ewk_custom_handlers_data_result_set(
1642                 static_cast<Ewk_Custom_Handlers_Data*>(data),
1643                 EWK_CUSTOM_HANDLERS_DECLINED);
1644         }
1645     } else {
1646         ewk_custom_handlers_data_result_set(
1647             static_cast<Ewk_Custom_Handlers_Data*>(data),
1648             EWK_CUSTOM_HANDLERS_NEW);
1649     }
1650     This->detachFromCustomHandlersDao();
1651 }
1652
1653 void ViewLogic::protocolHandlerUnregistrationCallback(void* data,
1654                                                       Evas_Object* /*obj*/,
1655                                                       void* eventInfo)
1656 {
1657     LogDebug("enter");
1658     CustomHandlerDB::CustomHandlerPtr customHandler =
1659         getCustomHandlerFromData(eventInfo);
1660     ViewLogic* This = static_cast<ViewLogic*>(data);
1661     LogDebug("Creating handlers dao");
1662     This->attachToCustomHandlersDao();
1663     CustomHandlerDB::CustomHandlerDAO handlersDao(This->m_model->TizenId);
1664     CustomHandlerDB::CustomHandlerPtr handlerCheck =
1665         handlersDao.getProtocolHandler(customHandler->target,
1666                                        customHandler->url,
1667                                        customHandler->base_url);
1668     if (handlerCheck) {
1669         if (handlerCheck->user_decision & CustomHandlerDB::Agreed) {
1670             appsvc_unset_defapp(DPL::ToUTF8String(This->m_model->TizenId).c_str());
1671         }
1672
1673         handlersDao.unregisterProtocolHandler(customHandler->target,
1674                                               customHandler->url,
1675                                               customHandler->base_url);
1676     } else {
1677         LogDebug("Nothing to unregister");
1678     }
1679
1680     This->detachFromCustomHandlersDao();
1681 }
1682
1683 void ViewLogic::contentHandlerRegistrationCallback(void* data,
1684                                                    Evas_Object* /*obj*/,
1685                                                    void* eventInfo)
1686 {
1687     Assert(data);
1688     LogDebug("enter");
1689     CustomHandlerDB::CustomHandlerPtr customHandler =
1690         getCustomHandlerFromData(eventInfo);
1691
1692     std::string mimeType = DPL::ToUTF8String(customHandler->target);
1693     if (mimeType.empty()) {
1694         LogError("No mimeType provided.");
1695         return;
1696     }
1697     for (int i = 0; i < contentBlackListLenth; ++i) {
1698         if (0 == strcmp(contentBlackList[i], mimeType.c_str())) {
1699             LogWarning("mimeType blacklisted");
1700             //throw SecurityException
1701             return;
1702         }
1703     }
1704
1705     ViewLogic* This = static_cast<ViewLogic*>(data);
1706     LogDebug("Creating handlers dao");
1707     This->attachToCustomHandlersDao();
1708     CustomHandlerDB::CustomHandlerDAO handlersDao(This->m_model->TizenId);
1709     CustomHandlerDB::CustomHandlerPtr handler =
1710         handlersDao.getContentHandler(customHandler->target,
1711                                       customHandler->url,
1712                                       customHandler->base_url);
1713     if (handler && (handler->user_decision & CustomHandlerDB::DecisionSaved)) {
1714         LogDebug("Protocol already registered - nothing to do");
1715     } else {
1716         LogDebug("Protocol handler not found");
1717         Wrt::Popup::PopupResponse response =
1718             GlobalSettings::PopupsTestModeEnabled() ? Wrt::Popup::
1719                 YES_DO_REMEMBER :
1720             Wrt::Popup::PopupInvoker().askYesNoCheckbox(
1721                 CONTENT_HANDLER_ASK_TITLE,
1722                 CONTENT_HANDLER_ASK_MSG,
1723                 CONTENT_HANDLER_AKS_REMEMBER);
1724         saveUserResponse(response, customHandler);
1725         if (customHandler->user_decision == CustomHandlerDB::Declined) {
1726             return;
1727         }
1728         handlersDao.registerContentHandler(*(customHandler.get()));
1729         if (customHandler->user_decision & CustomHandlerDB::Agreed) {
1730             //TODO remove old default handler somehow from appsvc
1731             LogDebug("Registering appservice entry");
1732             int ret = appsvc_set_defapp(APPSVC_OPERATION_VIEW,
1733                                         DPL::ToUTF8String(
1734                                             customHandler->target).c_str(),
1735                                         NULL,
1736                                         DPL::ToUTF8String(This->m_model->
1737                                                               TizenId).c_str());
1738             if (APPSVC_RET_OK != ret) {
1739                 LogWarning("Appsvc entry failed: " << ret);
1740             }
1741         }
1742         LogDebug("Content saved");
1743     }
1744     This->detachFromCustomHandlersDao();
1745 }
1746
1747 void ViewLogic::contentHandlerIsRegisteredCallback(void* data,
1748                                                    Evas_Object* /*obj*/,
1749                                                    void* eventInfo)
1750 {
1751     LogDebug("enter");
1752     CustomHandlerDB::CustomHandlerPtr customHandler =
1753         getCustomHandlerFromData(eventInfo);
1754     ViewLogic* This = static_cast<ViewLogic*>(data);
1755     LogDebug("Creating handlers dao");
1756
1757     This->attachToCustomHandlersDao();
1758     CustomHandlerDB::CustomHandlerDAO handlersDao(This->m_model->TizenId);
1759     CustomHandlerDB::CustomHandlerPtr handler =
1760         handlersDao.getContentHandler(customHandler->target,
1761                                       customHandler->url,
1762                                       customHandler->base_url);
1763     if (handler) {
1764         if (handler->user_decision & CustomHandlerDB::Agreed) {
1765             ewk_custom_handlers_data_result_set(
1766                 static_cast<Ewk_Custom_Handlers_Data*>(data),
1767                 EWK_CUSTOM_HANDLERS_REGISTERED);
1768         } else {
1769             ewk_custom_handlers_data_result_set(
1770                 static_cast<Ewk_Custom_Handlers_Data*>(data),
1771                 EWK_CUSTOM_HANDLERS_DECLINED);
1772         }
1773     } else {
1774         ewk_custom_handlers_data_result_set(
1775             static_cast<Ewk_Custom_Handlers_Data*>(data),
1776             EWK_CUSTOM_HANDLERS_NEW);
1777     }
1778     This->detachFromCustomHandlersDao();
1779 }
1780
1781 void ViewLogic::contentHandlerUnregistrationCallback(void* data,
1782                                                      Evas_Object* /*obj*/,
1783                                                      void* eventInfo)
1784 {
1785     LogDebug("enter");
1786     CustomHandlerDB::CustomHandlerPtr customHandler =
1787         getCustomHandlerFromData(eventInfo);
1788     ViewLogic* This = static_cast<ViewLogic*>(data);
1789     LogDebug("Creating handlers dao");
1790     This->attachToCustomHandlersDao();
1791     CustomHandlerDB::CustomHandlerDAO handlersDao(This->m_model->TizenId);
1792     CustomHandlerDB::CustomHandlerPtr handlerCheck =
1793         handlersDao.getContentHandler(customHandler->target,
1794                                       customHandler->url,
1795                                       customHandler->base_url);
1796     if (handlerCheck) {
1797         if (handlerCheck->user_decision & CustomHandlerDB::Agreed) {
1798             appsvc_unset_defapp(DPL::ToUTF8String(This->m_model->TizenId).c_str());
1799         }
1800
1801         handlersDao.unregisterContentHandler(customHandler->target,
1802                                              customHandler->url,
1803                                              customHandler->base_url);
1804     } else {
1805         LogDebug("Nothing to unregister");
1806     }
1807     This->detachFromCustomHandlersDao();
1808 }
1809
1810 void ViewLogic::didRunJavaScriptCallback(
1811     Evas_Object* /*obj*/,
1812     const char* result,
1813     void* /*userData*/)
1814 {
1815     LogInfo("didRunJavaScriptCallback called");
1816     LogInfo("result = " << result);
1817 }
1818
1819 Eina_Bool ViewLogic::windowCloseIdlerCallback(void* data)
1820 {
1821     LogDebug("closeIdlerCallback");
1822     ViewLogic* This = static_cast<ViewLogic*>(data);
1823     This->windowClose();
1824     return ECORE_CALLBACK_CANCEL;
1825 }
1826
1827 void ViewLogic::certificateConfirmRequestCallback(
1828     void* data,
1829     Evas_Object* /*obj*/,
1830     void* eventInfo)
1831 {
1832     LogDebug("certificateConfirmRequestCallback called");
1833
1834     Assert(data);
1835     ViewLogic* This = static_cast<ViewLogic*>(data);
1836     Assert(eventInfo);
1837     ViewModule::CertificateConfirmSupport::certificatePermissionRequest(
1838         This->m_window,
1839         This->m_certificateSupport->getCertificateDAO(),
1840         eventInfo);
1841 }
1842
1843 void ViewLogic::authenticationChallengeRequestCallback(
1844     void* data,
1845     Evas_Object* /*obj*/,
1846     void* eventInfo)
1847 {
1848     LogDebug("authenticationChallengeRequestCallback called");
1849
1850     Assert(data);
1851     ViewLogic* This = static_cast<ViewLogic*>(data);
1852     const char* url = ewk_view_url_get(This->m_currentEwkView);
1853     if (!url || strlen(url) == 0) {
1854         url = This->m_currentUri.c_str();
1855     }
1856     Assert(eventInfo);
1857     ViewModule::AuthenticationChallengeSupport::authenticationChallengeRequest(
1858         This->m_currentEwkView,
1859         url,
1860         eventInfo);
1861 }
1862
1863 std::string ViewLogic::requestUrlBlocked(const std::string& blockedUrl)
1864 {
1865     LogInfo("enter");
1866
1867     if (m_model->Type.Get().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
1868         // block this page and open it in browser
1869         LogDebug("Request was blocked by WARP: " << blockedUrl);
1870         LogDebug("open browser : " << blockedUrl);
1871         bundle* bundleData = bundle_create();
1872         appsvc_set_operation(bundleData, APPSVC_OPERATION_VIEW);
1873         appsvc_set_uri(bundleData, blockedUrl.c_str());
1874         CONTROLLER_POST_EVENT(
1875             ApplicationLauncher,
1876             ApplicationLauncherEvents::LaunchApplicationByAppService(
1877                 bundleData,
1878                 NULL,
1879                 NULL));
1880     }
1881
1882     // set block url. This is used on load finished callback
1883     m_blockedUri = blockedUrl;
1884
1885     // This is used in case of returning previous page
1886     return URICHANGE_PLUGIN_NO_CHANGE;
1887 }
1888
1889 std::string ViewLogic::requestUrlChanged(const std::string& changedUrl)
1890 {
1891     using namespace ViewModule::SecuritySupport;
1892
1893     LogInfo("changed url: " << changedUrl);
1894
1895     // Check if this url with 'http' or 'https' is included in whitelist,
1896     // which has lists of accessible external documents and
1897     // used for ONLY Tizen app
1898     std::string matchedScheme;
1899     std::string matchedUri;
1900     pcrecpp::RE(PATTERN_URI_CHANGE).PartialMatch(changedUrl.c_str(),
1901                                                  &matchedUri,
1902                                                  &matchedScheme);
1903     ViewModule::Scheme scheme(matchedScheme);
1904     if (scheme.GetType() == ViewModule::Scheme::HTTP ||
1905         scheme.GetType() == ViewModule::Scheme::HTTPS)
1906     {
1907         if (m_model->Type.Get().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
1908             if (!checkWhitelist(changedUrl.c_str())) {
1909                 LogInfo("This uri is not included in white document list");
1910                 return URICHANGE_PLUGIN_STOP_ONLY;
1911             }
1912             LogInfo("This url is included in WhiteList");
1913         } else {
1914             // For WAC app, WRT should block access of device api
1915             // for external documents
1916             return URICHANGE_PLUGIN_STOP_ONLY;
1917         }
1918     }
1919
1920     m_currentUri = changedUrl;
1921     return URICHANGE_PLUGIN_RESTART;
1922 }
1923
1924 void ViewLogic::windowClose()
1925 {
1926     LogDebug("windowClose");
1927     Assert(m_closedEwkView && "no closed webview");
1928
1929     if (1 >= m_ewkViewList.size()) {
1930         if (!m_cbs->webkitExit.empty()) {
1931             m_cbs->webkitExit();
1932         }
1933     } else {
1934         // call user callbacks
1935         if (!m_cbs->bufferUnset.empty()) {
1936             m_cbs->bufferUnset(m_currentEwkView);
1937         }
1938         if (!m_cbs->windowClose.empty()) {
1939             m_cbs->windowClose(m_closedEwkView);
1940         }
1941         removeEwkView(m_closedEwkView);
1942
1943         // get latest ewkView
1944         m_currentEwkView = m_ewkViewList.back();
1945         const char* uri = ewk_view_url_get(m_currentEwkView);
1946         if (NULL == uri || 0 == strlen(uri)) {
1947             m_currentUri.clear();
1948         } else {
1949             m_currentUri = uri;
1950         }
1951
1952         // resume ewkView
1953         /* In case we support many pages in parallel
1954          * then view is not suspended*/
1955         //resumeEwkView(m_currentEwkView);
1956         setEwkViewVisible(m_currentEwkView);
1957
1958         // show ewkView
1959         if (!m_cbs->bufferSet.empty()) {
1960             m_cbs->bufferSet(m_currentEwkView);
1961         }
1962     }
1963 }
1964