[M108 Migration][API] Introduce AddJavascriptInterface for Tizen 32/287232/4
authorGajendra N <gajendra.n@samsung.com>
Tue, 24 Jan 2023 06:45:06 +0000 (12:15 +0530)
committerBot Blink <blinkbot@samsung.com>
Thu, 26 Jan 2023 02:02:13 +0000 (02:02 +0000)
Introduces AddJavascriptInterface for tizen, adds logs for debugging and
support for posting blob type data type when using custom JS msg handler.

Additionally, on M108, due to lot of upstream changes in base/values.{h,cc}
prototypes, this patch fixes many build errors with respect to conversion
of JS types (list, blob, dict etc) to Native types.

Reference:
https://review.tizen.org/gerrit/273935

Change-Id: Id18d8756919c3730ad991ab2a2ea02f91d64131f
Signed-off-by: Gajendra N <gajendra.n@samsung.com>
28 files changed:
content/browser/renderer_host/render_frame_host_impl.cc
ipc/ipc_message_start.h
third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
tizen_src/ewk/efl_integration/BUILD.gn
tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bound_object.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bound_object.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_dispatcher_host.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_dispatcher_host.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_message_filter.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_message_filter.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/common/gin_native_bridge_errors.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/common/gin_native_bridge_errors.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/common/gin_native_bridge_messages.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/common/gin_native_bridge_value.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/common/gin_native_bridge_value.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/common/message_generator_ewk.h
tizen_src/ewk/efl_integration/eweb_view.cc
tizen_src/ewk/efl_integration/eweb_view.h
tizen_src/ewk/efl_integration/public/ewk_view.cc
tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc
tizen_src/ewk/efl_integration/renderer/gin_native_bridge_dispatcher.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/renderer/gin_native_bridge_dispatcher.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/renderer/gin_native_bridge_object.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/renderer/gin_native_bridge_object.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/renderer/gin_native_bridge_value_converter.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/renderer/gin_native_bridge_value_converter.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/renderer/gin_native_function_invocation_helper.cc [new file with mode: 0644]
tizen_src/ewk/efl_integration/renderer/gin_native_function_invocation_helper.h [new file with mode: 0644]

index c735f4a..a614089 100644 (file)
@@ -2326,6 +2326,7 @@ void RenderFrameHostImpl::ForEachRenderFrameHostImpl(
     base::FunctionRef<FrameIterationAction(RenderFrameHostImpl*)> on_frame,
     bool include_speculative) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  LOG(INFO) << __FUNCTION__;
 
   if (!include_speculative &&
       (lifecycle_state() == LifecycleStateImpl::kSpeculative ||
index 8c91037..7758a5f 100644 (file)
@@ -27,6 +27,7 @@ enum IPCMessageStart {
   TtsMsgStart,
 #endif
   ExtensionWorkerMsgStart,
+  GinNativeBridgeMsgStart,
   LastIPCMsgStart  // Must come last.
 };
 
index 4716b95..4dd8501 100644 (file)
@@ -943,6 +943,7 @@ void LocalFrameMojoHandler::JavaScriptExecuteRequestForTests(
     bool resolve_promises,
     int32_t world_id,
     JavaScriptExecuteRequestForTestsCallback callback) {
+  LOG(INFO) << __FUNCTION__;
   TRACE_EVENT_INSTANT0("test_tracing", "JavaScriptExecuteRequestForTests",
                        TRACE_EVENT_SCOPE_THREAD);
 
index c04d0c6..bfbb46a 100755 (executable)
@@ -313,6 +313,12 @@ shared_library("chromium-ewk") {
     "browser/input_picker/color_chooser_efl.h",
     "browser/input_picker/input_picker.cc",
     "browser/input_picker/input_picker.h",
+    "browser/javascript_interface/gin_native_bound_object.cc",
+    "browser/javascript_interface/gin_native_bound_object.h",
+    "browser/javascript_interface/gin_native_bridge_dispatcher_host.cc",
+    "browser/javascript_interface/gin_native_bridge_dispatcher_host.h",
+    "browser/javascript_interface/gin_native_bridge_message_filter.cc",
+    "browser/javascript_interface/gin_native_bridge_message_filter.h",
     "browser/network_service/browser_url_loader_throttle_efl.cc",
     "browser/network_service/browser_url_loader_throttle_efl.h",
     "browser/notification/notification_controller_efl.cc",
@@ -345,6 +351,11 @@ shared_library("chromium-ewk") {
     "common/content_switches_efl.cc",
     "common/content_switches_efl.h",
     "common/editing_messages.h",
+    "common/gin_native_bridge_errors.cc",
+    "common/gin_native_bridge_errors.h",
+    "common/gin_native_bridge_messages.h",
+    "common/gin_native_bridge_value.cc",
+    "common/gin_native_bridge_value.h",
     "common/hit_test_params.h",
     "common/message_generator_ewk.cc",
     "common/message_generator_ewk.h",
@@ -549,6 +560,16 @@ shared_library("chromium-ewk") {
     "renderer/content_renderer_client_efl.h",
     "renderer/content_settings_client_efl.cc",
     "renderer/content_settings_client_efl.h",
+    "renderer/gin_native_bridge_dispatcher.cc",
+    "renderer/gin_native_bridge_dispatcher.h",
+    "renderer/gin_native_bridge_object.cc",
+    "renderer/gin_native_bridge_object.h",
+    "renderer/gin_native_bridge_value_converter.cc",
+    "renderer/gin_native_bridge_value_converter.h",
+    "renderer/gin_native_function_invocation_helper.cc",
+    "renderer/gin_native_function_invocation_helper.h",
+    "renderer/plugins/plugin_placeholder_efl.cc",
+    "renderer/plugins/plugin_placeholder_efl.h",
     "renderer/print_web_view_helper_efl.cc",
     "renderer/print_web_view_helper_efl.h",
     "renderer/render_frame_observer_efl.cc",
diff --git a/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bound_object.cc b/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bound_object.cc
new file mode 100644 (file)
index 0000000..a16ee7a
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "browser/javascript_interface/gin_native_bound_object.h"
+
+namespace content {
+
+GinNativeBoundObject::GinNativeBoundObject(Evas_Object* obj,
+                                           Ewk_View_Script_Message_Cb callback,
+                                           const std::string& name)
+    : obj_(obj), callback_(callback), name_(name), names_count_(0) {}
+
+GinNativeBoundObject::GinNativeBoundObject(Evas_Object* obj,
+                                           Ewk_View_Script_Message_Cb callback,
+                                           const std::string& name,
+                                           const std::set<int32_t>& holders)
+    : obj_(obj),
+      callback_(callback),
+      name_(name),
+      names_count_(0),
+      holders_(holders) {}
+
+// static
+GinNativeBoundObject* GinNativeBoundObject::CreateNamed(
+    Evas_Object* obj,
+    Ewk_View_Script_Message_Cb callback,
+    const std::string& name) {
+  return new GinNativeBoundObject(obj, callback, name);
+}
+
+// static
+GinNativeBoundObject* GinNativeBoundObject::CreateTransient(
+    Evas_Object* obj,
+    Ewk_View_Script_Message_Cb callback,
+    const std::string& name,
+    int32_t holder) {
+  std::set<int32_t> holders;
+  holders.insert(holder);
+  return new GinNativeBoundObject(obj, callback, name, holders);
+}
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bound_object.h b/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bound_object.h
new file mode 100644 (file)
index 0000000..d95658f
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BOUND_OBJECT_H_
+#define EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BOUND_OBJECT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <set>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "public/ewk_view.h"
+
+namespace content {
+
+class GinNativeBoundObject
+    : public base::RefCountedThreadSafe<GinNativeBoundObject> {
+ public:
+  typedef int32_t ObjectID;
+  static GinNativeBoundObject* CreateNamed(Evas_Object* obj,
+                                           Ewk_View_Script_Message_Cb callback,
+                                           const std::string& name);
+  static GinNativeBoundObject* CreateTransient(
+      Evas_Object* obj,
+      Ewk_View_Script_Message_Cb callback,
+      const std::string& name,
+      int32_t holder);
+  void AddName() { ++names_count_; }
+  void RemoveName() { --names_count_; }
+  Evas_Object* GetView() const { return obj_; }
+  Ewk_View_Script_Message_Cb CallBack() const { return callback_; }
+  const char* Name() const { return name_.c_str(); }
+
+ private:
+  friend class base::RefCountedThreadSafe<GinNativeBoundObject>;
+  GinNativeBoundObject(Evas_Object* obj,
+                       Ewk_View_Script_Message_Cb callback,
+                       const std::string& name);
+  GinNativeBoundObject(Evas_Object* obj,
+                       Ewk_View_Script_Message_Cb callback,
+                       const std::string& name,
+                       const std::set<int32_t>& holders);
+  ~GinNativeBoundObject(){};
+
+  GinNativeBoundObject(const GinNativeBoundObject&) = delete;
+  GinNativeBoundObject& operator=(const GinNativeBoundObject&) = delete;
+
+  Evas_Object* obj_;
+  Ewk_View_Script_Message_Cb callback_;
+  std::string name_;
+
+  // An object must be kept in retained_object_set_ either if it has
+  // names or if it has a non-empty holders set.
+  int names_count_;
+  std::set<int32_t> holders_;
+};
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BOUND_OBJECT_H_
diff --git a/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_dispatcher_host.cc b/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_dispatcher_host.cc
new file mode 100644 (file)
index 0000000..145925c
--- /dev/null
@@ -0,0 +1,381 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "browser/javascript_interface/gin_native_bridge_dispatcher_host.h"
+
+#include "base/logging.h"
+#include "base/task/task_runner_util.h"
+#include "browser/javascript_interface/gin_native_bridge_message_filter.h"
+#include "common/gin_native_bridge_messages.h"
+#include "common/gin_native_bridge_value.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace content {
+
+GinNativeBridgeDispatcherHost::GinNativeBridgeDispatcherHost(
+    WebContents* web_contents)
+    : WebContentsObserver(web_contents), next_object_id_(1) {}
+
+GinNativeBridgeDispatcherHost::~GinNativeBridgeDispatcherHost() {}
+
+void GinNativeBridgeDispatcherHost::InstallFilterAndRegisterAllRoutingIds() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!web_contents()->GetPrimaryMainFrame()->GetProcess()->GetChannel()) {
+    return;
+  }
+
+  web_contents()->GetPrimaryMainFrame()->ForEachRenderFrameHost(
+      [this](RenderFrameHostImpl* frame) {
+        auto filter = GinNativeBridgeMessageFilter::FromHost(this, true);
+        filter->AddRoutingIdForHost(this, frame);
+      });
+}
+
+void GinNativeBridgeDispatcherHost::RenderFrameCreated(
+    RenderFrameHost* render_frame_host) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  if (auto filter = GinNativeBridgeMessageFilter::FromHost(this, false)) {
+    filter->AddRoutingIdForHost(
+        this, static_cast<RenderFrameHostImpl*>(render_frame_host));
+  } else {
+    InstallFilterAndRegisterAllRoutingIds();
+  }
+  for (NamedObjectMap::const_iterator iter = named_objects_.begin();
+       iter != named_objects_.end(); ++iter) {
+    render_frame_host->Send(new GinNativeBridgeMsg_AddNamedObject(
+        render_frame_host->GetRoutingID(), iter->first, iter->second));
+  }
+}
+
+void GinNativeBridgeDispatcherHost::WebContentsDestroyed() {
+  scoped_refptr<GinNativeBridgeMessageFilter> filter =
+      GinNativeBridgeMessageFilter::FromHost(this, false);
+  if (filter)
+    filter->RemoveHost(this);
+}
+
+WebContentsImpl* GinNativeBridgeDispatcherHost::web_contents() const {
+  return static_cast<WebContentsImpl*>(WebContentsObserver::web_contents());
+}
+
+bool GinNativeBridgeDispatcherHost::AddNamedObject(
+    Evas_Object* view,
+    Ewk_View_Script_Message_Cb callback,
+    const std::string& name) {
+  LOG(INFO) << __FUNCTION__;
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  GinNativeBoundObject::ObjectID object_id;
+  NamedObjectMap::iterator iter = named_objects_.find(name);
+  if (iter != named_objects_.end())
+    return false;
+
+  object_id = AddObject(view, callback, name, true, 0);
+  named_objects_[name] = object_id;
+
+  InstallFilterAndRegisterAllRoutingIds();
+
+  web_contents()
+      ->GetPrimaryMainFrame()
+      ->ForEachRenderFrameHostIncludingSpeculative(
+          [&name, object_id](RenderFrameHostImpl* render_frame_host) {
+            render_frame_host->Send(new GinNativeBridgeMsg_AddNamedObject(
+                render_frame_host->GetRoutingID(), name, object_id));
+          });
+
+  return true;
+}
+
+void GinNativeBridgeDispatcherHost::RemoveNamedObject(const std::string& name) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  NamedObjectMap::iterator iter = named_objects_.find(name);
+  if (iter == named_objects_.end())
+    return;
+
+  // |name| may come from |named_objects_|. Make a copy of name so that if
+  // |name| is from |named_objects_| it'll be valid after the remove below.
+  const std::string copied_name(name);
+  {
+    base::AutoLock locker(objects_lock_);
+    objects_[iter->second]->RemoveName();
+  }
+  named_objects_.erase(iter);
+
+  // As the object isn't going to be removed from the JavaScript side until the
+  // next page reload, calls to it must still work, thus we should continue to
+  // hold it. All the transient objects and removed named objects will be purged
+  // during the cleansing caused by DocumentAvailableInMainFrame event.
+  web_contents()
+      ->GetPrimaryMainFrame()
+      ->ForEachRenderFrameHostIncludingSpeculative(
+          [&copied_name](RenderFrameHostImpl* render_frame_host) {
+            render_frame_host->Send(new GinNativeBridgeMsg_RemoveNamedObject(
+                render_frame_host->GetRoutingID(), copied_name));
+          });
+}
+
+GinNativeBoundObject::ObjectID GinNativeBridgeDispatcherHost::AddObject(
+    Evas_Object* view,
+    Ewk_View_Script_Message_Cb callback,
+    const std::string& name,
+    bool is_named,
+    int32_t holder) {
+  scoped_refptr<GinNativeBoundObject> new_object =
+      is_named
+          ? GinNativeBoundObject::CreateNamed(view, callback, name)
+          : GinNativeBoundObject::CreateTransient(view, callback, name, holder);
+  // Note that we are abusing the fact that StaticAtomicSequenceNumber
+  // uses Atomic32 as a counter, so it is guaranteed that it will not
+  // overflow our int32_t IDs. IDs start from 1.
+  GinNativeBoundObject::ObjectID object_id = next_object_id_++;
+  {
+    base::AutoLock locker(objects_lock_);
+    objects_[object_id] = new_object;
+  }
+  return object_id;
+}
+
+void GinNativeBridgeDispatcherHost::PrimaryMainDocumentElementAvailable() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // Called when the window object has been cleared in the main frame.
+  // That means, all sub-frames have also been cleared, so only named
+  // objects survived.
+
+  NOTIMPLEMENTED();
+}
+
+scoped_refptr<GinNativeBoundObject> GinNativeBridgeDispatcherHost::FindObject(
+    GinNativeBoundObject::ObjectID object_id) {
+  // Can be called on any thread.
+  base::AutoLock locker(objects_lock_);
+  auto iter = objects_.find(object_id);
+  if (iter != objects_.end())
+    return iter->second;
+  LOG(ERROR) << "WebView: Unknown object: " << object_id;
+  return nullptr;
+}
+
+void GinNativeBridgeDispatcherHost::OnHasMethod(
+    GinNativeBoundObject::ObjectID object_id,
+    const std::string& method_name,
+    bool* result) {
+  scoped_refptr<GinNativeBoundObject> object = FindObject(object_id);
+
+  *result = (object.get()) ? true : false;
+}
+
+void GinNativeBridgeDispatcherHost::OnInvokeMethod(
+    int routing_id,
+    GinNativeBoundObject::ObjectID object_id,
+    const std::string& method_name,
+    const base::Value::List& arguments,
+    base::Value::List* wrapped_result,
+    content::GinNativeBridgeError* error_code) {
+  LOG(INFO) << __FUNCTION__;
+  DCHECK(routing_id != MSG_ROUTING_NONE);
+  if (method_name != "postMessage") {
+    LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeMethodNotFound";
+    wrapped_result->Append(base::Value());
+    *error_code = kGinNativeBridgeMethodNotFound;
+    return;
+  }
+
+  scoped_refptr<GinNativeBoundObject> object = FindObject(object_id);
+  if (!object.get()) {
+    LOG(ERROR) << "WebView: Unknown object: " << object_id;
+    wrapped_result->Append(base::Value());
+    *error_code = kGinNativeBridgeUnknownObjectId;
+    return;
+  }
+
+  Ewk_Script_Message msg;
+  msg.name = object->Name();
+
+  if (named_objects_.find(msg.name) == named_objects_.end()) {
+    LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeMessageNameIsWrong";
+    wrapped_result->Append(base::Value());
+    *error_code = kGinNativeBridgeMessageNameIsWrong;
+    return;
+  }
+
+  JavaScript_Values values;
+  values.bool_buf = EINA_FALSE;
+  values.int_buf = -1;
+  values.double_buf = -1;
+  values.str_buf = "";
+
+  bool bool_buf = false;
+  bool should_free = false;
+
+  base::Value::List::const_iterator iter = arguments.begin();
+
+  switch (iter->type()) {
+    case base::Value::Type::BOOLEAN:
+      bool_buf = iter->GetBool();
+      (bool_buf) ? values.bool_buf = EINA_TRUE : values.bool_buf = EINA_FALSE;
+      msg.body = &values.bool_buf;
+      break;
+    case base::Value::Type::INTEGER:
+      values.int_buf = iter->GetInt();
+      msg.body = &values.int_buf;
+      break;
+    case base::Value::Type::DOUBLE:
+      values.double_buf = iter->GetDouble();
+      msg.body = &values.double_buf;
+      break;
+    case base::Value::Type::STRING:
+      values.str_buf = iter->GetString();
+      msg.body = strdup(values.str_buf.c_str());
+      should_free = true;
+      break;
+    case base::Value::Type::DICTIONARY:
+      values.str_buf = ConvertDictionaryValueToString(iter->GetDict());
+      msg.body = strdup(values.str_buf.c_str());
+      should_free = true;
+      break;
+    case base::Value::Type::LIST:
+      values.str_buf = ConvertListValueToString(iter->GetList());
+      msg.body = strdup(values.str_buf.c_str());
+      should_free = true;
+      break;
+    case base::Value::Type::BINARY:
+      values.str_buf.assign(iter->GetBlob().begin(), iter->GetBlob().end());
+      msg.body = (void*)values.str_buf.data();
+      break;
+    default:
+      LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeNotSupportedTypes";
+      wrapped_result->Append(base::Value());
+      *error_code = kGinNativeBridgeNotSupportedTypes;
+      return;
+  }
+
+  object->CallBack()(object->GetView(), msg);
+  wrapped_result->Append(base::Value::FromUniquePtrValue(
+      GinNativeBridgeValue::CreateObjectIDValue(object_id)));
+
+  if (should_free)
+    free(msg.body);
+
+  return;
+}
+
+std::string GinNativeBridgeDispatcherHost::ConvertListValueToString(
+    const base::Value::List& list) {
+  bool init = false;
+  bool bool_buf = false;
+  int int_buf = -1;
+  double double_buf = -1;
+  std::string str_buf = "";
+  std::string token = "";
+
+  str_buf = "[";
+  for (base::Value::List::const_iterator iter_list = list.begin();
+       iter_list != list.end(); ++iter_list) {
+    if (init)
+      str_buf += ",";
+
+    switch (iter_list->type()) {
+      case base::Value::Type::BOOLEAN:
+        bool_buf = false;
+        bool_buf = iter_list->GetBool();
+        (bool_buf) ? str_buf += "true" : str_buf += "false";
+        break;
+      case base::Value::Type::INTEGER:
+        int_buf = -1;
+        int_buf = iter_list->GetInt();
+        str_buf += std::to_string(int_buf);
+        break;
+      case base::Value::Type::DOUBLE:
+        double_buf = -1;
+        double_buf = iter_list->GetDouble();
+        str_buf += std::to_string(double_buf);
+        break;
+      case base::Value::Type::STRING:
+        token = "";
+        token = iter_list->GetString();
+        str_buf += "\"";
+        str_buf += token;
+        str_buf += "\"";
+        break;
+      case base::Value::Type::DICTIONARY:
+        str_buf = ConvertDictionaryValueToString(iter_list->GetDict());
+        break;
+      case base::Value::Type::LIST:
+        str_buf += ConvertListValueToString(iter_list->GetList());
+        break;
+      default:
+        str_buf += "\"\"";
+        break;
+    }
+    init = true;
+  }
+  str_buf += "]";
+
+  return str_buf;
+}
+
+std::string GinNativeBridgeDispatcherHost::ConvertDictionaryValueToString(
+    const base::Value::Dict& dict) {
+  bool init = false;
+  bool bool_buf = false;
+  int int_buf = -1;
+  double double_buf = -1;
+  std::string str_buf = "";
+  std::string token = "";
+
+  str_buf = "{";
+  for (const auto item : dict) {
+    if (init)
+      str_buf += ",";
+    str_buf += "   \"";
+    str_buf += item.first;
+    str_buf += "\": ";
+
+    switch (item.second.type()) {
+      case base::Value::Type::BOOLEAN:
+        bool_buf = false;
+        bool_buf = item.second.GetBool();
+        (bool_buf) ? str_buf += "true" : str_buf += "false";
+        break;
+      case base::Value::Type::INTEGER:
+        int_buf = -1;
+        int_buf = item.second.GetInt();
+        str_buf += std::to_string(int_buf);
+        break;
+      case base::Value::Type::DOUBLE:
+        double_buf = -1;
+        double_buf = item.second.GetDouble();
+        str_buf += std::to_string(double_buf);
+        break;
+      case base::Value::Type::STRING:
+        token = "";
+        token = item.second.GetString();
+        str_buf += "\"";
+        str_buf += token;
+        str_buf += "\"";
+        break;
+      case base::Value::Type::DICTIONARY:
+        str_buf += ConvertDictionaryValueToString(item.second.GetDict());
+        break;
+      case base::Value::Type::LIST:
+        str_buf += ConvertListValueToString(item.second.GetList());
+        break;
+      default:
+        str_buf += "\"\"";
+        break;
+    }
+    init = true;
+  }
+  str_buf += "}";
+
+  return str_buf;
+}
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_dispatcher_host.h b/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_dispatcher_host.h
new file mode 100644 (file)
index 0000000..43df6ef
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BRIDGE_DISPATCHER_HOST_H_
+#define EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BRIDGE_DISPATCHER_HOST_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "browser/javascript_interface/gin_native_bound_object.h"
+#include "common/gin_native_bridge_errors.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "public/ewk_view.h"
+
+namespace content {
+
+class GinNativeBridgeDispatcherHost
+    : public base::RefCountedThreadSafe<GinNativeBridgeDispatcherHost>,
+      public WebContentsObserver {
+ public:
+  explicit GinNativeBridgeDispatcherHost(WebContents* web_contents);
+  ~GinNativeBridgeDispatcherHost() override;
+
+  GinNativeBridgeDispatcherHost(const GinNativeBridgeDispatcherHost&) = delete;
+  GinNativeBridgeDispatcherHost& operator=(
+      const GinNativeBridgeDispatcherHost&) = delete;
+
+  // WebContentsObserver
+  void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
+  void WebContentsDestroyed() override;
+  void PrimaryMainDocumentElementAvailable() override;
+
+  bool AddNamedObject(Evas_Object* view,
+                      Ewk_View_Script_Message_Cb callback,
+                      const std::string& name);
+  void RemoveNamedObject(const std::string& name);
+  void OnHasMethod(GinNativeBoundObject::ObjectID object_id,
+                   const std::string& method_name,
+                   bool* result);
+
+  void OnInvokeMethod(int routing_id,
+                      GinNativeBoundObject::ObjectID object_id,
+                      const std::string& method_name,
+                      const base::Value::List& arguments,
+                      base::Value::List* result,
+                      content::GinNativeBridgeError* error_code);
+  WebContentsImpl* web_contents() const;
+
+ private:
+  friend class base::RefCountedThreadSafe<GinNativeBridgeDispatcherHost>;
+  typedef std::map<GinNativeBoundObject::ObjectID,
+                   scoped_refptr<GinNativeBoundObject>>
+      ObjectMap;
+
+  // Run on the UI thread.
+  void InstallFilterAndRegisterAllRoutingIds();
+
+  bool FindObjectId();
+  GinNativeBoundObject::ObjectID AddObject(Evas_Object* view,
+                                           Ewk_View_Script_Message_Cb callback,
+                                           const std::string& name,
+                                           bool is_named,
+                                           int32_t holder);
+  scoped_refptr<GinNativeBoundObject> FindObject(
+      GinNativeBoundObject::ObjectID object_id);
+
+  std::string ConvertListValueToString(const base::Value::List& list);
+
+  std::string ConvertDictionaryValueToString(const base::Value::Dict& dict);
+
+  typedef std::map<std::string, GinNativeBoundObject::ObjectID> NamedObjectMap;
+  NamedObjectMap named_objects_;
+
+  GinNativeBoundObject::ObjectID next_object_id_;
+
+  // Note that retained_object_set_ does not need to be consistent
+  // with objects_.
+  ObjectMap objects_;
+  base::Lock objects_lock_;
+
+  struct _JavaScript_Values {
+    Eina_Bool bool_buf;  /**< Buffer for boolean */
+    int int_buf;         /**< Buffer for integer  */
+    double double_buf;   /**< Buffer for double  */
+    std::string str_buf; /**< Buffer for string  */
+  };
+  typedef struct _JavaScript_Values JavaScript_Values;
+};
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BRIDGE_DISPATCHER_HOST_H_
diff --git a/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_message_filter.cc b/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_message_filter.cc
new file mode 100644 (file)
index 0000000..2eacac2
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "browser/javascript_interface/gin_native_bridge_message_filter.h"
+
+#include "base/auto_reset.h"
+#include "browser/javascript_interface/gin_native_bridge_dispatcher_host.h"
+#include "common/gin_native_bridge_messages.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace {
+const char kGinNativeBridgeMessageFilterKey[] = "GinNativeBridgeMessageFilter";
+}  // namespace
+
+namespace content {
+
+GinNativeBridgeMessageFilter::GinNativeBridgeMessageFilter()
+    : BrowserMessageFilter(GinNativeBridgeMsgStart),
+      current_routing_id_(MSG_ROUTING_NONE) {}
+
+GinNativeBridgeMessageFilter::~GinNativeBridgeMessageFilter() {}
+
+void GinNativeBridgeMessageFilter::OnDestruct() const {
+  if (BrowserThread::CurrentlyOn(BrowserThread::UI))
+    delete this;
+  else
+    BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
+}
+
+bool GinNativeBridgeMessageFilter::OnMessageReceived(
+    const IPC::Message& message) {
+  base::AutoReset<int32_t> routing_id(&current_routing_id_,
+                                      message.routing_id());
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(GinNativeBridgeMessageFilter, message)
+    IPC_MESSAGE_HANDLER(GinNativeBridgeHostMsg_HasMethod, OnHasMethod)
+    IPC_MESSAGE_HANDLER(GinNativeBridgeHostMsg_InvokeMethod, OnInvokeMethod)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+scoped_refptr<base::SequencedTaskRunner>
+GinNativeBridgeMessageFilter::OverrideTaskRunnerForMessage(
+    const IPC::Message& message) {
+  // As the filter is only invoked for the messages of the particular class,
+  // we can return the task runner unconfitionally.
+  return nullptr;
+}
+
+void GinNativeBridgeMessageFilter::AddRoutingIdForHost(
+    GinNativeBridgeDispatcherHost* host,
+    RenderFrameHostImpl* render_frame_host) {
+  base::AutoLock locker(hosts_lock_);
+  hosts_[render_frame_host->GetRoutingID()] = host;
+}
+
+void GinNativeBridgeMessageFilter::RemoveHost(
+    GinNativeBridgeDispatcherHost* host) {
+  base::AutoLock locker(hosts_lock_);
+  auto iter = hosts_.begin();
+  while (iter != hosts_.end()) {
+    if (iter->second == host)
+      hosts_.erase(iter++);
+    else
+      ++iter;
+  }
+}
+
+// static
+scoped_refptr<GinNativeBridgeMessageFilter>
+GinNativeBridgeMessageFilter::FromHost(GinNativeBridgeDispatcherHost* host,
+                                       bool create_if_not_exists) {
+  RenderProcessHost* rph =
+      host->web_contents()->GetPrimaryMainFrame()->GetProcess();
+  scoped_refptr<GinNativeBridgeMessageFilter> filter =
+      base::UserDataAdapter<GinNativeBridgeMessageFilter>::Get(
+          rph, kGinNativeBridgeMessageFilterKey);
+  if (!filter && create_if_not_exists) {
+    filter = new GinNativeBridgeMessageFilter();
+    rph->AddFilter(filter.get());
+    rph->SetUserData(
+        kGinNativeBridgeMessageFilterKey,
+        base::WrapUnique(
+            new base::UserDataAdapter<GinNativeBridgeMessageFilter>(
+                filter.get())));
+  }
+  return filter;
+}
+
+GinNativeBridgeDispatcherHost* GinNativeBridgeMessageFilter::FindHost() {
+  base::AutoLock locker(hosts_lock_);
+  auto iter = hosts_.find(current_routing_id_);
+  if (iter != hosts_.end())
+    return iter->second;
+  // This is usually OK -- we can receive messages form RenderFrames for
+  // which the corresponding host part has already been destroyed. That means,
+  // any references to Native objects that the host was holding were already
+  // released (with the death of ContentViewCore), so we can just drop such
+  // messages.
+  LOG(WARNING) << "WebView: Unknown frame routing id: " << current_routing_id_;
+  return nullptr;
+}
+
+void GinNativeBridgeMessageFilter::OnHasMethod(
+    GinNativeBoundObject::ObjectID object_id,
+    const std::string& method_name,
+    bool* result) {
+  GinNativeBridgeDispatcherHost* host = FindHost();
+  if (host)
+    host->OnHasMethod(object_id, method_name, result);
+  else
+    *result = false;
+}
+
+void GinNativeBridgeMessageFilter::OnInvokeMethod(
+    GinNativeBoundObject::ObjectID object_id,
+    const std::string& method_name,
+    const base::Value::List& arguments,
+    base::Value::List* wrapped_result,
+    content::GinNativeBridgeError* error_code) {
+  LOG(INFO) << __FUNCTION__;
+  GinNativeBridgeDispatcherHost* host = FindHost();
+  if (host) {
+    host->OnInvokeMethod(current_routing_id_, object_id, method_name, arguments,
+                         wrapped_result, error_code);
+  } else {
+    wrapped_result->Append(base::Value());
+    *error_code = kGinNativeBridgeRenderFrameDeleted;
+  }
+}
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_message_filter.h b/tizen_src/ewk/efl_integration/browser/javascript_interface/gin_native_bridge_message_filter.h
new file mode 100644 (file)
index 0000000..dbb24c6
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BRIDGE_MESSAGE_FILTER_H_
+#define EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BRIDGE_MESSAGE_FILTER_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/values.h"
+#include "browser/javascript_interface/gin_native_bound_object.h"
+#include "common/gin_native_bridge_errors.h"
+#include "content/public/browser/browser_message_filter.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace content {
+
+class GinNativeBridgeDispatcherHost;
+class RenderFrameHostImpl;
+
+class GinNativeBridgeMessageFilter : public BrowserMessageFilter {
+ public:
+  // BrowserMessageFilter
+  void OnDestruct() const override;
+  bool OnMessageReceived(const IPC::Message& message) override;
+  scoped_refptr<base::SequencedTaskRunner> OverrideTaskRunnerForMessage(
+      const IPC::Message& message) override;
+
+  // Called on the UI thread.
+  void AddRoutingIdForHost(GinNativeBridgeDispatcherHost* host,
+                           RenderFrameHostImpl* render_frame_host);
+  void RemoveHost(GinNativeBridgeDispatcherHost* host);
+
+  static scoped_refptr<GinNativeBridgeMessageFilter> FromHost(
+      GinNativeBridgeDispatcherHost* host,
+      bool create_if_not_exists);
+
+ private:
+  friend class BrowserThread;
+  friend class base::DeleteHelper<GinNativeBridgeMessageFilter>;
+
+  // WebView (who owns GinNativeBridgeDispatcherHost) outlives
+  // WebContents, and GinNativeBridgeDispatcherHost removes itself form the map
+  // on WebContents destruction, so there is no risk that the pointer would
+  // become stale.
+  //
+  // The filter keeps its own routing map of RenderFrames for two reasons:
+  //  1. Message dispatching must be done on the background thread,
+  //     without resorting to the UI thread, which can be in fact currently
+  //     blocked, waiting for an event from an injected Native object.
+  //  2. As RenderFrames pass away earlier than JavaScript wrappers,
+  //     messages form the latter can arrive after the RenderFrame has been
+  //     removed from the WebContent's routing table.
+  typedef std::map<int32_t, GinNativeBridgeDispatcherHost*> HostMap;
+
+  GinNativeBridgeMessageFilter();
+  ~GinNativeBridgeMessageFilter() override;
+
+  GinNativeBridgeMessageFilter(const GinNativeBridgeMessageFilter&) = delete;
+  GinNativeBridgeMessageFilter& operator=(const GinNativeBridgeMessageFilter&) =
+      delete;
+
+  // Called on the background thread.
+  GinNativeBridgeDispatcherHost* FindHost();
+  void OnHasMethod(GinNativeBoundObject::ObjectID object_id,
+                   const std::string& method_name,
+                   bool* result);
+  void OnInvokeMethod(GinNativeBoundObject::ObjectID object_id,
+                      const std::string& method_name,
+                      const base::Value::List& arguments,
+                      base::Value::List* result,
+                      content::GinNativeBridgeError* error_code);
+
+  // Accessed both from UI and background threads.
+  HostMap hosts_;
+  base::Lock hosts_lock_;
+
+  // The routing id of the RenderFrameHost whose request we are processing.
+  // Used on the backgrount thread.
+  int32_t current_routing_id_;
+};
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_INTERFACE_GIN_NATIVE_BRIDGE_MESSAGE_FILTER_H_
diff --git a/tizen_src/ewk/efl_integration/common/gin_native_bridge_errors.cc b/tizen_src/ewk/efl_integration/common/gin_native_bridge_errors.cc
new file mode 100644 (file)
index 0000000..dd8184a
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "common/gin_native_bridge_errors.h"
+
+#include "base/notreached.h"
+
+namespace content {
+
+const char* GinNativeBridgeErrorToString(GinNativeBridgeError error) {
+  switch (error) {
+    case kGinNativeBridgeNoError:
+      return "No error";
+    case kGinNativeBridgeUnknownObjectId:
+      return "Unknown Native object ID";
+    case kGinNativeBridgeObjectIsGone:
+      return "Native object is gone";
+    case kGinNativeBridgeMethodNotFound:
+      return "Method not found";
+    case kGinNativeBridgeAccessToObjectGetClassIsBlocked:
+      return "Access to Object.getClass is blocked";
+    case kGinNativeBridgeNativeExceptionRaised:
+      return "Native exception was raised during method invocation";
+    case kGinNativeBridgeNonAssignableTypes:
+      return "The type of the object passed to the method is incompatible "
+             "with the type of method's argument";
+    case kGinNativeBridgeRenderFrameDeleted:
+      return "RenderFrame has been deleted";
+    case kGinNativeBridgeNotSupportedTypes:
+      return "This type is not supported";
+    case kGinNativeBridgeMessageNameIsWrong:
+      return "Message name is wrong";
+  }
+  NOTREACHED();
+  return "Unknown error";
+}
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/common/gin_native_bridge_errors.h b/tizen_src/ewk/efl_integration/common/gin_native_bridge_errors.h
new file mode 100644 (file)
index 0000000..cee74ff
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_COMMON_GIN_NATIVE_BRIDGE_ERRORS_H_
+#define EWK_EFL_INTEGRATION_COMMON_GIN_NATIVE_BRIDGE_ERRORS_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+enum GinNativeBridgeError {
+  kGinNativeBridgeNoError = 0,
+  kGinNativeBridgeUnknownObjectId,
+  kGinNativeBridgeObjectIsGone,
+  kGinNativeBridgeMethodNotFound,
+  kGinNativeBridgeAccessToObjectGetClassIsBlocked,
+  kGinNativeBridgeNativeExceptionRaised,
+  kGinNativeBridgeNonAssignableTypes,
+  kGinNativeBridgeRenderFrameDeleted,
+  kGinNativeBridgeNotSupportedTypes,
+  kGinNativeBridgeMessageNameIsWrong,
+  kGinNativeBridgeErrorLast = kGinNativeBridgeRenderFrameDeleted
+};
+
+CONTENT_EXPORT const char* GinNativeBridgeErrorToString(
+    GinNativeBridgeError error);
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_COMMON_GIN_NATIVE_BRIDGE_ERRORS_H_
diff --git a/tizen_src/ewk/efl_integration/common/gin_native_bridge_messages.h b/tizen_src/ewk/efl_integration/common/gin_native_bridge_messages.h
new file mode 100644 (file)
index 0000000..6f976df
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <set>
+#include <string>
+
+#include "common/gin_native_bridge_errors.h"
+#include "content/common/content_export.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_start.h"
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
+#define IPC_MESSAGE_START GinNativeBridgeMsgStart
+
+// Messages for handling Java objects injected into JavaScript -----------------
+
+IPC_ENUM_TRAITS_MAX_VALUE(content::GinNativeBridgeError,
+                          content::kGinNativeBridgeErrorLast)
+
+// Sent from browser to renderer to add a Native object with the given name.
+// Object IDs are generated on the browser side.
+IPC_MESSAGE_ROUTED2(GinNativeBridgeMsg_AddNamedObject,
+                    std::string /* name */,
+                    int32_t /* object_id */)
+
+// Sent from browser to renderer to remove a Java object with the given name.
+IPC_MESSAGE_ROUTED1(GinNativeBridgeMsg_RemoveNamedObject,
+                    std::string /* name */)
+
+// Sent from renderer to browser to get information about methods of
+// the given object. The query will only succeed if inspection of injected
+// objects is enabled on the browser side.
+IPC_SYNC_MESSAGE_ROUTED1_1(GinNativeBridgeHostMsg_GetMethods,
+                           int32_t /* object_id */,
+                           std::set<std::string> /* returned_method_names */)
+
+// Sent from renderer to browser to find out, if an object has a method with
+// the given name.
+IPC_SYNC_MESSAGE_ROUTED2_1(GinNativeBridgeHostMsg_HasMethod,
+                           int32_t /* object_id */,
+                           std::string /* method_name */,
+                           bool /* result */)
+
+// Sent from renderer to browser to invoke a method. Method arguments
+// are chained into |arguments| list. base::Value::List is used for |result| as
+// a container to work around immutability of base::Value.
+// Empty result list indicates that an error has happened on the Native side
+// (either bridge-induced error or an unhandled Native exception) and an
+// exception must be thrown into JavaScript. |error_code| indicates the cause of
+// the error.
+// Some special value types that are not supported by base::Value are encoded
+// as BinaryValues via GinNativeBridgeValue.
+IPC_SYNC_MESSAGE_ROUTED3_2(GinNativeBridgeHostMsg_InvokeMethod,
+                           int32_t /* object_id */,
+                           std::string /* method_name */,
+                           base::Value::List /* arguments */,
+                           base::Value::List /* result */,
+                           content::GinNativeBridgeError /* error_code */)
diff --git a/tizen_src/ewk/efl_integration/common/gin_native_bridge_value.cc b/tizen_src/ewk/efl_integration/common/gin_native_bridge_value.cc
new file mode 100644 (file)
index 0000000..ab8e34a
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ewk/efl_integration/common/gin_native_bridge_value.h"
+
+namespace content {
+
+namespace {
+// The magic value is only used to prevent accidental attempts of reading
+// GinJavaBridgeValue from a random BinaryValue.  GinJavaBridgeValue is not
+// intended for scenarios where with BinaryValues are being used for anything
+// else than holding GinJavaBridgeValues.  If a need for such scenario ever
+// emerges, the best solution would be to extend GinJavaBridgeValue to be able
+// to wrap raw BinaryValues.
+const uint32_t kHeaderMagic = 0xBEEFCAFE;
+
+#pragma pack(push, 4)
+struct Header : public base::Pickle::Header {
+  uint32_t magic;
+  int32_t type;
+};
+#pragma pack(pop)
+}  // namespace
+
+// static
+std::unique_ptr<base::Value> GinNativeBridgeValue::CreateObjectIDValue(
+    int32_t in_value) {
+  GinNativeBridgeValue gin_value(TYPE_OBJECT_ID);
+  gin_value.pickle_.WriteInt(in_value);
+  return gin_value.SerializeToValue();
+}
+
+// static
+bool GinNativeBridgeValue::ContainsGinJavaBridgeValue(
+    const base::Value* value) {
+  if (!value->is_blob())
+    return false;
+  const base::Value* binary_value = reinterpret_cast<const base::Value*>(value);
+  if (binary_value->GetBlob().size() < sizeof(Header))
+    return false;
+  base::Pickle pickle((const char*)binary_value->GetBlob().data(),
+                      binary_value->GetBlob().size());
+  // Broken binary value: payload or header size is wrong
+  if (!pickle.data() || pickle.size() - pickle.payload_size() != sizeof(Header))
+    return false;
+  Header* header = pickle.headerT<Header>();
+  return (header->magic == kHeaderMagic && header->type >= TYPE_FIRST_VALUE &&
+          header->type < TYPE_LAST_VALUE);
+}
+
+// static
+std::unique_ptr<const GinNativeBridgeValue> GinNativeBridgeValue::FromValue(
+    const base::Value* value) {
+  return std::unique_ptr<const GinNativeBridgeValue>(
+      value->is_blob() ? new GinNativeBridgeValue(
+                             reinterpret_cast<const base::Value*>(value))
+                       : NULL);
+}
+
+GinNativeBridgeValue::Type GinNativeBridgeValue::GetType() const {
+  const Header* header = pickle_.headerT<Header>();
+  DCHECK(header->type >= TYPE_FIRST_VALUE && header->type < TYPE_LAST_VALUE);
+  return static_cast<Type>(header->type);
+}
+
+bool GinNativeBridgeValue::IsType(Type type) const {
+  return GetType() == type;
+}
+
+bool GinNativeBridgeValue::GetAsNonFinite(float* out_value) const {
+  if (GetType() != TYPE_NONFINITE)
+    return false;
+
+  base::PickleIterator iter(pickle_);
+  return iter.ReadFloat(out_value);
+}
+
+bool GinNativeBridgeValue::GetAsObjectID(int32_t* out_object_id) const {
+  if (GetType() != TYPE_OBJECT_ID)
+    return false;
+
+  base::PickleIterator iter(pickle_);
+  return iter.ReadInt(out_object_id);
+}
+
+GinNativeBridgeValue::GinNativeBridgeValue(Type type)
+    : pickle_(sizeof(Header)) {
+  Header* header = pickle_.headerT<Header>();
+  header->magic = kHeaderMagic;
+  header->type = type;
+}
+
+GinNativeBridgeValue::GinNativeBridgeValue(const base::Value* value)
+    : pickle_((const char*)value->GetBlob().data(), value->GetBlob().size()) {
+  DCHECK(ContainsGinJavaBridgeValue(value));
+}
+
+std::unique_ptr<base::Value> GinNativeBridgeValue::SerializeToValue() {
+  return std::make_unique<base::Value>(base::Value::BlobStorage(
+      reinterpret_cast<const char*>(pickle_.data()),
+      reinterpret_cast<const char*>(pickle_.data()) + pickle_.size()));
+}
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/common/gin_native_bridge_value.h b/tizen_src/ewk/efl_integration/common/gin_native_bridge_value.h
new file mode 100644 (file)
index 0000000..946293f
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_COMMON_GIN_NATIVE_BRIDGE_VALUE_H_
+#define EWK_EFL_INTEGRATION_COMMON_GIN_NATIVE_BRIDGE_VALUE_H_
+
+#include <stdint.h>
+
+#include "base/pickle.h"
+#include "base/values.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class GinNativeBridgeValue {
+ public:
+  enum Type {
+    TYPE_FIRST_VALUE = 0,
+    // JavaScript 'undefined'
+    TYPE_UNDEFINED = 0,
+    // JavaScript NaN and Infinity
+    TYPE_NONFINITE,
+    // Bridge Object ID
+    TYPE_OBJECT_ID,
+    TYPE_LAST_VALUE
+  };
+
+  CONTENT_EXPORT static std::unique_ptr<base::Value> CreateObjectIDValue(
+      int32_t in_value);
+
+  // De-serialization
+  CONTENT_EXPORT static bool ContainsGinJavaBridgeValue(
+      const base::Value* value);
+  CONTENT_EXPORT static std::unique_ptr<const GinNativeBridgeValue> FromValue(
+      const base::Value* value);
+  CONTENT_EXPORT Type GetType() const;
+  CONTENT_EXPORT bool IsType(Type type) const;
+  CONTENT_EXPORT bool GetAsNonFinite(float* out_value) const;
+  CONTENT_EXPORT bool GetAsObjectID(int32_t* out_object_id) const;
+
+ private:
+  explicit GinNativeBridgeValue(Type type);
+  explicit GinNativeBridgeValue(const base::Value* value);
+
+  GinNativeBridgeValue(const GinNativeBridgeValue&) = delete;
+  GinNativeBridgeValue& operator=(const GinNativeBridgeValue&) = delete;
+
+  std::unique_ptr<base::Value> SerializeToValue();
+
+  base::Pickle pickle_;
+};
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_COMMON_GIN_NATIVE_BRIDGE_VALUE_H_
index db42330..f9760ba 100644 (file)
@@ -5,5 +5,6 @@
 // Multiply-included file, hence no include guard.
 // efl message generator
 
-#include "common/render_messages_ewk.h"
 #include "common/editing_messages.h"
+#include "common/gin_native_bridge_messages.h"
+#include "common/render_messages_ewk.h"
index a9f9686..449ac1b 100644 (file)
@@ -14,6 +14,7 @@
 #include "base/logging.h"
 #include "base/pickle.h"
 #include "base/strings/utf_string_conversions.h"
+#include "browser/javascript_interface/gin_native_bridge_dispatcher_host.h"
 #include "browser/navigation_policy_handler_efl.h"
 #include "browser/quota_permission_context_efl.h"
 #include "browser/selectpicker/popup_menu_item.h"
@@ -64,6 +65,7 @@
 #include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/display/screen.h"
+#include "ui/events/event_switches.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 #include "ui/platform_window/platform_window_init_properties.h"
@@ -290,6 +292,7 @@ EWebView::~EWebView() {
 
   if (context_->GetImpl()->browser_context()->IsOffTheRecord())
     Ewk_Context::Delete(context_.get());
+  gin_native_bridge_dispatcher_host_.reset();
 }
 
 void EWebView::ReleasePopupMenuList() {
@@ -332,6 +335,17 @@ Eina_Bool EWebView::HasFocus() const {
   return rwhva()->offscreen_helper()->HasFocus() ? EINA_TRUE : EINA_FALSE;
 }
 
+Eina_Bool EWebView::AddJavaScriptMessageHandler(
+    Evas_Object* view,
+    Ewk_View_Script_Message_Cb callback,
+    std::string name) {
+  if (!gin_native_bridge_dispatcher_host_)
+    return EINA_FALSE;
+
+  return gin_native_bridge_dispatcher_host_->AddNamedObject(view, callback,
+                                                            name);
+}
+
 bool EWebView::CreateNewWindow(
     content::WebContentsEflDelegate::WebContentsCreateCallback cb) {
   create_new_window_web_contents_cb_ = cb;
@@ -734,18 +748,17 @@ void JavaScriptComplete(JavaScriptCallbackDetails* script_callback_data,
 bool EWebView::ExecuteJavaScript(const char* script,
                                  Ewk_View_Script_Execute_Callback callback,
                                  void* userdata) {
-  if (!script)
-    return false;
-
-  if (!web_contents_delegate_)  // question, can I remove this check?
-    return false;
-
-  if (!web_contents_)
+  LOG(INFO) << __FUNCTION__;
+  if (!web_contents_) {
+    LOG(ERROR) << __FUNCTION__ << "web_contents_ is null";
     return false;
+  }
 
   RenderFrameHost* render_frame_host = web_contents_->GetPrimaryMainFrame();
-  if (!render_frame_host)
+  if (!render_frame_host) {
+    LOG(ERROR) << __FUNCTION__ << " render_frame_host is null";
     return false;
+  }
 
   // Note: M37. Execute JavaScript, |script| with
   // |RenderFrameHost::ExecuteJavaScript|.
@@ -2264,6 +2277,8 @@ void EWebView::InitializeContent() {
       new _Ewk_Back_Forward_List(web_contents_->GetController()));
 
   permission_popup_manager_.reset(new PermissionPopupManager(evas_object_));
+  gin_native_bridge_dispatcher_host_.reset(
+      new content::GinNativeBridgeDispatcherHost(web_contents_.get()));
 
   native_view_ =
       static_cast<WebContentsImplEfl*>(web_contents_.get())->GetEflNativeView();
index 93a0b53..bb7357b 100755 (executable)
@@ -71,6 +71,7 @@ class WebContentsViewAura;
 class ContextMenuControllerEfl;
 class PopupControllerEfl;
 class InputPicker;
+class GinNativeBridgeDispatcherHost;
 }
 
 class ErrorParams;
@@ -475,6 +476,14 @@ class EWebView {
     return context_menu_.get();
   }
   void ResetContextMenuController();
+  Eina_Bool AddJavaScriptMessageHandler(Evas_Object* view,
+                                        Ewk_View_Script_Message_Cb callback,
+                                        std::string name);
+
+  content::GinNativeBridgeDispatcherHost* GetGinNativeBridgeDispatcherHost()
+      const {
+    return gin_native_bridge_dispatcher_host_.get();
+  }
 
   /// ---- Event handling
   bool HandleShow();
@@ -623,6 +632,10 @@ class EWebView {
   std::unique_ptr<PermissionPopupManager> permission_popup_manager_;
   std::unique_ptr<ScrollDetector> scroll_detector_;
 
+  // Manages injecting native objects.
+  std::unique_ptr<content::GinNativeBridgeDispatcherHost>
+      gin_native_bridge_dispatcher_host_;
+
 #if BUILDFLAG(IS_TIZEN)
   blink::mojom::FileChooserParams::Mode filechooser_mode_;
 #endif
index 40d8e79..9392ea8 100644 (file)
@@ -21,6 +21,7 @@
 #include "ewk_view_product.h"
 
 #include <Evas.h>
+#include <algorithm>
 
 #include "authentication_challenge_popup.h"
 #include "content/public/browser/navigation_controller.h"
@@ -1318,6 +1319,44 @@ Eina_Bool ewk_view_tts_mode_set(Evas_Object* view, ewk_tts_mode tts_mode) {
   return false;
 }
 
+Eina_Bool ewk_view_javascript_message_handler_add(
+    Evas_Object* view,
+    Ewk_View_Script_Message_Cb callback,
+    const char* name) {
+  EWK_VIEW_IMPL_GET_OR_RETURN(view, impl, EINA_FALSE);
+  EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+  return impl->AddJavaScriptMessageHandler(view, callback, std::string(name));
+}
+
+Eina_Bool ewk_view_evaluate_javascript(Evas_Object* view,
+                                       const char* name,
+                                       const char* result) {
+  EWK_VIEW_IMPL_GET_OR_RETURN(view, impl, EINA_FALSE);
+  EINA_SAFETY_ON_NULL_RETURN_VAL(result, EINA_FALSE);
+  EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+
+  std::string function(name);
+  std::string data(result);
+  std::string pattern("\n");
+  std::string replace("</br>");
+  std::string::size_type pos = 0;
+  std::string::size_type offset = 0;
+  while ((pos = data.find(pattern, offset)) != std::string::npos) {
+    data.replace(data.begin() + pos, data.begin() + pos + pattern.size(),
+                 replace);
+    offset = pos + replace.size();
+  }
+
+  // For JSON Object or Array.
+  if (result[0] == '{' || result[0] == '[') {
+    data = "javascript:" + function + "(JSON.parse('" + data + "'))";
+  } else {
+    data = "javascript:" + function + "('" + data + "')";
+  }
+
+  return impl->ExecuteJavaScript(data.c_str(), NULL, 0);
+}
+
 void ewk_view_authentication_callback_set(
     Evas_Object* ewk_view,
     Ewk_View_Authentication_Callback callback,
index eb24496..aaf4c52 100644 (file)
@@ -26,6 +26,7 @@
 #if !defined(EWK_BRINGUP)  // FIXME: m94 bringup
 #include "renderer/editorclient_agent.h"
 #endif
+#include "renderer/gin_native_bridge_dispatcher.h"
 #include "renderer/plugins/plugin_placeholder_efl.h"
 #include "renderer/render_frame_observer_efl.h"
 #include "third_party/blink/public/platform/url_conversion.h"
@@ -147,6 +148,8 @@ void ContentRendererClientEfl::RenderThreadStarted() {
 void ContentRendererClientEfl::RenderFrameCreated(content::RenderFrame* render_frame) {
   new content::RenderFrameObserverEfl(render_frame);
   new content::ContentSettingsClientEfl(render_frame);
+  // Deletes itself when render_frame is destroyed.
+  new content::GinNativeBridgeDispatcher(render_frame);
 
 #if defined(TIZEN_AUTOFILL_SUPPORT)
   PasswordAutofillAgent* password_autofill_agent =
diff --git a/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_dispatcher.cc b/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_dispatcher.cc
new file mode 100644 (file)
index 0000000..1b95734
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "renderer/gin_native_bridge_dispatcher.h"
+
+#include "base/auto_reset.h"
+#include "common/gin_native_bridge_messages.h"
+#include "content/public/renderer/render_frame.h"
+#include "renderer/gin_native_bridge_object.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_view.h"
+
+namespace content {
+
+GinNativeBridgeDispatcher::GinNativeBridgeDispatcher(RenderFrame* render_frame)
+    : RenderFrameObserver(render_frame),
+      inside_did_clear_window_object_(false) {}
+
+GinNativeBridgeDispatcher::~GinNativeBridgeDispatcher() {}
+
+bool GinNativeBridgeDispatcher::OnMessageReceived(const IPC::Message& msg) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(GinNativeBridgeDispatcher, msg)
+    IPC_MESSAGE_HANDLER(GinNativeBridgeMsg_AddNamedObject, OnAddNamedObject)
+    IPC_MESSAGE_HANDLER(GinNativeBridgeMsg_RemoveNamedObject,
+                        OnRemoveNamedObject)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void GinNativeBridgeDispatcher::DidClearWindowObject() {
+  // Accessing window object when adding properties to it may trigger
+  // a nested call to DidClearWindowObject.
+  if (inside_did_clear_window_object_)
+    return;
+  base::AutoReset<bool> flag_entry(&inside_did_clear_window_object_, true);
+  for (NamedObjectMap::const_iterator iter = named_objects_.begin();
+       iter != named_objects_.end(); ++iter) {
+    // Always create a new GinNativeBridgeObject, so we don't pull any of the V8
+    // wrapper's custom properties into the context of the page we have
+    // navigated to. The old GinNativeBridgeObject will be automatically
+    // deleted after its wrapper will be collected.
+    // On the browser side, we ignore wrapper deletion events for named objects,
+    // as they are only removed upon embedder's request (RemoveNamedObject).
+    if (objects_.Lookup(iter->second))
+      objects_.Remove(iter->second);
+    GinNativeBridgeObject* object = GinNativeBridgeObject::InjectNamed(
+        render_frame()->GetWebFrame(), AsWeakPtr(), iter->first, iter->second);
+    if (object) {
+      objects_.AddWithID(object, iter->second);
+    } else {
+      // FIXME: Inform the host about wrapper creation failure.
+    }
+  }
+}
+
+void GinNativeBridgeDispatcher::OnAddNamedObject(const std::string& name,
+                                                 ObjectID object_id) {
+  LOG(INFO) << __FUNCTION__;
+  // Added objects only become available after page reload, so here they
+  // are only added into the internal map.
+  named_objects_.insert(std::make_pair(name, object_id));
+}
+
+void GinNativeBridgeDispatcher::OnRemoveNamedObject(const std::string& name) {
+  // Removal becomes in effect on next reload. We simply removing the entry
+  // from the map here.
+  NamedObjectMap::iterator iter = named_objects_.find(name);
+  DCHECK(iter != named_objects_.end());
+  named_objects_.erase(iter);
+}
+
+void GinNativeBridgeDispatcher::GetNativeMethods(
+    ObjectID object_id,
+    std::set<std::string>* methods) {
+  render_frame()->Send(
+      new GinNativeBridgeHostMsg_GetMethods(routing_id(), object_id, methods));
+}
+
+bool GinNativeBridgeDispatcher::HasNativeMethod(
+    ObjectID object_id,
+    const std::string& method_name) {
+  bool result;
+  render_frame()->Send(new GinNativeBridgeHostMsg_HasMethod(
+      routing_id(), object_id, method_name, &result));
+  return result;
+}
+
+std::unique_ptr<base::Value> GinNativeBridgeDispatcher::InvokeNativeMethod(
+    ObjectID object_id,
+    const std::string& method_name,
+    const base::Value::List& arguments,
+    GinNativeBridgeError* error) {
+  LOG(INFO) << __FUNCTION__;
+  base::Value::List result_wrapper;
+  render_frame()->Send(new GinNativeBridgeHostMsg_InvokeMethod(
+      routing_id(), object_id, method_name, arguments, &result_wrapper, error));
+  if (result_wrapper.empty())
+    return nullptr;
+  return base::Value::ToUniquePtrValue(result_wrapper[0].Clone());
+}
+
+GinNativeBridgeObject* GinNativeBridgeDispatcher::GetObject(
+    ObjectID object_id) {
+  GinNativeBridgeObject* result = objects_.Lookup(object_id);
+  if (!result) {
+    result = GinNativeBridgeObject::InjectAnonymous(AsWeakPtr(), object_id);
+    if (result)
+      objects_.AddWithID(result, object_id);
+  }
+  return result;
+}
+
+void GinNativeBridgeDispatcher::OnDestruct() {
+  delete this;
+}
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_dispatcher.h b/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_dispatcher.h
new file mode 100644 (file)
index 0000000..0905eb6
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_DISPATCHER_H_
+#define EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_DISPATCHER_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/containers/id_map.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "ewk/efl_integration/common/gin_native_bridge_errors.h"
+
+namespace blink {
+class WebFrame;
+}
+
+namespace content {
+
+class GinNativeBridgeObject;
+
+// This class handles injecting Native objects into the main frame of a
+// RenderView. The 'add' and 'remove' messages received from the browser
+// process modify the entries in a map of 'pending' objects. These objects are
+// bound to the window object of the main frame when that window object is next
+// cleared. These objects remain bound until the window object is cleared
+// again.
+
+class GinNativeBridgeDispatcher
+    : public base::SupportsWeakPtr<GinNativeBridgeDispatcher>,
+      public RenderFrameObserver {
+ public:
+  // GinNativeBridgeObjects are managed by gin. An object gets destroyed
+  // when it is no more referenced from JS. As GinNativeBridgeObjects reports
+  // deletion of self to GinNativeBridgeDispatcher, we would not have stale
+  // pointers here.
+  typedef base::IDMap<GinNativeBridgeObject*> ObjectMap;
+  typedef ObjectMap::KeyType ObjectID;
+
+  explicit GinNativeBridgeDispatcher(RenderFrame* render_frame);
+  ~GinNativeBridgeDispatcher() override;
+
+  GinNativeBridgeDispatcher(const GinNativeBridgeDispatcher&) = delete;
+  GinNativeBridgeDispatcher& operator=(const GinNativeBridgeDispatcher&) =
+      delete;
+
+  // RenderFrameObserver override:
+  void OnDestruct() override;
+  bool OnMessageReceived(const IPC::Message& message) override;
+  void DidClearWindowObject() override;
+
+  void GetNativeMethods(ObjectID object_id, std::set<std::string>* methods);
+  bool HasNativeMethod(ObjectID object_id, const std::string& method_name);
+  std::unique_ptr<base::Value> InvokeNativeMethod(
+      ObjectID object_id,
+      const std::string& method_name,
+      const base::Value::List& arguments,
+      GinNativeBridgeError* error);
+  GinNativeBridgeObject* GetObject(ObjectID object_id);
+
+ private:
+  void OnAddNamedObject(const std::string& name, ObjectID object_id);
+  void OnRemoveNamedObject(const std::string& name);
+
+  typedef std::map<std::string, ObjectID> NamedObjectMap;
+  NamedObjectMap named_objects_;
+  ObjectMap objects_;
+  bool inside_did_clear_window_object_;
+};
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_DISPATCHER_H_
diff --git a/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_object.cc b/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_object.cc
new file mode 100644 (file)
index 0000000..caf9e41
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "renderer/gin_native_bridge_object.h"
+
+#include "common/gin_native_bridge_messages.h"
+#include "content/public/renderer/render_thread.h"
+#include "gin/function_template.h"
+#include "renderer/gin_native_function_invocation_helper.h"
+#include "third_party/blink/public/web/blink.h"
+#include "third_party/blink/public/web/web_frame.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "v8/include/v8-function.h"
+
+namespace content {
+// static
+GinNativeBridgeObject* GinNativeBridgeObject::InjectNamed(
+    blink::WebFrame* frame,
+    const base::WeakPtr<GinNativeBridgeDispatcher>& dispatcher,
+    const std::string& object_name,
+    GinNativeBridgeDispatcher::ObjectID object_id) {
+  v8::Isolate* isolate = blink::MainThreadIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  if (!frame->IsWebLocalFrame())
+    return NULL;
+
+  v8::Local<v8::Context> context =
+      frame->ToWebLocalFrame()->MainWorldScriptContext();
+  if (context.IsEmpty())
+    return NULL;
+
+  GinNativeBridgeObject* object =
+      new GinNativeBridgeObject(isolate, dispatcher, object_id);
+
+  v8::Context::Scope context_scope(context);
+  v8::Handle<v8::Object> global = context->Global();
+  gin::Handle<GinNativeBridgeObject> controller =
+      gin::CreateHandle(isolate, object);
+  // WrappableBase instance deletes itself in case of a wrapper
+  // creation failure, thus there is no need to delete |object|.
+  if (controller.IsEmpty())
+    return NULL;
+
+  global->Set(context, gin::StringToV8(isolate, object_name), controller.ToV8())
+      .Check();
+  return object;
+}
+
+// static
+GinNativeBridgeObject* GinNativeBridgeObject::InjectAnonymous(
+    const base::WeakPtr<GinNativeBridgeDispatcher>& dispatcher,
+    GinNativeBridgeDispatcher::ObjectID object_id) {
+  return new GinNativeBridgeObject(blink::MainThreadIsolate(), dispatcher,
+                                   object_id);
+}
+
+GinNativeBridgeObject::GinNativeBridgeObject(
+    v8::Isolate* isolate,
+    const base::WeakPtr<GinNativeBridgeDispatcher>& dispatcher,
+    GinNativeBridgeDispatcher::ObjectID object_id)
+    : gin::NamedPropertyInterceptor(isolate, this),
+      dispatcher_(dispatcher),
+      object_id_(object_id),
+      frame_routing_id_(dispatcher_->routing_id()),
+      template_cache_(isolate) {}
+
+GinNativeBridgeObject::~GinNativeBridgeObject() {}
+
+gin::ObjectTemplateBuilder GinNativeBridgeObject::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return gin::Wrappable<GinNativeBridgeObject>::GetObjectTemplateBuilder(
+             isolate)
+      .AddNamedPropertyInterceptor();
+}
+
+v8::Local<v8::Value> GinNativeBridgeObject::GetNamedProperty(
+    v8::Isolate* isolate,
+    const std::string& property) {
+  std::map<std::string, bool>::iterator method_pos =
+      known_methods_.find(property);
+  if (method_pos == known_methods_.end()) {
+    if (!dispatcher_)
+      return v8::Local<v8::Value>();
+
+    known_methods_[property] =
+        dispatcher_->HasNativeMethod(object_id_, property);
+  }
+  if (known_methods_[property])
+    return GetFunctionTemplate(isolate, property)
+        ->GetFunction(isolate->GetCurrentContext())
+        .FromMaybe(v8::Local<v8::Value>());
+  else
+    return v8::Local<v8::Value>();
+}
+
+std::vector<std::string> GinNativeBridgeObject::EnumerateNamedProperties(
+    v8::Isolate* isolate) {
+  std::set<std::string> method_names;
+  if (dispatcher_)
+    dispatcher_->GetNativeMethods(object_id_, &method_names);
+  return std::vector<std::string>(method_names.begin(), method_names.end());
+}
+
+v8::Local<v8::FunctionTemplate> GinNativeBridgeObject::GetFunctionTemplate(
+    v8::Isolate* isolate,
+    const std::string& name) {
+  v8::Local<v8::FunctionTemplate> function_template = template_cache_.Get(name);
+  if (!function_template.IsEmpty())
+    return function_template;
+  function_template = gin::CreateFunctionTemplate(
+      isolate,
+      base::BindRepeating(&GinNativeFunctionInvocationHelper::Invoke,
+                          base::Owned(new GinNativeFunctionInvocationHelper(
+                              name, dispatcher_))));
+  template_cache_.Set(name, function_template);
+  return function_template;
+}
+
+gin::WrapperInfo GinNativeBridgeObject::kWrapperInfo = {
+    gin::kEmbedderNativeGin};
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_object.h b/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_object.h
new file mode 100644 (file)
index 0000000..4c5af69
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_OBJECT_H_
+#define EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_OBJECT_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "gin/handle.h"
+#include "gin/interceptor.h"
+#include "gin/object_template_builder.h"
+#include "gin/wrappable.h"
+#include "renderer/gin_native_bridge_dispatcher.h"
+#include "v8/include/v8-util.h"
+
+namespace blink {
+class WebFrame;
+}
+
+namespace content {
+
+class GinNativeBridgeObject : public gin::Wrappable<GinNativeBridgeObject>,
+                              public gin::NamedPropertyInterceptor {
+ public:
+  static gin::WrapperInfo kWrapperInfo;
+  GinNativeBridgeDispatcher::ObjectID object_id() const { return object_id_; }
+
+  // gin::Wrappable.
+  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) override;
+
+  // gin::NamedPropertyInterceptor
+  v8::Local<v8::Value> GetNamedProperty(v8::Isolate* isolate,
+                                        const std::string& property) override;
+  std::vector<std::string> EnumerateNamedProperties(
+      v8::Isolate* isolate) override;
+
+  static GinNativeBridgeObject* InjectNamed(
+      blink::WebFrame* frame,
+      const base::WeakPtr<GinNativeBridgeDispatcher>& dispatcher,
+      const std::string& object_name,
+      GinNativeBridgeDispatcher::ObjectID object_id);
+  static GinNativeBridgeObject* InjectAnonymous(
+      const base::WeakPtr<GinNativeBridgeDispatcher>& dispatcher,
+      GinNativeBridgeDispatcher::ObjectID object_id);
+
+ private:
+  GinNativeBridgeObject(
+      v8::Isolate* isolate,
+      const base::WeakPtr<GinNativeBridgeDispatcher>& dispatcher,
+      GinNativeBridgeDispatcher::ObjectID object_id);
+  ~GinNativeBridgeObject() override;
+
+  GinNativeBridgeObject(const GinNativeBridgeObject&) = delete;
+  GinNativeBridgeObject& operator=(const GinNativeBridgeObject&) = delete;
+
+  v8::Local<v8::FunctionTemplate> GetFunctionTemplate(v8::Isolate* isolate,
+                                                      const std::string& name);
+
+  base::WeakPtr<GinNativeBridgeDispatcher> dispatcher_;
+  GinNativeBridgeDispatcher::ObjectID object_id_;
+  int frame_routing_id_;
+  std::map<std::string, bool> known_methods_;
+  v8::StdGlobalValueMap<std::string, v8::FunctionTemplate> template_cache_;
+};
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_OBJECT_H_
diff --git a/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_value_converter.cc b/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_value_converter.cc
new file mode 100644 (file)
index 0000000..209eb6a
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "renderer/gin_native_bridge_value_converter.h"
+
+#include <cmath>
+
+#include "base/values.h"
+#include "gin/array_buffer.h"
+#include "renderer/gin_native_bridge_object.h"
+
+namespace content {
+
+GinNativeBridgeValueConverter::GinNativeBridgeValueConverter()
+    : converter_(V8ValueConverter::Create()) {
+  converter_->SetDateAllowed(false);
+  converter_->SetRegExpAllowed(false);
+  converter_->SetFunctionAllowed(true);
+  converter_->SetStrategy(this);
+}
+
+GinNativeBridgeValueConverter::~GinNativeBridgeValueConverter() {}
+
+v8::Local<v8::Value> GinNativeBridgeValueConverter::ToV8Value(
+    const base::Value* value,
+    v8::Local<v8::Context> context) const {
+  return converter_->ToV8Value(*value, context);
+}
+
+std::unique_ptr<base::Value> GinNativeBridgeValueConverter::FromV8Value(
+    v8::Local<v8::Value> value,
+    v8::Local<v8::Context> context) const {
+  return converter_->FromV8Value(value, context);
+}
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_value_converter.h b/tizen_src/ewk/efl_integration/renderer/gin_native_bridge_value_converter.h
new file mode 100644 (file)
index 0000000..fb4185b
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_VALUE_CONVERTER_H_
+#define EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_VALUE_CONVERTER_H_
+
+#include "content/common/content_export.h"
+#include "content/public/renderer/v8_value_converter.h"
+
+namespace content {
+
+class GinNativeBridgeValueConverter
+    : public content::V8ValueConverter::Strategy {
+ public:
+  CONTENT_EXPORT GinNativeBridgeValueConverter();
+  CONTENT_EXPORT ~GinNativeBridgeValueConverter() override;
+
+  GinNativeBridgeValueConverter(const GinNativeBridgeValueConverter&) = delete;
+  GinNativeBridgeValueConverter& operator=(
+      const GinNativeBridgeValueConverter&) = delete;
+
+  CONTENT_EXPORT v8::Local<v8::Value> ToV8Value(
+      const base::Value* value,
+      v8::Local<v8::Context> context) const;
+  CONTENT_EXPORT std::unique_ptr<base::Value> FromV8Value(
+      v8::Local<v8::Value> value,
+      v8::Local<v8::Context> context) const;
+
+ private:
+  std::unique_ptr<V8ValueConverter> converter_;
+};
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_BRIDGE_VALUE_CONVERTER_H_
diff --git a/tizen_src/ewk/efl_integration/renderer/gin_native_function_invocation_helper.cc b/tizen_src/ewk/efl_integration/renderer/gin_native_function_invocation_helper.cc
new file mode 100644 (file)
index 0000000..8906fdd
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "renderer/gin_native_function_invocation_helper.h"
+
+#include "common/gin_native_bridge_value.h"
+#include "content/public/renderer/v8_value_converter.h"
+#include "renderer/gin_native_bridge_object.h"
+#include "renderer/gin_native_bridge_value_converter.h"
+#include "v8/include/v8-exception.h"
+
+namespace content {
+
+namespace {
+
+const char kMethodInvocationAsConstructorDisallowed[] =
+    "Native bridge method can't be invoked as a constructor";
+const char kMethodInvocationOnNonInjectedObjectDisallowed[] =
+    "Native bridge method can't be invoked on a non-injected object";
+const char kMethodInvocationErrorMessage[] =
+    "Native bridge method invocation error";
+
+}  // namespace
+
+GinNativeFunctionInvocationHelper::GinNativeFunctionInvocationHelper(
+    const std::string& method_name,
+    const base::WeakPtr<GinNativeBridgeDispatcher>& dispatcher)
+    : method_name_(method_name),
+      dispatcher_(dispatcher),
+      converter_(new GinNativeBridgeValueConverter()) {}
+
+GinNativeFunctionInvocationHelper::~GinNativeFunctionInvocationHelper() {}
+
+v8::Local<v8::Value> GinNativeFunctionInvocationHelper::Invoke(
+    gin::Arguments* args) {
+  if (!dispatcher_) {
+    args->isolate()->ThrowException(v8::Exception::Error(
+        gin::StringToV8(args->isolate(), kMethodInvocationErrorMessage)));
+    return v8::Undefined(args->isolate());
+  }
+
+  if (args->IsConstructCall()) {
+    args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
+        args->isolate(), kMethodInvocationAsConstructorDisallowed)));
+    return v8::Undefined(args->isolate());
+  }
+
+  content::GinNativeBridgeObject* object = NULL;
+  if (!args->GetHolder(&object) || !object) {
+    args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
+        args->isolate(), kMethodInvocationOnNonInjectedObjectDisallowed)));
+    return v8::Undefined(args->isolate());
+  }
+
+  base::Value::List arguments;
+  {
+    v8::HandleScope handle_scope(args->isolate());
+    v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
+    v8::Local<v8::Value> val;
+    while (args->GetNext(&val)) {
+      std::unique_ptr<base::Value> arg(converter_->FromV8Value(val, context));
+      if (arg.get()) {
+        arguments.Append(base::Value::FromUniquePtrValue(std::move(arg)));
+      } else {
+        arguments.Append(base::Value());
+      }
+    }
+  }
+
+  GinNativeBridgeError error;
+  std::unique_ptr<base::Value> result = dispatcher_->InvokeNativeMethod(
+      object->object_id(), method_name_, arguments, &error);
+  if (!result.get()) {
+    args->isolate()->ThrowException(v8::Exception::Error(
+        gin::StringToV8(args->isolate(), GinNativeBridgeErrorToString(error))));
+    return v8::Undefined(args->isolate());
+  }
+  if (!result->is_blob()) {
+    return converter_->ToV8Value(result.get(),
+                                 args->isolate()->GetCurrentContext());
+  }
+
+  std::unique_ptr<const GinNativeBridgeValue> gin_value =
+      GinNativeBridgeValue::FromValue(result.get());
+
+  if (gin_value->IsType(GinNativeBridgeValue::TYPE_OBJECT_ID)) {
+    GinNativeBridgeObject* result = NULL;
+    GinNativeBridgeDispatcher::ObjectID object_id;
+    if (gin_value->GetAsObjectID(&object_id)) {
+      result = dispatcher_->GetObject(object_id);
+    }
+    if (result) {
+      gin::Handle<GinNativeBridgeObject> controller =
+          gin::CreateHandle(args->isolate(), result);
+      if (controller.IsEmpty())
+        return v8::Undefined(args->isolate());
+      return controller.ToV8();
+    }
+  } else if (gin_value->IsType(GinNativeBridgeValue::TYPE_NONFINITE)) {
+    float float_value;
+    gin_value->GetAsNonFinite(&float_value);
+    return v8::Number::New(args->isolate(), float_value);
+  }
+  return v8::Undefined(args->isolate());
+}
+
+}  // namespace content
diff --git a/tizen_src/ewk/efl_integration/renderer/gin_native_function_invocation_helper.h b/tizen_src/ewk/efl_integration/renderer/gin_native_function_invocation_helper.h
new file mode 100644 (file)
index 0000000..adca806
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2017 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_FUNCTION_INVOCATION_HELPER_H_
+#define EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_FUNCTION_INVOCATION_HELPER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "gin/arguments.h"
+#include "gin/handle.h"
+#include "renderer/gin_native_bridge_dispatcher.h"
+
+namespace content {
+
+class GinNativeBridgeValueConverter;
+
+class GinNativeFunctionInvocationHelper {
+ public:
+  GinNativeFunctionInvocationHelper(
+      const std::string& method_name,
+      const base::WeakPtr<GinNativeBridgeDispatcher>& dispatcher);
+  ~GinNativeFunctionInvocationHelper();
+
+  GinNativeFunctionInvocationHelper(const GinNativeFunctionInvocationHelper&) =
+      delete;
+  GinNativeFunctionInvocationHelper& operator=(
+      const GinNativeFunctionInvocationHelper&) = delete;
+
+  v8::Local<v8::Value> Invoke(gin::Arguments* args);
+
+ private:
+  std::string method_name_;
+  base::WeakPtr<GinNativeBridgeDispatcher> dispatcher_;
+  std::unique_ptr<GinNativeBridgeValueConverter> converter_;
+};
+
+}  // namespace content
+
+#endif  // EWK_EFL_INTEGRATION_RENDERER_GIN_NATIVE_FUNCTION_INVOCATION_HELPER_H_