Clean up CPDF_AnnotList.
[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)(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 CJS_Parameters&,
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   CJS_Parameters 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* pRuntimeContext = 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(pRuntimeContext, 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* pRuntimeContext = 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(pRuntimeContext, 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* pRuntimeContext = 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(pRuntimeContext, 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 (
439     *F)(IJS_Context*, const CJS_Parameters&, CJS_Value&, CFX_WideString&)>
440 void JSGlobalFunc(const char* func_name_string,
441                   const v8::FunctionCallbackInfo<v8::Value>& info) {
442   CJS_Runtime* pRuntime =
443       static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(info.GetIsolate()));
444   if (!pRuntime)
445     return;
446   IJS_Context* pContext = pRuntime->GetCurrentContext();
447   CJS_Parameters parameters;
448   for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) {
449     parameters.push_back(CJS_Value(pRuntime, info[i], CJS_Value::VT_unknown));
450   }
451   CJS_Value valueRes(pRuntime);
452   CFX_WideString sError;
453   if (!(*F)(pContext, parameters, valueRes, sError)) {
454     FXJS_Error(pRuntime->GetIsolate(),
455                JSFormatErrorString(func_name_string, nullptr, sError));
456     return;
457   }
458   info.GetReturnValue().Set(valueRes.ToV8Value());
459 }
460
461 #define JS_STATIC_GLOBAL_FUN(fun_name)                   \
462   static void fun_name##_static(                         \
463       const v8::FunctionCallbackInfo<v8::Value>& info) { \
464     JSGlobalFunc<fun_name>(#fun_name, info);             \
465   }
466
467 #define JS_STATIC_DECLARE_GLOBAL_FUN()  \
468   static JSMethodSpec global_methods[]; \
469   static void DefineJSObjects(v8::Isolate* pIsolate)
470
471 #define BEGIN_JS_STATIC_GLOBAL_FUN(js_class_name) \
472   JSMethodSpec js_class_name::global_methods[] = {
473 #define JS_STATIC_GLOBAL_FUN_ENTRY(method_name) \
474   JS_STATIC_METHOD_ENTRY(method_name)
475
476 #define END_JS_STATIC_GLOBAL_FUN() END_JS_STATIC_METHOD()
477
478 #define IMPLEMENT_JS_STATIC_GLOBAL_FUN(js_class_name)                        \
479   void js_class_name::DefineJSObjects(v8::Isolate* pIsolate) {               \
480     for (size_t i = 0; i < FX_ArraySize(global_methods) - 1; ++i) {          \
481       FXJS_DefineGlobalMethod(pIsolate,                                      \
482                               js_class_name::global_methods[i].pName,        \
483                               js_class_name::global_methods[i].pMethodCall); \
484     }                                                                        \
485   }
486
487 CJS_Value::Type GET_VALUE_TYPE(v8::Local<v8::Value> p);
488
489 #endif  // FPDFSDK_SRC_JAVASCRIPT_JS_DEFINE_H_