| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  | // Copyright (c) 2015 GitHub, Inc. All rights reserved.
 | 
					
						
							|  |  |  | // Use of this source code is governed by the MIT license that can be
 | 
					
						
							|  |  |  | // found in the LICENSE file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 13:46:59 -07:00
										 |  |  | #include "shell/common/native_mate_converters/callback.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-21 23:56:33 +05:30
										 |  |  | #include "base/stl_util.h"
 | 
					
						
							| 
									
										
										
										
											2018-11-30 01:48:27 -08:00
										 |  |  | #include "content/public/browser/browser_thread.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  | #include "native_mate/dictionary.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-03 11:24:33 +08:00
										 |  |  | using content::BrowserThread; | 
					
						
							| 
									
										
										
										
											2015-11-06 20:23:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  | namespace mate { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace internal { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-28 20:44:46 +08:00
										 |  |  | struct TranslaterHolder { | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  |   explicit TranslaterHolder(v8::Isolate* isolate) | 
					
						
							|  |  |  |       : handle(isolate, v8::External::New(isolate, this)) { | 
					
						
							|  |  |  |     handle.SetWeak(this, &GC, v8::WeakCallbackType::kFinalizer); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ~TranslaterHolder() { | 
					
						
							|  |  |  |     if (!handle.IsEmpty()) { | 
					
						
							|  |  |  |       handle.ClearWeak(); | 
					
						
							|  |  |  |       handle.Reset(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static void GC(const v8::WeakCallbackInfo<TranslaterHolder>& data) { | 
					
						
							|  |  |  |     delete data.GetParameter(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v8::Global<v8::External> handle; | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  |   Translater translater; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Cached JavaScript version of |CallTranslater|.
 | 
					
						
							|  |  |  | v8::Persistent<v8::FunctionTemplate> g_call_translater; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-28 20:44:46 +08:00
										 |  |  | void CallTranslater(v8::Local<v8::External> external, | 
					
						
							|  |  |  |                     v8::Local<v8::Object> state, | 
					
						
							|  |  |  |                     mate::Arguments* args) { | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  |   // Whether the callback should only be called for once.
 | 
					
						
							| 
									
										
										
										
											2015-10-28 20:44:46 +08:00
										 |  |  |   v8::Isolate* isolate = args->isolate(); | 
					
						
							| 
									
										
										
										
											2019-01-09 11:17:05 -08:00
										 |  |  |   auto context = isolate->GetCurrentContext(); | 
					
						
							|  |  |  |   bool one_time = | 
					
						
							|  |  |  |       state->Has(context, mate::StringToSymbol(isolate, "oneTime")).ToChecked(); | 
					
						
							| 
									
										
										
										
											2015-10-28 20:44:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Check if the callback has already been called.
 | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  |   if (one_time) { | 
					
						
							|  |  |  |     auto called_symbol = mate::StringToSymbol(isolate, "called"); | 
					
						
							| 
									
										
										
										
											2019-01-09 11:17:05 -08:00
										 |  |  |     if (state->Has(context, called_symbol).ToChecked()) { | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  |       args->ThrowError("callback can only be called for once"); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-01-09 11:17:05 -08:00
										 |  |  |       state->Set(context, called_symbol, v8::Boolean::New(isolate, true)) | 
					
						
							|  |  |  |           .ToChecked(); | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-10-28 20:44:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   TranslaterHolder* holder = static_cast<TranslaterHolder*>(external->Value()); | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  |   holder->translater.Run(args); | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Free immediately for one-time callback.
 | 
					
						
							|  |  |  |   if (one_time) | 
					
						
							|  |  |  |     delete holder; | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-03 11:24:33 +08:00
										 |  |  | // Destroy the class on UI thread when possible.
 | 
					
						
							|  |  |  | struct DeleteOnUIThread { | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |   template <typename T> | 
					
						
							| 
									
										
										
										
											2015-12-03 11:24:33 +08:00
										 |  |  |   static void Destruct(const T* x) { | 
					
						
							|  |  |  |     if (Locker::IsBrowserProcess() && | 
					
						
							|  |  |  |         !BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 
					
						
							|  |  |  |       BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, x); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       delete x; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Like v8::Global, but ref-counted.
 | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  | template <typename T> | 
					
						
							|  |  |  | class RefCountedGlobal | 
					
						
							|  |  |  |     : public base::RefCountedThreadSafe<RefCountedGlobal<T>, DeleteOnUIThread> { | 
					
						
							| 
									
										
										
										
											2015-12-03 11:24:33 +08:00
										 |  |  |  public: | 
					
						
							|  |  |  |   RefCountedGlobal(v8::Isolate* isolate, v8::Local<v8::Value> value) | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |       : handle_(isolate, v8::Local<T>::Cast(value)) {} | 
					
						
							| 
									
										
										
										
											2015-12-03 11:24:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |   bool IsAlive() const { return !handle_.IsEmpty(); } | 
					
						
							| 
									
										
										
										
											2015-12-03 11:24:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   v8::Local<T> NewHandle(v8::Isolate* isolate) const { | 
					
						
							|  |  |  |     return v8::Local<T>::New(isolate, handle_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  private: | 
					
						
							|  |  |  |   v8::Global<T> handle_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   DISALLOW_COPY_AND_ASSIGN(RefCountedGlobal); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-06 20:23:41 +08:00
										 |  |  | SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value) | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |     : v8_function_(new RefCountedGlobal<v8::Function>(isolate, value)) {} | 
					
						
							| 
									
										
										
										
											2015-11-06 20:23:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | SafeV8Function::SafeV8Function(const SafeV8Function& other) | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |     : v8_function_(other.v8_function_) {} | 
					
						
							| 
									
										
										
										
											2015-11-06 20:23:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  | SafeV8Function::~SafeV8Function() {} | 
					
						
							| 
									
										
										
										
											2015-11-06 20:23:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-03 11:24:33 +08:00
										 |  |  | bool SafeV8Function::IsAlive() const { | 
					
						
							|  |  |  |   return v8_function_.get() && v8_function_->IsAlive(); | 
					
						
							| 
									
										
										
										
											2015-11-06 20:23:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-03 11:24:33 +08:00
										 |  |  | v8::Local<v8::Function> SafeV8Function::NewHandle(v8::Isolate* isolate) const { | 
					
						
							|  |  |  |   return v8_function_->NewHandle(isolate); | 
					
						
							| 
									
										
										
										
											2015-11-06 20:23:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-05 10:38:27 -05:00
										 |  |  | v8::Local<v8::Value> CreateFunctionFromTranslater(v8::Isolate* isolate, | 
					
						
							|  |  |  |                                                   const Translater& translater, | 
					
						
							|  |  |  |                                                   bool one_time) { | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  |   // The FunctionTemplate is cached.
 | 
					
						
							|  |  |  |   if (g_call_translater.IsEmpty()) | 
					
						
							| 
									
										
										
										
											2019-05-29 13:02:15 -07:00
										 |  |  |     g_call_translater.Reset(isolate, | 
					
						
							|  |  |  |                             mate::CreateFunctionTemplate( | 
					
						
							|  |  |  |                                 isolate, base::BindRepeating(&CallTranslater))); | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   v8::Local<v8::FunctionTemplate> call_translater = | 
					
						
							|  |  |  |       v8::Local<v8::FunctionTemplate>::New(isolate, g_call_translater); | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  |   auto* holder = new TranslaterHolder(isolate); | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  |   holder->translater = translater; | 
					
						
							| 
									
										
										
										
											2018-10-04 23:13:09 +09:00
										 |  |  |   Dictionary state = mate::Dictionary::CreateEmpty(isolate); | 
					
						
							|  |  |  |   if (one_time) | 
					
						
							|  |  |  |     state.Set("oneTime", true); | 
					
						
							| 
									
										
										
										
											2019-01-09 11:17:05 -08:00
										 |  |  |   auto context = isolate->GetCurrentContext(); | 
					
						
							|  |  |  |   return BindFunctionWith( | 
					
						
							|  |  |  |       isolate, context, call_translater->GetFunction(context).ToLocalChecked(), | 
					
						
							|  |  |  |       holder->handle.Get(isolate), state.GetHandle()); | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 15:00:41 -03:00
										 |  |  | // func.bind(func, arg1).
 | 
					
						
							|  |  |  | // NB(zcbenz): Using C++11 version crashes VS.
 | 
					
						
							|  |  |  | v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate, | 
					
						
							|  |  |  |                                       v8::Local<v8::Context> context, | 
					
						
							|  |  |  |                                       v8::Local<v8::Function> func, | 
					
						
							|  |  |  |                                       v8::Local<v8::Value> arg1, | 
					
						
							|  |  |  |                                       v8::Local<v8::Value> arg2) { | 
					
						
							| 
									
										
										
										
											2019-04-30 20:18:22 -04:00
										 |  |  |   v8::MaybeLocal<v8::Value> bind = | 
					
						
							|  |  |  |       func->Get(context, mate::StringToV8(isolate, "bind")); | 
					
						
							| 
									
										
										
										
											2017-11-03 15:00:41 -03:00
										 |  |  |   CHECK(!bind.IsEmpty()); | 
					
						
							|  |  |  |   v8::Local<v8::Function> bind_func = | 
					
						
							|  |  |  |       v8::Local<v8::Function>::Cast(bind.ToLocalChecked()); | 
					
						
							|  |  |  |   v8::Local<v8::Value> converted[] = {func, arg1, arg2}; | 
					
						
							| 
									
										
										
										
											2019-01-21 23:56:33 +05:30
										 |  |  |   return bind_func->Call(context, func, base::size(converted), converted) | 
					
						
							| 
									
										
										
										
											2017-11-03 15:00:41 -03:00
										 |  |  |       .ToLocalChecked(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-28 17:36:01 +08:00
										 |  |  | }  // namespace internal
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace mate
 |