Merge "Cleanup code to remove warning messages at buildtime." into devel/wrt2
[platform/framework/web/nwrt.git] / src / runtime / web_view_impl.cc
1 // Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "runtime/web_view_impl.h"
6
7 #include <ewk_chromium.h>
8 #include <functional>
9 #include <sstream>
10
11 #include "runtime/native_window.h"
12
13 namespace wrt {
14
15 namespace {
16 // TODO(sngn.lee) : It should be declare in common header
17 const char* kKeyNameBack = "back";
18 const char* kKeyNameMenu = "menu";
19
20 static int ToWebRotation(int r) {
21   switch (r) {
22     case 90:
23       return -90;
24     case 270:
25       return 90;
26   }
27   return r;
28 }
29
30 static int ToNativeRotation(int r) {
31   switch (r) {
32     case -90:
33       return 90;
34     case 90:
35       return 270;
36   }
37   return r;
38 }
39
40 }  // namespace
41
42 WebViewImpl::WebViewImpl(WebView* view,
43                          NativeWindow* window,
44                          Ewk_Context* context)
45     : window_(window),
46       context_(context),
47       ewk_view_(NULL),
48       listener_(NULL),
49       view_(view) {
50   Initialize();
51 }
52
53 WebViewImpl::~WebViewImpl() {
54   Deinitialize();
55   evas_object_del(ewk_view_);
56 }
57
58 void WebViewImpl::LoadUrl(const std::string& url) {
59   ewk_view_url_set(ewk_view_, url.c_str());
60 }
61
62 void WebViewImpl::Suspend() {
63   // suspend webview
64   ewk_view_suspend(ewk_view_);
65 }
66
67 void WebViewImpl::Resume() {
68   // resume webview
69   ewk_view_resume(ewk_view_);
70 }
71
72 void WebViewImpl::Reload() {
73   ewk_view_reload(ewk_view_);
74 }
75
76 void WebViewImpl::SetVisibility(bool show) {
77   ewk_view_visibility_set(ewk_view_, show ? EINA_TRUE : EINA_FALSE);
78 }
79
80
81 bool WebViewImpl::EvalJavascript(const std::string& script) {
82   return ewk_view_script_execute(ewk_view_, script.c_str(), NULL, NULL);
83 }
84
85 void WebViewImpl::Initialize() {
86   ewk_view_ = ewk_view_add_with_context(window_->evas_object(), context_);
87
88   InitKeyCallback();
89   InitLoaderCallback();
90   InitPolicyDecideCallback();
91   InitQuotaExceededCallback();
92   InitIPCMessageCallback();
93   InitOrientaionLockCallback();
94   InitConsoleMessageCallback();
95   InitCustomContextMenuCallback();
96   InitRotationCallback();
97   InitWindowCreateCallback();
98
99   // TODO(sngn.lee): "request,certificate,confirm" certification popup
100   // TODO(sngn.lee): ewk_view_notification_permission_callback_set
101   // TODO(sngn.lee): "notification,show"
102   // TODO(sngn.lee): "notification,cancel"
103   // TODO(sngn.lee): "create,window"
104   // TODO(sngn.lee): "close,window"
105   // TODO(sngn.lee): "fullscreen,enterfullscreen"
106   // TODO(sngn.lee): "fullscreen,exitfullscreen"
107   // TODO(sngn.lee): "protocolhandler,registration,requested"
108   //                  custom protocol handler
109   // TODO(sngn.lee): ewk_view_geolocation_permission_callback_set
110   // TODO(sngn.lee): ewk_view_user_media_permission_callback_set
111
112   // Show webview
113   evas_object_show(ewk_view_);
114 }
115
116 void WebViewImpl::Deinitialize() {
117   auto it = smart_callbacks_.begin();
118   for ( ; it != smart_callbacks_.end(); ++it) {
119     evas_object_smart_callback_del(
120         ewk_view_,
121         it->first.c_str(),
122         it->second);
123   }
124   ea_object_event_callback_del(ewk_view_,
125                                EA_CALLBACK_BACK,
126                                smart_callbacks_["key_callback"]);
127   ewk_view_exceeded_database_quota_callback_set(
128       ewk_view_,
129       NULL,
130       NULL);
131   ewk_view_exceeded_indexed_database_quota_callback_set(
132       ewk_view_,
133       NULL,
134       NULL);
135   ewk_view_exceeded_local_file_system_quota_callback_set(
136       ewk_view_,
137       NULL,
138       NULL);
139   ewk_view_orientation_lock_callback_set(
140       ewk_view_,
141       NULL,
142       NULL);
143   window_->RemoveRotationHandler(rotation_handler_id_);
144 }
145
146 void WebViewImpl::InitKeyCallback() {
147   auto key_callback = [](void* user_data,
148                          Evas_Object* /*obj*/,
149                          void* event_info) -> void {
150     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
151     Ea_Callback_Type key = static_cast<Ea_Callback_Type>(
152                               reinterpret_cast<int>(event_info));
153     self->OnKeyEvent(key);
154   };
155   ea_object_event_callback_add(ewk_view_,
156                                EA_CALLBACK_BACK,
157                                key_callback,
158                                view_);
159   ea_object_event_callback_add(ewk_view_,
160                                EA_CALLBACK_MORE,
161                                key_callback,
162                                view_);
163   smart_callbacks_["key_callback"] = key_callback;
164 }
165
166 void WebViewImpl::InitLoaderCallback() {
167   // load statred callback
168   auto loadstart_callback = [](void* user_data,
169                                Evas_Object* /*obj*/,
170                                void*) {
171     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
172     if (self->listener_)
173       self->listener_->OnLoadStart(self->view_);
174   };
175   evas_object_smart_callback_add(ewk_view_,
176                                  "load,started",
177                                  loadstart_callback,
178                                  this);
179   // load finished callback
180   auto loadfinished_callback = [](void* user_data,
181                                   Evas_Object*,
182                                   void*) {
183     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
184     if (self->listener_)
185       self->listener_->OnLoadFinished(self->view_);
186   };
187   evas_object_smart_callback_add(ewk_view_,
188                                  "load,finished",
189                                  loadfinished_callback,
190                                  this);
191
192   // load progress callback
193   auto loadprogress_callback = [](void* user_data,
194                                   Evas_Object*,
195                                   void* event_info) {
196     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
197     double* progress = static_cast<double*>(event_info);
198     if (self->listener_)
199       self->listener_->OnLoadProgress(self->view_, *progress);
200   };
201   evas_object_smart_callback_add(ewk_view_,
202                                  "load,progress",
203                                  loadprogress_callback,
204                                  this);
205   // rendered callback
206   auto rendered_callback = [](void* user_data,
207                               Evas_Object*,
208                               void*) {
209     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
210     if (self->listener_)
211       self->listener_->OnRendered(self->view_);
212   };
213   evas_object_smart_callback_add(ewk_view_,
214                                  "frame,rendered",
215                                  rendered_callback,
216                                  this);
217   smart_callbacks_["load,started"] = loadstart_callback;
218   smart_callbacks_["load,finished"] = loadfinished_callback;
219   smart_callbacks_["load,progress"] = loadprogress_callback;
220   smart_callbacks_["frame,rendered"] = rendered_callback;
221 }
222
223 void WebViewImpl::InitPolicyDecideCallback() {
224   // "policy,navigation,decide"
225   auto navigation_decide_callback = [](void* user_data,
226                                        Evas_Object*,
227                                        void* event_info) {
228     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
229     Ewk_Policy_Decision* policy =
230             static_cast<Ewk_Policy_Decision*>(event_info);
231     const char* url = ewk_policy_decision_url_get(policy);
232
233     if (self->listener_) {
234       if (self->listener_->OnDidNavigation(self->view_, url))
235         ewk_policy_decision_use(policy);
236       else
237         ewk_policy_decision_ignore(policy);
238     } else {
239       ewk_policy_decision_use(policy);
240     }
241   };
242   evas_object_smart_callback_add(ewk_view_,
243                                  "policy,navigation,decide",
244                                  navigation_decide_callback,
245                                  this);
246
247   // policy,newwindow,decide
248   auto newwindow_decide_callback = [](void* user_data,
249                                       Evas_Object*,
250                                       void* event_info) {
251     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
252     Ewk_Policy_Decision* policy =
253             static_cast<Ewk_Policy_Decision*>(event_info);
254
255     const char* url = ewk_policy_decision_url_get(policy);
256
257     if (self->listener_) {
258       if (self->listener_->OnDidNavigation(self->view_, url) &&
259          self->listener_->OnDidOpenWindow(self->view_, url)) {
260          ewk_policy_decision_use(policy);
261       } else {
262         ewk_policy_decision_ignore(policy);
263       }
264     } else {
265       ewk_policy_decision_use(policy);
266     }
267   };
268   evas_object_smart_callback_add(ewk_view_,
269                                  "policy,newwindow,decide",
270                                  newwindow_decide_callback,
271                                  this);
272   smart_callbacks_["policy,navigation,decide"] = navigation_decide_callback;
273   smart_callbacks_["policy,newwindow,decide"] = newwindow_decide_callback;
274 }
275
276 void WebViewImpl::InitQuotaExceededCallback() {
277   // TODO(sngn.lee): Need callback interface - OnQutaExceed
278   // check http://tizen.org/privilege/unlimitedstorage
279
280   // callback for database quota exceeded
281   auto database_exceeded_callback = [](Evas_Object* view,
282                                        Ewk_Security_Origin* origin,
283                                        const char*,
284                                        uint64_t,
285                                        void*) -> Eina_Bool {
286     std::string protocol(ewk_security_origin_protocol_get(origin));
287     if (protocol == "file" || protocol == "app") {
288       // Allow for local origin
289       ewk_view_exceeded_database_quota_reply(view, EINA_TRUE);
290     } else {
291       // Deny for remote origin
292       ewk_view_exceeded_database_quota_reply(view, EINA_FALSE);
293     }
294     return EINA_TRUE;
295   };
296   ewk_view_exceeded_database_quota_callback_set(
297     ewk_view_,
298     database_exceeded_callback,
299     NULL);
300
301   // callback for indexed database quota exceeded
302   auto indexed_db_exceeded_callback = [](Evas_Object* view,
303                                        Ewk_Security_Origin* origin,
304                                        int64_t,
305                                        void*) -> Eina_Bool {
306     std::string protocol(ewk_security_origin_protocol_get(origin));
307     if (protocol == "file://" || protocol == "app://") {
308       // Allow for local origin
309       ewk_view_exceeded_indexed_database_quota_reply(view, EINA_TRUE);
310     } else {
311       // Deny for remote origin
312       ewk_view_exceeded_indexed_database_quota_reply(view, EINA_FALSE);
313     }
314     return EINA_TRUE;
315   };
316   ewk_view_exceeded_indexed_database_quota_callback_set(
317     ewk_view_,
318     indexed_db_exceeded_callback,
319     NULL);
320
321   // callback for localfile quota exceeded
322   auto localfile_exceeded_callback = [](Evas_Object* view,
323                                        Ewk_Security_Origin* origin,
324                                        int64_t,
325                                        void*) -> Eina_Bool {
326     std::string protocol(ewk_security_origin_protocol_get(origin));
327     if (protocol == "file://" || protocol == "app://") {
328       // Allow for local origin
329       ewk_view_exceeded_local_file_system_quota_reply(view, EINA_TRUE);
330     } else {
331       // Deny for remote origin
332       ewk_view_exceeded_local_file_system_quota_reply(view, EINA_FALSE);
333     }
334     return EINA_TRUE;
335   };
336   ewk_view_exceeded_local_file_system_quota_callback_set(
337     ewk_view_,
338     localfile_exceeded_callback,
339     NULL);
340 }
341
342 void WebViewImpl::InitIPCMessageCallback() {
343   // wrt,message
344   auto wrt_message_callback = [](void* user_data,
345                                  Evas_Object*,
346                                  void* event_info) {
347     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
348     Ewk_IPC_Wrt_Message_Data* msg =
349         static_cast<Ewk_IPC_Wrt_Message_Data*>(event_info);
350     if (self->listener_)
351       self->listener_->OnReceivedWrtMessage(self->view_, msg);
352   };
353   evas_object_smart_callback_add(ewk_view_,
354                                  "wrt,message",
355                                  wrt_message_callback,
356                                  this);
357   smart_callbacks_["wrt,message"] = wrt_message_callback;
358 }
359
360 void WebViewImpl::InitOrientaionLockCallback() {
361   // Orientation lock callback
362   auto orientation_lock_callback = [](Evas_Object*,
363                                       Eina_Bool need_lock,
364                                       int orientation,
365                                       void* user_data) -> Eina_Bool {
366     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
367     if (self->listener_) {
368       self->listener_->OnOrientationLock(self->view_,
369                                          need_lock,
370                                          ToNativeRotation(orientation));
371     }
372     return EINA_TRUE;
373   };
374   ewk_view_orientation_lock_callback_set(ewk_view_,
375                                          orientation_lock_callback,
376                                          this);
377 }
378
379 void WebViewImpl::InitConsoleMessageCallback() {
380   // console log
381   auto console_message_callback = [](void* user_data,
382                                  Evas_Object*,
383                                  void* event_info) {
384     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
385     if (!self->listener_) {
386       return;
387     }
388     Ewk_Console_Message* msg = static_cast<Ewk_Console_Message*>(event_info);
389     unsigned int line_number = ewk_console_message_line_get(msg);
390
391     std::stringstream buf;
392     if (line_number) {
393         buf << ewk_console_message_source_get(msg) << ":";
394         buf << line_number << ":";
395     }
396     buf << ewk_console_message_text_get(msg);
397     int level = ewk_console_message_level_get(msg);
398     self->listener_->OnConsoleMessage(buf.str(), level);
399   };
400   evas_object_smart_callback_add(ewk_view_,
401                                  "console,message",
402                                  console_message_callback,
403                                  this);
404   smart_callbacks_["console,message"] = console_message_callback;
405 }
406
407 void WebViewImpl::InitCustomContextMenuCallback() {
408   auto custom_context_menu_callback = [](void* user_data,
409                                          Evas_Object*,
410                                          void* event_info) {
411     Ewk_Context_Menu* contextmenu = static_cast<Ewk_Context_Menu*>(event_info);
412     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
413     bool disabled = false;
414     if (self->listener_ &&
415         self->listener_->OnContextMenuDisabled(self->view_)) {
416       disabled = true;
417     }
418     int cnt = ewk_context_menu_item_count(contextmenu);
419     for (unsigned idx = cnt-1; idx > 0; --idx) {
420       auto* item = ewk_context_menu_nth_item_get(contextmenu, idx);
421       Ewk_Context_Menu_Item_Tag tag = ewk_context_menu_item_tag_get(item);
422       switch (tag) {
423         case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_IMAGE_IN_NEW_WINDOW:
424         case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_LINK_IN_NEW_WINDOW:
425         case EWK_CONTEXT_MENU_ITEM_TAG_OPEN_FRAME_IN_NEW_WINDOW:
426         case EWK_CONTEXT_MENU_ITEM_TAG_SEARCH_WEB:
427         case EWK_CONTEXT_MENU_ITEM_TAG_DOWNLOAD_IMAGE_TO_DISK:
428           ewk_context_menu_item_remove(contextmenu, item);
429           break;
430         default:
431           if (disabled)
432             ewk_context_menu_item_remove(contextmenu, item);
433       }
434     }
435   };
436   evas_object_smart_callback_add(ewk_view_,
437                                  "contextmenu,customize",
438                                  custom_context_menu_callback,
439                                  this);
440   smart_callbacks_["contextmenu,customize"] = custom_context_menu_callback;
441 }
442
443 void WebViewImpl::InitRotationCallback() {
444   // rotation support
445   ewk_view_orientation_send(ewk_view_, ToWebRotation(window_->rotation()));
446   rotation_handler_id_ = window_->AddRotationHandler(
447                                   std::bind(&WebViewImpl::OnRotation,
448                                   this,
449                                   std::placeholders::_1));
450 }
451
452 void WebViewImpl::InitWindowCreateCallback() {
453   auto create_callback = [](void* user_data,
454                             Evas_Object*,
455                             void* event_info) {
456     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
457     if (!self->listener_) {
458       return;
459     }
460     WebView* new_view = new WebView(self->window_, self->context_);
461     self->listener_->OnCreatedNewWebView(self->view_, new_view);
462   };
463
464   auto close_callback = [](void* user_data,
465                             Evas_Object*,
466                             void*) {
467     WebViewImpl* self = static_cast<WebViewImpl*>(user_data);
468     if (!self->listener_) {
469       return;
470     }
471     self->listener_->OnClosedWebView(self->view_);
472   };
473   evas_object_smart_callback_add(ewk_view_,
474                                  "create,window",
475                                  create_callback,
476                                  this);
477   evas_object_smart_callback_add(ewk_view_,
478                                  "close,window",
479                                  close_callback,
480                                  this);
481
482   smart_callbacks_["create,window"] = create_callback;
483   smart_callbacks_["close,window"] = close_callback;
484 }
485
486 std::string WebViewImpl::GetUrl() {
487   return std::string(ewk_view_url_get(ewk_view_));
488 }
489
490 Evas_Object* WebViewImpl::evas_object() const {
491   return ewk_view_;
492 }
493
494 void WebViewImpl::OnRotation(int degree) {
495   ewk_view_orientation_send(ewk_view_, ToWebRotation(degree));
496 }
497
498 void WebViewImpl::OnKeyEvent(Ea_Callback_Type key_type) {
499   std::string keyname;
500   if (key_type == EA_CALLBACK_BACK) {
501     if (EINA_TRUE == ewk_view_text_selection_clear(ewk_view_)) {
502       return;
503     }
504     keyname = kKeyNameBack;
505   } else if (key_type == EA_CALLBACK_MORE) {
506     keyname = kKeyNameMenu;
507   } else {
508     return;
509   }
510
511   if (listener_)
512     listener_->OnHardwareKey(view_, keyname);
513 }
514
515 void WebViewImpl::SetEventListener(WebView::EventListener* listener) {
516   listener_ = listener;
517 }
518
519 void WebViewImpl::SetAppInfo(const std::string& app_name,
520                              const std::string& version) {
521   std::string ua = app_name + "/" + version;
522   ewk_view_application_name_for_user_agent_set(ewk_view_, ua.c_str());
523 }
524 void WebViewImpl::SetUserAgent(const std::string& user_agent) {
525   ewk_view_user_agent_set(ewk_view_, user_agent.c_str());
526 }
527
528 }  // namespace wrt