Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxjse / src / dynprop.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../foxitlib.h"\r
8 #include "fxv8.h"\r
9 #include "class.h"\r
10 #include "value.h"\r
11 static void FXJSE_DynPropGetterAdapter_MethodCallback   (const v8::FunctionCallbackInfo<v8::Value>& info)\r
12 {\r
13     v8::Local<v8::Object> hCallBackInfo = info.Data().As<v8::Object>();\r
14     FXJSE_CLASS*          lpClass               = static_cast<FXJSE_CLASS*>(hCallBackInfo->GetAlignedPointerFromInternalField(0));\r
15     v8::Local<v8::String> hPropName             = hCallBackInfo->GetInternalField(1).As<v8::String>();\r
16     ASSERT(lpClass && !hPropName.IsEmpty());\r
17     v8::String::Utf8Value szPropName(hPropName);\r
18     CFX_ByteStringC           szFxPropName      = *szPropName;\r
19     CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate());\r
20     lpThisValue->ForceSetValue(info.This());\r
21     CFXJSE_Value* lpRetValue = CFXJSE_Value::Create(info.GetIsolate());\r
22     CFXJSE_ArgumentsImpl impl = {&info, lpRetValue};\r
23     lpClass->dynMethodCall(reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), szFxPropName, reinterpret_cast<CFXJSE_Arguments&>(impl));\r
24     if(!lpRetValue->DirectGetValue().IsEmpty()) {\r
25         info.GetReturnValue().Set(lpRetValue->DirectGetValue());\r
26     }\r
27     delete lpRetValue;\r
28     lpRetValue = NULL;\r
29     delete lpThisValue;\r
30     lpThisValue = NULL;\r
31 }\r
32 static void FXJSE_DynPropGetterAdapter                                  (const FXJSE_CLASS* lpClass, FXJSE_HOBJECT hObject, FX_BSTR szPropName, FXJSE_HVALUE hValue)\r
33 {\r
34     ASSERT(lpClass);\r
35     FX_INT32 nPropType = lpClass->dynPropTypeGetter == NULL ? FXJSE_ClassPropType_Property : lpClass->dynPropTypeGetter(hObject, szPropName, FALSE);\r
36     if(nPropType == FXJSE_ClassPropType_Property) {\r
37         if(lpClass->dynPropGetter) {\r
38             lpClass->dynPropGetter(hObject, szPropName, hValue);\r
39         }\r
40     } else if(nPropType == FXJSE_ClassPropType_Method) {\r
41         if(lpClass->dynMethodCall && hValue) {\r
42             CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);\r
43             v8::Isolate*        pIsolate = lpValue->GetIsolate();\r
44             v8::HandleScope hscope(pIsolate);\r
45             v8::Local<v8::ObjectTemplate> hCallBackInfoTemplate = v8::ObjectTemplate::New();\r
46             hCallBackInfoTemplate->SetInternalFieldCount(2);\r
47             v8::Local<v8::Object> hCallBackInfo = hCallBackInfoTemplate->NewInstance();\r
48             hCallBackInfo->SetAlignedPointerInInternalField(0, const_cast<FXJSE_CLASS*>(lpClass));\r
49             hCallBackInfo->SetInternalField(1, v8::String::NewFromUtf8(pIsolate, reinterpret_cast<const char*>(szPropName.GetPtr()), v8::String::kNormalString, szPropName.GetLength()));\r
50             lpValue->ForceSetValue(v8::Function::New(lpValue->GetIsolate(), FXJSE_DynPropGetterAdapter_MethodCallback, hCallBackInfo));\r
51         }\r
52     }\r
53 }\r
54 static void FXJSE_DynPropSetterAdapter                                  (const FXJSE_CLASS* lpClass, FXJSE_HOBJECT hObject, FX_BSTR szPropName, FXJSE_HVALUE hValue)\r
55 {\r
56     ASSERT(lpClass);\r
57     FX_INT32 nPropType = lpClass->dynPropTypeGetter == NULL ? FXJSE_ClassPropType_Property : lpClass->dynPropTypeGetter(hObject, szPropName, FALSE);\r
58     if(nPropType != FXJSE_ClassPropType_Method) {\r
59         if(lpClass->dynPropSetter) {\r
60             lpClass->dynPropSetter(hObject, szPropName, hValue);\r
61         }\r
62     }\r
63 }\r
64 static FX_BOOL FXJSE_DynPropQueryAdapter                                (const FXJSE_CLASS* lpClass, FXJSE_HOBJECT hObject, FX_BSTR szPropName)\r
65 {\r
66     ASSERT(lpClass);\r
67     FX_INT32 nPropType = lpClass->dynPropTypeGetter == NULL ? FXJSE_ClassPropType_Property : lpClass->dynPropTypeGetter(hObject, szPropName, TRUE);\r
68     return nPropType != FXJSE_ClassPropType_None;\r
69 }\r
70 static FX_BOOL FXJSE_DynPropDeleterAdapter                                      (const FXJSE_CLASS* lpClass, FXJSE_HOBJECT hObject, FX_BSTR szPropName)\r
71 {\r
72     ASSERT(lpClass);\r
73     FX_INT32 nPropType = lpClass->dynPropTypeGetter == NULL ? FXJSE_ClassPropType_Property : lpClass->dynPropTypeGetter(hObject, szPropName, FALSE);\r
74     if(nPropType != FXJSE_ClassPropType_Method) {\r
75         if(lpClass->dynPropDeleter) {\r
76             return lpClass->dynPropDeleter(hObject, szPropName);\r
77         } else {\r
78             return nPropType == FXJSE_ClassPropType_Property ? FALSE : TRUE;\r
79         }\r
80     }\r
81     return FALSE;\r
82 }\r
83 static void FXJSE_V8ProxyCallback_getOwnPropertyDescriptor_getter(const v8::FunctionCallbackInfo<v8::Value>& info)\r
84 {\r
85     v8::Local<v8::Object> hCallBackInfo = info.Data().As<v8::Object>();\r
86     FXJSE_CLASS*          lpClass               = static_cast<FXJSE_CLASS*>(hCallBackInfo->GetAlignedPointerFromInternalField(0));\r
87     v8::Local<v8::String> hPropName             = hCallBackInfo->GetInternalField(1).As<v8::String>();\r
88     ASSERT(lpClass && !hPropName.IsEmpty());\r
89     v8::String::Utf8Value szPropName(hPropName);\r
90     CFX_ByteStringC           szFxPropName      = *szPropName;\r
91     CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate());\r
92     CFXJSE_Value* lpNewValue = CFXJSE_Value::Create(info.GetIsolate());\r
93     lpThisValue->ForceSetValue(info.This());\r
94     FXJSE_DynPropGetterAdapter(lpClass, reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), szFxPropName, reinterpret_cast<FXJSE_HVALUE>(lpNewValue));\r
95     info.GetReturnValue().Set(lpNewValue->DirectGetValue());\r
96     delete lpThisValue;\r
97     lpThisValue = NULL;\r
98     delete lpNewValue;\r
99     lpNewValue = NULL;\r
100 }\r
101 static void FXJSE_V8ProxyCallback_getOwnPropertyDescriptor_setter(const v8::FunctionCallbackInfo<v8::Value>& info)\r
102 {\r
103     v8::Local<v8::Object> hCallBackInfo = info.Data().As<v8::Object>();\r
104     FXJSE_CLASS*          lpClass               = static_cast<FXJSE_CLASS*>(hCallBackInfo->GetAlignedPointerFromInternalField(0));\r
105     v8::Local<v8::String> hPropName             = hCallBackInfo->GetInternalField(1).As<v8::String>();\r
106     ASSERT(lpClass && !hPropName.IsEmpty());\r
107     v8::String::Utf8Value szPropName(hPropName);\r
108     CFX_ByteStringC           szFxPropName      = *szPropName;\r
109     CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate());\r
110     CFXJSE_Value* lpNewValue = CFXJSE_Value::Create(info.GetIsolate());\r
111     lpThisValue->ForceSetValue(info.This());\r
112     lpNewValue->ForceSetValue(info[0]);\r
113     FXJSE_DynPropSetterAdapter(lpClass, reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), szFxPropName, reinterpret_cast<FXJSE_HVALUE>(lpNewValue));\r
114     delete lpThisValue;\r
115     lpThisValue = NULL;\r
116     delete lpNewValue;\r
117     lpNewValue = NULL;\r
118 }\r
119 static void FXJSE_V8ProxyCallback_getOwnPropertyDescriptor      (const v8::FunctionCallbackInfo<v8::Value>& info)\r
120 {\r
121     const FXJSE_CLASS* lpClass = static_cast<FXJSE_CLASS*>(info.Data().As<v8::External>()->Value());\r
122     if (!lpClass) {\r
123         return;\r
124     }\r
125     v8::Isolate*        pIsolate = info.GetIsolate();\r
126     v8::HandleScope scope(pIsolate);\r
127     v8::Local<v8::String> hPropName = info[0]->ToString();\r
128     v8::String::Utf8Value szPropName(hPropName);\r
129     CFX_ByteStringC               szFxPropName(*szPropName, szPropName.length());\r
130     v8::Local<v8::ObjectTemplate> hCallBackInfoTemplate = v8::ObjectTemplate::New();\r
131     hCallBackInfoTemplate->SetInternalFieldCount(2);\r
132     v8::Local<v8::Object> hCallBackInfo = hCallBackInfoTemplate->NewInstance();\r
133     hCallBackInfo->SetAlignedPointerInInternalField(0, const_cast<FXJSE_CLASS*>(lpClass));\r
134     hCallBackInfo->SetInternalField(1, hPropName);\r
135     v8::Local<v8::Object> hPropDescriptor = v8::Object::New(pIsolate);\r
136     hPropDescriptor->ForceSet(v8::String::NewFromUtf8(pIsolate, "get"), v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_getOwnPropertyDescriptor_getter, hCallBackInfo));\r
137     hPropDescriptor->ForceSet(v8::String::NewFromUtf8(pIsolate, "set"), v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_getOwnPropertyDescriptor_setter, hCallBackInfo));\r
138     hPropDescriptor->ForceSet(v8::String::NewFromUtf8(pIsolate, "enumerable"), v8::Boolean::New(pIsolate, false));\r
139     hPropDescriptor->ForceSet(v8::String::NewFromUtf8(pIsolate, "configurable"), v8::Boolean::New(pIsolate, true));\r
140     info.GetReturnValue().Set(hPropDescriptor);\r
141 }\r
142 static void FXJSE_V8ProxyCallback_getPropertyDescriptor         (const v8::FunctionCallbackInfo<v8::Value>& info)\r
143 {\r
144     v8::Isolate* pIsolate = info.GetIsolate();\r
145     v8::Local<v8::Object> hChainObj = info.This()->GetPrototype().As<v8::Object>();\r
146     v8::Local<v8::Script> fnSource = v8::Script::Compile(v8::String::NewFromUtf8(pIsolate,\r
147                                      "(function (o, name) { var fn, x, d; fn = Object.getOwnPropertyDescriptor; x = o; while(x && !(d = fn(x, name))){x = x.__proto__;} return d; })"));\r
148     v8::Local<v8::Function> fn = fnSource->Run().As<v8::Function>();\r
149     v8::Handle<v8::Value> rgArgs[] = {hChainObj, info[0]};\r
150     v8::Local<v8::Value> hChainDescriptor = fn->Call(info.This(), 2, rgArgs);\r
151     if(!hChainDescriptor.IsEmpty() && hChainDescriptor->IsObject()) {\r
152         info.GetReturnValue().Set(hChainDescriptor);\r
153     } else {\r
154         FXJSE_V8ProxyCallback_getOwnPropertyDescriptor(info);\r
155     }\r
156 }\r
157 static void FXJSE_V8ProxyCallback_getOwnPropertyNames           (const v8::FunctionCallbackInfo<v8::Value>& info)\r
158 {\r
159     v8::Isolate*        pIsolate = info.GetIsolate();\r
160     v8::HandleScope scope(pIsolate);\r
161     info.GetReturnValue().Set(v8::Array::New(pIsolate));\r
162 }\r
163 static void FXJSE_V8ProxyCallback_getPropertyNames                      (const v8::FunctionCallbackInfo<v8::Value>& info)\r
164 {\r
165     v8::Local<v8::Object> hChainObj = info.This()->GetPrototype().As<v8::Object>();\r
166     v8::Local<v8::Value> hChainPropertyNames = hChainObj->GetPropertyNames();\r
167     info.GetReturnValue().Set(hChainPropertyNames);\r
168 }\r
169 static void FXJSE_V8ProxyCallback_defineProperty                        (const v8::FunctionCallbackInfo<v8::Value>& info)\r
170 {\r
171     const FXJSE_CLASS* lpClass = static_cast<FXJSE_CLASS*>(info.Data().As<v8::External>()->Value());\r
172     if (!lpClass) {\r
173         return;\r
174     }\r
175     v8::Isolate*        pIsolate = info.GetIsolate();\r
176     v8::HandleScope scope(pIsolate);\r
177     v8::Local<v8::String> hPropName = info[0]->ToString();\r
178     v8::Local<v8::Object> hPropDescriptor = info[1]->ToObject();\r
179     v8::String::Utf8Value szPropName(hPropName);\r
180     if(!hPropDescriptor->Has(v8::String::NewFromUtf8(pIsolate, "value"))) {\r
181         return;\r
182     }\r
183     v8::Local<v8::Value> hPropValue = hPropDescriptor->Get(v8::String::NewFromUtf8(pIsolate, "value"));\r
184     CFX_ByteStringC               szFxPropName(*szPropName, szPropName.length());\r
185     CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate());\r
186     CFXJSE_Value* lpPropValue = CFXJSE_Value::Create(info.GetIsolate());\r
187     lpThisValue->ForceSetValue(info.This());\r
188     lpPropValue->ForceSetValue(hPropValue);\r
189     FXJSE_DynPropSetterAdapter(lpClass, reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), szFxPropName, reinterpret_cast<FXJSE_HVALUE>(lpPropValue));\r
190     delete lpThisValue;\r
191     lpThisValue = NULL;\r
192     delete lpPropValue;\r
193     lpPropValue = NULL;\r
194 }\r
195 static void FXJSE_V8ProxyCallback_delete                                        (const v8::FunctionCallbackInfo<v8::Value>& info)\r
196 {\r
197     info.GetReturnValue().Set(true);\r
198     const FXJSE_CLASS* lpClass = static_cast<FXJSE_CLASS*>(info.Data().As<v8::External>()->Value());\r
199     if (!lpClass) {\r
200         return;\r
201     }\r
202     v8::Isolate*        pIsolate = info.GetIsolate();\r
203     v8::HandleScope scope(pIsolate);\r
204     v8::Local<v8::String> hPropName = info[0]->ToString();\r
205     v8::String::Utf8Value szPropName(hPropName);\r
206     CFX_ByteStringC               szFxPropName(*szPropName, szPropName.length());\r
207     CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate());\r
208     lpThisValue->ForceSetValue(info.This());\r
209     info.GetReturnValue().Set(FXJSE_DynPropDeleterAdapter(lpClass, reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), szFxPropName) ? true : false);\r
210     delete lpThisValue;\r
211     lpThisValue = NULL;\r
212 }\r
213 static void FXJSE_V8ProxyCallback_fix                                           (const v8::FunctionCallbackInfo<v8::Value>& info)\r
214 {\r
215     info.GetReturnValue().SetUndefined();\r
216 }\r
217 static void FXJSE_V8_NamedPropertyQueryCallback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Integer>& info)\r
218 {\r
219     v8::Local<v8::Object> thisObject = info.This();\r
220     if (thisObject->HasRealNamedProperty(property)) {\r
221         return;\r
222     }\r
223     const FXJSE_CLASS* lpClass = static_cast<FXJSE_CLASS*>(info.Data().As<v8::External>()->Value());\r
224     v8::Isolate*        pIsolate = info.GetIsolate();\r
225     v8::HandleScope scope(pIsolate);\r
226     v8::String::Utf8Value szPropName(property);\r
227     CFX_ByteStringC               szFxPropName(*szPropName, szPropName.length());\r
228     CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate());\r
229     lpThisValue->ForceSetValue(thisObject);\r
230     if(FXJSE_DynPropQueryAdapter(lpClass, reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), szFxPropName)) {\r
231         info.GetReturnValue().Set(v8::DontDelete);\r
232     } else {\r
233         const FX_INT32 iV8Absent = 64;\r
234         info.GetReturnValue().Set(iV8Absent);\r
235     }\r
236     delete lpThisValue;\r
237     lpThisValue = NULL;\r
238 }\r
239 static void FXJSE_V8_NamedPropertyDeleterCallback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Boolean>& info)\r
240 {\r
241     v8::Local<v8::Object> thisObject = info.This();\r
242     if (thisObject->HasRealNamedProperty(property)) {\r
243         return;\r
244     }\r
245     const FXJSE_CLASS* lpClass = static_cast<FXJSE_CLASS*>(info.Data().As<v8::External>()->Value());\r
246     v8::Isolate*        pIsolate = info.GetIsolate();\r
247     v8::HandleScope scope(pIsolate);\r
248     v8::String::Utf8Value szPropName(property);\r
249     CFX_ByteStringC               szFxPropName(*szPropName, szPropName.length());\r
250     CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate());\r
251     lpThisValue->ForceSetValue(thisObject);\r
252     info.GetReturnValue().Set(FXJSE_DynPropDeleterAdapter(lpClass, reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), szFxPropName) ? true : false);\r
253     delete lpThisValue;\r
254     lpThisValue = NULL;\r
255 }\r
256 void CFXJSE_Class::SetUpDynPropHandler(CFXJSE_Context* pContext, CFXJSE_Value* pValue, const FXJSE_CLASS* lpClassDefinition)\r
257 {\r
258     v8::Isolate* pIsolate = pValue->GetIsolate();\r
259     CFXJSE_ScopeUtil_IsolateHandleRootOrNormalContext scope(pIsolate, pContext);\r
260     v8::Local<v8::Context> hContext = v8::Local<v8::Context>::New(pIsolate, pContext ? pContext->m_hContext : CFXJSE_RuntimeData::Get(pIsolate)->m_hRootContext);\r
261     v8::Local<v8::Object> hObject = v8::Local<v8::Object>::New(pIsolate, pValue->m_hValue.As<v8::Object>());\r
262     v8::Local<v8::Object> hHarmonyProxyObj =  hContext->Global()->Get(v8::String::NewFromUtf8(pIsolate, "Proxy")).As<v8::Object>();\r
263     v8::Local<v8::Function> hHarmonyProxyCreateFn = hHarmonyProxyObj->Get(v8::String::NewFromUtf8(pIsolate, "create")).As<v8::Function>();\r
264     v8::Local<v8::Value> hOldPrototype = hObject->GetPrototype();\r
265     v8::Local<v8::Object> hTrapper = v8::Object::New(pIsolate);\r
266     hTrapper->ForceSet(v8::String::NewFromUtf8(pIsolate, "getOwnPropertyDescriptor"),   v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_getOwnPropertyDescriptor, v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition))));\r
267     hTrapper->ForceSet(v8::String::NewFromUtf8(pIsolate, "getPropertyDescriptor"),              v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_getPropertyDescriptor,        v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition))));\r
268     hTrapper->ForceSet(v8::String::NewFromUtf8(pIsolate, "getOwnPropertyNames"),                v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_getOwnPropertyNames,          v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition))));\r
269     hTrapper->ForceSet(v8::String::NewFromUtf8(pIsolate, "getPropertyNames"),                   v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_getPropertyNames,                     v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition))));\r
270     hTrapper->ForceSet(v8::String::NewFromUtf8(pIsolate, "delete"),                                             v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_delete,                                       v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition))));\r
271     hTrapper->ForceSet(v8::String::NewFromUtf8(pIsolate, "defineProperty"),                             v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_defineProperty,                       v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition))));\r
272     hTrapper->ForceSet(v8::String::NewFromUtf8(pIsolate, "fix"),                                                v8::Function::New(pIsolate, FXJSE_V8ProxyCallback_fix,                                          v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition))));\r
273     v8::Handle<v8::Value> rgArgs[] = {hTrapper, hOldPrototype};\r
274     v8::Local<v8::Value> hNewPrototype = hHarmonyProxyCreateFn->Call(hHarmonyProxyObj, 2, rgArgs);\r
275     hObject->SetPrototype(hNewPrototype);\r
276 }\r
277 void CFXJSE_Class::SetUpNamedPropHandler(v8::Isolate* pIsolate, v8::Local<v8::ObjectTemplate>& hObjectTemplate, const FXJSE_CLASS* lpClassDefinition)\r
278 {\r
279     hObjectTemplate->SetNamedPropertyHandler(0, 0,\r
280             lpClassDefinition->dynPropTypeGetter ? FXJSE_V8_NamedPropertyQueryCallback : 0,\r
281             lpClassDefinition->dynPropDeleter ? FXJSE_V8_NamedPropertyDeleterCallback : 0,\r
282             0,\r
283             v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition)));\r
284 }\r