Store object definition ID in each js_class.
[pdfium.git] / fpdfsdk / src / javascript / JS_Define.h
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 "../../include/jsapi/fxjs_v8.h"
11 #include "resource.h"
12 #include "JS_Object.h"
13 #include "JS_Value.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)(IFXJS_Context* cc,
76                           CJS_PropValue& vp,
77                           CFX_WideString& sError)>
78 void JSPropGetter(const char* prop_name_string,
79                   const char* class_name_string,
80                   v8::Local<v8::String> property,
81                   const v8::PropertyCallbackInfo<v8::Value>& info) {
82   v8::Isolate* isolate = info.GetIsolate();
83   IFXJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate);
84   if (!pRuntime)
85     return;
86   IFXJS_Context* pContext = pRuntime->GetCurrentContext();
87   CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder());
88   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
89   CFX_WideString sError;
90   CJS_PropValue value(isolate);
91   value.StartGetting();
92   if (!(pObj->*M)(pContext, value, sError)) {
93     FXJS_Error(isolate, JSFormatErrorString(class_name_string, prop_name_string,
94                                             sError));
95     return;
96   }
97   info.GetReturnValue().Set((v8::Local<v8::Value>)value);
98 }
99
100 template <class C,
101           FX_BOOL (C::*M)(IFXJS_Context* cc,
102                           CJS_PropValue& vp,
103                           CFX_WideString& sError)>
104 void JSPropSetter(const char* prop_name_string,
105                   const char* class_name_string,
106                   v8::Local<v8::String> property,
107                   v8::Local<v8::Value> value,
108                   const v8::PropertyCallbackInfo<void>& info) {
109   v8::Isolate* isolate = info.GetIsolate();
110   IFXJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate);
111   if (!pRuntime)
112     return;
113   IFXJS_Context* pContext = pRuntime->GetCurrentContext();
114   CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder());
115   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
116   CFX_WideString sError;
117   CJS_PropValue propValue(CJS_Value(isolate, value, CJS_Value::VT_unknown));
118   propValue.StartSetting();
119   if (!(pObj->*M)(pContext, propValue, sError)) {
120     FXJS_Error(isolate, JSFormatErrorString(class_name_string, prop_name_string,
121                                             sError));
122   }
123 }
124
125 #define JS_STATIC_PROP(prop_name, class_name)                                 \
126   static void get_##prop_name##_static(                                       \
127       v8::Local<v8::String> property,                                         \
128       const v8::PropertyCallbackInfo<v8::Value>& info) {                      \
129     JSPropGetter<class_name, &class_name::prop_name>(#prop_name, #class_name, \
130                                                      property, info);         \
131   }                                                                           \
132   static void set_##prop_name##_static(                                       \
133       v8::Local<v8::String> property, v8::Local<v8::Value> value,             \
134       const v8::PropertyCallbackInfo<void>& info) {                           \
135     JSPropSetter<class_name, &class_name::prop_name>(#prop_name, #class_name, \
136                                                      property, value, info);  \
137   }
138
139 template <class C,
140           FX_BOOL (C::*M)(IFXJS_Context* cc,
141                           const CJS_Parameters& params,
142                           CJS_Value& vRet,
143                           CFX_WideString& sError)>
144 void JSMethod(const char* method_name_string,
145               const char* class_name_string,
146               const v8::FunctionCallbackInfo<v8::Value>& info) {
147   v8::Isolate* isolate = info.GetIsolate();
148   IFXJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate);
149   if (!pRuntime)
150     return;
151   IFXJS_Context* cc = pRuntime->GetCurrentContext();
152   CJS_Parameters parameters;
153   for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) {
154     parameters.push_back(CJS_Value(isolate, info[i], CJS_Value::VT_unknown));
155   }
156   CJS_Value valueRes(isolate);
157   CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder());
158   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
159   CFX_WideString sError;
160   if (!(pObj->*M)(cc, parameters, valueRes, sError)) {
161     FXJS_Error(isolate, JSFormatErrorString(class_name_string,
162                                             method_name_string, sError));
163     return;
164   }
165   info.GetReturnValue().Set(valueRes.ToV8Value());
166 }
167
168 #define JS_STATIC_METHOD(method_name, class_name)                             \
169   static void method_name##_static(                                           \
170       const v8::FunctionCallbackInfo<v8::Value>& info) {                      \
171     JSMethod<class_name, &class_name::method_name>(#method_name, #class_name, \
172                                                    info);                     \
173   }
174
175 #define JS_SPECIAL_STATIC_METHOD(method_name, class_alternate, class_name) \
176   static void method_name##_static(                                        \
177       const v8::FunctionCallbackInfo<v8::Value>& info) {                   \
178     JSMethod<class_alternate, &class_alternate::method_name>(              \
179         #method_name, #class_name, info);                                  \
180   }
181
182 // All JS classes have a name, an object defintion ID, and the ability to
183 // register themselves with FXJS_V8. We never make a BASE class on its own
184 // because it can't really do anything.
185 #define DECLARE_JS_CLASS_BASE_PART()  \
186   static const wchar_t* g_pClassName; \
187   static int g_nObjDefnID;            \
188   static void DefineJSObjects(v8::Isolate* pIsolate, FXJSOBJTYPE eObjType);
189
190 #define IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)           \
191   const wchar_t* js_class_name::g_pClassName = JS_WIDESTRING(class_name); \
192   int js_class_name::g_nObjDefnID = -1;
193
194 // CONST classes provide constants, but not constructors, methods, or props.
195 #define DECLARE_JS_CLASS_CONST() \
196   DECLARE_JS_CLASS_BASE_PART()   \
197   DECLARE_JS_CLASS_CONST_PART()
198
199 #define IMPLEMENT_JS_CLASS_CONST(js_class_name, class_name)              \
200   IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                \
201   IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)               \
202   void js_class_name::DefineJSObjects(v8::Isolate* pIsolate,             \
203                                       FXJSOBJTYPE eObjType) {            \
204     g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName, \
205                                   eObjType, nullptr, nullptr);           \
206     DefineConsts(pIsolate);                                              \
207   }
208
209 #define DECLARE_JS_CLASS_CONST_PART()   \
210   static JSConstSpec JS_Class_Consts[]; \
211   static void DefineConsts(v8::Isolate* pIsolate);
212
213 #define IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)      \
214   void js_class_name::DefineConsts(v8::Isolate* pIsolate) {           \
215     for (size_t i = 0; i < FX_ArraySize(JS_Class_Consts) - 1; ++i) {  \
216       FXJS_DefineObjConst(                                            \
217           pIsolate, g_nObjDefnID, JS_Class_Consts[i].pName,           \
218           JS_Class_Consts[i].t == 0                                   \
219               ? FXJS_NewNumber(pIsolate, JS_Class_Consts[i].number)   \
220               : FXJS_NewString(pIsolate, JS_Class_Consts[i].string)); \
221     }                                                                 \
222   }
223
224 // Convenience macros for declaring classes without an alternate.
225 #define DECLARE_JS_CLASS() DECLARE_JS_CLASS_RICH()
226 #define IMPLEMENT_JS_CLASS(js_class_name, class_name) \
227   IMPLEMENT_JS_CLASS_RICH(js_class_name, class_name, class_name)
228
229 // Rich JS classes provide constants, methods, properties, and the ability
230 // to construct native object state.
231 #define DECLARE_JS_CLASS_RICH() \
232   DECLARE_JS_CLASS_BASE_PART()  \
233   DECLARE_JS_CLASS_CONST_PART() \
234   DECLARE_JS_CLASS_RICH_PART()
235
236 #define IMPLEMENT_JS_CLASS_RICH(js_class_name, class_alternate, class_name) \
237   IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                   \
238   IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                  \
239   IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name)  \
240   void js_class_name::DefineJSObjects(v8::Isolate* pIsolate,                \
241                                       FXJSOBJTYPE eObjType) {               \
242     g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName,    \
243                                   eObjType, JSConstructor, JSDestructor);   \
244     DefineConsts(pIsolate);                                                 \
245     DefineProps(pIsolate);                                                  \
246     DefineMethods(pIsolate);                                                \
247   }
248
249 #define DECLARE_JS_CLASS_RICH_PART()                                      \
250   static void JSConstructor(IFXJS_Context* cc, v8::Local<v8::Object> obj, \
251                             v8::Local<v8::Object> global);                \
252   static void JSDestructor(v8::Local<v8::Object> obj);                    \
253   static void DefineProps(v8::Isolate* pIsoalte);                         \
254   static void DefineMethods(v8::Isolate* pIsoalte);                       \
255   static JSPropertySpec JS_Class_Properties[];                            \
256   static JSMethodSpec JS_Class_Methods[];
257
258 #define IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate,          \
259                                      class_name)                              \
260   void js_class_name::JSConstructor(IFXJS_Context* cc,                        \
261                                     v8::Local<v8::Object> obj,                \
262                                     v8::Local<v8::Object> global) {           \
263     CJS_Object* pObj = new js_class_name(obj);                                \
264     pObj->SetEmbedObject(new class_alternate(pObj));                          \
265     FXJS_SetPrivate(nullptr, obj, (void*)pObj);                               \
266     pObj->InitInstance(cc);                                                   \
267   }                                                                           \
268   void js_class_name::JSDestructor(v8::Local<v8::Object> obj) {               \
269     js_class_name* pObj = (js_class_name*)FXJS_GetPrivate(nullptr, obj);      \
270     pObj->ExitInstance();                                                     \
271     delete pObj;                                                              \
272   }                                                                           \
273   void js_class_name::DefineProps(v8::Isolate* pIsolate) {                    \
274     for (size_t i = 0; i < FX_ArraySize(JS_Class_Properties) - 1; ++i) {      \
275       FXJS_DefineObjProperty(                                                 \
276           pIsolate, g_nObjDefnID, JS_Class_Properties[i].pName,               \
277           JS_Class_Properties[i].pPropGet, JS_Class_Properties[i].pPropPut);  \
278     }                                                                         \
279   }                                                                           \
280   void js_class_name::DefineMethods(v8::Isolate* pIsolate) {                  \
281     for (size_t i = 0; i < FX_ArraySize(JS_Class_Methods) - 1; ++i) {         \
282       FXJS_DefineObjMethod(pIsolate, g_nObjDefnID, JS_Class_Methods[i].pName, \
283                            JS_Class_Methods[i].pMethodCall);                  \
284     }                                                                         \
285   }
286
287 // Special JS classes implement methods, props, and queries, but not consts.
288 #define DECLARE_SPECIAL_JS_CLASS() \
289   DECLARE_JS_CLASS_BASE_PART()     \
290   DECLARE_JS_CLASS_CONST_PART()    \
291   DECLARE_JS_CLASS_RICH_PART()     \
292   DECLARE_SPECIAL_JS_CLASS_PART()
293
294 #define IMPLEMENT_SPECIAL_JS_CLASS(js_class_name, class_alternate, class_name) \
295   IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                      \
296   IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                     \
297   IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name)     \
298   IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate, class_name)  \
299   void js_class_name::DefineJSObjects(v8::Isolate* pIsolate,                   \
300                                       FXJSOBJTYPE eObjType) {                  \
301     g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName,       \
302                                   eObjType, JSConstructor, JSDestructor);      \
303     DefineConsts(pIsolate);                                                    \
304     DefineProps(pIsolate);                                                     \
305     DefineMethods(pIsolate);                                                   \
306     DefineAllProperties(pIsolate);                                             \
307   }
308
309 #define DECLARE_SPECIAL_JS_CLASS_PART()                                        \
310   static void queryprop_static(                                                \
311       v8::Local<v8::String> property,                                          \
312       const v8::PropertyCallbackInfo<v8::Integer>& info);                      \
313   static void getprop_static(v8::Local<v8::String> property,                   \
314                              const v8::PropertyCallbackInfo<v8::Value>& info); \
315   static void putprop_static(v8::Local<v8::String> property,                   \
316                              v8::Local<v8::Value> value,                       \
317                              const v8::PropertyCallbackInfo<v8::Value>& info); \
318   static void delprop_static(                                                  \
319       v8::Local<v8::String> property,                                          \
320       const v8::PropertyCallbackInfo<v8::Boolean>& info);                      \
321   static void DefineAllProperties(v8::Isolate* pIsolate);
322
323 #define IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate,    \
324                                         class_name)                        \
325   void js_class_name::queryprop_static(                                    \
326       v8::Local<v8::String> property,                                      \
327       const v8::PropertyCallbackInfo<v8::Integer>& info) {                 \
328     JSSpecialPropQuery<class_alternate>(#class_name, property, info);      \
329   }                                                                        \
330   void js_class_name::getprop_static(                                      \
331       v8::Local<v8::String> property,                                      \
332       const v8::PropertyCallbackInfo<v8::Value>& info) {                   \
333     JSSpecialPropGet<class_alternate>(#class_name, property, info);        \
334   }                                                                        \
335   void js_class_name::putprop_static(                                      \
336       v8::Local<v8::String> property, v8::Local<v8::Value> value,          \
337       const v8::PropertyCallbackInfo<v8::Value>& info) {                   \
338     JSSpecialPropPut<class_alternate>(#class_name, property, value, info); \
339   }                                                                        \
340   void js_class_name::delprop_static(                                      \
341       v8::Local<v8::String> property,                                      \
342       const v8::PropertyCallbackInfo<v8::Boolean>& info) {                 \
343     JSSpecialPropDel<class_alternate>(#class_name, property, info);        \
344   }                                                                        \
345   void js_class_name::DefineAllProperties(v8::Isolate* pIsolate) {         \
346     FXJS_DefineObjAllProperties(                                           \
347         pIsolate, g_nObjDefnID, js_class_name::queryprop_static,           \
348         js_class_name::getprop_static, js_class_name::putprop_static,      \
349         js_class_name::delprop_static);                                    \
350   }
351
352 template <class Alt>
353 void JSSpecialPropQuery(const char*,
354                         v8::Local<v8::String> property,
355                         const v8::PropertyCallbackInfo<v8::Integer>& info) {
356   v8::Isolate* isolate = info.GetIsolate();
357   v8::String::Utf8Value utf8_value(property);
358   CFX_WideString propname =
359       CFX_WideString::FromUTF8(*utf8_value, utf8_value.length());
360   CJS_Object* pJSObj =
361       reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder()));
362   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
363   FX_BOOL bRet = pObj->QueryProperty(propname.c_str());
364   info.GetReturnValue().Set(bRet ? 4 : 0);
365 }
366
367 template <class Alt>
368 void JSSpecialPropGet(const char* class_name,
369                       v8::Local<v8::String> property,
370                       const v8::PropertyCallbackInfo<v8::Value>& info) {
371   v8::Isolate* isolate = info.GetIsolate();
372   IFXJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate);
373   if (!pRuntime)
374     return;
375   IFXJS_Context* pRuntimeContext = pRuntime->GetCurrentContext();
376   CJS_Object* pJSObj =
377       reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder()));
378   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
379   v8::String::Utf8Value utf8_value(property);
380   CFX_WideString propname =
381       CFX_WideString::FromUTF8(*utf8_value, utf8_value.length());
382   CFX_WideString sError;
383   CJS_PropValue value(isolate);
384   value.StartGetting();
385   if (!pObj->DoProperty(pRuntimeContext, propname.c_str(), value, sError)) {
386     FXJS_Error(isolate, JSFormatErrorString(class_name, "GetProperty", sError));
387     return;
388   }
389   info.GetReturnValue().Set((v8::Local<v8::Value>)value);
390 }
391
392 template <class Alt>
393 void JSSpecialPropPut(const char* class_name,
394                       v8::Local<v8::String> property,
395                       v8::Local<v8::Value> value,
396                       const v8::PropertyCallbackInfo<v8::Value>& info) {
397   v8::Isolate* isolate = info.GetIsolate();
398   IFXJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate);
399   if (!pRuntime)
400     return;
401   IFXJS_Context* pRuntimeContext = pRuntime->GetCurrentContext();
402   CJS_Object* pJSObj =
403       reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder()));
404   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
405   v8::String::Utf8Value utf8_value(property);
406   CFX_WideString propname =
407       CFX_WideString::FromUTF8(*utf8_value, utf8_value.length());
408   CFX_WideString sError;
409   CJS_PropValue PropValue(CJS_Value(isolate, value, CJS_Value::VT_unknown));
410   PropValue.StartSetting();
411   if (!pObj->DoProperty(pRuntimeContext, propname.c_str(), PropValue, sError)) {
412     FXJS_Error(isolate, JSFormatErrorString(class_name, "PutProperty", sError));
413   }
414 }
415
416 template <class Alt>
417 void JSSpecialPropDel(const char* class_name,
418                       v8::Local<v8::String> property,
419                       const v8::PropertyCallbackInfo<v8::Boolean>& info) {
420   v8::Isolate* isolate = info.GetIsolate();
421   IFXJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate);
422   if (!pRuntime)
423     return;
424   IFXJS_Context* pRuntimeContext = pRuntime->GetCurrentContext();
425   CJS_Object* pJSObj =
426       reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder()));
427   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
428   v8::String::Utf8Value utf8_value(property);
429   CFX_WideString propname =
430       CFX_WideString::FromUTF8(*utf8_value, utf8_value.length());
431   CFX_WideString sError;
432   if (!pObj->DelProperty(pRuntimeContext, propname.c_str(), sError)) {
433     CFX_ByteString cbName;
434     cbName.Format("%s.%s", class_name, "DelProperty");
435     // Probably a missing call to JSFX_Error().
436   }
437 }
438
439 template <FX_BOOL (*F)(IFXJS_Context* cc,
440                        const CJS_Parameters& params,
441                        CJS_Value& vRet,
442                        CFX_WideString& sError)>
443 void JSGlobalFunc(const char* func_name_string,
444                   const v8::FunctionCallbackInfo<v8::Value>& info) {
445   v8::Isolate* isolate = info.GetIsolate();
446   IFXJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate);
447   if (!pRuntime)
448     return;
449   IFXJS_Context* cc = pRuntime->GetCurrentContext();
450   CJS_Parameters parameters;
451   for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) {
452     parameters.push_back(CJS_Value(isolate, info[i], CJS_Value::VT_unknown));
453   }
454   CJS_Value valueRes(isolate);
455   CFX_WideString sError;
456   if (!(*F)(cc, parameters, valueRes, sError)) {
457     FXJS_Error(isolate, 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_