Run Tizen Webapps in single process mode
[platform/framework/web/crosswalk-tizen.git] / atom / common / native_mate_converters / callback.h
1 // Copyright (c) 2015 GitHub, Inc. All rights reserved.
2 // Use of this source code is governed by the MIT license that can be
3 // found in the LICENSE file.
4
5 #ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_
6 #define ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_
7
8 #include <vector>
9
10 #include "atom/common/api/locker.h"
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "native_mate/function_template.h"
17 #include "native_mate/scoped_persistent.h"
18
19 namespace mate {
20
21 namespace internal {
22
23 template<typename T>
24 class RefCountedGlobal;
25
26 // Manages the V8 function with RAII.
27 class SafeV8Function {
28  public:
29   SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value);
30   SafeV8Function(const SafeV8Function& other);
31   ~SafeV8Function();
32
33   bool IsAlive() const;
34   v8::Local<v8::Function> NewHandle(v8::Isolate* isolate) const;
35
36  private:
37   scoped_refptr<RefCountedGlobal<v8::Function>> v8_function_;
38 };
39
40 // Helper to invoke a V8 function with C++ parameters.
41 template <typename Sig>
42 struct V8FunctionInvoker {};
43
44 template <typename... ArgTypes>
45 struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
46   static v8::Local<v8::Value> Go(v8::Isolate* isolate,
47                                  const SafeV8Function& function,
48                                  ArgTypes... raw) {
49     if (!::tizen::is_single_process)
50       Locker locker(isolate);
51     v8::EscapableHandleScope handle_scope(isolate);
52     if (!function.IsAlive())
53       return v8::Null(isolate);
54     v8::MicrotasksScope script_scope(isolate,
55                                      v8::MicrotasksScope::kRunMicrotasks);
56     v8::Local<v8::Function> holder = function.NewHandle(isolate);
57     v8::Local<v8::Context> context = holder->CreationContext();
58     v8::Context::Scope context_scope(context);
59     std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
60     v8::Local<v8::Value> ret(holder->Call(holder, args.size(), &args.front()));
61     return handle_scope.Escape(ret);
62   }
63 };
64
65 template <typename... ArgTypes>
66 struct V8FunctionInvoker<void(ArgTypes...)> {
67   static void Go(v8::Isolate* isolate,
68                  const SafeV8Function& function,
69                  ArgTypes... raw) {
70     if (!::tizen::is_single_process)
71       Locker locker(isolate);
72     v8::HandleScope handle_scope(isolate);
73     if (!function.IsAlive())
74       return;
75     v8::MicrotasksScope script_scope(isolate,
76                                      v8::MicrotasksScope::kRunMicrotasks);
77     v8::Local<v8::Function> holder = function.NewHandle(isolate);
78     v8::Local<v8::Context> context = holder->CreationContext();
79     v8::Context::Scope context_scope(context);
80     std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
81     holder->Call(holder, args.size(), &args.front());
82   }
83 };
84
85 template <typename ReturnType, typename... ArgTypes>
86 struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
87   static ReturnType Go(v8::Isolate* isolate,
88                        const SafeV8Function& function,
89                        ArgTypes... raw) {
90     Locker locker(isolate);
91     v8::HandleScope handle_scope(isolate);
92     ReturnType ret = ReturnType();
93     if (!function.IsAlive())
94       return ret;
95     v8::MicrotasksScope script_scope(isolate,
96                                      v8::MicrotasksScope::kRunMicrotasks);
97     v8::Local<v8::Function> holder = function.NewHandle(isolate);
98     v8::Local<v8::Context> context = holder->CreationContext();
99     v8::Context::Scope context_scope(context);
100     std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
101     v8::Local<v8::Value> result;
102     auto maybe_result =
103         holder->Call(context, holder, args.size(), &args.front());
104     if (maybe_result.ToLocal(&result))
105       Converter<ReturnType>::FromV8(isolate, result, &ret);
106     return ret;
107   }
108 };
109
110 // Helper to pass a C++ funtion to JavaScript.
111 using Translater = base::Callback<void(Arguments* args)>;
112 v8::Local<v8::Value> CreateFunctionFromTranslater(
113     v8::Isolate* isolate, const Translater& translater);
114
115 // Calls callback with Arguments.
116 template <typename Sig>
117 struct NativeFunctionInvoker {};
118
119 template <typename ReturnType, typename... ArgTypes>
120 struct NativeFunctionInvoker<ReturnType(ArgTypes...)> {
121   static void Go(base::Callback<ReturnType(ArgTypes...)> val, Arguments* args) {
122     using Indices = typename IndicesGenerator<sizeof...(ArgTypes)>::type;
123     Invoker<Indices, ArgTypes...> invoker(args, 0);
124     if (invoker.IsOK())
125       invoker.DispatchToCallback(val);
126   }
127 };
128
129 }  // namespace internal
130
131 template<typename Sig>
132 struct Converter<base::Callback<Sig>> {
133   static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
134                                    const base::Callback<Sig>& val) {
135     // We don't use CreateFunctionTemplate here because it creates a new
136     // FunctionTemplate everytime, which is cached by V8 and causes leaks.
137     internal::Translater translater = base::Bind(
138         &internal::NativeFunctionInvoker<Sig>::Go, val);
139     return internal::CreateFunctionFromTranslater(isolate, translater);
140   }
141   static bool FromV8(v8::Isolate* isolate,
142                      v8::Local<v8::Value> val,
143                      base::Callback<Sig>* out) {
144     if (!val->IsFunction())
145       return false;
146
147     *out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go,
148                       isolate, internal::SafeV8Function(isolate, val));
149     return true;
150   }
151 };
152
153 }  // namespace mate
154
155 #endif  // ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_