Added Injected Bundle and extension server and client 94/173694/12
authorprathmeshm <prathmesh.m@samsung.com>
Fri, 23 Mar 2018 06:46:03 +0000 (12:16 +0530)
committerjaekuk lee <juku1999@samsung.com>
Wed, 18 Apr 2018 10:21:58 +0000 (10:21 +0000)
- 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 <prathmesh.m@samsung.com>
48 files changed:
atom/app/atom_main_delegate.cc
packaging/electron-efl.spec
tizen/build/common.gypi
tizen/extensions/common/constants.cc [new file with mode: 0644]
tizen/extensions/common/constants.h [new file with mode: 0644]
tizen/extensions/common/xwalk_extension.cc [new file with mode: 0644]
tizen/extensions/common/xwalk_extension.h [new file with mode: 0644]
tizen/extensions/common/xwalk_extension_adapter.cc [new file with mode: 0644]
tizen/extensions/common/xwalk_extension_adapter.h [new file with mode: 0644]
tizen/extensions/common/xwalk_extension_instance.cc [new file with mode: 0644]
tizen/extensions/common/xwalk_extension_instance.h [new file with mode: 0644]
tizen/extensions/common/xwalk_extension_manager.cc [new file with mode: 0644]
tizen/extensions/common/xwalk_extension_manager.h [new file with mode: 0644]
tizen/extensions/common/xwalk_extension_server.cc [new file with mode: 0644]
tizen/extensions/common/xwalk_extension_server.h [new file with mode: 0644]
tizen/extensions/extensions.gyp [new file with mode: 0644]
tizen/extensions/internal/splash_screen/splash_screen.json [new file with mode: 0644]
tizen/extensions/internal/splash_screen/splash_screen_api.js [new file with mode: 0644]
tizen/extensions/internal/splash_screen/splash_screen_extension.cc [new file with mode: 0644]
tizen/extensions/internal/widget/widget.json [new file with mode: 0644]
tizen/extensions/internal/widget/widget_api.js [new file with mode: 0644]
tizen/extensions/internal/widget/widget_extension.cc [new file with mode: 0644]
tizen/extensions/public/XW_Extension.h [new file with mode: 0644]
tizen/extensions/public/XW_Extension_EntryPoints.h [new file with mode: 0644]
tizen/extensions/public/XW_Extension_Message_2.h [new file with mode: 0644]
tizen/extensions/public/XW_Extension_Permissions.h [new file with mode: 0644]
tizen/extensions/public/XW_Extension_Runtime.h [new file with mode: 0644]
tizen/extensions/public/XW_Extension_SyncMessage.h [new file with mode: 0644]
tizen/extensions/renderer/object_tools_module.cc [new file with mode: 0644]
tizen/extensions/renderer/object_tools_module.h [new file with mode: 0644]
tizen/extensions/renderer/runtime_ipc_client.cc [new file with mode: 0644]
tizen/extensions/renderer/runtime_ipc_client.h [new file with mode: 0644]
tizen/extensions/renderer/widget_module.cc [new file with mode: 0644]
tizen/extensions/renderer/widget_module.h [new file with mode: 0644]
tizen/extensions/renderer/xwalk_extension_client.cc [new file with mode: 0644]
tizen/extensions/renderer/xwalk_extension_client.h [new file with mode: 0644]
tizen/extensions/renderer/xwalk_extension_module.cc [new file with mode: 0644]
tizen/extensions/renderer/xwalk_extension_module.h [new file with mode: 0644]
tizen/extensions/renderer/xwalk_extension_renderer_controller.cc [new file with mode: 0644]
tizen/extensions/renderer/xwalk_extension_renderer_controller.h [new file with mode: 0644]
tizen/extensions/renderer/xwalk_module_system.cc [new file with mode: 0644]
tizen/extensions/renderer/xwalk_module_system.h [new file with mode: 0644]
tizen/extensions/renderer/xwalk_v8tools_module.cc [new file with mode: 0644]
tizen/extensions/renderer/xwalk_v8tools_module.h [new file with mode: 0644]
tizen/renderer/injected_bundle.cc [new file with mode: 0644]
tizen/renderer/injected_bundle.gyp [new file with mode: 0644]
vendor/brightray/browser/browser_context.cc
wrt.gyp

index 9f9ac69..f840690 100644 (file)
 #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<std::string> 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");
index f26da7c..7f48f8b 100755 (executable)
@@ -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
index 587a0ad..5f90ec5 100644 (file)
@@ -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': {
       '../',
       '<(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 (file)
index 0000000..cfc9fa4
--- /dev/null
@@ -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 (file)
index 0000000..588f09b
--- /dev/null
@@ -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 (file)
index 0000000..d41af24
--- /dev/null
@@ -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 <dlfcn.h>
+#include <string>
+
+#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<XW_Initialize_Func>(
+      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 (file)
index 0000000..c7aaf83
--- /dev/null
@@ -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 <string>
+#include <vector>
+
+#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<std::string> 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 (file)
index 0000000..ef693ff
--- /dev/null
@@ -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 <string>
+
+#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 (file)
index 0000000..9a29c35
--- /dev/null
@@ -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 <map>
+
+#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<XW_Extension, XWalkExtension*> ExtensionMap;
+  typedef std::map<XW_Instance, XWalkExtensionInstance*> 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 (file)
index 0000000..c86bb59
--- /dev/null
@@ -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 (file)
index 0000000..9efe2db
--- /dev/null
@@ -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 <functional>
+#include <string>
+
+#include "extensions/public/XW_Extension.h"
+
+namespace extensions {
+
+class XWalkExtension;
+
+class XWalkExtensionInstance {
+ public:
+  typedef std::function<void(const std::string&)> 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 (file)
index 0000000..130eca8
--- /dev/null
@@ -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 <glob.h>
+#include <dlfcn.h>
+#include <sys/utsname.h>
+
+#include <fstream>
+#include <set>
+#include <string>
+#include <vector>
+
+#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<picojson::array>()) {
+    auto& plugins = metadata.get<picojson::array>();
+    for (auto plugin = plugins.begin(); plugin != plugins.end(); ++plugin) {
+      if (!plugin->is<picojson::object>())
+        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<std::string> entries;
+      auto& entry_points_value = plugin->get("entry_points");
+      if (entry_points_value.is<picojson::array>()) {
+        auto& entry_points = entry_points_value.get<picojson::array>();
+        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 (file)
index 0000000..cfbdede
--- /dev/null
@@ -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 <string>
+#include <set>
+#include <map>
+
+#include "extensions/common/xwalk_extension.h"
+
+namespace extensions {
+
+class XWalkExtensionManager : public XWalkExtension::XWalkExtensionDelegate {
+ public:
+  typedef std::set<std::string> StringSet;
+  typedef std::map<std::string, XWalkExtension*> 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 (file)
index 0000000..fc50396
--- /dev/null
@@ -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 <Ecore.h>
+
+#include <string>
+
+#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 (file)
index 0000000..3cd67bf
--- /dev/null
@@ -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 <EWebKit.h>
+#include <EWebKit_internal.h>
+#include <json/json.h>
+
+#include <string>
+#include <map>
+
+#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<std::string, XWalkExtensionInstance*> 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 (file)
index 0000000..165271b
--- /dev/null
@@ -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 (file)
index 0000000..e7a565d
--- /dev/null
@@ -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 (file)
index 0000000..551a72d
--- /dev/null
@@ -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 (file)
index 0000000..19823e5
--- /dev/null
@@ -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 <list>
+#include <memory>
+#include <map>
+#include <vector>
+
+#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<const XW_CoreInterface*>(
+      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<const XW_MessagingInterface*>(
+      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<const XW_Internal_SyncMessagingInterface*>(
+          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<const XW_Internal_EntryPointsInterface*>(
+      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<const XW_Internal_RuntimeInterface*>(
+      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 (file)
index 0000000..ae1dbbd
--- /dev/null
@@ -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 (file)
index 0000000..6a5b7a6
--- /dev/null
@@ -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 (file)
index 0000000..aab1dab
--- /dev/null
@@ -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 <list>
+#include <memory>
+#include <map>
+#include <vector>
+
+#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<const XW_CoreInterface*>(
+      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<const XW_MessagingInterface*>(
+      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<const XW_Internal_SyncMessagingInterface*>(
+          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<const XW_Internal_EntryPointsInterface*>(
+      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<const XW_Internal_RuntimeInterface*>(
+      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 (file)
index 0000000..174915a
--- /dev/null
@@ -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 <stdint.h>
+
+
+// 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 (file)
index 0000000..54532a9
--- /dev/null
@@ -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 (file)
index 0000000..f417f88
--- /dev/null
@@ -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 (file)
index 0000000..d25484e
--- /dev/null
@@ -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 (file)
index 0000000..11ad307
--- /dev/null
@@ -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 (file)
index 0000000..4eddbf9
--- /dev/null
@@ -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 (file)
index 0000000..67cb503
--- /dev/null
@@ -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 <v8/v8.h>
+
+#include <string>
+
+#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<v8::Value> RunString(const std::string& code) {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::EscapableHandleScope handle_scope(isolate);
+  v8::Handle<v8::String> v8_code(
+      v8::String::NewFromUtf8(isolate, code.c_str()));
+
+  v8::TryCatch try_catch;
+  try_catch.SetVerbose(true);
+
+  v8::Handle<v8::Script> 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::Primitive>(v8::Undefined(isolate)));
+  }
+
+  v8::Local<v8::Value> 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::Primitive>(v8::Undefined(isolate)));
+  }
+  return handle_scope.Escape(result);
+}
+}  //  namespace
+
+
+ObjectToolsModule::ObjectToolsModule() {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::HandleScope handle_scope(isolate);
+
+  v8::Handle<v8::Value> result = RunString(kCreateObjectCode);
+  if (!result->IsFunction()) {
+    LOGGER(ERROR) << "Couldn't load Object Create function";
+    return;
+  }
+  v8::Handle<v8::Function> create_function =
+      v8::Handle<v8::Function>::Cast(result);
+
+  create_function_.Reset(isolate, create_function);
+}
+
+ObjectToolsModule::~ObjectToolsModule() {
+  create_function_.Reset();
+}
+
+v8::Handle<v8::Object> ObjectToolsModule::NewInstance() {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  if (create_function_.IsEmpty()) {
+    return v8::Object::New(isolate);
+  }
+  v8::Handle<v8::Function> function =
+      v8::Local<v8::Function>::New(isolate, create_function_);
+
+  v8::Handle<v8::Context> context = v8::Context::New(isolate);
+  v8::TryCatch try_catch;
+  v8::Handle<v8::Value> 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<v8::Object>::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 (file)
index 0000000..eb4609b
--- /dev/null
@@ -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<v8::Object> NewInstance() override;
+  v8::Persistent<v8::Function> 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 (file)
index 0000000..6b96828
--- /dev/null
@@ -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<v8::Function> callback) {
+  callback_.Reset(isolate, callback);
+}
+
+RuntimeIPCClient::JSCallback::~JSCallback() {
+  callback_.Reset();
+}
+
+void RuntimeIPCClient::JSCallback::Call(v8::Isolate* isolate,
+                                        v8::Handle<v8::Value> args[]) {
+  if (!callback_.IsEmpty()) {
+    v8::HandleScope handle_scope(isolate);
+    v8::TryCatch try_catch(isolate);
+    v8::Handle<v8::Function> func =
+        v8::Local<v8::Function>::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<v8::Context> context) {
+  v8::Handle<v8::Value> 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<v8::Context> context,
+                                    int routing_id) {
+  context->SetEmbedderData(kRoutingIdEmbedderDataIndex,
+                           v8::Integer::New(context->GetIsolate(), routing_id));
+}
+
+void RuntimeIPCClient::SendMessage(v8::Handle<v8::Context> context,
+                                   const std::string& type,
+                                   const std::string& value) {
+  SendMessage(context, type, "", "", value);
+}
+
+void RuntimeIPCClient::SendMessage(v8::Handle<v8::Context> context,
+                                   const std::string& type,
+                                   const std::string& id,
+                                   const std::string& value) {
+  SendMessage(context, type, id, "", value);
+}
+
+void RuntimeIPCClient::SendMessage(v8::Handle<v8::Context> 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<v8::Context> context,
+                                              const std::string& type,
+                                              const std::string& value) {
+  return SendSyncMessage(context, type, "", "", value);
+}
+
+std::string RuntimeIPCClient::SendSyncMessage(v8::Handle<v8::Context> 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<v8::Context> 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<v8::Context> 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 (file)
index 0000000..7f94fb3
--- /dev/null
@@ -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 <v8/v8.h>
+#include <EWebKit.h>
+#include <EWebKit_internal.h>
+
+#include <functional>
+#include <map>
+#include <string>
+
+namespace extensions {
+
+class RuntimeIPCClient {
+ public:
+  class JSCallback {
+   public:
+    explicit JSCallback(v8::Isolate* isolate,
+                        v8::Handle<v8::Function> callback);
+    ~JSCallback();
+
+    void Call(v8::Isolate* isolate, v8::Handle<v8::Value> args[]);
+   private:
+    v8::Persistent<v8::Function> callback_;
+  };
+
+  typedef std::function<void(const std::string& type,
+                             const std::string& value)> ReplyCallback;
+
+  static RuntimeIPCClient* GetInstance();
+
+  // Send message to BrowserProcess without reply
+  void SendMessage(v8::Handle<v8::Context> context,
+                   const std::string& type,
+                   const std::string& value);
+
+  void SendMessage(v8::Handle<v8::Context> context,
+                   const std::string& type,
+                   const std::string& id,
+                   const std::string& value);
+
+  void SendMessage(v8::Handle<v8::Context> 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<v8::Context> context,
+                              const std::string& type,
+                              const std::string& value);
+
+  std::string SendSyncMessage(v8::Handle<v8::Context> context,
+                              const std::string& type,
+                              const std::string& id,
+                              const std::string& value);
+
+  std::string SendSyncMessage(v8::Handle<v8::Context> 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<v8::Context> context,
+                        const std::string& type, const std::string& value,
+                        ReplyCallback callback);
+
+  void HandleMessageFromRuntime(const Ewk_IPC_Wrt_Message_Data* msg);
+
+  int GetRoutingId(v8::Handle<v8::Context> context);
+
+  void SetRoutingId(v8::Handle<v8::Context> context, int routing_id);
+
+ private:
+  RuntimeIPCClient();
+
+  std::map<std::string, ReplyCallback> 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 (file)
index 0000000..2237501
--- /dev/null
@@ -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 <v8/v8.h>
+
+#include <algorithm>
+#include <vector>
+
+#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<const char*> kExcludeList = {
+  kOnchangedEventHandler,
+  kKeyKey,
+  kGetItemKey,
+  kSetItemKey,
+  kRemoveItemKey,
+  kLengthKey,
+  kClearKey};
+
+void DispatchEvent(const v8::Local<v8::Object>& This,
+                   v8::Local<v8::Value> key,
+                   v8::Local<v8::Value> oldvalue,
+                   v8::Local<v8::Value> newvalue) {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+  v8::Handle<v8::Value> function =
+      This->Get(v8::String::NewFromUtf8(isolate, kOnchangedEventHandler));
+
+  if (function.IsEmpty() || !function->IsFunction()) {
+    LOGGER(DEBUG) << "onChanged function not set";
+    return;
+  }
+
+  v8::Handle<v8::Context> context = v8::Context::New(isolate);
+
+  const int argc = 3;
+  v8::Handle<v8::Value> argv[argc] = {
+    key,
+    oldvalue,
+    newvalue
+  };
+
+  v8::TryCatch try_catch;
+  v8::Handle<v8::Function>::Cast(function)->Call(
+      context->Global(), argc, argv);
+  if (try_catch.HasCaught())
+    LOGGER(DEBUG) << "Exception when running onChanged callback";
+}
+
+v8::Handle<v8::Object> MakeException(int code,
+                                   std::string name,
+                                   std::string message) {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::EscapableHandleScope handle_scope(isolate);
+  v8::Local<v8::Object> 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<v8::Value>& 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<v8::Value>& 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<v8::Value>& 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<v8::Value> 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<v8::Value>& 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<v8::Value> 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<v8::Value>& 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<v8::ObjectTemplate>
+      preference_object_template = v8::ObjectTemplate::New();
+
+  auto getter = [](
+      v8::Local<v8::String> property,
+      const v8::PropertyCallbackInfo<v8::Value>& 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<v8::String> property,
+      v8::Local<v8::Value> value,
+      const v8::PropertyCallbackInfo<v8::Value>& 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<v8::Value> 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<v8::String> property,
+      const v8::PropertyCallbackInfo<v8::Boolean>& 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<v8::Value> 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<v8::Object> WidgetModule::NewInstance() {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::EscapableHandleScope handle_scope(isolate);
+
+  v8::Local<v8::Object> widget = v8::Object::New(isolate);
+  v8::Handle<v8::ObjectTemplate> object_template =
+      v8::Local<v8::ObjectTemplate>::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<std::string> list;
+  db->GetKeys(kDBPublicSection, &list);
+  return list.size();
+}
+
+bool WidgetPreferenceDB::Key(int idx, std::string* key) {
+  common::AppDB* db = common::AppDB::GetInstance();
+  std::list<std::string> 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<std::string> 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<std::string>* 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 (file)
index 0000000..36acec1
--- /dev/null
@@ -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 <list>
+#include <string>
+
+#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<v8::Object> NewInstance() override;
+  v8::Persistent<v8::ObjectTemplate> 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<std::string>* 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 (file)
index 0000000..383473f
--- /dev/null
@@ -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 <Ecore.h>
+#include <unistd.h>
+#include <v8/v8.h>
+#include <json/json.h>
+
+#include <string>
+
+#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<const char*>(data);
+    XWalkExtensionServer* server = XWalkExtensionServer::GetInstance();
+    std::string instance_id = server->CreateInstance(extension_name);
+    return static_cast<void*>(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<v8::Context> context,
+    const std::string& extension_name, InstanceHandler* handler) {
+  void* ret = ecore_main_loop_thread_safe_call_sync(
+      CreateInstanceInMainloop,
+      static_cast<void*>(const_cast<char*>(extension_name.data())));
+  std::string* sp = static_cast<std::string*>(ret);
+  std::string instance_id = *sp;
+  delete sp;
+
+  handlers_[instance_id] = handler;
+  return instance_id;
+}
+
+void XWalkExtensionClient::DestroyInstance(
+    v8::Handle<v8::Context> 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<v8::Context> 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<v8::Context> 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<v8::Context> 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 (file)
index 0000000..5b98ee9
--- /dev/null
@@ -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 <v8/v8.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#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<v8::Context> context,
+                             const std::string& extension_name,
+                             InstanceHandler* handler);
+  void DestroyInstance(v8::Handle<v8::Context> context,
+                       const std::string& instance_id);
+
+  void PostMessageToNative(v8::Handle<v8::Context> context,
+                           const std::string& instance_id,
+                           const std::string& msg);
+  std::string SendSyncMessageToNative(v8::Handle<v8::Context> context,
+                                      const std::string& instance_id,
+                                      const std::string& msg);
+
+  std::string GetAPIScript(v8::Handle<v8::Context> 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<std::string> entry_points;
+  };
+
+  typedef std::map<std::string, ExtensionCodePoints*> ExtensionAPIMap;
+
+  const ExtensionAPIMap& extension_apis() const { return extension_apis_; }
+
+ private:
+  ExtensionAPIMap extension_apis_;
+
+  typedef std::map<std::string, InstanceHandler*> 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 (file)
index 0000000..c222556
--- /dev/null
@@ -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 <v8/v8.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <vector>
+
+#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<v8::Object> function_data = v8::Object::New(isolate);
+  function_data->Set(v8::String::NewFromUtf8(isolate, kXWalkExtensionModule),
+                     v8::External::New(isolate, this));
+
+  v8::Handle<v8::ObjectTemplate> 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<v8::Object> function_data =
+      v8::Local<v8::Object>::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 <class StringType>
+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<int>(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<typename StringType::value_type> 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<v8::Message> 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<v8::Value> RunString(const std::string& code,
+                                std::string* exception) {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::EscapableHandleScope handle_scope(isolate);
+  v8::Handle<v8::String> v8_code(
+      v8::String::NewFromUtf8(isolate, code.c_str()));
+
+  v8::TryCatch try_catch;
+  try_catch.SetVerbose(true);
+
+  v8::Handle<v8::Script> script(v8::Script::Compile(v8_code));
+  if (try_catch.HasCaught()) {
+    *exception = ExceptionToString(try_catch);
+    return handle_scope.Escape(
+        v8::Local<v8::Primitive>(v8::Undefined(isolate)));
+  }
+
+  v8::Local<v8::Value> result = script->Run();
+  if (try_catch.HasCaught()) {
+    *exception = ExceptionToString(try_catch);
+    return handle_scope.Escape(
+        v8::Local<v8::Primitive>(v8::Undefined(isolate)));
+  }
+
+  return handle_scope.Escape(result);
+}
+
+}  // namespace
+
+void XWalkExtensionModule::LoadExtensionCode(
+    v8::Handle<v8::Context> context, v8::Handle<v8::Function> 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<v8::Value> result = RunString(wrapped_api_code, &exception);
+
+  if (!result->IsFunction()) {
+    LOGGER(ERROR) << "Couldn't load JS API code for "
+                  << extension_name_ << " : " << exception;
+    return;
+  }
+  v8::Handle<v8::Function> callable_api_code =
+      v8::Handle<v8::Function>::Cast(result);
+  v8::Handle<v8::ObjectTemplate> object_template =
+      v8::Local<v8::ObjectTemplate>::New(context->GetIsolate(),
+                                          object_template_);
+
+  const int argc = 2;
+  v8::Handle<v8::Value> 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<v8::Context> context = module_system_->GetV8Context();
+  v8::Context::Scope context_scope(context);
+
+  v8::Handle<v8::Value> args[] = {
+      v8::String::NewFromUtf8(isolate, msg.c_str()) };
+
+  v8::Handle<v8::Function> message_listener =
+      v8::Local<v8::Function>::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<v8::Value>& info) {
+  v8::ReturnValue<v8::Value> 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<v8::Value>& info) {
+  v8::ReturnValue<v8::Value> 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<v8::Value>& info) {
+  v8::ReturnValue<v8::Value> 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<v8::Function>());
+
+  result.Set(true);
+}
+
+// static
+void XWalkExtensionModule::SendRuntimeMessageCallback(
+    const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::ReturnValue<v8::Value> 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<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+
+  v8::ReturnValue<v8::Value> 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<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  v8::ReturnValue<v8::Value> 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<v8::Function> func = info[2].As<v8::Function>();
+      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<v8::Value> 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<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  v8::Local<v8::Object> data = info.Data().As<v8::Object>();
+  v8::Local<v8::Value> 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<XWalkExtensionModule*>(module.As<v8::External>()->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 (file)
index 0000000..1076f0f
--- /dev/null
@@ -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 <v8/v8.h>
+
+#include <memory>
+#include <string>
+
+#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<v8::Object>, and
+  // let the module system set it to the appropriated object.
+  void LoadExtensionCode(v8::Handle<v8::Context> context,
+                         v8::Handle<v8::Function> 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<v8::Value>& info);
+  static void SendSyncMessageCallback(
+      const v8::FunctionCallbackInfo<v8::Value>& info);
+  static void SetMessageListenerCallback(
+      const v8::FunctionCallbackInfo<v8::Value>& info);
+  static void SendRuntimeMessageCallback(
+      const v8::FunctionCallbackInfo<v8::Value>& info);
+  static void SendRuntimeSyncMessageCallback(
+      const v8::FunctionCallbackInfo<v8::Value>& info);
+  static void SendRuntimeAsyncMessageCallback(
+      const v8::FunctionCallbackInfo<v8::Value>& info);
+
+  static XWalkExtensionModule* GetExtensionModule(
+      const v8::FunctionCallbackInfo<v8::Value>& info);
+
+  // Template for the 'extension' object exposed to the extension JS code.
+  v8::Persistent<v8::ObjectTemplate> object_template_;
+
+  // This JS object contains a pointer back to the ExtensionModule, it is
+  // set as data for the function callbacks.
+  v8::Persistent<v8::Object> 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<v8::Function> 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 (file)
index 0000000..6c8dd11
--- /dev/null
@@ -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 <Ecore.h>
+#include <v8/v8.h>
+#include <string>
+#include <utility>
+
+#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<XWalkExtensionModule> 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<v8::Context> 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<XWalkModuleSystem>(module_system), context);
+  module_system->RegisterNativeModule(
+        "v8tools",
+        std::unique_ptr<XWalkNativeModule>(new XWalkV8ToolsModule));
+  module_system->RegisterNativeModule(
+        "WidgetModule",
+        std::unique_ptr<XWalkNativeModule>(new WidgetModule));
+  module_system->RegisterNativeModule(
+        "objecttools",
+        std::unique_ptr<XWalkNativeModule>(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<v8::Context> 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 (file)
index 0000000..95e3145
--- /dev/null
@@ -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 <EWebKit.h>
+#include <EWebKit_internal.h>
+#include <v8/v8.h>
+
+#include <memory>
+#include <string>
+
+namespace extensions {
+
+class XWalkExtensionClient;
+
+class XWalkExtensionRendererController {
+ public:
+  static XWalkExtensionRendererController& GetInstance();
+  static int plugin_session_count;
+
+  void DidCreateScriptContext(v8::Handle<v8::Context> context);
+  void WillReleaseScriptContext(v8::Handle<v8::Context> 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<XWalkExtensionClient> 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 (file)
index 0000000..2218188
--- /dev/null
@@ -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 <v8/v8.h>
+
+#include <algorithm>
+
+#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<v8::Value>& info) {
+  v8::ReturnValue<v8::Value> result(info.GetReturnValue());
+
+  v8::Isolate* isolate = info.GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  v8::Handle<v8::Object> data = info.Data().As<v8::Object>();
+  v8::Handle<v8::Value> 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<XWalkModuleSystem*>(
+      module_system_value.As<v8::External>()->Value());
+
+  if (info.Length() < 1) {
+    // TODO(cmarcelo): Throw appropriate exception or warning.
+    result.SetUndefined();
+    return;
+  }
+  if (!module_system) {
+    result.SetUndefined();
+    return;
+  }
+  v8::Handle<v8::Object> 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<v8::Context> context) {
+  v8::Isolate* isolate = context->GetIsolate();
+  v8_context_.Reset(isolate, context);
+
+  v8::HandleScope handle_scope(isolate);
+  v8::Handle<v8::Object> function_data = v8::Object::New(isolate);
+  function_data->Set(v8::String::NewFromUtf8(isolate, kXWalkModuleSystem),
+                     v8::External::New(isolate, this));
+  v8::Handle<v8::FunctionTemplate> 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<v8::Context> context) {
+  return reinterpret_cast<XWalkModuleSystem*>(
+      context->GetAlignedPointerFromEmbedderData(
+          kModuleSystemEmbedderDataIndex));
+}
+
+// static
+void XWalkModuleSystem::SetModuleSystemInContext(
+    std::unique_ptr<XWalkModuleSystem> module_system,
+    v8::Handle<v8::Context> context) {
+  context->SetAlignedPointerInEmbedderData(kModuleSystemEmbedderDataIndex,
+                                           module_system.release());
+}
+
+// static
+void XWalkModuleSystem::ResetModuleSystemFromContext(
+    v8::Handle<v8::Context> context) {
+  XWalkModuleSystem* module_system = GetModuleSystemFromContext(context);
+  if (module_system) {
+    delete module_system;
+    SetModuleSystemInContext(std::unique_ptr<XWalkModuleSystem>(), context);
+  }
+}
+
+void XWalkModuleSystem::RegisterExtensionModule(
+    std::unique_ptr<XWalkExtensionModule> module,
+    const std::vector<std::string>& 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<std::string>::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<XWalkNativeModule> module) {
+  if (native_modules_.find(name) != native_modules_.end()) {
+    return;
+  }
+  native_modules_[name] = module.release();
+}
+
+
+namespace {
+
+v8::Handle<v8::Value> EnsureTargetObjectForTrampoline(
+    v8::Handle<v8::Context> context, const std::vector<std::string>& path,
+    std::string* error) {
+  v8::Handle<v8::Object> object = context->Global();
+  v8::Isolate* isolate = context->GetIsolate();
+
+  std::vector<std::string>::const_iterator it = path.begin();
+  for (; it != path.end(); ++it) {
+    v8::Handle<v8::String> part =
+        v8::String::NewFromUtf8(isolate, it->c_str());
+    v8::Handle<v8::Value> value = object->Get(part);
+
+    if (value->IsUndefined()) {
+      v8::Handle<v8::Object> 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<v8::Object>();
+  }
+  return object;
+}
+
+v8::Handle<v8::Value> GetObjectForPath(v8::Handle<v8::Context> context,
+                                       const std::vector<std::string>& path,
+                                       std::string* error) {
+  v8::Handle<v8::Object> object = context->Global();
+  v8::Isolate* isolate = context->GetIsolate();
+
+  std::vector<std::string>::const_iterator it = path.begin();
+  for (; it != path.end(); ++it) {
+    v8::Handle<v8::String> part =
+        v8::String::NewFromUtf8(isolate, it->c_str());
+    v8::Handle<v8::Value> value = object->Get(part);
+
+    if (!value->IsObject()) {
+      *error = "the property '" + *it + "' in the path is undefined";
+      return v8::Undefined(isolate);
+    }
+
+    object = value.As<v8::Object>();
+  }
+  return object;
+}
+
+}  // namespace
+
+template <typename STR>
+void SplitString(const STR& str, const typename STR::value_type s,
+                 std::vector<STR>* 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<v8::Context> context,
+    const std::string& entry_point,
+    v8::Local<v8::External> user_data) {
+  std::vector<std::string> path;
+  SplitString(entry_point, '.', &path);
+  std::string basename = path.back();
+  path.pop_back();
+
+  std::string error;
+  v8::Handle<v8::Value> 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<v8::Array> params = v8::Array::New(isolate);
+  v8::Local<v8::String> 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<v8::Object>()->SetAccessor(context,
+      v8::String::NewFromUtf8(isolate, basename.c_str()),
+      TrampolineCallback, TrampolineSetterCallback, params);
+  return true;
+}
+
+// static
+bool XWalkModuleSystem::DeleteAccessorForEntryPoint(
+    v8::Handle<v8::Context> context,
+    const std::string& entry_point) {
+  std::vector<std::string> path;
+  SplitString(entry_point, '.', &path);
+  std::string basename = path.back();
+  path.pop_back();
+
+  std::string error;
+  v8::Handle<v8::Value> value = GetObjectForPath(context, path, &error);
+  if (value->IsUndefined()) {
+    LOGGER(ERROR) << "Error retrieving object for " << entry_point
+                  << " : " << error;
+    return false;
+  }
+
+  value.As<v8::Object>()->Delete(
+      v8::String::NewFromUtf8(context->GetIsolate(), basename.c_str()));
+  return true;
+}
+
+bool XWalkModuleSystem::InstallTrampoline(v8::Handle<v8::Context> context,
+                                     ExtensionModuleEntry* entry) {
+  v8::Local<v8::External> 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<std::string>::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<v8::Object> XWalkModuleSystem::RequireNative(
+    const std::string& name) {
+  NativeModuleMap::iterator it = native_modules_.find(name);
+  if (it == native_modules_.end())
+    return v8::Handle<v8::Object>();
+  return it->second->NewInstance();
+}
+
+void XWalkModuleSystem::Initialize() {
+  SCOPE_PROFILE();
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::HandleScope handle_scope(isolate);
+  v8::Handle<v8::Context> context = GetV8Context();
+  v8::Handle<v8::FunctionTemplate> require_native_template =
+      v8::Local<v8::FunctionTemplate>::New(isolate, require_native_template_);
+  v8::Handle<v8::Function> 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<v8::Context> XWalkModuleSystem::GetV8Context() {
+  return v8::Local<v8::Context>::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<v8::Value> data) {
+  v8::HandleScope handle_scope(isolate);
+  v8::Local<v8::Array> params = data.As<v8::Array>();
+  void* ptr = params->Get(
+      v8::Integer::New(isolate, 0)).As<v8::External>()->Value();
+
+  ExtensionModuleEntry* entry = static_cast<ExtensionModuleEntry*>(ptr);
+
+  if (!entry)
+    return;
+
+  v8::Handle<v8::Context> 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<v8::FunctionTemplate> require_native_template =
+      v8::Local<v8::FunctionTemplate>::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<v8::Value> XWalkModuleSystem::RefetchHolder(
+    v8::Isolate* isolate,
+    v8::Local<v8::Value> data) {
+  v8::Local<v8::Array> params = data.As<v8::Array>();
+  const std::string entry_point = *v8::String::Utf8Value(
+      params->Get(v8::Integer::New(isolate, 1)).As<v8::String>());
+
+  std::vector<std::string> path;
+  SplitString(entry_point, '.', &path);
+  path.pop_back();
+
+  std::string error;
+  return GetObjectForPath(isolate->GetCurrentContext(), path, &error);
+}
+
+// static
+void XWalkModuleSystem::TrampolineCallback(
+    v8::Local<v8::Name> property,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
+  XWalkModuleSystem::LoadExtensionForTrampoline(info.GetIsolate(), info.Data());
+  v8::Handle<v8::Value> holder = RefetchHolder(info.GetIsolate(), info.Data());
+  if (holder->IsUndefined())
+    return;
+
+  info.GetReturnValue().Set(holder.As<v8::Object>()->Get(property));
+}
+
+// static
+void XWalkModuleSystem::TrampolineSetterCallback(
+    v8::Local<v8::Name> property,
+    v8::Local<v8::Value> value,
+    const v8::PropertyCallbackInfo<void>& info) {
+  XWalkModuleSystem::LoadExtensionForTrampoline(info.GetIsolate(), info.Data());
+  v8::Handle<v8::Value> holder = RefetchHolder(info.GetIsolate(), info.Data());
+  if (holder->IsUndefined())
+    return;
+
+  holder.As<v8::Object>()->Set(property, value);
+}
+
+XWalkModuleSystem::ExtensionModuleEntry::ExtensionModuleEntry(
+    const std::string& name,
+    XWalkExtensionModule* module,
+    const std::vector<std::string>& 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<v8::Context> context,
+    const std::string& extension_name) {
+  std::vector<std::string> path;
+  SplitString(extension_name, '.', &path);
+  std::string basename = path.back();
+  path.pop_back();
+
+  std::string error;
+  v8::Handle<v8::Value> value = GetObjectForPath(context, path, &error);
+  if (value->IsUndefined()) {
+    LOGGER(ERROR) << "Error retrieving object for " << extension_name << " : "
+                  << error;
+    return;
+  }
+
+  v8::Handle<v8::String> v8_extension_name(
+      v8::String::NewFromUtf8(context->GetIsolate(), basename.c_str()));
+  value.As<v8::Object>()->ForceSet(
+      v8_extension_name, value.As<v8::Object>()->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 (file)
index 0000000..e8bf6bf
--- /dev/null
@@ -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 <v8/v8.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+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<v8::Object> NewInstance() = 0;
+  virtual ~XWalkNativeModule() {}
+};
+
+
+class XWalkModuleSystem {
+ public:
+  explicit XWalkModuleSystem(v8::Handle<v8::Context> context);
+  ~XWalkModuleSystem();
+
+  static XWalkModuleSystem* GetModuleSystemFromContext(
+      v8::Handle<v8::Context> context);
+  static void SetModuleSystemInContext(
+      std::unique_ptr<XWalkModuleSystem> module_system,
+      v8::Handle<v8::Context> context);
+  static void ResetModuleSystemFromContext(v8::Handle<v8::Context> context);
+
+  void RegisterExtensionModule(std::unique_ptr<XWalkExtensionModule> module,
+                               const std::vector<std::string>& entry_points);
+  void RegisterNativeModule(const std::string& name,
+                            std::unique_ptr<XWalkNativeModule> module);
+  v8::Handle<v8::Object> RequireNative(const std::string& name);
+
+  void Initialize();
+
+  v8::Handle<v8::Context> GetV8Context();
+
+ private:
+  struct ExtensionModuleEntry {
+    ExtensionModuleEntry(const std::string& name, XWalkExtensionModule* module,
+                         const std::vector<std::string>& entry_points);
+    ~ExtensionModuleEntry();
+    std::string name;
+    XWalkExtensionModule* module;
+    bool use_trampoline;
+    std::vector<std::string> 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<v8::Context> context,
+      const std::string& entry_point,
+      v8::Local<v8::External> user_data);
+
+  static bool DeleteAccessorForEntryPoint(v8::Handle<v8::Context> context,
+                                          const std::string& entry_point);
+
+  bool InstallTrampoline(v8::Handle<v8::Context> context,
+                         ExtensionModuleEntry* entry);
+
+  static void TrampolineCallback(
+      v8::Local<v8::Name> property,
+      const v8::PropertyCallbackInfo<v8::Value>& info);
+  static void TrampolineSetterCallback(
+      v8::Local<v8::Name> property,
+      v8::Local<v8::Value> value,
+      const v8::PropertyCallbackInfo<void>& info);
+  static void LoadExtensionForTrampoline(
+      v8::Isolate* isolate,
+      v8::Local<v8::Value> data);
+  static v8::Handle<v8::Value> RefetchHolder(
+    v8::Isolate* isolate,
+    v8::Local<v8::Value> data);
+
+  bool ContainsEntryPoint(const std::string& entry_point);
+  void MarkModulesWithTrampoline();
+  void DeleteExtensionModules();
+
+  void EnsureExtensionNamespaceIsReadOnly(v8::Handle<v8::Context> context,
+                                          const std::string& extension_name);
+
+  typedef std::vector<ExtensionModuleEntry> ExtensionModules;
+  ExtensionModules extension_modules_;
+  typedef std::map<std::string, XWalkNativeModule*> NativeModuleMap;
+  NativeModuleMap native_modules_;
+
+  v8::Persistent<v8::FunctionTemplate> require_native_template_;
+  v8::Persistent<v8::Object> 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> 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 (file)
index 0000000..4fcad37
--- /dev/null
@@ -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 <v8/v8.h>
+
+#include "common/logger.h"
+
+namespace extensions {
+
+namespace {
+
+void ForceSetPropertyCallback(
+    const v8::FunctionCallbackInfo<v8::Value>& info) {
+  if (info.Length() != 3 || !info[0]->IsObject() || !info[1]->IsString()) {
+    return;
+  }
+  info[0].As<v8::Object>()->ForceSet(info[1], info[2]);
+}
+
+// ================
+// lifecycleTracker
+// ================
+struct LifecycleTrackerWrapper {
+  v8::Global<v8::Object> handle;
+  v8::Global<v8::Function> destructor;
+};
+
+void LifecycleTrackerCleanup(
+    const v8::WeakCallbackInfo<LifecycleTrackerWrapper>& data) {
+  LifecycleTrackerWrapper* wrapper = data.GetParameter();
+
+  if (!wrapper->destructor.IsEmpty()) {
+    v8::HandleScope handle_scope(data.GetIsolate());
+    v8::Local<v8::Context> context = v8::Context::New(data.GetIsolate());
+    v8::Context::Scope scope(context);
+
+    v8::Local<v8::Function> 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<v8::Value>& info) {
+  v8::Isolate* isolate = info.GetIsolate();
+       v8::HandleScope handle_scope(info.GetIsolate());
+
+  v8::Local<v8::Object> 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<v8::ObjectTemplate> 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<v8::Object> XWalkV8ToolsModule::NewInstance() {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::EscapableHandleScope handle_scope(isolate);
+  v8::Handle<v8::ObjectTemplate> object_template =
+      v8::Local<v8::ObjectTemplate>::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 (file)
index 0000000..5b31dce
--- /dev/null
@@ -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<v8::Object> NewInstance() override;
+
+  v8::Persistent<v8::ObjectTemplate> 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 (file)
index 0000000..a030975
--- /dev/null
@@ -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 <Ecore.h>
+#include <EWebKit.h>
+#include <EWebKit_internal.h>
+#include <unistd.h>
+#include <v8.h>
+#include <dlfcn.h>
+
+#include <memory>
+#include <string>
+
+#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<common::ResourceManager> resource_manager_;
+  std::unique_ptr<common::LocaleManager> 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<v8::Context> 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<extensions::XWalkModuleSystem>(), 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<v8::Context> 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 (file)
index 0000000..f6ab6d7
--- /dev/null
@@ -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'
+  ],
+}
index 46f7630..4ab07e4 100644 (file)
 #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 (file)
--- 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',