Home | History | Annotate | Download | only in fxjs
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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
    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
    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 
    433 CFXJSE_Class::CFXJSE_Class(CFXJSE_Context* lpContext)
    434     : m_lpClassDefinition(nullptr), m_pContext(lpContext) {}
    435 
    436 CFXJSE_Class::~CFXJSE_Class() {}
    437