• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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