Run Tizen Webapps in single process mode
[platform/framework/web/crosswalk-tizen.git] / atom / common / native_mate_converters / callback.cc
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 #include "atom/common/native_mate_converters/callback.h"
6 #include "tizen/common/env_variables.h"
7
8 using content::BrowserThread;
9
10 namespace mate {
11
12 namespace internal {
13
14 namespace {
15
16 struct TranslaterHolder {
17   Translater translater;
18 };
19
20 // Cached JavaScript version of |CallTranslater|.
21 v8::Persistent<v8::FunctionTemplate> g_call_translater;
22
23 void CallTranslater(v8::Local<v8::External> external,
24                     v8::Local<v8::Object> state,
25                     mate::Arguments* args) {
26   v8::Isolate* isolate = args->isolate();
27
28   // Check if the callback has already been called.
29   v8::Local<v8::String> called_symbol = mate::StringToSymbol(isolate, "called");
30   if (state->Has(called_symbol)) {
31     args->ThrowError("callback can only be called for once");
32     return;
33   } else {
34     state->Set(called_symbol, v8::Boolean::New(isolate, true));
35   }
36
37   TranslaterHolder* holder = static_cast<TranslaterHolder*>(external->Value());
38   holder->translater.Run(args);
39   delete holder;
40 }
41
42 // func.bind(func, arg1).
43 // NB(zcbenz): Using C++11 version crashes VS.
44 v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
45                                       v8::Local<v8::Context> context,
46                                       v8::Local<v8::Function> func,
47                                       v8::Local<v8::Value> arg1,
48                                       v8::Local<v8::Value> arg2) {
49   v8::MaybeLocal<v8::Value> bind = func->Get(mate::StringToV8(isolate, "bind"));
50   CHECK(!bind.IsEmpty());
51   v8::Local<v8::Function> bind_func =
52       v8::Local<v8::Function>::Cast(bind.ToLocalChecked());
53   v8::Local<v8::Value> converted[] = { func, arg1, arg2 };
54   return bind_func->Call(
55       context, func, arraysize(converted), converted).ToLocalChecked();
56 }
57
58 }  // namespace
59
60 // Destroy the class on UI thread when possible.
61 struct DeleteOnUIThread {
62   template<typename T>
63   static void Destruct(const T* x) {
64     if ((::tizen::is_single_process || Locker::IsBrowserProcess()) &&
65         !BrowserThread::CurrentlyOn(BrowserThread::UI)) {
66       BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, x);
67     } else {
68       delete x;
69     }
70   }
71 };
72
73 // Like v8::Global, but ref-counted.
74 template<typename T>
75 class RefCountedGlobal : public base::RefCountedThreadSafe<RefCountedGlobal<T>,
76                                                            DeleteOnUIThread> {
77  public:
78   RefCountedGlobal(v8::Isolate* isolate, v8::Local<v8::Value> value)
79       : handle_(isolate, v8::Local<T>::Cast(value)) {
80   }
81
82   bool IsAlive() const {
83     return !handle_.IsEmpty();
84   }
85
86   v8::Local<T> NewHandle(v8::Isolate* isolate) const {
87     return v8::Local<T>::New(isolate, handle_);
88   }
89
90  private:
91   v8::Global<T> handle_;
92
93   DISALLOW_COPY_AND_ASSIGN(RefCountedGlobal);
94 };
95
96 SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value)
97     : v8_function_(new RefCountedGlobal<v8::Function>(isolate, value)) {
98 }
99
100 SafeV8Function::SafeV8Function(const SafeV8Function& other)
101     : v8_function_(other.v8_function_) {
102 }
103
104 SafeV8Function::~SafeV8Function() {
105 }
106
107 bool SafeV8Function::IsAlive() const {
108   return v8_function_.get() && v8_function_->IsAlive();
109 }
110
111 v8::Local<v8::Function> SafeV8Function::NewHandle(v8::Isolate* isolate) const {
112   return v8_function_->NewHandle(isolate);
113 }
114
115 v8::Local<v8::Value> CreateFunctionFromTranslater(
116     v8::Isolate* isolate, const Translater& translater) {
117   // The FunctionTemplate is cached.
118   if (g_call_translater.IsEmpty())
119     g_call_translater.Reset(
120         isolate,
121         mate::CreateFunctionTemplate(isolate, base::Bind(&CallTranslater)));
122
123   v8::Local<v8::FunctionTemplate> call_translater =
124       v8::Local<v8::FunctionTemplate>::New(isolate, g_call_translater);
125   auto* holder = new TranslaterHolder;
126   holder->translater = translater;
127   return BindFunctionWith(isolate,
128                           isolate->GetCurrentContext(),
129                           call_translater->GetFunction(),
130                           v8::External::New(isolate, holder),
131                           v8::Object::New(isolate));
132 }
133
134 }  // namespace internal
135
136 }  // namespace mate