1 // Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "runtime/web_view_impl.h"
7 #include <ewk_chromium.h>
11 #include "runtime/native_window.h"
12 #include "common/logger.h"
17 // TODO(sngn.lee) : It should be declare in common header
18 const char* kKeyNameBack = "back";
19 const char* kKeyNameMenu = "menu";
21 static int ToWebRotation(int r) {
31 static int ToNativeRotation(int r) {
43 WebViewImpl::WebViewImpl(WebView* view,
55 WebViewImpl::~WebViewImpl() {
57 evas_object_del(ewk_view_);
60 void WebViewImpl::LoadUrl(const std::string& url) {
61 ewk_view_url_set(ewk_view_, url.c_str());
64 void WebViewImpl::Suspend() {
66 ewk_view_suspend(ewk_view_);
69 void WebViewImpl::Resume() {
71 ewk_view_resume(ewk_view_);
74 void WebViewImpl::Reload() {
75 ewk_view_reload(ewk_view_);
78 void WebViewImpl::SetVisibility(bool show) {
79 ewk_view_visibility_set(ewk_view_, show ? EINA_TRUE : EINA_FALSE);
83 bool WebViewImpl::EvalJavascript(const std::string& script) {
84 return ewk_view_script_execute(ewk_view_, script.c_str(), NULL, NULL);
87 void WebViewImpl::Initialize() {
88 ewk_view_ = ewk_view_add_with_context(window_->evas_object(), context_);
92 InitPolicyDecideCallback();
93 InitQuotaExceededCallback();
94 InitIPCMessageCallback();
95 InitOrientaionLockCallback();
96 InitConsoleMessageCallback();
97 InitCustomContextMenuCallback();
98 InitRotationCallback();
99 InitWindowCreateCallback();
100 InitFullscreenCallback();
101 InitNotificationPermissionCallback();
102 InitGeolocationPermissionCallback();
103 InitAuthenticationCallback();
104 InitCertificateAllowCallback();
106 // TODO(sngn.lee): "notification,show"
107 // TODO(sngn.lee): "notification,cancel"
108 // TODO(sngn.lee): "protocolhandler,registration,requested"
109 // custom protocol handler
110 // TODO(sngn.lee): ewk_view_user_media_permission_callback_set
113 evas_object_show(ewk_view_);
116 void WebViewImpl::Deinitialize() {
117 auto it = smart_callbacks_.begin();
118 for ( ; it != smart_callbacks_.end(); ++it) {
119 evas_object_smart_callback_del(
124 ea_object_event_callback_del(ewk_view_,
126 smart_callbacks_["key_callback"]);
127 ewk_view_exceeded_database_quota_callback_set(
131 ewk_view_exceeded_indexed_database_quota_callback_set(
135 ewk_view_exceeded_local_file_system_quota_callback_set(
139 ewk_view_orientation_lock_callback_set(
143 ewk_view_notification_permission_callback_set(
147 ewk_view_geolocation_permission_callback_set(
151 window_->RemoveRotationHandler(rotation_handler_id_);
154 void WebViewImpl::InitKeyCallback() {
155 auto key_callback = [](void* user_data,
156 Evas_Object* /*obj*/,
157 void* event_info) -> void {
158 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
159 Ea_Callback_Type key = static_cast<Ea_Callback_Type>(
160 *static_cast<int*>(event_info));
161 self->OnKeyEvent(key);
163 ea_object_event_callback_add(ewk_view_,
167 ea_object_event_callback_add(ewk_view_,
171 smart_callbacks_["key_callback"] = key_callback;
174 void WebViewImpl::InitLoaderCallback() {
175 // load statred callback
176 auto loadstart_callback = [](void* user_data,
177 Evas_Object* /*obj*/,
179 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
181 self->listener_->OnLoadStart(self->view_);
183 evas_object_smart_callback_add(ewk_view_,
187 // load finished callback
188 auto loadfinished_callback = [](void* user_data,
191 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
193 self->listener_->OnLoadFinished(self->view_);
195 evas_object_smart_callback_add(ewk_view_,
197 loadfinished_callback,
200 // load progress callback
201 auto loadprogress_callback = [](void* user_data,
204 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
205 double* progress = static_cast<double*>(event_info);
207 self->listener_->OnLoadProgress(self->view_, *progress);
209 evas_object_smart_callback_add(ewk_view_,
211 loadprogress_callback,
214 auto rendered_callback = [](void* user_data,
217 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
219 self->listener_->OnRendered(self->view_);
221 evas_object_smart_callback_add(ewk_view_,
225 smart_callbacks_["load,started"] = loadstart_callback;
226 smart_callbacks_["load,finished"] = loadfinished_callback;
227 smart_callbacks_["load,progress"] = loadprogress_callback;
228 smart_callbacks_["frame,rendered"] = rendered_callback;
231 void WebViewImpl::InitPolicyDecideCallback() {
232 // "policy,navigation,decide"
233 auto navigation_decide_callback = [](void* user_data,
236 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
237 Ewk_Policy_Decision* policy =
238 static_cast<Ewk_Policy_Decision*>(event_info);
239 const char* url = ewk_policy_decision_url_get(policy);
241 if (self->listener_) {
242 if (self->listener_->OnDidNavigation(self->view_, url))
243 ewk_policy_decision_use(policy);
245 ewk_policy_decision_ignore(policy);
247 ewk_policy_decision_use(policy);
250 evas_object_smart_callback_add(ewk_view_,
251 "policy,navigation,decide",
252 navigation_decide_callback,
255 // policy,newwindow,decide
256 auto newwindow_decide_callback = [](void* user_data,
259 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
260 Ewk_Policy_Decision* policy =
261 static_cast<Ewk_Policy_Decision*>(event_info);
263 const char* url = ewk_policy_decision_url_get(policy);
265 if (self->listener_) {
266 if (self->listener_->OnDidNavigation(self->view_, url) &&
267 self->listener_->OnDidOpenWindow(self->view_, url)) {
268 ewk_policy_decision_use(policy);
270 ewk_policy_decision_ignore(policy);
273 ewk_policy_decision_use(policy);
276 evas_object_smart_callback_add(ewk_view_,
277 "policy,newwindow,decide",
278 newwindow_decide_callback,
280 smart_callbacks_["policy,navigation,decide"] = navigation_decide_callback;
281 smart_callbacks_["policy,newwindow,decide"] = newwindow_decide_callback;
284 void WebViewImpl::InitQuotaExceededCallback() {
285 // TODO(sngn.lee): Need callback interface - OnQutaExceed
286 // check http://tizen.org/privilege/unlimitedstorage
288 // callback for database quota exceeded
289 // TODO(wy80.choi): AARCH64:
290 // Fix ewk api to use stdint types instead of longlong.
291 auto database_exceeded_callback = [](Evas_Object* view,
292 Ewk_Security_Origin* origin,
295 void* user_data) -> Eina_Bool {
296 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
297 if (self == NULL || self->listener_ == NULL)
300 auto result_handler = [view](bool result) {
301 LOGGER(DEBUG) << "database quota Permission Result : " << result;
302 ewk_view_exceeded_database_quota_reply(view, result);
304 std::stringstream url;
305 url << ewk_security_origin_protocol_get(origin)
307 << ewk_security_origin_host_get(origin)
309 << ewk_security_origin_port_get(origin);
310 self->listener_->OnQuotaExceed(
316 ewk_view_exceeded_database_quota_callback_set(
318 database_exceeded_callback,
321 // callback for indexed database quota exceeded
322 // TODO(wy80.choi): AARCH64:
323 // Fix ewk api to use stdint types instead of longlong.
324 auto indexed_db_exceeded_callback = [](Evas_Object* view,
325 Ewk_Security_Origin* origin,
327 void* user_data) -> Eina_Bool {
328 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
329 if (self == NULL || self->listener_ == NULL)
332 auto result_handler = [view](bool result) {
333 LOGGER(DEBUG) << "indexed db quota Permission Result : " << result;
334 ewk_view_exceeded_indexed_database_quota_reply(view, result);
336 std::stringstream url;
337 url << ewk_security_origin_protocol_get(origin)
339 << ewk_security_origin_host_get(origin)
341 << ewk_security_origin_port_get(origin);
342 self->listener_->OnQuotaExceed(
348 ewk_view_exceeded_indexed_database_quota_callback_set(
350 indexed_db_exceeded_callback,
353 // callback for localfile quota exceeded
354 // TODO(wy80.choi): AARCH64:
355 // Fix ewk api to use stdint types instead of longlong.
356 auto localfile_exceeded_callback = [](Evas_Object* view,
357 Ewk_Security_Origin* origin,
359 void* user_data) -> Eina_Bool {
360 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
361 if (self == NULL || self->listener_ == NULL)
364 auto result_handler = [view](bool result) {
365 LOGGER(DEBUG) << "local file quota Permission Result : " << result;
366 ewk_view_exceeded_local_file_system_quota_reply(view, result);
368 std::stringstream url;
369 url << ewk_security_origin_protocol_get(origin)
371 << ewk_security_origin_host_get(origin)
373 << ewk_security_origin_port_get(origin);
374 self->listener_->OnQuotaExceed(
380 ewk_view_exceeded_local_file_system_quota_callback_set(
382 localfile_exceeded_callback,
386 void WebViewImpl::InitIPCMessageCallback() {
388 auto wrt_message_callback = [](void* user_data,
391 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
392 Ewk_IPC_Wrt_Message_Data* msg =
393 static_cast<Ewk_IPC_Wrt_Message_Data*>(event_info);
395 self->listener_->OnReceivedWrtMessage(self->view_, msg);
397 evas_object_smart_callback_add(ewk_view_,
399 wrt_message_callback,
401 smart_callbacks_["wrt,message"] = wrt_message_callback;
404 void WebViewImpl::InitOrientaionLockCallback() {
405 // Orientation lock callback
406 auto orientation_lock_callback = [](Evas_Object*,
409 void* user_data) -> Eina_Bool {
410 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
411 if (self->listener_) {
412 self->listener_->OnOrientationLock(self->view_,
414 ToNativeRotation(orientation));
418 ewk_view_orientation_lock_callback_set(ewk_view_,
419 orientation_lock_callback,
423 void WebViewImpl::InitConsoleMessageCallback() {
425 auto console_message_callback = [](void* user_data,
428 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
429 if (!self->listener_) {
432 Ewk_Console_Message* msg = static_cast<Ewk_Console_Message*>(event_info);
433 unsigned int line_number = ewk_console_message_line_get(msg);
435 std::stringstream buf;
437 buf << ewk_console_message_source_get(msg) << ":";
438 buf << line_number << ":";
440 buf << ewk_console_message_text_get(msg);
441 int level = ewk_console_message_level_get(msg);
442 self->listener_->OnConsoleMessage(buf.str(), level);
444 evas_object_smart_callback_add(ewk_view_,
446 console_message_callback,
448 smart_callbacks_["console,message"] = console_message_callback;
451 void WebViewImpl::InitCustomContextMenuCallback() {
452 auto custom_context_menu_callback = [](void* user_data,
455 Ewk_Context_Menu* contextmenu = static_cast<Ewk_Context_Menu*>(event_info);
456 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
457 bool disabled = false;
458 if (self->listener_ &&
459 self->listener_->OnContextMenuDisabled(self->view_)) {
462 int cnt = ewk_context_menu_item_count(contextmenu);
463 for (unsigned idx = cnt-1; idx > 0; --idx) {
464 auto* item = ewk_context_menu_nth_item_get(contextmenu, idx);
465 Ewk_Context_Menu_Item_Tag tag = ewk_context_menu_item_tag_get(item);
467 case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_IMAGE_IN_NEW_WINDOW:
468 case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_LINK_IN_NEW_WINDOW:
469 case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_FRAME_IN_NEW_WINDOW:
470 case EWK_CONTEXT_MENU_ITEM_TAG_SEARCH_WEB:
471 case EWK_CONTEXT_MENU_ITEM_TAG_DOWNLOAD_IMAGE_TO_DISK:
472 ewk_context_menu_item_remove(contextmenu, item);
476 ewk_context_menu_item_remove(contextmenu, item);
480 evas_object_smart_callback_add(ewk_view_,
481 "contextmenu,customize",
482 custom_context_menu_callback,
484 smart_callbacks_["contextmenu,customize"] = custom_context_menu_callback;
487 void WebViewImpl::InitRotationCallback() {
489 ewk_view_orientation_send(ewk_view_, ToWebRotation(window_->rotation()));
490 rotation_handler_id_ = window_->AddRotationHandler(
491 std::bind(&WebViewImpl::OnRotation,
493 std::placeholders::_1));
496 void WebViewImpl::InitWindowCreateCallback() {
497 auto create_callback = [](void* user_data,
500 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
501 if (!self->listener_) {
504 WebView* new_view = new WebView(self->window_, self->context_);
505 self->listener_->OnCreatedNewWebView(self->view_, new_view);
506 *(static_cast<Evas_Object **>(event_info)) = new_view->evas_object();
509 auto close_callback = [](void* user_data,
512 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
513 if (!self->listener_) {
516 self->listener_->OnClosedWebView(self->view_);
518 evas_object_smart_callback_add(ewk_view_,
522 evas_object_smart_callback_add(ewk_view_,
527 smart_callbacks_["create,window"] = create_callback;
528 smart_callbacks_["close,window"] = close_callback;
531 void WebViewImpl::InitFullscreenCallback() {
532 auto enter_callback = [](void* user_data,
534 void* /*event_info*/) {
535 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
536 self->fullscreen_ = true;
537 self->window_->FullScreen(true);
539 auto exit_callback = [](void* user_data,
541 void* /*event_info*/) {
542 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
543 self->fullscreen_ = false;
544 self->window_->FullScreen(false);
546 evas_object_smart_callback_add(ewk_view_,
547 "fullscreen,enterfullscreen",
550 evas_object_smart_callback_add(ewk_view_,
551 "fullscreen,exitfullscreen",
554 smart_callbacks_["fullscreen,enterfullscreen"] = enter_callback;
555 smart_callbacks_["fullscreen,exitfullscreen"] = exit_callback;
558 void WebViewImpl::InitNotificationPermissionCallback() {
559 auto request_callback = [](Evas_Object*,
560 Ewk_Notification_Permission_Request* request,
562 LOGGER(DEBUG) << "Notification Permission Request";
563 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
564 if (!self->listener_) {
565 ewk_notification_permission_reply(request, EINA_FALSE);
569 ewk_notification_permission_request_suspend(request);
570 auto result_handler = [request](bool result) {
571 LOGGER(DEBUG) << "Notification Permission Result : %d" << result;
572 ewk_notification_permission_reply(request, result);
574 const Ewk_Security_Origin* ewk_origin =
575 ewk_notification_permission_request_origin_get(request);
577 std::stringstream url;
578 url << ewk_security_origin_protocol_get(ewk_origin)
580 << ewk_security_origin_host_get(ewk_origin)
582 << ewk_security_origin_port_get(ewk_origin);
583 self->listener_->OnNotificationPermissionRequest(
589 ewk_view_notification_permission_callback_set(ewk_view_,
594 void WebViewImpl::InitGeolocationPermissionCallback() {
595 auto permission_callback = [](
597 Ewk_Geolocation_Permission_Request* request,
599 LOGGER(DEBUG) << "Geolocation Permission Request";
600 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
601 if (self == NULL || self->listener_ == NULL) {
602 ewk_geolocation_permission_reply(request, EINA_FALSE);
605 ewk_geolocation_permission_request_suspend(request);
607 const Ewk_Security_Origin* ewk_origin =
608 ewk_geolocation_permission_request_origin_get(request);
609 auto result_handler = [request](bool result) {
610 LOGGER(DEBUG) << "Geolocation Permission Result : " << result;
611 ewk_geolocation_permission_reply(request, result);
614 std::stringstream url;
615 url << ewk_security_origin_protocol_get(ewk_origin)
617 << ewk_security_origin_host_get(ewk_origin)
619 << ewk_security_origin_port_get(ewk_origin);
621 self->listener_->OnGeolocationPermissionRequest(
627 ewk_view_geolocation_permission_callback_set(ewk_view_,
632 void WebViewImpl::InitAuthenticationCallback() {
633 auto auth_callback = [](void* user_data,
636 LOGGER(DEBUG) << "Authentication Request";
637 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
638 Ewk_Auth_Challenge* auth_challenge =
639 static_cast<Ewk_Auth_Challenge*>(event_info);
641 if (self == NULL || self->listener_ == NULL) {
642 ewk_auth_challenge_credential_cancel(auth_challenge);
645 auto result_handler = [auth_challenge](bool submit,
646 const std::string& id,
647 const std::string& password) {
648 LOGGER(DEBUG) << "Authentication Result : submit = " << submit;
650 ewk_auth_challenge_credential_cancel(auth_challenge);
653 ewk_auth_challenge_credential_use(auth_challenge,
657 ewk_auth_challenge_suspend(auth_challenge);
658 const char* message =
659 ewk_auth_challenge_realm_get(auth_challenge);
660 std::string url = self->GetUrl();
661 self->listener_->OnAuthenticationRequest(self->view_,
666 // "authentication,challenge"
667 evas_object_smart_callback_add(ewk_view_,
668 "authentication,challenge",
671 smart_callbacks_["authentication,challenge"] = auth_callback;
674 void WebViewImpl::InitCertificateAllowCallback() {
675 auto certi_callback = [](void* user_data,
678 WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
679 Ewk_Certificate_Policy_Decision* policy =
680 static_cast<Ewk_Certificate_Policy_Decision*>(event_info);
682 if (self == NULL || self->listener_ == NULL) {
683 ewk_certificate_policy_decision_allowed_set(policy, EINA_FALSE);
687 ewk_certificate_policy_decision_suspend(policy);
688 auto result_handler = [policy](bool allow) {
689 ewk_certificate_policy_decision_allowed_set(policy, allow);
692 auto ptr = ewk_certificate_policy_decision_url_get(policy);
693 std::string url(ptr ? ptr : "");
694 ptr = ewk_certificate_policy_decision_certificate_pem_get(policy);
695 std::string pem(ptr ? ptr : "");
696 self->listener_->OnCertificateAllowRequest(self->view_,
701 evas_object_smart_callback_add(ewk_view_,
702 "request,certificate,confirm",
705 smart_callbacks_["request,certificate,confirm"] = certi_callback;
709 std::string WebViewImpl::GetUrl() {
710 return std::string(ewk_view_url_get(ewk_view_));
713 Evas_Object* WebViewImpl::evas_object() const {
717 void WebViewImpl::OnRotation(int degree) {
718 ewk_view_orientation_send(ewk_view_, ToWebRotation(degree));
721 void WebViewImpl::OnKeyEvent(Ea_Callback_Type key_type) {
723 if (key_type == EA_CALLBACK_BACK) {
725 ewk_view_fullscreen_exit(ewk_view_);
728 if (EINA_TRUE == ewk_view_text_selection_clear(ewk_view_)) {
731 keyname = kKeyNameBack;
732 } else if (key_type == EA_CALLBACK_MORE) {
733 keyname = kKeyNameMenu;
739 listener_->OnHardwareKey(view_, keyname);
742 void WebViewImpl::SetEventListener(WebView::EventListener* listener) {
743 listener_ = listener;
746 void WebViewImpl::SetAppInfo(const std::string& app_name,
747 const std::string& version) {
748 std::string ua = app_name + "/" + version;
749 ewk_view_application_name_for_user_agent_set(ewk_view_, ua.c_str());
751 bool WebViewImpl::SetUserAgent(const std::string& user_agent) {
752 return ewk_view_user_agent_set(ewk_view_, user_agent.c_str());