Remove JS macros

This CL removes the JS macros and inlines the code directly into the
requisite classes.

Change-Id: I514ca025be42cd46b041b4af271f7b1d1067ab42
Reviewed-on: https://pdfium-review.googlesource.com/16890
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
diff --git a/fpdfsdk/javascript/Document.cpp b/fpdfsdk/javascript/Document.cpp
index 0280af4..940b7b7 100644
--- a/fpdfsdk/javascript/Document.cpp
+++ b/fpdfsdk/javascript/Document.cpp
@@ -44,7 +44,55 @@
 
 JSMethodSpec CJS_PrintParamsObj::MethodSpecs[] = {{0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_PrintParamsObj, PrintParamsObj, PrintParamsObj)
+const char* CJS_PrintParamsObj::g_pClassName = "PrintParamsObj";
+int CJS_PrintParamsObj::g_nObjDefnID = -1;
+
+void CJS_PrintParamsObj::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_PrintParamsObj::JSConstructor(CFXJS_Engine* pEngine,
+                                       v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_PrintParamsObj(obj);
+  pObj->SetEmbedObject(new PrintParamsObj(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_PrintParamsObj::JSDestructor(CFXJS_Engine* pEngine,
+                                      v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_PrintParamsObj*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_PrintParamsObj::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_PrintParamsObj::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_PrintParamsObj::DefineJSObjects(CFXJS_Engine* pEngine,
+                                         FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_PrintParamsObj::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 PrintParamsObj::PrintParamsObj(CJS_Object* pJSObject)
     : CJS_EmbedObj(pJSObject) {
@@ -145,7 +193,55 @@
     {"mailDoc", mailDoc_static},
     {0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Document, Document, Document)
+const char* CJS_Document::g_pClassName = "Document";
+int CJS_Document::g_nObjDefnID = -1;
+
+void CJS_Document::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Document::JSConstructor(CFXJS_Engine* pEngine,
+                                 v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Document(obj);
+  pObj->SetEmbedObject(new Document(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Document::JSDestructor(CFXJS_Engine* pEngine,
+                                v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Document*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Document::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Document::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Document::DefineJSObjects(CFXJS_Engine* pEngine,
+                                   FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Document::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 void CJS_Document::InitInstance(IJS_Runtime* pIRuntime) {
   CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime);
diff --git a/fpdfsdk/javascript/Document.h b/fpdfsdk/javascript/Document.h
index 18469b0..3c6c388 100644
--- a/fpdfsdk/javascript/Document.h
+++ b/fpdfsdk/javascript/Document.h
@@ -38,7 +38,17 @@
       : CJS_Object(pObject) {}
   ~CJS_PrintParamsObj() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
 };
 
 struct CJS_AnnotObj;
@@ -269,7 +279,17 @@
   // CJS_Object
   void InitInstance(IJS_Runtime* pIRuntime) override;
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
 
   JS_STATIC_PROP(ADBE, ADBE, Document);
   JS_STATIC_PROP(author, author, Document);
diff --git a/fpdfsdk/javascript/Field.cpp b/fpdfsdk/javascript/Field.cpp
index 12791e7..0729292 100644
--- a/fpdfsdk/javascript/Field.cpp
+++ b/fpdfsdk/javascript/Field.cpp
@@ -167,7 +167,53 @@
     {"signatureValidate", signatureValidate_static},
     {0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Field, Field, Field)
+const char* CJS_Field::g_pClassName = "Field";
+int CJS_Field::g_nObjDefnID = -1;
+
+void CJS_Field::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Field::JSConstructor(CFXJS_Engine* pEngine,
+                              v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Field(obj);
+  pObj->SetEmbedObject(new Field(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Field::JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Field*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Field::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Field::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Field::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Field::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 CJS_DelayData::CJS_DelayData(FIELD_PROP prop, int idx, const WideString& name)
     : eProp(prop), nControlIndex(idx), sFieldName(name) {}
diff --git a/fpdfsdk/javascript/Field.h b/fpdfsdk/javascript/Field.h
index 37c7d42..41f8535 100644
--- a/fpdfsdk/javascript/Field.h
+++ b/fpdfsdk/javascript/Field.h
@@ -364,7 +364,18 @@
 
   void InitInstance(IJS_Runtime* pIRuntime) override;
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
+
   JS_STATIC_PROP(alignment, alignment, Field);
   JS_STATIC_PROP(borderStyle, border_style, Field);
   JS_STATIC_PROP(buttonAlignX, button_align_x, Field);
diff --git a/fpdfsdk/javascript/Icon.cpp b/fpdfsdk/javascript/Icon.cpp
index 2eefaf1..0d9b1d5 100644
--- a/fpdfsdk/javascript/Icon.cpp
+++ b/fpdfsdk/javascript/Icon.cpp
@@ -18,7 +18,52 @@
 
 JSMethodSpec CJS_Icon::MethodSpecs[] = {{0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Icon, Icon, Icon)
+const char* CJS_Icon::g_pClassName = "Icon";
+int CJS_Icon::g_nObjDefnID = -1;
+
+void CJS_Icon::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Icon::JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Icon(obj);
+  pObj->SetEmbedObject(new Icon(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Icon::JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Icon*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Icon::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Icon::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Icon::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Icon::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 Icon::Icon(CJS_Object* pJSObject)
     : CJS_EmbedObj(pJSObject), m_swIconName(L"") {}
diff --git a/fpdfsdk/javascript/Icon.h b/fpdfsdk/javascript/Icon.h
index 704ecbd..60a5c30 100644
--- a/fpdfsdk/javascript/Icon.h
+++ b/fpdfsdk/javascript/Icon.h
@@ -31,7 +31,18 @@
   explicit CJS_Icon(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Icon() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
+
   JS_STATIC_PROP(name, name, Icon);
 };
 
diff --git a/fpdfsdk/javascript/JS_Define.h b/fpdfsdk/javascript/JS_Define.h
index 22ce7cb..7d089aa 100644
--- a/fpdfsdk/javascript/JS_Define.h
+++ b/fpdfsdk/javascript/JS_Define.h
@@ -14,6 +14,13 @@
 #include "fpdfsdk/javascript/resource.h"
 #include "fxjs/fxjs_v8.h"
 
+// All JS classes have a name, an object defintion ID, and the ability to
+// register themselves with FXJS_V8. We never make a BASE class on its own
+// because it can't really do anything.
+
+// Rich JS classes provide constants, methods, properties, and the ability
+// to construct native object state.
+
 struct JSConstSpec {
   enum Type { Number = 0, String = 1 };
 
@@ -85,20 +92,6 @@
   }
 }
 
-#define JS_STATIC_PROP(err_name, prop_name, class_name)           \
-  static void get_##prop_name##_static(                           \
-      v8::Local<v8::String> property,                             \
-      const v8::PropertyCallbackInfo<v8::Value>& info) {          \
-    JSPropGetter<class_name, &class_name::get_##prop_name>(       \
-        #err_name, #class_name, property, info);                  \
-  }                                                               \
-  static void set_##prop_name##_static(                           \
-      v8::Local<v8::String> property, v8::Local<v8::Value> value, \
-      const v8::PropertyCallbackInfo<void>& info) {               \
-    JSPropSetter<class_name, &class_name::set_##prop_name>(       \
-        #err_name, #class_name, property, value, info);           \
-  }
-
 template <class C,
           CJS_Return (C::*M)(CJS_Runtime*,
                              const std::vector<v8::Local<v8::Value>>&)>
@@ -131,6 +124,20 @@
     info.GetReturnValue().Set(result.Return());
 }
 
+#define JS_STATIC_PROP(err_name, prop_name, class_name)           \
+  static void get_##prop_name##_static(                           \
+      v8::Local<v8::String> property,                             \
+      const v8::PropertyCallbackInfo<v8::Value>& info) {          \
+    JSPropGetter<class_name, &class_name::get_##prop_name>(       \
+        #err_name, #class_name, property, info);                  \
+  }                                                               \
+  static void set_##prop_name##_static(                           \
+      v8::Local<v8::String> property, v8::Local<v8::Value> value, \
+      const v8::PropertyCallbackInfo<void>& info) {               \
+    JSPropSetter<class_name, &class_name::set_##prop_name>(       \
+        #err_name, #class_name, property, value, info);           \
+  }
+
 #define JS_STATIC_METHOD(method_name, class_name)                             \
   static void method_name##_static(                                           \
       const v8::FunctionCallbackInfo<v8::Value>& info) {                      \
@@ -138,95 +145,4 @@
                                                    info);                     \
   }
 
-// All JS classes have a name, an object defintion ID, and the ability to
-// register themselves with FXJS_V8. We never make a BASE class on its own
-// because it can't really do anything.
-#define DECLARE_JS_CLASS_BASE_PART() \
-  static const char* g_pClassName;   \
-  static int g_nObjDefnID;           \
-  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
-
-#define IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \
-  const char* js_class_name::g_pClassName = #class_name;        \
-  int js_class_name::g_nObjDefnID = -1;
-
-#define DECLARE_JS_CLASS_CONST_PART() \
-  static JSConstSpec ConstSpecs[];    \
-  static void DefineConsts(CFXJS_Engine* pEngine);
-
-#define IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)         \
-  void js_class_name::DefineConsts(CFXJS_Engine* pEngine) {              \
-    for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {          \
-      pEngine->DefineObjConst(                                           \
-          g_nObjDefnID, ConstSpecs[i].pName,                             \
-          ConstSpecs[i].eType == JSConstSpec::Number                     \
-              ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>() \
-              : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>()); \
-    }                                                                    \
-  }
-
-#define IMPLEMENT_JS_CLASS_CONST(js_class_name, class_name)                  \
-  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                    \
-  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                   \
-  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                 \
-                                      FXJSOBJTYPE eObjType) {                \
-    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType, \
-                                      nullptr, nullptr);                     \
-    DefineConsts(pEngine);                                                   \
-  }
-
-// Rich JS classes provide constants, methods, properties, and the ability
-// to construct native object state.
-#define DECLARE_JS_CLASS()      \
-  DECLARE_JS_CLASS_BASE_PART()  \
-  DECLARE_JS_CLASS_CONST_PART() \
-  DECLARE_JS_CLASS_PART()
-
-#define IMPLEMENT_JS_CLASS(js_class_name, class_alternate, class_name)       \
-  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                    \
-  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                   \
-  IMPLEMENT_JS_CLASS_PART(js_class_name, class_alternate, class_name)        \
-  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                 \
-                                      FXJSOBJTYPE eObjType) {                \
-    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType, \
-                                      JSConstructor, JSDestructor);          \
-    DefineConsts(pEngine);                                                   \
-    DefineProps(pEngine);                                                    \
-    DefineMethods(pEngine);                                                  \
-  }
-
-#define DECLARE_JS_CLASS_PART()                                                \
-  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj); \
-  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);  \
-  static void DefineProps(CFXJS_Engine* pEngine);                              \
-  static void DefineMethods(CFXJS_Engine* pEngine);                            \
-  static JSPropertySpec PropertySpecs[];                                       \
-  static JSMethodSpec MethodSpecs[];
-
-#define IMPLEMENT_JS_CLASS_PART(js_class_name, class_alternate, class_name) \
-  void js_class_name::JSConstructor(CFXJS_Engine* pEngine,                  \
-                                    v8::Local<v8::Object> obj) {            \
-    CJS_Object* pObj = new js_class_name(obj);                              \
-    pObj->SetEmbedObject(new class_alternate(pObj));                        \
-    pEngine->SetObjectPrivate(obj, pObj);                                   \
-    pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));                 \
-  }                                                                         \
-  void js_class_name::JSDestructor(CFXJS_Engine* pEngine,                   \
-                                   v8::Local<v8::Object> obj) {             \
-    delete static_cast<js_class_name*>(pEngine->GetObjectPrivate(obj));     \
-  }                                                                         \
-  void js_class_name::DefineProps(CFXJS_Engine* pEngine) {                  \
-    for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {          \
-      pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,      \
-                                 PropertySpecs[i].pPropGet,                 \
-                                 PropertySpecs[i].pPropPut);                \
-    }                                                                       \
-  }                                                                         \
-  void js_class_name::DefineMethods(CFXJS_Engine* pEngine) {                \
-    for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {            \
-      pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,          \
-                               MethodSpecs[i].pMethodCall);                 \
-    }                                                                       \
-  }
-
 #endif  // FPDFSDK_JAVASCRIPT_JS_DEFINE_H_
diff --git a/fpdfsdk/javascript/app.cpp b/fpdfsdk/javascript/app.cpp
index 1d78c1d..486c74d 100644
--- a/fpdfsdk/javascript/app.cpp
+++ b/fpdfsdk/javascript/app.cpp
@@ -148,7 +148,55 @@
 
 JSMethodSpec CJS_TimerObj::MethodSpecs[] = {{0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_TimerObj, TimerObj, TimerObj)
+const char* CJS_TimerObj::g_pClassName = "TimerObj";
+int CJS_TimerObj::g_nObjDefnID = -1;
+
+void CJS_TimerObj::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_TimerObj::JSConstructor(CFXJS_Engine* pEngine,
+                                 v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_TimerObj(obj);
+  pObj->SetEmbedObject(new TimerObj(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_TimerObj::JSDestructor(CFXJS_Engine* pEngine,
+                                v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_TimerObj*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_TimerObj::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_TimerObj::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_TimerObj::DefineJSObjects(CFXJS_Engine* pEngine,
+                                   FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_TimerObj::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 TimerObj::TimerObj(CJS_Object* pJSObject)
     : CJS_EmbedObj(pJSObject), m_nTimerID(0) {}
@@ -211,7 +259,52 @@
                                        {"setTimeOut", setTimeOut_static},
                                        {0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_App, app, app)
+const char* CJS_App::g_pClassName = "app";
+int CJS_App::g_nObjDefnID = -1;
+
+void CJS_App::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_App::JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_App(obj);
+  pObj->SetEmbedObject(new app(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_App::JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_App*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_App::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_App::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_App::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_App::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 app::app(CJS_Object* pJSObject)
     : CJS_EmbedObj(pJSObject), m_bCalculate(true), m_bRuntimeHighLight(false) {}
diff --git a/fpdfsdk/javascript/app.h b/fpdfsdk/javascript/app.h
index b88e0fe..41190ca 100644
--- a/fpdfsdk/javascript/app.h
+++ b/fpdfsdk/javascript/app.h
@@ -33,7 +33,17 @@
   explicit CJS_TimerObj(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_TimerObj() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
 };
 
 class app : public CJS_EmbedObj {
@@ -143,7 +153,17 @@
   explicit CJS_App(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_App() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
 
   JS_STATIC_PROP(activeDocs, active_docs, app);
   JS_STATIC_PROP(calculate, calculate, app);
diff --git a/fpdfsdk/javascript/cjs_annot.cpp b/fpdfsdk/javascript/cjs_annot.cpp
index e69f7ce..82d11cc 100644
--- a/fpdfsdk/javascript/cjs_annot.cpp
+++ b/fpdfsdk/javascript/cjs_annot.cpp
@@ -29,7 +29,53 @@
 
 JSMethodSpec CJS_Annot::MethodSpecs[] = {{0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Annot, Annot, Annot)
+const char* CJS_Annot::g_pClassName = "Annot";
+int CJS_Annot::g_nObjDefnID = -1;
+
+void CJS_Annot::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Annot::JSConstructor(CFXJS_Engine* pEngine,
+                              v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Annot(obj);
+  pObj->SetEmbedObject(new Annot(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Annot::JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Annot*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Annot::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Annot::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Annot::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Annot::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 Annot::Annot(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {}
 
diff --git a/fpdfsdk/javascript/cjs_annot.h b/fpdfsdk/javascript/cjs_annot.h
index d630431..74162ea 100644
--- a/fpdfsdk/javascript/cjs_annot.h
+++ b/fpdfsdk/javascript/cjs_annot.h
@@ -35,7 +35,18 @@
   explicit CJS_Annot(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Annot() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
+
   JS_STATIC_PROP(hidden, hidden, Annot);
   JS_STATIC_PROP(name, name, Annot);
   JS_STATIC_PROP(type, type, Annot);
diff --git a/fpdfsdk/javascript/cjs_border.cpp b/fpdfsdk/javascript/cjs_border.cpp
index 2a310ac..50e69b2 100644
--- a/fpdfsdk/javascript/cjs_border.cpp
+++ b/fpdfsdk/javascript/cjs_border.cpp
@@ -14,4 +14,21 @@
     {"u", JSConstSpec::String, 0, "underline"},
     {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_Border, border)
+const char* CJS_Border::g_pClassName = "border";
+int CJS_Border::g_nObjDefnID = -1;
+
+void CJS_Border::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Border::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID =
+      pEngine->DefineObj(CJS_Border::g_pClassName, eObjType, nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_border.h b/fpdfsdk/javascript/cjs_border.h
index 6dd362a..c3ce247 100644
--- a/fpdfsdk/javascript/cjs_border.h
+++ b/fpdfsdk/javascript/cjs_border.h
@@ -14,8 +14,12 @@
   explicit CJS_Border(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Border() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_BORDER_H_
diff --git a/fpdfsdk/javascript/cjs_display.cpp b/fpdfsdk/javascript/cjs_display.cpp
index 4b6000f..df05ed2 100644
--- a/fpdfsdk/javascript/cjs_display.cpp
+++ b/fpdfsdk/javascript/cjs_display.cpp
@@ -12,4 +12,21 @@
                                          {"noView", JSConstSpec::Number, 3, 0},
                                          {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_Display, display)
+const char* CJS_Display::g_pClassName = "display";
+int CJS_Display::g_nObjDefnID = -1;
+
+void CJS_Display::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Display::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID =
+      pEngine->DefineObj(CJS_Display::g_pClassName, eObjType, nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_display.h b/fpdfsdk/javascript/cjs_display.h
index 9965170..f92eb86 100644
--- a/fpdfsdk/javascript/cjs_display.h
+++ b/fpdfsdk/javascript/cjs_display.h
@@ -14,8 +14,12 @@
   explicit CJS_Display(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Display() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_DISPLAY_H_
diff --git a/fpdfsdk/javascript/cjs_font.cpp b/fpdfsdk/javascript/cjs_font.cpp
index cd7047d..799702c 100644
--- a/fpdfsdk/javascript/cjs_font.cpp
+++ b/fpdfsdk/javascript/cjs_font.cpp
@@ -23,4 +23,21 @@
     {"ZapfD", JSConstSpec::String, 0, "ZapfDingbats"},
     {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_Font, font)
+const char* CJS_Font::g_pClassName = "font";
+int CJS_Font::g_nObjDefnID = -1;
+
+void CJS_Font::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Font::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID =
+      pEngine->DefineObj(CJS_Font::g_pClassName, eObjType, nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_font.h b/fpdfsdk/javascript/cjs_font.h
index 05cca73..d45a578 100644
--- a/fpdfsdk/javascript/cjs_font.h
+++ b/fpdfsdk/javascript/cjs_font.h
@@ -14,8 +14,12 @@
   explicit CJS_Font(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Font() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_FONT_H_
diff --git a/fpdfsdk/javascript/cjs_global.cpp b/fpdfsdk/javascript/cjs_global.cpp
index 4cf85bd..d81fe04 100644
--- a/fpdfsdk/javascript/cjs_global.cpp
+++ b/fpdfsdk/javascript/cjs_global.cpp
@@ -21,46 +21,6 @@
 #include "fpdfsdk/javascript/cjs_eventhandler.h"
 #include "fpdfsdk/javascript/resource.h"
 
-#define IMPLEMENT_SPECIAL_JS_CLASS(js_class_name, class_alternate, class_name) \
-  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                      \
-  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                     \
-  IMPLEMENT_JS_CLASS_PART(js_class_name, class_alternate, class_name)          \
-  void js_class_name::queryprop_static(                                        \
-      v8::Local<v8::String> property,                                          \
-      const v8::PropertyCallbackInfo<v8::Integer>& info) {                     \
-    JSSpecialPropQuery<class_alternate>(#class_name, property, info);          \
-  }                                                                            \
-  void js_class_name::getprop_static(                                          \
-      v8::Local<v8::String> property,                                          \
-      const v8::PropertyCallbackInfo<v8::Value>& info) {                       \
-    JSSpecialPropGet<class_alternate>(#class_name, property, info);            \
-  }                                                                            \
-  void js_class_name::putprop_static(                                          \
-      v8::Local<v8::String> property, v8::Local<v8::Value> value,              \
-      const v8::PropertyCallbackInfo<v8::Value>& info) {                       \
-    JSSpecialPropPut<class_alternate>(#class_name, property, value, info);     \
-  }                                                                            \
-  void js_class_name::delprop_static(                                          \
-      v8::Local<v8::String> property,                                          \
-      const v8::PropertyCallbackInfo<v8::Boolean>& info) {                     \
-    JSSpecialPropDel<class_alternate>(#class_name, property, info);            \
-  }                                                                            \
-  void js_class_name::DefineAllProperties(CFXJS_Engine* pEngine) {             \
-    pEngine->DefineObjAllProperties(                                           \
-        g_nObjDefnID, js_class_name::queryprop_static,                         \
-        js_class_name::getprop_static, js_class_name::putprop_static,          \
-        js_class_name::delprop_static);                                        \
-  }                                                                            \
-  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                   \
-                                      FXJSOBJTYPE eObjType) {                  \
-    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType,   \
-                                      JSConstructor, JSDestructor);            \
-    DefineConsts(pEngine);                                                     \
-    DefineProps(pEngine);                                                      \
-    DefineMethods(pEngine);                                                    \
-    DefineAllProperties(pEngine);                                              \
-  }
-
 namespace {
 
 WideString PropFromV8Prop(v8::Local<v8::String> property) {
@@ -222,7 +182,8 @@
     {"setPersistent", setPersistent_static},
     {0, 0}};
 
-IMPLEMENT_SPECIAL_JS_CLASS(CJS_Global, JSGlobalAlternate, global);
+const char* CJS_Global::g_pClassName = "global";
+int CJS_Global::g_nObjDefnID = -1;
 
 // static
 void CJS_Global::setPersistent_static(
@@ -238,6 +199,84 @@
   pGlobal->Initial(pRuntime->GetFormFillEnv());
 }
 
+void CJS_Global::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Global::JSConstructor(CFXJS_Engine* pEngine,
+                               v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Global(obj);
+  pObj->SetEmbedObject(new JSGlobalAlternate(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Global::JSDestructor(CFXJS_Engine* pEngine,
+                              v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Global*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Global::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Global::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Global::queryprop_static(
+    v8::Local<v8::String> property,
+    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+  JSSpecialPropQuery<JSGlobalAlternate>("global", property, info);
+}
+
+void CJS_Global::getprop_static(
+    v8::Local<v8::String> property,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
+  JSSpecialPropGet<JSGlobalAlternate>("global", property, info);
+}
+
+void CJS_Global::putprop_static(
+    v8::Local<v8::String> property,
+    v8::Local<v8::Value> value,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
+  JSSpecialPropPut<JSGlobalAlternate>("global", property, value, info);
+}
+
+void CJS_Global::delprop_static(
+    v8::Local<v8::String> property,
+    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
+  JSSpecialPropDel<JSGlobalAlternate>("global", property, info);
+}
+
+void CJS_Global::DefineAllProperties(CFXJS_Engine* pEngine) {
+  pEngine->DefineObjAllProperties(
+      g_nObjDefnID, CJS_Global::queryprop_static, CJS_Global::getprop_static,
+      CJS_Global::putprop_static, CJS_Global::delprop_static);
+}
+
+void CJS_Global::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Global::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+  DefineAllProperties(pEngine);
+}
+
 JSGlobalData::JSGlobalData()
     : nType(JS_GlobalDataType::NUMBER),
       dData(0),
diff --git a/fpdfsdk/javascript/cjs_global.h b/fpdfsdk/javascript/cjs_global.h
index a98bf97..96788f7 100644
--- a/fpdfsdk/javascript/cjs_global.h
+++ b/fpdfsdk/javascript/cjs_global.h
@@ -17,9 +17,20 @@
   // CJS_Object
   void InitInstance(IJS_Runtime* pIRuntime) override;
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
-  DECLARE_JS_CLASS_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
+
   static void queryprop_static(
       v8::Local<v8::String> property,
       const v8::PropertyCallbackInfo<v8::Integer>& info);
diff --git a/fpdfsdk/javascript/cjs_highlight.cpp b/fpdfsdk/javascript/cjs_highlight.cpp
index 3c70543..6cd40dc 100644
--- a/fpdfsdk/javascript/cjs_highlight.cpp
+++ b/fpdfsdk/javascript/cjs_highlight.cpp
@@ -13,4 +13,22 @@
     {"o", JSConstSpec::String, 0, "outline"},
     {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_Highlight, highlight)
+const char* CJS_Highlight::g_pClassName = "highlight";
+int CJS_Highlight::g_nObjDefnID = -1;
+
+void CJS_Highlight::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Highlight::DefineJSObjects(CFXJS_Engine* pEngine,
+                                    FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Highlight::g_pClassName, eObjType,
+                                    nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_highlight.h b/fpdfsdk/javascript/cjs_highlight.h
index 39f6c0f..0ac645d 100644
--- a/fpdfsdk/javascript/cjs_highlight.h
+++ b/fpdfsdk/javascript/cjs_highlight.h
@@ -14,8 +14,12 @@
   explicit CJS_Highlight(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Highlight() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_HIGHLIGHT_H_
diff --git a/fpdfsdk/javascript/cjs_position.cpp b/fpdfsdk/javascript/cjs_position.cpp
index 9180ff5..5c33546 100644
--- a/fpdfsdk/javascript/cjs_position.cpp
+++ b/fpdfsdk/javascript/cjs_position.cpp
@@ -16,4 +16,22 @@
     {"overlay", JSConstSpec::Number, 6, 0},
     {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_Position, position)
+const char* CJS_Position::g_pClassName = "position";
+int CJS_Position::g_nObjDefnID = -1;
+
+void CJS_Position::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Position::DefineJSObjects(CFXJS_Engine* pEngine,
+                                   FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Position::g_pClassName, eObjType,
+                                    nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_position.h b/fpdfsdk/javascript/cjs_position.h
index 9b81b62..54d12c5 100644
--- a/fpdfsdk/javascript/cjs_position.h
+++ b/fpdfsdk/javascript/cjs_position.h
@@ -14,8 +14,12 @@
   explicit CJS_Position(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Position() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_POSITION_H_
diff --git a/fpdfsdk/javascript/cjs_scalehow.cpp b/fpdfsdk/javascript/cjs_scalehow.cpp
index 8f0938b..25160ba 100644
--- a/fpdfsdk/javascript/cjs_scalehow.cpp
+++ b/fpdfsdk/javascript/cjs_scalehow.cpp
@@ -11,4 +11,22 @@
     {"anamorphic", JSConstSpec::Number, 1, 0},
     {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_ScaleHow, scaleHow)
+const char* CJS_ScaleHow::g_pClassName = "scaleHow";
+int CJS_ScaleHow::g_nObjDefnID = -1;
+
+void CJS_ScaleHow::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_ScaleHow::DefineJSObjects(CFXJS_Engine* pEngine,
+                                   FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_ScaleHow::g_pClassName, eObjType,
+                                    nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_scalehow.h b/fpdfsdk/javascript/cjs_scalehow.h
index 352486d..c742398 100644
--- a/fpdfsdk/javascript/cjs_scalehow.h
+++ b/fpdfsdk/javascript/cjs_scalehow.h
@@ -14,8 +14,12 @@
   explicit CJS_ScaleHow(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_ScaleHow() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_SCALEHOW_H_
diff --git a/fpdfsdk/javascript/cjs_scalewhen.cpp b/fpdfsdk/javascript/cjs_scalewhen.cpp
index b48f329..22c6784 100644
--- a/fpdfsdk/javascript/cjs_scalewhen.cpp
+++ b/fpdfsdk/javascript/cjs_scalewhen.cpp
@@ -13,4 +13,22 @@
     {"tooSmall", JSConstSpec::Number, 3, 0},
     {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_ScaleWhen, scaleWhen)
+const char* CJS_ScaleWhen::g_pClassName = "scaleWhen";
+int CJS_ScaleWhen::g_nObjDefnID = -1;
+
+void CJS_ScaleWhen::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_ScaleWhen::DefineJSObjects(CFXJS_Engine* pEngine,
+                                    FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_ScaleWhen::g_pClassName, eObjType,
+                                    nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_scalewhen.h b/fpdfsdk/javascript/cjs_scalewhen.h
index 7f570eb..d7727e9 100644
--- a/fpdfsdk/javascript/cjs_scalewhen.h
+++ b/fpdfsdk/javascript/cjs_scalewhen.h
@@ -14,8 +14,12 @@
   explicit CJS_ScaleWhen(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_ScaleWhen() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_SCALEWHEN_H_
diff --git a/fpdfsdk/javascript/cjs_style.cpp b/fpdfsdk/javascript/cjs_style.cpp
index 63da925..872851f 100644
--- a/fpdfsdk/javascript/cjs_style.cpp
+++ b/fpdfsdk/javascript/cjs_style.cpp
@@ -15,4 +15,21 @@
     {"sq", JSConstSpec::String, 0, "square"},
     {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_Style, style)
+const char* CJS_Style::g_pClassName = "style";
+int CJS_Style::g_nObjDefnID = -1;
+
+void CJS_Style::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Style::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID =
+      pEngine->DefineObj(CJS_Style::g_pClassName, eObjType, nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_style.h b/fpdfsdk/javascript/cjs_style.h
index 062ae0f..0c98f50 100644
--- a/fpdfsdk/javascript/cjs_style.h
+++ b/fpdfsdk/javascript/cjs_style.h
@@ -14,8 +14,12 @@
   explicit CJS_Style(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Style() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_STYLE_H_
diff --git a/fpdfsdk/javascript/cjs_zoomtype.cpp b/fpdfsdk/javascript/cjs_zoomtype.cpp
index c025f69..fb5e2ab 100644
--- a/fpdfsdk/javascript/cjs_zoomtype.cpp
+++ b/fpdfsdk/javascript/cjs_zoomtype.cpp
@@ -16,4 +16,22 @@
     {"refW", JSConstSpec::String, 0, "ReflowWidth"},
     {0, JSConstSpec::Number, 0, 0}};
 
-IMPLEMENT_JS_CLASS_CONST(CJS_Zoomtype, zoomtype)
+const char* CJS_Zoomtype::g_pClassName = "zoomtype";
+int CJS_Zoomtype::g_nObjDefnID = -1;
+
+void CJS_Zoomtype::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Zoomtype::DefineJSObjects(CFXJS_Engine* pEngine,
+                                   FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Zoomtype::g_pClassName, eObjType,
+                                    nullptr, nullptr);
+  DefineConsts(pEngine);
+}
diff --git a/fpdfsdk/javascript/cjs_zoomtype.h b/fpdfsdk/javascript/cjs_zoomtype.h
index fea0ae9..b204d58 100644
--- a/fpdfsdk/javascript/cjs_zoomtype.h
+++ b/fpdfsdk/javascript/cjs_zoomtype.h
@@ -14,8 +14,12 @@
   explicit CJS_Zoomtype(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Zoomtype() override {}
 
-  DECLARE_JS_CLASS_BASE_PART();
-  DECLARE_JS_CLASS_CONST_PART();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
 };
 
 #endif  // FPDFSDK_JAVASCRIPT_CJS_ZOOMTYPE_H_
diff --git a/fpdfsdk/javascript/color.cpp b/fpdfsdk/javascript/color.cpp
index ad5f8ac..6c80ca0 100644
--- a/fpdfsdk/javascript/color.cpp
+++ b/fpdfsdk/javascript/color.cpp
@@ -36,7 +36,53 @@
                                          {"equal", equal_static},
                                          {0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Color, color, color)
+const char* CJS_Color::g_pClassName = "color";
+int CJS_Color::g_nObjDefnID = -1;
+
+void CJS_Color::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Color::JSConstructor(CFXJS_Engine* pEngine,
+                              v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Color(obj);
+  pObj->SetEmbedObject(new color(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Color::JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Color*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Color::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Color::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Color::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Color::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 // static
 v8::Local<v8::Array> color::ConvertPWLColorToArray(CJS_Runtime* pRuntime,
diff --git a/fpdfsdk/javascript/color.h b/fpdfsdk/javascript/color.h
index cbb759c..17a00eb 100644
--- a/fpdfsdk/javascript/color.h
+++ b/fpdfsdk/javascript/color.h
@@ -88,7 +88,17 @@
   explicit CJS_Color(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Color() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
 
   JS_STATIC_PROP(black, black, color);
   JS_STATIC_PROP(blue, blue, color);
diff --git a/fpdfsdk/javascript/console.cpp b/fpdfsdk/javascript/console.cpp
index ee7bc7f..d3528ee 100644
--- a/fpdfsdk/javascript/console.cpp
+++ b/fpdfsdk/javascript/console.cpp
@@ -24,7 +24,54 @@
                                            {"show", show_static},
                                            {0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Console, console, console)
+const char* CJS_Console::g_pClassName = "console";
+int CJS_Console::g_nObjDefnID = -1;
+
+void CJS_Console::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Console::JSConstructor(CFXJS_Engine* pEngine,
+                                v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Console(obj);
+  pObj->SetEmbedObject(new console(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Console::JSDestructor(CFXJS_Engine* pEngine,
+                               v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Console*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Console::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Console::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Console::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Console::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 console::console(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {}
 
diff --git a/fpdfsdk/javascript/console.h b/fpdfsdk/javascript/console.h
index 4ed66c1..07ee292 100644
--- a/fpdfsdk/javascript/console.h
+++ b/fpdfsdk/javascript/console.h
@@ -32,7 +32,17 @@
   explicit CJS_Console(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Console() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
 
   JS_STATIC_METHOD(clear, console);
   JS_STATIC_METHOD(hide, console);
diff --git a/fpdfsdk/javascript/event.cpp b/fpdfsdk/javascript/event.cpp
index 2439af2..4744f37 100644
--- a/fpdfsdk/javascript/event.cpp
+++ b/fpdfsdk/javascript/event.cpp
@@ -40,7 +40,53 @@
 
 JSMethodSpec CJS_Event::MethodSpecs[] = {{0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Event, event, event)
+const char* CJS_Event::g_pClassName = "event";
+int CJS_Event::g_nObjDefnID = -1;
+
+void CJS_Event::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Event::JSConstructor(CFXJS_Engine* pEngine,
+                              v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Event(obj);
+  pObj->SetEmbedObject(new event(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Event::JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Event*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Event::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Event::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Event::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Event::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 event::event(CJS_Object* pJsObject) : CJS_EmbedObj(pJsObject) {}
 
diff --git a/fpdfsdk/javascript/event.h b/fpdfsdk/javascript/event.h
index ad19e78..1d5c262 100644
--- a/fpdfsdk/javascript/event.h
+++ b/fpdfsdk/javascript/event.h
@@ -80,7 +80,18 @@
   explicit CJS_Event(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Event() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
+
   JS_STATIC_PROP(change, change, event);
   JS_STATIC_PROP(changeEx, change_ex, event);
   JS_STATIC_PROP(commitKey, commit_key, event);
diff --git a/fpdfsdk/javascript/report.cpp b/fpdfsdk/javascript/report.cpp
index 043a68e..0c96139 100644
--- a/fpdfsdk/javascript/report.cpp
+++ b/fpdfsdk/javascript/report.cpp
@@ -20,7 +20,54 @@
                                           {"writeText", writeText_static},
                                           {0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Report, Report, Report)
+const char* CJS_Report::g_pClassName = "Report";
+int CJS_Report::g_nObjDefnID = -1;
+
+void CJS_Report::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Report::JSConstructor(CFXJS_Engine* pEngine,
+                               v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Report(obj);
+  pObj->SetEmbedObject(new Report(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Report::JSDestructor(CFXJS_Engine* pEngine,
+                              v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Report*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Report::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Report::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Report::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Report::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 Report::Report(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {}
 
diff --git a/fpdfsdk/javascript/report.h b/fpdfsdk/javascript/report.h
index da5f179..a733f14 100644
--- a/fpdfsdk/javascript/report.h
+++ b/fpdfsdk/javascript/report.h
@@ -28,7 +28,17 @@
   explicit CJS_Report(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Report() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
 
   JS_STATIC_METHOD(save, Report)
   JS_STATIC_METHOD(writeText, Report);
diff --git a/fpdfsdk/javascript/util.cpp b/fpdfsdk/javascript/util.cpp
index 7e08168..a0d0a57 100644
--- a/fpdfsdk/javascript/util.cpp
+++ b/fpdfsdk/javascript/util.cpp
@@ -37,7 +37,52 @@
     {"printx", printx_static},         {"scand", scand_static},
     {"byteToChar", byteToChar_static}, {0, 0}};
 
-IMPLEMENT_JS_CLASS(CJS_Util, util, util)
+const char* CJS_Util::g_pClassName = "util";
+int CJS_Util::g_nObjDefnID = -1;
+
+void CJS_Util::DefineConsts(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(ConstSpecs) - 1; ++i) {
+    pEngine->DefineObjConst(
+        g_nObjDefnID, ConstSpecs[i].pName,
+        ConstSpecs[i].eType == JSConstSpec::Number
+            ? pEngine->NewNumber(ConstSpecs[i].number).As<v8::Value>()
+            : pEngine->NewString(ConstSpecs[i].pStr).As<v8::Value>());
+  }
+}
+
+void CJS_Util::JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  CJS_Object* pObj = new CJS_Util(obj);
+  pObj->SetEmbedObject(new util(pObj));
+  pEngine->SetObjectPrivate(obj, pObj);
+  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+}
+
+void CJS_Util::JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
+  delete static_cast<CJS_Util*>(pEngine->GetObjectPrivate(obj));
+}
+
+void CJS_Util::DefineProps(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(PropertySpecs) - 1; ++i) {
+    pEngine->DefineObjProperty(g_nObjDefnID, PropertySpecs[i].pName,
+                               PropertySpecs[i].pPropGet,
+                               PropertySpecs[i].pPropPut);
+  }
+}
+
+void CJS_Util::DefineMethods(CFXJS_Engine* pEngine) {
+  for (size_t i = 0; i < FX_ArraySize(MethodSpecs) - 1; ++i) {
+    pEngine->DefineObjMethod(g_nObjDefnID, MethodSpecs[i].pName,
+                             MethodSpecs[i].pMethodCall);
+  }
+}
+
+void CJS_Util::DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType) {
+  g_nObjDefnID = pEngine->DefineObj(CJS_Util::g_pClassName, eObjType,
+                                    JSConstructor, JSDestructor);
+  DefineConsts(pEngine);
+  DefineProps(pEngine);
+  DefineMethods(pEngine);
+}
 
 namespace {
 
diff --git a/fpdfsdk/javascript/util.h b/fpdfsdk/javascript/util.h
index d71897d..05492f3 100644
--- a/fpdfsdk/javascript/util.h
+++ b/fpdfsdk/javascript/util.h
@@ -47,7 +47,17 @@
   explicit CJS_Util(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
   ~CJS_Util() override {}
 
-  DECLARE_JS_CLASS();
+  static const char* g_pClassName;
+  static int g_nObjDefnID;
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
+  static JSConstSpec ConstSpecs[];
+  static void DefineConsts(CFXJS_Engine* pEngine);
+  static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
+  static void DefineProps(CFXJS_Engine* pEngine);
+  static void DefineMethods(CFXJS_Engine* pEngine);
+  static JSPropertySpec PropertySpecs[];
+  static JSMethodSpec MethodSpecs[];
 
   JS_STATIC_METHOD(printd, util);
   JS_STATIC_METHOD(printf, util);