base::FunctionRef<FrameIterationAction(RenderFrameHostImpl*)> on_frame,
bool include_speculative) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ LOG(INFO) << __FUNCTION__;
if (!include_speculative &&
(lifecycle_state() == LifecycleStateImpl::kSpeculative ||
TtsMsgStart,
#endif
ExtensionWorkerMsgStart,
+ GinNativeBridgeMsgStart,
LastIPCMsgStart // Must come last.
};
bool resolve_promises,
int32_t world_id,
JavaScriptExecuteRequestForTestsCallback callback) {
+ LOG(INFO) << __FUNCTION__;
TRACE_EVENT_INSTANT0("test_tracing", "JavaScriptExecuteRequestForTests",
TRACE_EVENT_SCOPE_THREAD);
"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",
"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",
"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",
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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(¤t_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
--- /dev/null
+// 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_
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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 */)
--- /dev/null
+// 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
--- /dev/null
+// 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_
// 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"
#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"
#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"
if (context_->GetImpl()->browser_context()->IsOffTheRecord())
Ewk_Context::Delete(context_.get());
+ gin_native_bridge_dispatcher_host_.reset();
}
void EWebView::ReleasePopupMenuList() {
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;
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|.
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();
class ContextMenuControllerEfl;
class PopupControllerEfl;
class InputPicker;
+class GinNativeBridgeDispatcherHost;
}
class ErrorParams;
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();
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
#include "ewk_view_product.h"
#include <Evas.h>
+#include <algorithm>
#include "authentication_challenge_popup.h"
#include "content/public/browser/navigation_controller.h"
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,
#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"
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 =
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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
--- /dev/null
+// 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_