Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

724 lines
29 KiB

  1. //=========== Copyright Valve Corporation, All rights reserved. ===============//
  2. //
  3. // Purpose:
  4. //=============================================================================//
  5. #ifndef UIJSREGISTRATION_H
  6. #define UIJSREGISTRATION_H
  7. #pragma once
  8. #include "../panorama/uiengine.h"
  9. #if defined( OSX ) && !defined( SOURCE2_PANORAMA )
  10. #include <tr1/tuple>
  11. #include <tr1/utility>
  12. #define STDTR1 std::tr1
  13. #else
  14. #define STDTR1 std
  15. #endif
  16. #if _GNUC
  17. #pragma GCC diagnostic push
  18. #pragma GCC diagnostic ignored "-Wuninitialized"
  19. #endif // _GNUC
  20. #ifdef None
  21. #undef None // X11 defines None breaking the ability to use v8::None down below, so remove the preprocessor macro here
  22. #endif
  23. #pragma warning(push)
  24. //warning C4700 : uninitialized local variable 'getcaster' used -- we'll do a lot of this, but its ok
  25. #pragma warning( disable : 4700 )
  26. namespace panorama
  27. {
  28. template<typename T> struct RegisterJSTypeDeducer_t { static RegisterJSType_t Type() { return k_ERegisterJSTypeUnknown; } };
  29. #define PANORAMA_DECLARE_DEDUCE_JSTYPE( _JSType, _T ) template<> struct RegisterJSTypeDeducer_t<_T> { static RegisterJSType_t Type() { return k_ERegisterJSType##_JSType; } };
  30. PANORAMA_DECLARE_DEDUCE_JSTYPE( Void, void )
  31. PANORAMA_DECLARE_DEDUCE_JSTYPE( Bool, bool )
  32. PANORAMA_DECLARE_DEDUCE_JSTYPE( Int8, int8 )
  33. PANORAMA_DECLARE_DEDUCE_JSTYPE( Uint8, uint8 )
  34. PANORAMA_DECLARE_DEDUCE_JSTYPE( Int16, int16 )
  35. PANORAMA_DECLARE_DEDUCE_JSTYPE( Uint16, uint16 )
  36. PANORAMA_DECLARE_DEDUCE_JSTYPE( Int32, int32 )
  37. PANORAMA_DECLARE_DEDUCE_JSTYPE( Uint32, uint32 )
  38. PANORAMA_DECLARE_DEDUCE_JSTYPE( Int64, int64 )
  39. PANORAMA_DECLARE_DEDUCE_JSTYPE( Uint64, uint64 )
  40. PANORAMA_DECLARE_DEDUCE_JSTYPE( Float, float )
  41. PANORAMA_DECLARE_DEDUCE_JSTYPE( Double, double )
  42. PANORAMA_DECLARE_DEDUCE_JSTYPE( ConstString, const char * )
  43. PANORAMA_DECLARE_DEDUCE_JSTYPE( PanoramaSymbol, CPanoramaSymbol )
  44. PANORAMA_DECLARE_DEDUCE_JSTYPE( RawV8Args, const v8::FunctionCallbackInfo<v8::Value>& )
  45. inline void JSCheckObjectValidity( const v8::FunctionCallbackInfo<v8::Value>& args )
  46. {
  47. // Don't use helper for getting panel, as it will throw exception, which we don't want in just this function
  48. v8::Local<v8::Object> obj = args.Holder();
  49. if( obj->InternalFieldCount() != 1 )
  50. {
  51. v8::Handle< v8::Boolean > value = v8::Boolean::New( args.GetIsolate(), false );
  52. args.GetReturnValue().Set( value );
  53. }
  54. v8::Local<v8::External> wrap = v8::Local<v8::External>::Cast( obj->GetInternalField( 0 ) );
  55. void *pPanel = (void*)wrap->Value();
  56. if( !pPanel )
  57. {
  58. v8::Handle< v8::Boolean > value = v8::Boolean::New( args.GetIsolate(), false );
  59. args.GetReturnValue().Set( value );
  60. }
  61. else
  62. {
  63. v8::Handle< v8::Boolean > value = v8::Boolean::New( args.GetIsolate(), true );
  64. args.GetReturnValue().Set( value );
  65. }
  66. }
  67. // Register special IsValid(), which makes the JS obj like a safe handle where you can use this
  68. // to check if the obj has been deleted in C++ and is gone. You must still track all objects that are
  69. // created and set their internal value to 0 so they point at nothing to make this work.
  70. inline void RegisterJSIsValid()
  71. {
  72. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  73. v8::HandleScope handle_scope( GetV8Isolate() );
  74. v8::Handle<v8::ObjectTemplate> objTemplate = UIEngine()->GetCurrentV8ObjectTemplateToSetup();
  75. objTemplate->Set( v8::String::NewFromUtf8( GetV8Isolate(), "IsValid" ), v8::FunctionTemplate::New( GetV8Isolate(), &JSCheckObjectValidity ) );
  76. }
  77. // Register a member to expose to JavaScript as read/write
  78. template< typename ObjType, typename MemberType >
  79. void RegisterJSAccessor( const char *jsMemberName, MemberType( ObjType::*pGetFunc )() const, void(ObjType::*pSetFunc)(MemberType), const char *pDesc = NULL );
  80. // Register a read-only member to expose to JavaScript
  81. template< typename ObjType, typename MemberType >
  82. void RegisterJSAccessorReadOnly( const char *jsMemberName, MemberType( ObjType::*pGetFunc )() const, const char *pDesc = NULL );
  83. template < typename ObjType, typename RetType, typename ...Args>
  84. void RegisterJSMethod( const char *pchMethodName, RetType( ObjType::*mf )(Args...) const, const char *pDesc = NULL );
  85. template <typename T>
  86. void RegisterJSConstantValue( const char *pchJSMemberName, T value, const char *pDesc = NULL );
  87. template < typename RetType, typename ...Args>
  88. void RegisterJSGlobalFunction( const char *pchJSFunctionName, RetType(*pFunc)(Args...), bool bTrueGlobal = false, const char *pDesc = NULL );
  89. //
  90. // Everything below here is internals, and should be ignored if you aren't adding additional type
  91. // support inside panorama itself.
  92. //
  93. template< typename ObjType> ObjType* GetThisPtrForJSCall( v8::Local<v8::Object> self )
  94. {
  95. v8::Local<v8::External> wrap = v8::Local<v8::External>::Cast( self->GetInternalField( 0 ) );
  96. ObjType *pPanel = (ObjType*)wrap->Value();
  97. if( pPanel && panorama_is_base_of< IUIPanelClient, ObjType >::value )
  98. {
  99. IUIPanel *pUIPanel = (IUIPanel*)(pPanel);
  100. pPanel = (ObjType*)(pUIPanel->ClientPtr());
  101. }
  102. if( !pPanel )
  103. {
  104. GetV8Isolate()->ThrowException( v8::String::NewFromUtf8( GetV8Isolate(), "Underlying object is deleted!" ) );
  105. return NULL;
  106. }
  107. return pPanel;
  108. }
  109. template < typename T > void GetPtrToCallbackArray( T pGetFunc, v8::Handle<v8::Array> &callbackArray );
  110. template < typename T > void SetPtrToCallbackArray( T pSetFunc, v8::Handle<v8::Array> &callbackArray );
  111. struct funcbytes
  112. {
  113. void * v1;
  114. void * v2;
  115. void * v3;
  116. };
  117. template< typename T> union HACKY_FUNC_PTR_CASTER
  118. {
  119. T funcPtr;
  120. funcbytes funcBytes;
  121. };
  122. template< typename T> void RestoreFuncPtr( HACKY_FUNC_PTR_CASTER< T > &caster, v8::Local<v8::Array> &callbackArray, int iOffset )
  123. {
  124. Assert( (int)callbackArray->Length() >= iOffset + 3 );
  125. caster.funcBytes.v1 = v8::Local<v8::External>::Cast( callbackArray->Get( iOffset++ ) )->Value();
  126. caster.funcBytes.v2 = v8::Local<v8::External>::Cast( callbackArray->Get( iOffset++ ) )->Value();
  127. caster.funcBytes.v3 = v8::Local<v8::External>::Cast( callbackArray->Get( iOffset++ ) )->Value();
  128. }
  129. template <typename T>
  130. void RegisterJSConstantValue( const char *pchJSMemberName, T value, const char *pDesc )
  131. {
  132. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  133. v8::HandleScope handle_scope( GetV8Isolate() );
  134. v8::Handle<v8::ObjectTemplate> objTemplate = UIEngine()->GetCurrentV8ObjectTemplateToSetup();
  135. v8::Handle<v8::Value> val;
  136. PanoramaTypeToV8Param( value, &val );
  137. objTemplate->Set( v8::String::NewFromUtf8( GetV8Isolate(), pchJSMemberName ), val, v8::PropertyAttribute( v8::ReadOnly | v8::DontDelete ) );
  138. UIEngine()->NewRegisterJSEntry( pchJSMemberName, RegisterJSEntryInfo_t::k_EConstantValue, pDesc, RegisterJSTypeDeducer_t<T>::Type() );
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: More heavily templated helper for registering accessors of various types. We'll
  142. // expose explicit more strongly typed versions, but this avoids duplicating setup code in each.
  143. //-----------------------------------------------------------------------------
  144. template <typename JSGetterCallback, typename JSSetterCallback, typename ObjGetMethod, typename ObjSetMethod>
  145. void RegisterJSAccessorInternal( const char *pchJSMemberName, ObjGetMethod pGetFunc, ObjSetMethod pSetFunc, JSGetterCallback pGetCallback, JSSetterCallback pSetCallback, const char *pDesc = NULL, RegisterJSType_t eDataType = k_ERegisterJSTypeUnknown )
  146. {
  147. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  148. v8::HandleScope handle_scope( GetV8Isolate() );
  149. v8::Handle<v8::Array> callbackArray = v8::Array::New( GetV8Isolate(), 6 );
  150. GetPtrToCallbackArray( pGetFunc, callbackArray );
  151. SetPtrToCallbackArray( pSetFunc, callbackArray );
  152. v8::Handle<v8::ObjectTemplate> objTemplate = UIEngine()->GetCurrentV8ObjectTemplateToSetup();
  153. if( pSetFunc )
  154. objTemplate->SetAccessor( v8::String::NewFromUtf8( GetV8Isolate(), pchJSMemberName ), pGetCallback, pSetCallback, callbackArray, v8::DEFAULT, v8::None );
  155. else
  156. objTemplate->SetAccessor( v8::String::NewFromUtf8( GetV8Isolate(), pchJSMemberName ), pGetCallback, 0, callbackArray, v8::DEFAULT, v8::ReadOnly );
  157. UIEngine()->NewRegisterJSEntry( pchJSMemberName, pSetFunc ? RegisterJSEntryInfo_t::k_EAccessor : RegisterJSEntryInfo_t::k_EAccessorReadOnly, pDesc, eDataType );
  158. }
  159. template < class ObjType, class T > class CJSPropGetter
  160. {
  161. public:
  162. static void GetProp( v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info )
  163. {
  164. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  165. v8::HandleScope handle_scope( GetV8Isolate() );
  166. ObjType *pPanel = GetThisPtrForJSCall<ObjType>( info.Holder() );
  167. if( !pPanel )
  168. return;
  169. v8::Local<v8::Array> callbackArray = v8::Local<v8::Array>::Cast( info.Data() );
  170. HACKY_FUNC_PTR_CASTER< T( ObjType::* )() const > caster;
  171. RestoreFuncPtr( caster, callbackArray, 0 );
  172. v8::Handle< v8::Value > val;
  173. T nativeval = (pPanel->*caster.funcPtr)();
  174. PanoramaTypeToV8Param( nativeval, &val );
  175. info.GetReturnValue().Set( val );
  176. }
  177. static void SetProp( v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info )
  178. {
  179. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  180. v8::HandleScope handle_scope( GetV8Isolate() );
  181. ObjType *pPanel = GetThisPtrForJSCall<ObjType>( info.Holder() );
  182. if( !pPanel )
  183. return;
  184. v8::Local<v8::Array> callbackArray = v8::Local<v8::Array>::Cast( info.Data() );
  185. HACKY_FUNC_PTR_CASTER< void (ObjType::*)(T) > caster;
  186. RestoreFuncPtr( caster, callbackArray, 3 );
  187. T val;
  188. V8ParamToPanoramaType( value, &val );
  189. (pPanel->*caster.funcPtr)(val);
  190. FreeConvertedParam( val );
  191. }
  192. };
  193. //-----------------------------------------------------------------------------
  194. // Purpose: Register a float member to expose to JavaScript, can pass NULL for pSetFunc if this is only able to be read not written
  195. //-----------------------------------------------------------------------------
  196. template< typename ObjType, typename MemberType >
  197. void RegisterJSAccessor( const char *jsMemberName, MemberType( ObjType::*pGetFunc )() const, void(ObjType::*pSetFunc)(MemberType), const char *pDesc )
  198. {
  199. RegisterJSAccessorInternal( jsMemberName, pGetFunc, pSetFunc, &CJSPropGetter<ObjType, MemberType>::GetProp, &CJSPropGetter<ObjType, MemberType>::SetProp, pDesc, RegisterJSTypeDeducer_t<MemberType>::Type() );
  200. }
  201. // Register a read-only member to expose to JavaScript
  202. template< typename ObjType, typename MemberType >
  203. void RegisterJSAccessorReadOnly( const char *jsMemberName, MemberType( ObjType::*pGetFunc )() const, const char *pDesc )
  204. {
  205. RegisterJSAccessorInternal( jsMemberName, pGetFunc, 0, &CJSPropGetter<ObjType, MemberType>::GetProp, &CJSPropGetter<ObjType, MemberType>::SetProp, pDesc, RegisterJSTypeDeducer_t<MemberType>::Type() );
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose: Convert a v8 argument to native panorama type
  209. //-----------------------------------------------------------------------------
  210. template< typename T> bool BConvertV8ArgToPanorama( const v8::Handle<v8::Value> &val, T *pNativeVal )
  211. {
  212. v8::TryCatch try_catch;
  213. V8ParamToPanoramaType( val, pNativeVal );
  214. if( try_catch.HasCaught() )
  215. {
  216. UIEngine()->OutputJSExceptionToConsole( try_catch, UIEngine()->GetPanelForJavaScriptContext( *(GetV8Isolate()->GetCurrentContext()) ) );
  217. return false;
  218. }
  219. return true;
  220. }
  221. void JSCheckObjectValidity( const v8::FunctionCallbackInfo<v8::Value>& args );
  222. //-----------------------------------------------------------------------------
  223. // Purpose: Helper for passing function pointers into js data callback
  224. //-----------------------------------------------------------------------------
  225. template < typename T > void GetPtrToCallbackArray( T pGetFunc, v8::Handle<v8::Array> &callbackArray )
  226. {
  227. COMPILE_TIME_ASSERT( sizeof( T ) <= sizeof( funcbytes ) );
  228. Assert( callbackArray->Length() >= 3 );
  229. HACKY_FUNC_PTR_CASTER< T > getcaster;
  230. // single a legit GCC warning when our func pointers are 2 bytes, not 3
  231. getcaster.funcBytes.v3 = NULL;
  232. getcaster.funcPtr = pGetFunc;
  233. callbackArray->Set( 0, v8::External::New( GetV8Isolate(), getcaster.funcBytes.v1 ) );
  234. callbackArray->Set( 1, v8::External::New( GetV8Isolate(), getcaster.funcBytes.v2 ) );
  235. callbackArray->Set( 2, v8::External::New( GetV8Isolate(), getcaster.funcBytes.v3 ) );
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Purpose: Helper for passing function pointers into js data callback
  239. //-----------------------------------------------------------------------------
  240. template < typename T > void SetPtrToCallbackArray( T pSetFunc, v8::Handle<v8::Array> &callbackArray )
  241. {
  242. COMPILE_TIME_ASSERT( sizeof( T ) <= sizeof( funcbytes ) );
  243. Assert( callbackArray->Length() >= 6 );
  244. if( pSetFunc )
  245. {
  246. HACKY_FUNC_PTR_CASTER< T > setcaster;
  247. // single a legit GCC warning when our func pointers are 2 bytes, not 3
  248. setcaster.funcBytes.v3 = NULL;
  249. setcaster.funcPtr = pSetFunc;
  250. callbackArray->Set( 3, v8::External::New( GetV8Isolate(), setcaster.funcBytes.v1 ) );
  251. callbackArray->Set( 4, v8::External::New( GetV8Isolate(), setcaster.funcBytes.v2 ) );
  252. callbackArray->Set( 5, v8::External::New( GetV8Isolate(), setcaster.funcBytes.v3 ) );
  253. }
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose: Handler for JS method call callbacks
  257. //-----------------------------------------------------------------------------
  258. // two JSMethodCallbackWrappers to handle void callbacks & callbacks with return values
  259. template< typename RetType, typename ObjType, typename ...Args >
  260. struct JSMethodCallbackWrapper
  261. {
  262. static void Call( ObjType *pObject, RetType( ObjType::*mf )(Args...), const v8::FunctionCallbackInfo<v8::Value>& v8Args, Args... args )
  263. {
  264. RetType ret = (pObject->*mf)(panorama_forward< Args >( args )...);
  265. v8::Handle< v8::Value > value;
  266. PanoramaTypeToV8Param( ret, &value );
  267. v8Args.GetReturnValue().Set( value );
  268. }
  269. };
  270. template< typename ObjType, typename ...Args >
  271. struct JSMethodCallbackWrapper< void, ObjType, Args... >
  272. {
  273. static void Call( ObjType *pObject, void(ObjType::*mf)(Args...), const v8::FunctionCallbackInfo<v8::Value>& v8Args, Args... args )
  274. {
  275. (pObject->*mf)(panorama_forward< Args >( args )...);
  276. }
  277. };
  278. template< typename RetType, typename ...Args >
  279. struct JSFunctionCallbackWrapper
  280. {
  281. static void Call( RetType( *mf )(Args...), const v8::FunctionCallbackInfo<v8::Value>& v8Args, Args... args )
  282. {
  283. RetType ret = mf(panorama_forward< Args >( args )... );
  284. v8::Handle< v8::Value > value;
  285. PanoramaTypeToV8Param( ret, &value );
  286. v8Args.GetReturnValue().Set( value );
  287. }
  288. };
  289. template< typename ...Args >
  290. struct JSFunctionCallbackWrapper < void, Args... >
  291. {
  292. static void Call( void(*mf)(Args...), const v8::FunctionCallbackInfo<v8::Value>& v8Args, Args... args )
  293. {
  294. mf(panorama_forward< Args >( args )...);
  295. }
  296. };
  297. // helper to generate a sequences of index to iterate
  298. template<int...> struct index_tuple {};
  299. template<int I, typename IndexTuple, typename... Types>
  300. struct make_indexes_impl;
  301. template<int I, int... Indexes, typename T, typename ... Types>
  302. struct make_indexes_impl < I, index_tuple<Indexes...>, T, Types... >
  303. {
  304. typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
  305. };
  306. template<int I, int... Indexes>
  307. struct make_indexes_impl < I, index_tuple<Indexes...> >
  308. {
  309. typedef index_tuple<Indexes...> type;
  310. };
  311. template<typename ... Types>
  312. struct make_indexes : make_indexes_impl < 0, index_tuple<>, Types... >
  313. {
  314. };
  315. // Expands values in tuple into a single function call
  316. template< typename ObjType, typename RetType, typename TupleType, class... Args, int... Indexes >
  317. void JSMethodCallTuple_Helper( ObjType *pPanel, RetType( ObjType::*mf )(Args...), const v8::FunctionCallbackInfo<v8::Value> &args, index_tuple< Indexes... >, TupleType &tup )
  318. {
  319. JSMethodCallbackWrapper< RetType, ObjType, Args... >::Call( pPanel, mf, args, panorama_forward<Args>( STDTR1::get<Indexes>( tup ) )... );
  320. }
  321. // Expands values in tuple into a single function call
  322. template< typename RetType, typename TupleType, class... Args, int... Indexes >
  323. void JSFunctionCallTuple_Helper( RetType( *pFunc )(Args...), const v8::FunctionCallbackInfo<v8::Value> &args, index_tuple< Indexes... >, TupleType &tup )
  324. {
  325. JSFunctionCallbackWrapper< RetType, Args... >::Call( pFunc, args, panorama_forward<Args>( STDTR1::get<Indexes>( tup ) )... );
  326. }
  327. // converts all v8 args into a tuple
  328. template< int Index, typename T >
  329. struct ConvertV8ArgsToTuple
  330. {
  331. static void Call( T &tup, const v8::FunctionCallbackInfo<v8::Value> &args, bool *pbSucceeded )
  332. {
  333. bool bSucceeded = BConvertV8ArgToPanorama( args[Index - 1], &STDTR1::get< Index - 1>( tup ) );
  334. if ( pbSucceeded )
  335. pbSucceeded[Index - 1] = bSucceeded;
  336. if ( !bSucceeded )
  337. return;
  338. ConvertV8ArgsToTuple<Index - 1, T >::Call( tup, args, pbSucceeded );
  339. }
  340. };
  341. template< typename T >
  342. struct ConvertV8ArgsToTuple< 0, T >
  343. {
  344. static void Call( T &tup, const v8::FunctionCallbackInfo<v8::Value> &args, bool *pbSucceeded )
  345. {
  346. }
  347. };
  348. // frees all args in tuple
  349. template< int Index, typename T >
  350. struct FreeV8ArgsToTuple
  351. {
  352. static void Call( T &tup, bool *pbSucceeded )
  353. {
  354. if ( pbSucceeded && pbSucceeded[Index - 1] )
  355. FreeConvertedParam( STDTR1::get< Index - 1 >( tup ) );
  356. FreeV8ArgsToTuple<Index - 1, T >::Call( tup, pbSucceeded );
  357. }
  358. };
  359. template< typename T >
  360. struct FreeV8ArgsToTuple < 0, T >
  361. {
  362. static void Call( T &tup, bool *pbSucceeded )
  363. {
  364. }
  365. };
  366. template< typename ObjType, typename RetType, typename ...Args >
  367. void JSMethodCallTuple( const v8::FunctionCallbackInfo<v8::Value>& args )
  368. {
  369. v8::Isolate::Scope isolate_scope( args.GetIsolate() );
  370. v8::HandleScope handle_scope( args.GetIsolate() );
  371. v8::Persistent<v8::Context> &perContext = UIEngine()->GetV8GlobalContext();
  372. v8::Handle<v8::Context> context = v8::Local<v8::Context>::New( GetV8Isolate(), perContext );
  373. v8::Context::Scope context_scope( context );
  374. if( args.Length() < sizeof...(Args) )
  375. {
  376. v8::String::Utf8Value str( args.Callee()->GetName()->ToString() );
  377. GetV8Isolate()->ThrowException( v8::String::NewFromUtf8( GetV8Isolate(), CFmtStr1024( "%s requires %d arguments; only %d given.", *str, (int)sizeof...(Args), (int)args.Length() ).String() ) );
  378. return;
  379. }
  380. ObjType *pPanel = GetThisPtrForJSCall<ObjType>( args.Holder() );
  381. if ( !pPanel )
  382. return;
  383. v8::Local<v8::Array> callbackArray = v8::Local<v8::Array>::Cast( args.Data() );
  384. HACKY_FUNC_PTR_CASTER< RetType( ObjType::* )(Args...) > caster;
  385. RestoreFuncPtr( caster, callbackArray, 0 );
  386. bool *pbSucceeded = NULL;
  387. if ( sizeof...(Args) > 0 )
  388. {
  389. pbSucceeded = new bool[sizeof...(Args)];
  390. V_memset( pbSucceeded, 0, sizeof...(Args)* sizeof( bool ) );
  391. }
  392. STDTR1::tuple< Args... > tupleArgs;
  393. ConvertV8ArgsToTuple< sizeof...(Args), STDTR1::tuple< Args... > >::Call( tupleArgs, args, pbSucceeded );
  394. bool bSucceeded = true;
  395. for ( int i = 0; i < sizeof...(Args); i++ )
  396. {
  397. if ( !pbSucceeded[i] )
  398. bSucceeded = false;
  399. }
  400. if ( bSucceeded )
  401. JSMethodCallTuple_Helper( pPanel, caster.funcPtr, args, typename make_indexes<Args...>::type(), tupleArgs );
  402. FreeV8ArgsToTuple< sizeof...(Args), STDTR1::tuple< Args... > >::Call( tupleArgs, pbSucceeded );
  403. delete[] pbSucceeded;
  404. }
  405. template< typename ObjType >
  406. void JSMethodCallTupleRaw( const v8::FunctionCallbackInfo<v8::Value>& args )
  407. {
  408. v8::Isolate::Scope isolate_scope( args.GetIsolate() );
  409. v8::HandleScope handle_scope( args.GetIsolate() );
  410. v8::Persistent<v8::Context> &perContext = UIEngine()->GetV8GlobalContext();
  411. v8::Handle<v8::Context> context = v8::Local<v8::Context>::New( GetV8Isolate(), perContext );
  412. v8::Context::Scope context_scope( context );
  413. ObjType *pPanel = GetThisPtrForJSCall<ObjType>( args.Holder() );
  414. if ( !pPanel )
  415. return;
  416. v8::Local<v8::Array> callbackArray = v8::Local<v8::Array>::Cast( args.Data() );
  417. HACKY_FUNC_PTR_CASTER< void ( ObjType::* )( const v8::FunctionCallbackInfo<v8::Value>& ) > caster;
  418. RestoreFuncPtr( caster, callbackArray, 0 );
  419. (pPanel->*caster.funcPtr)( args );
  420. }
  421. template< typename RetType, typename ...Args >
  422. void JSFunctionCallTuple( const v8::FunctionCallbackInfo<v8::Value>& args )
  423. {
  424. v8::Isolate::Scope isolate_scope( args.GetIsolate() );
  425. v8::HandleScope handle_scope( args.GetIsolate() );
  426. v8::Persistent<v8::Context> &perContext = UIEngine()->GetV8GlobalContext();
  427. v8::Handle<v8::Context> context = v8::Local<v8::Context>::New( GetV8Isolate(), perContext );
  428. v8::Context::Scope context_scope( context );
  429. if( args.Length() < sizeof...(Args) )
  430. {
  431. v8::String::Utf8Value str( args.Callee()->GetName()->ToString() );
  432. GetV8Isolate()->ThrowException( v8::String::NewFromUtf8( GetV8Isolate(), CFmtStr1024( "%s requires %d arguments; only %d given.", *str, (int)sizeof...(Args), (int)args.Length() ).String() ) );
  433. return;
  434. }
  435. v8::Local<v8::Array> callbackArray = v8::Local<v8::Array>::Cast( args.Data() );
  436. HACKY_FUNC_PTR_CASTER< RetType( * )(Args...) > caster;
  437. RestoreFuncPtr( caster, callbackArray, 0 );
  438. bool *pbSucceeded = NULL;
  439. if( sizeof...(Args) > 0 )
  440. {
  441. pbSucceeded = new bool[sizeof...(Args)];
  442. V_memset( pbSucceeded, 0, sizeof...(Args)* sizeof( bool ) );
  443. }
  444. STDTR1::tuple< Args... > tupleArgs;
  445. ConvertV8ArgsToTuple< sizeof...(Args), STDTR1::tuple< Args... > >::Call( tupleArgs, args, pbSucceeded );
  446. bool bSucceeded = true;
  447. for( int i = 0; i < sizeof...(Args); i++ )
  448. {
  449. if( !pbSucceeded[i] )
  450. bSucceeded = false;
  451. }
  452. if( bSucceeded )
  453. JSFunctionCallTuple_Helper( caster.funcPtr, args, typename make_indexes<Args...>::type(), tupleArgs );
  454. FreeV8ArgsToTuple< sizeof...(Args), STDTR1::tuple< Args... > >::Call( tupleArgs, pbSucceeded );
  455. delete[] pbSucceeded;
  456. }
  457. // Infer types for all arguments.
  458. template< uint8 unIndex, typename Type1, typename ...Types >
  459. struct RegisterJSTypesDeducer
  460. {
  461. static void Call( RegisterJSType_t *pTypes, uint8 unMaxIndex )
  462. {
  463. Assert( unIndex <= RegisterJSEntryInfo_t::k_unMaxParams );
  464. if ( unIndex <= RegisterJSEntryInfo_t::k_unMaxParams )
  465. {
  466. pTypes[unMaxIndex - unIndex] = RegisterJSTypeDeducer_t<Type1>::Type();
  467. #if defined( SOURCE2_PANORAMA )
  468. RegisterJSTypesDeducer< unIndex - 1, Types... >::Call( pTypes, unMaxIndex );
  469. #endif
  470. }
  471. }
  472. };
  473. template< typename Type1 >
  474. struct RegisterJSTypesDeducer< 0, Type1 >
  475. {
  476. static void Call( RegisterJSType_t *pTypes, uint8 unMaxIndex )
  477. {
  478. // This is the termination placeholder.
  479. }
  480. };
  481. // two RegisterJSMethods, one for const function pointers, one for mutable
  482. template < typename ObjType, typename RetType, typename ...Args>
  483. void RegisterJSMethod( const char *pchMethodName, RetType( ObjType::*mf )(Args...), const char *pDesc = NULL )
  484. {
  485. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  486. v8::HandleScope handle_scope( GetV8Isolate() );
  487. v8::Handle<v8::Array> callbackArray = v8::Array::New( GetV8Isolate(), 3 );
  488. GetPtrToCallbackArray( mf, callbackArray );
  489. v8::Handle<v8::ObjectTemplate> objTemplate = UIEngine()->GetCurrentV8ObjectTemplateToSetup();
  490. objTemplate->Set( v8::String::NewFromUtf8( GetV8Isolate(), pchMethodName ), v8::FunctionTemplate::New( GetV8Isolate(), &JSMethodCallTuple<ObjType, RetType, Args...>, callbackArray ) );
  491. int nEntry = UIEngine()->NewRegisterJSEntry( pchMethodName, RegisterJSEntryInfo_t::k_EMethod, pDesc, RegisterJSTypeDeducer_t<RetType>::Type() );
  492. #if defined( SOURCE2_PANORAMA )
  493. RegisterJSType_t pParamTypes[RegisterJSEntryInfo_t::k_unMaxParams];
  494. RegisterJSTypesDeducer< sizeof...(Args), Args..., void >::Call( pParamTypes, sizeof...(Args) );
  495. UIEngine()->SetRegisterJSEntryParams( nEntry, sizeof...(Args), pParamTypes );
  496. #else
  497. REFERENCE( nEntry );
  498. #endif
  499. }
  500. template < typename ObjType, typename RetType, typename ...Args>
  501. void RegisterJSMethod( const char *pchMethodName, RetType( ObjType::*mf )(Args...) const, const char *pDesc )
  502. {
  503. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  504. v8::HandleScope handle_scope( GetV8Isolate() );
  505. v8::Handle<v8::Array> callbackArray = v8::Array::New( GetV8Isolate(), 3 );
  506. GetPtrToCallbackArray( mf, callbackArray );
  507. v8::Handle<v8::ObjectTemplate> objTemplate = UIEngine()->GetCurrentV8ObjectTemplateToSetup();
  508. objTemplate->Set( v8::String::NewFromUtf8( GetV8Isolate(), pchMethodName ), v8::FunctionTemplate::New( GetV8Isolate(), &JSMethodCallTuple<ObjType, RetType, Args...>, callbackArray ) );
  509. int nEntry = UIEngine()->NewRegisterJSEntry( pchMethodName, RegisterJSEntryInfo_t::k_EMethod, pDesc, RegisterJSTypeDeducer_t<RetType>::Type() );
  510. #if defined( SOURCE2_PANORAMA )
  511. RegisterJSType_t pParamTypes[RegisterJSEntryInfo_t::k_unMaxParams];
  512. RegisterJSTypesDeducer< sizeof...(Args), Args..., void >::Call( pParamTypes, sizeof...(Args) );
  513. UIEngine()->SetRegisterJSEntryParams( nEntry, sizeof...(Args), pParamTypes );
  514. #else
  515. REFERENCE( nEntry );
  516. #endif
  517. }
  518. template < typename RetType, typename ...Args>
  519. void RegisterJSGlobalFunction( const char *pchJSFunctionName, RetType( *pFunc )(Args...), bool bTrueGlobal, const char *pDesc )
  520. {
  521. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  522. v8::HandleScope handle_scope( GetV8Isolate() );
  523. v8::Persistent<v8::Context> &perContext = UIEngine()->GetV8GlobalContext();
  524. v8::Handle<v8::Context> context = v8::Local<v8::Context>::New( GetV8Isolate(), perContext );
  525. v8::Context::Scope context_scope( context );
  526. v8::Handle<v8::Array> callbackArray = v8::Array::New( GetV8Isolate(), 3 );
  527. GetPtrToCallbackArray( pFunc, callbackArray );
  528. v8::Handle< v8::FunctionTemplate > funcTempl = v8::FunctionTemplate::New( GetV8Isolate(), &JSFunctionCallTuple< RetType, Args...>, callbackArray );
  529. UIEngine()->AddGlobalV8FunctionTemplate( pchJSFunctionName, &funcTempl, bTrueGlobal );
  530. int nEntry = UIEngine()->NewRegisterJSEntry( pchJSFunctionName, RegisterJSEntryInfo_t::k_EGlobalFunction, pDesc, RegisterJSTypeDeducer_t<RetType>::Type() );
  531. #if defined( SOURCE2_PANORAMA )
  532. RegisterJSType_t pParamTypes[RegisterJSEntryInfo_t::k_unMaxParams];
  533. RegisterJSTypesDeducer< sizeof...(Args), Args..., void >::Call( pParamTypes, sizeof...(Args) );
  534. UIEngine()->SetRegisterJSEntryParams( nEntry, sizeof...(Args), pParamTypes );
  535. #else
  536. REFERENCE( nEntry );
  537. #endif
  538. }
  539. inline void RegisterJSGlobalFunctionRaw( const char *pchJSFunctionName, void (*pCallbackFunc)( const v8::FunctionCallbackInfo< v8::Value > &callbackInfo ), bool bTrueGlobal, const char *pDesc = NULL )
  540. {
  541. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  542. v8::HandleScope handle_scope( GetV8Isolate() );
  543. v8::Persistent<v8::Context> &perContext = UIEngine()->GetV8GlobalContext();
  544. v8::Handle<v8::Context> context = v8::Local<v8::Context>::New( GetV8Isolate(), perContext );
  545. v8::Context::Scope context_scope( context );
  546. v8::Handle< v8::FunctionTemplate > funcTempl = v8::FunctionTemplate::New( GetV8Isolate(), pCallbackFunc );
  547. UIEngine()->AddGlobalV8FunctionTemplate( pchJSFunctionName, &funcTempl, bTrueGlobal );
  548. int nEntry = UIEngine()->NewRegisterJSEntry( pchJSFunctionName, RegisterJSEntryInfo_t::k_EGlobalFunction, pDesc, k_ERegisterJSTypeVoid );
  549. RegisterJSType_t pParamTypes[1] = { k_ERegisterJSTypeRawV8Args };
  550. UIEngine()->SetRegisterJSEntryParams( nEntry, 1, pParamTypes );
  551. }
  552. template < typename ObjType >
  553. inline void RegisterJSMethodRaw( const char *pchMethodName, void ( ObjType::*mf )( const v8::FunctionCallbackInfo< v8::Value > &callbackInfo ), const char *pDesc = NULL )
  554. {
  555. v8::Isolate::Scope isolate_scope( GetV8Isolate() );
  556. v8::HandleScope handle_scope( GetV8Isolate() );
  557. v8::Handle<v8::Array> callbackArray = v8::Array::New( GetV8Isolate(), 3 );
  558. GetPtrToCallbackArray( mf, callbackArray );
  559. v8::Handle<v8::ObjectTemplate> objTemplate = UIEngine()->GetCurrentV8ObjectTemplateToSetup();
  560. objTemplate->Set( v8::String::NewFromUtf8( GetV8Isolate(), pchMethodName ), v8::FunctionTemplate::New( GetV8Isolate(), &JSMethodCallTupleRaw<ObjType>, callbackArray ) );
  561. int nEntry = UIEngine()->NewRegisterJSEntry( pchMethodName, RegisterJSEntryInfo_t::k_EMethod, pDesc, k_ERegisterJSTypeVoid );
  562. RegisterJSType_t pParamTypes[1] = { k_ERegisterJSTypeRawV8Args };
  563. UIEngine()->SetRegisterJSEntryParams( nEntry, 1, pParamTypes );
  564. }
  565. inline v8::Local< v8::String > JSObjectToJSON( v8::Isolate *pIsolate, v8::Local< v8::Value > object )
  566. {
  567. v8::Local< v8::Context > context = pIsolate->GetCurrentContext();
  568. v8::Local< v8::Object > global = context->Global();
  569. v8::Local< v8::Object > global_JSON = v8::Handle< v8::Object >::Cast( global->Get( v8::String::NewFromUtf8( pIsolate, "JSON" ) ) );
  570. v8::Local< v8::Function > global_JSON_stringify = v8::Handle< v8::Function >::Cast( global_JSON->Get( v8::String::NewFromUtf8( pIsolate, "stringify" ) ) );
  571. v8::Local< v8::Value > args[] = { object };
  572. return v8::Local< v8::String >::Cast( global_JSON_stringify->Call( global_JSON, 1, args ) );
  573. }
  574. }
  575. #pragma warning(pop)
  576. #if _GNUC
  577. #pragma GCC diagnostic pop
  578. #endif
  579. #endif // _WIN32