fixup! [M108 Migration][API] Introduce AddJavascriptInterface for Tizen
[platform/framework/web/chromium-efl.git] / tizen_src / ewk / efl_integration / browser / javascript_interface / gin_native_bridge_dispatcher_host.cc
1 // Copyright 2017 Samsung Electronics. 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 "browser/javascript_interface/gin_native_bridge_dispatcher_host.h"
6
7 #include "base/logging.h"
8 #include "base/task/task_runner_util.h"
9 #include "browser/javascript_interface/gin_native_bridge_message_filter.h"
10 #include "common/gin_native_bridge_messages.h"
11 #include "common/gin_native_bridge_value.h"
12 #include "content/browser/renderer_host/render_frame_host_impl.h"
13 #include "content/browser/web_contents/web_contents_impl.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/render_frame_host.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/web_contents.h"
18 #include "ipc/ipc_message_utils.h"
19
20 namespace content {
21
22 GinNativeBridgeDispatcherHost::GinNativeBridgeDispatcherHost(
23     WebContents* web_contents)
24     : WebContentsObserver(web_contents), next_object_id_(1) {}
25
26 GinNativeBridgeDispatcherHost::~GinNativeBridgeDispatcherHost() {}
27
28 void GinNativeBridgeDispatcherHost::InstallFilterAndRegisterAllRoutingIds() {
29   DCHECK_CURRENTLY_ON(BrowserThread::UI);
30   if (!web_contents()->GetPrimaryMainFrame()->GetProcess()->GetChannel()) {
31     return;
32   }
33
34   web_contents()->GetPrimaryMainFrame()->ForEachRenderFrameHost(
35       [this](RenderFrameHostImpl* frame) {
36         auto filter = GinNativeBridgeMessageFilter::FromHost(this, true);
37         filter->AddRoutingIdForHost(this, frame);
38       });
39 }
40
41 void GinNativeBridgeDispatcherHost::RenderFrameCreated(
42     RenderFrameHost* render_frame_host) {
43   DCHECK_CURRENTLY_ON(BrowserThread::UI);
44
45   if (auto filter = GinNativeBridgeMessageFilter::FromHost(this, false)) {
46     filter->AddRoutingIdForHost(
47         this, static_cast<RenderFrameHostImpl*>(render_frame_host));
48   } else {
49     InstallFilterAndRegisterAllRoutingIds();
50   }
51   for (NamedObjectMap::const_iterator iter = named_objects_.begin();
52        iter != named_objects_.end(); ++iter) {
53     render_frame_host->Send(new GinNativeBridgeMsg_AddNamedObject(
54         render_frame_host->GetRoutingID(), iter->first, iter->second));
55   }
56 }
57
58 void GinNativeBridgeDispatcherHost::WebContentsDestroyed() {
59   scoped_refptr<GinNativeBridgeMessageFilter> filter =
60       GinNativeBridgeMessageFilter::FromHost(this, false);
61   if (filter)
62     filter->RemoveHost(this);
63 }
64
65 WebContentsImpl* GinNativeBridgeDispatcherHost::web_contents() const {
66   return static_cast<WebContentsImpl*>(WebContentsObserver::web_contents());
67 }
68
69 bool GinNativeBridgeDispatcherHost::AddNamedObject(
70     Evas_Object* view,
71     Ewk_View_Script_Message_Cb callback,
72     const std::string& name) {
73   LOG(INFO) << __FUNCTION__;
74   DCHECK_CURRENTLY_ON(BrowserThread::UI);
75   GinNativeBoundObject::ObjectID object_id;
76   NamedObjectMap::iterator iter = named_objects_.find(name);
77   if (iter != named_objects_.end())
78     return false;
79
80   object_id = AddObject(view, callback, name, true, 0);
81   named_objects_[name] = object_id;
82
83   InstallFilterAndRegisterAllRoutingIds();
84
85   web_contents()
86       ->GetPrimaryMainFrame()
87       ->ForEachRenderFrameHostIncludingSpeculative(
88           [&name, object_id](RenderFrameHostImpl* render_frame_host) {
89             render_frame_host->Send(new GinNativeBridgeMsg_AddNamedObject(
90                 render_frame_host->GetRoutingID(), name, object_id));
91           });
92
93   return true;
94 }
95
96 void GinNativeBridgeDispatcherHost::RemoveNamedObject(const std::string& name) {
97   DCHECK_CURRENTLY_ON(BrowserThread::UI);
98   NamedObjectMap::iterator iter = named_objects_.find(name);
99   if (iter == named_objects_.end())
100     return;
101
102   // |name| may come from |named_objects_|. Make a copy of name so that if
103   // |name| is from |named_objects_| it'll be valid after the remove below.
104   const std::string copied_name(name);
105   {
106     base::AutoLock locker(objects_lock_);
107     objects_[iter->second]->RemoveName();
108   }
109   named_objects_.erase(iter);
110
111   // As the object isn't going to be removed from the JavaScript side until the
112   // next page reload, calls to it must still work, thus we should continue to
113   // hold it. All the transient objects and removed named objects will be purged
114   // during the cleansing caused by DocumentAvailableInMainFrame event.
115   web_contents()
116       ->GetPrimaryMainFrame()
117       ->ForEachRenderFrameHostIncludingSpeculative(
118           [&copied_name](RenderFrameHostImpl* render_frame_host) {
119             render_frame_host->Send(new GinNativeBridgeMsg_RemoveNamedObject(
120                 render_frame_host->GetRoutingID(), copied_name));
121           });
122 }
123
124 GinNativeBoundObject::ObjectID GinNativeBridgeDispatcherHost::AddObject(
125     Evas_Object* view,
126     Ewk_View_Script_Message_Cb callback,
127     const std::string& name,
128     bool is_named,
129     int32_t holder) {
130   scoped_refptr<GinNativeBoundObject> new_object =
131       is_named
132           ? GinNativeBoundObject::CreateNamed(view, callback, name)
133           : GinNativeBoundObject::CreateTransient(view, callback, name, holder);
134   // Note that we are abusing the fact that StaticAtomicSequenceNumber
135   // uses Atomic32 as a counter, so it is guaranteed that it will not
136   // overflow our int32_t IDs. IDs start from 1.
137   GinNativeBoundObject::ObjectID object_id = next_object_id_++;
138   {
139     base::AutoLock locker(objects_lock_);
140     objects_[object_id] = new_object;
141   }
142   return object_id;
143 }
144
145 void GinNativeBridgeDispatcherHost::PrimaryMainDocumentElementAvailable() {
146   DCHECK_CURRENTLY_ON(BrowserThread::UI);
147   // Called when the window object has been cleared in the main frame.
148   // That means, all sub-frames have also been cleared, so only named
149   // objects survived.
150
151   NOTIMPLEMENTED();
152 }
153
154 scoped_refptr<GinNativeBoundObject> GinNativeBridgeDispatcherHost::FindObject(
155     GinNativeBoundObject::ObjectID object_id) {
156   // Can be called on any thread.
157   base::AutoLock locker(objects_lock_);
158   auto iter = objects_.find(object_id);
159   if (iter != objects_.end())
160     return iter->second;
161   LOG(ERROR) << "WebView: Unknown object: " << object_id;
162   return nullptr;
163 }
164
165 void GinNativeBridgeDispatcherHost::OnHasMethod(
166     GinNativeBoundObject::ObjectID object_id,
167     const std::string& method_name,
168     bool* result) {
169   scoped_refptr<GinNativeBoundObject> object = FindObject(object_id);
170
171   *result = (object.get()) ? true : false;
172 }
173
174 void GinNativeBridgeDispatcherHost::OnInvokeMethod(
175     int routing_id,
176     GinNativeBoundObject::ObjectID object_id,
177     const std::string& method_name,
178     const base::Value::List& arguments,
179     base::Value::List* wrapped_result,
180     content::GinNativeBridgeError* error_code) {
181   LOG(INFO) << __FUNCTION__;
182   DCHECK(routing_id != MSG_ROUTING_NONE);
183   if (method_name != "postMessage") {
184     LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeMethodNotFound";
185     wrapped_result->Append(base::Value());
186     *error_code = kGinNativeBridgeMethodNotFound;
187     return;
188   }
189
190   scoped_refptr<GinNativeBoundObject> object = FindObject(object_id);
191   if (!object.get()) {
192     LOG(ERROR) << "WebView: Unknown object: " << object_id;
193     wrapped_result->Append(base::Value());
194     *error_code = kGinNativeBridgeUnknownObjectId;
195     return;
196   }
197
198   Ewk_Script_Message msg;
199   msg.name = object->Name();
200
201   if (named_objects_.find(msg.name) == named_objects_.end()) {
202     LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeMessageNameIsWrong";
203     wrapped_result->Append(base::Value());
204     *error_code = kGinNativeBridgeMessageNameIsWrong;
205     return;
206   }
207
208   JavaScript_Values values;
209   values.bool_buf = EINA_FALSE;
210   values.int_buf = -1;
211   values.double_buf = -1;
212   values.str_buf = "";
213
214   bool bool_buf = false;
215   bool should_free = false;
216
217   base::Value::List::const_iterator iter = arguments.begin();
218
219   switch (iter->type()) {
220     case base::Value::Type::BOOLEAN:
221       bool_buf = iter->GetBool();
222       (bool_buf) ? values.bool_buf = EINA_TRUE : values.bool_buf = EINA_FALSE;
223       msg.body = &values.bool_buf;
224       break;
225     case base::Value::Type::INTEGER:
226       values.int_buf = iter->GetInt();
227       msg.body = &values.int_buf;
228       break;
229     case base::Value::Type::DOUBLE:
230       values.double_buf = iter->GetDouble();
231       msg.body = &values.double_buf;
232       break;
233     case base::Value::Type::STRING:
234       values.str_buf = iter->GetString();
235       msg.body = strdup(values.str_buf.c_str());
236       should_free = true;
237       break;
238     case base::Value::Type::DICTIONARY:
239       values.str_buf = ConvertDictionaryValueToString(iter->GetDict());
240       msg.body = strdup(values.str_buf.c_str());
241       should_free = true;
242       break;
243     case base::Value::Type::LIST:
244       values.str_buf = ConvertListValueToString(iter->GetList());
245       msg.body = strdup(values.str_buf.c_str());
246       should_free = true;
247       break;
248     case base::Value::Type::BINARY:
249       values.str_buf.assign(iter->GetBlob().begin(), iter->GetBlob().end());
250       msg.body = (void*)values.str_buf.data();
251       break;
252     default:
253       LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeNotSupportedTypes";
254       wrapped_result->Append(base::Value());
255       *error_code = kGinNativeBridgeNotSupportedTypes;
256       return;
257   }
258
259   object->CallBack()(object->GetView(), msg);
260   wrapped_result->Append(base::Value::FromUniquePtrValue(
261       GinNativeBridgeValue::CreateObjectIDValue(object_id)));
262
263   if (should_free)
264     free(msg.body);
265
266   return;
267 }
268
269 std::string GinNativeBridgeDispatcherHost::ConvertListValueToString(
270     const base::Value::List& list) {
271   bool init = false;
272   bool bool_buf = false;
273   int int_buf = -1;
274   double double_buf = -1;
275   std::string str_buf = "";
276   std::string token = "";
277
278   str_buf = "[";
279   for (base::Value::List::const_iterator iter_list = list.begin();
280        iter_list != list.end(); ++iter_list) {
281     if (init)
282       str_buf += ",";
283
284     switch (iter_list->type()) {
285       case base::Value::Type::BOOLEAN:
286         bool_buf = false;
287         bool_buf = iter_list->GetBool();
288         (bool_buf) ? str_buf += "true" : str_buf += "false";
289         break;
290       case base::Value::Type::INTEGER:
291         int_buf = -1;
292         int_buf = iter_list->GetInt();
293         str_buf += std::to_string(int_buf);
294         break;
295       case base::Value::Type::DOUBLE:
296         double_buf = -1;
297         double_buf = iter_list->GetDouble();
298         str_buf += std::to_string(double_buf);
299         break;
300       case base::Value::Type::STRING:
301         token = "";
302         token = iter_list->GetString();
303         str_buf += "\"";
304         str_buf += token;
305         str_buf += "\"";
306         break;
307       case base::Value::Type::DICTIONARY:
308         str_buf += ConvertDictionaryValueToString(iter_list->GetDict());
309         break;
310       case base::Value::Type::LIST:
311         str_buf += ConvertListValueToString(iter_list->GetList());
312         break;
313       default:
314         str_buf += "\"\"";
315         break;
316     }
317     init = true;
318   }
319   str_buf += "]";
320
321   return str_buf;
322 }
323
324 std::string GinNativeBridgeDispatcherHost::ConvertDictionaryValueToString(
325     const base::Value::Dict& dict) {
326   bool init = false;
327   bool bool_buf = false;
328   int int_buf = -1;
329   double double_buf = -1;
330   std::string str_buf = "";
331   std::string token = "";
332
333   str_buf = "{";
334   for (const auto item : dict) {
335     if (init)
336       str_buf += ",";
337     str_buf += "   \"";
338     str_buf += item.first;
339     str_buf += "\": ";
340
341     switch (item.second.type()) {
342       case base::Value::Type::BOOLEAN:
343         bool_buf = false;
344         bool_buf = item.second.GetBool();
345         (bool_buf) ? str_buf += "true" : str_buf += "false";
346         break;
347       case base::Value::Type::INTEGER:
348         int_buf = -1;
349         int_buf = item.second.GetInt();
350         str_buf += std::to_string(int_buf);
351         break;
352       case base::Value::Type::DOUBLE:
353         double_buf = -1;
354         double_buf = item.second.GetDouble();
355         str_buf += std::to_string(double_buf);
356         break;
357       case base::Value::Type::STRING:
358         token = "";
359         token = item.second.GetString();
360         str_buf += "\"";
361         str_buf += token;
362         str_buf += "\"";
363         break;
364       case base::Value::Type::DICTIONARY:
365         str_buf += ConvertDictionaryValueToString(item.second.GetDict());
366         break;
367       case base::Value::Type::LIST:
368         str_buf += ConvertListValueToString(item.second.GetList());
369         break;
370       default:
371         str_buf += "\"\"";
372         break;
373     }
374     init = true;
375   }
376   str_buf += "}";
377
378   return str_buf;
379 }
380
381 }  // namespace content