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