Locate ewk_view_page_close in extended main loop
[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     LOGGER(DEBUG) << "close_callback is called";
637     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
638     if (!self->listener_) {
639       return;
640     }
641     self->listener_->OnClosedWebView(self->view_);
642   };
643   evas_object_smart_callback_add(ewk_view_,
644                                  "create,window",
645                                  create_callback,
646                                  this);
647   evas_object_smart_callback_add(ewk_view_,
648                                  "close,window",
649                                  close_callback,
650                                  this);
651
652   smart_callbacks_["create,window"] = create_callback;
653   smart_callbacks_["close,window"] = close_callback;
654 }
655
656 void WebViewImpl::InitFullscreenCallback() {
657   auto enter_callback = [](void* user_data,
658                             Evas_Object*,
659                             void* /*event_info*/) {
660     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
661     self->fullscreen_ = true;
662     self->window_->FullScreen(true);
663   };
664   auto exit_callback =  [](void* user_data,
665                             Evas_Object*,
666                             void* /*event_info*/) {
667     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
668     self->fullscreen_ = false;
669     self->window_->FullScreen(false);
670   };
671   evas_object_smart_callback_add(ewk_view_,
672                                  "fullscreen,enterfullscreen",
673                                  enter_callback,
674                                  this);
675   evas_object_smart_callback_add(ewk_view_,
676                                  "fullscreen,exitfullscreen",
677                                  exit_callback,
678                                  this);
679   smart_callbacks_["fullscreen,enterfullscreen"] = enter_callback;
680   smart_callbacks_["fullscreen,exitfullscreen"] = exit_callback;
681 }
682
683 void WebViewImpl::InitNotificationPermissionCallback() {
684   auto request_callback = [](Evas_Object*,
685                              Ewk_Notification_Permission_Request* request,
686                              void* user_data) {
687     LOGGER(DEBUG) << "Notification Permission Request";
688     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
689     if (!self->listener_) {
690       ewk_notification_permission_reply(request, EINA_FALSE);
691       return EINA_TRUE;
692     }
693
694     ewk_notification_permission_request_suspend(request);
695     auto result_handler = [request](bool result) {
696       LOGGER(DEBUG) << "Notification Permission Result : %d" << result;
697       ewk_notification_permission_reply(request, result);
698     };
699     const Ewk_Security_Origin* ewk_origin =
700         ewk_notification_permission_request_origin_get(request);
701
702     std::stringstream url;
703     url << ewk_security_origin_protocol_get(ewk_origin)
704         << "://"
705         << ewk_security_origin_host_get(ewk_origin)
706         << ":"
707         << ewk_security_origin_port_get(ewk_origin);
708     self->listener_->OnNotificationPermissionRequest(
709         self->view_,
710         url.str(),
711         result_handler);
712     return EINA_TRUE;
713   };
714   ewk_view_notification_permission_callback_set(ewk_view_,
715                                                 request_callback,
716                                                 this);
717 }
718
719 void WebViewImpl::InitGeolocationPermissionCallback() {
720   auto permission_callback = [](
721       Evas_Object*,
722       Ewk_Geolocation_Permission_Request* request,
723       void* user_data) {
724     LOGGER(DEBUG) << "Geolocation Permission Request";
725     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
726     if (self == NULL || self->listener_ == NULL) {
727       ewk_geolocation_permission_reply(request, EINA_FALSE);
728       return EINA_TRUE;
729     }
730     ewk_geolocation_permission_request_suspend(request);
731
732     const Ewk_Security_Origin* ewk_origin =
733         ewk_geolocation_permission_request_origin_get(request);
734     auto result_handler = [request](bool result) {
735       LOGGER(DEBUG) << "Geolocation Permission Result : " << result;
736       ewk_geolocation_permission_reply(request, result);
737     };
738
739     std::stringstream url;
740     url << ewk_security_origin_protocol_get(ewk_origin)
741         << "://"
742         << ewk_security_origin_host_get(ewk_origin)
743         << ":"
744         << ewk_security_origin_port_get(ewk_origin);
745
746     self->listener_->OnGeolocationPermissionRequest(
747         self->view_,
748         url.str(),
749         result_handler);
750     return EINA_TRUE;
751   };
752   ewk_view_geolocation_permission_callback_set(ewk_view_,
753                                                permission_callback,
754                                                this);
755 }
756
757 void WebViewImpl::InitAuthenticationCallback() {
758   auto auth_callback = [](void* user_data,
759                           Evas_Object*,
760                           void* event_info) {
761     LOGGER(DEBUG) << "Authentication Request";
762     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
763     Ewk_Auth_Challenge* auth_challenge =
764         static_cast<Ewk_Auth_Challenge*>(event_info);
765
766     if (self == NULL || self->listener_ == NULL) {
767       ewk_auth_challenge_credential_cancel(auth_challenge);
768       return;
769     }
770     auto result_handler = [auth_challenge](bool submit,
771                                     const std::string& id,
772                                     const std::string& password) {
773       LOGGER(DEBUG) << "Authentication Result : submit = " << submit;
774       if (!submit) {
775         ewk_auth_challenge_credential_cancel(auth_challenge);
776         return;
777       }
778       ewk_auth_challenge_credential_use(auth_challenge,
779                                         id.c_str(),
780                                         password.c_str());
781     };
782     ewk_auth_challenge_suspend(auth_challenge);
783     const char* message =
784         ewk_auth_challenge_realm_get(auth_challenge);
785     std::string url = self->GetUrl();
786     self->listener_->OnAuthenticationRequest(self->view_,
787                                              url,
788                                              message,
789                                              result_handler);
790   };
791   // "authentication,challenge"
792   evas_object_smart_callback_add(ewk_view_,
793                                  "authentication,challenge",
794                                  auth_callback,
795                                  this);
796   smart_callbacks_["authentication,challenge"] = auth_callback;
797 }
798
799 void WebViewImpl::InitCertificateAllowCallback() {
800   auto certi_callback = [](void* user_data,
801                            Evas_Object*,
802                            void* event_info) {
803     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
804     Ewk_Certificate_Policy_Decision* policy =
805       static_cast<Ewk_Certificate_Policy_Decision*>(event_info);
806
807     if (self == NULL || self->listener_ == NULL) {
808       ewk_certificate_policy_decision_allowed_set(policy, EINA_FALSE);
809       return;
810     }
811
812     ewk_certificate_policy_decision_suspend(policy);
813     auto result_handler = [policy](bool allow) {
814       ewk_certificate_policy_decision_allowed_set(policy, allow);
815     };
816
817     auto ptr = ewk_certificate_policy_decision_url_get(policy);
818     std::string url(ptr ? ptr : "");
819     ptr = ewk_certificate_policy_decision_certificate_pem_get(policy);
820     std::string pem(ptr ? ptr : "");
821     self->listener_->OnCertificateAllowRequest(self->view_,
822                                                url,
823                                                pem,
824                                                result_handler);
825   };
826   evas_object_smart_callback_add(ewk_view_,
827                                  "request,certificate,confirm",
828                                  certi_callback,
829                                  this);
830   smart_callbacks_["request,certificate,confirm"] = certi_callback;
831 }
832
833 void WebViewImpl::InitPopupWaitCallback() {
834   evas_object_smart_callback_add(ewk_view_,
835       "popup,reply,wait,start",
836       [](void* user_data, Evas_Object* /*obj*/, void*) {
837         WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
838         self->internal_popup_opened_ = true;
839 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
840         self->window_->EnableManualRotation(false);
841 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
842       }, this);
843   evas_object_smart_callback_add(ewk_view_,
844       "popup,reply,wait,finish",
845       [](void* user_data, Evas_Object* /*obj*/, void*) {
846         WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
847         self->internal_popup_opened_ = false;
848 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
849         self->window_->EnableManualRotation(true);
850 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
851       }, this);
852 }
853
854 void WebViewImpl::InitUsermediaCallback() {
855   auto callback = [](Evas_Object*,
856                      Ewk_User_Media_Permission_Request* request,
857                      void* user_data) {
858     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
859     if (self == NULL || self->listener_ == NULL) {
860       ewk_user_media_permission_reply(request, EINA_FALSE);
861       return EINA_TRUE;
862     }
863
864     ewk_user_media_permission_request_suspend(request);
865     const Ewk_Security_Origin* origin =
866         ewk_user_media_permission_request_origin_get(request);
867     std::stringstream url;
868     url << ewk_security_origin_protocol_get(origin)
869         << "://"
870         << ewk_security_origin_host_get(origin)
871         << ":"
872         << ewk_security_origin_port_get(origin);
873
874     auto result_handler = [request](bool result) {
875       LOGGER(DEBUG) << "Getusermedia Permission Result : " << result;
876       ewk_user_media_permission_reply(request, result);
877     };
878     self->listener_->OnUsermediaPermissionRequest(self->view_,
879                                                   url.str(),
880                                                   result_handler);
881     return EINA_TRUE;
882   };
883   ewk_view_user_media_permission_callback_set(ewk_view_, callback, this);
884 }
885
886 void WebViewImpl::InitEditorClientImeCallback() {
887   auto ime_changed_callback = [](void* user_data,
888                            Evas_Object*,
889                            void* event_info) {
890     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
891
892     Eina_Rectangle *rect = static_cast<Eina_Rectangle *>(event_info);
893     self->ime_width_ = rect->w;
894     self->ime_height_ = rect->h;
895   };
896
897   auto ime_opened_callback = [](void* user_data,
898                            Evas_Object*,
899                            void* event_info) {
900     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
901     if (!self->listener_)
902       return;
903
904     SoftKeyboardChangeEventValue softkeyboard_value;
905     softkeyboard_value.state = "on";
906     softkeyboard_value.width = self->ime_width_;
907     softkeyboard_value.height = self->ime_height_;
908
909     self->listener_->OnSoftKeyboardChangeEvent(self->view_, softkeyboard_value);
910   };
911
912   auto ime_closed_callback = [](void* user_data,
913                            Evas_Object*,
914                            void* event_info) {
915     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
916     if (!self->listener_)
917       return;
918
919     SoftKeyboardChangeEventValue softkeyboard_value;
920     softkeyboard_value.state = "off";
921
922     self->listener_->OnSoftKeyboardChangeEvent(self->view_, softkeyboard_value);
923   };
924   evas_object_smart_callback_add(ewk_view_,
925                                  "inputmethod,changed",
926                                  ime_changed_callback,
927                                  this);
928   evas_object_smart_callback_add(ewk_view_,
929                                  "editorclient,ime,opened",
930                                  ime_opened_callback,
931                                  this);
932   evas_object_smart_callback_add(ewk_view_,
933                                  "editorclient,ime,closed",
934                                  ime_closed_callback,
935                                  this);
936   smart_callbacks_["inputmethod,changed"] = ime_changed_callback;
937   smart_callbacks_["editorclient,ime,opened"] = ime_opened_callback;
938   smart_callbacks_["editorclient,ime,closed"] = ime_closed_callback;
939 }
940
941 #ifdef ROTARY_EVENT_FEATURE_SUPPORT
942 void WebViewImpl::InitRotaryEventCallback() {
943   auto rotary_callback = [](void* user_data,
944                          Evas_Object*,
945                          Eext_Rotary_Event_Info* event_info) -> Eina_Bool {
946     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
947     if (!self->listener_)
948       return EINA_FALSE;
949
950     Eext_Rotary_Event_Info* rotary = event_info;
951
952     RotaryEventType type;
953     if (rotary->direction == EEXT_ROTARY_DIRECTION_CLOCKWISE)
954       type = RotaryEventType::CLOCKWISE;
955     else
956       type = RotaryEventType::COUNTER_CLOCKWISE;
957
958     self->listener_->OnRotaryEvent(self->view_, type);
959     return EINA_TRUE;
960   };
961
962   // add callback to handle rotary event
963   eext_rotary_object_event_callback_add(ewk_view_, rotary_callback, this);
964   eext_rotary_object_event_activated_set(ewk_view_, EINA_TRUE);
965 }
966 #endif  // ROTARY_EVENT_FEATURE_SUPPORT
967
968 std::string WebViewImpl::GetUrl() {
969   return std::string(ewk_view_url_get(ewk_view_));
970 }
971
972 Evas_Object* WebViewImpl::evas_object() const {
973   return ewk_view_;
974 }
975
976 void WebViewImpl::OnRotation(int degree) {
977   ewk_view_orientation_send(ewk_view_, ToWebRotation(degree));
978 }
979
980 void WebViewImpl::OnKeyEvent(Eext_Callback_Type key_type) {
981   std::string keyname;
982   if (key_type == EEXT_CALLBACK_BACK) {
983     if (fullscreen_) {
984       ewk_view_fullscreen_exit(ewk_view_);
985       return;
986     }
987     if (EINA_TRUE == ewk_view_text_selection_clear(ewk_view_)) {
988       return;
989     }
990     keyname = kKeyNameBack;
991   } else if (key_type == EEXT_CALLBACK_MORE) {
992     keyname = kKeyNameMenu;
993   } else {
994     return;
995   }
996
997   if (listener_ && !internal_popup_opened_) {
998     listener_->OnHardwareKey(view_, keyname);
999   }
1000 }
1001
1002 void WebViewImpl::SetEventListener(WebView::EventListener* listener) {
1003   listener_ = listener;
1004 }
1005
1006 void WebViewImpl::SetAppInfo(const std::string& app_name,
1007                              const std::string& version) {
1008   std::string ua = app_name + "/" + version;
1009   ewk_view_application_name_for_user_agent_set(ewk_view_, ua.c_str());
1010 }
1011 bool WebViewImpl::SetUserAgent(const std::string& user_agent) {
1012   return ewk_view_user_agent_set(ewk_view_, user_agent.c_str());
1013 }
1014
1015 void WebViewImpl::SetCSPRule(const std::string& rule, bool report_only) {
1016   ewk_view_content_security_policy_set(
1017       ewk_view_,
1018       rule.c_str(),
1019       report_only ? EWK_REPORT_ONLY : EWK_ENFORCE_POLICY);
1020 }
1021
1022 void WebViewImpl::SetDefaultEncoding(const std::string& encoding) {
1023   if (ewk_settings_is_encoding_valid(encoding.c_str())) {
1024     Ewk_Settings* settings = ewk_view_settings_get(ewk_view_);
1025     ewk_settings_default_text_encoding_name_set(settings, encoding.c_str());
1026   }
1027 }
1028
1029 void WebViewImpl::SetLongPolling(unsigned long longpolling) {
1030     ewk_view_session_timeout_set(ewk_view_, longpolling);
1031 }
1032
1033 #ifdef PROFILE_WEARABLE
1034 void WebViewImpl::SetBGColor(int r, int g, int b, int a) {
1035   ewk_view_bg_color_set(ewk_view_, r, g, b, a);
1036 }
1037 #endif
1038
1039 }  // namespace runtime