Merge branch 'tizen_3.0' of ssh://review.tizen.org:29418/platform/framework/web/cross...
[platform/framework/web/crosswalk-tizen.git] / runtime / browser / web_view_impl.cc
1 /*
2  * Copyright (c) 2015 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
18 #include "runtime/browser/web_view_impl.h"
19
20 #include <functional>
21 #include <sstream>
22
23 #include "common/file_utils.h"
24 #include "common/logger.h"
25 #include "common/profiler.h"
26 #include "runtime/browser/native_window.h"
27
28 namespace runtime {
29
30 namespace {
31
32 const char* kKeyNameBack = "back";
33 const char* kKeyNameMenu = "menu";
34 const char* kDefaultEncoding = "UTF-8";
35 const char* kSmartClassUserDataKey = "__SC_USERDATA__";
36
37 static int ToWebRotation(int r) {
38   switch (r) {
39     case 90:
40       return -90;
41     case 270:
42       return 90;
43   }
44   return r;
45 }
46
47 static NativeWindow::ScreenOrientation ToNativeRotation(int r) {
48   if (r ==
49       (EWK_SCREEN_ORIENTATION_PORTRAIT_PRIMARY
50        | EWK_SCREEN_ORIENTATION_PORTRAIT_SECONDARY
51        | EWK_SCREEN_ORIENTATION_LANDSCAPE_PRIMARY
52        | EWK_SCREEN_ORIENTATION_LANDSCAPE_SECONDARY)) {
53     return NativeWindow::ScreenOrientation::ANY;
54   } else if (r ==
55       (EWK_SCREEN_ORIENTATION_PORTRAIT_PRIMARY
56        | EWK_SCREEN_ORIENTATION_LANDSCAPE_PRIMARY)) {
57     return NativeWindow::ScreenOrientation::NATURAL;
58   } else if (r & EWK_SCREEN_ORIENTATION_PORTRAIT_PRIMARY) {
59     return NativeWindow::ScreenOrientation::PORTRAIT_PRIMARY;
60   } else if (r & EWK_SCREEN_ORIENTATION_PORTRAIT_SECONDARY) {
61     return NativeWindow::ScreenOrientation::PORTRAIT_SECONDARY;
62   } else if (r & EWK_SCREEN_ORIENTATION_LANDSCAPE_PRIMARY) {
63     return NativeWindow::ScreenOrientation::LANDSCAPE_PRIMARY;
64   } else {
65     return NativeWindow::ScreenOrientation::LANDSCAPE_SECONDARY;
66   }
67 }
68
69 }  // namespace
70
71 WebViewImpl::WebViewImpl(WebView* view,
72                          NativeWindow* window,
73                          Ewk_Context* context)
74     : window_(window),
75       context_(context),
76       ewk_view_(NULL),
77       listener_(NULL),
78       rotation_handler_id_(0),
79       view_(view),
80       fullscreen_(false),
81       evas_smart_class_(NULL),
82       internal_popup_opened_(false),
83       ime_width_(0),
84       ime_height_(0) {
85   Initialize();
86 }
87
88 WebViewImpl::~WebViewImpl() {
89   if (internal_popup_opened_) {
90     internal_popup_opened_ = false;
91     ewk_view_javascript_alert_reply(ewk_view_);
92   }
93   Deinitialize();
94   evas_object_del(ewk_view_);
95   if (evas_smart_class_ != NULL)
96     evas_smart_free(evas_smart_class_);
97 }
98
99 void WebViewImpl::ReplyToJavascriptDialog() {
100   if (internal_popup_opened_) {
101     internal_popup_opened_ = false;
102     ewk_view_javascript_alert_reply(ewk_view_);
103   }
104 }
105
106 void WebViewImpl::LoadUrl(const std::string& url, const std::string& mime) {
107   SCOPE_PROFILE();
108   if (!mime.empty()) {
109     mime_set_cb_ = [url, mime]
110                    (const char* request_url, const char* request_mime,
111                     char** new_mime, void* data) {
112       WebViewImpl* view = static_cast<WebViewImpl*>(data);
113       if (view != nullptr &&
114           common::utils::BaseName(url) ==
115           common::utils::BaseName(request_url)) {
116         *new_mime = strdup(mime.c_str());
117         LOGGER(DEBUG) << "ewk's new_mime: " << *new_mime;
118         return EINA_TRUE;
119       }
120       return EINA_FALSE;
121     };
122     auto mime_override_cb = [](const char* url, const char* mime,
123                                  char** new_mime, void* data) -> Eina_Bool {
124       WebViewImpl* view = static_cast<WebViewImpl*>(data);
125       return view->mime_set_cb_(url, mime, new_mime, data);
126     };
127     ewk_context_mime_override_callback_set(context_, mime_override_cb, this);
128   } else {
129     // In order to prevent crash issue, the callback should be released
130     // when the mime is empty.
131     ewk_context_mime_override_callback_set(context_, nullptr, nullptr);
132   }
133   ewk_view_url_set(ewk_view_, url.c_str());
134 }
135
136 void WebViewImpl::Suspend() {
137   // suspend webview
138   ewk_view_suspend(ewk_view_);
139 }
140
141 void WebViewImpl::Resume() {
142   // resume webview
143   ewk_view_resume(ewk_view_);
144 }
145
146 void WebViewImpl::Reload() {
147   ewk_view_reload(ewk_view_);
148 }
149
150 bool WebViewImpl::Backward() {
151   if (ewk_view_back_possible(ewk_view_)) {
152     ewk_view_back(ewk_view_);
153     return EINA_TRUE;
154   }
155   return EINA_FALSE;
156 }
157
158 void WebViewImpl::SetVisibility(bool show) {
159   ewk_view_page_visibility_state_set(ewk_view_,
160                                      show ? EWK_PAGE_VISIBILITY_STATE_VISIBLE :
161                                             EWK_PAGE_VISIBILITY_STATE_HIDDEN,
162                                      EINA_FALSE);
163 }
164
165
166 bool WebViewImpl::EvalJavascript(const std::string& script) {
167   return ewk_view_script_execute(ewk_view_, script.c_str(), NULL, NULL);
168 }
169
170 void WebViewImpl::Initialize() {
171   ewk_smart_class_ = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("WebView");
172   ewk_view_smart_class_set(&ewk_smart_class_);
173   ewk_smart_class_.orientation_lock = [](Ewk_View_Smart_Data *sd,
174                                          int orientation) {
175     WebViewImpl* self = static_cast<WebViewImpl*>(
176         evas_object_data_get(sd->self, kSmartClassUserDataKey));
177     if (self == NULL || self->listener_ == NULL)
178       return EINA_FALSE;
179     self->listener_->OnOrientationLock(self->view_,
180                                        true,
181                                        ToNativeRotation(orientation));
182     return EINA_TRUE;
183   };
184
185   ewk_smart_class_.orientation_unlock = [](Ewk_View_Smart_Data *sd) {
186     WebViewImpl* self = static_cast<WebViewImpl*>(
187         evas_object_data_get(sd->self, kSmartClassUserDataKey));
188     if (self == NULL || self->listener_ == NULL)
189       return;
190     self->listener_->OnOrientationLock(
191         self->view_,
192         false,
193         NativeWindow::ScreenOrientation::PORTRAIT_PRIMARY);
194   };
195
196   if (evas_smart_class_ != NULL)
197     evas_smart_free(evas_smart_class_);
198   evas_smart_class_ = evas_smart_class_new(&ewk_smart_class_.sc);
199   if (evas_smart_class_ == NULL) {
200     LOGGER(ERROR) << "Can't create evas smart class";
201     return;
202   }
203
204   Ewk_Page_Group* page_group = ewk_page_group_create("");
205   ewk_view_ = ewk_view_smart_add(evas_object_evas_get(window_->evas_object()),
206                                  evas_smart_class_,
207                                  context_,
208                                  page_group);
209   evas_object_data_set(ewk_view_, kSmartClassUserDataKey, this);
210
211   InitKeyCallback();
212   InitLoaderCallback();
213   InitPolicyDecideCallback();
214   InitQuotaExceededCallback();
215   InitIPCMessageCallback();
216   InitConsoleMessageCallback();
217   InitCustomContextMenuCallback();
218   InitRotationCallback();
219   InitWindowCreateCallback();
220   InitFullscreenCallback();
221   InitNotificationPermissionCallback();
222   InitGeolocationPermissionCallback();
223   InitAuthenticationCallback();
224   InitCertificateAllowCallback();
225   InitPopupWaitCallback();
226   InitUsermediaCallback();
227   InitEditorClientImeCallback();
228 #ifdef ROTARY_EVENT_FEATURE_SUPPORT
229   InitRotaryEventCallback();
230 #endif  // ROTARY_EVENT_FEATURE_SUPPORT
231
232   Ewk_Settings* settings = ewk_view_settings_get(ewk_view_);
233   ewk_settings_scripts_can_open_windows_set(settings, EINA_TRUE);
234 #ifndef PROFILE_WEARABLE
235   ewk_settings_form_candidate_data_enabled_set(settings, EINA_TRUE);
236 #endif
237   ewk_settings_default_text_encoding_name_set(settings, kDefaultEncoding);
238
239   // TODO(sngn.lee): "protocolhandler,registration,requested"
240   //                  custom protocol handler
241
242   // Show webview
243   evas_object_show(ewk_view_);
244 }
245
246 void WebViewImpl::Deinitialize() {
247   auto it = smart_callbacks_.begin();
248   for ( ; it != smart_callbacks_.end(); ++it) {
249     evas_object_smart_callback_del(
250         ewk_view_,
251         it->first.c_str(),
252         it->second);
253   }
254   eext_object_event_callback_del(ewk_view_,
255                                EEXT_CALLBACK_BACK,
256                                smart_callbacks_["key_callback"]);
257   ewk_view_exceeded_database_quota_callback_set(
258       ewk_view_,
259       NULL,
260       NULL);
261   ewk_view_exceeded_indexed_database_quota_callback_set(
262       ewk_view_,
263       NULL,
264       NULL);
265   ewk_view_exceeded_local_file_system_quota_callback_set(
266       ewk_view_,
267       NULL,
268       NULL);
269   ewk_view_notification_permission_callback_set(
270       ewk_view_,
271       NULL,
272       NULL);
273   ewk_view_geolocation_permission_callback_set(
274       ewk_view_,
275       NULL,
276       NULL);
277   ewk_view_user_media_permission_callback_set(
278       ewk_view_,
279       NULL,
280       NULL);
281   window_->RemoveRotationHandler(rotation_handler_id_);
282 }
283
284 void WebViewImpl::InitKeyCallback() {
285   auto key_callback = [](void* user_data,
286                          Evas_Object* /*obj*/,
287                          void* event_info) -> void {
288     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
289     Eext_Callback_Type key = static_cast<Eext_Callback_Type>(
290       reinterpret_cast<long long>(event_info));  // NOLINT
291     self->OnKeyEvent(key);
292   };
293   eext_object_event_callback_add(ewk_view_,
294                                EEXT_CALLBACK_BACK,
295                                key_callback,
296                                this);
297   eext_object_event_callback_add(ewk_view_,
298                                EEXT_CALLBACK_MORE,
299                                key_callback,
300                                this);
301   smart_callbacks_["key_callback"] = key_callback;
302 }
303
304 void WebViewImpl::InitLoaderCallback() {
305   // load statred callback
306   auto loadstart_callback = [](void* user_data,
307                                Evas_Object* /*obj*/,
308                                void*) {
309     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
310     if (self->listener_)
311       self->listener_->OnLoadStart(self->view_);
312   };
313   evas_object_smart_callback_add(ewk_view_,
314                                  "load,started",
315                                  loadstart_callback,
316                                  this);
317   // load finished callback
318   auto loadfinished_callback = [](void* user_data,
319                                   Evas_Object*,
320                                   void*) {
321     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
322     if (self->listener_)
323       self->listener_->OnLoadFinished(self->view_);
324   };
325   evas_object_smart_callback_add(ewk_view_,
326                                  "load,finished",
327                                  loadfinished_callback,
328                                  this);
329
330   // load progress callback
331   auto loadprogress_callback = [](void* user_data,
332                                   Evas_Object*,
333                                   void* event_info) {
334     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
335     double* progress = static_cast<double*>(event_info);
336     if (self->listener_)
337       self->listener_->OnLoadProgress(self->view_, *progress);
338   };
339   evas_object_smart_callback_add(ewk_view_,
340                                  "load,progress",
341                                  loadprogress_callback,
342                                  this);
343   // rendered callback
344   auto rendered_callback = [](void* user_data,
345                               Evas_Object*,
346                               void*) {
347     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
348     if (self->listener_)
349       self->listener_->OnRendered(self->view_);
350   };
351   evas_object_smart_callback_add(ewk_view_,
352                                  "frame,rendered",
353                                  rendered_callback,
354                                  this);
355   smart_callbacks_["load,started"] = loadstart_callback;
356   smart_callbacks_["load,finished"] = loadfinished_callback;
357   smart_callbacks_["load,progress"] = loadprogress_callback;
358   smart_callbacks_["frame,rendered"] = rendered_callback;
359
360 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
361   // rotate prepared callback
362   auto rotateprepared_callback = [](void* user_data,
363                               Evas_Object*,
364                               void*) {
365     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
366     if (self->listener_)
367       self->listener_->OnRotatePrepared(self->view_);
368   };
369   evas_object_smart_callback_add(ewk_view_,
370                                  "rotate,prepared",
371                                  rotateprepared_callback,
372                                  this);
373   smart_callbacks_["rotate,prepared"] = rotateprepared_callback;
374 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
375 }
376
377 void WebViewImpl::InitPolicyDecideCallback() {
378   // "policy,navigation,decide"
379   auto navigation_decide_callback = [](void* user_data,
380                                        Evas_Object*,
381                                        void* event_info) {
382     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
383     Ewk_Policy_Decision* policy =
384             static_cast<Ewk_Policy_Decision*>(event_info);
385     const char* url = ewk_policy_decision_url_get(policy);
386
387     if (self->listener_) {
388       if (self->listener_->OnDidNavigation(self->view_, url))
389         ewk_policy_decision_use(policy);
390       else
391         ewk_policy_decision_ignore(policy);
392     } else {
393       ewk_policy_decision_use(policy);
394     }
395   };
396   evas_object_smart_callback_add(ewk_view_,
397                                  "policy,navigation,decide",
398                                  navigation_decide_callback,
399                                  this);
400
401   // policy,newwindow,decide
402   auto newwindow_decide_callback = [](void* user_data,
403                                       Evas_Object*,
404                                       void* event_info) {
405     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
406     Ewk_Policy_Decision* policy =
407             static_cast<Ewk_Policy_Decision*>(event_info);
408
409     const char* url = ewk_policy_decision_url_get(policy);
410
411     if (self->listener_) {
412       if (self->listener_->OnDidNavigation(self->view_, url) &&
413          self->listener_->OnDidOpenWindow(self->view_, url)) {
414          ewk_policy_decision_use(policy);
415       } else {
416         ewk_policy_decision_ignore(policy);
417       }
418     } else {
419       ewk_policy_decision_use(policy);
420     }
421   };
422   evas_object_smart_callback_add(ewk_view_,
423                                  "policy,newwindow,decide",
424                                  newwindow_decide_callback,
425                                  this);
426   smart_callbacks_["policy,navigation,decide"] = navigation_decide_callback;
427   smart_callbacks_["policy,newwindow,decide"] = newwindow_decide_callback;
428 }
429
430 void WebViewImpl::InitQuotaExceededCallback() {
431   // TODO(sngn.lee): Need callback interface - OnQutaExceed
432   // check http://tizen.org/privilege/unlimitedstorage
433
434   // callback for database quota exceeded
435   auto database_exceeded_callback = [](Evas_Object* view,
436                                        Ewk_Security_Origin* origin,
437                                        const char*,
438                                        unsigned long long, // NOLINT
439                                        void* user_data) -> Eina_Bool {
440     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
441     if (self == NULL || self->listener_ == NULL)
442       return EINA_TRUE;
443
444     auto result_handler = [view](bool result) {
445       LOGGER(DEBUG) << "database quota Permission Result : " << result;
446       ewk_view_exceeded_database_quota_reply(view, result);
447     };
448     std::stringstream url;
449     url << ewk_security_origin_protocol_get(origin)
450         << "://"
451         << ewk_security_origin_host_get(origin)
452         << ":"
453         << ewk_security_origin_port_get(origin);
454     self->listener_->OnQuotaExceed(
455         self->view_,
456         url.str(),
457         result_handler);
458     return EINA_TRUE;
459   };
460   ewk_view_exceeded_database_quota_callback_set(
461     ewk_view_,
462     database_exceeded_callback,
463     this);
464
465   // callback for indexed database quota exceeded
466   auto indexed_db_exceeded_callback = [](Evas_Object* view,
467                                        Ewk_Security_Origin* origin,
468                                        long long, // NOLINT
469                                        void* user_data) -> Eina_Bool {
470     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
471     if (self == NULL || self->listener_ == NULL)
472       return EINA_TRUE;
473
474     auto result_handler = [view](bool result) {
475       LOGGER(DEBUG) << "indexed db quota Permission Result : " << result;
476       ewk_view_exceeded_indexed_database_quota_reply(view, result);
477     };
478     std::stringstream url;
479     url << ewk_security_origin_protocol_get(origin)
480         << "://"
481         << ewk_security_origin_host_get(origin)
482         << ":"
483         << ewk_security_origin_port_get(origin);
484     self->listener_->OnQuotaExceed(
485         self->view_,
486         url.str(),
487         result_handler);
488     return EINA_TRUE;
489   };
490   ewk_view_exceeded_indexed_database_quota_callback_set(
491     ewk_view_,
492     indexed_db_exceeded_callback,
493     this);
494
495   // callback for localfile quota exceeded
496   auto localfile_exceeded_callback = [](Evas_Object* view,
497                                        Ewk_Security_Origin* origin,
498                                        long long, // NOLINT
499                                        void* user_data) -> Eina_Bool {
500     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
501     if (self == NULL || self->listener_ == NULL)
502       return EINA_TRUE;
503
504     auto result_handler = [view](bool result) {
505       LOGGER(DEBUG) << "local file quota Permission Result : " << result;
506       ewk_view_exceeded_local_file_system_quota_reply(view, result);
507     };
508     std::stringstream url;
509     url << ewk_security_origin_protocol_get(origin)
510         << "://"
511         << ewk_security_origin_host_get(origin)
512         << ":"
513         << ewk_security_origin_port_get(origin);
514     self->listener_->OnQuotaExceed(
515         self->view_,
516         url.str(),
517         result_handler);
518     return EINA_TRUE;
519   };
520   ewk_view_exceeded_local_file_system_quota_callback_set(
521     ewk_view_,
522     localfile_exceeded_callback,
523     this);
524 }
525
526 void WebViewImpl::InitIPCMessageCallback() {
527   // wrt,message
528   auto wrt_message_callback = [](void* user_data,
529                                  Evas_Object*,
530                                  void* event_info) {
531     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
532     Ewk_IPC_Wrt_Message_Data* msg =
533         static_cast<Ewk_IPC_Wrt_Message_Data*>(event_info);
534     if (self->listener_)
535       self->listener_->OnReceivedWrtMessage(self->view_, msg);
536   };
537   evas_object_smart_callback_add(ewk_view_,
538                                  "wrt,message",
539                                  wrt_message_callback,
540                                  this);
541   smart_callbacks_["wrt,message"] = wrt_message_callback;
542 }
543
544 void WebViewImpl::InitConsoleMessageCallback() {
545   // console log
546   auto console_message_callback = [](void* user_data,
547                                  Evas_Object*,
548                                  void* event_info) {
549     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
550     if (!self->listener_) {
551       return;
552     }
553     Ewk_Console_Message* msg = static_cast<Ewk_Console_Message*>(event_info);
554     unsigned int line_number = ewk_console_message_line_get(msg);
555
556     std::stringstream buf;
557     if (line_number) {
558         buf << ewk_console_message_source_get(msg)
559             << ":" << line_number << ": ";
560     }
561     buf << ewk_console_message_text_get(msg);
562     int level = ewk_console_message_level_get(msg);
563     self->listener_->OnConsoleMessage(buf.str(), level);
564   };
565   evas_object_smart_callback_add(ewk_view_,
566                                  "console,message",
567                                  console_message_callback,
568                                  this);
569   smart_callbacks_["console,message"] = console_message_callback;
570 }
571
572 void WebViewImpl::InitCustomContextMenuCallback() {
573   auto custom_context_menu_callback = [](void* user_data,
574                                          Evas_Object*,
575                                          void* event_info) {
576     Ewk_Context_Menu* contextmenu = static_cast<Ewk_Context_Menu*>(event_info);
577     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
578     bool disabled = false;
579     if (self->listener_ &&
580         self->listener_->OnContextMenuDisabled(self->view_)) {
581       disabled = true;
582     }
583     int cnt = ewk_context_menu_item_count(contextmenu);
584     for (int idx = cnt-1; idx >= 0; --idx) {
585       auto* item = ewk_context_menu_nth_item_get(contextmenu, idx);
586       Ewk_Context_Menu_Item_Tag tag = ewk_context_menu_item_tag_get(item);
587       switch (tag) {
588         case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_IMAGE_IN_CURRENT_WINDOW:
589         case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_LINK:
590         case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_IMAGE_IN_NEW_WINDOW:
591         case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_LINK_IN_NEW_WINDOW:
592         case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_FRAME_IN_NEW_WINDOW:
593         case EWK_CONTEXT_MENU_ITEM_TAG_SEARCH_WEB:
594         case EWK_CONTEXT_MENU_ITEM_TAG_DOWNLOAD_IMAGE_TO_DISK:
595         case EWK_CONTEXT_MENU_ITEM_TAG_DOWNLOAD_LINK_TO_DISK:
596           ewk_context_menu_item_remove(contextmenu, item);
597           break;
598         default:
599           if (disabled)
600             ewk_context_menu_item_remove(contextmenu, item);
601       }
602     }
603   };
604   evas_object_smart_callback_add(ewk_view_,
605                                  "contextmenu,customize",
606                                  custom_context_menu_callback,
607                                  this);
608   smart_callbacks_["contextmenu,customize"] = custom_context_menu_callback;
609 }
610
611 void WebViewImpl::InitRotationCallback() {
612   // rotation support
613   ewk_view_orientation_send(ewk_view_, ToWebRotation(window_->rotation()));
614   rotation_handler_id_ = window_->AddRotationHandler(
615                                   std::bind(&WebViewImpl::OnRotation,
616                                   this,
617                                   std::placeholders::_1));
618 }
619
620 void WebViewImpl::InitWindowCreateCallback() {
621   auto create_callback = [](void* user_data,
622                             Evas_Object*,
623                             void* event_info) {
624     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
625     if (!self->listener_) {
626       return;
627     }
628     WebView* new_view = new WebView(self->window_, self->context_);
629     self->listener_->OnCreatedNewWebView(self->view_, new_view);
630     *(static_cast<Evas_Object **>(event_info)) = new_view->evas_object();
631   };
632
633   auto close_callback = [](void* user_data,
634                             Evas_Object*,
635                             void*) {
636     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
637     if (!self->listener_) {
638       return;
639     }
640     self->listener_->OnClosedWebView(self->view_);
641   };
642   evas_object_smart_callback_add(ewk_view_,
643                                  "create,window",
644                                  create_callback,
645                                  this);
646   evas_object_smart_callback_add(ewk_view_,
647                                  "close,window",
648                                  close_callback,
649                                  this);
650
651   smart_callbacks_["create,window"] = create_callback;
652   smart_callbacks_["close,window"] = close_callback;
653 }
654
655 void WebViewImpl::InitFullscreenCallback() {
656   auto enter_callback = [](void* user_data,
657                             Evas_Object*,
658                             void* /*event_info*/) {
659     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
660     self->fullscreen_ = true;
661     self->window_->FullScreen(true);
662   };
663   auto exit_callback =  [](void* user_data,
664                             Evas_Object*,
665                             void* /*event_info*/) {
666     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
667     self->fullscreen_ = false;
668     self->window_->FullScreen(false);
669   };
670   evas_object_smart_callback_add(ewk_view_,
671                                  "fullscreen,enterfullscreen",
672                                  enter_callback,
673                                  this);
674   evas_object_smart_callback_add(ewk_view_,
675                                  "fullscreen,exitfullscreen",
676                                  exit_callback,
677                                  this);
678   smart_callbacks_["fullscreen,enterfullscreen"] = enter_callback;
679   smart_callbacks_["fullscreen,exitfullscreen"] = exit_callback;
680 }
681
682 void WebViewImpl::InitNotificationPermissionCallback() {
683   auto request_callback = [](Evas_Object*,
684                              Ewk_Notification_Permission_Request* request,
685                              void* user_data) {
686     LOGGER(DEBUG) << "Notification Permission Request";
687     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
688     if (!self->listener_) {
689       ewk_notification_permission_reply(request, EINA_FALSE);
690       return EINA_TRUE;
691     }
692
693     ewk_notification_permission_request_suspend(request);
694     auto result_handler = [request](bool result) {
695       LOGGER(DEBUG) << "Notification Permission Result : %d" << result;
696       ewk_notification_permission_reply(request, result);
697     };
698     const Ewk_Security_Origin* ewk_origin =
699         ewk_notification_permission_request_origin_get(request);
700
701     std::stringstream url;
702     url << ewk_security_origin_protocol_get(ewk_origin)
703         << "://"
704         << ewk_security_origin_host_get(ewk_origin)
705         << ":"
706         << ewk_security_origin_port_get(ewk_origin);
707     self->listener_->OnNotificationPermissionRequest(
708         self->view_,
709         url.str(),
710         result_handler);
711     return EINA_TRUE;
712   };
713   ewk_view_notification_permission_callback_set(ewk_view_,
714                                                 request_callback,
715                                                 this);
716 }
717
718 void WebViewImpl::InitGeolocationPermissionCallback() {
719   auto permission_callback = [](
720       Evas_Object*,
721       Ewk_Geolocation_Permission_Request* request,
722       void* user_data) {
723     LOGGER(DEBUG) << "Geolocation Permission Request";
724     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
725     if (self == NULL || self->listener_ == NULL) {
726       ewk_geolocation_permission_reply(request, EINA_FALSE);
727       return EINA_TRUE;
728     }
729     ewk_geolocation_permission_request_suspend(request);
730
731     const Ewk_Security_Origin* ewk_origin =
732         ewk_geolocation_permission_request_origin_get(request);
733     auto result_handler = [request](bool result) {
734       LOGGER(DEBUG) << "Geolocation Permission Result : " << result;
735       ewk_geolocation_permission_reply(request, result);
736     };
737
738     std::stringstream url;
739     url << ewk_security_origin_protocol_get(ewk_origin)
740         << "://"
741         << ewk_security_origin_host_get(ewk_origin)
742         << ":"
743         << ewk_security_origin_port_get(ewk_origin);
744
745     self->listener_->OnGeolocationPermissionRequest(
746         self->view_,
747         url.str(),
748         result_handler);
749     return EINA_TRUE;
750   };
751   ewk_view_geolocation_permission_callback_set(ewk_view_,
752                                                permission_callback,
753                                                this);
754 }
755
756 void WebViewImpl::InitAuthenticationCallback() {
757   auto auth_callback = [](void* user_data,
758                           Evas_Object*,
759                           void* event_info) {
760     LOGGER(DEBUG) << "Authentication Request";
761     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
762     Ewk_Auth_Challenge* auth_challenge =
763         static_cast<Ewk_Auth_Challenge*>(event_info);
764
765     if (self == NULL || self->listener_ == NULL) {
766       ewk_auth_challenge_credential_cancel(auth_challenge);
767       return;
768     }
769     auto result_handler = [auth_challenge](bool submit,
770                                     const std::string& id,
771                                     const std::string& password) {
772       LOGGER(DEBUG) << "Authentication Result : submit = " << submit;
773       if (!submit) {
774         ewk_auth_challenge_credential_cancel(auth_challenge);
775         return;
776       }
777       ewk_auth_challenge_credential_use(auth_challenge,
778                                         id.c_str(),
779                                         password.c_str());
780     };
781     ewk_auth_challenge_suspend(auth_challenge);
782     const char* message =
783         ewk_auth_challenge_realm_get(auth_challenge);
784     std::string url = self->GetUrl();
785     self->listener_->OnAuthenticationRequest(self->view_,
786                                              url,
787                                              message,
788                                              result_handler);
789   };
790   // "authentication,challenge"
791   evas_object_smart_callback_add(ewk_view_,
792                                  "authentication,challenge",
793                                  auth_callback,
794                                  this);
795   smart_callbacks_["authentication,challenge"] = auth_callback;
796 }
797
798 void WebViewImpl::InitCertificateAllowCallback() {
799   auto certi_callback = [](void* user_data,
800                            Evas_Object*,
801                            void* event_info) {
802     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
803     Ewk_Certificate_Policy_Decision* policy =
804       static_cast<Ewk_Certificate_Policy_Decision*>(event_info);
805
806     if (self == NULL || self->listener_ == NULL) {
807       ewk_certificate_policy_decision_allowed_set(policy, EINA_FALSE);
808       return;
809     }
810
811     ewk_certificate_policy_decision_suspend(policy);
812     auto result_handler = [policy](bool allow) {
813       ewk_certificate_policy_decision_allowed_set(policy, allow);
814     };
815
816     auto ptr = ewk_certificate_policy_decision_url_get(policy);
817     std::string url(ptr ? ptr : "");
818     ptr = ewk_certificate_policy_decision_certificate_pem_get(policy);
819     std::string pem(ptr ? ptr : "");
820     self->listener_->OnCertificateAllowRequest(self->view_,
821                                                url,
822                                                pem,
823                                                result_handler);
824   };
825   evas_object_smart_callback_add(ewk_view_,
826                                  "request,certificate,confirm",
827                                  certi_callback,
828                                  this);
829   smart_callbacks_["request,certificate,confirm"] = certi_callback;
830 }
831
832 void WebViewImpl::InitPopupWaitCallback() {
833   evas_object_smart_callback_add(ewk_view_,
834       "popup,reply,wait,start",
835       [](void* user_data, Evas_Object* /*obj*/, void*) {
836         WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
837         self->internal_popup_opened_ = true;
838 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
839         self->window_->EnableManualRotation(false);
840 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
841       }, this);
842   evas_object_smart_callback_add(ewk_view_,
843       "popup,reply,wait,finish",
844       [](void* user_data, Evas_Object* /*obj*/, void*) {
845         WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
846         self->internal_popup_opened_ = false;
847 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
848         self->window_->EnableManualRotation(true);
849 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
850       }, this);
851 }
852
853 void WebViewImpl::InitUsermediaCallback() {
854   auto callback = [](Evas_Object*,
855                      Ewk_User_Media_Permission_Request* request,
856                      void* user_data) {
857     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
858     if (self == NULL || self->listener_ == NULL) {
859       ewk_user_media_permission_reply(request, EINA_FALSE);
860       return EINA_TRUE;
861     }
862
863     ewk_user_media_permission_request_suspend(request);
864     const Ewk_Security_Origin* origin =
865         ewk_user_media_permission_request_origin_get(request);
866     std::stringstream url;
867     url << ewk_security_origin_protocol_get(origin)
868         << "://"
869         << ewk_security_origin_host_get(origin)
870         << ":"
871         << ewk_security_origin_port_get(origin);
872
873     auto result_handler = [request](bool result) {
874       LOGGER(DEBUG) << "Getusermedia Permission Result : " << result;
875       ewk_user_media_permission_reply(request, result);
876     };
877     self->listener_->OnUsermediaPermissionRequest(self->view_,
878                                                   url.str(),
879                                                   result_handler);
880     return EINA_TRUE;
881   };
882   ewk_view_user_media_permission_callback_set(ewk_view_, callback, this);
883 }
884
885 void WebViewImpl::InitEditorClientImeCallback() {
886   auto ime_changed_callback = [](void* user_data,
887                            Evas_Object*,
888                            void* event_info) {
889     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
890
891     Eina_Rectangle *rect = static_cast<Eina_Rectangle *>(event_info);
892     self->ime_width_ = rect->w;
893     self->ime_height_ = rect->h;
894   };
895
896   auto ime_opened_callback = [](void* user_data,
897                            Evas_Object*,
898                            void* event_info) {
899     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
900     if (!self->listener_)
901       return;
902
903     SoftKeyboardChangeEventValue softkeyboard_value;
904     softkeyboard_value.state = "on";
905     softkeyboard_value.width = self->ime_width_;
906     softkeyboard_value.height = self->ime_height_;
907
908     self->listener_->OnSoftKeyboardChangeEvent(self->view_, softkeyboard_value);
909   };
910
911   auto ime_closed_callback = [](void* user_data,
912                            Evas_Object*,
913                            void* event_info) {
914     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
915     if (!self->listener_)
916       return;
917
918     SoftKeyboardChangeEventValue softkeyboard_value;
919     softkeyboard_value.state = "off";
920
921     self->listener_->OnSoftKeyboardChangeEvent(self->view_, softkeyboard_value);
922   };
923   evas_object_smart_callback_add(ewk_view_,
924                                  "inputmethod,changed",
925                                  ime_changed_callback,
926                                  this);
927   evas_object_smart_callback_add(ewk_view_,
928                                  "editorclient,ime,opened",
929                                  ime_opened_callback,
930                                  this);
931   evas_object_smart_callback_add(ewk_view_,
932                                  "editorclient,ime,closed",
933                                  ime_closed_callback,
934                                  this);
935   smart_callbacks_["inputmethod,changed"] = ime_changed_callback;
936   smart_callbacks_["editorclient,ime,opened"] = ime_opened_callback;
937   smart_callbacks_["editorclient,ime,closed"] = ime_closed_callback;
938 }
939
940 #ifdef ROTARY_EVENT_FEATURE_SUPPORT
941 void WebViewImpl::InitRotaryEventCallback() {
942   auto rotary_callback = [](void* user_data,
943                          Evas_Object*,
944                          Eext_Rotary_Event_Info* event_info) -> Eina_Bool {
945     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
946     if (!self->listener_)
947       return EINA_FALSE;
948
949     Eext_Rotary_Event_Info* rotary = event_info;
950
951     RotaryEventType type;
952     if (rotary->direction == EEXT_ROTARY_DIRECTION_CLOCKWISE)
953       type = RotaryEventType::CLOCKWISE;
954     else
955       type = RotaryEventType::COUNTER_CLOCKWISE;
956
957     self->listener_->OnRotaryEvent(self->view_, type);
958     return EINA_TRUE;
959   };
960
961   // add callback to handle rotary event
962   eext_rotary_object_event_callback_add(ewk_view_, rotary_callback, this);
963   eext_rotary_object_event_activated_set(ewk_view_, EINA_TRUE);
964 }
965 #endif  // ROTARY_EVENT_FEATURE_SUPPORT
966
967 std::string WebViewImpl::GetUrl() {
968   return std::string(ewk_view_url_get(ewk_view_));
969 }
970
971 Evas_Object* WebViewImpl::evas_object() const {
972   return ewk_view_;
973 }
974
975 void WebViewImpl::OnRotation(int degree) {
976   ewk_view_orientation_send(ewk_view_, ToWebRotation(degree));
977 }
978
979 void WebViewImpl::OnKeyEvent(Eext_Callback_Type key_type) {
980   std::string keyname;
981   if (key_type == EEXT_CALLBACK_BACK) {
982     if (fullscreen_) {
983       ewk_view_fullscreen_exit(ewk_view_);
984       return;
985     }
986     if (EINA_TRUE == ewk_view_text_selection_clear(ewk_view_)) {
987       return;
988     }
989     keyname = kKeyNameBack;
990   } else if (key_type == EEXT_CALLBACK_MORE) {
991     keyname = kKeyNameMenu;
992   } else {
993     return;
994   }
995
996   if (listener_ && !internal_popup_opened_) {
997     listener_->OnHardwareKey(view_, keyname);
998   }
999 }
1000
1001 void WebViewImpl::SetEventListener(WebView::EventListener* listener) {
1002   listener_ = listener;
1003 }
1004
1005 void WebViewImpl::SetAppInfo(const std::string& app_name,
1006                              const std::string& version) {
1007   std::string ua = app_name + "/" + version;
1008   ewk_view_application_name_for_user_agent_set(ewk_view_, ua.c_str());
1009 }
1010 bool WebViewImpl::SetUserAgent(const std::string& user_agent) {
1011   return ewk_view_user_agent_set(ewk_view_, user_agent.c_str());
1012 }
1013
1014 void WebViewImpl::SetCSPRule(const std::string& rule, bool report_only) {
1015   ewk_view_content_security_policy_set(
1016       ewk_view_,
1017       rule.c_str(),
1018       report_only ? EWK_REPORT_ONLY : EWK_ENFORCE_POLICY);
1019 }
1020
1021 void WebViewImpl::SetDefaultEncoding(const std::string& encoding) {
1022   if (ewk_settings_is_encoding_valid(encoding.c_str())) {
1023     Ewk_Settings* settings = ewk_view_settings_get(ewk_view_);
1024     ewk_settings_default_text_encoding_name_set(settings, encoding.c_str());
1025   }
1026 }
1027
1028 void WebViewImpl::SetLongPolling(unsigned long longpolling) {
1029     ewk_view_session_timeout_set(ewk_view_, longpolling);
1030 }
1031
1032 #ifdef PROFILE_WEARABLE
1033 void WebViewImpl::SetBGColor(int r, int g, int b, int a) {
1034   ewk_view_bg_color_set(ewk_view_, r, g, b, a);
1035 }
1036 #endif
1037
1038 }  // namespace runtime