1 // Copyright 2014 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 "xfa/src/foxitlib.h" 8 #include "fxv8.h" 9 #include "context.h" 10 #include "class.h" 11 #include "value.h" 12 #include "scope_inline.h" 13 #include "util_inline.h" 14 static void FXJSE_V8ConstructorCallback_Wrapper( 15 const v8::FunctionCallbackInfo<v8::Value>& info); 16 static void FXJSE_V8FunctionCallback_Wrapper( 17 const v8::FunctionCallbackInfo<v8::Value>& info); 18 static void FXJSE_V8GetterCallback_Wrapper( 19 v8::Local<v8::String> property, 20 const v8::PropertyCallbackInfo<v8::Value>& info); 21 static void FXJSE_V8SetterCallback_Wrapper( 22 v8::Local<v8::String> property, 23 v8::Local<v8::Value> value, 24 const v8::PropertyCallbackInfo<void>& info); 25 void FXJSE_DefineFunctions(FXJSE_HCONTEXT hContext, 26 const FXJSE_FUNCTION* lpFunctions, 27 int nNum) { 28 CFXJSE_Context* lpContext = reinterpret_cast<CFXJSE_Context*>(hContext); 29 ASSERT(lpContext); 30 CFXJSE_ScopeUtil_IsolateHandleContext scope(lpContext); 31 v8::Isolate* pIsolate = lpContext->GetRuntime(); 32 v8::Local<v8::Object> hGlobalObject = 33 FXJSE_GetGlobalObjectFromContext(scope.GetLocalContext()); 34 for (int32_t i = 0; i < nNum; i++) { 35 hGlobalObject->ForceSet( 36 v8::String::NewFromUtf8(pIsolate, lpFunctions[i].name), 37 v8::Function::New( 38 pIsolate, FXJSE_V8FunctionCallback_Wrapper, 39 v8::External::New(pIsolate, 40 const_cast<FXJSE_FUNCTION*>(lpFunctions + i))), 41 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete)); 42 } 43 } 44 FXJSE_HCLASS FXJSE_DefineClass(FXJSE_HCONTEXT hContext, 45 const FXJSE_CLASS* lpClass) { 46 CFXJSE_Context* lpContext = reinterpret_cast<CFXJSE_Context*>(hContext); 47 ASSERT(lpContext); 48 return reinterpret_cast<FXJSE_HCLASS>( 49 CFXJSE_Class::Create(lpContext, lpClass, FALSE)); 50 } 51 FXJSE_HCLASS FXJSE_GetClass(FXJSE_HCONTEXT hContext, 52 const CFX_ByteStringC& szName) { 53 return reinterpret_cast<FXJSE_HCLASS>(CFXJSE_Class::GetClassFromContext( 54 reinterpret_cast<CFXJSE_Context*>(hContext), szName)); 55 } 56 static void FXJSE_V8FunctionCallback_Wrapper( 57 const v8::FunctionCallbackInfo<v8::Value>& info) { 58 const FXJSE_FUNCTION* lpFunctionInfo = 59 static_cast<FXJSE_FUNCTION*>(info.Data().As<v8::External>()->Value()); 60 if (!lpFunctionInfo) { 61 return; 62 } 63 CFX_ByteStringC szFunctionName(lpFunctionInfo->name); 64 CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate()); 65 lpThisValue->ForceSetValue(info.This()); 66 CFXJSE_Value* lpRetValue = CFXJSE_Value::Create(info.GetIsolate()); 67 CFXJSE_ArgumentsImpl impl = {&info, lpRetValue}; 68 lpFunctionInfo->callbackProc(reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), 69 szFunctionName, 70 reinterpret_cast<CFXJSE_Arguments&>(impl)); 71 if (!lpRetValue->DirectGetValue().IsEmpty()) { 72 info.GetReturnValue().Set(lpRetValue->DirectGetValue()); 73 } 74 delete lpRetValue; 75 lpRetValue = NULL; 76 delete lpThisValue; 77 lpThisValue = NULL; 78 } 79 static void FXJSE_V8ClassGlobalConstructorCallback_Wrapper( 80 const v8::FunctionCallbackInfo<v8::Value>& info) { 81 const FXJSE_CLASS* lpClassDefinition = 82 static_cast<FXJSE_CLASS*>(info.Data().As<v8::External>()->Value()); 83 if (!lpClassDefinition) { 84 return; 85 } 86 CFX_ByteStringC szFunctionName(lpClassDefinition->name); 87 CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate()); 88 lpThisValue->ForceSetValue(info.This()); 89 CFXJSE_Value* lpRetValue = CFXJSE_Value::Create(info.GetIsolate()); 90 CFXJSE_ArgumentsImpl impl = {&info, lpRetValue}; 91 lpClassDefinition->constructor(reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), 92 szFunctionName, 93 reinterpret_cast<CFXJSE_Arguments&>(impl)); 94 if (!lpRetValue->DirectGetValue().IsEmpty()) { 95 info.GetReturnValue().Set(lpRetValue->DirectGetValue()); 96 } 97 delete lpRetValue; 98 lpRetValue = NULL; 99 delete lpThisValue; 100 lpThisValue = NULL; 101 } 102 static void FXJSE_V8GetterCallback_Wrapper( 103 v8::Local<v8::String> property, 104 const v8::PropertyCallbackInfo<v8::Value>& info) { 105 const FXJSE_PROPERTY* lpPropertyInfo = 106 static_cast<FXJSE_PROPERTY*>(info.Data().As<v8::External>()->Value()); 107 if (!lpPropertyInfo) { 108 return; 109 } 110 CFX_ByteStringC szPropertyName(lpPropertyInfo->name); 111 CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate()); 112 CFXJSE_Value* lpPropValue = CFXJSE_Value::Create(info.GetIsolate()); 113 lpThisValue->ForceSetValue(info.This()); 114 lpPropertyInfo->getProc(reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), 115 szPropertyName, 116 reinterpret_cast<FXJSE_HVALUE>(lpPropValue)); 117 info.GetReturnValue().Set(lpPropValue->DirectGetValue()); 118 delete lpThisValue; 119 lpThisValue = NULL; 120 delete lpPropValue; 121 lpPropValue = NULL; 122 } 123 static void FXJSE_V8SetterCallback_Wrapper( 124 v8::Local<v8::String> property, 125 v8::Local<v8::Value> value, 126 const v8::PropertyCallbackInfo<void>& info) { 127 const FXJSE_PROPERTY* lpPropertyInfo = 128 static_cast<FXJSE_PROPERTY*>(info.Data().As<v8::External>()->Value()); 129 if (!lpPropertyInfo) { 130 return; 131 } 132 CFX_ByteStringC szPropertyName(lpPropertyInfo->name); 133 CFXJSE_Value* lpThisValue = CFXJSE_Value::Create(info.GetIsolate()); 134 CFXJSE_Value* lpPropValue = CFXJSE_Value::Create(info.GetIsolate()); 135 lpThisValue->ForceSetValue(info.This()); 136 lpPropValue->ForceSetValue(value); 137 lpPropertyInfo->setProc(reinterpret_cast<FXJSE_HOBJECT>(lpThisValue), 138 szPropertyName, 139 reinterpret_cast<FXJSE_HVALUE>(lpPropValue)); 140 delete lpThisValue; 141 lpThisValue = NULL; 142 delete lpPropValue; 143 lpPropValue = NULL; 144 } 145 static void FXJSE_V8ConstructorCallback_Wrapper( 146 const v8::FunctionCallbackInfo<v8::Value>& info) { 147 const FXJSE_CLASS* lpClassDefinition = 148 static_cast<FXJSE_CLASS*>(info.Data().As<v8::External>()->Value()); 149 if (!lpClassDefinition) { 150 return; 151 } 152 FXSYS_assert(info.This()->InternalFieldCount()); 153 info.This()->SetAlignedPointerInInternalField(0, NULL); 154 } 155 FXJSE_HRUNTIME CFXJSE_Arguments::GetRuntime() const { 156 const CFXJSE_ArgumentsImpl* lpArguments = 157 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 158 return reinterpret_cast<FXJSE_HRUNTIME>( 159 lpArguments->m_pRetValue->GetIsolate()); 160 } 161 int32_t CFXJSE_Arguments::GetLength() const { 162 const CFXJSE_ArgumentsImpl* lpArguments = 163 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 164 return lpArguments->m_pInfo->Length(); 165 } 166 FXJSE_HVALUE CFXJSE_Arguments::GetValue(int32_t index) const { 167 const CFXJSE_ArgumentsImpl* lpArguments = 168 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 169 CFXJSE_Value* lpArgValue = CFXJSE_Value::Create(v8::Isolate::GetCurrent()); 170 ASSERT(lpArgValue); 171 lpArgValue->ForceSetValue((*lpArguments->m_pInfo)[index]); 172 return reinterpret_cast<FXJSE_HVALUE>(lpArgValue); 173 } 174 FX_BOOL CFXJSE_Arguments::GetBoolean(int32_t index) const { 175 const CFXJSE_ArgumentsImpl* lpArguments = 176 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 177 return (*lpArguments->m_pInfo)[index]->BooleanValue(); 178 } 179 int32_t CFXJSE_Arguments::GetInt32(int32_t index) const { 180 const CFXJSE_ArgumentsImpl* lpArguments = 181 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 182 return static_cast<int32_t>((*lpArguments->m_pInfo)[index]->NumberValue()); 183 } 184 FX_FLOAT CFXJSE_Arguments::GetFloat(int32_t index) const { 185 const CFXJSE_ArgumentsImpl* lpArguments = 186 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 187 return static_cast<FX_FLOAT>((*lpArguments->m_pInfo)[index]->NumberValue()); 188 } 189 CFX_ByteString CFXJSE_Arguments::GetUTF8String(int32_t index) const { 190 const CFXJSE_ArgumentsImpl* lpArguments = 191 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 192 v8::Local<v8::String> hString = (*lpArguments->m_pInfo)[index]->ToString(); 193 v8::String::Utf8Value szStringVal(hString); 194 return CFX_ByteString(*szStringVal); 195 } 196 void* CFXJSE_Arguments::GetObject(int32_t index, FXJSE_HCLASS hClass) const { 197 const CFXJSE_ArgumentsImpl* lpArguments = 198 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 199 v8::Local<v8::Value> hValue = (*lpArguments->m_pInfo)[index]; 200 ASSERT(!hValue.IsEmpty()); 201 if (!hValue->IsObject()) { 202 return NULL; 203 } 204 CFXJSE_Class* lpClass = reinterpret_cast<CFXJSE_Class*>(hClass); 205 return FXJSE_RetrieveObjectBinding(hValue.As<v8::Object>(), lpClass); 206 } 207 FXJSE_HVALUE CFXJSE_Arguments::GetReturnValue() { 208 const CFXJSE_ArgumentsImpl* lpArguments = 209 reinterpret_cast<const CFXJSE_ArgumentsImpl* const>(this); 210 return reinterpret_cast<FXJSE_HVALUE>(lpArguments->m_pRetValue); 211 } 212 static void FXJSE_Context_GlobalObjToString( 213 const v8::FunctionCallbackInfo<v8::Value>& info) { 214 const FXJSE_CLASS* lpClass = 215 static_cast<FXJSE_CLASS*>(info.Data().As<v8::External>()->Value()); 216 if (!lpClass) { 217 return; 218 } 219 if (info.This() == info.Holder() && lpClass->name) { 220 CFX_ByteString szStringVal; 221 szStringVal.Format("[object %s]", lpClass->name); 222 info.GetReturnValue().Set(v8::String::NewFromUtf8( 223 info.GetIsolate(), (const FX_CHAR*)szStringVal, 224 v8::String::kNormalString, szStringVal.GetLength())); 225 } else { 226 info.GetReturnValue().Set(info.This()->ObjectProtoToString()); 227 } 228 } 229 CFXJSE_Class* CFXJSE_Class::Create(CFXJSE_Context* lpContext, 230 const FXJSE_CLASS* lpClassDefinition, 231 FX_BOOL bIsJSGlobal) { 232 if (!lpContext || !lpClassDefinition) { 233 return NULL; 234 } 235 CFXJSE_Class* pClass = 236 GetClassFromContext(lpContext, lpClassDefinition->name); 237 if (pClass) { 238 return pClass; 239 } 240 v8::Isolate* pIsolate = lpContext->m_pIsolate; 241 pClass = new CFXJSE_Class(lpContext); 242 pClass->m_szClassName = lpClassDefinition->name; 243 pClass->m_lpClassDefinition = lpClassDefinition; 244 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate); 245 v8::Local<v8::FunctionTemplate> hFunctionTemplate = v8::FunctionTemplate::New( 246 pIsolate, bIsJSGlobal ? 0 : FXJSE_V8ConstructorCallback_Wrapper, 247 v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>(lpClassDefinition))); 248 hFunctionTemplate->SetClassName( 249 v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name)); 250 hFunctionTemplate->InstanceTemplate()->SetInternalFieldCount(1); 251 v8::Local<v8::ObjectTemplate> hObjectTemplate = 252 hFunctionTemplate->InstanceTemplate(); 253 SetUpNamedPropHandler(pIsolate, hObjectTemplate, lpClassDefinition); 254 255 if (lpClassDefinition->propNum) { 256 for (int32_t i = 0; i < lpClassDefinition->propNum; i++) { 257 hObjectTemplate->SetNativeDataProperty( 258 v8::String::NewFromUtf8(pIsolate, 259 lpClassDefinition->properties[i].name), 260 lpClassDefinition->properties[i].getProc 261 ? FXJSE_V8GetterCallback_Wrapper 262 : NULL, 263 lpClassDefinition->properties[i].setProc 264 ? FXJSE_V8SetterCallback_Wrapper 265 : NULL, 266 v8::External::New(pIsolate, const_cast<FXJSE_PROPERTY*>( 267 lpClassDefinition->properties + i)), 268 static_cast<v8::PropertyAttribute>(v8::DontDelete)); 269 } 270 } 271 if (lpClassDefinition->methNum) { 272 for (int32_t i = 0; i < lpClassDefinition->methNum; i++) { 273 hObjectTemplate->Set( 274 v8::String::NewFromUtf8(pIsolate, lpClassDefinition->methods[i].name), 275 v8::FunctionTemplate::New( 276 pIsolate, FXJSE_V8FunctionCallback_Wrapper, 277 v8::External::New(pIsolate, const_cast<FXJSE_FUNCTION*>( 278 lpClassDefinition->methods + i))), 279 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete)); 280 } 281 } 282 if (lpClassDefinition->constructor) { 283 if (bIsJSGlobal) { 284 hObjectTemplate->Set( 285 v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name), 286 v8::FunctionTemplate::New( 287 pIsolate, FXJSE_V8ClassGlobalConstructorCallback_Wrapper, 288 v8::External::New(pIsolate, 289 const_cast<FXJSE_CLASS*>(lpClassDefinition))), 290 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete)); 291 } else { 292 v8::Local<v8::Context> hLocalContext = 293 v8::Local<v8::Context>::New(pIsolate, lpContext->m_hContext); 294 FXJSE_GetGlobalObjectFromContext(hLocalContext) 295 ->Set(v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name), 296 v8::Function::New( 297 pIsolate, FXJSE_V8ClassGlobalConstructorCallback_Wrapper, 298 v8::External::New(pIsolate, const_cast<FXJSE_CLASS*>( 299 lpClassDefinition)))); 300 } 301 } 302 if (bIsJSGlobal) { 303 hObjectTemplate->Set( 304 v8::String::NewFromUtf8(pIsolate, "toString"), 305 v8::FunctionTemplate::New( 306 pIsolate, FXJSE_Context_GlobalObjToString, 307 v8::External::New(pIsolate, 308 const_cast<FXJSE_CLASS*>(lpClassDefinition)))); 309 } 310 pClass->m_hTemplate.Reset(lpContext->m_pIsolate, hFunctionTemplate); 311 lpContext->m_rgClasses.Add(pClass); 312 return pClass; 313 } 314 CFXJSE_Class* CFXJSE_Class::GetClassFromContext(CFXJSE_Context* pContext, 315 const CFX_ByteStringC& szName) { 316 for (int count = pContext->m_rgClasses.GetSize(), i = 0; i < count; i++) { 317 CFXJSE_Class* pClass = pContext->m_rgClasses[i]; 318 if (pClass->m_szClassName == szName) { 319 return pClass; 320 } 321 } 322 return NULL; 323 } 324