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