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 |