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/src/javascript/JS_Runtime.h" | |
8 | |
9 #include "fpdfsdk/include/fsdk_mgr.h" // For CPDFDoc_Environment. | |
10 #include "fpdfsdk/include/javascript/IJavaScript.h" | |
11 #include "fpdfsdk/src/javascript/Consts.h" | |
12 #include "fpdfsdk/src/javascript/Document.h" | |
13 #include "fpdfsdk/src/javascript/Field.h" | |
14 #include "fpdfsdk/src/javascript/Icon.h" | |
15 #include "fpdfsdk/src/javascript/JS_Context.h" | |
16 #include "fpdfsdk/src/javascript/JS_Define.h" | |
17 #include "fpdfsdk/src/javascript/JS_EventHandler.h" | |
18 #include "fpdfsdk/src/javascript/JS_GlobalData.h" | |
19 #include "fpdfsdk/src/javascript/JS_Object.h" | |
20 #include "fpdfsdk/src/javascript/JS_Value.h" | |
21 #include "fpdfsdk/src/javascript/PublicMethods.h" | |
22 #include "fpdfsdk/src/javascript/app.h" | |
23 #include "fpdfsdk/src/javascript/color.h" | |
24 #include "fpdfsdk/src/javascript/console.h" | |
25 #include "fpdfsdk/src/javascript/event.h" | |
26 #include "fpdfsdk/src/javascript/global.h" | |
27 #include "fpdfsdk/src/javascript/report.h" | |
28 #include "fpdfsdk/src/javascript/util.h" | |
29 #include "third_party/base/stl_util.h" | |
30 | |
31 #ifdef PDF_ENABLE_XFA | |
32 #include "fpdfsdk/include/fpdfxfa/fpdfxfa_app.h" | |
33 #include "xfa/src/fxjse/value.h" | |
34 #endif // PDF_ENABLE_XFA | |
35 | |
36 // static | |
37 void IJS_Runtime::Initialize(unsigned int slot, void* isolate) { | |
38 FXJS_Initialize(slot, reinterpret_cast<v8::Isolate*>(isolate)); | |
39 } | |
40 | |
41 // static | |
42 IJS_Runtime* IJS_Runtime::Create(CPDFDoc_Environment* pEnv) { | |
43 return new CJS_Runtime(pEnv); | |
44 } | |
45 | |
46 // static | |
47 CJS_Runtime* CJS_Runtime::FromContext(const IJS_Context* cc) { | |
48 const CJS_Context* pContext = static_cast<const CJS_Context*>(cc); | |
49 return pContext->GetJSRuntime(); | |
50 } | |
51 | |
52 CJS_Runtime::CJS_Runtime(CPDFDoc_Environment* pApp) | |
53 : m_pApp(pApp), | |
54 m_pDocument(NULL), | |
55 m_bBlocking(FALSE), | |
56 m_isolate(NULL), | |
57 m_isolateManaged(false) { | |
58 #ifndef PDF_ENABLE_XFA | |
59 IPDF_JSPLATFORM* pPlatform = m_pApp->GetFormFillInfo()->m_pJsPlatform; | |
60 if (pPlatform->version <= 2) { | |
61 unsigned int embedderDataSlot = 0; | |
62 v8::Isolate* pExternalIsolate = nullptr; | |
63 if (pPlatform->version == 2) { | |
64 pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate); | |
65 embedderDataSlot = pPlatform->m_v8EmbedderSlot; | |
66 #else | |
67 if (CPDFXFA_App::GetInstance()->GetJSERuntime()) { | |
68 // TODO(tsepez): CPDFXFA_App should also use the embedder provided isolate. | |
69 m_isolate = (v8::Isolate*)CPDFXFA_App::GetInstance()->GetJSERuntime(); | |
70 } else { | |
71 IPDF_JSPLATFORM* pPlatform = m_pApp->GetFormFillInfo()->m_pJsPlatform; | |
72 if (pPlatform->version <= 2) { | |
73 unsigned int embedderDataSlot = 0; | |
74 v8::Isolate* pExternalIsolate = nullptr; | |
75 if (pPlatform->version == 2) { | |
76 pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate); | |
77 embedderDataSlot = pPlatform->m_v8EmbedderSlot; | |
78 } | |
79 FXJS_Initialize(embedderDataSlot, pExternalIsolate); | |
80 #endif | |
81 } | |
82 #ifndef PDF_ENABLE_XFA | |
83 FXJS_Initialize(embedderDataSlot, pExternalIsolate); | |
84 #else | |
85 m_isolateManaged = FXJS_GetIsolate(&m_isolate); | |
86 } | |
87 | |
88 v8::Isolate* isolate = m_isolate; | |
89 v8::Isolate::Scope isolate_scope(isolate); | |
90 v8::Locker locker(isolate); | |
91 v8::HandleScope handle_scope(isolate); | |
92 if (CPDFXFA_App::GetInstance()->IsJavaScriptInitialized()) { | |
93 CJS_Context* pContext = (CJS_Context*)NewContext(); | |
94 FXJS_InitializeRuntime(GetIsolate(), this, &m_context, &m_StaticObjects); | |
95 ReleaseContext(pContext); | |
96 return; | |
97 #endif | |
98 } | |
99 #ifndef PDF_ENABLE_XFA | |
100 m_isolateManaged = FXJS_GetIsolate(&m_isolate); | |
101 #else | |
102 | |
103 #endif | |
104 if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0) | |
105 DefineJSObjects(); | |
106 | |
107 #ifdef PDF_ENABLE_XFA | |
108 CPDFXFA_App::GetInstance()->SetJavaScriptInitialized(TRUE); | |
109 | |
110 #endif | |
111 CJS_Context* pContext = (CJS_Context*)NewContext(); | |
112 FXJS_InitializeRuntime(GetIsolate(), this, &m_context, &m_StaticObjects); | |
113 ReleaseContext(pContext); | |
114 } | |
115 | |
116 CJS_Runtime::~CJS_Runtime() { | |
117 for (auto* obs : m_observers) | |
118 obs->OnDestroyed(); | |
119 | |
120 for (int i = 0, sz = m_ContextArray.GetSize(); i < sz; i++) | |
121 delete m_ContextArray.GetAt(i); | |
122 | |
123 m_ContextArray.RemoveAll(); | |
124 m_ConstArrays.clear(); | |
125 FXJS_ReleaseRuntime(GetIsolate(), &m_context, &m_StaticObjects); | |
126 | |
127 m_pApp = NULL; | |
128 m_pDocument = NULL; | |
129 m_context.Reset(); | |
130 | |
131 if (m_isolateManaged) | |
132 m_isolate->Dispose(); | |
133 } | |
134 | |
135 void CJS_Runtime::DefineJSObjects() { | |
136 v8::Isolate::Scope isolate_scope(GetIsolate()); | |
137 #ifdef PDF_ENABLE_XFA | |
138 v8::Locker locker(GetIsolate()); | |
139 #endif | |
140 v8::HandleScope handle_scope(GetIsolate()); | |
141 v8::Local<v8::Context> context = v8::Context::New(GetIsolate()); | |
142 v8::Context::Scope context_scope(context); | |
143 | |
144 // The call order determines the "ObjDefID" assigned to each class. | |
145 // ObjDefIDs 0 - 2 | |
146 CJS_Border::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
147 CJS_Display::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
148 CJS_Font::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
149 | |
150 // ObjDefIDs 3 - 5 | |
151 CJS_Highlight::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
152 CJS_Position::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
153 CJS_ScaleHow::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
154 | |
155 // ObjDefIDs 6 - 8 | |
156 CJS_ScaleWhen::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
157 CJS_Style::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
158 CJS_Zoomtype::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
159 | |
160 // ObjDefIDs 9 - 11 | |
161 CJS_App::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
162 CJS_Color::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
163 CJS_Console::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
164 | |
165 // ObjDefIDs 12 - 14 | |
166 CJS_Document::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_GLOBAL); | |
167 CJS_Event::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
168 CJS_Field::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC); | |
169 | |
170 // ObjDefIDs 15 - 17 | |
171 CJS_Global::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
172 CJS_Icon::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC); | |
173 CJS_Util::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); | |
174 | |
175 // ObjDefIDs 18 - 20 (these can't fail, return void). | |
176 CJS_PublicMethods::DefineJSObjects(GetIsolate()); | |
177 CJS_GlobalConsts::DefineJSObjects(this); | |
178 CJS_GlobalArrays::DefineJSObjects(this); | |
179 | |
180 // ObjDefIDs 21 - 22. | |
181 CJS_TimerObj::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC); | |
182 CJS_PrintParamsObj::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC); | |
183 } | |
184 | |
185 IJS_Context* CJS_Runtime::NewContext() { | |
186 CJS_Context* p = new CJS_Context(this); | |
187 m_ContextArray.Add(p); | |
188 return p; | |
189 } | |
190 | |
191 void CJS_Runtime::ReleaseContext(IJS_Context* pContext) { | |
192 CJS_Context* pJSContext = (CJS_Context*)pContext; | |
193 | |
194 for (int i = 0, sz = m_ContextArray.GetSize(); i < sz; i++) { | |
195 if (pJSContext == m_ContextArray.GetAt(i)) { | |
196 delete pJSContext; | |
197 m_ContextArray.RemoveAt(i); | |
198 break; | |
199 } | |
200 } | |
201 } | |
202 | |
203 IJS_Context* CJS_Runtime::GetCurrentContext() { | |
204 if (!m_ContextArray.GetSize()) | |
205 return NULL; | |
206 return m_ContextArray.GetAt(m_ContextArray.GetSize() - 1); | |
207 } | |
208 | |
209 void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc) { | |
210 if (m_pDocument != pReaderDoc) { | |
211 v8::Isolate::Scope isolate_scope(m_isolate); | |
212 #ifdef PDF_ENABLE_XFA | |
213 v8::Locker locker(m_isolate); | |
214 #endif | |
215 v8::HandleScope handle_scope(m_isolate); | |
216 v8::Local<v8::Context> context = | |
217 v8::Local<v8::Context>::New(m_isolate, m_context); | |
218 v8::Context::Scope context_scope(context); | |
219 | |
220 m_pDocument = pReaderDoc; | |
221 if (pReaderDoc) { | |
222 v8::Local<v8::Object> pThis = FXJS_GetThisObj(GetIsolate()); | |
223 if (!pThis.IsEmpty()) { | |
224 if (FXJS_GetObjDefnID(pThis) == CJS_Document::g_nObjDefnID) { | |
225 if (CJS_Document* pJSDocument = | |
226 (CJS_Document*)FXJS_GetPrivate(GetIsolate(), pThis)) { | |
227 if (Document* pDocument = (Document*)pJSDocument->GetEmbedObject()) | |
228 pDocument->AttachDoc(pReaderDoc); | |
229 } | |
230 } | |
231 } | |
232 } | |
233 } | |
234 } | |
235 | |
236 int CJS_Runtime::Execute(IJS_Context* cc, | |
237 const wchar_t* script, | |
238 CFX_WideString* info) { | |
239 FXJSErr error = {}; | |
240 int nRet = FXJS_Execute(m_isolate, cc, script, &error); | |
241 if (nRet < 0) { | |
242 info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline, | |
243 error.message); | |
244 } | |
245 return nRet; | |
246 } | |
247 | |
248 bool CJS_Runtime::AddEventToSet(const FieldEvent& event) { | |
249 return m_FieldEventSet.insert(event).second; | |
250 } | |
251 | |
252 void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) { | |
253 m_FieldEventSet.erase(event); | |
254 } | |
255 | |
256 v8::Local<v8::Context> CJS_Runtime::NewJSContext() { | |
257 return v8::Local<v8::Context>::New(m_isolate, m_context); | |
258 } | |
259 | |
260 void CJS_Runtime::SetConstArray(const CFX_WideString& name, | |
261 v8::Local<v8::Array> array) { | |
262 m_ConstArrays[name] = v8::Global<v8::Array>(m_isolate, array); | |
263 } | |
264 | |
265 v8::Local<v8::Array> CJS_Runtime::GetConstArray(const CFX_WideString& name) { | |
266 return v8::Local<v8::Array>::New(m_isolate, m_ConstArrays[name]); | |
267 } | |
268 | |
269 #ifdef PDF_ENABLE_XFA | |
270 CFX_WideString ChangeObjName(const CFX_WideString& str) { | |
271 CFX_WideString sRet = str; | |
272 sRet.Replace(L"_", L"."); | |
273 return sRet; | |
274 } | |
275 FX_BOOL CJS_Runtime::GetHValueByName(const CFX_ByteStringC& utf8Name, | |
276 FXJSE_HVALUE hValue) { | |
277 #ifdef PDF_ENABLE_XFA | |
278 const FX_CHAR* name = utf8Name.GetCStr(); | |
279 | |
280 v8::Locker lock(GetIsolate()); | |
281 v8::Isolate::Scope isolate_scope(GetIsolate()); | |
282 v8::HandleScope handle_scope(GetIsolate()); | |
283 v8::Local<v8::Context> old_context = GetIsolate()->GetCurrentContext(); | |
284 v8::Local<v8::Context> context = | |
285 v8::Local<v8::Context>::New(GetIsolate(), m_context); | |
286 v8::Context::Scope context_scope(context); | |
287 | |
288 // Caution: We're about to hand to XFA an object that in order to invoke | |
289 // methods will require that the current v8::Context always has a pointer | |
290 // to a CJS_Runtime in its embedder data slot. Unfortunately, XFA creates | |
291 // its own v8::Context which has not initialized the embedder data slot. | |
292 // Do so now. | |
293 // TODO(tsepez): redesign PDF-side objects to not rely on v8::Context's | |
294 // embedder data slots, and/or to always use the right context. | |
295 FXJS_SetRuntimeForV8Context(old_context, this); | |
296 | |
297 v8::Local<v8::Value> propvalue = | |
298 context->Global()->Get(v8::String::NewFromUtf8( | |
299 GetIsolate(), name, v8::String::kNormalString, utf8Name.GetLength())); | |
300 | |
301 if (propvalue.IsEmpty()) { | |
302 FXJSE_Value_SetUndefined(hValue); | |
303 return FALSE; | |
304 } | |
305 ((CFXJSE_Value*)hValue)->ForceSetValue(propvalue); | |
306 #endif | |
307 | |
308 return TRUE; | |
309 } | |
310 FX_BOOL CJS_Runtime::SetHValueByName(const CFX_ByteStringC& utf8Name, | |
311 FXJSE_HVALUE hValue) { | |
312 #ifdef PDF_ENABLE_XFA | |
313 if (utf8Name.IsEmpty() || hValue == NULL) | |
314 return FALSE; | |
315 const FX_CHAR* name = utf8Name.GetCStr(); | |
316 v8::Isolate* pIsolate = GetIsolate(); | |
317 v8::Locker lock(pIsolate); | |
318 v8::Isolate::Scope isolate_scope(pIsolate); | |
319 v8::HandleScope handle_scope(pIsolate); | |
320 v8::Local<v8::Context> context = | |
321 v8::Local<v8::Context>::New(pIsolate, m_context); | |
322 v8::Context::Scope context_scope(context); | |
323 | |
324 // v8::Local<v8::Context> tmpCotext = | |
325 // v8::Local<v8::Context>::New(GetIsolate(), m_context); | |
326 v8::Local<v8::Value> propvalue = v8::Local<v8::Value>::New( | |
327 GetIsolate(), ((CFXJSE_Value*)hValue)->DirectGetValue()); | |
328 context->Global()->Set( | |
329 v8::String::NewFromUtf8(pIsolate, name, v8::String::kNormalString, | |
330 utf8Name.GetLength()), | |
331 propvalue); | |
332 #endif | |
333 return TRUE; | |
334 } | |
335 | |
336 #endif | |
337 void CJS_Runtime::AddObserver(Observer* observer) { | |
338 ASSERT(!pdfium::ContainsKey(m_observers, observer)); | |
339 m_observers.insert(observer); | |
340 } | |
341 | |
342 void CJS_Runtime::RemoveObserver(Observer* observer) { | |
343 ASSERT(pdfium::ContainsKey(m_observers, observer)); | |
344 m_observers.erase(observer); | |
345 } | |
OLD | NEW |