From ba3836c993b5a128cd7d9fe21a3bd49e3f5b3acc Mon Sep 17 00:00:00 2001 From: prathmeshm Date: Fri, 23 Mar 2018 12:16:03 +0530 Subject: [PATCH] Added Injected Bundle and extension server and client - Added injected bundle in electron - Added extension server and client - Set injected bundle path to chromium for init - related patch https://review.tizen.org/gerrit/#/c/174986/ Change-Id: Iee1717b760cb68576ad02c7cab657b099e54b913 Signed-off-by: prathmeshm --- atom/app/atom_main_delegate.cc | 13 + packaging/electron-efl.spec | 12 + tizen/build/common.gypi | 12 +- tizen/extensions/common/constants.cc | 30 ++ tizen/extensions/common/constants.h | 32 ++ tizen/extensions/common/xwalk_extension.cc | 125 +++++ tizen/extensions/common/xwalk_extension.h | 82 +++ tizen/extensions/common/xwalk_extension_adapter.cc | 323 ++++++++++++ tizen/extensions/common/xwalk_extension_adapter.h | 96 ++++ .../extensions/common/xwalk_extension_instance.cc | 63 +++ tizen/extensions/common/xwalk_extension_instance.h | 47 ++ tizen/extensions/common/xwalk_extension_manager.cc | 260 +++++++++ tizen/extensions/common/xwalk_extension_manager.h | 47 ++ tizen/extensions/common/xwalk_extension_server.cc | 229 ++++++++ tizen/extensions/common/xwalk_extension_server.h | 57 ++ tizen/extensions/extensions.gyp | 60 +++ .../internal/splash_screen/splash_screen.json | 7 + .../internal/splash_screen/splash_screen_api.js | 22 + .../splash_screen/splash_screen_extension.cc | 95 ++++ tizen/extensions/internal/widget/widget.json | 7 + tizen/extensions/internal/widget/widget_api.js | 93 ++++ .../extensions/internal/widget/widget_extension.cc | 95 ++++ tizen/extensions/public/XW_Extension.h | 185 +++++++ tizen/extensions/public/XW_Extension_EntryPoints.h | 49 ++ tizen/extensions/public/XW_Extension_Message_2.h | 64 +++ tizen/extensions/public/XW_Extension_Permissions.h | 41 ++ tizen/extensions/public/XW_Extension_Runtime.h | 44 ++ tizen/extensions/public/XW_Extension_SyncMessage.h | 48 ++ tizen/extensions/renderer/object_tools_module.cc | 114 ++++ tizen/extensions/renderer/object_tools_module.h | 36 ++ tizen/extensions/renderer/runtime_ipc_client.cc | 238 +++++++++ tizen/extensions/renderer/runtime_ipc_client.h | 100 ++++ tizen/extensions/renderer/widget_module.cc | 581 +++++++++++++++++++++ tizen/extensions/renderer/widget_module.h | 75 +++ .../extensions/renderer/xwalk_extension_client.cc | 131 +++++ tizen/extensions/renderer/xwalk_extension_client.h | 71 +++ .../extensions/renderer/xwalk_extension_module.cc | 514 ++++++++++++++++++ tizen/extensions/renderer/xwalk_extension_module.h | 84 +++ .../xwalk_extension_renderer_controller.cc | 132 +++++ .../renderer/xwalk_extension_renderer_controller.h | 45 ++ tizen/extensions/renderer/xwalk_module_system.cc | 524 +++++++++++++++++++ tizen/extensions/renderer/xwalk_module_system.h | 116 ++++ tizen/extensions/renderer/xwalk_v8tools_module.cc | 98 ++++ tizen/extensions/renderer/xwalk_v8tools_module.h | 28 + tizen/renderer/injected_bundle.cc | 190 +++++++ tizen/renderer/injected_bundle.gyp | 23 + vendor/brightray/browser/browser_context.cc | 15 + wrt.gyp | 2 + 48 files changed, 5349 insertions(+), 6 deletions(-) create mode 100644 tizen/extensions/common/constants.cc create mode 100644 tizen/extensions/common/constants.h create mode 100644 tizen/extensions/common/xwalk_extension.cc create mode 100644 tizen/extensions/common/xwalk_extension.h create mode 100644 tizen/extensions/common/xwalk_extension_adapter.cc create mode 100644 tizen/extensions/common/xwalk_extension_adapter.h create mode 100644 tizen/extensions/common/xwalk_extension_instance.cc create mode 100644 tizen/extensions/common/xwalk_extension_instance.h create mode 100644 tizen/extensions/common/xwalk_extension_manager.cc create mode 100644 tizen/extensions/common/xwalk_extension_manager.h create mode 100644 tizen/extensions/common/xwalk_extension_server.cc create mode 100644 tizen/extensions/common/xwalk_extension_server.h create mode 100644 tizen/extensions/extensions.gyp create mode 100644 tizen/extensions/internal/splash_screen/splash_screen.json create mode 100644 tizen/extensions/internal/splash_screen/splash_screen_api.js create mode 100644 tizen/extensions/internal/splash_screen/splash_screen_extension.cc create mode 100644 tizen/extensions/internal/widget/widget.json create mode 100644 tizen/extensions/internal/widget/widget_api.js create mode 100644 tizen/extensions/internal/widget/widget_extension.cc create mode 100644 tizen/extensions/public/XW_Extension.h create mode 100644 tizen/extensions/public/XW_Extension_EntryPoints.h create mode 100644 tizen/extensions/public/XW_Extension_Message_2.h create mode 100644 tizen/extensions/public/XW_Extension_Permissions.h create mode 100644 tizen/extensions/public/XW_Extension_Runtime.h create mode 100644 tizen/extensions/public/XW_Extension_SyncMessage.h create mode 100644 tizen/extensions/renderer/object_tools_module.cc create mode 100644 tizen/extensions/renderer/object_tools_module.h create mode 100644 tizen/extensions/renderer/runtime_ipc_client.cc create mode 100644 tizen/extensions/renderer/runtime_ipc_client.h create mode 100644 tizen/extensions/renderer/widget_module.cc create mode 100644 tizen/extensions/renderer/widget_module.h create mode 100644 tizen/extensions/renderer/xwalk_extension_client.cc create mode 100644 tizen/extensions/renderer/xwalk_extension_client.h create mode 100644 tizen/extensions/renderer/xwalk_extension_module.cc create mode 100644 tizen/extensions/renderer/xwalk_extension_module.h create mode 100644 tizen/extensions/renderer/xwalk_extension_renderer_controller.cc create mode 100644 tizen/extensions/renderer/xwalk_extension_renderer_controller.h create mode 100644 tizen/extensions/renderer/xwalk_module_system.cc create mode 100644 tizen/extensions/renderer/xwalk_module_system.h create mode 100644 tizen/extensions/renderer/xwalk_v8tools_module.cc create mode 100644 tizen/extensions/renderer/xwalk_v8tools_module.h create mode 100644 tizen/renderer/injected_bundle.cc create mode 100644 tizen/renderer/injected_bundle.gyp diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc index 9f9ac69..f840690 100644 --- a/atom/app/atom_main_delegate.cc +++ b/atom/app/atom_main_delegate.cc @@ -25,6 +25,11 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" +#if defined(OS_TIZEN) +#include "tizen/common/command_line.h" +#include "atom/common/atom_command_line.h" +#endif + namespace atom { namespace { @@ -141,6 +146,14 @@ void AtomMainDelegate::PreSandboxStartup() { // Allow file:// URIs to read other file:// URIs by default. command_line->AppendSwitch(::switches::kAllowFileAccessFromFiles); +#if defined(OS_TIZEN) + LOG (ERROR) << "Set Injected bundle path to engine"; + command_line->AppendSwitchASCII("injected-bundle-path","/usr/lib/libxwalk_injected_bundle.so"); + std::vector cmdAgrs = atom::AtomCommandLine::argv(); + std::string app_id = cmdAgrs[1]; + command_line->AppendSwitchASCII("widget-id",app_id); +#endif + #if defined(OS_MACOSX) // Enable AVFoundation. command_line->AppendSwitch("enable-avfoundation"); diff --git a/packaging/electron-efl.spec b/packaging/electron-efl.spec index f26da7c..7f48f8b 100755 --- a/packaging/electron-efl.spec +++ b/packaging/electron-efl.spec @@ -53,6 +53,7 @@ BuildRequires: pkgconfig(ttrace) BuildRequires: pkgconfig(vd-win-util) %endif BuildRequires: pkgconfig(wgt-manifest-handlers) +BuildRequires: pkgconfig(jsoncpp) Requires: /usr/bin/systemctl @@ -74,6 +75,8 @@ DEFINE_ARGS=" libchromiumcontent_component=1 use_efl=1 is_tizen=1 + injected_bundle_path=%{_libdir}/libxwalk_injected_bundle.so + extension_path=%{_libdir}/tizen-extensions-crosswalk " %if "%{?TIZEN_PRODUCT_TV}" == "1" DEFINE_ARGS+=" @@ -131,6 +134,13 @@ install -m 0755 %{_out}/resources/electron.asar %{buildroot}/opt/usr/home/ow ./node_modules/asar/bin/asar p wrt %{_out}/resources/app.asar install -m 0755 %{_out}/resources/app.asar %{buildroot}/opt/usr/home/owner/data/org.tizen.electron-efl +# injected bundle and extensions +mkdir -p %{buildroot}%{extension_path} +# xwalk extension shared +install -p -m 644 %{_out}/lib/libxwalk_extension_shared.so %{buildroot}%{_libdir} +# xwalk_injected_bundle +install -p -m 755 %{_out}/lib/libxwalk_injected_bundle.so %{buildroot}%{_libdir} + %post # Owner account can't write /opt/usr/home/owner/data/org.tizen.electron-efl # which is created in 'install'. So we should copy resources in 'post'. @@ -161,3 +171,5 @@ rm -fr %{buildroot} %attr(755,root,root) %{_bindir}/xwalk_runtime %attr(644,root,root) %{_datadir}/aul/wrt.loader %attr(644,root,root) %{_libdir}/libwrt_common.so +%attr(644,root,root) %{_libdir}/libxwalk_extension_shared.so +%attr(644,root,root) %{_libdir}/libxwalk_injected_bundle.so diff --git a/tizen/build/common.gypi b/tizen/build/common.gypi index 587a0ad..5f90ec5 100644 --- a/tizen/build/common.gypi +++ b/tizen/build/common.gypi @@ -1,8 +1,8 @@ { 'variables': { 'build_type%': 'Debug', -# 'extension_path%': '<(extension_path)', -# 'injected_bundle_path%': '<(injected_bundle_path)', + 'extension_path%': '<(extension_path)', + 'injected_bundle_path%': '<(injected_bundle_path)', }, 'target_defaults': { 'variables': { @@ -36,10 +36,10 @@ '../', '<(SHARED_INTERMEDIATE_DIR)', ], -# 'defines': [ -# 'EXTENSION_PATH="<(extension_path)"', -# 'INJECTED_BUNDLE_PATH="<(injected_bundle_path)"', -# ], + 'defines': [ + 'EXTENSION_PATH="<(extension_path)"', + 'INJECTED_BUNDLE_PATH="<(injected_bundle_path)"', + ], 'cflags': [ '-std=c++0x', '-fPIC', diff --git a/tizen/extensions/common/constants.cc b/tizen/extensions/common/constants.cc new file mode 100644 index 0000000..cfc9fa4 --- /dev/null +++ b/tizen/extensions/common/constants.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "extensions/common/constants.h" + +namespace extensions { + +const char kMethodGetExtensions[] = "xwalk://GetExtensions"; +const char kMethodCreateInstance[] = "xwalk://CreateInstance"; +const char kMethodDestroyInstance[] = "xwalk://DestroyInstance"; +const char kMethodSendSyncMessage[] = "xwalk://SendSyncMessage"; +const char kMethodPostMessage[] = "xwalk://PostMessage"; +const char kMethodGetAPIScript[] = "xwalk://GetAPIScript"; +const char kMethodPostMessageToJS[] = "xwalk://PostMessageToJS"; + + +} // namespace extensions diff --git a/tizen/extensions/common/constants.h b/tizen/extensions/common/constants.h new file mode 100644 index 0000000..588f09b --- /dev/null +++ b/tizen/extensions/common/constants.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef XWALK_EXTENSIONS_COMMON_CONSTANTS_H_ +#define XWALK_EXTENSIONS_COMMON_CONSTANTS_H_ + +namespace extensions { + +extern const char kMethodGetExtensions[]; +extern const char kMethodCreateInstance[]; +extern const char kMethodDestroyInstance[]; +extern const char kMethodSendSyncMessage[]; +extern const char kMethodPostMessage[]; +extern const char kMethodGetAPIScript[]; +extern const char kMethodPostMessageToJS[]; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_COMMON_CONSTANTS_H_ diff --git a/tizen/extensions/common/xwalk_extension.cc b/tizen/extensions/common/xwalk_extension.cc new file mode 100644 index 0000000..d41af24 --- /dev/null +++ b/tizen/extensions/common/xwalk_extension.cc @@ -0,0 +1,125 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/common/xwalk_extension.h" + +#include +#include + +#include "common/logger.h" +#include "extensions/common/xwalk_extension_adapter.h" +#include "extensions/public/XW_Extension.h" + +namespace extensions { + +XWalkExtension::XWalkExtension(const std::string& path, + XWalkExtensionDelegate* delegate) + : initialized_(false), + library_path_(path), + xw_extension_(0), + lazy_loading_(false), + delegate_(delegate), + created_instance_callback_(NULL), + destroyed_instance_callback_(NULL), + shutdown_callback_(NULL), + handle_msg_callback_(NULL), + handle_sync_msg_callback_(NULL), + handle_binary_msg_callback_(NULL) { +} + +XWalkExtension::XWalkExtension(const std::string& path, + const std::string& name, + const StringVector& entry_points, + XWalkExtensionDelegate* delegate) + : initialized_(false), + library_path_(path), + xw_extension_(0), + name_(name), + entry_points_(entry_points), + lazy_loading_(true), + delegate_(delegate), + created_instance_callback_(NULL), + destroyed_instance_callback_(NULL), + shutdown_callback_(NULL), + handle_msg_callback_(NULL), + handle_sync_msg_callback_(NULL), + handle_binary_msg_callback_(NULL) { +} + +XWalkExtension::~XWalkExtension() { + if (!initialized_) + return; + if (shutdown_callback_) + shutdown_callback_(xw_extension_); + XWalkExtensionAdapter::GetInstance()->UnregisterExtension(this); +} + +bool XWalkExtension::Initialize() { + if (initialized_) + return true; + + LOGGER(DEBUG) << "XWalkExtension:Initialize"; + void* handle = dlopen(library_path_.c_str(), RTLD_LAZY); + if (!handle) { + LOGGER(ERROR) << "Error loading extension '" + << library_path_ << "' : " << dlerror(); + return false; + } + + XW_Initialize_Func initialize = reinterpret_cast( + dlsym(handle, "XW_Initialize")); + if (!initialize) { + LOGGER(ERROR) << "Error loading extension '" << library_path_ + << "' : couldn't get XW_Initialize function."; + dlclose(handle); + return false; + } + + XWalkExtensionAdapter* adapter = XWalkExtensionAdapter::GetInstance(); + xw_extension_ = adapter->GetNextXWExtension(); + adapter->RegisterExtension(this); + + int ret = initialize(xw_extension_, XWalkExtensionAdapter::GetInterface); + if (ret != XW_OK) { + LOGGER(ERROR) << "Error loading extension '" << library_path_ + << "' : XW_Initialize() returned error value."; + dlclose(handle); + return false; + } + + initialized_ = true; + return true; +} + +XWalkExtensionInstance* XWalkExtension::CreateInstance() { + Initialize(); + XWalkExtensionAdapter* adapter = XWalkExtensionAdapter::GetInstance(); + XW_Instance xw_instance = adapter->GetNextXWInstance(); + return new XWalkExtensionInstance(this, xw_instance); +} + +std::string XWalkExtension::GetJavascriptCode() { + Initialize(); + return javascript_api_; +} + +void XWalkExtension::GetRuntimeVariable(const char* key, char* value, + size_t value_len) { + if (delegate_) { + delegate_->GetRuntimeVariable(key, value, value_len); + } +} +int XWalkExtension::CheckAPIAccessControl(const char* /*api_name*/) { + // Not Supported + return XW_OK; +} + +int XWalkExtension::RegisterPermissions(const char* /*perm_table*/) { + // Not Supported + return XW_OK; +} + +} // namespace extensions + diff --git a/tizen/extensions/common/xwalk_extension.h b/tizen/extensions/common/xwalk_extension.h new file mode 100644 index 0000000..c7aaf83 --- /dev/null +++ b/tizen/extensions/common/xwalk_extension.h @@ -0,0 +1,82 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_XWALK_EXTENSION_H_ +#define XWALK_EXTENSIONS_XWALK_EXTENSION_H_ + +#include +#include + +#include "extensions/common/xwalk_extension_instance.h" +#include "extensions/public/XW_Extension.h" +#include "extensions/public/XW_Extension_SyncMessage.h" +#include "extensions/public/XW_Extension_Message_2.h" + +namespace extensions { + +class XWalkExtensionAdapter; +class XWalkExtensionInstance; + +class XWalkExtension { + public: + typedef std::vector StringVector; + + class XWalkExtensionDelegate { + public: + virtual void GetRuntimeVariable(const char* key, char* value, + size_t value_len) = 0; + }; + + XWalkExtension(const std::string& path, XWalkExtensionDelegate* delegate); + XWalkExtension(const std::string& path, + const std::string& name, + const StringVector& entry_points, + XWalkExtensionDelegate* delegate); + virtual ~XWalkExtension(); + + bool Initialize(); + XWalkExtensionInstance* CreateInstance(); + std::string GetJavascriptCode(); + + std::string name() const { return name_; } + + const StringVector& entry_points() const { + return entry_points_; + } + + bool lazy_loading() const { + return lazy_loading_; + } + + private: + friend class XWalkExtensionAdapter; + friend class XWalkExtensionInstance; + + void GetRuntimeVariable(const char* key, char* value, size_t value_len); + int CheckAPIAccessControl(const char* api_name); + int RegisterPermissions(const char* perm_table); + + bool initialized_; + std::string library_path_; + XW_Extension xw_extension_; + + std::string name_; + std::string javascript_api_; + StringVector entry_points_; + bool lazy_loading_; + + XWalkExtensionDelegate* delegate_; + + XW_CreatedInstanceCallback created_instance_callback_; + XW_DestroyedInstanceCallback destroyed_instance_callback_; + XW_ShutdownCallback shutdown_callback_; + XW_HandleMessageCallback handle_msg_callback_; + XW_HandleSyncMessageCallback handle_sync_msg_callback_; + XW_HandleBinaryMessageCallback handle_binary_msg_callback_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_XWALK_EXTENSION_H_ diff --git a/tizen/extensions/common/xwalk_extension_adapter.cc b/tizen/extensions/common/xwalk_extension_adapter.cc new file mode 100644 index 0000000..ef693ff --- /dev/null +++ b/tizen/extensions/common/xwalk_extension_adapter.cc @@ -0,0 +1,323 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/common/xwalk_extension_adapter.h" + +#include + +#include "common/logger.h" + +namespace extensions { + +XWalkExtensionAdapter::XWalkExtensionAdapter() + : next_xw_extension_(1), + next_xw_instance_(1) { +} + +XWalkExtensionAdapter::~XWalkExtensionAdapter() { +} + +XWalkExtensionAdapter* XWalkExtensionAdapter::GetInstance() { + static XWalkExtensionAdapter self; + return &self; +} + +XW_Extension XWalkExtensionAdapter::GetNextXWExtension() { + return next_xw_extension_++; +} + +XW_Instance XWalkExtensionAdapter::GetNextXWInstance() { + return next_xw_instance_++; +} + +void XWalkExtensionAdapter::RegisterExtension(XWalkExtension* extension) { + XW_Extension xw_extension = extension->xw_extension_; + if (!(xw_extension > 0 && xw_extension < next_xw_extension_)) { + LOGGER(WARN) << "xw_extension (" << xw_extension << ") is invalid."; + return; + } + if (extension_map_.find(xw_extension) == extension_map_.end()) + extension_map_[xw_extension] = extension; +} + +void XWalkExtensionAdapter::UnregisterExtension(XWalkExtension* extension) { + XW_Extension xw_extension = extension->xw_extension_; + if (!(xw_extension > 0 && xw_extension < next_xw_extension_)) { + LOGGER(WARN) << "xw_extension (" << xw_extension << ") is invalid."; + return; + } + auto it = extension_map_.find(xw_extension); + if (it != extension_map_.end()) { + extension_map_.erase(it); + } +} + +void XWalkExtensionAdapter::RegisterInstance( + XWalkExtensionInstance* instance) { + XW_Instance xw_instance = instance->xw_instance_; + if (!(xw_instance > 0 && xw_instance < next_xw_instance_)) { + LOGGER(WARN) << "xw_instance (" << xw_instance << ") is invalid."; + return; + } + if (instance_map_.find(xw_instance) == instance_map_.end()) + instance_map_[xw_instance] = instance; +} + +void XWalkExtensionAdapter::UnregisterInstance( + XWalkExtensionInstance* instance) { + XW_Instance xw_instance = instance->xw_instance_; + if (!(xw_instance > 0 && xw_instance < next_xw_instance_)) { + LOGGER(WARN) << "xw_instance (" << xw_instance << ") is invalid."; + return; + } + auto it = instance_map_.find(xw_instance); + if (it != instance_map_.end()) { + instance_map_.erase(it); + } +} + +const void* XWalkExtensionAdapter::GetInterface(const char* name) { + if (!strcmp(name, XW_CORE_INTERFACE_1)) { + static const XW_CoreInterface_1 coreInterface1 = { + CoreSetExtensionName, + CoreSetJavaScriptAPI, + CoreRegisterInstanceCallbacks, + CoreRegisterShutdownCallback, + CoreSetInstanceData, + CoreGetInstanceData + }; + return &coreInterface1; + } + + if (!strcmp(name, XW_MESSAGING_INTERFACE_1)) { + static const XW_MessagingInterface_1 messagingInterface1 = { + MessagingRegister, + MessagingPostMessage + }; + return &messagingInterface1; + } + + if (!strcmp(name, XW_MESSAGING_INTERFACE_2)) { + static const XW_MessagingInterface_2 messagingInterface2 = { + MessagingRegister, + MessagingPostMessage, + MessagingRegisterBinaryMessageCallback, + MessagingPostBinaryMessage + }; + return &messagingInterface2; + } + + if (!strcmp(name, XW_INTERNAL_SYNC_MESSAGING_INTERFACE_1)) { + static const XW_Internal_SyncMessagingInterface_1 + syncMessagingInterface1 = { + SyncMessagingRegister, + SyncMessagingSetSyncReply + }; + return &syncMessagingInterface1; + } + + if (!strcmp(name, XW_INTERNAL_ENTRY_POINTS_INTERFACE_1)) { + static const XW_Internal_EntryPointsInterface_1 entryPointsInterface1 = { + EntryPointsSetExtraJSEntryPoints + }; + return &entryPointsInterface1; + } + + if (!strcmp(name, XW_INTERNAL_RUNTIME_INTERFACE_1)) { + static const XW_Internal_RuntimeInterface_1 runtimeInterface1 = { + RuntimeGetStringVariable + }; + return &runtimeInterface1; + } + + if (!strcmp(name, XW_INTERNAL_PERMISSIONS_INTERFACE_1)) { + static const XW_Internal_PermissionsInterface_1 permissionsInterface1 = { + PermissionsCheckAPIAccessControl, + PermissionsRegisterPermissions + }; + return &permissionsInterface1; + } + + LOGGER(WARN) << "Interface '" << name << "' is not supported."; + return NULL; +} + +XWalkExtension* XWalkExtensionAdapter::GetExtension(XW_Extension xw_extension) { + XWalkExtensionAdapter* adapter = XWalkExtensionAdapter::GetInstance(); + ExtensionMap::iterator it = adapter->extension_map_.find(xw_extension); + if (it == adapter->extension_map_.end()) + return NULL; + return it->second; +} + +XWalkExtensionInstance* XWalkExtensionAdapter::GetExtensionInstance( + XW_Instance xw_instance) { + XWalkExtensionAdapter* adapter = XWalkExtensionAdapter::GetInstance(); + InstanceMap::iterator it = adapter->instance_map_.find(xw_instance); + if (it == adapter->instance_map_.end()) + return NULL; + return it->second; +} + +#define CHECK(x, xw) \ + if (!x) { \ + LOGGER(WARN) << "Ignoring call. Invalid " << #xw << " = " << xw; \ + return; \ + } + +#define RETURN_IF_INITIALIZED(x) \ + if (x->initialized_) \ + return; + +void XWalkExtensionAdapter::CoreSetExtensionName( + XW_Extension xw_extension, + const char* name) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + RETURN_IF_INITIALIZED(extension); + extension->name_ = name; +} + +void XWalkExtensionAdapter::CoreSetJavaScriptAPI( + XW_Extension xw_extension, + const char* javascript_api) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + RETURN_IF_INITIALIZED(extension); + extension->javascript_api_ = javascript_api; +} + +void XWalkExtensionAdapter::CoreRegisterInstanceCallbacks( + XW_Extension xw_extension, + XW_CreatedInstanceCallback created, + XW_DestroyedInstanceCallback destroyed) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + RETURN_IF_INITIALIZED(extension); + extension->created_instance_callback_ = created; + extension->destroyed_instance_callback_ = destroyed; +} + +void XWalkExtensionAdapter::CoreRegisterShutdownCallback( + XW_Extension xw_extension, + XW_ShutdownCallback shutdown) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + RETURN_IF_INITIALIZED(extension); + extension->shutdown_callback_ = shutdown; +} + +void XWalkExtensionAdapter::CoreSetInstanceData( + XW_Instance xw_instance, + void* data) { + XWalkExtensionInstance* instance = GetExtensionInstance(xw_instance); + CHECK(instance, xw_instance); + instance->instance_data_ = data; +} + +void* XWalkExtensionAdapter::CoreGetInstanceData( + XW_Instance xw_instance) { + XWalkExtensionInstance* instance = GetExtensionInstance(xw_instance); + if (instance) + return instance->instance_data_; + else + return NULL; +} + +void XWalkExtensionAdapter::MessagingRegister( + XW_Extension xw_extension, + XW_HandleMessageCallback handle_message) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + RETURN_IF_INITIALIZED(extension); + extension->handle_msg_callback_ = handle_message; +} + +void XWalkExtensionAdapter::MessagingPostMessage( + XW_Instance xw_instance, + const char* message) { + XWalkExtensionInstance* instance = GetExtensionInstance(xw_instance); + CHECK(instance, xw_instance); + instance->PostMessageToJS(message); +} + +void XWalkExtensionAdapter::SyncMessagingRegister( + XW_Extension xw_extension, + XW_HandleSyncMessageCallback handle_sync_message) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + RETURN_IF_INITIALIZED(extension); + extension->handle_sync_msg_callback_ = handle_sync_message; +} + +void XWalkExtensionAdapter::SyncMessagingSetSyncReply( + XW_Instance xw_instance, + const char* reply) { + XWalkExtensionInstance* instance = GetExtensionInstance(xw_instance); + CHECK(instance, xw_instance); + instance->SyncReplyToJS(reply); +} + +void XWalkExtensionAdapter::EntryPointsSetExtraJSEntryPoints( + XW_Extension xw_extension, + const char** entry_points) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + RETURN_IF_INITIALIZED(extension); + + for (int i=0; entry_points[i]; ++i) { + extension->entry_points_.push_back(std::string(entry_points[i])); + } +} + +void XWalkExtensionAdapter::RuntimeGetStringVariable( + XW_Extension xw_extension, + const char* key, + char* value, + unsigned int value_len) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + extension->GetRuntimeVariable(key, value, value_len); +} + +int XWalkExtensionAdapter::PermissionsCheckAPIAccessControl( + XW_Extension xw_extension, + const char* api_name) { + XWalkExtension* extension = GetExtension(xw_extension); + if (extension) + return extension->CheckAPIAccessControl(api_name); + else + return XW_ERROR; +} + +int XWalkExtensionAdapter::PermissionsRegisterPermissions( + XW_Extension xw_extension, + const char* perm_table) { + XWalkExtension* extension = GetExtension(xw_extension); + if (extension) + return extension->RegisterPermissions(perm_table); + else + return XW_ERROR; +} + +void XWalkExtensionAdapter::MessagingRegisterBinaryMessageCallback( + XW_Extension xw_extension, XW_HandleBinaryMessageCallback handle_message) { + XWalkExtension* extension = GetExtension(xw_extension); + CHECK(extension, xw_extension); + RETURN_IF_INITIALIZED(extension); + extension->handle_binary_msg_callback_ = handle_message; +} + +void XWalkExtensionAdapter::MessagingPostBinaryMessage( + XW_Instance xw_instance, const char* message, size_t size) { + XWalkExtensionInstance* instance = GetExtensionInstance(xw_instance); + CHECK(instance, xw_instance); + instance->PostMessageToJS(message); +} + +#undef CHECK +#undef RETURN_IF_INITIALIZED + +} // namespace extensions diff --git a/tizen/extensions/common/xwalk_extension_adapter.h b/tizen/extensions/common/xwalk_extension_adapter.h new file mode 100644 index 0000000..9a29c35 --- /dev/null +++ b/tizen/extensions/common/xwalk_extension_adapter.h @@ -0,0 +1,96 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_XWALK_EXTENSION_ADAPTER_H_ +#define XWALK_EXTENSIONS_XWALK_EXTENSION_ADAPTER_H_ + +#include + +#include "extensions/common/xwalk_extension.h" +#include "extensions/common/xwalk_extension_instance.h" +#include "extensions/public/XW_Extension.h" +#include "extensions/public/XW_Extension_EntryPoints.h" +#include "extensions/public/XW_Extension_Permissions.h" +#include "extensions/public/XW_Extension_Runtime.h" +#include "extensions/public/XW_Extension_SyncMessage.h" +#include "extensions/public/XW_Extension_Message_2.h" + +namespace extensions { + +class XWalkExtensionAdapter { + public: + typedef std::map ExtensionMap; + typedef std::map InstanceMap; + + static XWalkExtensionAdapter* GetInstance(); + + XW_Extension GetNextXWExtension(); + XW_Instance GetNextXWInstance(); + + void RegisterExtension(XWalkExtension* extension); + void UnregisterExtension(XWalkExtension* extension); + + void RegisterInstance(XWalkExtensionInstance* instance); + void UnregisterInstance(XWalkExtensionInstance* instance); + + // Returns the correct struct according to interface asked. This is + // passed to external extensions in XW_Initialize() call. + static const void* GetInterface(const char* name); + + private: + XWalkExtensionAdapter(); + virtual ~XWalkExtensionAdapter(); + + static XWalkExtension* GetExtension(XW_Extension xw_extension); + static XWalkExtensionInstance* GetExtensionInstance(XW_Instance xw_instance); + + static void CoreSetExtensionName( + XW_Extension xw_extension, const char* name); + static void CoreSetJavaScriptAPI( + XW_Extension xw_extension, const char* javascript_api); + static void CoreRegisterInstanceCallbacks( + XW_Extension xw_extension, + XW_CreatedInstanceCallback created, + XW_DestroyedInstanceCallback destroyed); + static void CoreRegisterShutdownCallback( + XW_Extension xw_extension, + XW_ShutdownCallback shutdown); + static void CoreSetInstanceData( + XW_Instance xw_instance, void* data); + static void* CoreGetInstanceData(XW_Instance xw_instance); + static void MessagingRegister( + XW_Extension xw_extension, + XW_HandleMessageCallback handle_message); + static void MessagingPostMessage( + XW_Instance xw_instance, const char* message); + static void SyncMessagingRegister( + XW_Extension xw_extension, + XW_HandleSyncMessageCallback handle_sync_message); + static void SyncMessagingSetSyncReply( + XW_Instance xw_instance, const char* reply); + static void EntryPointsSetExtraJSEntryPoints( + XW_Extension xw_extension, const char** entry_points); + static void RuntimeGetStringVariable( + XW_Extension xw_extension, + const char* key, char* value, unsigned int value_len); + static int PermissionsCheckAPIAccessControl( + XW_Extension xw_extension, const char* api_name); + static int PermissionsRegisterPermissions( + XW_Extension xw_extension, const char* perm_table); + static void MessagingRegisterBinaryMessageCallback( + XW_Extension xw_extension, XW_HandleBinaryMessageCallback handle_message); + static void MessagingPostBinaryMessage( + XW_Instance xw_instance, const char* message, size_t size); + + ExtensionMap extension_map_; + InstanceMap instance_map_; + + XW_Extension next_xw_extension_; + XW_Instance next_xw_instance_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_XWALK_EXTENSION_ADAPTER_H_ diff --git a/tizen/extensions/common/xwalk_extension_instance.cc b/tizen/extensions/common/xwalk_extension_instance.cc new file mode 100644 index 0000000..c86bb59 --- /dev/null +++ b/tizen/extensions/common/xwalk_extension_instance.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/common/xwalk_extension_instance.h" + +#include "extensions/common/xwalk_extension_adapter.h" +#include "extensions/public/XW_Extension_SyncMessage.h" + +namespace extensions { + +XWalkExtensionInstance::XWalkExtensionInstance( + XWalkExtension* extension, XW_Instance xw_instance) + : extension_(extension), + xw_instance_(xw_instance), + instance_data_(NULL) { + XWalkExtensionAdapter::GetInstance()->RegisterInstance(this); + XW_CreatedInstanceCallback callback = extension_->created_instance_callback_; + if (callback) + callback(xw_instance_); +} + +XWalkExtensionInstance::~XWalkExtensionInstance() { + XW_DestroyedInstanceCallback callback = + extension_->destroyed_instance_callback_; + if (callback) + callback(xw_instance_); + XWalkExtensionAdapter::GetInstance()->UnregisterInstance(this); +} + +void XWalkExtensionInstance::HandleMessage(const std::string& msg) { + XW_HandleMessageCallback callback = extension_->handle_msg_callback_; + if (callback) + callback(xw_instance_, msg.c_str()); +} + +void XWalkExtensionInstance::HandleSyncMessage(const std::string& msg) { + XW_HandleSyncMessageCallback callback = extension_->handle_sync_msg_callback_; + if (callback) { + callback(xw_instance_, msg.c_str()); + } +} + +void XWalkExtensionInstance::SetPostMessageCallback( + MessageCallback callback) { + post_message_callback_ = callback; +} + +void XWalkExtensionInstance::SetSendSyncReplyCallback( + MessageCallback callback) { + send_sync_reply_callback_ = callback; +} + +void XWalkExtensionInstance::PostMessageToJS(const std::string& msg) { + post_message_callback_(msg); +} + +void XWalkExtensionInstance::SyncReplyToJS(const std::string& reply) { + send_sync_reply_callback_(reply); +} + +} // namespace extensions diff --git a/tizen/extensions/common/xwalk_extension_instance.h b/tizen/extensions/common/xwalk_extension_instance.h new file mode 100644 index 0000000..9efe2db --- /dev/null +++ b/tizen/extensions/common/xwalk_extension_instance.h @@ -0,0 +1,47 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_XWALK_EXTENSION_INSTANCE_H_ +#define XWALK_EXTENSIONS_XWALK_EXTENSION_INSTANCE_H_ + +#include +#include + +#include "extensions/public/XW_Extension.h" + +namespace extensions { + +class XWalkExtension; + +class XWalkExtensionInstance { + public: + typedef std::function MessageCallback; + + XWalkExtensionInstance(XWalkExtension* extension, XW_Instance xw_instance); + virtual ~XWalkExtensionInstance(); + + void HandleMessage(const std::string& msg); + void HandleSyncMessage(const std::string& msg); + + void SetPostMessageCallback(MessageCallback callback); + void SetSendSyncReplyCallback(MessageCallback callback); + + private: + friend class XWalkExtensionAdapter; + + void PostMessageToJS(const std::string& msg); + void SyncReplyToJS(const std::string& reply); + + XWalkExtension* extension_; + XW_Instance xw_instance_; + void* instance_data_; + + MessageCallback post_message_callback_; + MessageCallback send_sync_reply_callback_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_XWALK_EXTENSION_INSTANCE_H_ diff --git a/tizen/extensions/common/xwalk_extension_manager.cc b/tizen/extensions/common/xwalk_extension_manager.cc new file mode 100644 index 0000000..130eca8 --- /dev/null +++ b/tizen/extensions/common/xwalk_extension_manager.cc @@ -0,0 +1,260 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/common/xwalk_extension_manager.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "common/app_db.h" +#include "common/logger.h" +#include "common/picojson.h" +#include "common/file_utils.h" +#include "common/string_utils.h" + +#include "extensions/common/constants.h" +#include "extensions/common/xwalk_extension.h" + +#ifndef EXTENSION_PATH + #error EXTENSION_PATH is not set. +#endif + +namespace extensions { + +namespace { + +const char kAppDBRuntimeSection[] = "Runtime"; + +const char kExtensionPrefix[] = "lib"; +const char kExtensionSuffix[] = ".so"; +const char kExtensionMetadataSuffix[] = ".json"; + +static const char* kPreloadLibs[] = { + EXTENSION_PATH"/libtizen.so", + EXTENSION_PATH"/libtizen_common.so", + EXTENSION_PATH"/libtizen_application.so", + EXTENSION_PATH"/libtizen_utils.so", + NULL +}; + +const char kUserPluginsDirectory[] = "plugin/"; +const char kArchArmv7l[] = "armv7l"; +const char kArchI586[] = "i586"; +const char kArchDefault[] = "default"; + +} // namespace + +XWalkExtensionManager::XWalkExtensionManager() { +} + +XWalkExtensionManager::~XWalkExtensionManager() { +} + +void XWalkExtensionManager::PreloadExtensions() { + for (int i = 0; kPreloadLibs[i]; i++) { + LOGGER(DEBUG) << "Preload libs : " << kPreloadLibs[i]; + void* handle = dlopen(kPreloadLibs[i], RTLD_NOW|RTLD_GLOBAL); + if (handle == nullptr) { + LOGGER(WARN) << "Fail to load libs : " << dlerror(); + } + } +} + +void XWalkExtensionManager::LoadExtensions(bool meta_only) { + if (!extensions_.empty()) { + return; + } + + std::string extension_path(EXTENSION_PATH); + + // Gets all extension files in the EXTENSION_PATH + std::string ext_pattern(extension_path); + ext_pattern.append("/"); + ext_pattern.append(kExtensionPrefix); + ext_pattern.append("*"); + ext_pattern.append(kExtensionSuffix); + + StringSet files; + { + glob_t glob_result; + glob(ext_pattern.c_str(), GLOB_TILDE, NULL, &glob_result); + for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) { + files.insert(glob_result.gl_pathv[i]); + } + } + + // Gets all metadata files in the EXTENSION_PATH + // Loads information from the metadata files and remove the loaded file from + // the set 'files' + std::string meta_pattern(extension_path); + meta_pattern.append("/"); + meta_pattern.append("*"); + meta_pattern.append(kExtensionMetadataSuffix); + { + glob_t glob_result; + glob(meta_pattern.c_str(), GLOB_TILDE, NULL, &glob_result); + for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) { + RegisterExtensionsByMeta(glob_result.gl_pathv[i], &files); + } + } + + // Load extensions in the remained files of the set 'files' + if (!meta_only) { + for (auto it = files.begin(); it != files.end(); ++it) { + XWalkExtension* ext = new XWalkExtension(*it, this); + RegisterExtension(ext); + } + } +} + +void XWalkExtensionManager::LoadUserExtensions(const std::string app_path) { + if (app_path.empty()) { + LOGGER(ERROR) << "Failed to get package root path"; + return; + } + std::string app_ext_pattern(app_path); + app_ext_pattern.append(kUserPluginsDirectory); + struct utsname u; + if (0 == uname(&u)) { + std::string machine = u.machine; + if (!machine.empty()) { + if (machine == kArchArmv7l) { + app_ext_pattern.append(kArchArmv7l); + } else if (machine == kArchI586) { + app_ext_pattern.append(kArchI586); + } else { + app_ext_pattern.append(kArchDefault); + } + } else { + LOGGER(ERROR) << "cannot get machine info"; + app_ext_pattern.append(kArchDefault); + } + app_ext_pattern.append("/"); + } + app_ext_pattern.append("*"); + app_ext_pattern.append(kExtensionSuffix); + + StringSet files; + { + glob_t glob_result; + glob(app_ext_pattern.c_str(), GLOB_TILDE, NULL, &glob_result); + for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) { + files.insert(glob_result.gl_pathv[i]); + } + } + for (auto it = files.begin(); it != files.end(); ++it) { + XWalkExtension* ext = new XWalkExtension(*it, this); + RegisterExtension(ext); + } + LOGGER(DEBUG) << "finish load user extension plugins"; +} + +void XWalkExtensionManager::UnloadExtensions() { + for (auto it = extensions_.begin(); it != extensions_.end(); ++it) { + delete it->second; + } + extensions_.clear(); +} + +bool XWalkExtensionManager::RegisterSymbols(XWalkExtension* extension) { + std::string name = extension->name(); + + if (extension_symbols_.find(name) != extension_symbols_.end()) { + LOGGER(WARN) << "Ignoring extension with name already registred. '" + << name << "'"; + return false; + } + + XWalkExtension::StringVector entry_points = extension->entry_points(); + for (auto it = entry_points.begin(); it != entry_points.end(); ++it) { + if (extension_symbols_.find(*it) != extension_symbols_.end()) { + LOGGER(WARN) << "Ignoring extension with entry_point already registred. '" + << (*it) << "'"; + return false; + } + } + + for (auto it = entry_points.begin(); it != entry_points.end(); ++it) { + extension_symbols_.insert(*it); + } + + extension_symbols_.insert(name); + + return true; +} + +void XWalkExtensionManager::RegisterExtension(XWalkExtension* extension) { + if (!extension->lazy_loading() && !extension->Initialize()) { + delete extension; + return; + } + + if (!RegisterSymbols(extension)) { + delete extension; + return; + } + + extensions_[extension->name()] = extension; + LOGGER(DEBUG) << extension->name() << " is registered."; +} + +void XWalkExtensionManager::RegisterExtensionsByMeta( + const std::string& meta_path, StringSet* files) { + std::string extension_path(EXTENSION_PATH); + + std::ifstream metafile(meta_path.c_str()); + if (!metafile.is_open()) { + LOGGER(ERROR) << "Fail to open the plugin metadata file :" << meta_path; + return; + } + + picojson::value metadata; + metafile >> metadata; + if (metadata.is()) { + auto& plugins = metadata.get(); + for (auto plugin = plugins.begin(); plugin != plugins.end(); ++plugin) { + if (!plugin->is()) + continue; + + std::string name = plugin->get("name").to_str(); + std::string lib = plugin->get("lib").to_str(); + if (!common::utils::StartsWith(lib, "/")) { + lib = extension_path + "/" + lib; + } + + std::vector entries; + auto& entry_points_value = plugin->get("entry_points"); + if (entry_points_value.is()) { + auto& entry_points = entry_points_value.get(); + for (auto entry = entry_points.begin(); entry != entry_points.end(); + ++entry) { + entries.push_back(entry->to_str()); + } + } + XWalkExtension* extension = new XWalkExtension(lib, name, entries, this); + RegisterExtension(extension); + files->erase(lib); + } + } else { + LOGGER(ERROR) << meta_path << " is not a valid metadata file."; + } + metafile.close(); +} + +// override +void XWalkExtensionManager::GetRuntimeVariable( + const char* key, char* value, size_t value_len) { + common::AppDB* db = common::AppDB::GetInstance(); + std::string ret = db->Get(kAppDBRuntimeSection, key); + strncpy(value, ret.c_str(), value_len); +} + + +} // namespace extensions diff --git a/tizen/extensions/common/xwalk_extension_manager.h b/tizen/extensions/common/xwalk_extension_manager.h new file mode 100644 index 0000000..cfbdede --- /dev/null +++ b/tizen/extensions/common/xwalk_extension_manager.h @@ -0,0 +1,47 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_XWALK_EXTENSION_MANAGER_H_ +#define XWALK_EXTENSIONS_XWALK_EXTENSION_MANAGER_H_ + +#include +#include +#include + +#include "extensions/common/xwalk_extension.h" + +namespace extensions { + +class XWalkExtensionManager : public XWalkExtension::XWalkExtensionDelegate { + public: + typedef std::set StringSet; + typedef std::map ExtensionMap; + + XWalkExtensionManager(); + virtual ~XWalkExtensionManager(); + + ExtensionMap extensions() const { return extensions_; } + + void LoadExtensions(bool meta_only = true); + void LoadUserExtensions(const std::string app_path); + void PreloadExtensions(); + + void UnloadExtensions(); + + private: + // override + void GetRuntimeVariable(const char* key, char* value, size_t value_len); + + bool RegisterSymbols(XWalkExtension* extension); + void RegisterExtension(XWalkExtension* extension); + void RegisterExtensionsByMeta(const std::string& meta_path, + StringSet* files); + + StringSet extension_symbols_; + ExtensionMap extensions_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_XWALK_EXTENSION_MANAGER_H_ diff --git a/tizen/extensions/common/xwalk_extension_server.cc b/tizen/extensions/common/xwalk_extension_server.cc new file mode 100644 index 0000000..fc50396 --- /dev/null +++ b/tizen/extensions/common/xwalk_extension_server.cc @@ -0,0 +1,229 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/common/xwalk_extension_server.h" + +#include + +#include + +#include "common/logger.h" +#include "common/profiler.h" +#include "common/string_utils.h" +#include "extensions/common/constants.h" +#include "extensions/common/xwalk_extension_manager.h" + +namespace extensions { + +// static +XWalkExtensionServer* XWalkExtensionServer::GetInstance() { + static XWalkExtensionServer self; + return &self; +} + +XWalkExtensionServer::XWalkExtensionServer() { + manager_.LoadExtensions(); +} + +XWalkExtensionServer::~XWalkExtensionServer() { +} + +void XWalkExtensionServer::SetupIPC(Ewk_Context* ewk_context) { + ewk_context_ = ewk_context; +} + +void XWalkExtensionServer::Preload() { + manager_.PreloadExtensions(); +} + +void XWalkExtensionServer::Shutdown() { + for (auto it = instances_.begin(); it != instances_.end(); ++it) { + delete it->second; + } + instances_.clear(); + manager_.UnloadExtensions(); +} + +Json::Value XWalkExtensionServer::GetExtensions() { + Json::Value out; + auto extensions = manager_.extensions(); + for (auto it = extensions.begin(); it != extensions.end(); ++it) { + Json::Value ext; + ext["name"] = it->second->name(); + // ext["api"] = it->second->GetJavascriptCode(); + auto entry_points = it->second->entry_points(); + for (auto ite = entry_points.begin(); ite != entry_points.end(); ++ite) { + ext["entry_points"].append(*ite); + } + out.append(ext); + } + return out; +} + +std::string XWalkExtensionServer::GetAPIScript( + const std::string& extension_name) { + auto extensions = manager_.extensions(); + auto it = extensions.find(extension_name); + if (it == extensions.end()) { + LOGGER(ERROR) << "No such extension '" << extension_name << "'"; + return std::string(); + } + + return it->second->GetJavascriptCode(); +} + +std::string XWalkExtensionServer::CreateInstance( + const std::string& extension_name) { + std::string instance_id; + + auto extensions = manager_.extensions(); + auto it = extensions.find(extension_name); + if (it != extensions.end()) { + XWalkExtensionInstance* instance = it->second->CreateInstance(); + if (instance) { + instance_id = common::utils::GenerateUUID(); + instance->SetPostMessageCallback( + [this, instance_id](const std::string& msg) { + Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new(); + ewk_ipc_wrt_message_data_type_set(ans, kMethodPostMessageToJS); + ewk_ipc_wrt_message_data_id_set(ans, instance_id.c_str()); + ewk_ipc_wrt_message_data_value_set(ans, msg.c_str()); + if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) { + LOGGER(ERROR) << "Failed to send response"; + } + ewk_ipc_wrt_message_data_del(ans); + }); + + instances_[instance_id] = instance; + } else { + LOGGER(ERROR) << "Failed to create instance of the extension '" + << extension_name << "'"; + } + } else { + LOGGER(ERROR) << "No such extension '" << extension_name << "'"; + } + return instance_id; +} + +void XWalkExtensionServer::HandleIPCMessage(Ewk_IPC_Wrt_Message_Data* data) { + if (!data) { + LOGGER(ERROR) << "Invalid parameter. data is NULL."; + return; + } + + if (!ewk_context_) { + LOGGER(WARN) << "IPC is not ready yet."; + return; + } + + Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(data); + #define TYPE_IS(x) (!strcmp(msg_type, x)) + + if (TYPE_IS(kMethodGetExtensions)) { + HandleGetExtensions(data); + } else if (TYPE_IS(kMethodCreateInstance)) { + HandleCreateInstance(data); + } else if (TYPE_IS(kMethodDestroyInstance)) { + HandleDestroyInstance(data); + } else if (TYPE_IS(kMethodPostMessage)) { + HandlePostMessageToNative(data); + } else if (TYPE_IS(kMethodSendSyncMessage)) { + HandleSendSyncMessageToNative(data); + } else if (TYPE_IS(kMethodGetAPIScript)) { + HandleGetAPIScript(data); + } + + eina_stringshare_del(msg_type); + #undef TYPE_IS +} + +void XWalkExtensionServer::HandleGetExtensions(Ewk_IPC_Wrt_Message_Data* data) { + Json::Value reply = GetExtensions(); + Json::FastWriter writer; + std::string reply_str = writer.write(reply); + ewk_ipc_wrt_message_data_value_set(data, reply_str.c_str()); +} + +void XWalkExtensionServer::HandleCreateInstance( + Ewk_IPC_Wrt_Message_Data* data) { + Eina_Stringshare* extension_name = ewk_ipc_wrt_message_data_value_get(data); + + std::string instance_id = CreateInstance(extension_name); + + ewk_ipc_wrt_message_data_value_set(data, instance_id.c_str()); + + eina_stringshare_del(extension_name); +} + +void XWalkExtensionServer::HandleDestroyInstance( + Ewk_IPC_Wrt_Message_Data* data) { + Eina_Stringshare* instance_id = ewk_ipc_wrt_message_data_id_get(data); + + auto it = instances_.find(instance_id); + if (it != instances_.end()) { + XWalkExtensionInstance* instance = it->second; + delete instance; + instances_.erase(it); + } else { + LOGGER(ERROR) << "No such instance '" << instance_id << "'"; + } + + eina_stringshare_del(instance_id); +} + +void XWalkExtensionServer::HandlePostMessageToNative( + Ewk_IPC_Wrt_Message_Data* data) { + Eina_Stringshare* instance_id = ewk_ipc_wrt_message_data_id_get(data); + + auto it = instances_.find(instance_id); + if (it != instances_.end()) { + Eina_Stringshare* msg = ewk_ipc_wrt_message_data_value_get(data); + XWalkExtensionInstance* instance = it->second; + instance->HandleMessage(msg); + eina_stringshare_del(msg); + } else { + LOGGER(ERROR) << "No such instance '" << instance_id << "'"; + } + + eina_stringshare_del(instance_id); +} + +void XWalkExtensionServer::HandleSendSyncMessageToNative( + Ewk_IPC_Wrt_Message_Data* data) { + Eina_Stringshare* instance_id = ewk_ipc_wrt_message_data_id_get(data); + + auto it = instances_.find(instance_id); + if (it != instances_.end()) { + Eina_Stringshare* msg = ewk_ipc_wrt_message_data_value_get(data); + XWalkExtensionInstance* instance = it->second; + std::string reply; + instance->SetSendSyncReplyCallback([&reply](const std::string& msg) { + reply = msg; + }); + instance->HandleSyncMessage(msg); + ewk_ipc_wrt_message_data_value_set(data, reply.c_str()); + eina_stringshare_del(msg); + } else { + LOGGER(ERROR) << "No such instance '" << instance_id << "'"; + } + + eina_stringshare_del(instance_id); +} + +void XWalkExtensionServer::HandleGetAPIScript( + Ewk_IPC_Wrt_Message_Data* data) { + Eina_Stringshare* extension_name = ewk_ipc_wrt_message_data_value_get(data); + + std::string api = GetAPIScript(extension_name); + + ewk_ipc_wrt_message_data_value_set(data, api.c_str()); + + eina_stringshare_del(extension_name); +} + +void XWalkExtensionServer::LoadUserExtensions(const std::string app_path) { + manager_.LoadUserExtensions(app_path); +} + +} // namespace extensions diff --git a/tizen/extensions/common/xwalk_extension_server.h b/tizen/extensions/common/xwalk_extension_server.h new file mode 100644 index 0000000..3cd67bf --- /dev/null +++ b/tizen/extensions/common/xwalk_extension_server.h @@ -0,0 +1,57 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_XWALK_EXTENSION_SERVER_H_ +#define XWALK_EXTENSIONS_XWALK_EXTENSION_SERVER_H_ + +#include +#include +#include + +#include +#include + +#include "extensions/common/xwalk_extension_manager.h" +#include "extensions/common/xwalk_extension_instance.h" + +namespace extensions { + +class XWalkExtensionServer { + public: + static XWalkExtensionServer* GetInstance(); + + void SetupIPC(Ewk_Context* ewk_context); + void Preload(); + Json::Value GetExtensions(); + std::string GetAPIScript(const std::string& extension_name); + std::string CreateInstance(const std::string& extension_name); + + void HandleIPCMessage(Ewk_IPC_Wrt_Message_Data* data); + + void Shutdown(); + void LoadUserExtensions(const std::string app_path); + + private: + XWalkExtensionServer(); + virtual ~XWalkExtensionServer(); + + void HandleGetExtensions(Ewk_IPC_Wrt_Message_Data* data); + void HandleCreateInstance(Ewk_IPC_Wrt_Message_Data* data); + void HandleDestroyInstance(Ewk_IPC_Wrt_Message_Data* data); + void HandlePostMessageToNative(Ewk_IPC_Wrt_Message_Data* data); + void HandleSendSyncMessageToNative(Ewk_IPC_Wrt_Message_Data* data); + void HandleGetAPIScript(Ewk_IPC_Wrt_Message_Data* data); + + typedef std::map InstanceMap; + + Ewk_Context* ewk_context_; + + XWalkExtensionManager manager_; + + InstanceMap instances_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_XWALK_EXTENSION_SERVER_H_ diff --git a/tizen/extensions/extensions.gyp b/tizen/extensions/extensions.gyp new file mode 100644 index 0000000..165271b --- /dev/null +++ b/tizen/extensions/extensions.gyp @@ -0,0 +1,60 @@ +{ + 'includes':[ + '../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'xwalk_extension_shared', + 'type': 'shared_library', + 'sources': [ + 'common/constants.h', + 'common/constants.cc', + 'common/xwalk_extension.h', + 'common/xwalk_extension.cc', + 'common/xwalk_extension_instance.h', + 'common/xwalk_extension_instance.cc', + 'common/xwalk_extension_adapter.h', + 'common/xwalk_extension_adapter.cc', + 'common/xwalk_extension_manager.h', + 'common/xwalk_extension_manager.cc', + 'common/xwalk_extension_server.h', + 'common/xwalk_extension_server.cc', + 'renderer/xwalk_extension_client.h', + 'renderer/xwalk_extension_client.cc', + 'renderer/xwalk_extension_module.h', + 'renderer/xwalk_extension_module.cc', + 'renderer/xwalk_extension_renderer_controller.h', + 'renderer/xwalk_extension_renderer_controller.cc', + 'renderer/xwalk_module_system.h', + 'renderer/xwalk_module_system.cc', + 'renderer/xwalk_v8tools_module.h', + 'renderer/xwalk_v8tools_module.cc', + 'renderer/widget_module.h', + 'renderer/widget_module.cc', + 'renderer/object_tools_module.h', + 'renderer/object_tools_module.cc', + 'renderer/runtime_ipc_client.h', + 'renderer/runtime_ipc_client.cc', + ], + 'cflags': [ + '-fvisibility=default', + ], + 'variables': { + 'packages': [ + 'chromium-efl', + 'elementary', + ], + }, + 'direct_dependent_settings': { +# 'libraries': [ +# '-lxwalk_extension_shared', +# ], + 'variables': { + 'packages': [ + 'jsoncpp', + ], + }, + }, + }, # end of target 'xwalk_extension_static' + ], # end of targets +} diff --git a/tizen/extensions/internal/splash_screen/splash_screen.json b/tizen/extensions/internal/splash_screen/splash_screen.json new file mode 100644 index 0000000..e7a565d --- /dev/null +++ b/tizen/extensions/internal/splash_screen/splash_screen.json @@ -0,0 +1,7 @@ +[ + { + "name":"SplashScreen", + "lib":"libsplash_screen_plugin.so", + "entry_points":["window.screen.show"] + } +] diff --git a/tizen/extensions/internal/splash_screen/splash_screen_api.js b/tizen/extensions/internal/splash_screen/splash_screen_api.js new file mode 100644 index 0000000..551a72d --- /dev/null +++ b/tizen/extensions/internal/splash_screen/splash_screen_api.js @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var sendRuntimeMessage = extension.sendRuntimeMessage || function() { + console.error('Runtime did not implement extension.sendRuntimeMessage!'); +}; +window.screen.show = function() { + sendRuntimeMessage('tizen://hide_splash_screen'); +}; diff --git a/tizen/extensions/internal/splash_screen/splash_screen_extension.cc b/tizen/extensions/internal/splash_screen/splash_screen_extension.cc new file mode 100644 index 0000000..19823e5 --- /dev/null +++ b/tizen/extensions/internal/splash_screen/splash_screen_extension.cc @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "extensions/public/XW_Extension.h" +#include "extensions/public/XW_Extension_EntryPoints.h" +#include "extensions/public/XW_Extension_Permissions.h" +#include "extensions/public/XW_Extension_Runtime.h" +#include "extensions/public/XW_Extension_SyncMessage.h" + +#include "common/application_data.h" +#include "common/locale_manager.h" +#include "common/logger.h" +#include "common/string_utils.h" + +XW_Extension g_xw_extension = 0; +const XW_CoreInterface* g_core = NULL; +const XW_MessagingInterface* g_messaging = NULL; +const XW_Internal_SyncMessagingInterface* g_sync_messaging = NULL; +const XW_Internal_EntryPointsInterface* g_entry_points = NULL; +const XW_Internal_RuntimeInterface* g_runtime = NULL; + +extern const char kSource_splash_screen_api[]; + +extern "C" int32_t XW_Initialize(XW_Extension extension, + XW_GetInterface get_interface) { + g_xw_extension = extension; + g_core = reinterpret_cast( + get_interface(XW_CORE_INTERFACE)); + if (!g_core) { + LOGGER(ERROR) + << "Can't initialize extension: error getting Core interface."; + return XW_ERROR; + } + + g_messaging = reinterpret_cast( + get_interface(XW_MESSAGING_INTERFACE)); + if (!g_messaging) { + LOGGER(ERROR) + << "Can't initialize extension: error getting Messaging interface."; + return XW_ERROR; + } + + g_sync_messaging = + reinterpret_cast( + get_interface(XW_INTERNAL_SYNC_MESSAGING_INTERFACE)); + if (!g_sync_messaging) { + LOGGER(ERROR) + << "Can't initialize extension: " + << "error getting SyncMessaging interface."; + return XW_ERROR; + } + + g_entry_points = reinterpret_cast( + get_interface(XW_INTERNAL_ENTRY_POINTS_INTERFACE)); + if (!g_entry_points) { + LOGGER(ERROR) + << "NOTE: Entry points interface not available in this version " + << "of Crosswalk, ignoring entry point data for extensions.\n"; + return XW_ERROR; + } + + g_runtime = reinterpret_cast( + get_interface(XW_INTERNAL_RUNTIME_INTERFACE)); + if (!g_runtime) { + LOGGER(ERROR) + << "NOTE: runtime interface not available in this version " + << "of Crosswalk, ignoring runtime variables for extensions.\n"; + return XW_ERROR; + } + + g_core->SetExtensionName(g_xw_extension, "SplashScreen"); + const char* entry_points[] = {"window.screen.show", NULL}; + g_entry_points->SetExtraJSEntryPoints(g_xw_extension, entry_points); + g_core->SetJavaScriptAPI(g_xw_extension, kSource_splash_screen_api); + + return XW_OK; +} diff --git a/tizen/extensions/internal/widget/widget.json b/tizen/extensions/internal/widget/widget.json new file mode 100644 index 0000000..ae1dbbd --- /dev/null +++ b/tizen/extensions/internal/widget/widget.json @@ -0,0 +1,7 @@ +[ + { + "name":"Widget", + "lib":"libwidget_plugin.so", + "entry_points":["widget"] + } +] diff --git a/tizen/extensions/internal/widget/widget_api.js b/tizen/extensions/internal/widget/widget_api.js new file mode 100644 index 0000000..6a5b7a6 --- /dev/null +++ b/tizen/extensions/internal/widget/widget_api.js @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var dispatchStorageEvent = function(key, oldValue, newValue) { + var evt = document.createEvent("CustomEvent"); + evt.initCustomEvent("storage", true, true, null); + evt.key = key; + evt.oldValue = oldValue; + evt.newValue = newValue; + evt.storageArea = window.widget.preference; + document.dispatchEvent(evt); + for (var i=0; i < window.frames.length; i++) { + window.frames[i].document.dispatchEvent(evt); + } +}; + +var widget_info_ = requireNative('WidgetModule'); +var preference_ = widget_info_['preference']; +preference_.__onChanged_WRT__ = dispatchStorageEvent; + +function Widget() { + Object.defineProperties(this, { + "author": { + value: widget_info_[ +"author"], + writable: false + }, + "description": { + value: widget_info_["description"], + writable: false + }, + "name": { + value: widget_info_["name"], + writable: false + }, + "shortName": { + value: widget_info_["shortName"], + writable: false + }, + "version": { + value: widget_info_["version"], + writable: false + }, + "id": { + value: widget_info_["id"], + writable: false + }, + "authorEmail": { + value: widget_info_["authorEmail"], + writable: false + }, + "authorHref": { + value: widget_info_["authorHref"], + writable: false + }, + "height": { + get: function() { + return window && window.innerHeight || 0; + }, + configurable: false + }, + "width": { + get: function() { + return window && window.innerWidth || 0; + }, + configurable: false + }, + "preferences": { + value: preference_, + writable: false + } + }); +}; + +Widget.prototype.toString = function() { + return "[object Widget]"; +}; + +window.widget = new Widget(); +exports = Widget; diff --git a/tizen/extensions/internal/widget/widget_extension.cc b/tizen/extensions/internal/widget/widget_extension.cc new file mode 100644 index 0000000..aab1dab --- /dev/null +++ b/tizen/extensions/internal/widget/widget_extension.cc @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "extensions/public/XW_Extension.h" +#include "extensions/public/XW_Extension_EntryPoints.h" +#include "extensions/public/XW_Extension_Permissions.h" +#include "extensions/public/XW_Extension_Runtime.h" +#include "extensions/public/XW_Extension_SyncMessage.h" + +#include "common/application_data.h" +#include "common/locale_manager.h" +#include "common/logger.h" +#include "common/string_utils.h" + +XW_Extension g_xw_extension = 0; +const XW_CoreInterface* g_core = NULL; +const XW_MessagingInterface* g_messaging = NULL; +const XW_Internal_SyncMessagingInterface* g_sync_messaging = NULL; +const XW_Internal_EntryPointsInterface* g_entry_points = NULL; +const XW_Internal_RuntimeInterface* g_runtime = NULL; + +extern const char kSource_widget_api[]; + +extern "C" int32_t XW_Initialize(XW_Extension extension, + XW_GetInterface get_interface) { + g_xw_extension = extension; + g_core = reinterpret_cast( + get_interface(XW_CORE_INTERFACE)); + if (!g_core) { + LOGGER(ERROR) + << "Can't initialize extension: error getting Core interface."; + return XW_ERROR; + } + + g_messaging = reinterpret_cast( + get_interface(XW_MESSAGING_INTERFACE)); + if (!g_messaging) { + LOGGER(ERROR) + << "Can't initialize extension: error getting Messaging interface."; + return XW_ERROR; + } + + g_sync_messaging = + reinterpret_cast( + get_interface(XW_INTERNAL_SYNC_MESSAGING_INTERFACE)); + if (!g_sync_messaging) { + LOGGER(ERROR) + << "Can't initialize extension: " + << "error getting SyncMessaging interface."; + return XW_ERROR; + } + + g_entry_points = reinterpret_cast( + get_interface(XW_INTERNAL_ENTRY_POINTS_INTERFACE)); + if (!g_entry_points) { + LOGGER(ERROR) + << "NOTE: Entry points interface not available in this version " + << "of Crosswalk, ignoring entry point data for extensions.\n"; + return XW_ERROR; + } + + g_runtime = reinterpret_cast( + get_interface(XW_INTERNAL_RUNTIME_INTERFACE)); + if (!g_runtime) { + LOGGER(ERROR) + << "NOTE: runtime interface not available in this version " + << "of Crosswalk, ignoring runtime variables for extensions.\n"; + return XW_ERROR; + } + + g_core->SetExtensionName(g_xw_extension, "Widget"); + const char* entry_points[] = {"widget", NULL}; + g_entry_points->SetExtraJSEntryPoints(g_xw_extension, entry_points); + g_core->SetJavaScriptAPI(g_xw_extension, kSource_widget_api); + + return XW_OK; +} diff --git a/tizen/extensions/public/XW_Extension.h b/tizen/extensions/public/XW_Extension.h new file mode 100644 index 0000000..174915a --- /dev/null +++ b/tizen/extensions/public/XW_Extension.h @@ -0,0 +1,185 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ + +// Crosswalk Extensions are modules of code loaded by Crosswalk runtime that +// allow extending its capabilities. The extension is expected to define a +// XW_Initialize() function as declared below, get the interfaces it need to +// use and register to whatever callbacks it needs, then return XW_OK. +// +// The Extension is represented by the type XW_Extension. Each extension +// loaded may be used multiple times for different pages, so to each execution +// there will be an associated XW_Instance. A reasonable analogy is that the +// XW_Extension represent a "class", and have concrete instances running. +// +// An interface is a struct with a set of functions, provided by Crosswalk, +// that allow the extension code to interact with the web content. Certain +// functions in an interface are used to register callbacks, so that Crosswalk +// can call the extension at specific situations. +// +// Crosswalk won't call an extension's XW_Initialize() multiple times in the +// same process. + +#ifdef __cplusplus +extern "C" { +#endif + +#if __GNUC__ >= 4 +#define XW_EXPORT __attribute__ ((visibility("default"))) +#elif defined(_MSC_VER) +#define XW_EXPORT __declspec(dllexport) +#endif + +#include + + +// XW_Extension is used to identify your extension when calling functions from +// the API. You should always use the XW_Extension received at XW_Initialize(). +// +// XW_Instance is used to identify different web contents using your +// extension. Each time a new web content is created you can be notified +// registering the XW_CreatedInstanceCallback, that receives the new +// XW_Instance. When interacting with an Instance (for example to post a +// message), you should pass the corresponding XW_Instance. +// +// In both types the zero value is never used by Crosswalk, so can be used to +// initialize variables. +typedef int32_t XW_Extension; +typedef int32_t XW_Instance; + +enum { + XW_OK = 0, + XW_ERROR = -1 +}; + +// Returns a struct containing functions to be used by the extension. Those +// structs can be stored statically and used until the extension is unloaded. +// Extensions should use definitions like XW_CORE_INTERFACE, instead of using +// the versioned definition or the literal string. Returns NULL if the +// interface is not supported. +typedef const void* (*XW_GetInterface)(const char* interface_name); + + +typedef int32_t (*XW_Initialize_Func)(XW_Extension extension, + XW_GetInterface get_interface); + +// XW_Initialize is called after the extension code is loaded. The 'extension' +// value should be used in further calls that expect XW_Extension argument. +// +// The 'get_interface' function should be used to get access to functions that +// interact with the web content. It is only valid during the execution of the +// XW_Initialize() function. +// +// This function should return XW_OK when the extension was succesfully +// loaded, otherwise XW_ERROR. +XW_EXPORT int32_t XW_Initialize(XW_Extension extension, + XW_GetInterface get_interface); + + +// +// XW_CORE_INTERFACE: Basic functionality for Crosswalk Extensions. All +// extensions should use this interface to set at least their name. +// + +#define XW_CORE_INTERFACE_1 "XW_CoreInterface_1" +#define XW_CORE_INTERFACE XW_CORE_INTERFACE_1 + +typedef void (*XW_CreatedInstanceCallback)(XW_Instance instance); +typedef void (*XW_DestroyedInstanceCallback)(XW_Instance instance); +typedef void (*XW_ShutdownCallback)(XW_Extension extension); + +struct XW_CoreInterface_1 { + // Set the name of the extension. It is used as the namespace for the + // JavaScript code exposed by the extension. So extension named + // 'my_extension', will expose its JavaScript functionality inside + // the 'my_extension' namespace. + // + // This function should be called only during XW_Initialize(). + void (*SetExtensionName)(XW_Extension extension, const char* name); + + // Set the JavaScript code loaded in the web content when the extension is + // used. This can be used together with the messaging mechanism to implement + // a higher-level API that posts messages to extensions, see + // XW_MESSAGING_INTERFACE below. + // + // The code will be executed inside a JS function context with the following + // objects available: + // + // - exports: this object should be filled with properties and functions + // that will be exposed in the namespace associated with this + // extension. + // + // - extension.postMessage(): post a string message to the extension native + // code. See below for details. + // - extension.setMessageListener(): allow setting a callback that is called + // when the native code sends a message + // to JavaScript. Callback takes a string. + // + // This function should be called only during XW_Initialize(). + void (*SetJavaScriptAPI)(XW_Extension extension, const char* api); + + // Register callbacks that are called when an instance of this extension + // is created or destroyed. Everytime a new web content is loaded, it will + // get a new associated instance. + // + // This function should be called only during XW_Initialize(). + void (*RegisterInstanceCallbacks)(XW_Extension extension, + XW_CreatedInstanceCallback created, + XW_DestroyedInstanceCallback destroyed); + + // Register a callback to be executed when the extension will be unloaded. + // + // This function should be called only during XW_Initialize(). + void (*RegisterShutdownCallback)(XW_Extension extension, + XW_ShutdownCallback shutdown_callback); + + // These two functions are conveniences used to associated arbitrary data + // with a given XW_Instance. They can be used only with instances that were + // created but not yet completely destroyed. GetInstanceData() can be used + // during the destroyed instance callback. If not instance data was set, + // getting it returns NULL. + void (*SetInstanceData)(XW_Instance instance, void* data); + void* (*GetInstanceData)(XW_Instance instance); +}; + +typedef struct XW_CoreInterface_1 XW_CoreInterface; + + +// +// XW_MESSAGING_INTERFACE: Exchange asynchronous messages with JavaScript +// code provided by extension. +// + +#define XW_MESSAGING_INTERFACE_1 "XW_MessagingInterface_1" +#define XW_MESSAGING_INTERFACE XW_MESSAGING_INTERFACE_1 + +typedef void (*XW_HandleMessageCallback)(XW_Instance instance, + const char* message); + +struct XW_MessagingInterface_1 { + // Register a callback to be called when the JavaScript code associated + // with the extension posts a message. Note that the callback will be called + // with the XW_Instance that posted the message as well as the message + // contents. + void (*Register)(XW_Extension extension, + XW_HandleMessageCallback handle_message); + + // Post a message to the web content associated with the instance. To + // receive this message the extension's JavaScript code should set a + // listener using extension.setMessageListener() function. + // + // This function is thread-safe and can be called until the instance is + // destroyed. + void (*PostMessage)(XW_Instance instance, const char* message); +}; + +typedef struct XW_MessagingInterface_1 XW_MessagingInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ diff --git a/tizen/extensions/public/XW_Extension_EntryPoints.h b/tizen/extensions/public/XW_Extension_EntryPoints.h new file mode 100644 index 0000000..54532a9 --- /dev/null +++ b/tizen/extensions/public/XW_Extension_EntryPoints.h @@ -0,0 +1,49 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_ + +// NOTE: This file and interfaces marked as internal are not considered stable +// and can be modified in incompatible ways between Crosswalk versions. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define XW_INTERNAL_ENTRY_POINTS_INTERFACE_1 \ + "XW_Internal_EntryPointsInterface_1" +#define XW_INTERNAL_ENTRY_POINTS_INTERFACE \ + XW_INTERNAL_ENTRY_POINTS_INTERFACE_1 + +// +// XW_INTERNAL_ENTRY_POINTS_INTERFACE: provides a way for extensions to add +// more information about its implementation. For now, allow extensions to +// specify more objects that the access should cause the extension to be +// loaded. +// + +struct XW_Internal_EntryPointsInterface_1 { + // Register extra entry points for this extension. An "extra" entry points + // are objects outside the implicit namespace for which the extension should + // be loaded when they are touched. + // + // This function should be called only during XW_Initialize(). + void (*SetExtraJSEntryPoints)(XW_Extension extension, + const char** entry_points); +}; + +typedef struct XW_Internal_EntryPointsInterface_1 + XW_Internal_EntryPointsInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_ + diff --git a/tizen/extensions/public/XW_Extension_Message_2.h b/tizen/extensions/public/XW_Extension_Message_2.h new file mode 100644 index 0000000..f417f88 --- /dev/null +++ b/tizen/extensions/public/XW_Extension_Message_2.h @@ -0,0 +1,64 @@ +// Copyright (c) 2015 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_MESSAGE_2_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_MESSAGE_2_H_ + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define XW_MESSAGING_INTERFACE_2 "XW_MessagingInterface_2" + +typedef void (*XW_HandleBinaryMessageCallback)(XW_Instance instance, + const char* message, + const size_t size); + +struct XW_MessagingInterface_2 { + // Register a callback to be called when the JavaScript code associated + // with the extension posts a message. Note that the callback will be called + // with the XW_Instance that posted the message as well as the message + // contents. + void (*Register)(XW_Extension extension, + XW_HandleMessageCallback handle_message); + + // Post a message to the web content associated with the instance. To + // receive this message the extension's JavaScript code should set a + // listener using extension.setMessageListener() function. + // + // This function is thread-safe and can be called until the instance is + // destroyed. + void (*PostMessage)(XW_Instance instance, const char* message); + + // Register a callback to be called when the JavaScript code associated + // with the extension posts a binary message (ArrayBuffer object). + // Note that the callback will be called with the XW_Instance that posted + // the message as well as the message contents. + void (*RegisterBinaryMesssageCallback)( + XW_Extension extension, + XW_HandleBinaryMessageCallback handle_message); + + // Post a binary message to the web content associated with the instance. To + // receive this message the extension's JavaScript code should set a + // listener using extension.setMessageListener() function. + // The JavaScript message listener function would receive the binary message + // in an ArrayBuffer object. + // + // This function is thread-safe and can be called until the instance is + // destroyed. + void (*PostBinaryMessage)(XW_Instance instance, + const char* message, size_t size); +}; + +typedef struct XW_MessagingInterface_2 XW_MessagingInterface2; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_MESSAGE_2_H_ diff --git a/tizen/extensions/public/XW_Extension_Permissions.h b/tizen/extensions/public/XW_Extension_Permissions.h new file mode 100644 index 0000000..d25484e --- /dev/null +++ b/tizen/extensions/public/XW_Extension_Permissions.h @@ -0,0 +1,41 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_ + +// NOTE: This file and interfaces marked as internal are not considered stable +// and can be modified in incompatible ways between Crosswalk versions. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define XW_INTERNAL_PERMISSIONS_INTERFACE_1 \ + "XW_Internal_PermissionsInterface_1" +#define XW_INTERNAL_PERMISSIONS_INTERFACE \ + XW_INTERNAL_PERMISSIONS_INTERFACE_1 + +// +// XW_INTERNAL_PERMISSIONS_INTERFACE: provides a way for extensions +// check if they have the proper permissions for certain APIs. +// + +struct XW_Internal_PermissionsInterface_1 { + int (*CheckAPIAccessControl)(XW_Extension extension, const char* api_name); + int (*RegisterPermissions)(XW_Extension extension, const char* perm_table); +}; + +typedef struct XW_Internal_PermissionsInterface_1 + XW_Internal_PermissionsInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_ diff --git a/tizen/extensions/public/XW_Extension_Runtime.h b/tizen/extensions/public/XW_Extension_Runtime.h new file mode 100644 index 0000000..11ad307 --- /dev/null +++ b/tizen/extensions/public/XW_Extension_Runtime.h @@ -0,0 +1,44 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_ + +// NOTE: This file and interfaces marked as internal are not considered stable +// and can be modified in incompatible ways between Crosswalk versions. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define XW_INTERNAL_RUNTIME_INTERFACE_1 \ + "XW_Internal_RuntimeInterface_1" +#define XW_INTERNAL_RUNTIME_INTERFACE \ + XW_INTERNAL_RUNTIME_INTERFACE_1 + +// +// XW_INTERNAL_RUNTIME_INTERFACE: allow extensions to gather information +// from the runtime. +// + +struct XW_Internal_RuntimeInterface_1 { + void (*GetRuntimeVariableString)(XW_Extension extension, + const char* key, + char* value, + unsigned int value_len); +}; + +typedef struct XW_Internal_RuntimeInterface_1 + XW_Internal_RuntimeInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_ + diff --git a/tizen/extensions/public/XW_Extension_SyncMessage.h b/tizen/extensions/public/XW_Extension_SyncMessage.h new file mode 100644 index 0000000..4eddbf9 --- /dev/null +++ b/tizen/extensions/public/XW_Extension_SyncMessage.h @@ -0,0 +1,48 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_ + +// NOTE: This file and interfaces marked as internal are not considered stable +// and can be modified in incompatible ways between Crosswalk versions. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// +// XW_INTERNAL_SYNC_MESSAGING_INTERFACE: allow JavaScript code to send a +// synchronous message to extension code and block until response is +// available. The response is made available by calling the SetSyncReply +// function, that can be done from outside the context of the SyncMessage +// handler. +// + +#define XW_INTERNAL_SYNC_MESSAGING_INTERFACE_1 \ + "XW_InternalSyncMessagingInterface_1" +#define XW_INTERNAL_SYNC_MESSAGING_INTERFACE \ + XW_INTERNAL_SYNC_MESSAGING_INTERFACE_1 + +typedef void (*XW_HandleSyncMessageCallback)(XW_Instance instance, + const char* message); + +struct XW_Internal_SyncMessagingInterface_1 { + void (*Register)(XW_Extension extension, + XW_HandleSyncMessageCallback handle_sync_message); + void (*SetSyncReply)(XW_Instance instance, const char* reply); +}; + +typedef struct XW_Internal_SyncMessagingInterface_1 + XW_Internal_SyncMessagingInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_ diff --git a/tizen/extensions/renderer/object_tools_module.cc b/tizen/extensions/renderer/object_tools_module.cc new file mode 100644 index 0000000..67cb503 --- /dev/null +++ b/tizen/extensions/renderer/object_tools_module.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "extensions/renderer/object_tools_module.h" + +#include + +#include + +#include "common/logger.h" + +namespace extensions { + +namespace { +const char *kCreateObjectCode = + "(function(object) {" + " var newobject = Object.create(object);" + " Object.getOwnPropertyNames(object).forEach(function(name) {" + " if (object[name] instanceof Function) {" + " newobject[name] = object[name];" + " }" + " });" + " newobject['origin_prototype'] = {};" + " Object.getOwnPropertyNames(object.prototype).forEach(function(name) {" + " if (object.prototype[name] instanceof Function) {" + " newobject['origin_prototype'][name] = object.prototype[name];" + " }" + " });" + " return function() {" + " return newobject;" + " };" + "}(Object));"; + +v8::Handle RunString(const std::string& code) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + v8::Handle v8_code( + v8::String::NewFromUtf8(isolate, code.c_str())); + + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + + v8::Handle script(v8::Script::Compile(v8_code)); + if (try_catch.HasCaught()) { + v8::String::Utf8Value exception(try_catch.Exception()); + LOGGER(ERROR) << "Error occurred(script compile):" << *exception; + return handle_scope.Escape( + v8::Local(v8::Undefined(isolate))); + } + + v8::Local result = script->Run(); + if (try_catch.HasCaught()) { + v8::String::Utf8Value exception(try_catch.Exception()); + LOGGER(ERROR) << "Error occurred(script run):" << *exception; + return handle_scope.Escape( + v8::Local(v8::Undefined(isolate))); + } + return handle_scope.Escape(result); +} +} // namespace + + +ObjectToolsModule::ObjectToolsModule() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + + v8::Handle result = RunString(kCreateObjectCode); + if (!result->IsFunction()) { + LOGGER(ERROR) << "Couldn't load Object Create function"; + return; + } + v8::Handle create_function = + v8::Handle::Cast(result); + + create_function_.Reset(isolate, create_function); +} + +ObjectToolsModule::~ObjectToolsModule() { + create_function_.Reset(); +} + +v8::Handle ObjectToolsModule::NewInstance() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + if (create_function_.IsEmpty()) { + return v8::Object::New(isolate); + } + v8::Handle function = + v8::Local::New(isolate, create_function_); + + v8::Handle context = v8::Context::New(isolate); + v8::TryCatch try_catch; + v8::Handle ret = function->Call(context->Global(), 0, NULL); + if (try_catch.HasCaught()) { + LOGGER(ERROR) << "Exception when running create function: "; + return v8::Object::New(isolate); + } + return v8::Handle::Cast(ret); +} + +} // namespace extensions + diff --git a/tizen/extensions/renderer/object_tools_module.h b/tizen/extensions/renderer/object_tools_module.h new file mode 100644 index 0000000..eb4609b --- /dev/null +++ b/tizen/extensions/renderer/object_tools_module.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef XWALK_EXTENSIONS_RENDERER_OBJECT_TOOLS_MODULE_H_ +#define XWALK_EXTENSIONS_RENDERER_OBJECT_TOOLS_MODULE_H_ + +#include "extensions/renderer/xwalk_module_system.h" + +namespace extensions { + +class ObjectToolsModule : public XWalkNativeModule { + public: + ObjectToolsModule(); + ~ObjectToolsModule() override; + + private: + v8::Handle NewInstance() override; + v8::Persistent create_function_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_RENDERER_OBJECT_TOOLS_MODULE_H_ diff --git a/tizen/extensions/renderer/runtime_ipc_client.cc b/tizen/extensions/renderer/runtime_ipc_client.cc new file mode 100644 index 0000000..6b96828 --- /dev/null +++ b/tizen/extensions/renderer/runtime_ipc_client.cc @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "extensions/renderer/runtime_ipc_client.h" +#include "extensions/renderer/xwalk_extension_renderer_controller.h" + +#include "common/logger.h" +#include "common/profiler.h" +#include "common/string_utils.h" + +namespace extensions { + +namespace { + +const int kRoutingIdEmbedderDataIndex = 12; + +} // namespace + +RuntimeIPCClient::JSCallback::JSCallback(v8::Isolate* isolate, + v8::Handle callback) { + callback_.Reset(isolate, callback); +} + +RuntimeIPCClient::JSCallback::~JSCallback() { + callback_.Reset(); +} + +void RuntimeIPCClient::JSCallback::Call(v8::Isolate* isolate, + v8::Handle args[]) { + if (!callback_.IsEmpty()) { + v8::HandleScope handle_scope(isolate); + v8::TryCatch try_catch(isolate); + v8::Handle func = + v8::Local::New(isolate, callback_); + func->Call(func, 1, args); + if (try_catch.HasCaught()) { + LOGGER(ERROR) << "Exception when running Javascript callback"; + v8::String::Utf8Value exception_str(try_catch.Exception()); + LOGGER(ERROR) << (*exception_str); + } + } +} + +// static +RuntimeIPCClient* RuntimeIPCClient::GetInstance() { + static RuntimeIPCClient self; + return &self; +} + +RuntimeIPCClient::RuntimeIPCClient() { +} + +int RuntimeIPCClient::GetRoutingId(v8::Handle context) { + v8::Handle value = + context->GetEmbedderData(kRoutingIdEmbedderDataIndex); + int routing_id = 0; + if (value->IsNumber()) { + routing_id = value->IntegerValue(); + } else { + LOGGER(WARN) << "Failed to get routing index from context."; + } + + return routing_id; +} + +void RuntimeIPCClient::SetRoutingId(v8::Handle context, + int routing_id) { + context->SetEmbedderData(kRoutingIdEmbedderDataIndex, + v8::Integer::New(context->GetIsolate(), routing_id)); +} + +void RuntimeIPCClient::SendMessage(v8::Handle context, + const std::string& type, + const std::string& value) { + SendMessage(context, type, "", "", value); +} + +void RuntimeIPCClient::SendMessage(v8::Handle context, + const std::string& type, + const std::string& id, + const std::string& value) { + SendMessage(context, type, id, "", value); +} + +void RuntimeIPCClient::SendMessage(v8::Handle context, + const std::string& type, + const std::string& id, + const std::string& ref_id, + const std::string& value) { + if (!strcmp(type.c_str(), "tizen://exit")) { + extensions::XWalkExtensionRendererController& controller = + extensions::XWalkExtensionRendererController::GetInstance(); + controller.exit_requested = true; + } + + int routing_id = GetRoutingId(context); + if (routing_id < 1) { + LOGGER(ERROR) << "Invalid routing handle for IPC."; + return; + } + + Ewk_IPC_Wrt_Message_Data* msg = ewk_ipc_wrt_message_data_new(); + ewk_ipc_wrt_message_data_type_set(msg, type.c_str()); + ewk_ipc_wrt_message_data_id_set(msg, id.c_str()); + ewk_ipc_wrt_message_data_reference_id_set(msg, ref_id.c_str()); + ewk_ipc_wrt_message_data_value_set(msg, value.c_str()); + + if (!ewk_ipc_plugins_message_send(routing_id, msg)) { + LOGGER(ERROR) << "Failed to send message to runtime using ewk_ipc."; + } + + ewk_ipc_wrt_message_data_del(msg); +} + +std::string RuntimeIPCClient::SendSyncMessage(v8::Handle context, + const std::string& type, + const std::string& value) { + return SendSyncMessage(context, type, "", "", value); +} + +std::string RuntimeIPCClient::SendSyncMessage(v8::Handle context, + const std::string& type, + const std::string& id, + const std::string& value) { + return SendSyncMessage(context, type, id, "", value); +} + +std::string RuntimeIPCClient::SendSyncMessage(v8::Handle context, + const std::string& type, + const std::string& id, + const std::string& ref_id, + const std::string& value) { + int routing_id = GetRoutingId(context); + if (routing_id < 1) { + LOGGER(ERROR) << "Invalid routing handle for IPC."; + return std::string(); + } + + Ewk_IPC_Wrt_Message_Data* msg = ewk_ipc_wrt_message_data_new(); + ewk_ipc_wrt_message_data_type_set(msg, type.c_str()); + ewk_ipc_wrt_message_data_id_set(msg, id.c_str()); + ewk_ipc_wrt_message_data_reference_id_set(msg, ref_id.c_str()); + ewk_ipc_wrt_message_data_value_set(msg, value.c_str()); + + if (!ewk_ipc_plugins_sync_message_send(routing_id, msg)) { + LOGGER(ERROR) << "Failed to send message to runtime using ewk_ipc."; + ewk_ipc_wrt_message_data_del(msg); + return std::string(); + } + + Eina_Stringshare* msg_value = ewk_ipc_wrt_message_data_value_get(msg); + std::string result(msg_value); + eina_stringshare_del(msg_value); + + ewk_ipc_wrt_message_data_del(msg); + + return result; +} + +void RuntimeIPCClient::SendAsyncMessage(v8::Handle context, + const std::string& type, + const std::string& value, + ReplyCallback callback) { + int routing_id = GetRoutingId(context); + if (routing_id < 1) { + LOGGER(ERROR) << "Invalid routing handle for IPC."; + return; + } + + std::string msg_id = common::utils::GenerateUUID(); + + Ewk_IPC_Wrt_Message_Data* msg = ewk_ipc_wrt_message_data_new(); + ewk_ipc_wrt_message_data_id_set(msg, msg_id.c_str()); + ewk_ipc_wrt_message_data_type_set(msg, type.c_str()); + ewk_ipc_wrt_message_data_value_set(msg, value.c_str()); + + if (!ewk_ipc_plugins_message_send(routing_id, msg)) { + LOGGER(ERROR) << "Failed to send message to runtime using ewk_ipc."; + ewk_ipc_wrt_message_data_del(msg); + return; + } + + callbacks_[msg_id] = callback; + + ewk_ipc_wrt_message_data_del(msg); +} + +void RuntimeIPCClient::HandleMessageFromRuntime( + const Ewk_IPC_Wrt_Message_Data* msg) { + if (msg == NULL) { + LOGGER(ERROR) << "received message is NULL"; + return; + } + + Eina_Stringshare* msg_refid = ewk_ipc_wrt_message_data_reference_id_get(msg); + + if (msg_refid == NULL || !strcmp(msg_refid, "")) { + if (msg_refid) eina_stringshare_del(msg_refid); + LOGGER(ERROR) << "No reference id of received message."; + return; + } + + auto it = callbacks_.find(msg_refid); + if (it == callbacks_.end()) { + eina_stringshare_del(msg_refid); + LOGGER(ERROR) << "No registered callback with reference id : " << msg_refid; + return; + } + + Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(msg); + Eina_Stringshare* msg_value = ewk_ipc_wrt_message_data_value_get(msg); + + ReplyCallback func = it->second; + if (func) { + func(msg_type, msg_value); + } + + callbacks_.erase(it); + + eina_stringshare_del(msg_refid); + eina_stringshare_del(msg_type); + eina_stringshare_del(msg_value); +} + +} // namespace extensions diff --git a/tizen/extensions/renderer/runtime_ipc_client.h b/tizen/extensions/renderer/runtime_ipc_client.h new file mode 100644 index 0000000..7f94fb3 --- /dev/null +++ b/tizen/extensions/renderer/runtime_ipc_client.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef XWALK_EXTENSIONS_RENDERER_RUNTIME_IPC_CLIENT_H_ +#define XWALK_EXTENSIONS_RENDERER_RUNTIME_IPC_CLIENT_H_ + +#include +#include +#include + +#include +#include +#include + +namespace extensions { + +class RuntimeIPCClient { + public: + class JSCallback { + public: + explicit JSCallback(v8::Isolate* isolate, + v8::Handle callback); + ~JSCallback(); + + void Call(v8::Isolate* isolate, v8::Handle args[]); + private: + v8::Persistent callback_; + }; + + typedef std::function ReplyCallback; + + static RuntimeIPCClient* GetInstance(); + + // Send message to BrowserProcess without reply + void SendMessage(v8::Handle context, + const std::string& type, + const std::string& value); + + void SendMessage(v8::Handle context, + const std::string& type, + const std::string& id, + const std::string& value); + + void SendMessage(v8::Handle context, + const std::string& type, + const std::string& id, + const std::string& ref_id, + const std::string& value); + + // Send message to BrowserProcess synchronous with reply + std::string SendSyncMessage(v8::Handle context, + const std::string& type, + const std::string& value); + + std::string SendSyncMessage(v8::Handle context, + const std::string& type, + const std::string& id, + const std::string& value); + + std::string SendSyncMessage(v8::Handle context, + const std::string& type, + const std::string& id, + const std::string& ref_id, + const std::string& value); + + // Send message to BrowserProcess asynchronous, + // reply message will be passed to callback function. + void SendAsyncMessage(v8::Handle context, + const std::string& type, const std::string& value, + ReplyCallback callback); + + void HandleMessageFromRuntime(const Ewk_IPC_Wrt_Message_Data* msg); + + int GetRoutingId(v8::Handle context); + + void SetRoutingId(v8::Handle context, int routing_id); + + private: + RuntimeIPCClient(); + + std::map callbacks_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_RENDERER_RUNTIME_IPC_CLIENT_H_ diff --git a/tizen/extensions/renderer/widget_module.cc b/tizen/extensions/renderer/widget_module.cc new file mode 100644 index 0000000..2237501 --- /dev/null +++ b/tizen/extensions/renderer/widget_module.cc @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "extensions/renderer/widget_module.h" + +#include + +#include +#include + +#include "common/app_db.h" +#include "common/logger.h" + +namespace extensions { + +namespace { +const char* kOnchangedEventHandler = "__onChanged_WRT__"; +const char* kKeyKey = "key"; +const char* kGetItemKey = "getItem"; +const char* kSetItemKey = "setItem"; +const char* kRemoveItemKey = "removeItem"; +const char* kLengthKey = "length"; +const char* kClearKey = "clear"; +const int kKeyLengthLimit = 80; +const int kValueLengthLimit = 8192; + +std::vector kExcludeList = { + kOnchangedEventHandler, + kKeyKey, + kGetItemKey, + kSetItemKey, + kRemoveItemKey, + kLengthKey, + kClearKey}; + +void DispatchEvent(const v8::Local& This, + v8::Local key, + v8::Local oldvalue, + v8::Local newvalue) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + + v8::Handle function = + This->Get(v8::String::NewFromUtf8(isolate, kOnchangedEventHandler)); + + if (function.IsEmpty() || !function->IsFunction()) { + LOGGER(DEBUG) << "onChanged function not set"; + return; + } + + v8::Handle context = v8::Context::New(isolate); + + const int argc = 3; + v8::Handle argv[argc] = { + key, + oldvalue, + newvalue + }; + + v8::TryCatch try_catch; + v8::Handle::Cast(function)->Call( + context->Global(), argc, argv); + if (try_catch.HasCaught()) + LOGGER(DEBUG) << "Exception when running onChanged callback"; +} + +v8::Handle MakeException(int code, + std::string name, + std::string message) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + v8::Local error = v8::Object::New(isolate); + + error->Set( + v8::String::NewFromUtf8(isolate, "code"), + v8::Number::New(isolate, code)); + error->Set( + v8::String::NewFromUtf8(isolate, "name"), + v8::String::NewFromUtf8(isolate, name.c_str())); + error->Set( + v8::String::NewFromUtf8(isolate, "message"), + v8::String::NewFromUtf8(isolate, message.c_str())); + + return handle_scope.Escape(error); +} + +void KeyFunction(const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + int idx = info[0]->ToInt32()->Value(); + auto widget = WidgetPreferenceDB::GetInstance(); + std::string keyname; + if (widget->Key(idx, &keyname)) { + info.GetReturnValue().Set( + v8::String::NewFromUtf8(isolate, keyname.c_str())); + } else { + info.GetReturnValue().SetNull(); + } +} + +void GetItemFunction(const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + std::string key = *v8::String::Utf8Value(info[0]->ToString()); + auto widget = WidgetPreferenceDB::GetInstance(); + std::string valuestr; + if (widget->GetItem(key, &valuestr)) { + info.GetReturnValue().Set( + v8::String::NewFromUtf8(isolate, valuestr.c_str())); + } else { + info.GetReturnValue().SetNull(); + } +} + +void SetItemFunction(const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + std::string key = *v8::String::Utf8Value(info[0]->ToString()); + std::string value = *v8::String::Utf8Value(info[1]->ToString()); + auto widget = WidgetPreferenceDB::GetInstance(); + + v8::Local oldvalue = v8::Null(isolate); + std::string oldvaluestr; + if (widget->GetItem(key, &oldvaluestr)) { + oldvalue = v8::String::NewFromUtf8(isolate, oldvaluestr.c_str()); + } + + if (widget->SetItem(key, value)) { + DispatchEvent(info.This(), + info[0], + oldvalue, + info[1]); + } else { + info.GetReturnValue().Set(isolate->ThrowException(MakeException( + 7, "NoModificationAllowedError", "Read only data"))); + } +} + +void RemoveItemFunction(const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + std::string key = *v8::String::Utf8Value(info[0]->ToString()); + auto widget = WidgetPreferenceDB::GetInstance(); + + if (!widget->HasItem(key)) { + return; + } + + v8::Local oldvalue = v8::Null(isolate); + std::string oldvaluestr; + if (widget->GetItem(key, &oldvaluestr)) { + oldvalue = v8::String::NewFromUtf8(isolate, oldvaluestr.c_str()); + } + + if (widget->RemoveItem(key)) { + DispatchEvent(info.This(), + info[0], + oldvalue, + v8::Null(isolate)); + } else { + info.GetReturnValue().Set(isolate->ThrowException(MakeException( + 7, "NoModificationAllowedError", "Read only data"))); + } +} + +void ClearFunction(const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + auto widget = WidgetPreferenceDB::GetInstance(); + widget->Clear(); + DispatchEvent(info.This(), + v8::Null(isolate), + v8::Null(isolate), + v8::Null(isolate)); +} + +} // namespace + +WidgetModule::WidgetModule() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle + preference_object_template = v8::ObjectTemplate::New(); + + auto getter = []( + v8::Local property, + const v8::PropertyCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + auto widget = WidgetPreferenceDB::GetInstance(); + std::string key = *v8::String::Utf8Value(property); + + if (key == kLengthKey) { + info.GetReturnValue().Set(widget->Length()); + return; + } + + if (std::find(kExcludeList.begin(), kExcludeList.end(), key) + != kExcludeList.end()) { + return; + } + + if (!widget->HasItem(key)) { + return; + } + + std::string value; + if (widget->GetItem(key, &value)) { + info.GetReturnValue().Set( + v8::String::NewFromUtf8(isolate, value.c_str())); + } else { + info.GetReturnValue().SetNull(); + } + }; + + auto setter = []( + v8::Local property, + v8::Local value, + const v8::PropertyCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + auto widget = WidgetPreferenceDB::GetInstance(); + std::string key = *v8::String::Utf8Value(property); + std::string nvalue = *v8::String::Utf8Value(value->ToString()); + + if (std::find(kExcludeList.begin(), kExcludeList.end(), key) + != kExcludeList.end()) { + return; + } + + v8::Local oldvalue = v8::Null(isolate); + std::string oldvaluestr; + if (widget->GetItem(key, &oldvaluestr)) { + oldvalue = v8::String::NewFromUtf8(isolate, oldvaluestr.c_str()); + } + if (widget->SetItem(key, nvalue)) { + info.GetReturnValue().Set(value); + DispatchEvent(info.This(), + property, + oldvalue, + value); + } + }; + + auto deleter = []( + v8::Local property, + const v8::PropertyCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + auto widget = WidgetPreferenceDB::GetInstance(); + std::string key = *v8::String::Utf8Value(property); + if (!widget->HasItem(key)) { + info.GetReturnValue().Set(false); + return; + } + + v8::Local oldvalue = v8::Null(isolate); + std::string oldvaluestr; + if (widget->GetItem(key, &oldvaluestr)) { + oldvalue = v8::String::NewFromUtf8(isolate, oldvaluestr.c_str()); + } + + if (widget->RemoveItem(key)) { + info.GetReturnValue().Set(true); + DispatchEvent(info.This(), + property, + oldvalue, + v8::Null(isolate)); + } else { + info.GetReturnValue().Set(false); + } + }; + + preference_object_template->SetNamedPropertyHandler( + getter, + setter, + NULL, + deleter, + NULL); + + preference_object_template->Set( + v8::String::NewFromUtf8(isolate, kKeyKey), + v8::FunctionTemplate::New(isolate, KeyFunction)); + + preference_object_template->Set( + v8::String::NewFromUtf8(isolate, kGetItemKey), + v8::FunctionTemplate::New(isolate, GetItemFunction)); + + preference_object_template->Set( + v8::String::NewFromUtf8(isolate, kSetItemKey), + v8::FunctionTemplate::New(isolate, SetItemFunction)); + + preference_object_template->Set( + v8::String::NewFromUtf8(isolate, kRemoveItemKey), + v8::FunctionTemplate::New(isolate, RemoveItemFunction)); + + preference_object_template->Set( + v8::String::NewFromUtf8(isolate, kClearKey), + v8::FunctionTemplate::New(isolate, ClearFunction)); + + + preference_object_template_.Reset(isolate, preference_object_template); +} + +WidgetModule::~WidgetModule() { +} + +v8::Handle WidgetModule::NewInstance() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + + v8::Local widget = v8::Object::New(isolate); + v8::Handle object_template = + v8::Local::New(isolate, preference_object_template_); + + auto widgetdb = WidgetPreferenceDB::GetInstance(); + widgetdb->InitializeDB(); + + widget->Set( + v8::String::NewFromUtf8(isolate, "preference"), + object_template->NewInstance()); + + widget->Set( + v8::String::NewFromUtf8(isolate, "author"), + v8::String::NewFromUtf8(isolate, widgetdb->author().c_str())); + widget->Set( + v8::String::NewFromUtf8(isolate, "description"), + v8::String::NewFromUtf8(isolate, widgetdb->description().c_str())); + widget->Set( + v8::String::NewFromUtf8(isolate, "name"), + v8::String::NewFromUtf8(isolate, widgetdb->name().c_str())); + widget->Set( + v8::String::NewFromUtf8(isolate, "shortName"), + v8::String::NewFromUtf8(isolate, widgetdb->shortName().c_str())); + widget->Set( + v8::String::NewFromUtf8(isolate, "version"), + v8::String::NewFromUtf8(isolate, widgetdb->version().c_str())); + widget->Set( + v8::String::NewFromUtf8(isolate, "id"), + v8::String::NewFromUtf8(isolate, widgetdb->id().c_str())); + widget->Set( + v8::String::NewFromUtf8(isolate, "authorEmail"), + v8::String::NewFromUtf8(isolate, widgetdb->authorEmail().c_str())); + widget->Set( + v8::String::NewFromUtf8(isolate, "authorHref"), + v8::String::NewFromUtf8(isolate, widgetdb->authorHref().c_str())); + + return handle_scope.Escape(widget); +} + + +namespace { + const char* kDbInitedCheckKey = "__WRT_DB_INITED__"; + const char* kDBPublicSection = "public"; + const char* kDBPrivateSection = "private"; + const char* kReadOnlyPrefix = "_READONLY_KEY_"; +} // namespace + + +WidgetPreferenceDB* WidgetPreferenceDB::GetInstance() { + static WidgetPreferenceDB instance; + return &instance; +} + +WidgetPreferenceDB::WidgetPreferenceDB() + : appdata_(nullptr), + locale_manager_(nullptr) { +} +WidgetPreferenceDB::~WidgetPreferenceDB() { +} + +void WidgetPreferenceDB::Initialize( + const common::ApplicationData* appdata, + common::LocaleManager* locale_manager) { + appdata_ = appdata; + locale_manager_ = locale_manager; +} + +void WidgetPreferenceDB::InitializeDB() { + common::AppDB* db = common::AppDB::GetInstance(); + if (db->HasKey(kDBPrivateSection, kDbInitedCheckKey)) { + return; + } + if (appdata_->widget_info() == NULL) { + return; + } + + auto& preferences = appdata_->widget_info()->preferences(); + + for (const auto& pref : preferences) { + if (pref->Name().empty()) + continue; + + // check size limit + std::string key = pref->Name(); + std::string value = pref->Value(); + if (key.length() > kKeyLengthLimit) { + key.resize(kKeyLengthLimit); + } + + if (db->HasKey(kDBPublicSection, key)) + continue; + + // check size limit + if (value.length() > kValueLengthLimit) { + value.resize(kValueLengthLimit); + } + + db->Set(kDBPublicSection, + key, + value); + if (pref->ReadOnly()) { + db->Set(kDBPrivateSection, + kReadOnlyPrefix + key, "true"); + } + } + db->Set(kDBPrivateSection, kDbInitedCheckKey, "true"); +} + +int WidgetPreferenceDB::Length() { + common::AppDB* db = common::AppDB::GetInstance(); + std::list list; + db->GetKeys(kDBPublicSection, &list); + return list.size(); +} + +bool WidgetPreferenceDB::Key(int idx, std::string* key) { + common::AppDB* db = common::AppDB::GetInstance(); + std::list list; + db->GetKeys(kDBPublicSection, &list); + + auto it = list.begin(); + for ( ; it != list.end() && idx >= 0; ++it) { + if (idx == 0) { + *key = *it; + return true; + } + idx--; + } + return false; +} + +bool WidgetPreferenceDB::GetItem(const std::string& key, std::string* value) { + common::AppDB* db = common::AppDB::GetInstance(); + if (!db->HasKey(kDBPublicSection, key)) + return false; + *value = db->Get(kDBPublicSection, key); + return true; +} + +bool WidgetPreferenceDB::SetItem(const std::string& key, + const std::string& value) { + common::AppDB* db = common::AppDB::GetInstance(); + if (db->HasKey(kDBPrivateSection, kReadOnlyPrefix + key)) + return false; + db->Set(kDBPublicSection, key, value); + return true; +} + +bool WidgetPreferenceDB::RemoveItem(const std::string& key) { + common::AppDB* db = common::AppDB::GetInstance(); + if (!db->HasKey(kDBPublicSection, key)) + return false; + if (db->HasKey(kDBPrivateSection, kReadOnlyPrefix + key)) + return false; + db->Remove(kDBPublicSection, key); + return true; +} + +bool WidgetPreferenceDB::HasItem(const std::string& key) { + common::AppDB* db = common::AppDB::GetInstance(); + return db->HasKey(kDBPublicSection, key); +} + +void WidgetPreferenceDB::Clear() { + common::AppDB* db = common::AppDB::GetInstance(); + std::list list; + db->GetKeys(kDBPublicSection, &list); + auto it = list.begin(); + for ( ; it != list.end(); ++it) { + if (db->HasKey(kDBPrivateSection, kReadOnlyPrefix + *it)) + continue; + db->Remove(kDBPublicSection, *it); + } +} + +void WidgetPreferenceDB::GetKeys(std::list* keys) { + common::AppDB* db = common::AppDB::GetInstance(); + db->GetKeys(kDBPublicSection, keys); +} + +std::string WidgetPreferenceDB::author() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL) + return std::string(); + auto widget_info = appdata_->widget_info(); + return widget_info->author(); +} + +std::string WidgetPreferenceDB::description() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL || + locale_manager_ == NULL) + return std::string(); + auto widget_info = appdata_->widget_info(); + return locale_manager_->GetLocalizedString(widget_info->description_set()); +} + +std::string WidgetPreferenceDB::name() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL || + locale_manager_ == NULL) + return std::string(); + + auto widget_info = appdata_->widget_info(); + return locale_manager_->GetLocalizedString(widget_info->name_set()); +} + +std::string WidgetPreferenceDB::shortName() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL || + locale_manager_ == NULL) + return std::string(); + + auto widget_info = appdata_->widget_info(); + return locale_manager_->GetLocalizedString(widget_info->short_name_set()); +} + +std::string WidgetPreferenceDB::version() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL) + return std::string(); + auto widget_info = appdata_->widget_info(); + return widget_info->version(); +} + +std::string WidgetPreferenceDB::id() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL) + return std::string(); + auto widget_info = appdata_->widget_info(); + return widget_info->id(); +} + +std::string WidgetPreferenceDB::authorEmail() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL) + return std::string(); + auto widget_info = appdata_->widget_info(); + return widget_info->author_email(); +} + +std::string WidgetPreferenceDB::authorHref() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL) + return std::string(); + auto widget_info = appdata_->widget_info(); + return widget_info->author_href(); +} + +unsigned int WidgetPreferenceDB::height() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL) + return 0; + auto widget_info = appdata_->widget_info(); + return widget_info->height(); +} + +unsigned int WidgetPreferenceDB::width() { + if (appdata_ == NULL || + appdata_->widget_info() == NULL) + return 0; + auto widget_info = appdata_->widget_info(); + return widget_info->width(); +} + +} // namespace extensions diff --git a/tizen/extensions/renderer/widget_module.h b/tizen/extensions/renderer/widget_module.h new file mode 100644 index 0000000..36acec1 --- /dev/null +++ b/tizen/extensions/renderer/widget_module.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef XWALK_EXTENSIONS_RENDERER_WIDGET_MODULE_H_ +#define XWALK_EXTENSIONS_RENDERER_WIDGET_MODULE_H_ + +#include +#include + +#include "common/application_data.h" +#include "common/locale_manager.h" +#include "extensions/renderer/xwalk_module_system.h" + +namespace extensions { + +// This module provides widget object +class WidgetModule : public XWalkNativeModule { + public: + WidgetModule(); + ~WidgetModule() override; + + private: + v8::Handle NewInstance() override; + v8::Persistent preference_object_template_; +}; + +class WidgetPreferenceDB { + public: + static WidgetPreferenceDB* GetInstance(); + void Initialize(const common::ApplicationData* appdata, + common::LocaleManager* locale_manager); + void InitializeDB(); + int Length(); + bool Key(int idx, std::string* key); + bool GetItem(const std::string& key, std::string* value); + bool SetItem(const std::string& key, const std::string& value); + bool RemoveItem(const std::string& key); + bool HasItem(const std::string& key); + void Clear(); + void GetKeys(std::list* keys); + + std::string author(); + std::string description(); + std::string name(); + std::string shortName(); + std::string version(); + std::string id(); + std::string authorEmail(); + std::string authorHref(); + unsigned int height(); + unsigned int width(); + + private: + WidgetPreferenceDB(); + virtual ~WidgetPreferenceDB(); + const common::ApplicationData* appdata_; + common::LocaleManager* locale_manager_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_RENDERER_WIDGET_MODULE_H_ diff --git a/tizen/extensions/renderer/xwalk_extension_client.cc b/tizen/extensions/renderer/xwalk_extension_client.cc new file mode 100644 index 0000000..383473f --- /dev/null +++ b/tizen/extensions/renderer/xwalk_extension_client.cc @@ -0,0 +1,131 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/xwalk_extension_client.h" + +#include +#include +#include +#include + +#include + +#include "common/logger.h" +#include "common/profiler.h" +#include "common/string_utils.h" +#include "extensions/common/constants.h" +#include "extensions/common/xwalk_extension_server.h" +#include "extensions/renderer/runtime_ipc_client.h" + +namespace extensions { + +namespace { + void* CreateInstanceInMainloop(void* data) { + const char* extension_name = static_cast(data); + XWalkExtensionServer* server = XWalkExtensionServer::GetInstance(); + std::string instance_id = server->CreateInstance(extension_name); + return static_cast(new std::string(instance_id)); + } +} // namespace + +XWalkExtensionClient::XWalkExtensionClient() { +} + +XWalkExtensionClient::~XWalkExtensionClient() { + for (auto it = extension_apis_.begin(); it != extension_apis_.end(); ++it) { + delete it->second; + } + extension_apis_.clear(); +} + +void XWalkExtensionClient::Initialize() { + SCOPE_PROFILE(); + if (!extension_apis_.empty()) { + return; + } + + XWalkExtensionServer* server = XWalkExtensionServer::GetInstance(); + Json::Value reply = server->GetExtensions(); + for (auto it = reply.begin(); it != reply.end(); ++it) { + ExtensionCodePoints* codepoint = new ExtensionCodePoints; + Json::Value entry_points = (*it)["entry_points"]; + for (auto ep = entry_points.begin(); ep != entry_points.end(); ++ep) { + codepoint->entry_points.push_back((*ep).asString()); + } + std::string name = (*it)["name"].asString(); + extension_apis_[name] = codepoint; + } +} + +std::string XWalkExtensionClient::CreateInstance( + v8::Handle context, + const std::string& extension_name, InstanceHandler* handler) { + void* ret = ecore_main_loop_thread_safe_call_sync( + CreateInstanceInMainloop, + static_cast(const_cast(extension_name.data()))); + std::string* sp = static_cast(ret); + std::string instance_id = *sp; + delete sp; + + handlers_[instance_id] = handler; + return instance_id; +} + +void XWalkExtensionClient::DestroyInstance( + v8::Handle context, const std::string& instance_id) { + auto it = handlers_.find(instance_id); + if (it == handlers_.end()) { + LOGGER(WARN) << "Failed to destory invalid instance id: " << instance_id; + return; + } + RuntimeIPCClient* ipc = RuntimeIPCClient::GetInstance(); + ipc->SendMessage(context, kMethodDestroyInstance, instance_id, ""); + + handlers_.erase(it); +} + +void XWalkExtensionClient::PostMessageToNative( + v8::Handle context, + const std::string& instance_id, const std::string& msg) { + RuntimeIPCClient* ipc = RuntimeIPCClient::GetInstance(); + ipc->SendMessage(context, kMethodPostMessage, instance_id, msg); +} + +std::string XWalkExtensionClient::SendSyncMessageToNative( + v8::Handle context, + const std::string& instance_id, const std::string& msg) { + RuntimeIPCClient* ipc = RuntimeIPCClient::GetInstance(); + std::string reply = + ipc->SendSyncMessage(context, kMethodSendSyncMessage, instance_id, msg); + return reply; +} + +std::string XWalkExtensionClient::GetAPIScript( + v8::Handle context, + const std::string& extension_name) { + XWalkExtensionServer* server = XWalkExtensionServer::GetInstance(); + return server->GetAPIScript(extension_name); +} + +void XWalkExtensionClient::OnReceivedIPCMessage( + const std::string& instance_id, const std::string& msg) { + auto it = handlers_.find(instance_id); + if (it == handlers_.end()) { + LOGGER(WARN) << "Failed to post the message. Invalid instance id."; + return; + } + + if (!it->second) + return; + + it->second->HandleMessageFromNative(msg); +} + +void XWalkExtensionClient::LoadUserExtensions(const std::string app_path) { + XWalkExtensionServer* server = XWalkExtensionServer::GetInstance(); + server->LoadUserExtensions(app_path); +} + +} // namespace extensions diff --git a/tizen/extensions/renderer/xwalk_extension_client.h b/tizen/extensions/renderer/xwalk_extension_client.h new file mode 100644 index 0000000..5b98ee9 --- /dev/null +++ b/tizen/extensions/renderer/xwalk_extension_client.h @@ -0,0 +1,71 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_CLIENT_H_ +#define XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_CLIENT_H_ + +#include + +#include +#include +#include +#include + +#include "extensions/renderer/xwalk_module_system.h" + +namespace extensions { + +class XWalkExtensionClient { + public: + struct InstanceHandler { + virtual void HandleMessageFromNative(const std::string& msg) = 0; + protected: + ~InstanceHandler() {} + }; + + XWalkExtensionClient(); + virtual ~XWalkExtensionClient(); + + void Initialize(); + + std::string CreateInstance(v8::Handle context, + const std::string& extension_name, + InstanceHandler* handler); + void DestroyInstance(v8::Handle context, + const std::string& instance_id); + + void PostMessageToNative(v8::Handle context, + const std::string& instance_id, + const std::string& msg); + std::string SendSyncMessageToNative(v8::Handle context, + const std::string& instance_id, + const std::string& msg); + + std::string GetAPIScript(v8::Handle context, + const std::string& extension_name); + + void OnReceivedIPCMessage(const std::string& instance_id, + const std::string& msg); + void LoadUserExtensions(const std::string app_path); + + struct ExtensionCodePoints { + std::string api; + std::vector entry_points; + }; + + typedef std::map ExtensionAPIMap; + + const ExtensionAPIMap& extension_apis() const { return extension_apis_; } + + private: + ExtensionAPIMap extension_apis_; + + typedef std::map HandlerMap; + HandlerMap handlers_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_CLIENT_H_ diff --git a/tizen/extensions/renderer/xwalk_extension_module.cc b/tizen/extensions/renderer/xwalk_extension_module.cc new file mode 100644 index 0000000..c222556 --- /dev/null +++ b/tizen/extensions/renderer/xwalk_extension_module.cc @@ -0,0 +1,514 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/xwalk_extension_module.h" + +#include +#include +#include + +#include + +#include "common/arraysize.h" +#include "common/logger.h" +#include "common/profiler.h" +#include "extensions/renderer/runtime_ipc_client.h" +#include "extensions/renderer/xwalk_extension_client.h" +#include "extensions/renderer/xwalk_module_system.h" + +namespace extensions { + +namespace { + +// This is the key used in the data object passed to our callbacks to store a +// pointer back to kXWalkExtensionModule. +const char* kXWalkExtensionModule = "kXWalkExtensionModule"; + +} // namespace + +XWalkExtensionModule::XWalkExtensionModule(XWalkExtensionClient* client, + XWalkModuleSystem* module_system, + const std::string& extension_name, + const std::string& extension_code) + : extension_name_(extension_name), + extension_code_(extension_code), + client_(client), + module_system_(module_system), + instance_id_("") { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle function_data = v8::Object::New(isolate); + function_data->Set(v8::String::NewFromUtf8(isolate, kXWalkExtensionModule), + v8::External::New(isolate, this)); + + v8::Handle object_template = + v8::ObjectTemplate::New(isolate); + // TODO(cmarcelo): Use Template::Set() function that takes isolate, once we + // update the Chromium (and V8) version. + object_template->Set( + v8::String::NewFromUtf8(isolate, "postMessage"), + v8::FunctionTemplate::New(isolate, PostMessageCallback, function_data)); + object_template->Set( + v8::String::NewFromUtf8(isolate, "sendSyncMessage"), + v8::FunctionTemplate::New( + isolate, SendSyncMessageCallback, function_data)); + object_template->Set( + v8::String::NewFromUtf8(isolate, "setMessageListener"), + v8::FunctionTemplate::New( + isolate, SetMessageListenerCallback, function_data)); + object_template->Set( + v8::String::NewFromUtf8(isolate, "sendRuntimeMessage"), + v8::FunctionTemplate::New( + isolate, SendRuntimeMessageCallback, function_data)); + object_template->Set( + v8::String::NewFromUtf8(isolate, "sendRuntimeSyncMessage"), + v8::FunctionTemplate::New( + isolate, SendRuntimeSyncMessageCallback, function_data)); + object_template->Set( + v8::String::NewFromUtf8(isolate, "sendRuntimeAsyncMessage"), + v8::FunctionTemplate::New( + isolate, SendRuntimeAsyncMessageCallback, function_data)); + + function_data_.Reset(isolate, function_data); + object_template_.Reset(isolate, object_template); +} + +XWalkExtensionModule::~XWalkExtensionModule() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + + // Deleting the data will disable the functions, they'll return early. We do + // this because it might be the case that the JS objects we created outlive + // this object (getting references from inside an iframe and then destroying + // the iframe), even if we destroy the references we have. + v8::Handle function_data = + v8::Local::New(isolate, function_data_); + function_data->Delete(v8::String::NewFromUtf8(isolate, + kXWalkExtensionModule)); + + object_template_.Reset(); + function_data_.Reset(); + message_listener_.Reset(); + + if (!instance_id_.empty()) + client_->DestroyInstance(module_system_->GetV8Context(), instance_id_); +} + +namespace { + +std::string CodeToEnsureNamespace(const std::string& extension_name) { + std::string result; + size_t pos = 0; + while (true) { + pos = extension_name.find('.', pos); + if (pos == std::string::npos) { + result += extension_name + " = {};"; + break; + } + std::string ns = extension_name.substr(0, pos); + result += ns + " = " + ns + " || {}; "; + pos++; + } + return result; +} + +// Templatized backend for StringPrintF/StringAppendF. This does not finalize +// the va_list, the caller is expected to do that. +template +static void StringAppendVT(StringType* dst, + const typename StringType::value_type* format, + va_list ap) { + // First try with a small fixed size buffer. + // This buffer size should be kept in sync with StringUtilTest.GrowBoundary + // and StringUtilTest.StringPrintfBounds. + typename StringType::value_type stack_buf[1024]; + + va_list ap_copy; + va_copy(ap_copy, ap); + + int result = vsnprintf(stack_buf, ARRAYSIZE(stack_buf), format, ap_copy); + va_end(ap_copy); + + if (result >= 0 && result < static_cast(ARRAYSIZE(stack_buf))) { + // It fit. + dst->append(stack_buf, result); + return; + } + + // Repeatedly increase buffer size until it fits. + int mem_length = ARRAYSIZE(stack_buf); + while (true) { + if (result < 0) { + if (errno != 0 && errno != EOVERFLOW) + return; + // Try doubling the buffer size. + mem_length *= 2; + } else { + // We need exactly "result + 1" characters. + mem_length = result + 1; + } + + if (mem_length > 32 * 1024 * 1024) { + // That should be plenty, don't try anything larger. This protects + // against huge allocations when using vsnprintfT implementations that + // return -1 for reasons other than overflow without setting errno. + LOGE("Unable to printf the requested string due to size."); + return; + } + + std::vector mem_buf(mem_length); + + // NOTE: You can only use a va_list once. Since we're in a while loop, we + // need to make a new copy each time so we don't use up the original. + va_copy(ap_copy, ap); + result = vsnprintf(&mem_buf[0], mem_length, format, ap_copy); + va_end(ap_copy); + + if ((result >= 0) && (result < mem_length)) { + // It fit. + dst->append(&mem_buf[0], result); + return; + } + } +} + +std::string StringPrintf(const char* format, ...) { + va_list ap; + va_start(ap, format); + std::string result; + StringAppendVT(&result, format, ap); + va_end(ap); + return result; +} + +// Wrap API code into a callable form that takes extension object as parameter. +std::string WrapAPICode(const std::string& extension_code, + const std::string& extension_name) { + // We take care here to make sure that line numbering for api_code after + // wrapping doesn't change, so that syntax errors point to the correct line. + + return StringPrintf( + "var %s; (function(extension, requireNative) { " + "extension.internal = {};" + "extension.internal.sendSyncMessage = extension.sendSyncMessage;" + "delete extension.sendSyncMessage;" + "var Object = requireNative('objecttools');" + "var exports = {}; (function() {'use strict'; %s\n})();" + "%s = exports; });", + CodeToEnsureNamespace(extension_name).c_str(), + extension_code.c_str(), + extension_name.c_str()); +} + +std::string ExceptionToString(const v8::TryCatch& try_catch) { + std::string str; + v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); + v8::String::Utf8Value exception(try_catch.Exception()); + v8::Local message(try_catch.Message()); + if (message.IsEmpty()) { + str.append(StringPrintf("%s\n", *exception)); + } else { + v8::String::Utf8Value filename(message->GetScriptResourceName()); + int linenum = message->GetLineNumber(); + int colnum = message->GetStartColumn(); + str.append(StringPrintf( + "%s:%i:%i %s\n", *filename, linenum, colnum, *exception)); + v8::String::Utf8Value sourceline(message->GetSourceLine()); + str.append(StringPrintf("%s\n", *sourceline)); + } + return str; +} + +v8::Handle RunString(const std::string& code, + std::string* exception) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + v8::Handle v8_code( + v8::String::NewFromUtf8(isolate, code.c_str())); + + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + + v8::Handle script(v8::Script::Compile(v8_code)); + if (try_catch.HasCaught()) { + *exception = ExceptionToString(try_catch); + return handle_scope.Escape( + v8::Local(v8::Undefined(isolate))); + } + + v8::Local result = script->Run(); + if (try_catch.HasCaught()) { + *exception = ExceptionToString(try_catch); + return handle_scope.Escape( + v8::Local(v8::Undefined(isolate))); + } + + return handle_scope.Escape(result); +} + +} // namespace + +void XWalkExtensionModule::LoadExtensionCode( + v8::Handle context, v8::Handle require_native) { + instance_id_ = client_->CreateInstance(context, extension_name_, this); + if (instance_id_.empty()) { + LOGGER(ERROR) << "Failed to create an instance of " << extension_name_; + return; + } + + if (extension_code_.empty()) { + extension_code_ = client_->GetAPIScript(context, extension_name_); + if (extension_code_.empty()) { + LOGGER(ERROR) << "Failed to get API script of " << extension_name_; + return; + } + } + + std::string wrapped_api_code = WrapAPICode(extension_code_, extension_name_); + + std::string exception; + v8::Handle result = RunString(wrapped_api_code, &exception); + + if (!result->IsFunction()) { + LOGGER(ERROR) << "Couldn't load JS API code for " + << extension_name_ << " : " << exception; + return; + } + v8::Handle callable_api_code = + v8::Handle::Cast(result); + v8::Handle object_template = + v8::Local::New(context->GetIsolate(), + object_template_); + + const int argc = 2; + v8::Handle argv[argc] = { + object_template->NewInstance(), + require_native + }; + + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + callable_api_code->Call(context->Global(), argc, argv); + if (try_catch.HasCaught()) { + LOGGER(ERROR) << "Exception while loading JS API code for " + << extension_name_ << " : " << ExceptionToString(try_catch); + } +} + +void XWalkExtensionModule::HandleMessageFromNative(const std::string& msg) { + if (message_listener_.IsEmpty()) + return; + + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle context = module_system_->GetV8Context(); + v8::Context::Scope context_scope(context); + + v8::Handle args[] = { + v8::String::NewFromUtf8(isolate, msg.c_str()) }; + + v8::Handle message_listener = + v8::Local::New(isolate, message_listener_); + + v8::TryCatch try_catch; + message_listener->Call(context->Global(), 1, args); + if (try_catch.HasCaught()) + LOGGER(ERROR) << "Exception when running message listener: " + << ExceptionToString(try_catch); +} + +// static +void XWalkExtensionModule::PostMessageCallback( + const v8::FunctionCallbackInfo& info) { + v8::ReturnValue result(info.GetReturnValue()); + XWalkExtensionModule* module = GetExtensionModule(info); + if (!module || info.Length() != 1) { + result.Set(false); + return; + } + + v8::String::Utf8Value value(info[0]->ToString()); + + // CHECK(module->instance_id_); + module->client_->PostMessageToNative(module->module_system_->GetV8Context(), + module->instance_id_, + std::string(*value)); + result.Set(true); +} + +// static +void XWalkExtensionModule::SendSyncMessageCallback( + const v8::FunctionCallbackInfo& info) { + v8::ReturnValue result(info.GetReturnValue()); + XWalkExtensionModule* module = GetExtensionModule(info); + if (!module || info.Length() != 1) { + result.Set(false); + return; + } + + v8::String::Utf8Value value(info[0]->ToString()); + + // CHECK(module->instance_id_); + std::string reply = + module->client_->SendSyncMessageToNative( + module->module_system_->GetV8Context(), + module->instance_id_, + std::string(*value)); + + // If we tried to send a message to an instance that became invalid, + // then reply will be NULL. + if (!reply.empty()) { + result.Set(v8::String::NewFromUtf8(info.GetIsolate(), reply.c_str())); + } +} + +// static +void XWalkExtensionModule::SetMessageListenerCallback( + const v8::FunctionCallbackInfo& info) { + v8::ReturnValue result(info.GetReturnValue()); + XWalkExtensionModule* module = GetExtensionModule(info); + if (!module || info.Length() != 1) { + result.Set(false); + return; + } + + if (!info[0]->IsFunction() && !info[0]->IsUndefined()) { + LOGGER(ERROR) << "Trying to set message listener with invalid value."; + result.Set(false); + return; + } + + v8::Isolate* isolate = info.GetIsolate(); + if (info[0]->IsUndefined()) + module->message_listener_.Reset(); + else + module->message_listener_.Reset(isolate, info[0].As()); + + result.Set(true); +} + +// static +void XWalkExtensionModule::SendRuntimeMessageCallback( + const v8::FunctionCallbackInfo& info) { + v8::ReturnValue result(info.GetReturnValue()); + XWalkExtensionModule* module = GetExtensionModule(info); + if (!module || info.Length() < 1) { + result.Set(false); + return; + } + + v8::String::Utf8Value type(info[0]->ToString()); + std::string data_str; + if (info.Length() > 1) { + v8::String::Utf8Value data(info[1]->ToString()); + data_str = std::string(*data); + } + + RuntimeIPCClient* rc = RuntimeIPCClient::GetInstance(); + rc->SendMessage(module->module_system_->GetV8Context(), + std::string(*type), data_str); + + result.Set(true); +} + +// static +void XWalkExtensionModule::SendRuntimeSyncMessageCallback( + const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + + v8::ReturnValue result(info.GetReturnValue()); + XWalkExtensionModule* module = GetExtensionModule(info); + if (!module || info.Length() < 1) { + result.SetUndefined(); + return; + } + + v8::String::Utf8Value type(info[0]->ToString()); + std::string data_str; + if (info.Length() > 1) { + v8::String::Utf8Value data(info[1]->ToString()); + data_str = std::string(*data); + } + + RuntimeIPCClient* rc = RuntimeIPCClient::GetInstance(); + std::string reply = rc->SendSyncMessage( + module->module_system_->GetV8Context(), + std::string(*type), data_str); + + result.Set(v8::String::NewFromUtf8(isolate, reply.c_str())); +} + +// static +void XWalkExtensionModule::SendRuntimeAsyncMessageCallback( + const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::HandleScope handle_scope(isolate); + + v8::ReturnValue result(info.GetReturnValue()); + XWalkExtensionModule* module = GetExtensionModule(info); + if (!module || info.Length() < 1) { + result.Set(false); + return; + } + + // type + v8::String::Utf8Value type(info[0]->ToString()); + + // value + std::string value_str; + if (info.Length() > 1) { + v8::String::Utf8Value value(info[1]->ToString()); + value_str = std::string(*value); + } + + // callback + RuntimeIPCClient::JSCallback* js_callback = NULL; + if (info.Length() > 2) { + if (info[2]->IsFunction()) { + v8::Handle func = info[2].As(); + js_callback = new RuntimeIPCClient::JSCallback(isolate, func); + } + } + + auto callback = [js_callback](const std::string& /*type*/, + const std::string& value) -> void { + if (!js_callback) { + LOGGER(ERROR) << "JsCallback is NULL."; + return; + } + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle args[] = { + v8::String::NewFromUtf8(isolate, value.c_str()) }; + js_callback->Call(isolate, args); + delete js_callback; + }; + + RuntimeIPCClient* rc = RuntimeIPCClient::GetInstance(); + rc->SendAsyncMessage(module->module_system_->GetV8Context(), + std::string(*type), value_str, callback); + + result.Set(true); +} + +// static +XWalkExtensionModule* XWalkExtensionModule::GetExtensionModule( + const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::HandleScope handle_scope(isolate); + + v8::Local data = info.Data().As(); + v8::Local module = + data->Get(v8::String::NewFromUtf8(isolate, kXWalkExtensionModule)); + if (module.IsEmpty() || module->IsUndefined()) { + LOGGER(ERROR) << "Trying to use extension from already destroyed context!"; + return NULL; + } + // CHECK(module->IsExternal()); + return static_cast(module.As()->Value()); +} + +} // namespace extensions diff --git a/tizen/extensions/renderer/xwalk_extension_module.h b/tizen/extensions/renderer/xwalk_extension_module.h new file mode 100644 index 0000000..1076f0f --- /dev/null +++ b/tizen/extensions/renderer/xwalk_extension_module.h @@ -0,0 +1,84 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_MODULE_H_ +#define XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_MODULE_H_ + +#include + +#include +#include + +#include "extensions/renderer/xwalk_extension_client.h" + +namespace extensions { + +class XWalkModuleSystem; + +// Responsible for running the JS code of a Extension. This includes +// creating and exposing an 'extension' object for the execution context of +// the extension JS code. +// +// We'll create one XWalkExtensionModule per extension/frame pair, so +// there'll be a set of different modules per v8::Context. +class XWalkExtensionModule : public XWalkExtensionClient::InstanceHandler { + public: + XWalkExtensionModule(XWalkExtensionClient* client, + XWalkModuleSystem* module_system, + const std::string& extension_name, + const std::string& extension_code); + virtual ~XWalkExtensionModule(); + + // TODO(cmarcelo): Make this return a v8::Handle, and + // let the module system set it to the appropriated object. + void LoadExtensionCode(v8::Handle context, + v8::Handle require_native); + + std::string extension_name() const { return extension_name_; } + + private: + // ExtensionClient::InstanceHandler implementation. + virtual void HandleMessageFromNative(const std::string& msg); + + // Callbacks for JS functions available in 'extension' object. + static void PostMessageCallback( + const v8::FunctionCallbackInfo& info); + static void SendSyncMessageCallback( + const v8::FunctionCallbackInfo& info); + static void SetMessageListenerCallback( + const v8::FunctionCallbackInfo& info); + static void SendRuntimeMessageCallback( + const v8::FunctionCallbackInfo& info); + static void SendRuntimeSyncMessageCallback( + const v8::FunctionCallbackInfo& info); + static void SendRuntimeAsyncMessageCallback( + const v8::FunctionCallbackInfo& info); + + static XWalkExtensionModule* GetExtensionModule( + const v8::FunctionCallbackInfo& info); + + // Template for the 'extension' object exposed to the extension JS code. + v8::Persistent object_template_; + + // This JS object contains a pointer back to the ExtensionModule, it is + // set as data for the function callbacks. + v8::Persistent function_data_; + + // Function to be called when the extension sends a message to its JS code. + // This value is registered by using 'extension.setMessageListener()'. + v8::Persistent message_listener_; + + std::string extension_name_; + std::string extension_code_; + + XWalkExtensionClient* client_; + XWalkModuleSystem* module_system_; + std::string instance_id_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_MODULE_H_ diff --git a/tizen/extensions/renderer/xwalk_extension_renderer_controller.cc b/tizen/extensions/renderer/xwalk_extension_renderer_controller.cc new file mode 100644 index 0000000..6c8dd11 --- /dev/null +++ b/tizen/extensions/renderer/xwalk_extension_renderer_controller.cc @@ -0,0 +1,132 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/xwalk_extension_renderer_controller.h" + +#include +#include +#include +#include + +#include "common/logger.h" +#include "common/profiler.h" +#include "extensions/renderer/object_tools_module.h" +#include "extensions/renderer/widget_module.h" +#include "extensions/renderer/xwalk_extension_client.h" +#include "extensions/renderer/xwalk_extension_module.h" +#include "extensions/renderer/xwalk_module_system.h" +#include "extensions/renderer/xwalk_v8tools_module.h" +#include "extensions/renderer/runtime_ipc_client.h" + +namespace extensions { + +// static +int XWalkExtensionRendererController::plugin_session_count = 0; + +namespace { + +void CreateExtensionModules(XWalkExtensionClient* client, + XWalkModuleSystem* module_system) { + const XWalkExtensionClient::ExtensionAPIMap& extensions = + client->extension_apis(); + + for (auto it = extensions.begin(); it != extensions.end(); ++it) { + XWalkExtensionClient::ExtensionCodePoints* codepoint = it->second; + std::unique_ptr module( + new XWalkExtensionModule(client, module_system, + it->first, codepoint->api)); + module_system->RegisterExtensionModule(std::move(module), + codepoint->entry_points); + } +} + +} // namespace + +XWalkExtensionRendererController& +XWalkExtensionRendererController::GetInstance() { + static XWalkExtensionRendererController instance; + return instance; +} + +XWalkExtensionRendererController::XWalkExtensionRendererController() + : exit_requested(false), + extensions_client_(new XWalkExtensionClient()) { +} + +XWalkExtensionRendererController::~XWalkExtensionRendererController() { +} + +void XWalkExtensionRendererController::DidCreateScriptContext( + v8::Handle context) { + SCOPE_PROFILE(); + + // Skip plugin loading after application exit request. + if (exit_requested) { + return; + } + + XWalkModuleSystem* module_system = new XWalkModuleSystem(context); + XWalkModuleSystem::SetModuleSystemInContext( + std::unique_ptr(module_system), context); + module_system->RegisterNativeModule( + "v8tools", + std::unique_ptr(new XWalkV8ToolsModule)); + module_system->RegisterNativeModule( + "WidgetModule", + std::unique_ptr(new WidgetModule)); + module_system->RegisterNativeModule( + "objecttools", + std::unique_ptr(new ObjectToolsModule)); + + extensions_client_->Initialize(); + CreateExtensionModules(extensions_client_.get(), module_system); + + module_system->Initialize(); + plugin_session_count++; + LOGGER(DEBUG) << "plugin_session_count : " << plugin_session_count; +} + +void XWalkExtensionRendererController::WillReleaseScriptContext( + v8::Handle context) { + v8::Context::Scope contextScope(context); + XWalkModuleSystem* module_system = XWalkModuleSystem::GetModuleSystemFromContext(context); + if (module_system) { + plugin_session_count--; + LOGGER(DEBUG) << "plugin_session_count : " << plugin_session_count; + } + XWalkModuleSystem::ResetModuleSystemFromContext(context); +} + +void XWalkExtensionRendererController::OnReceivedIPCMessage( + const Ewk_IPC_Wrt_Message_Data* data) { + + Eina_Stringshare* type = ewk_ipc_wrt_message_data_type_get(data); + +#define TYPE_BEGIN(x) (!strncmp(type, x, strlen(x))) + if (TYPE_BEGIN("xwalk://")) { + Eina_Stringshare* id = ewk_ipc_wrt_message_data_id_get(data); + Eina_Stringshare* msg = ewk_ipc_wrt_message_data_value_get(data); + extensions_client_->OnReceivedIPCMessage(id, msg); + eina_stringshare_del(id); + eina_stringshare_del(msg); + } else { + RuntimeIPCClient* ipc = RuntimeIPCClient::GetInstance(); + ipc->HandleMessageFromRuntime(data); + } +#undef TYPE_BEGIN + + eina_stringshare_del(type); +} + +void XWalkExtensionRendererController::InitializeExtensionClient() { + extensions_client_->Initialize(); +} + +void XWalkExtensionRendererController::LoadUserExtensions( + const std::string app_path) { + extensions_client_->LoadUserExtensions(app_path); +} + +} // namespace extensions diff --git a/tizen/extensions/renderer/xwalk_extension_renderer_controller.h b/tizen/extensions/renderer/xwalk_extension_renderer_controller.h new file mode 100644 index 0000000..95e3145 --- /dev/null +++ b/tizen/extensions/renderer/xwalk_extension_renderer_controller.h @@ -0,0 +1,45 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_RENDERER_CONTROLLER_H_ +#define XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_RENDERER_CONTROLLER_H_ + +#include +#include +#include + +#include +#include + +namespace extensions { + +class XWalkExtensionClient; + +class XWalkExtensionRendererController { + public: + static XWalkExtensionRendererController& GetInstance(); + static int plugin_session_count; + + void DidCreateScriptContext(v8::Handle context); + void WillReleaseScriptContext(v8::Handle context); + + void OnReceivedIPCMessage(const Ewk_IPC_Wrt_Message_Data* data); + + void InitializeExtensionClient(); + void LoadUserExtensions(const std::string app_path); + + bool exit_requested; + + private: + XWalkExtensionRendererController(); + virtual ~XWalkExtensionRendererController(); + + private: + std::unique_ptr extensions_client_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_RENDERER_XWALK_EXTENSION_RENDERER_CONTROLLER_H_ diff --git a/tizen/extensions/renderer/xwalk_module_system.cc b/tizen/extensions/renderer/xwalk_module_system.cc new file mode 100644 index 0000000..2218188 --- /dev/null +++ b/tizen/extensions/renderer/xwalk_module_system.cc @@ -0,0 +1,524 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/xwalk_module_system.h" + +#include + +#include + +#include "common/logger.h" +#include "common/profiler.h" +#include "extensions/renderer/xwalk_extension_module.h" + +namespace extensions { + +namespace { + +// Index used to set embedder data into v8::Context, so we can get from a +// context to its corresponding module. Index chosen to not conflict with +// WebCore::V8ContextEmbedderDataField in V8PerContextData.h. +const int kModuleSystemEmbedderDataIndex = 8; + +// This is the key used in the data object passed to our callbacks to store a +// pointer back to XWalkExtensionModule. +const char* kXWalkModuleSystem = "kXWalkModuleSystem"; + +void RequireNativeCallback(const v8::FunctionCallbackInfo& info) { + v8::ReturnValue result(info.GetReturnValue()); + + v8::Isolate* isolate = info.GetIsolate(); + v8::HandleScope handle_scope(isolate); + + v8::Handle data = info.Data().As(); + v8::Handle module_system_value = + data->Get(v8::String::NewFromUtf8(isolate, kXWalkModuleSystem)); + if (module_system_value.IsEmpty() || module_system_value->IsUndefined()) { + LOGGER(ERROR) << "Trying to use requireNative from already " + << "destroyed module system!"; + result.SetUndefined(); + return; + } + + XWalkModuleSystem* module_system = static_cast( + module_system_value.As()->Value()); + + if (info.Length() < 1) { + // TODO(cmarcelo): Throw appropriate exception or warning. + result.SetUndefined(); + return; + } + if (!module_system) { + result.SetUndefined(); + return; + } + v8::Handle object = + module_system->RequireNative(*v8::String::Utf8Value(info[0])); + if (object.IsEmpty()) { + // TODO(cmarcelo): Throw appropriate exception or warning. + result.SetUndefined(); + return; + } + result.Set(object); +} + +} // namespace + +XWalkModuleSystem::XWalkModuleSystem(v8::Handle context) { + v8::Isolate* isolate = context->GetIsolate(); + v8_context_.Reset(isolate, context); + + v8::HandleScope handle_scope(isolate); + v8::Handle function_data = v8::Object::New(isolate); + function_data->Set(v8::String::NewFromUtf8(isolate, kXWalkModuleSystem), + v8::External::New(isolate, this)); + v8::Handle require_native_template = + v8::FunctionTemplate::New(isolate, RequireNativeCallback, function_data); + + function_data_.Reset(isolate, function_data); + require_native_template_.Reset(isolate, require_native_template); +} + +XWalkModuleSystem::~XWalkModuleSystem() { + DeleteExtensionModules(); + auto it = native_modules_.begin(); + for ( ; it != native_modules_.end(); ++it) { + delete it->second; + } + native_modules_.clear(); + + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + + require_native_template_.Reset(); + function_data_.Reset(); + v8_context_.Reset(); +} + +// static +XWalkModuleSystem* XWalkModuleSystem::GetModuleSystemFromContext( + v8::Handle context) { + return reinterpret_cast( + context->GetAlignedPointerFromEmbedderData( + kModuleSystemEmbedderDataIndex)); +} + +// static +void XWalkModuleSystem::SetModuleSystemInContext( + std::unique_ptr module_system, + v8::Handle context) { + context->SetAlignedPointerInEmbedderData(kModuleSystemEmbedderDataIndex, + module_system.release()); +} + +// static +void XWalkModuleSystem::ResetModuleSystemFromContext( + v8::Handle context) { + XWalkModuleSystem* module_system = GetModuleSystemFromContext(context); + if (module_system) { + delete module_system; + SetModuleSystemInContext(std::unique_ptr(), context); + } +} + +void XWalkModuleSystem::RegisterExtensionModule( + std::unique_ptr module, + const std::vector& entry_points) { + const std::string& extension_name = module->extension_name(); + if (ContainsEntryPoint(extension_name)) { + LOGGER(ERROR) << "Can't register Extension Module named for extension '" + << extension_name << "' in the Module System because name " + << " was already registered."; + return; + } + + std::vector::const_iterator it = entry_points.begin(); + for (; it != entry_points.end(); ++it) { + if (ContainsEntryPoint(*it)) { + LOGGER(ERROR) << "Can't register Extension Module named for extension '" + << extension_name << "' in the Module System because " + << "another extension has the entry point '" + << (*it) << "'."; + return; + } + } + + extension_modules_.push_back( + ExtensionModuleEntry(extension_name, module.release(), entry_points)); +} + +void XWalkModuleSystem::RegisterNativeModule( + const std::string& name, std::unique_ptr module) { + if (native_modules_.find(name) != native_modules_.end()) { + return; + } + native_modules_[name] = module.release(); +} + + +namespace { + +v8::Handle EnsureTargetObjectForTrampoline( + v8::Handle context, const std::vector& path, + std::string* error) { + v8::Handle object = context->Global(); + v8::Isolate* isolate = context->GetIsolate(); + + std::vector::const_iterator it = path.begin(); + for (; it != path.end(); ++it) { + v8::Handle part = + v8::String::NewFromUtf8(isolate, it->c_str()); + v8::Handle value = object->Get(part); + + if (value->IsUndefined()) { + v8::Handle next_object = v8::Object::New(isolate); + object->Set(part, next_object); + object = next_object; + continue; + } + + if (!value->IsObject()) { + *error = "the property '" + *it + "' in the path is undefined"; + return v8::Undefined(isolate); + } + + object = value.As(); + } + return object; +} + +v8::Handle GetObjectForPath(v8::Handle context, + const std::vector& path, + std::string* error) { + v8::Handle object = context->Global(); + v8::Isolate* isolate = context->GetIsolate(); + + std::vector::const_iterator it = path.begin(); + for (; it != path.end(); ++it) { + v8::Handle part = + v8::String::NewFromUtf8(isolate, it->c_str()); + v8::Handle value = object->Get(part); + + if (!value->IsObject()) { + *error = "the property '" + *it + "' in the path is undefined"; + return v8::Undefined(isolate); + } + + object = value.As(); + } + return object; +} + +} // namespace + +template +void SplitString(const STR& str, const typename STR::value_type s, + std::vector* r) { + r->clear(); + size_t last = 0; + size_t c = str.size(); + for (size_t i = 0; i <= c; ++i) { + if (i == c || str[i] == s) { + STR tmp(str, last, i - last); + if (i != c || !r->empty() || !tmp.empty()) + r->push_back(tmp); + last = i + 1; + } + } +} + +bool XWalkModuleSystem::SetTrampolineAccessorForEntryPoint( + v8::Handle context, + const std::string& entry_point, + v8::Local user_data) { + std::vector path; + SplitString(entry_point, '.', &path); + std::string basename = path.back(); + path.pop_back(); + + std::string error; + v8::Handle value = + EnsureTargetObjectForTrampoline(context, path, &error); + if (value->IsUndefined()) { + LOGGER(ERROR) << "Error installing trampoline for " << entry_point + << " : " << error; + return false; + } + + v8::Isolate* isolate = context->GetIsolate(); + v8::Local params = v8::Array::New(isolate); + v8::Local entry = + v8::String::NewFromUtf8(isolate, entry_point.c_str()); + params->Set(v8::Integer::New(isolate, 0), user_data); + params->Set(v8::Integer::New(isolate, 1), entry); + + // FIXME(cmarcelo): ensure that trampoline is readonly. + value.As()->SetAccessor(context, + v8::String::NewFromUtf8(isolate, basename.c_str()), + TrampolineCallback, TrampolineSetterCallback, params); + return true; +} + +// static +bool XWalkModuleSystem::DeleteAccessorForEntryPoint( + v8::Handle context, + const std::string& entry_point) { + std::vector path; + SplitString(entry_point, '.', &path); + std::string basename = path.back(); + path.pop_back(); + + std::string error; + v8::Handle value = GetObjectForPath(context, path, &error); + if (value->IsUndefined()) { + LOGGER(ERROR) << "Error retrieving object for " << entry_point + << " : " << error; + return false; + } + + value.As()->Delete( + v8::String::NewFromUtf8(context->GetIsolate(), basename.c_str())); + return true; +} + +bool XWalkModuleSystem::InstallTrampoline(v8::Handle context, + ExtensionModuleEntry* entry) { + v8::Local entry_ptr = + v8::External::New(context->GetIsolate(), entry); + bool ret = SetTrampolineAccessorForEntryPoint(context, entry->name, + entry_ptr); + if (!ret) { + LOGGER(ERROR) << "Error installing trampoline for " << entry->name; + return false; + } + + std::vector::const_iterator it = entry->entry_points.begin(); + for (; it != entry->entry_points.end(); ++it) { + ret = SetTrampolineAccessorForEntryPoint(context, *it, entry_ptr); + if (!ret) { + // TODO(vcgomes): Remove already added trampolines when it fails. + LOGGER(ERROR) << "Error installing trampoline for " << entry->name; + return false; + } + } + return true; +} + +v8::Handle XWalkModuleSystem::RequireNative( + const std::string& name) { + NativeModuleMap::iterator it = native_modules_.find(name); + if (it == native_modules_.end()) + return v8::Handle(); + return it->second->NewInstance(); +} + +void XWalkModuleSystem::Initialize() { + SCOPE_PROFILE(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle context = GetV8Context(); + v8::Handle require_native_template = + v8::Local::New(isolate, require_native_template_); + v8::Handle require_native = + require_native_template->GetFunction(); + + MarkModulesWithTrampoline(); + + ExtensionModules::iterator it = extension_modules_.begin(); + for (; it != extension_modules_.end(); ++it) { + if (it->use_trampoline && InstallTrampoline(context, &*it)) + continue; + it->module->LoadExtensionCode(context, require_native); + EnsureExtensionNamespaceIsReadOnly(context, it->name); + } +} + +v8::Handle XWalkModuleSystem::GetV8Context() { + return v8::Local::New(v8::Isolate::GetCurrent(), v8_context_); +} + +bool XWalkModuleSystem::ContainsEntryPoint( + const std::string& entry) { + auto it = extension_modules_.begin(); + for (; it != extension_modules_.end(); ++it) { + if (it->name == entry) + return true; + + auto entry_it = std::find( + it->entry_points.begin(), it->entry_points.end(), entry); + if (entry_it != it->entry_points.end()) { + return true; + } + } + return false; +} + +void XWalkModuleSystem::DeleteExtensionModules() { + for (ExtensionModules::iterator it = extension_modules_.begin(); + it != extension_modules_.end(); ++it) { + delete it->module; + } + extension_modules_.clear(); +} + +// static +void XWalkModuleSystem::LoadExtensionForTrampoline( + v8::Isolate* isolate, + v8::Local data) { + v8::HandleScope handle_scope(isolate); + v8::Local params = data.As(); + void* ptr = params->Get( + v8::Integer::New(isolate, 0)).As()->Value(); + + ExtensionModuleEntry* entry = static_cast(ptr); + + if (!entry) + return; + + v8::Handle context = isolate->GetCurrentContext(); + + DeleteAccessorForEntryPoint(context, entry->name); + + auto it = entry->entry_points.begin(); + for (; it != entry->entry_points.end(); ++it) { + DeleteAccessorForEntryPoint(context, *it); + } + + XWalkModuleSystem* module_system = GetModuleSystemFromContext(context); + v8::Handle require_native_template = + v8::Local::New( + isolate, + module_system->require_native_template_); + + XWalkExtensionModule* module = entry->module; + module->LoadExtensionCode(module_system->GetV8Context(), + require_native_template->GetFunction()); + + module_system->EnsureExtensionNamespaceIsReadOnly(context, entry->name); +} + +// static +v8::Handle XWalkModuleSystem::RefetchHolder( + v8::Isolate* isolate, + v8::Local data) { + v8::Local params = data.As(); + const std::string entry_point = *v8::String::Utf8Value( + params->Get(v8::Integer::New(isolate, 1)).As()); + + std::vector path; + SplitString(entry_point, '.', &path); + path.pop_back(); + + std::string error; + return GetObjectForPath(isolate->GetCurrentContext(), path, &error); +} + +// static +void XWalkModuleSystem::TrampolineCallback( + v8::Local property, + const v8::PropertyCallbackInfo& info) { + XWalkModuleSystem::LoadExtensionForTrampoline(info.GetIsolate(), info.Data()); + v8::Handle holder = RefetchHolder(info.GetIsolate(), info.Data()); + if (holder->IsUndefined()) + return; + + info.GetReturnValue().Set(holder.As()->Get(property)); +} + +// static +void XWalkModuleSystem::TrampolineSetterCallback( + v8::Local property, + v8::Local value, + const v8::PropertyCallbackInfo& info) { + XWalkModuleSystem::LoadExtensionForTrampoline(info.GetIsolate(), info.Data()); + v8::Handle holder = RefetchHolder(info.GetIsolate(), info.Data()); + if (holder->IsUndefined()) + return; + + holder.As()->Set(property, value); +} + +XWalkModuleSystem::ExtensionModuleEntry::ExtensionModuleEntry( + const std::string& name, + XWalkExtensionModule* module, + const std::vector& entry_points) : + name(name), module(module), use_trampoline(true), + entry_points(entry_points) { +} + +XWalkModuleSystem::ExtensionModuleEntry::~ExtensionModuleEntry() { +} + +// Returns whether the name of first is prefix of the second, considering "." +// character as a separator. So "a" is prefix of "a.b" but not of "ab". +bool XWalkModuleSystem::ExtensionModuleEntry::IsPrefix( + const ExtensionModuleEntry& first, + const ExtensionModuleEntry& second) { + const std::string& p = first.name; + const std::string& s = second.name; + return s.size() > p.size() && s[p.size()] == '.' + && std::mismatch(p.begin(), p.end(), s.begin()).first == p.end(); +} + +// Mark the extension modules that we want to setup "trampolines" +// instead of loading the code directly. The current algorithm is very +// simple: we only create trampolines for extensions that are leaves +// in the namespace tree. +// +// For example, if there are two extensions "tizen" and "tizen.time", +// the first one won't be marked with trampoline, but the second one +// will. So we'll only load code for "tizen" extension. +void XWalkModuleSystem::MarkModulesWithTrampoline() { + std::sort(extension_modules_.begin(), extension_modules_.end()); + { + ExtensionModules::iterator it = extension_modules_.begin(); + while (it != extension_modules_.end()) { + it = std::adjacent_find(it, extension_modules_.end(), + &ExtensionModuleEntry::IsPrefix); + if (it == extension_modules_.end()) + break; + it->use_trampoline = false; + ++it; + } + } + + // NOTE: Special Case for Security Reason + // xwalk module should not be trampolined even it does not have any children. + { + ExtensionModules::iterator it = extension_modules_.begin(); + while (it != extension_modules_.end()) { + if ("xwalk" == (*it).name) { + it->use_trampoline = false; + break; + } + ++it; + } + } +} + +void XWalkModuleSystem::EnsureExtensionNamespaceIsReadOnly( + v8::Handle context, + const std::string& extension_name) { + std::vector path; + SplitString(extension_name, '.', &path); + std::string basename = path.back(); + path.pop_back(); + + std::string error; + v8::Handle value = GetObjectForPath(context, path, &error); + if (value->IsUndefined()) { + LOGGER(ERROR) << "Error retrieving object for " << extension_name << " : " + << error; + return; + } + + v8::Handle v8_extension_name( + v8::String::NewFromUtf8(context->GetIsolate(), basename.c_str())); + value.As()->ForceSet( + v8_extension_name, value.As()->Get(v8_extension_name), + v8::ReadOnly); +} + +} // namespace extensions diff --git a/tizen/extensions/renderer/xwalk_module_system.h b/tizen/extensions/renderer/xwalk_module_system.h new file mode 100644 index 0000000..e8bf6bf --- /dev/null +++ b/tizen/extensions/renderer/xwalk_module_system.h @@ -0,0 +1,116 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_RENDERER_XWALK_MODULE_SYSTEM_H_ +#define XWALK_EXTENSIONS_RENDERER_XWALK_MODULE_SYSTEM_H_ + +#include + +#include +#include +#include +#include + +namespace extensions { + +class XWalkExtensionModule; + +// Interface used to expose objects via the requireNative() function in JS API +// code. Native modules should be registered with the module system. +class XWalkNativeModule { + public: + virtual v8::Handle NewInstance() = 0; + virtual ~XWalkNativeModule() {} +}; + + +class XWalkModuleSystem { + public: + explicit XWalkModuleSystem(v8::Handle context); + ~XWalkModuleSystem(); + + static XWalkModuleSystem* GetModuleSystemFromContext( + v8::Handle context); + static void SetModuleSystemInContext( + std::unique_ptr module_system, + v8::Handle context); + static void ResetModuleSystemFromContext(v8::Handle context); + + void RegisterExtensionModule(std::unique_ptr module, + const std::vector& entry_points); + void RegisterNativeModule(const std::string& name, + std::unique_ptr module); + v8::Handle RequireNative(const std::string& name); + + void Initialize(); + + v8::Handle GetV8Context(); + + private: + struct ExtensionModuleEntry { + ExtensionModuleEntry(const std::string& name, XWalkExtensionModule* module, + const std::vector& entry_points); + ~ExtensionModuleEntry(); + std::string name; + XWalkExtensionModule* module; + bool use_trampoline; + std::vector entry_points; + bool operator<(const ExtensionModuleEntry& other) const { + return name < other.name; + } + + static bool IsPrefix(const ExtensionModuleEntry& first, + const ExtensionModuleEntry& second); + }; + + bool SetTrampolineAccessorForEntryPoint( + v8::Handle context, + const std::string& entry_point, + v8::Local user_data); + + static bool DeleteAccessorForEntryPoint(v8::Handle context, + const std::string& entry_point); + + bool InstallTrampoline(v8::Handle context, + ExtensionModuleEntry* entry); + + static void TrampolineCallback( + v8::Local property, + const v8::PropertyCallbackInfo& info); + static void TrampolineSetterCallback( + v8::Local property, + v8::Local value, + const v8::PropertyCallbackInfo& info); + static void LoadExtensionForTrampoline( + v8::Isolate* isolate, + v8::Local data); + static v8::Handle RefetchHolder( + v8::Isolate* isolate, + v8::Local data); + + bool ContainsEntryPoint(const std::string& entry_point); + void MarkModulesWithTrampoline(); + void DeleteExtensionModules(); + + void EnsureExtensionNamespaceIsReadOnly(v8::Handle context, + const std::string& extension_name); + + typedef std::vector ExtensionModules; + ExtensionModules extension_modules_; + typedef std::map NativeModuleMap; + NativeModuleMap native_modules_; + + v8::Persistent require_native_template_; + v8::Persistent function_data_; + + // Points back to the current context, used when native wants to callback + // JavaScript. When WillReleaseScriptContext() is called, we dispose this + // persistent. + v8::Persistent v8_context_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_RENDERER_XWALK_MODULE_SYSTEM_H_ diff --git a/tizen/extensions/renderer/xwalk_v8tools_module.cc b/tizen/extensions/renderer/xwalk_v8tools_module.cc new file mode 100644 index 0000000..4fcad37 --- /dev/null +++ b/tizen/extensions/renderer/xwalk_v8tools_module.cc @@ -0,0 +1,98 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/xwalk_v8tools_module.h" + +#include + +#include "common/logger.h" + +namespace extensions { + +namespace { + +void ForceSetPropertyCallback( + const v8::FunctionCallbackInfo& info) { + if (info.Length() != 3 || !info[0]->IsObject() || !info[1]->IsString()) { + return; + } + info[0].As()->ForceSet(info[1], info[2]); +} + +// ================ +// lifecycleTracker +// ================ +struct LifecycleTrackerWrapper { + v8::Global handle; + v8::Global destructor; +}; + +void LifecycleTrackerCleanup( + const v8::WeakCallbackInfo& data) { + LifecycleTrackerWrapper* wrapper = data.GetParameter(); + + if (!wrapper->destructor.IsEmpty()) { + v8::HandleScope handle_scope(data.GetIsolate()); + v8::Local context = v8::Context::New(data.GetIsolate()); + v8::Context::Scope scope(context); + + v8::Local destructor = + wrapper->destructor.Get(data.GetIsolate()); + + v8::MicrotasksScope microtasks( + data.GetIsolate(), v8::MicrotasksScope::kDoNotRunMicrotasks); + + v8::TryCatch try_catch(data.GetIsolate()); + destructor->Call(context->Global(), 0, nullptr); + + if (try_catch.HasCaught()) { + LOGGER(WARN) << "Exception when running LifecycleTracker destructor"; + } + } +} + +void LifecycleTracker(const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::HandleScope handle_scope(info.GetIsolate()); + + v8::Local tracker = v8::Object::New(isolate); + LifecycleTrackerWrapper* wrapper = new LifecycleTrackerWrapper; + wrapper->handle.Reset(isolate, tracker); + wrapper->handle.SetWeak(wrapper, LifecycleTrackerCleanup, + v8::WeakCallbackType::kParameter); + info.GetReturnValue().Set(wrapper->handle); +} + +} // namespace + +XWalkV8ToolsModule::XWalkV8ToolsModule() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle object_template = v8::ObjectTemplate::New(); + + // TODO(cmarcelo): Use Template::Set() function that takes isolate, once we + // update the Chromium (and V8) version. + object_template->Set(v8::String::NewFromUtf8(isolate, "forceSetProperty"), + v8::FunctionTemplate::New( + isolate, ForceSetPropertyCallback)); + object_template->Set(v8::String::NewFromUtf8(isolate, "lifecycleTracker"), + v8::FunctionTemplate::New(isolate, LifecycleTracker)); + + object_template_.Reset(isolate, object_template); +} + +XWalkV8ToolsModule::~XWalkV8ToolsModule() { + object_template_.Reset(); +} + +v8::Handle XWalkV8ToolsModule::NewInstance() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + v8::Handle object_template = + v8::Local::New(isolate, object_template_); + return handle_scope.Escape(object_template->NewInstance()); +} + +} // namespace extensions diff --git a/tizen/extensions/renderer/xwalk_v8tools_module.h b/tizen/extensions/renderer/xwalk_v8tools_module.h new file mode 100644 index 0000000..5b31dce --- /dev/null +++ b/tizen/extensions/renderer/xwalk_v8tools_module.h @@ -0,0 +1,28 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_EXTENSIONS_RENDERER_XWALK_V8TOOLS_MODULE_H_ +#define XWALK_EXTENSIONS_RENDERER_XWALK_V8TOOLS_MODULE_H_ + +#include "extensions/renderer/xwalk_module_system.h" + +namespace extensions { + +// This module provides extra JS functions that help writing JS API code for +// extensions, for example: allowing setting a read-only property of an object. +class XWalkV8ToolsModule : public XWalkNativeModule { + public: + XWalkV8ToolsModule(); + ~XWalkV8ToolsModule() override; + + private: + v8::Handle NewInstance() override; + + v8::Persistent object_template_; +}; + +} // namespace extensions + +#endif // XWALK_EXTENSIONS_RENDERER_XWALK_V8TOOLS_MODULE_H_ diff --git a/tizen/renderer/injected_bundle.cc b/tizen/renderer/injected_bundle.cc new file mode 100644 index 0000000..a030975 --- /dev/null +++ b/tizen/renderer/injected_bundle.cc @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common/application_data.h" +#include "common/locale_manager.h" +#include "common/logger.h" +#include "common/profiler.h" +#include "common/resource_manager.h" +#include "common/string_utils.h" +#include "extensions/renderer/runtime_ipc_client.h" +#include "extensions/renderer/widget_module.h" +#include "extensions/renderer/xwalk_extension_renderer_controller.h" +#include "extensions/renderer/xwalk_module_system.h" + +namespace runtime { + +class BundleGlobalData { + public: + static BundleGlobalData* GetInstance() { + static BundleGlobalData instance; + return &instance; + } + void PreInitialize() { + if (preInitialized) + return; + preInitialized = true; + locale_manager_.reset(new common::LocaleManager); + } + void Initialize(const std::string& app_id) { + PreInitialize(); + + auto appdata_manager = common::ApplicationDataManager::GetInstance(); + common::ApplicationData* app_data = + appdata_manager->GetApplicationData(app_id); + + app_data->LoadManifestData(); + // PreInitialized locale_manager_.reset(new common::LocaleManager); + locale_manager_->EnableAutoUpdate(true); + if (app_data->widget_info() != NULL && + !app_data->widget_info()->default_locale().empty()) { + locale_manager_->SetDefaultLocale( + app_data->widget_info()->default_locale()); + } + resource_manager_.reset(new common::ResourceManager(app_data, + locale_manager_.get())); + resource_manager_->set_base_resource_path( + app_data->application_path()); + + auto widgetdb = extensions::WidgetPreferenceDB::GetInstance(); + widgetdb->Initialize(app_data, + locale_manager_.get()); + } + + common::ResourceManager* resource_manager() { + return resource_manager_.get(); + } + + private: + BundleGlobalData() : preInitialized(false) {} + ~BundleGlobalData() {} + std::unique_ptr resource_manager_; + std::unique_ptr locale_manager_; + + bool preInitialized; +}; + +} // namespace runtime + +extern "C" unsigned int DynamicPluginVersion(void) { + return 1; +} + +extern "C" void DynamicSetWidgetInfo(const char* tizen_id) { + SCOPE_PROFILE(); + ecore_init(); + + runtime::BundleGlobalData::GetInstance()->Initialize(tizen_id); + extensions::XWalkExtensionRendererController& controller = + extensions::XWalkExtensionRendererController::GetInstance(); + auto appdata_manager = common::ApplicationDataManager::GetInstance(); + common::ApplicationData* app_data = + appdata_manager->GetApplicationData(tizen_id); + controller.LoadUserExtensions(app_data->application_path()); +} + +extern "C" void DynamicPluginStartSession(const char* tizen_id, + v8::Handle context, + int routing_handle, + const char* base_url) { + SCOPE_PROFILE(); + + // Initialize context's aligned pointer in embedder data with null + extensions::XWalkModuleSystem::SetModuleSystemInContext( + std::unique_ptr(), context); + + if (base_url == NULL || common::utils::StartsWith(base_url, "http")) { + LOGGER(ERROR) << "External url not allowed plugin loading."; + return; + } + + // Initialize RuntimeIPCClient + extensions::RuntimeIPCClient* rc = + extensions::RuntimeIPCClient::GetInstance(); + rc->SetRoutingId(context, routing_handle); + + extensions::XWalkExtensionRendererController& controller = + extensions::XWalkExtensionRendererController::GetInstance(); + controller.DidCreateScriptContext(context); +} + +extern "C" void DynamicPluginStopSession( + const char* tizen_id, v8::Handle context) { + SCOPE_PROFILE(); + extensions::XWalkExtensionRendererController& controller = + extensions::XWalkExtensionRendererController::GetInstance(); + controller.WillReleaseScriptContext(context); +} + +extern "C" void DynamicUrlParsing( + std::string* old_url, std::string* new_url, const char* /*tizen_id*/) { + LOGGER(DEBUG) << "DynamicUrlParsing"; + auto res_manager = + runtime::BundleGlobalData::GetInstance()->resource_manager(); + if (res_manager == NULL) { + LOGGER(ERROR) << "Widget Info was not set, Resource Manager is NULL"; + *new_url = *old_url; + return; + } + // Check Access control + if (!res_manager->AllowedResource(*old_url)) { + // To maintain backward compatibility, we shoudn't explicitly set URL "about:blank" + *new_url = std::string(); + LOGGER(ERROR) << "request was blocked by WARP"; + return; + } + // convert to localized path + if (common::utils::StartsWith(*old_url, "file:/") || + common::utils::StartsWith(*old_url, "app:/")) { + *new_url = res_manager->GetLocalizedPath(*old_url); + } else { + *new_url = *old_url; + } + // check encryption + if (res_manager->IsEncrypted(*new_url)) { + *new_url = res_manager->DecryptResource(*new_url); + } +} + +extern "C" void DynamicDatabaseAttach(int /*attach*/) { + // LOGGER(DEBUG) << "InjectedBundle::DynamicDatabaseAttach !!"; +} + +extern "C" void DynamicOnIPCMessage(const Ewk_IPC_Wrt_Message_Data& data) { + SCOPE_PROFILE(); + extensions::XWalkExtensionRendererController& controller = + extensions::XWalkExtensionRendererController::GetInstance(); + controller.OnReceivedIPCMessage(&data); +} + +extern "C" void DynamicPreloading() { + LOGGER(ERROR) << "DynamicPreloading"; + SCOPE_PROFILE(); + runtime::BundleGlobalData::GetInstance()->PreInitialize(); + extensions::XWalkExtensionRendererController& controller = + extensions::XWalkExtensionRendererController::GetInstance(); + controller.InitializeExtensionClient(); +} diff --git a/tizen/renderer/injected_bundle.gyp b/tizen/renderer/injected_bundle.gyp new file mode 100644 index 0000000..f6ab6d7 --- /dev/null +++ b/tizen/renderer/injected_bundle.gyp @@ -0,0 +1,23 @@ +{ + 'includes':[ + '../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'xwalk_injected_bundle', + 'type': 'shared_library', + 'sources': [ + 'injected_bundle.cc', + ], + 'cflags': [ + '-fvisibility=default', + ], + 'variables': { + 'packages': [ + 'chromium-efl', + 'elementary', + ], + }, + }, # end of target 'xwalk_injected_bundle' + ], +} diff --git a/vendor/brightray/browser/browser_context.cc b/vendor/brightray/browser/browser_context.cc index 46f7630..4ab07e4 100644 --- a/vendor/brightray/browser/browser_context.cc +++ b/vendor/brightray/browser/browser_context.cc @@ -28,6 +28,13 @@ #include "content/public/browser/storage_partition.h" #include "net/base/escape.h" +#if defined(OS_TIZEN) +#include "content/browser/zygote_host/zygote_communication_linux.h" +#include "content/public/browser/zygote_handle_linux.h" +#include "content/public/common/content_switches.h" +#include "base/command_line.h" +#endif + using content::BrowserThread; namespace brightray { @@ -100,6 +107,14 @@ BrowserContext::BrowserContext(const std::string& partition, bool in_memory) content::BrowserContext::Initialize(this, path_); browser_context_map_[PartitionKey(partition, in_memory)] = GetWeakPtr(); +#if defined(OS_TIZEN) + auto command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch("injected-bundle-path")) { + std::string injected_bundle_path = command_line->GetSwitchValueASCII("injected-bundle-path"); + (*content::GetGenericZygote())-> + LoadInjectedBundlePath(injected_bundle_path); + } +#endif } BrowserContext::~BrowserContext() { diff --git a/wrt.gyp b/wrt.gyp index a24edb4..6ea31d4 100644 --- a/wrt.gyp +++ b/wrt.gyp @@ -13,6 +13,8 @@ 'wrt_lib', '<(DEPTH)/tizen/common/common.gyp:wrt_common', '<(DEPTH)/tizen/loader/loader.gyp:wrt-loader', + '<(DEPTH)/tizen/extensions/extensions.gyp:xwalk_extension_shared', + '<(DEPTH)/tizen/renderer/injected_bundle.gyp:xwalk_injected_bundle', '<(DEPTH)/efl/build/system.gyp:ecore', '<(DEPTH)/efl/build/system.gyp:launchpad', '<(DEPTH)/efl/build/system.gyp:capi-appfw-application', -- 2.7.4