Merge "Implement AppControl class" into devel/wrt2
[platform/framework/web/crosswalk-tizen.git] / src / runtime / web_view.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.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
17 // TODO(sngn.lee) : It should be declare in common header
18 const char* kKeyNameBack = "back";
19 const char* kKeyNameMenu = "menu";
20
21 static int ToWebRotation(int r) {
22   switch (r) {
23     case 90:
24       return -90;
25     case 270:
26       return 90;
27   }
28   return r;
29 }
30
31 static int ToNativeRotation(int r) {
32   switch (r) {
33     case -90:
34       return 90;
35     case 90:
36       return 270;
37   }
38   return r;
39 }
40
41 }  // namespace
42
43
44 WebView::WebView(NativeWindow* window, Ewk_Context* context)
45     : window_(window),
46       context_(context),
47       ewk_view_(NULL),
48       listener_(NULL) {
49   Initialize();
50 }
51
52 WebView::~WebView() {
53   window_->RemoveRotationHandler(rotation_handler_id_);
54   evas_object_del(ewk_view_);
55 }
56
57 void WebView::LoadUrl(const std::string& url) {
58   ewk_view_url_set(ewk_view_, url.c_str());
59 }
60
61 void WebView::Suspend() {
62   // suspend webview
63   ewk_view_suspend(ewk_view_);
64 }
65
66 void WebView::Resume() {
67   // resume webview
68   ewk_view_resume(ewk_view_);
69 }
70
71 void WebView::Reload() {
72   ewk_view_reload(ewk_view_);
73 }
74
75 void WebView::SetVisibility(bool show) {
76   ewk_view_visibility_set(ewk_view_, show ? EINA_TRUE : EINA_FALSE);
77 }
78
79
80 bool WebView::EvalJavascript(const std::string& script) {
81   return ewk_view_script_execute(ewk_view_, script.c_str(), NULL, NULL);
82 }
83
84 void WebView::Initialize() {
85   ewk_view_ = ewk_view_add_with_context(window_->evas_object(), context_);
86
87   // TODO(sngn.lee): To be implemented - orientation lock
88
89
90   auto key_callback = [](void* user_data,
91                          Evas_Object* /*obj*/,
92                          void* event_info) -> void {
93     WebView* self = static_cast<WebView*>(user_data);
94     Ea_Callback_Type key = static_cast<Ea_Callback_Type>(
95                               reinterpret_cast<int>(event_info));
96     self->OnKeyEvent(key);
97   };
98   ea_object_event_callback_add(ewk_view_,
99                                EA_CALLBACK_BACK,
100                                key_callback,
101                                this);
102   ea_object_event_callback_add(ewk_view_,
103                                EA_CALLBACK_MORE,
104                                key_callback,
105                                this);
106
107
108   // load statred callback
109   auto loadstart_callback = [](void* user_data,
110                                Evas_Object* /*obj*/,
111                                void*) {
112     WebView* self = static_cast<WebView*>(user_data);
113     if (self->listener_)
114       self->listener_->OnLoadStart(self);
115   };
116   evas_object_smart_callback_add(ewk_view_,
117                                  "load,started",
118                                  loadstart_callback,
119                                  this);
120   // load finished callback
121   auto loadfinished_callback = [](void* user_data,
122                                   Evas_Object*,
123                                   void*) {
124     WebView* self = static_cast<WebView*>(user_data);
125     if (self->listener_)
126       self->listener_->OnLoadFinished(self);
127   };
128   evas_object_smart_callback_add(ewk_view_,
129                                  "load,finished",
130                                  loadfinished_callback,
131                                  this);
132
133   // load progress callback
134   auto loadprogress_callback = [](void* user_data,
135                                   Evas_Object*,
136                                   void* event_info) {
137     WebView* self = static_cast<WebView*>(user_data);
138     double* progress = static_cast<double*>(event_info);
139     if (self->listener_)
140       self->listener_->OnLoadProgress(self, *progress);
141   };
142   evas_object_smart_callback_add(ewk_view_,
143                                  "load,progress",
144                                  loadprogress_callback,
145                                  this);
146   // rendered callback
147   auto rendered_callback = [](void* user_data,
148                               Evas_Object*,
149                               void*) {
150     WebView* self = static_cast<WebView*>(user_data);
151     if (self->listener_)
152       self->listener_->OnRendered(self);
153   };
154   evas_object_smart_callback_add(ewk_view_,
155                                  "frame,rendered",
156                                  rendered_callback,
157                                  this);
158
159   // "policy,navigation,decide"
160   auto navigation_decide_callback = [](void* user_data,
161                                        Evas_Object*,
162                                        void* event_info) {
163     WebView* self = static_cast<WebView*>(user_data);
164     Ewk_Policy_Decision* policy =
165             static_cast<Ewk_Policy_Decision*>(event_info);
166     const char* url = ewk_policy_decision_url_get(policy);
167
168     if (self->listener_) {
169       if (self->listener_->OnDidNavigation(self, url))
170         ewk_policy_decision_use(policy);
171       else
172         ewk_policy_decision_ignore(policy);
173     } else {
174       ewk_policy_decision_use(policy);
175     }
176   };
177   evas_object_smart_callback_add(ewk_view_,
178                                  "policy,navigation,decide",
179                                  navigation_decide_callback,
180                                  this);
181
182   // policy,newwindow,decide
183   auto newwindow_decide_callback = [](void* user_data,
184                                       Evas_Object*,
185                                       void* event_info) {
186     WebView* self = static_cast<WebView*>(user_data);
187     Ewk_Policy_Decision* policy =
188             static_cast<Ewk_Policy_Decision*>(event_info);
189
190     const char* url = ewk_policy_decision_url_get(policy);
191
192     if (self->listener_) {
193       if (self->listener_->OnDidNavigation(self, url) &&
194          self->listener_->OnDidOpenWindow(self, url)) {
195          ewk_policy_decision_use(policy);
196       } else {
197         ewk_policy_decision_ignore(policy);
198       }
199     } else {
200       ewk_policy_decision_use(policy);
201     }
202   };
203   evas_object_smart_callback_add(ewk_view_,
204                                  "policy,newwindow,decide",
205                                  newwindow_decide_callback,
206                                  this);
207
208   // callback for database quota exceeded
209   auto database_exceeded_callback = [](Evas_Object* view,
210                                        Ewk_Security_Origin* origin,
211                                        const char*,
212                                        uint64_t,
213                                        void*) -> Eina_Bool {
214     std::string protocol(ewk_security_origin_protocol_get(origin));
215     if (protocol == "file://" || protocol == "app://") {
216       // Allow for local origin
217       ewk_view_exceeded_database_quota_reply(view, EINA_TRUE);
218     } else {
219       // Deny for remote origin
220       ewk_view_exceeded_database_quota_reply(view, EINA_FALSE);
221     }
222     return EINA_TRUE;
223   };
224   ewk_view_exceeded_database_quota_callback_set(
225     ewk_view_,
226     database_exceeded_callback,
227     NULL);
228
229   // callback for indexed database quota exceeded
230   auto indexed_db_exceeded_callback = [](Evas_Object* view,
231                                        Ewk_Security_Origin* origin,
232                                        int64_t,
233                                        void*) -> Eina_Bool {
234     std::string protocol(ewk_security_origin_protocol_get(origin));
235     if (protocol == "file://" || protocol == "app://") {
236       // Allow for local origin
237       ewk_view_exceeded_indexed_database_quota_reply(view, EINA_TRUE);
238     } else {
239       // Deny for remote origin
240       ewk_view_exceeded_indexed_database_quota_reply(view, EINA_FALSE);
241     }
242     return EINA_TRUE;
243   };
244   ewk_view_exceeded_indexed_database_quota_callback_set(
245     ewk_view_,
246     indexed_db_exceeded_callback,
247     NULL);
248
249   // callback for localfile quota exceeded
250   auto localfile_exceeded_callback = [](Evas_Object* view,
251                                        Ewk_Security_Origin* origin,
252                                        int64_t,
253                                        void*) -> Eina_Bool {
254     std::string protocol(ewk_security_origin_protocol_get(origin));
255     if (protocol == "file://" || protocol == "app://") {
256       // Allow for local origin
257       ewk_view_exceeded_local_file_system_quota_reply(view, EINA_TRUE);
258     } else {
259       // Deny for remote origin
260       ewk_view_exceeded_local_file_system_quota_reply(view, EINA_FALSE);
261     }
262     return EINA_TRUE;
263   };
264   ewk_view_exceeded_local_file_system_quota_callback_set(
265     ewk_view_,
266     localfile_exceeded_callback,
267     NULL);
268
269   // wrt,message
270   auto wrt_message_callback = [](void* user_data,
271                                  Evas_Object*,
272                                  void* event_info) {
273     WebView* self = static_cast<WebView*>(user_data);
274     Ewk_IPC_Wrt_Message_Data* msg =
275         static_cast<Ewk_IPC_Wrt_Message_Data*>(event_info);
276     if (self->listener_)
277       self->listener_->OnReceivedWrtMessage(self, msg);
278   };
279   evas_object_smart_callback_add(ewk_view_,
280                                  "wrt,message",
281                                  wrt_message_callback,
282                                  this);
283
284   // Orientation lock callback
285   auto orientation_lock_callback = [](Evas_Object* o,
286                                       Eina_Bool need_lock,
287                                       int orientation,
288                                       void* user_data) -> Eina_Bool {
289     WebView* self = static_cast<WebView*>(user_data);
290     if (self->listener_) {
291       self->listener_->OnOrientationLock(self,
292                                          need_lock,
293                                          ToNativeRotation(orientation));
294     }
295     return EINA_TRUE;
296   };
297   ewk_view_orientation_lock_callback_set(ewk_view_,
298                                          orientation_lock_callback,
299                                          this);
300
301   auto console_message_callback = [](void* user_data,
302                                  Evas_Object*,
303                                  void* event_info) {
304     WebView* self = static_cast<WebView*>(user_data);
305     if (!self->listener_) {
306       return;
307     }
308     Ewk_Console_Message* msg = static_cast<Ewk_Console_Message*>(event_info);
309     unsigned int line_number = ewk_console_message_line_get(msg);
310
311     std::stringstream buf;
312     if (line_number) {
313         buf << ewk_console_message_source_get(msg) << ":";
314         buf << line_number << ":";
315     }
316     buf << ewk_console_message_text_get(msg);
317     int level = ewk_console_message_level_get(msg);
318     self->listener_->OnConsoleMessage(buf.str(), level);
319   };
320   // console log
321   evas_object_smart_callback_add(ewk_view_,
322                                  "console,message",
323                                  console_message_callback,
324                                  this);
325
326   // rotation support
327   ewk_view_orientation_send(ewk_view_, ToWebRotation(window_->rotation()));
328   rotation_handler_id_ = window_->AddRotationHandler(
329                                   std::bind(&WebView::OnRotation,
330                                   this,
331                                   std::placeholders::_1));
332   // Show webview
333   evas_object_show(ewk_view_);
334 }
335
336 std::string WebView::GetUrl() {
337   return std::string(ewk_view_url_get(ewk_view_));
338 }
339
340 Evas_Object* WebView::evas_object() const {
341   return ewk_view_;
342 }
343
344 void WebView::OnRotation(int degree) {
345   ewk_view_orientation_send(ewk_view_, ToWebRotation(degree));
346 }
347
348 void WebView::OnKeyEvent(Ea_Callback_Type key_type) {
349   std::string keyname;
350   if (key_type == EA_CALLBACK_BACK) {
351     if (EINA_TRUE == ewk_view_text_selection_clear(ewk_view_)) {
352       return;
353     }
354     keyname = kKeyNameBack;
355   } else if (key_type == EA_CALLBACK_MORE) {
356     keyname = kKeyNameMenu;
357   } else {
358     return;
359   }
360
361   if (listener_)
362     listener_->OnHardwareKey(this, keyname);
363 }
364
365 void WebView::SetEventListener(EventListener* listener) {
366   listener_ = listener;
367 }
368
369
370 }  // namespace wrt
371