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