1 // Copyright 2016 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 #include "fxjs/cfxjse_class.h"
8 
9 #include <memory>
10 
11 #include "fxjs/cfxjse_context.h"
12 #include "fxjs/cfxjse_value.h"
13 
14 namespace {
15 
V8FunctionCallback_Wrapper(const v8::FunctionCallbackInfo<v8::Value> & info)16 void V8FunctionCallback_Wrapper(
17     const v8::FunctionCallbackInfo<v8::Value>& info) {
18   const FXJSE_FUNCTION_DESCRIPTOR* lpFunctionInfo =
19       static_cast<FXJSE_FUNCTION_DESCRIPTOR*>(
20           info.Data().As<v8::External>()->Value());
21   if (!lpFunctionInfo)
22     return;
23 
24   CFX_ByteStringC szFunctionName(lpFunctionInfo->name);
25   std::unique_ptr<CFXJSE_Value> lpThisValue(
26       new CFXJSE_Value(info.GetIsolate()));
27   lpThisValue->ForceSetValue(info.This());
28   std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
29   CFXJSE_Arguments impl(&info, lpRetValue.get());
30   lpFunctionInfo->callbackProc(lpThisValue.get(), szFunctionName, impl);
31   if (!lpRetValue->DirectGetValue().IsEmpty())
32     info.GetReturnValue().Set(lpRetValue->DirectGetValue());
33 }
34 
V8ClassGlobalConstructorCallback_Wrapper(const v8::FunctionCallbackInfo<v8::Value> & info)35 void V8ClassGlobalConstructorCallback_Wrapper(
36     const v8::FunctionCallbackInfo<v8::Value>& info) {
37   const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition =
38       static_cast<FXJSE_CLASS_DESCRIPTOR*>(
39           info.Data().As<v8::External>()->Value());
40   if (!lpClassDefinition)
41     return;
42 
43   CFX_ByteStringC szFunctionName(lpClassDefinition->name);
44   std::unique_ptr<CFXJSE_Value> lpThisValue(
45       new CFXJSE_Value(info.GetIsolate()));
46   lpThisValue->ForceSetValue(info.This());
47   std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
48   CFXJSE_Arguments impl(&info, lpRetValue.get());
49   lpClassDefinition->constructor(lpThisValue.get(), szFunctionName, impl);
50   if (!lpRetValue->DirectGetValue().IsEmpty())
51     info.GetReturnValue().Set(lpRetValue->DirectGetValue());
52 }
53 
V8GetterCallback_Wrapper(v8::Local<v8::String> property,const v8::PropertyCallbackInfo<v8::Value> & info)54 void V8GetterCallback_Wrapper(v8::Local<v8::String> property,
55                               const v8::PropertyCallbackInfo<v8::Value>& info) {
56   const FXJSE_PROPERTY_DESCRIPTOR* lpPropertyInfo =
57       static_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
58           info.Data().As<v8::External>()->Value());
59   if (!lpPropertyInfo)
60     return;
61 
62   CFX_ByteStringC szPropertyName(lpPropertyInfo->name);
63   std::unique_ptr<CFXJSE_Value> lpThisValue(
64       new CFXJSE_Value(info.GetIsolate()));
65   std::unique_ptr<CFXJSE_Value> lpPropValue(
66       new CFXJSE_Value(info.GetIsolate()));
67   lpThisValue->ForceSetValue(info.This());
68   lpPropertyInfo->getProc(lpThisValue.get(), szPropertyName, lpPropValue.get());
69   info.GetReturnValue().Set(lpPropValue->DirectGetValue());
70 }
71 
V8SetterCallback_Wrapper(v8::Local<v8::String> property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)72 void V8SetterCallback_Wrapper(v8::Local<v8::String> property,
73                               v8::Local<v8::Value> value,
74                               const v8::PropertyCallbackInfo<void>& info) {
75   const FXJSE_PROPERTY_DESCRIPTOR* lpPropertyInfo =
76       static_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
77           info.Data().As<v8::External>()->Value());
78   if (!lpPropertyInfo)
79     return;
80 
81   CFX_ByteStringC szPropertyName(lpPropertyInfo->name);
82   std::unique_ptr<CFXJSE_Value> lpThisValue(
83       new CFXJSE_Value(info.GetIsolate()));
84   std::unique_ptr<CFXJSE_Value> lpPropValue(
85       new CFXJSE_Value(info.GetIsolate()));
86   lpThisValue->ForceSetValue(info.This());
87   lpPropValue->ForceSetValue(value);
88   lpPropertyInfo->setProc(lpThisValue.get(), szPropertyName, lpPropValue.get());
89 }
90 
V8ConstructorCallback_Wrapper(const v8::FunctionCallbackInfo<v8::Value> & info)91 void V8ConstructorCallback_Wrapper(
92     const v8::FunctionCallbackInfo<v8::Value>& info) {
93   if (!info.IsConstructCall())
94     return;
95 
96   const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition =
97       static_cast<FXJSE_CLASS_DESCRIPTOR*>(
98           info.Data().As<v8::External>()->Value());
99   if (!lpClassDefinition)
100     return;
101 
102   ASSERT(info.This()->InternalFieldCount());
103   info.This()->SetAlignedPointerInInternalField(0, nullptr);
104 }
105 
Context_GlobalObjToString(const v8::FunctionCallbackInfo<v8::Value> & info)106 void Context_GlobalObjToString(
107     const v8::FunctionCallbackInfo<v8::Value>& info) {
108   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
109       info.Data().As<v8::External>()->Value());
110   if (!lpClass)
111     return;
112 
113   if (info.This() == info.Holder() && lpClass->name) {
114     CFX_ByteString szStringVal;
115     szStringVal.Format("[object %s]", lpClass->name);
116     info.GetReturnValue().Set(v8::String::NewFromUtf8(
117         info.GetIsolate(), szStringVal.c_str(), v8::String::kNormalString,
118         szStringVal.GetLength()));
119     return;
120   }
121   v8::Local<v8::String> local_str =
122       info.This()
123           ->ObjectProtoToString(info.GetIsolate()->GetCurrentContext())
124           .FromMaybe(v8::Local<v8::String>());
125   info.GetReturnValue().Set(local_str);
126 }
127 
DynPropGetterAdapter_MethodCallback(const v8::FunctionCallbackInfo<v8::Value> & info)128 void DynPropGetterAdapter_MethodCallback(
129     const v8::FunctionCallbackInfo<v8::Value>& info) {
130   v8::Local<v8::Object> hCallBackInfo = info.Data().As<v8::Object>();
131   FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
132       hCallBackInfo->GetAlignedPointerFromInternalField(0));
133   v8::Local<v8::String> hPropName =
134       hCallBackInfo->GetInternalField(1).As<v8::String>();
135   ASSERT(lpClass && !hPropName.IsEmpty());
136   v8::String::Utf8Value szPropName(hPropName);
137   CFX_ByteStringC szFxPropName = *szPropName;
138   std::unique_ptr<CFXJSE_Value> lpThisValue(
139       new CFXJSE_Value(info.GetIsolate()));
140   lpThisValue->ForceSetValue(info.This());
141   std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
142   CFXJSE_Arguments impl(&info, lpRetValue.get());
143   lpClass->dynMethodCall(lpThisValue.get(), szFxPropName, impl);
144   if (!lpRetValue->DirectGetValue().IsEmpty())
145     info.GetReturnValue().Set(lpRetValue->DirectGetValue());
146 }
147 
DynPropGetterAdapter(const FXJSE_CLASS_DESCRIPTOR * lpClass,CFXJSE_Value * pObject,const CFX_ByteStringC & szPropName,CFXJSE_Value * pValue)148 void DynPropGetterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
149                           CFXJSE_Value* pObject,
150                           const CFX_ByteStringC& szPropName,
151                           CFXJSE_Value* pValue) {
152   ASSERT(lpClass);
153   int32_t nPropType =
154       lpClass->dynPropTypeGetter == nullptr
155           ? FXJSE_ClassPropType_Property
156           : lpClass->dynPropTypeGetter(pObject, szPropName, false);
157   if (nPropType == FXJSE_ClassPropType_Property) {
158     if (lpClass->dynPropGetter)
159       lpClass->dynPropGetter(pObject, szPropName, pValue);
160   } else if (nPropType == FXJSE_ClassPropType_Method) {
161     if (lpClass->dynMethodCall && pValue) {
162       v8::Isolate* pIsolate = pValue->GetIsolate();
163       v8::HandleScope hscope(pIsolate);
164       v8::Local<v8::ObjectTemplate> hCallBackInfoTemplate =
165           v8::ObjectTemplate::New(pIsolate);
166       hCallBackInfoTemplate->SetInternalFieldCount(2);
167       v8::Local<v8::Object> hCallBackInfo =
168           hCallBackInfoTemplate->NewInstance();
169       hCallBackInfo->SetAlignedPointerInInternalField(
170           0, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClass));
171       hCallBackInfo->SetInternalField(
172           1, v8::String::NewFromUtf8(
173                  pIsolate, reinterpret_cast<const char*>(szPropName.raw_str()),
174                  v8::String::kNormalString, szPropName.GetLength()));
175       pValue->ForceSetValue(
176           v8::Function::New(pValue->GetIsolate()->GetCurrentContext(),
177                             DynPropGetterAdapter_MethodCallback, hCallBackInfo,
178                             0, v8::ConstructorBehavior::kThrow)
179               .ToLocalChecked());
180     }
181   }
182 }
183 
DynPropSetterAdapter(const FXJSE_CLASS_DESCRIPTOR * lpClass,CFXJSE_Value * pObject,const CFX_ByteStringC & szPropName,CFXJSE_Value * pValue)184 void DynPropSetterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
185                           CFXJSE_Value* pObject,
186                           const CFX_ByteStringC& szPropName,
187                           CFXJSE_Value* pValue) {
188   ASSERT(lpClass);
189   int32_t nPropType =
190       lpClass->dynPropTypeGetter == nullptr
191           ? FXJSE_ClassPropType_Property
192           : lpClass->dynPropTypeGetter(pObject, szPropName, false);
193   if (nPropType != FXJSE_ClassPropType_Method) {
194     if (lpClass->dynPropSetter)
195       lpClass->dynPropSetter(pObject, szPropName, pValue);
196   }
197 }
198 
DynPropQueryAdapter(const FXJSE_CLASS_DESCRIPTOR * lpClass,CFXJSE_Value * pObject,const CFX_ByteStringC & szPropName)199 bool DynPropQueryAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
200                          CFXJSE_Value* pObject,
201                          const CFX_ByteStringC& szPropName) {
202   ASSERT(lpClass);
203   int32_t nPropType =
204       lpClass->dynPropTypeGetter == nullptr
205           ? FXJSE_ClassPropType_Property
206           : lpClass->dynPropTypeGetter(pObject, szPropName, true);
207   return nPropType != FXJSE_ClassPropType_None;
208 }
209 
DynPropDeleterAdapter(const FXJSE_CLASS_DESCRIPTOR * lpClass,CFXJSE_Value * pObject,const CFX_ByteStringC & szPropName)210 bool DynPropDeleterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
211                            CFXJSE_Value* pObject,
212                            const CFX_ByteStringC& szPropName) {
213   ASSERT(lpClass);
214   int32_t nPropType =
215       lpClass->dynPropTypeGetter == nullptr
216           ? FXJSE_ClassPropType_Property
217           : lpClass->dynPropTypeGetter(pObject, szPropName, false);
218   if (nPropType != FXJSE_ClassPropType_Method) {
219     if (lpClass->dynPropDeleter)
220       return lpClass->dynPropDeleter(pObject, szPropName);
221     return nPropType != FXJSE_ClassPropType_Property;
222   }
223   return false;
224 }
225 
NamedPropertyQueryCallback(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Integer> & info)226 void NamedPropertyQueryCallback(
227     v8::Local<v8::Name> property,
228     const v8::PropertyCallbackInfo<v8::Integer>& info) {
229   v8::Local<v8::Object> thisObject = info.This();
230   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
231       info.Data().As<v8::External>()->Value());
232   v8::Isolate* pIsolate = info.GetIsolate();
233   v8::HandleScope scope(pIsolate);
234   v8::String::Utf8Value szPropName(property);
235   CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
236   std::unique_ptr<CFXJSE_Value> lpThisValue(
237       new CFXJSE_Value(info.GetIsolate()));
238   lpThisValue->ForceSetValue(thisObject);
239   if (DynPropQueryAdapter(lpClass, lpThisValue.get(), szFxPropName)) {
240     info.GetReturnValue().Set(v8::DontDelete);
241     return;
242   }
243   const int32_t iV8Absent = 64;
244   info.GetReturnValue().Set(iV8Absent);
245 }
246 
NamedPropertyDeleterCallback(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Boolean> & info)247 void NamedPropertyDeleterCallback(
248     v8::Local<v8::Name> property,
249     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
250   v8::Local<v8::Object> thisObject = info.This();
251   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
252       info.Data().As<v8::External>()->Value());
253   v8::Isolate* pIsolate = info.GetIsolate();
254   v8::HandleScope scope(pIsolate);
255   v8::String::Utf8Value szPropName(property);
256   CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
257   std::unique_ptr<CFXJSE_Value> lpThisValue(
258       new CFXJSE_Value(info.GetIsolate()));
259   lpThisValue->ForceSetValue(thisObject);
260   info.GetReturnValue().Set(
261       !!DynPropDeleterAdapter(lpClass, lpThisValue.get(), szFxPropName));
262 }
263 
NamedPropertyGetterCallback(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)264 void NamedPropertyGetterCallback(
265     v8::Local<v8::Name> property,
266     const v8::PropertyCallbackInfo<v8::Value>& info) {
267   v8::Local<v8::Object> thisObject = info.This();
268   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
269       info.Data().As<v8::External>()->Value());
270   v8::String::Utf8Value szPropName(property);
271   CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
272   std::unique_ptr<CFXJSE_Value> lpThisValue(
273       new CFXJSE_Value(info.GetIsolate()));
274   lpThisValue->ForceSetValue(thisObject);
275   std::unique_ptr<CFXJSE_Value> lpNewValue(new CFXJSE_Value(info.GetIsolate()));
276   DynPropGetterAdapter(lpClass, lpThisValue.get(), szFxPropName,
277                        lpNewValue.get());
278   info.GetReturnValue().Set(lpNewValue->DirectGetValue());
279 }
280 
NamedPropertySetterCallback(v8::Local<v8::Name> property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)281 void NamedPropertySetterCallback(
282     v8::Local<v8::Name> property,
283     v8::Local<v8::Value> value,
284     const v8::PropertyCallbackInfo<v8::Value>& info) {
285   v8::Local<v8::Object> thisObject = info.This();
286   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
287       info.Data().As<v8::External>()->Value());
288   v8::String::Utf8Value szPropName(property);
289   CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
290   std::unique_ptr<CFXJSE_Value> lpThisValue(
291       new CFXJSE_Value(info.GetIsolate()));
292   lpThisValue->ForceSetValue(thisObject);
293 
294   std::unique_ptr<CFXJSE_Value> lpNewValue(new CFXJSE_Value(info.GetIsolate()));
295   lpNewValue->ForceSetValue(value);
296   DynPropSetterAdapter(lpClass, lpThisValue.get(), szFxPropName,
297                        lpNewValue.get());
298   info.GetReturnValue().Set(value);
299 }
300 
NamedPropertyEnumeratorCallback(const v8::PropertyCallbackInfo<v8::Array> & info)301 void NamedPropertyEnumeratorCallback(
302     const v8::PropertyCallbackInfo<v8::Array>& info) {
303   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
304       info.Data().As<v8::External>()->Value());
305   v8::Isolate* pIsolate = info.GetIsolate();
306   v8::Local<v8::Array> newArray = v8::Array::New(pIsolate, lpClass->propNum);
307   for (int i = 0; i < lpClass->propNum; i++) {
308     newArray->Set(
309         i, v8::String::NewFromUtf8(pIsolate, lpClass->properties[i].name));
310   }
311   info.GetReturnValue().Set(newArray);
312 }
313 
314 }  // namespace
315 
316 // static
Create(CFXJSE_Context * lpContext,const FXJSE_CLASS_DESCRIPTOR * lpClassDefinition,bool bIsJSGlobal)317 CFXJSE_Class* CFXJSE_Class::Create(
318     CFXJSE_Context* lpContext,
319     const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition,
320     bool bIsJSGlobal) {
321   if (!lpContext || !lpClassDefinition)
322     return nullptr;
323 
324   CFXJSE_Class* pClass =
325       GetClassFromContext(lpContext, lpClassDefinition->name);
326   if (pClass)
327     return pClass;
328 
329   v8::Isolate* pIsolate = lpContext->m_pIsolate;
330   pClass = new CFXJSE_Class(lpContext);
331   pClass->m_szClassName = lpClassDefinition->name;
332   pClass->m_lpClassDefinition = lpClassDefinition;
333   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
334   v8::Local<v8::FunctionTemplate> hFunctionTemplate = v8::FunctionTemplate::New(
335       pIsolate, bIsJSGlobal ? 0 : V8ConstructorCallback_Wrapper,
336       v8::External::New(
337           pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)));
338   hFunctionTemplate->SetClassName(
339       v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name));
340   hFunctionTemplate->InstanceTemplate()->SetInternalFieldCount(1);
341   v8::Local<v8::ObjectTemplate> hObjectTemplate =
342       hFunctionTemplate->InstanceTemplate();
343   SetUpNamedPropHandler(pIsolate, hObjectTemplate, lpClassDefinition);
344 
345   if (lpClassDefinition->propNum) {
346     for (int32_t i = 0; i < lpClassDefinition->propNum; i++) {
347       hObjectTemplate->SetNativeDataProperty(
348           v8::String::NewFromUtf8(pIsolate,
349                                   lpClassDefinition->properties[i].name),
350           lpClassDefinition->properties[i].getProc ? V8GetterCallback_Wrapper
351                                                    : nullptr,
352           lpClassDefinition->properties[i].setProc ? V8SetterCallback_Wrapper
353                                                    : nullptr,
354           v8::External::New(pIsolate, const_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
355                                           lpClassDefinition->properties + i)),
356           static_cast<v8::PropertyAttribute>(v8::DontDelete));
357     }
358   }
359   if (lpClassDefinition->methNum) {
360     for (int32_t i = 0; i < lpClassDefinition->methNum; i++) {
361       v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
362           pIsolate, V8FunctionCallback_Wrapper,
363           v8::External::New(pIsolate, const_cast<FXJSE_FUNCTION_DESCRIPTOR*>(
364                                           lpClassDefinition->methods + i)));
365       fun->RemovePrototype();
366       hObjectTemplate->Set(
367           v8::String::NewFromUtf8(pIsolate, lpClassDefinition->methods[i].name),
368           fun,
369           static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
370     }
371   }
372   if (lpClassDefinition->constructor) {
373     if (bIsJSGlobal) {
374       hObjectTemplate->Set(
375           v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name),
376           v8::FunctionTemplate::New(
377               pIsolate, V8ClassGlobalConstructorCallback_Wrapper,
378               v8::External::New(pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(
379                                               lpClassDefinition))),
380           static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
381     } else {
382       v8::Local<v8::Context> hLocalContext =
383           v8::Local<v8::Context>::New(pIsolate, lpContext->m_hContext);
384       FXJSE_GetGlobalObjectFromContext(hLocalContext)
385           ->Set(v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name),
386                 v8::Function::New(
387                     pIsolate, V8ClassGlobalConstructorCallback_Wrapper,
388                     v8::External::New(pIsolate,
389                                       const_cast<FXJSE_CLASS_DESCRIPTOR*>(
390                                           lpClassDefinition))));
391     }
392   }
393   if (bIsJSGlobal) {
394     v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
395         pIsolate, Context_GlobalObjToString,
396         v8::External::New(
397             pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)));
398     fun->RemovePrototype();
399     hObjectTemplate->Set(v8::String::NewFromUtf8(pIsolate, "toString"), fun);
400   }
401   pClass->m_hTemplate.Reset(lpContext->m_pIsolate, hFunctionTemplate);
402   lpContext->m_rgClasses.push_back(std::unique_ptr<CFXJSE_Class>(pClass));
403   return pClass;
404 }
405 
406 // static
GetClassFromContext(CFXJSE_Context * pContext,const CFX_ByteStringC & szName)407 CFXJSE_Class* CFXJSE_Class::GetClassFromContext(CFXJSE_Context* pContext,
408                                                 const CFX_ByteStringC& szName) {
409   for (const auto& pClass : pContext->m_rgClasses) {
410     if (pClass->m_szClassName == szName)
411       return pClass.get();
412   }
413   return nullptr;
414 }
415 
416 // static
SetUpNamedPropHandler(v8::Isolate * pIsolate,v8::Local<v8::ObjectTemplate> & hObjectTemplate,const FXJSE_CLASS_DESCRIPTOR * lpClassDefinition)417 void CFXJSE_Class::SetUpNamedPropHandler(
418     v8::Isolate* pIsolate,
419     v8::Local<v8::ObjectTemplate>& hObjectTemplate,
420     const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition) {
421   v8::NamedPropertyHandlerConfiguration configuration(
422       lpClassDefinition->dynPropGetter ? NamedPropertyGetterCallback : 0,
423       lpClassDefinition->dynPropSetter ? NamedPropertySetterCallback : 0,
424       lpClassDefinition->dynPropTypeGetter ? NamedPropertyQueryCallback : 0,
425       lpClassDefinition->dynPropDeleter ? NamedPropertyDeleterCallback : 0,
426       NamedPropertyEnumeratorCallback,
427       v8::External::New(pIsolate,
428                         const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)),
429       v8::PropertyHandlerFlags::kNonMasking);
430   hObjectTemplate->SetHandler(configuration);
431 }
432 
CFXJSE_Class(CFXJSE_Context * lpContext)433 CFXJSE_Class::CFXJSE_Class(CFXJSE_Context* lpContext)
434     : m_lpClassDefinition(nullptr), m_pContext(lpContext) {}
435 
~CFXJSE_Class()436 CFXJSE_Class::~CFXJSE_Class() {}
437