Home | History | Annotate | Download | only in javascript
      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