• Home
  • 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 #include <utility>
11 
12 #include "fxjs/cfxjse_arguments.h"
13 #include "fxjs/cfxjse_context.h"
14 #include "fxjs/cfxjse_value.h"
15 #include "fxjs/cjs_return.h"
16 #include "fxjs/js_resources.h"
17 #include "third_party/base/ptr_util.h"
18 
19 namespace {
20 
V8FunctionCallback_Wrapper(const v8::FunctionCallbackInfo<v8::Value> & info)21 void V8FunctionCallback_Wrapper(
22     const v8::FunctionCallbackInfo<v8::Value>& info) {
23   const FXJSE_FUNCTION_DESCRIPTOR* lpFunctionInfo =
24       static_cast<FXJSE_FUNCTION_DESCRIPTOR*>(
25           info.Data().As<v8::External>()->Value());
26   if (!lpFunctionInfo)
27     return;
28 
29   ByteStringView szFunctionName(lpFunctionInfo->name);
30   auto lpThisValue = pdfium::MakeUnique<CFXJSE_Value>(info.GetIsolate());
31   lpThisValue->ForceSetValue(info.Holder());
32   auto lpRetValue = pdfium::MakeUnique<CFXJSE_Value>(info.GetIsolate());
33   CFXJSE_Arguments impl(&info, lpRetValue.get());
34   lpFunctionInfo->callbackProc(lpThisValue.get(), szFunctionName, impl);
35   if (!lpRetValue->DirectGetValue().IsEmpty())
36     info.GetReturnValue().Set(lpRetValue->DirectGetValue());
37 }
38 
V8ConstructorCallback_Wrapper(const v8::FunctionCallbackInfo<v8::Value> & info)39 void V8ConstructorCallback_Wrapper(
40     const v8::FunctionCallbackInfo<v8::Value>& info) {
41   if (!info.IsConstructCall())
42     return;
43 
44   const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition =
45       static_cast<FXJSE_CLASS_DESCRIPTOR*>(
46           info.Data().As<v8::External>()->Value());
47   if (!lpClassDefinition)
48     return;
49 
50   ASSERT(info.Holder()->InternalFieldCount());
51   info.Holder()->SetAlignedPointerInInternalField(0, nullptr);
52 }
53 
Context_GlobalObjToString(const v8::FunctionCallbackInfo<v8::Value> & info)54 void Context_GlobalObjToString(
55     const v8::FunctionCallbackInfo<v8::Value>& info) {
56   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
57       info.Data().As<v8::External>()->Value());
58   if (!lpClass)
59     return;
60 
61   if (info.This() == info.Holder() && lpClass->name) {
62     ByteString szStringVal = ByteString::Format("[object %s]", lpClass->name);
63     info.GetReturnValue().Set(v8::String::NewFromUtf8(
64         info.GetIsolate(), szStringVal.c_str(), v8::String::kNormalString,
65         szStringVal.GetLength()));
66     return;
67   }
68   v8::Local<v8::String> local_str =
69       info.Holder()
70           ->ObjectProtoToString(info.GetIsolate()->GetCurrentContext())
71           .FromMaybe(v8::Local<v8::String>());
72   info.GetReturnValue().Set(local_str);
73 }
74 
DynPropGetterAdapter_MethodCallback(const v8::FunctionCallbackInfo<v8::Value> & info)75 void DynPropGetterAdapter_MethodCallback(
76     const v8::FunctionCallbackInfo<v8::Value>& info) {
77   v8::Local<v8::Object> hCallBackInfo = info.Data().As<v8::Object>();
78   FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
79       hCallBackInfo->GetAlignedPointerFromInternalField(0));
80   v8::Local<v8::String> hPropName =
81       hCallBackInfo->GetInternalField(1).As<v8::String>();
82   ASSERT(lpClass && !hPropName.IsEmpty());
83 
84   v8::String::Utf8Value szPropName(info.GetIsolate(), hPropName);
85   WideString szFxPropName = WideString::FromUTF8(*szPropName);
86 
87   CJS_Return result = lpClass->dynMethodCall(info, szFxPropName);
88   if (result.HasError()) {
89     WideString err = JSFormatErrorString(*szPropName, "", result.Error());
90     v8::MaybeLocal<v8::String> str = v8::String::NewFromUtf8(
91         info.GetIsolate(), ByteString::FromUnicode(err).c_str(),
92         v8::NewStringType::kNormal);
93     info.GetIsolate()->ThrowException(str.ToLocalChecked());
94     return;
95   }
96   if (result.HasReturn())
97     info.GetReturnValue().Set(result.Return());
98 }
99 
DynPropGetterAdapter(const FXJSE_CLASS_DESCRIPTOR * lpClass,CFXJSE_Value * pObject,const ByteStringView & szPropName,CFXJSE_Value * pValue)100 void DynPropGetterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
101                           CFXJSE_Value* pObject,
102                           const ByteStringView& szPropName,
103                           CFXJSE_Value* pValue) {
104   ASSERT(lpClass);
105 
106   int32_t nPropType =
107       lpClass->dynPropTypeGetter == nullptr
108           ? FXJSE_ClassPropType_Property
109           : lpClass->dynPropTypeGetter(pObject, szPropName, false);
110   if (nPropType == FXJSE_ClassPropType_Property) {
111     if (lpClass->dynPropGetter)
112       lpClass->dynPropGetter(pObject, szPropName, pValue);
113   } else if (nPropType == FXJSE_ClassPropType_Method) {
114     if (lpClass->dynMethodCall && pValue) {
115       v8::Isolate* pIsolate = pValue->GetIsolate();
116       v8::HandleScope hscope(pIsolate);
117       v8::Local<v8::ObjectTemplate> hCallBackInfoTemplate =
118           v8::ObjectTemplate::New(pIsolate);
119       hCallBackInfoTemplate->SetInternalFieldCount(2);
120       v8::Local<v8::Object> hCallBackInfo =
121           hCallBackInfoTemplate->NewInstance();
122       hCallBackInfo->SetAlignedPointerInInternalField(
123           0, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClass));
124       hCallBackInfo->SetInternalField(
125           1, v8::String::NewFromUtf8(
126                  pIsolate, reinterpret_cast<const char*>(szPropName.raw_str()),
127                  v8::String::kNormalString, szPropName.GetLength()));
128       pValue->ForceSetValue(
129           v8::Function::New(pValue->GetIsolate()->GetCurrentContext(),
130                             DynPropGetterAdapter_MethodCallback, hCallBackInfo,
131                             0, v8::ConstructorBehavior::kThrow)
132               .ToLocalChecked());
133     }
134   }
135 }
136 
DynPropSetterAdapter(const FXJSE_CLASS_DESCRIPTOR * lpClass,CFXJSE_Value * pObject,const ByteStringView & szPropName,CFXJSE_Value * pValue)137 void DynPropSetterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
138                           CFXJSE_Value* pObject,
139                           const ByteStringView& szPropName,
140                           CFXJSE_Value* pValue) {
141   ASSERT(lpClass);
142   int32_t nPropType =
143       lpClass->dynPropTypeGetter == nullptr
144           ? FXJSE_ClassPropType_Property
145           : lpClass->dynPropTypeGetter(pObject, szPropName, false);
146   if (nPropType != FXJSE_ClassPropType_Method) {
147     if (lpClass->dynPropSetter)
148       lpClass->dynPropSetter(pObject, szPropName, pValue);
149   }
150 }
151 
DynPropQueryAdapter(const FXJSE_CLASS_DESCRIPTOR * lpClass,CFXJSE_Value * pObject,const ByteStringView & szPropName)152 bool DynPropQueryAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
153                          CFXJSE_Value* pObject,
154                          const ByteStringView& szPropName) {
155   ASSERT(lpClass);
156   int32_t nPropType =
157       lpClass->dynPropTypeGetter == nullptr
158           ? FXJSE_ClassPropType_Property
159           : lpClass->dynPropTypeGetter(pObject, szPropName, true);
160   return nPropType != FXJSE_ClassPropType_None;
161 }
162 
NamedPropertyQueryCallback(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Integer> & info)163 void NamedPropertyQueryCallback(
164     v8::Local<v8::Name> property,
165     const v8::PropertyCallbackInfo<v8::Integer>& info) {
166   v8::Local<v8::Object> thisObject = info.Holder();
167   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
168       info.Data().As<v8::External>()->Value());
169   v8::Isolate* pIsolate = info.GetIsolate();
170   v8::HandleScope scope(pIsolate);
171   v8::String::Utf8Value szPropName(pIsolate, property);
172   ByteStringView szFxPropName(*szPropName, szPropName.length());
173   auto lpThisValue = pdfium::MakeUnique<CFXJSE_Value>(info.GetIsolate());
174   lpThisValue->ForceSetValue(thisObject);
175   if (DynPropQueryAdapter(lpClass, lpThisValue.get(), szFxPropName)) {
176     info.GetReturnValue().Set(v8::DontDelete);
177     return;
178   }
179   const int32_t iV8Absent = 64;
180   info.GetReturnValue().Set(iV8Absent);
181 }
182 
NamedPropertyGetterCallback(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)183 void NamedPropertyGetterCallback(
184     v8::Local<v8::Name> property,
185     const v8::PropertyCallbackInfo<v8::Value>& info) {
186   v8::Local<v8::Object> thisObject = info.Holder();
187   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
188       info.Data().As<v8::External>()->Value());
189   v8::String::Utf8Value szPropName(info.GetIsolate(), property);
190   ByteStringView szFxPropName(*szPropName, szPropName.length());
191   auto lpThisValue = pdfium::MakeUnique<CFXJSE_Value>(info.GetIsolate());
192   lpThisValue->ForceSetValue(thisObject);
193   auto lpNewValue = pdfium::MakeUnique<CFXJSE_Value>(info.GetIsolate());
194   DynPropGetterAdapter(lpClass, lpThisValue.get(), szFxPropName,
195                        lpNewValue.get());
196   info.GetReturnValue().Set(lpNewValue->DirectGetValue());
197 }
198 
NamedPropertySetterCallback(v8::Local<v8::Name> property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)199 void NamedPropertySetterCallback(
200     v8::Local<v8::Name> property,
201     v8::Local<v8::Value> value,
202     const v8::PropertyCallbackInfo<v8::Value>& info) {
203   v8::Local<v8::Object> thisObject = info.Holder();
204   const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
205       info.Data().As<v8::External>()->Value());
206   v8::String::Utf8Value szPropName(info.GetIsolate(), property);
207   ByteStringView szFxPropName(*szPropName, szPropName.length());
208   auto lpThisValue = pdfium::MakeUnique<CFXJSE_Value>(info.GetIsolate());
209   lpThisValue->ForceSetValue(thisObject);
210 
211   auto lpNewValue = pdfium::MakeUnique<CFXJSE_Value>(info.GetIsolate());
212   lpNewValue->ForceSetValue(value);
213   DynPropSetterAdapter(lpClass, lpThisValue.get(), szFxPropName,
214                        lpNewValue.get());
215   info.GetReturnValue().Set(value);
216 }
217 
NamedPropertyEnumeratorCallback(const v8::PropertyCallbackInfo<v8::Array> & info)218 void NamedPropertyEnumeratorCallback(
219     const v8::PropertyCallbackInfo<v8::Array>& info) {
220   info.GetReturnValue().Set(v8::Array::New(info.GetIsolate()));
221 }
222 
223 }  // namespace
224 
225 // static
Create(CFXJSE_Context * lpContext,const FXJSE_CLASS_DESCRIPTOR * lpClassDefinition,bool bIsJSGlobal)226 CFXJSE_Class* CFXJSE_Class::Create(
227     CFXJSE_Context* lpContext,
228     const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition,
229     bool bIsJSGlobal) {
230   if (!lpContext || !lpClassDefinition)
231     return nullptr;
232 
233   CFXJSE_Class* pExistingClass =
234       lpContext->GetClassByName(lpClassDefinition->name);
235   if (pExistingClass)
236     return pExistingClass;
237 
238   v8::Isolate* pIsolate = lpContext->GetIsolate();
239   auto pClass = pdfium::MakeUnique<CFXJSE_Class>(lpContext);
240   pClass->m_szClassName = lpClassDefinition->name;
241   pClass->m_lpClassDefinition = lpClassDefinition;
242   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
243   v8::Local<v8::FunctionTemplate> hFunctionTemplate = v8::FunctionTemplate::New(
244       pIsolate, bIsJSGlobal ? 0 : V8ConstructorCallback_Wrapper,
245       v8::External::New(
246           pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)));
247   hFunctionTemplate->SetClassName(
248       v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name));
249   hFunctionTemplate->InstanceTemplate()->SetInternalFieldCount(2);
250   v8::Local<v8::ObjectTemplate> hObjectTemplate =
251       hFunctionTemplate->InstanceTemplate();
252   SetUpNamedPropHandler(pIsolate, hObjectTemplate, lpClassDefinition);
253 
254   if (lpClassDefinition->methNum) {
255     for (int32_t i = 0; i < lpClassDefinition->methNum; i++) {
256       v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
257           pIsolate, V8FunctionCallback_Wrapper,
258           v8::External::New(pIsolate, const_cast<FXJSE_FUNCTION_DESCRIPTOR*>(
259                                           lpClassDefinition->methods + i)));
260       fun->RemovePrototype();
261       hObjectTemplate->Set(
262           v8::String::NewFromUtf8(pIsolate, lpClassDefinition->methods[i].name),
263           fun,
264           static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
265     }
266   }
267 
268   if (bIsJSGlobal) {
269     v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
270         pIsolate, Context_GlobalObjToString,
271         v8::External::New(
272             pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)));
273     fun->RemovePrototype();
274     hObjectTemplate->Set(v8::String::NewFromUtf8(pIsolate, "toString"), fun);
275   }
276   pClass->m_hTemplate.Reset(lpContext->GetIsolate(), hFunctionTemplate);
277   CFXJSE_Class* pResult = pClass.get();
278   lpContext->AddClass(std::move(pClass));
279   return pResult;
280 }
281 
282 // static
SetUpNamedPropHandler(v8::Isolate * pIsolate,v8::Local<v8::ObjectTemplate> & hObjectTemplate,const FXJSE_CLASS_DESCRIPTOR * lpClassDefinition)283 void CFXJSE_Class::SetUpNamedPropHandler(
284     v8::Isolate* pIsolate,
285     v8::Local<v8::ObjectTemplate>& hObjectTemplate,
286     const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition) {
287   v8::NamedPropertyHandlerConfiguration configuration(
288       lpClassDefinition->dynPropGetter ? NamedPropertyGetterCallback : 0,
289       lpClassDefinition->dynPropSetter ? NamedPropertySetterCallback : 0,
290       lpClassDefinition->dynPropTypeGetter ? NamedPropertyQueryCallback : 0, 0,
291       NamedPropertyEnumeratorCallback,
292       v8::External::New(pIsolate,
293                         const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)),
294       v8::PropertyHandlerFlags::kNonMasking);
295   hObjectTemplate->SetHandler(configuration);
296 }
297 
CFXJSE_Class(CFXJSE_Context * lpContext)298 CFXJSE_Class::CFXJSE_Class(CFXJSE_Context* lpContext)
299     : m_lpClassDefinition(nullptr), m_pContext(lpContext) {}
300 
~CFXJSE_Class()301 CFXJSE_Class::~CFXJSE_Class() {}
302