| OLD | NEW |
| (Empty) |
| 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 "fpdfsdk/jsapi/include/fxjs_v8.h" | |
| 8 | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "core/fxcrt/include/fx_basic.h" | |
| 12 | |
| 13 const wchar_t kFXJSValueNameString[] = L"string"; | |
| 14 const wchar_t kFXJSValueNameNumber[] = L"number"; | |
| 15 const wchar_t kFXJSValueNameBoolean[] = L"boolean"; | |
| 16 const wchar_t kFXJSValueNameDate[] = L"date"; | |
| 17 const wchar_t kFXJSValueNameObject[] = L"object"; | |
| 18 const wchar_t kFXJSValueNameFxobj[] = L"fxobj"; | |
| 19 const wchar_t kFXJSValueNameNull[] = L"null"; | |
| 20 const wchar_t kFXJSValueNameUndefined[] = L"undefined"; | |
| 21 | |
| 22 // Keep this consistent with the values defined in gin/public/context_holder.h | |
| 23 // (without actually requiring a dependency on gin itself for the standalone | |
| 24 // embedders of PDFIum). The value we want to use is: | |
| 25 // kPerContextDataStartIndex + kEmbedderPDFium, which is 3. | |
| 26 static const unsigned int kPerContextDataIndex = 3u; | |
| 27 static unsigned int g_embedderDataSlot = 1u; | |
| 28 static v8::Isolate* g_isolate = nullptr; | |
| 29 static size_t g_isolate_ref_count = 0; | |
| 30 static FXJS_ArrayBufferAllocator* g_arrayBufferAllocator = nullptr; | |
| 31 static v8::Global<v8::ObjectTemplate>* g_DefaultGlobalObjectTemplate = nullptr; | |
| 32 | |
| 33 class CFXJS_PerObjectData { | |
| 34 public: | |
| 35 explicit CFXJS_PerObjectData(int nObjDefID) | |
| 36 : m_ObjDefID(nObjDefID), m_pPrivate(nullptr) {} | |
| 37 | |
| 38 const int m_ObjDefID; | |
| 39 void* m_pPrivate; | |
| 40 }; | |
| 41 | |
| 42 class CFXJS_ObjDefinition { | |
| 43 public: | |
| 44 static int MaxID(v8::Isolate* pIsolate) { | |
| 45 return FXJS_PerIsolateData::Get(pIsolate)->m_ObjectDefnArray.size(); | |
| 46 } | |
| 47 | |
| 48 static CFXJS_ObjDefinition* ForID(v8::Isolate* pIsolate, int id) { | |
| 49 // Note: GetAt() halts if out-of-range even in release builds. | |
| 50 return FXJS_PerIsolateData::Get(pIsolate)->m_ObjectDefnArray[id]; | |
| 51 } | |
| 52 | |
| 53 CFXJS_ObjDefinition(v8::Isolate* isolate, | |
| 54 const wchar_t* sObjName, | |
| 55 FXJSOBJTYPE eObjType, | |
| 56 FXJS_CONSTRUCTOR pConstructor, | |
| 57 FXJS_DESTRUCTOR pDestructor) | |
| 58 : m_ObjName(sObjName), | |
| 59 m_ObjType(eObjType), | |
| 60 m_pConstructor(pConstructor), | |
| 61 m_pDestructor(pDestructor), | |
| 62 m_pIsolate(isolate) { | |
| 63 v8::Isolate::Scope isolate_scope(isolate); | |
| 64 v8::HandleScope handle_scope(isolate); | |
| 65 | |
| 66 v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); | |
| 67 fun->InstanceTemplate()->SetInternalFieldCount(2); | |
| 68 if (eObjType == FXJSOBJTYPE_GLOBAL) { | |
| 69 fun->InstanceTemplate()->Set( | |
| 70 v8::Symbol::GetToStringTag(isolate), | |
| 71 v8::String::NewFromUtf8(isolate, "global", v8::NewStringType::kNormal) | |
| 72 .ToLocalChecked()); | |
| 73 } | |
| 74 m_FunctionTemplate.Reset(isolate, fun); | |
| 75 | |
| 76 v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun); | |
| 77 m_Signature.Reset(isolate, sig); | |
| 78 } | |
| 79 | |
| 80 int AssignID() { | |
| 81 FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(m_pIsolate); | |
| 82 pData->m_ObjectDefnArray.push_back(this); | |
| 83 return pData->m_ObjectDefnArray.size() - 1; | |
| 84 } | |
| 85 | |
| 86 v8::Local<v8::ObjectTemplate> GetInstanceTemplate() { | |
| 87 v8::EscapableHandleScope scope(m_pIsolate); | |
| 88 v8::Local<v8::FunctionTemplate> function = | |
| 89 m_FunctionTemplate.Get(m_pIsolate); | |
| 90 return scope.Escape(function->InstanceTemplate()); | |
| 91 } | |
| 92 | |
| 93 v8::Local<v8::Signature> GetSignature() { | |
| 94 v8::EscapableHandleScope scope(m_pIsolate); | |
| 95 return scope.Escape(m_Signature.Get(m_pIsolate)); | |
| 96 } | |
| 97 | |
| 98 const wchar_t* const m_ObjName; | |
| 99 const FXJSOBJTYPE m_ObjType; | |
| 100 const FXJS_CONSTRUCTOR m_pConstructor; | |
| 101 const FXJS_DESTRUCTOR m_pDestructor; | |
| 102 | |
| 103 v8::Isolate* m_pIsolate; | |
| 104 v8::Global<v8::FunctionTemplate> m_FunctionTemplate; | |
| 105 v8::Global<v8::Signature> m_Signature; | |
| 106 }; | |
| 107 | |
| 108 static v8::Local<v8::ObjectTemplate> GetGlobalObjectTemplate( | |
| 109 v8::Isolate* pIsolate) { | |
| 110 int maxID = CFXJS_ObjDefinition::MaxID(pIsolate); | |
| 111 for (int i = 0; i < maxID; ++i) { | |
| 112 CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, i); | |
| 113 if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL) | |
| 114 return pObjDef->GetInstanceTemplate(); | |
| 115 } | |
| 116 if (!g_DefaultGlobalObjectTemplate) { | |
| 117 v8::Local<v8::ObjectTemplate> hGlobalTemplate = | |
| 118 v8::ObjectTemplate::New(pIsolate); | |
| 119 hGlobalTemplate->Set( | |
| 120 v8::Symbol::GetToStringTag(pIsolate), | |
| 121 v8::String::NewFromUtf8(pIsolate, "global", v8::NewStringType::kNormal) | |
| 122 .ToLocalChecked()); | |
| 123 g_DefaultGlobalObjectTemplate = | |
| 124 new v8::Global<v8::ObjectTemplate>(pIsolate, hGlobalTemplate); | |
| 125 } | |
| 126 return g_DefaultGlobalObjectTemplate->Get(pIsolate); | |
| 127 } | |
| 128 | |
| 129 void* FXJS_ArrayBufferAllocator::Allocate(size_t length) { | |
| 130 return calloc(1, length); | |
| 131 } | |
| 132 | |
| 133 void* FXJS_ArrayBufferAllocator::AllocateUninitialized(size_t length) { | |
| 134 return malloc(length); | |
| 135 } | |
| 136 | |
| 137 void FXJS_ArrayBufferAllocator::Free(void* data, size_t length) { | |
| 138 free(data); | |
| 139 } | |
| 140 | |
| 141 void V8TemplateMapTraits::Dispose(v8::Isolate* isolate, | |
| 142 v8::Global<v8::Object> value, | |
| 143 void* key) { | |
| 144 v8::Local<v8::Object> obj = value.Get(isolate); | |
| 145 if (obj.IsEmpty()) | |
| 146 return; | |
| 147 int id = FXJS_GetObjDefnID(obj); | |
| 148 if (id == -1) | |
| 149 return; | |
| 150 | |
| 151 CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(isolate, id); | |
| 152 if (!pObjDef) | |
| 153 return; | |
| 154 if (pObjDef->m_pDestructor) | |
| 155 pObjDef->m_pDestructor(obj); | |
| 156 FXJS_FreePrivate(obj); | |
| 157 } | |
| 158 | |
| 159 V8TemplateMapTraits::MapType* V8TemplateMapTraits::MapFromWeakCallbackInfo( | |
| 160 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { | |
| 161 V8TemplateMap* pMap = | |
| 162 (FXJS_PerIsolateData::Get(data.GetIsolate()))->m_pDynamicObjsMap; | |
| 163 return pMap ? &pMap->m_map : nullptr; | |
| 164 } | |
| 165 | |
| 166 void FXJS_Initialize(unsigned int embedderDataSlot, v8::Isolate* pIsolate) { | |
| 167 if (g_isolate) { | |
| 168 ASSERT(g_embedderDataSlot == embedderDataSlot); | |
| 169 ASSERT(g_isolate == pIsolate); | |
| 170 return; | |
| 171 } | |
| 172 g_embedderDataSlot = embedderDataSlot; | |
| 173 g_isolate = pIsolate; | |
| 174 } | |
| 175 | |
| 176 void FXJS_Release() { | |
| 177 ASSERT(!g_isolate || g_isolate_ref_count == 0); | |
| 178 delete g_DefaultGlobalObjectTemplate; | |
| 179 g_DefaultGlobalObjectTemplate = nullptr; | |
| 180 g_isolate = nullptr; | |
| 181 | |
| 182 delete g_arrayBufferAllocator; | |
| 183 g_arrayBufferAllocator = nullptr; | |
| 184 } | |
| 185 | |
| 186 bool FXJS_GetIsolate(v8::Isolate** pResultIsolate) { | |
| 187 if (g_isolate) { | |
| 188 *pResultIsolate = g_isolate; | |
| 189 return false; | |
| 190 } | |
| 191 // Provide backwards compatibility when no external isolate. | |
| 192 if (!g_arrayBufferAllocator) | |
| 193 g_arrayBufferAllocator = new FXJS_ArrayBufferAllocator(); | |
| 194 v8::Isolate::CreateParams params; | |
| 195 params.array_buffer_allocator = g_arrayBufferAllocator; | |
| 196 *pResultIsolate = v8::Isolate::New(params); | |
| 197 return true; | |
| 198 } | |
| 199 | |
| 200 size_t FXJS_GlobalIsolateRefCount() { | |
| 201 return g_isolate_ref_count; | |
| 202 } | |
| 203 | |
| 204 V8TemplateMap::V8TemplateMap(v8::Isolate* isolate) : m_map(isolate) {} | |
| 205 | |
| 206 V8TemplateMap::~V8TemplateMap() {} | |
| 207 | |
| 208 void V8TemplateMap::set(void* key, v8::Local<v8::Object> handle) { | |
| 209 ASSERT(!m_map.Contains(key)); | |
| 210 m_map.Set(key, handle); | |
| 211 } | |
| 212 | |
| 213 FXJS_PerIsolateData::~FXJS_PerIsolateData() {} | |
| 214 | |
| 215 // static | |
| 216 void FXJS_PerIsolateData::SetUp(v8::Isolate* pIsolate) { | |
| 217 if (!pIsolate->GetData(g_embedderDataSlot)) | |
| 218 pIsolate->SetData(g_embedderDataSlot, new FXJS_PerIsolateData()); | |
| 219 } | |
| 220 | |
| 221 // static | |
| 222 FXJS_PerIsolateData* FXJS_PerIsolateData::Get(v8::Isolate* pIsolate) { | |
| 223 return static_cast<FXJS_PerIsolateData*>( | |
| 224 pIsolate->GetData(g_embedderDataSlot)); | |
| 225 } | |
| 226 | |
| 227 #ifndef PDF_ENABLE_XFA | |
| 228 FXJS_PerIsolateData::FXJS_PerIsolateData() : m_pDynamicObjsMap(nullptr) {} | |
| 229 #else // PDF_ENABLE_XFA | |
| 230 FXJS_PerIsolateData::FXJS_PerIsolateData() | |
| 231 : m_pFXJSERuntimeData(nullptr), m_pDynamicObjsMap(nullptr) {} | |
| 232 #endif // PDF_ENABLE_XFA | |
| 233 | |
| 234 int FXJS_DefineObj(v8::Isolate* pIsolate, | |
| 235 const wchar_t* sObjName, | |
| 236 FXJSOBJTYPE eObjType, | |
| 237 FXJS_CONSTRUCTOR pConstructor, | |
| 238 FXJS_DESTRUCTOR pDestructor) { | |
| 239 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 240 v8::HandleScope handle_scope(pIsolate); | |
| 241 | |
| 242 FXJS_PerIsolateData::SetUp(pIsolate); | |
| 243 CFXJS_ObjDefinition* pObjDef = new CFXJS_ObjDefinition( | |
| 244 pIsolate, sObjName, eObjType, pConstructor, pDestructor); | |
| 245 return pObjDef->AssignID(); | |
| 246 } | |
| 247 | |
| 248 void FXJS_DefineObjMethod(v8::Isolate* pIsolate, | |
| 249 int nObjDefnID, | |
| 250 const wchar_t* sMethodName, | |
| 251 v8::FunctionCallback pMethodCall) { | |
| 252 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 253 v8::HandleScope handle_scope(pIsolate); | |
| 254 CFX_ByteString bsMethodName = CFX_WideString(sMethodName).UTF8Encode(); | |
| 255 CFXJS_ObjDefinition* pObjDef = | |
| 256 CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); | |
| 257 v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New( | |
| 258 pIsolate, pMethodCall, v8::Local<v8::Value>(), pObjDef->GetSignature()); | |
| 259 fun->RemovePrototype(); | |
| 260 pObjDef->GetInstanceTemplate()->Set( | |
| 261 v8::String::NewFromUtf8(pIsolate, bsMethodName.c_str(), | |
| 262 v8::NewStringType::kNormal) | |
| 263 .ToLocalChecked(), | |
| 264 fun, v8::ReadOnly); | |
| 265 } | |
| 266 | |
| 267 void FXJS_DefineObjProperty(v8::Isolate* pIsolate, | |
| 268 int nObjDefnID, | |
| 269 const wchar_t* sPropName, | |
| 270 v8::AccessorGetterCallback pPropGet, | |
| 271 v8::AccessorSetterCallback pPropPut) { | |
| 272 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 273 v8::HandleScope handle_scope(pIsolate); | |
| 274 CFX_ByteString bsPropertyName = CFX_WideString(sPropName).UTF8Encode(); | |
| 275 CFXJS_ObjDefinition* pObjDef = | |
| 276 CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); | |
| 277 pObjDef->GetInstanceTemplate()->SetAccessor( | |
| 278 v8::String::NewFromUtf8(pIsolate, bsPropertyName.c_str(), | |
| 279 v8::NewStringType::kNormal) | |
| 280 .ToLocalChecked(), | |
| 281 pPropGet, pPropPut); | |
| 282 } | |
| 283 | |
| 284 void FXJS_DefineObjAllProperties(v8::Isolate* pIsolate, | |
| 285 int nObjDefnID, | |
| 286 v8::NamedPropertyQueryCallback pPropQurey, | |
| 287 v8::NamedPropertyGetterCallback pPropGet, | |
| 288 v8::NamedPropertySetterCallback pPropPut, | |
| 289 v8::NamedPropertyDeleterCallback pPropDel) { | |
| 290 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 291 v8::HandleScope handle_scope(pIsolate); | |
| 292 CFXJS_ObjDefinition* pObjDef = | |
| 293 CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); | |
| 294 pObjDef->GetInstanceTemplate()->SetNamedPropertyHandler(pPropGet, pPropPut, | |
| 295 pPropQurey, pPropDel); | |
| 296 } | |
| 297 | |
| 298 void FXJS_DefineObjConst(v8::Isolate* pIsolate, | |
| 299 int nObjDefnID, | |
| 300 const wchar_t* sConstName, | |
| 301 v8::Local<v8::Value> pDefault) { | |
| 302 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 303 v8::HandleScope handle_scope(pIsolate); | |
| 304 CFX_ByteString bsConstName = CFX_WideString(sConstName).UTF8Encode(); | |
| 305 CFXJS_ObjDefinition* pObjDef = | |
| 306 CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); | |
| 307 pObjDef->GetInstanceTemplate()->Set(pIsolate, bsConstName.c_str(), pDefault); | |
| 308 } | |
| 309 | |
| 310 void FXJS_DefineGlobalMethod(v8::Isolate* pIsolate, | |
| 311 const wchar_t* sMethodName, | |
| 312 v8::FunctionCallback pMethodCall) { | |
| 313 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 314 v8::HandleScope handle_scope(pIsolate); | |
| 315 CFX_ByteString bsMethodName = CFX_WideString(sMethodName).UTF8Encode(); | |
| 316 v8::Local<v8::FunctionTemplate> fun = | |
| 317 v8::FunctionTemplate::New(pIsolate, pMethodCall); | |
| 318 fun->RemovePrototype(); | |
| 319 GetGlobalObjectTemplate(pIsolate)->Set( | |
| 320 v8::String::NewFromUtf8(pIsolate, bsMethodName.c_str(), | |
| 321 v8::NewStringType::kNormal) | |
| 322 .ToLocalChecked(), | |
| 323 fun, v8::ReadOnly); | |
| 324 } | |
| 325 | |
| 326 void FXJS_DefineGlobalConst(v8::Isolate* pIsolate, | |
| 327 const wchar_t* sConstName, | |
| 328 v8::FunctionCallback pConstGetter) { | |
| 329 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 330 v8::HandleScope handle_scope(pIsolate); | |
| 331 CFX_ByteString bsConst = CFX_WideString(sConstName).UTF8Encode(); | |
| 332 v8::Local<v8::FunctionTemplate> fun = | |
| 333 v8::FunctionTemplate::New(pIsolate, pConstGetter); | |
| 334 fun->RemovePrototype(); | |
| 335 GetGlobalObjectTemplate(pIsolate)->SetAccessorProperty( | |
| 336 v8::String::NewFromUtf8(pIsolate, bsConst.c_str(), | |
| 337 v8::NewStringType::kNormal) | |
| 338 .ToLocalChecked(), | |
| 339 fun); | |
| 340 } | |
| 341 | |
| 342 void FXJS_InitializeRuntime( | |
| 343 v8::Isolate* pIsolate, | |
| 344 IJS_Runtime* pIRuntime, | |
| 345 v8::Global<v8::Context>* pV8PersistentContext, | |
| 346 std::vector<v8::Global<v8::Object>*>* pStaticObjects) { | |
| 347 if (pIsolate == g_isolate) | |
| 348 ++g_isolate_ref_count; | |
| 349 | |
| 350 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 351 v8::HandleScope handle_scope(pIsolate); | |
| 352 | |
| 353 // This has to happen before we call GetGlobalObjectTemplate because that | |
| 354 // method gets the PerIsolateData from pIsolate. | |
| 355 FXJS_PerIsolateData::SetUp(pIsolate); | |
| 356 | |
| 357 v8::Local<v8::Context> v8Context = | |
| 358 v8::Context::New(pIsolate, nullptr, GetGlobalObjectTemplate(pIsolate)); | |
| 359 v8::Context::Scope context_scope(v8Context); | |
| 360 | |
| 361 FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate); | |
| 362 if (!pData) | |
| 363 return; | |
| 364 pData->CreateDynamicObjsMap(pIsolate); | |
| 365 v8Context->SetAlignedPointerInEmbedderData(kPerContextDataIndex, pIRuntime); | |
| 366 | |
| 367 int maxID = CFXJS_ObjDefinition::MaxID(pIsolate); | |
| 368 pStaticObjects->resize(maxID + 1); | |
| 369 for (int i = 0; i < maxID; ++i) { | |
| 370 CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, i); | |
| 371 if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL) { | |
| 372 v8Context->Global() | |
| 373 ->GetPrototype() | |
| 374 ->ToObject(v8Context) | |
| 375 .ToLocalChecked() | |
| 376 ->SetAlignedPointerInInternalField(0, new CFXJS_PerObjectData(i)); | |
| 377 | |
| 378 if (pObjDef->m_pConstructor) | |
| 379 pObjDef->m_pConstructor(pIRuntime, v8Context->Global() | |
| 380 ->GetPrototype() | |
| 381 ->ToObject(v8Context) | |
| 382 .ToLocalChecked()); | |
| 383 } else if (pObjDef->m_ObjType == FXJSOBJTYPE_STATIC) { | |
| 384 CFX_ByteString bs = CFX_WideString(pObjDef->m_ObjName).UTF8Encode(); | |
| 385 v8::Local<v8::String> m_ObjName = | |
| 386 v8::String::NewFromUtf8(pIsolate, bs.c_str(), | |
| 387 v8::NewStringType::kNormal, bs.GetLength()) | |
| 388 .ToLocalChecked(); | |
| 389 | |
| 390 v8::Local<v8::Object> obj = | |
| 391 FXJS_NewFxDynamicObj(pIsolate, pIRuntime, i, true); | |
| 392 v8Context->Global()->Set(v8Context, m_ObjName, obj).FromJust(); | |
| 393 pStaticObjects->at(i) = new v8::Global<v8::Object>(pIsolate, obj); | |
| 394 } | |
| 395 } | |
| 396 pV8PersistentContext->Reset(pIsolate, v8Context); | |
| 397 } | |
| 398 | |
| 399 void FXJS_ReleaseRuntime(v8::Isolate* pIsolate, | |
| 400 v8::Global<v8::Context>* pV8PersistentContext, | |
| 401 std::vector<v8::Global<v8::Object>*>* pStaticObjects) { | |
| 402 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 403 v8::HandleScope handle_scope(pIsolate); | |
| 404 v8::Local<v8::Context> context = | |
| 405 v8::Local<v8::Context>::New(pIsolate, *pV8PersistentContext); | |
| 406 v8::Context::Scope context_scope(context); | |
| 407 | |
| 408 FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate); | |
| 409 if (!pData) | |
| 410 return; | |
| 411 | |
| 412 int maxID = CFXJS_ObjDefinition::MaxID(pIsolate); | |
| 413 for (int i = 0; i < maxID; ++i) { | |
| 414 CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, i); | |
| 415 v8::Local<v8::Object> pObj; | |
| 416 if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL) { | |
| 417 pObj = | |
| 418 context->Global()->GetPrototype()->ToObject(context).ToLocalChecked(); | |
| 419 } else if (pStaticObjects->at(i) && !pStaticObjects->at(i)->IsEmpty()) { | |
| 420 pObj = v8::Local<v8::Object>::New(pIsolate, *pStaticObjects->at(i)); | |
| 421 delete pStaticObjects->at(i); | |
| 422 pStaticObjects->at(i) = nullptr; | |
| 423 } | |
| 424 | |
| 425 if (!pObj.IsEmpty()) { | |
| 426 if (pObjDef->m_pDestructor) | |
| 427 pObjDef->m_pDestructor(pObj); | |
| 428 FXJS_FreePrivate(pObj); | |
| 429 } | |
| 430 } | |
| 431 | |
| 432 if (pIsolate == g_isolate && --g_isolate_ref_count > 0) | |
| 433 return; | |
| 434 | |
| 435 pData->ReleaseDynamicObjsMap(); | |
| 436 for (int i = 0; i < maxID; ++i) | |
| 437 delete CFXJS_ObjDefinition::ForID(pIsolate, i); | |
| 438 | |
| 439 pIsolate->SetData(g_embedderDataSlot, nullptr); | |
| 440 delete pData; | |
| 441 } | |
| 442 | |
| 443 IJS_Runtime* FXJS_GetRuntimeFromIsolate(v8::Isolate* pIsolate) { | |
| 444 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 445 return static_cast<IJS_Runtime*>( | |
| 446 context->GetAlignedPointerFromEmbedderData(kPerContextDataIndex)); | |
| 447 } | |
| 448 | |
| 449 #ifdef PDF_ENABLE_XFA | |
| 450 void FXJS_SetRuntimeForV8Context(v8::Local<v8::Context> v8Context, | |
| 451 IJS_Runtime* pIRuntime) { | |
| 452 v8Context->SetAlignedPointerInEmbedderData(kPerContextDataIndex, pIRuntime); | |
| 453 } | |
| 454 #endif // PDF_ENABLE_XFA | |
| 455 | |
| 456 int FXJS_Execute(v8::Isolate* pIsolate, | |
| 457 const CFX_WideString& script, | |
| 458 FXJSErr* pError) { | |
| 459 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 460 v8::TryCatch try_catch(pIsolate); | |
| 461 CFX_ByteString bsScript = script.UTF8Encode(); | |
| 462 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 463 v8::Local<v8::Script> compiled_script; | |
| 464 if (!v8::Script::Compile(context, | |
| 465 v8::String::NewFromUtf8(pIsolate, bsScript.c_str(), | |
| 466 v8::NewStringType::kNormal, | |
| 467 bsScript.GetLength()) | |
| 468 .ToLocalChecked()) | |
| 469 .ToLocal(&compiled_script)) { | |
| 470 v8::String::Utf8Value error(try_catch.Exception()); | |
| 471 // TODO(tsepez): return error via pError->message. | |
| 472 return -1; | |
| 473 } | |
| 474 | |
| 475 v8::Local<v8::Value> result; | |
| 476 if (!compiled_script->Run(context).ToLocal(&result)) { | |
| 477 v8::String::Utf8Value error(try_catch.Exception()); | |
| 478 // TODO(tsepez): return error via pError->message. | |
| 479 return -1; | |
| 480 } | |
| 481 return 0; | |
| 482 } | |
| 483 | |
| 484 v8::Local<v8::Object> FXJS_NewFxDynamicObj(v8::Isolate* pIsolate, | |
| 485 IJS_Runtime* pIRuntime, | |
| 486 int nObjDefnID, | |
| 487 bool bStatic) { | |
| 488 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 489 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 490 if (nObjDefnID == -1) { | |
| 491 v8::Local<v8::ObjectTemplate> objTempl = v8::ObjectTemplate::New(pIsolate); | |
| 492 v8::Local<v8::Object> obj; | |
| 493 if (!objTempl->NewInstance(context).ToLocal(&obj)) | |
| 494 return v8::Local<v8::Object>(); | |
| 495 return obj; | |
| 496 } | |
| 497 | |
| 498 FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate); | |
| 499 if (!pData) | |
| 500 return v8::Local<v8::Object>(); | |
| 501 | |
| 502 if (nObjDefnID < 0 || nObjDefnID >= CFXJS_ObjDefinition::MaxID(pIsolate)) | |
| 503 return v8::Local<v8::Object>(); | |
| 504 | |
| 505 CFXJS_ObjDefinition* pObjDef = | |
| 506 CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); | |
| 507 v8::Local<v8::Object> obj; | |
| 508 if (!pObjDef->GetInstanceTemplate()->NewInstance(context).ToLocal(&obj)) | |
| 509 return v8::Local<v8::Object>(); | |
| 510 | |
| 511 CFXJS_PerObjectData* pPerObjData = new CFXJS_PerObjectData(nObjDefnID); | |
| 512 obj->SetAlignedPointerInInternalField(0, pPerObjData); | |
| 513 if (pObjDef->m_pConstructor) | |
| 514 pObjDef->m_pConstructor(pIRuntime, obj); | |
| 515 | |
| 516 if (!bStatic && FXJS_PerIsolateData::Get(pIsolate)->m_pDynamicObjsMap) { | |
| 517 FXJS_PerIsolateData::Get(pIsolate) | |
| 518 ->m_pDynamicObjsMap->set(pPerObjData, obj); | |
| 519 } | |
| 520 return obj; | |
| 521 } | |
| 522 | |
| 523 v8::Local<v8::Object> FXJS_GetThisObj(v8::Isolate* pIsolate) { | |
| 524 v8::Isolate::Scope isolate_scope(pIsolate); | |
| 525 if (!FXJS_PerIsolateData::Get(pIsolate)) | |
| 526 return v8::Local<v8::Object>(); | |
| 527 | |
| 528 // Return the global object. | |
| 529 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 530 return context->Global()->GetPrototype()->ToObject(context).ToLocalChecked(); | |
| 531 } | |
| 532 | |
| 533 int FXJS_GetObjDefnID(v8::Local<v8::Object> pObj) { | |
| 534 if (pObj.IsEmpty() || !pObj->InternalFieldCount()) | |
| 535 return -1; | |
| 536 CFXJS_PerObjectData* pPerObjectData = static_cast<CFXJS_PerObjectData*>( | |
| 537 pObj->GetAlignedPointerFromInternalField(0)); | |
| 538 if (pPerObjectData) | |
| 539 return pPerObjectData->m_ObjDefID; | |
| 540 return -1; | |
| 541 } | |
| 542 | |
| 543 void FXJS_Error(v8::Isolate* pIsolate, const CFX_WideString& message) { | |
| 544 // Conversion from pdfium's wchar_t wide-strings to v8's uint16_t | |
| 545 // wide-strings isn't handled by v8, so use UTF8 as a common | |
| 546 // intermediate format. | |
| 547 CFX_ByteString utf8_message = message.UTF8Encode(); | |
| 548 pIsolate->ThrowException(v8::String::NewFromUtf8(pIsolate, | |
| 549 utf8_message.c_str(), | |
| 550 v8::NewStringType::kNormal) | |
| 551 .ToLocalChecked()); | |
| 552 } | |
| 553 | |
| 554 const wchar_t* FXJS_GetTypeof(v8::Local<v8::Value> pObj) { | |
| 555 if (pObj.IsEmpty()) | |
| 556 return nullptr; | |
| 557 if (pObj->IsString()) | |
| 558 return kFXJSValueNameString; | |
| 559 if (pObj->IsNumber()) | |
| 560 return kFXJSValueNameNumber; | |
| 561 if (pObj->IsBoolean()) | |
| 562 return kFXJSValueNameBoolean; | |
| 563 if (pObj->IsDate()) | |
| 564 return kFXJSValueNameDate; | |
| 565 if (pObj->IsObject()) | |
| 566 return kFXJSValueNameObject; | |
| 567 if (pObj->IsNull()) | |
| 568 return kFXJSValueNameNull; | |
| 569 if (pObj->IsUndefined()) | |
| 570 return kFXJSValueNameUndefined; | |
| 571 return nullptr; | |
| 572 } | |
| 573 | |
| 574 void FXJS_SetPrivate(v8::Isolate* pIsolate, | |
| 575 v8::Local<v8::Object> pObj, | |
| 576 void* p) { | |
| 577 if (pObj.IsEmpty() || !pObj->InternalFieldCount()) | |
| 578 return; | |
| 579 CFXJS_PerObjectData* pPerObjectData = static_cast<CFXJS_PerObjectData*>( | |
| 580 pObj->GetAlignedPointerFromInternalField(0)); | |
| 581 if (!pPerObjectData) | |
| 582 return; | |
| 583 pPerObjectData->m_pPrivate = p; | |
| 584 } | |
| 585 | |
| 586 void* FXJS_GetPrivate(v8::Isolate* pIsolate, v8::Local<v8::Object> pObj) { | |
| 587 if (pObj.IsEmpty()) | |
| 588 return nullptr; | |
| 589 CFXJS_PerObjectData* pPerObjectData = nullptr; | |
| 590 if (pObj->InternalFieldCount()) { | |
| 591 pPerObjectData = static_cast<CFXJS_PerObjectData*>( | |
| 592 pObj->GetAlignedPointerFromInternalField(0)); | |
| 593 } else { | |
| 594 // It could be a global proxy object. | |
| 595 v8::Local<v8::Value> v = pObj->GetPrototype(); | |
| 596 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 597 if (v->IsObject()) { | |
| 598 pPerObjectData = static_cast<CFXJS_PerObjectData*>( | |
| 599 v->ToObject(context) | |
| 600 .ToLocalChecked() | |
| 601 ->GetAlignedPointerFromInternalField(0)); | |
| 602 } | |
| 603 } | |
| 604 return pPerObjectData ? pPerObjectData->m_pPrivate : nullptr; | |
| 605 } | |
| 606 | |
| 607 void FXJS_FreePrivate(void* pPerObjectData) { | |
| 608 delete static_cast<CFXJS_PerObjectData*>(pPerObjectData); | |
| 609 } | |
| 610 | |
| 611 void FXJS_FreePrivate(v8::Local<v8::Object> pObj) { | |
| 612 if (pObj.IsEmpty() || !pObj->InternalFieldCount()) | |
| 613 return; | |
| 614 FXJS_FreePrivate(pObj->GetAlignedPointerFromInternalField(0)); | |
| 615 pObj->SetAlignedPointerInInternalField(0, nullptr); | |
| 616 } | |
| 617 | |
| 618 v8::Local<v8::String> FXJS_WSToJSString(v8::Isolate* pIsolate, | |
| 619 const CFX_WideString& wsPropertyName) { | |
| 620 CFX_ByteString bs = wsPropertyName.UTF8Encode(); | |
| 621 if (!pIsolate) | |
| 622 pIsolate = v8::Isolate::GetCurrent(); | |
| 623 return v8::String::NewFromUtf8(pIsolate, bs.c_str(), | |
| 624 v8::NewStringType::kNormal, bs.GetLength()) | |
| 625 .ToLocalChecked(); | |
| 626 } | |
| 627 | |
| 628 v8::Local<v8::Value> FXJS_GetObjectElement( | |
| 629 v8::Isolate* pIsolate, | |
| 630 v8::Local<v8::Object> pObj, | |
| 631 const CFX_WideString& wsPropertyName) { | |
| 632 if (pObj.IsEmpty()) | |
| 633 return v8::Local<v8::Value>(); | |
| 634 v8::Local<v8::Value> val; | |
| 635 if (!pObj->Get(pIsolate->GetCurrentContext(), | |
| 636 FXJS_WSToJSString(pIsolate, wsPropertyName)) | |
| 637 .ToLocal(&val)) | |
| 638 return v8::Local<v8::Value>(); | |
| 639 return val; | |
| 640 } | |
| 641 | |
| 642 v8::Local<v8::Array> FXJS_GetObjectElementNames(v8::Isolate* pIsolate, | |
| 643 v8::Local<v8::Object> pObj) { | |
| 644 if (pObj.IsEmpty()) | |
| 645 return v8::Local<v8::Array>(); | |
| 646 v8::Local<v8::Array> val; | |
| 647 if (!pObj->GetPropertyNames(pIsolate->GetCurrentContext()).ToLocal(&val)) | |
| 648 return v8::Local<v8::Array>(); | |
| 649 return val; | |
| 650 } | |
| 651 | |
| 652 void FXJS_PutObjectString(v8::Isolate* pIsolate, | |
| 653 v8::Local<v8::Object> pObj, | |
| 654 const CFX_WideString& wsPropertyName, | |
| 655 const CFX_WideString& wsValue) { | |
| 656 if (pObj.IsEmpty()) | |
| 657 return; | |
| 658 pObj->Set(pIsolate->GetCurrentContext(), | |
| 659 FXJS_WSToJSString(pIsolate, wsPropertyName), | |
| 660 FXJS_WSToJSString(pIsolate, wsValue)) | |
| 661 .FromJust(); | |
| 662 } | |
| 663 | |
| 664 void FXJS_PutObjectNumber(v8::Isolate* pIsolate, | |
| 665 v8::Local<v8::Object> pObj, | |
| 666 const CFX_WideString& wsPropertyName, | |
| 667 int nValue) { | |
| 668 if (pObj.IsEmpty()) | |
| 669 return; | |
| 670 pObj->Set(pIsolate->GetCurrentContext(), | |
| 671 FXJS_WSToJSString(pIsolate, wsPropertyName), | |
| 672 v8::Int32::New(pIsolate, nValue)) | |
| 673 .FromJust(); | |
| 674 } | |
| 675 | |
| 676 void FXJS_PutObjectNumber(v8::Isolate* pIsolate, | |
| 677 v8::Local<v8::Object> pObj, | |
| 678 const CFX_WideString& wsPropertyName, | |
| 679 float fValue) { | |
| 680 if (pObj.IsEmpty()) | |
| 681 return; | |
| 682 pObj->Set(pIsolate->GetCurrentContext(), | |
| 683 FXJS_WSToJSString(pIsolate, wsPropertyName), | |
| 684 v8::Number::New(pIsolate, (double)fValue)) | |
| 685 .FromJust(); | |
| 686 } | |
| 687 | |
| 688 void FXJS_PutObjectNumber(v8::Isolate* pIsolate, | |
| 689 v8::Local<v8::Object> pObj, | |
| 690 const CFX_WideString& wsPropertyName, | |
| 691 double dValue) { | |
| 692 if (pObj.IsEmpty()) | |
| 693 return; | |
| 694 pObj->Set(pIsolate->GetCurrentContext(), | |
| 695 FXJS_WSToJSString(pIsolate, wsPropertyName), | |
| 696 v8::Number::New(pIsolate, (double)dValue)) | |
| 697 .FromJust(); | |
| 698 } | |
| 699 | |
| 700 void FXJS_PutObjectBoolean(v8::Isolate* pIsolate, | |
| 701 v8::Local<v8::Object> pObj, | |
| 702 const CFX_WideString& wsPropertyName, | |
| 703 bool bValue) { | |
| 704 if (pObj.IsEmpty()) | |
| 705 return; | |
| 706 pObj->Set(pIsolate->GetCurrentContext(), | |
| 707 FXJS_WSToJSString(pIsolate, wsPropertyName), | |
| 708 v8::Boolean::New(pIsolate, bValue)) | |
| 709 .FromJust(); | |
| 710 } | |
| 711 | |
| 712 void FXJS_PutObjectObject(v8::Isolate* pIsolate, | |
| 713 v8::Local<v8::Object> pObj, | |
| 714 const CFX_WideString& wsPropertyName, | |
| 715 v8::Local<v8::Object> pPut) { | |
| 716 if (pObj.IsEmpty()) | |
| 717 return; | |
| 718 pObj->Set(pIsolate->GetCurrentContext(), | |
| 719 FXJS_WSToJSString(pIsolate, wsPropertyName), pPut) | |
| 720 .FromJust(); | |
| 721 } | |
| 722 | |
| 723 void FXJS_PutObjectNull(v8::Isolate* pIsolate, | |
| 724 v8::Local<v8::Object> pObj, | |
| 725 const CFX_WideString& wsPropertyName) { | |
| 726 if (pObj.IsEmpty()) | |
| 727 return; | |
| 728 pObj->Set(pIsolate->GetCurrentContext(), | |
| 729 FXJS_WSToJSString(pIsolate, wsPropertyName), | |
| 730 v8::Local<v8::Object>()) | |
| 731 .FromJust(); | |
| 732 } | |
| 733 | |
| 734 v8::Local<v8::Array> FXJS_NewArray(v8::Isolate* pIsolate) { | |
| 735 return v8::Array::New(pIsolate); | |
| 736 } | |
| 737 | |
| 738 unsigned FXJS_PutArrayElement(v8::Isolate* pIsolate, | |
| 739 v8::Local<v8::Array> pArray, | |
| 740 unsigned index, | |
| 741 v8::Local<v8::Value> pValue) { | |
| 742 if (pArray.IsEmpty()) | |
| 743 return 0; | |
| 744 if (pArray->Set(pIsolate->GetCurrentContext(), index, pValue).IsNothing()) | |
| 745 return 0; | |
| 746 return 1; | |
| 747 } | |
| 748 | |
| 749 v8::Local<v8::Value> FXJS_GetArrayElement(v8::Isolate* pIsolate, | |
| 750 v8::Local<v8::Array> pArray, | |
| 751 unsigned index) { | |
| 752 if (pArray.IsEmpty()) | |
| 753 return v8::Local<v8::Value>(); | |
| 754 v8::Local<v8::Value> val; | |
| 755 if (!pArray->Get(pIsolate->GetCurrentContext(), index).ToLocal(&val)) | |
| 756 return v8::Local<v8::Value>(); | |
| 757 return val; | |
| 758 } | |
| 759 | |
| 760 unsigned FXJS_GetArrayLength(v8::Local<v8::Array> pArray) { | |
| 761 if (pArray.IsEmpty()) | |
| 762 return 0; | |
| 763 return pArray->Length(); | |
| 764 } | |
| 765 | |
| 766 v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, int number) { | |
| 767 return v8::Int32::New(pIsolate, number); | |
| 768 } | |
| 769 | |
| 770 v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, double number) { | |
| 771 return v8::Number::New(pIsolate, number); | |
| 772 } | |
| 773 | |
| 774 v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, float number) { | |
| 775 return v8::Number::New(pIsolate, (float)number); | |
| 776 } | |
| 777 | |
| 778 v8::Local<v8::Value> FXJS_NewBoolean(v8::Isolate* pIsolate, bool b) { | |
| 779 return v8::Boolean::New(pIsolate, b); | |
| 780 } | |
| 781 | |
| 782 v8::Local<v8::Value> FXJS_NewObject(v8::Isolate* pIsolate, | |
| 783 v8::Local<v8::Object> pObj) { | |
| 784 if (pObj.IsEmpty()) | |
| 785 return v8::Local<v8::Value>(); | |
| 786 return pObj->Clone(); | |
| 787 } | |
| 788 | |
| 789 v8::Local<v8::Value> FXJS_NewObject2(v8::Isolate* pIsolate, | |
| 790 v8::Local<v8::Array> pObj) { | |
| 791 if (pObj.IsEmpty()) | |
| 792 return v8::Local<v8::Value>(); | |
| 793 return pObj->Clone(); | |
| 794 } | |
| 795 | |
| 796 v8::Local<v8::Value> FXJS_NewString(v8::Isolate* pIsolate, const wchar_t* str) { | |
| 797 return FXJS_WSToJSString(pIsolate, str); | |
| 798 } | |
| 799 | |
| 800 v8::Local<v8::Value> FXJS_NewNull() { | |
| 801 return v8::Local<v8::Value>(); | |
| 802 } | |
| 803 | |
| 804 v8::Local<v8::Value> FXJS_NewDate(v8::Isolate* pIsolate, double d) { | |
| 805 return v8::Date::New(pIsolate->GetCurrentContext(), d).ToLocalChecked(); | |
| 806 } | |
| 807 | |
| 808 int FXJS_ToInt32(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue) { | |
| 809 if (pValue.IsEmpty()) | |
| 810 return 0; | |
| 811 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 812 return pValue->ToInt32(context).ToLocalChecked()->Value(); | |
| 813 } | |
| 814 | |
| 815 bool FXJS_ToBoolean(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue) { | |
| 816 if (pValue.IsEmpty()) | |
| 817 return false; | |
| 818 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 819 return pValue->ToBoolean(context).ToLocalChecked()->Value(); | |
| 820 } | |
| 821 | |
| 822 double FXJS_ToNumber(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue) { | |
| 823 if (pValue.IsEmpty()) | |
| 824 return 0.0; | |
| 825 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 826 return pValue->ToNumber(context).ToLocalChecked()->Value(); | |
| 827 } | |
| 828 | |
| 829 v8::Local<v8::Object> FXJS_ToObject(v8::Isolate* pIsolate, | |
| 830 v8::Local<v8::Value> pValue) { | |
| 831 if (pValue.IsEmpty()) | |
| 832 return v8::Local<v8::Object>(); | |
| 833 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 834 return pValue->ToObject(context).ToLocalChecked(); | |
| 835 } | |
| 836 | |
| 837 CFX_WideString FXJS_ToString(v8::Isolate* pIsolate, | |
| 838 v8::Local<v8::Value> pValue) { | |
| 839 if (pValue.IsEmpty()) | |
| 840 return L""; | |
| 841 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 842 v8::String::Utf8Value s(pValue->ToString(context).ToLocalChecked()); | |
| 843 return CFX_WideString::FromUTF8(CFX_ByteStringC(*s, s.length())); | |
| 844 } | |
| 845 | |
| 846 v8::Local<v8::Array> FXJS_ToArray(v8::Isolate* pIsolate, | |
| 847 v8::Local<v8::Value> pValue) { | |
| 848 if (pValue.IsEmpty()) | |
| 849 return v8::Local<v8::Array>(); | |
| 850 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | |
| 851 return v8::Local<v8::Array>::Cast(pValue->ToObject(context).ToLocalChecked()); | |
| 852 } | |
| 853 | |
| 854 void FXJS_ValueCopy(v8::Local<v8::Value>& pTo, v8::Local<v8::Value> pFrom) { | |
| 855 pTo = pFrom; | |
| 856 } | |
| OLD | NEW |