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