1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #ifndef FPDFSDK_SRC_JAVASCRIPT_JS_DEFINE_H_ 8 #define FPDFSDK_SRC_JAVASCRIPT_JS_DEFINE_H_ 9 10 #include "JS_Object.h" 11 #include "JS_Value.h" 12 #include "fpdfsdk/include/jsapi/fxjs_v8.h" 13 #include "resource.h" 14 15 struct JSConstSpec { 16 const wchar_t* pName; 17 double number; 18 const wchar_t* string; 19 uint8_t t; // 0:double 1:str 20 }; 21 22 struct JSPropertySpec { 23 const wchar_t* pName; 24 v8::AccessorGetterCallback pPropGet; 25 v8::AccessorSetterCallback pPropPut; 26 }; 27 28 struct JSMethodSpec { 29 const wchar_t* pName; 30 v8::FunctionCallback pMethodCall; 31 }; 32 33 #define JS_WIDESTRING(widestring) L## #widestring 34 #define BEGIN_JS_STATIC_CONST(js_class_name) \ 35 JSConstSpec js_class_name::JS_Class_Consts[] = { 36 #define JS_STATIC_CONST_ENTRY_NUMBER(const_name, pValue) \ 37 { const_name, pValue, L"", 0 } \ 38 , 39 40 #define JS_STATIC_CONST_ENTRY_STRING(const_name, pValue) \ 41 { const_name, 0, pValue, 1 } \ 42 , 43 44 #define END_JS_STATIC_CONST() \ 45 { 0, 0, 0, 0 } \ 46 } \ 47 ; 48 49 #define BEGIN_JS_STATIC_PROP(js_class_name) \ 50 JSPropertySpec js_class_name::JS_Class_Properties[] = { 51 #define JS_STATIC_PROP_ENTRY(prop_name) \ 52 { \ 53 JS_WIDESTRING(prop_name), get_##prop_name##_static, \ 54 set_##prop_name##_static \ 55 } \ 56 , 57 58 #define END_JS_STATIC_PROP() \ 59 { 0, 0, 0 } \ 60 } \ 61 ; 62 63 #define BEGIN_JS_STATIC_METHOD(js_class_name) \ 64 JSMethodSpec js_class_name::JS_Class_Methods[] = { 65 #define JS_STATIC_METHOD_ENTRY(method_name) \ 66 { JS_WIDESTRING(method_name), method_name##_static } \ 67 , 68 69 #define END_JS_STATIC_METHOD() \ 70 { 0, 0 } \ 71 } \ 72 ; 73 74 template <class C, 75 FX_BOOL (C::*M)(IJS_Context*, CJS_PropValue&, CFX_WideString&)> 76 void JSPropGetter(const char* prop_name_string, 77 const char* class_name_string, 78 v8::Local<v8::String> property, 79 const v8::PropertyCallbackInfo<v8::Value>& info) { 80 v8::Isolate* isolate = info.GetIsolate(); 81 CJS_Runtime* pRuntime = 82 static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); 83 if (!pRuntime) 84 return; 85 IJS_Context* pContext = pRuntime->GetCurrentContext(); 86 CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder()); 87 C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject()); 88 CFX_WideString sError; 89 CJS_PropValue value(pRuntime); 90 value.StartGetting(); 91 if (!(pObj->*M)(pContext, value, sError)) { 92 FXJS_Error(isolate, JSFormatErrorString(class_name_string, prop_name_string, 93 sError)); 94 return; 95 } 96 info.GetReturnValue().Set((v8::Local<v8::Value>)value); 97 } 98 99 template <class C, 100 FX_BOOL (C::*M)(IJS_Context*, CJS_PropValue&, CFX_WideString&)> 101 void JSPropSetter(const char* prop_name_string, 102 const char* class_name_string, 103 v8::Local<v8::String> property, 104 v8::Local<v8::Value> value, 105 const v8::PropertyCallbackInfo<void>& info) { 106 v8::Isolate* isolate = info.GetIsolate(); 107 CJS_Runtime* pRuntime = 108 static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); 109 if (!pRuntime) 110 return; 111 IJS_Context* pContext = pRuntime->GetCurrentContext(); 112 CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder()); 113 C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject()); 114 CFX_WideString sError; 115 CJS_PropValue propValue(CJS_Value(pRuntime, value, CJS_Value::VT_unknown)); 116 propValue.StartSetting(); 117 if (!(pObj->*M)(pContext, propValue, sError)) { 118 FXJS_Error(isolate, JSFormatErrorString(class_name_string, prop_name_string, 119 sError)); 120 } 121 } 122 123 #define JS_STATIC_PROP(prop_name, class_name) \ 124 static void get_##prop_name##_static( \ 125 v8::Local<v8::String> property, \ 126 const v8::PropertyCallbackInfo<v8::Value>& info) { \ 127 JSPropGetter<class_name, &class_name::prop_name>(#prop_name, #class_name, \ 128 property, info); \ 129 } \ 130 static void set_##prop_name##_static( \ 131 v8::Local<v8::String> property, v8::Local<v8::Value> value, \ 132 const v8::PropertyCallbackInfo<void>& info) { \ 133 JSPropSetter<class_name, &class_name::prop_name>(#prop_name, #class_name, \ 134 property, value, info); \ 135 } 136 137 template <class C, 138 FX_BOOL (C::*M)(IJS_Context*, 139 const std::vector<CJS_Value>&, 140 CJS_Value&, 141 CFX_WideString&)> 142 void JSMethod(const char* method_name_string, 143 const char* class_name_string, 144 const v8::FunctionCallbackInfo<v8::Value>& info) { 145 v8::Isolate* isolate = info.GetIsolate(); 146 CJS_Runtime* pRuntime = 147 static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); 148 if (!pRuntime) 149 return; 150 IJS_Context* pContext = pRuntime->GetCurrentContext(); 151 std::vector<CJS_Value> parameters; 152 for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) { 153 parameters.push_back(CJS_Value(pRuntime, info[i], CJS_Value::VT_unknown)); 154 } 155 CJS_Value valueRes(pRuntime); 156 CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder()); 157 C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject()); 158 CFX_WideString sError; 159 if (!(pObj->*M)(pContext, parameters, valueRes, sError)) { 160 FXJS_Error(isolate, JSFormatErrorString(class_name_string, 161 method_name_string, sError)); 162 return; 163 } 164 info.GetReturnValue().Set(valueRes.ToV8Value()); 165 } 166 167 #define JS_STATIC_METHOD(method_name, class_name) \ 168 static void method_name##_static( \ 169 const v8::FunctionCallbackInfo<v8::Value>& info) { \ 170 JSMethod<class_name, &class_name::method_name>(#method_name, #class_name, \ 171 info); \ 172 } 173 174 #define JS_SPECIAL_STATIC_METHOD(method_name, class_alternate, class_name) \ 175 static void method_name##_static( \ 176 const v8::FunctionCallbackInfo<v8::Value>& info) { \ 177 JSMethod<class_alternate, &class_alternate::method_name>( \ 178 #method_name, #class_name, info); \ 179 } 180 181 // All JS classes have a name, an object defintion ID, and the ability to 182 // register themselves with FXJS_V8. We never make a BASE class on its own 183 // because it can't really do anything. 184 #define DECLARE_JS_CLASS_BASE_PART() \ 185 static const wchar_t* g_pClassName; \ 186 static int g_nObjDefnID; \ 187 static void DefineJSObjects(v8::Isolate* pIsolate, FXJSOBJTYPE eObjType); 188 189 #define IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \ 190 const wchar_t* js_class_name::g_pClassName = JS_WIDESTRING(class_name); \ 191 int js_class_name::g_nObjDefnID = -1; 192 193 // CONST classes provide constants, but not constructors, methods, or props. 194 #define DECLARE_JS_CLASS_CONST() \ 195 DECLARE_JS_CLASS_BASE_PART() \ 196 DECLARE_JS_CLASS_CONST_PART() 197 198 #define IMPLEMENT_JS_CLASS_CONST(js_class_name, class_name) \ 199 IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \ 200 IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name) \ 201 void js_class_name::DefineJSObjects(v8::Isolate* pIsolate, \ 202 FXJSOBJTYPE eObjType) { \ 203 g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName, \ 204 eObjType, nullptr, nullptr); \ 205 DefineConsts(pIsolate); \ 206 } 207 208 #define DECLARE_JS_CLASS_CONST_PART() \ 209 static JSConstSpec JS_Class_Consts[]; \ 210 static void DefineConsts(v8::Isolate* pIsolate); 211 212 #define IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name) \ 213 void js_class_name::DefineConsts(v8::Isolate* pIsolate) { \ 214 for (size_t i = 0; i < FX_ArraySize(JS_Class_Consts) - 1; ++i) { \ 215 FXJS_DefineObjConst( \ 216 pIsolate, g_nObjDefnID, JS_Class_Consts[i].pName, \ 217 JS_Class_Consts[i].t == 0 \ 218 ? FXJS_NewNumber(pIsolate, JS_Class_Consts[i].number) \ 219 : FXJS_NewString(pIsolate, JS_Class_Consts[i].string)); \ 220 } \ 221 } 222 223 // Convenience macros for declaring classes without an alternate. 224 #define DECLARE_JS_CLASS() DECLARE_JS_CLASS_RICH() 225 #define IMPLEMENT_JS_CLASS(js_class_name, class_name) \ 226 IMPLEMENT_JS_CLASS_RICH(js_class_name, class_name, class_name) 227 228 // Rich JS classes provide constants, methods, properties, and the ability 229 // to construct native object state. 230 #define DECLARE_JS_CLASS_RICH() \ 231 DECLARE_JS_CLASS_BASE_PART() \ 232 DECLARE_JS_CLASS_CONST_PART() \ 233 DECLARE_JS_CLASS_RICH_PART() 234 235 #define IMPLEMENT_JS_CLASS_RICH(js_class_name, class_alternate, class_name) \ 236 IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \ 237 IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name) \ 238 IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name) \ 239 void js_class_name::DefineJSObjects(v8::Isolate* pIsolate, \ 240 FXJSOBJTYPE eObjType) { \ 241 g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName, \ 242 eObjType, JSConstructor, JSDestructor); \ 243 DefineConsts(pIsolate); \ 244 DefineProps(pIsolate); \ 245 DefineMethods(pIsolate); \ 246 } 247 248 #define DECLARE_JS_CLASS_RICH_PART() \ 249 static void JSConstructor(IJS_Runtime* pRuntime, v8::Local<v8::Object> obj); \ 250 static void JSDestructor(v8::Local<v8::Object> obj); \ 251 static void DefineProps(v8::Isolate* pIsoalte); \ 252 static void DefineMethods(v8::Isolate* pIsoalte); \ 253 static JSPropertySpec JS_Class_Properties[]; \ 254 static JSMethodSpec JS_Class_Methods[]; 255 256 #define IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, \ 257 class_name) \ 258 void js_class_name::JSConstructor(IJS_Runtime* pIRuntime, \ 259 v8::Local<v8::Object> obj) { \ 260 CJS_Object* pObj = new js_class_name(obj); \ 261 pObj->SetEmbedObject(new class_alternate(pObj)); \ 262 FXJS_SetPrivate(nullptr, obj, (void*)pObj); \ 263 pObj->InitInstance(pIRuntime); \ 264 } \ 265 void js_class_name::JSDestructor(v8::Local<v8::Object> obj) { \ 266 js_class_name* pObj = (js_class_name*)FXJS_GetPrivate(nullptr, obj); \ 267 pObj->ExitInstance(); \ 268 delete pObj; \ 269 } \ 270 void js_class_name::DefineProps(v8::Isolate* pIsolate) { \ 271 for (size_t i = 0; i < FX_ArraySize(JS_Class_Properties) - 1; ++i) { \ 272 FXJS_DefineObjProperty( \ 273 pIsolate, g_nObjDefnID, JS_Class_Properties[i].pName, \ 274 JS_Class_Properties[i].pPropGet, JS_Class_Properties[i].pPropPut); \ 275 } \ 276 } \ 277 void js_class_name::DefineMethods(v8::Isolate* pIsolate) { \ 278 for (size_t i = 0; i < FX_ArraySize(JS_Class_Methods) - 1; ++i) { \ 279 FXJS_DefineObjMethod(pIsolate, g_nObjDefnID, JS_Class_Methods[i].pName, \ 280 JS_Class_Methods[i].pMethodCall); \ 281 } \ 282 } 283 284 // Special JS classes implement methods, props, and queries, but not consts. 285 #define DECLARE_SPECIAL_JS_CLASS() \ 286 DECLARE_JS_CLASS_BASE_PART() \ 287 DECLARE_JS_CLASS_CONST_PART() \ 288 DECLARE_JS_CLASS_RICH_PART() \ 289 DECLARE_SPECIAL_JS_CLASS_PART() 290 291 #define IMPLEMENT_SPECIAL_JS_CLASS(js_class_name, class_alternate, class_name) \ 292 IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \ 293 IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name) \ 294 IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name) \ 295 IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate, class_name) \ 296 void js_class_name::DefineJSObjects(v8::Isolate* pIsolate, \ 297 FXJSOBJTYPE eObjType) { \ 298 g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName, \ 299 eObjType, JSConstructor, JSDestructor); \ 300 DefineConsts(pIsolate); \ 301 DefineProps(pIsolate); \ 302 DefineMethods(pIsolate); \ 303 DefineAllProperties(pIsolate); \ 304 } 305 306 #define DECLARE_SPECIAL_JS_CLASS_PART() \ 307 static void queryprop_static( \ 308 v8::Local<v8::String> property, \ 309 const v8::PropertyCallbackInfo<v8::Integer>& info); \ 310 static void getprop_static(v8::Local<v8::String> property, \ 311 const v8::PropertyCallbackInfo<v8::Value>& info); \ 312 static void putprop_static(v8::Local<v8::String> property, \ 313 v8::Local<v8::Value> value, \ 314 const v8::PropertyCallbackInfo<v8::Value>& info); \ 315 static void delprop_static( \ 316 v8::Local<v8::String> property, \ 317 const v8::PropertyCallbackInfo<v8::Boolean>& info); \ 318 static void DefineAllProperties(v8::Isolate* pIsolate); 319 320 #define IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate, \ 321 class_name) \ 322 void js_class_name::queryprop_static( \ 323 v8::Local<v8::String> property, \ 324 const v8::PropertyCallbackInfo<v8::Integer>& info) { \ 325 JSSpecialPropQuery<class_alternate>(#class_name, property, info); \ 326 } \ 327 void js_class_name::getprop_static( \ 328 v8::Local<v8::String> property, \ 329 const v8::PropertyCallbackInfo<v8::Value>& info) { \ 330 JSSpecialPropGet<class_alternate>(#class_name, property, info); \ 331 } \ 332 void js_class_name::putprop_static( \ 333 v8::Local<v8::String> property, v8::Local<v8::Value> value, \ 334 const v8::PropertyCallbackInfo<v8::Value>& info) { \ 335 JSSpecialPropPut<class_alternate>(#class_name, property, value, info); \ 336 } \ 337 void js_class_name::delprop_static( \ 338 v8::Local<v8::String> property, \ 339 const v8::PropertyCallbackInfo<v8::Boolean>& info) { \ 340 JSSpecialPropDel<class_alternate>(#class_name, property, info); \ 341 } \ 342 void js_class_name::DefineAllProperties(v8::Isolate* pIsolate) { \ 343 FXJS_DefineObjAllProperties( \ 344 pIsolate, g_nObjDefnID, js_class_name::queryprop_static, \ 345 js_class_name::getprop_static, js_class_name::putprop_static, \ 346 js_class_name::delprop_static); \ 347 } 348 349 template <class Alt> 350 void JSSpecialPropQuery(const char*, 351 v8::Local<v8::String> property, 352 const v8::PropertyCallbackInfo<v8::Integer>& info) { 353 v8::Isolate* isolate = info.GetIsolate(); 354 v8::String::Utf8Value utf8_value(property); 355 CFX_WideString propname = 356 CFX_WideString::FromUTF8(*utf8_value, utf8_value.length()); 357 CJS_Object* pJSObj = 358 reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder())); 359 Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject()); 360 FX_BOOL bRet = pObj->QueryProperty(propname.c_str()); 361 info.GetReturnValue().Set(bRet ? 4 : 0); 362 } 363 364 template <class Alt> 365 void JSSpecialPropGet(const char* class_name, 366 v8::Local<v8::String> property, 367 const v8::PropertyCallbackInfo<v8::Value>& info) { 368 v8::Isolate* isolate = info.GetIsolate(); 369 CJS_Runtime* pRuntime = 370 static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); 371 if (!pRuntime) 372 return; 373 IJS_Context* pContext = pRuntime->GetCurrentContext(); 374 CJS_Object* pJSObj = 375 reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder())); 376 Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject()); 377 v8::String::Utf8Value utf8_value(property); 378 CFX_WideString propname = 379 CFX_WideString::FromUTF8(*utf8_value, utf8_value.length()); 380 CFX_WideString sError; 381 CJS_PropValue value(pRuntime); 382 value.StartGetting(); 383 if (!pObj->DoProperty(pContext, propname.c_str(), value, sError)) { 384 FXJS_Error(isolate, JSFormatErrorString(class_name, "GetProperty", sError)); 385 return; 386 } 387 info.GetReturnValue().Set((v8::Local<v8::Value>)value); 388 } 389 390 template <class Alt> 391 void JSSpecialPropPut(const char* class_name, 392 v8::Local<v8::String> property, 393 v8::Local<v8::Value> value, 394 const v8::PropertyCallbackInfo<v8::Value>& info) { 395 v8::Isolate* isolate = info.GetIsolate(); 396 CJS_Runtime* pRuntime = 397 static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); 398 if (!pRuntime) 399 return; 400 IJS_Context* pContext = pRuntime->GetCurrentContext(); 401 CJS_Object* pJSObj = 402 reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder())); 403 Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject()); 404 v8::String::Utf8Value utf8_value(property); 405 CFX_WideString propname = 406 CFX_WideString::FromUTF8(*utf8_value, utf8_value.length()); 407 CFX_WideString sError; 408 CJS_PropValue PropValue(CJS_Value(pRuntime, value, CJS_Value::VT_unknown)); 409 PropValue.StartSetting(); 410 if (!pObj->DoProperty(pContext, propname.c_str(), PropValue, sError)) { 411 FXJS_Error(isolate, JSFormatErrorString(class_name, "PutProperty", sError)); 412 } 413 } 414 415 template <class Alt> 416 void JSSpecialPropDel(const char* class_name, 417 v8::Local<v8::String> property, 418 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 419 v8::Isolate* isolate = info.GetIsolate(); 420 IJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate); 421 if (!pRuntime) 422 return; 423 IJS_Context* pContext = pRuntime->GetCurrentContext(); 424 CJS_Object* pJSObj = 425 reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder())); 426 Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject()); 427 v8::String::Utf8Value utf8_value(property); 428 CFX_WideString propname = 429 CFX_WideString::FromUTF8(*utf8_value, utf8_value.length()); 430 CFX_WideString sError; 431 if (!pObj->DelProperty(pContext, propname.c_str(), sError)) { 432 CFX_ByteString cbName; 433 cbName.Format("%s.%s", class_name, "DelProperty"); 434 // Probably a missing call to JSFX_Error(). 435 } 436 } 437 438 template <FX_BOOL (*F)(IJS_Context*, 439 const std::vector<CJS_Value>&, 440 CJS_Value&, 441 CFX_WideString&)> 442 void JSGlobalFunc(const char* func_name_string, 443 const v8::FunctionCallbackInfo<v8::Value>& info) { 444 CJS_Runtime* pRuntime = 445 static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(info.GetIsolate())); 446 if (!pRuntime) 447 return; 448 IJS_Context* pContext = pRuntime->GetCurrentContext(); 449 std::vector<CJS_Value> parameters; 450 for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) { 451 parameters.push_back(CJS_Value(pRuntime, info[i], CJS_Value::VT_unknown)); 452 } 453 CJS_Value valueRes(pRuntime); 454 CFX_WideString sError; 455 if (!(*F)(pContext, parameters, valueRes, sError)) { 456 FXJS_Error(pRuntime->GetIsolate(), 457 JSFormatErrorString(func_name_string, nullptr, sError)); 458 return; 459 } 460 info.GetReturnValue().Set(valueRes.ToV8Value()); 461 } 462 463 #define JS_STATIC_GLOBAL_FUN(fun_name) \ 464 static void fun_name##_static( \ 465 const v8::FunctionCallbackInfo<v8::Value>& info) { \ 466 JSGlobalFunc<fun_name>(#fun_name, info); \ 467 } 468 469 #define JS_STATIC_DECLARE_GLOBAL_FUN() \ 470 static JSMethodSpec global_methods[]; \ 471 static void DefineJSObjects(v8::Isolate* pIsolate) 472 473 #define BEGIN_JS_STATIC_GLOBAL_FUN(js_class_name) \ 474 JSMethodSpec js_class_name::global_methods[] = { 475 #define JS_STATIC_GLOBAL_FUN_ENTRY(method_name) \ 476 JS_STATIC_METHOD_ENTRY(method_name) 477 478 #define END_JS_STATIC_GLOBAL_FUN() END_JS_STATIC_METHOD() 479 480 #define IMPLEMENT_JS_STATIC_GLOBAL_FUN(js_class_name) \ 481 void js_class_name::DefineJSObjects(v8::Isolate* pIsolate) { \ 482 for (size_t i = 0; i < FX_ArraySize(global_methods) - 1; ++i) { \ 483 FXJS_DefineGlobalMethod(pIsolate, \ 484 js_class_name::global_methods[i].pName, \ 485 js_class_name::global_methods[i].pMethodCall); \ 486 } \ 487 } 488 489 CJS_Value::Type GET_VALUE_TYPE(v8::Local<v8::Value> p); 490 491 #endif // FPDFSDK_SRC_JAVASCRIPT_JS_DEFINE_H_ 492