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/cjs_runtime.h"
8
9 #include <algorithm>
10
11 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
12 #include "fpdfsdk/javascript/Annot.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_Define.h"
18 #include "fpdfsdk/javascript/JS_EventHandler.h"
19 #include "fpdfsdk/javascript/JS_GlobalData.h"
20 #include "fpdfsdk/javascript/JS_Object.h"
21 #include "fpdfsdk/javascript/JS_Value.h"
22 #include "fpdfsdk/javascript/PublicMethods.h"
23 #include "fpdfsdk/javascript/app.h"
24 #include "fpdfsdk/javascript/cjs_event_context.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 "public/fpdf_formfill.h"
32 #include "third_party/base/stl_util.h"
33
34 #ifdef PDF_ENABLE_XFA
35 #include "fxjs/cfxjse_value.h"
36 #endif // PDF_ENABLE_XFA
37
38 // static
Initialize(unsigned int slot,void * isolate)39 void IJS_Runtime::Initialize(unsigned int slot, void* isolate) {
40 FXJS_Initialize(slot, reinterpret_cast<v8::Isolate*>(isolate));
41 }
42
43 // static
Destroy()44 void IJS_Runtime::Destroy() {
45 FXJS_Release();
46 }
47
48 // static
Create(CPDFSDK_FormFillEnvironment * pFormFillEnv)49 IJS_Runtime* IJS_Runtime::Create(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
50 return new CJS_Runtime(pFormFillEnv);
51 }
52
53 // static
CurrentRuntimeFromIsolate(v8::Isolate * pIsolate)54 CJS_Runtime* CJS_Runtime::CurrentRuntimeFromIsolate(v8::Isolate* pIsolate) {
55 return static_cast<CJS_Runtime*>(
56 CFXJS_Engine::CurrentEngineFromIsolate(pIsolate));
57 }
58
CJS_Runtime(CPDFSDK_FormFillEnvironment * pFormFillEnv)59 CJS_Runtime::CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv)
60 : m_pFormFillEnv(pFormFillEnv),
61 m_bBlocking(false),
62 m_isolateManaged(false) {
63 v8::Isolate* pIsolate = nullptr;
64
65 IPDF_JSPLATFORM* pPlatform = m_pFormFillEnv->GetFormFillInfo()->m_pJsPlatform;
66 if (pPlatform->version <= 2) {
67 unsigned int embedderDataSlot = 0;
68 v8::Isolate* pExternalIsolate = nullptr;
69 if (pPlatform->version == 2) {
70 pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate);
71 embedderDataSlot = pPlatform->m_v8EmbedderSlot;
72 }
73 FXJS_Initialize(embedderDataSlot, pExternalIsolate);
74 }
75 m_isolateManaged = FXJS_GetIsolate(&pIsolate);
76 SetIsolate(pIsolate);
77
78 #ifdef PDF_ENABLE_XFA
79 v8::Isolate::Scope isolate_scope(pIsolate);
80 v8::HandleScope handle_scope(pIsolate);
81 #endif
82
83 if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
84 DefineJSObjects();
85
86 IJS_EventContext* pContext = NewEventContext();
87 InitializeEngine();
88 ReleaseEventContext(pContext);
89 SetFormFillEnvToDocument();
90 }
91
~CJS_Runtime()92 CJS_Runtime::~CJS_Runtime() {
93 NotifyObservedPtrs();
94 ReleaseEngine();
95 if (m_isolateManaged) {
96 GetIsolate()->Dispose();
97 SetIsolate(nullptr);
98 }
99 }
100
DefineJSObjects()101 void CJS_Runtime::DefineJSObjects() {
102 v8::Isolate::Scope isolate_scope(GetIsolate());
103 v8::HandleScope handle_scope(GetIsolate());
104 v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
105 v8::Context::Scope context_scope(context);
106
107 // The call order determines the "ObjDefID" assigned to each class.
108 // ObjDefIDs 0 - 2
109 CJS_Border::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
110 CJS_Display::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
111 CJS_Font::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
112
113 // ObjDefIDs 3 - 5
114 CJS_Highlight::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
115 CJS_Position::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
116 CJS_ScaleHow::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
117
118 // ObjDefIDs 6 - 8
119 CJS_ScaleWhen::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
120 CJS_Style::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
121 CJS_Zoomtype::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
122
123 // ObjDefIDs 9 - 11
124 CJS_App::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
125 CJS_Color::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
126 CJS_Console::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
127
128 // ObjDefIDs 12 - 14
129 CJS_Document::DefineJSObjects(this, FXJSOBJTYPE_GLOBAL);
130 CJS_Event::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
131 CJS_Field::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
132
133 // ObjDefIDs 15 - 17
134 CJS_Global::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
135 CJS_Icon::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
136 CJS_Util::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
137
138 // ObjDefIDs 18 - 20 (these can't fail, return void).
139 CJS_PublicMethods::DefineJSObjects(this);
140 CJS_GlobalConsts::DefineJSObjects(this);
141 CJS_GlobalArrays::DefineJSObjects(this);
142
143 // ObjDefIDs 21 - 23.
144 CJS_TimerObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
145 CJS_PrintParamsObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
146 CJS_Annot::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
147 }
148
NewEventContext()149 IJS_EventContext* CJS_Runtime::NewEventContext() {
150 m_EventContextArray.push_back(
151 std::unique_ptr<CJS_EventContext>(new CJS_EventContext(this)));
152 return m_EventContextArray.back().get();
153 }
154
ReleaseEventContext(IJS_EventContext * pContext)155 void CJS_Runtime::ReleaseEventContext(IJS_EventContext* pContext) {
156 auto it = std::find(m_EventContextArray.begin(), m_EventContextArray.end(),
157 pdfium::FakeUniquePtr<CJS_EventContext>(
158 static_cast<CJS_EventContext*>(pContext)));
159 if (it != m_EventContextArray.end())
160 m_EventContextArray.erase(it);
161 }
162
GetCurrentEventContext() const163 CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
164 return m_EventContextArray.empty() ? nullptr
165 : m_EventContextArray.back().get();
166 }
167
SetFormFillEnvToDocument()168 void CJS_Runtime::SetFormFillEnvToDocument() {
169 v8::Isolate::Scope isolate_scope(GetIsolate());
170 v8::HandleScope handle_scope(GetIsolate());
171 v8::Local<v8::Context> context = NewLocalContext();
172 v8::Context::Scope context_scope(context);
173
174 v8::Local<v8::Object> pThis = GetThisObj();
175 if (pThis.IsEmpty())
176 return;
177
178 if (CFXJS_Engine::GetObjDefnID(pThis) != CJS_Document::g_nObjDefnID)
179 return;
180
181 CJS_Document* pJSDocument =
182 static_cast<CJS_Document*>(GetObjectPrivate(pThis));
183 if (!pJSDocument)
184 return;
185
186 Document* pDocument = static_cast<Document*>(pJSDocument->GetEmbedObject());
187 if (!pDocument)
188 return;
189
190 pDocument->SetFormFillEnv(m_pFormFillEnv.Get());
191 }
192
GetFormFillEnv() const193 CPDFSDK_FormFillEnvironment* CJS_Runtime::GetFormFillEnv() const {
194 return m_pFormFillEnv.Get();
195 }
196
ExecuteScript(const CFX_WideString & script,CFX_WideString * info)197 int CJS_Runtime::ExecuteScript(const CFX_WideString& script,
198 CFX_WideString* info) {
199 FXJSErr error = {};
200 int nRet = Execute(script, &error);
201 if (nRet < 0) {
202 info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline,
203 error.message);
204 }
205 return nRet;
206 }
207
AddEventToSet(const FieldEvent & event)208 bool CJS_Runtime::AddEventToSet(const FieldEvent& event) {
209 return m_FieldEventSet.insert(event).second;
210 }
211
RemoveEventFromSet(const FieldEvent & event)212 void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) {
213 m_FieldEventSet.erase(event);
214 }
215
216 #ifdef PDF_ENABLE_XFA
ChangeObjName(const CFX_WideString & str)217 CFX_WideString ChangeObjName(const CFX_WideString& str) {
218 CFX_WideString sRet = str;
219 sRet.Replace(L"_", L".");
220 return sRet;
221 }
GetValueByName(const CFX_ByteStringC & utf8Name,CFXJSE_Value * pValue)222 bool CJS_Runtime::GetValueByName(const CFX_ByteStringC& utf8Name,
223 CFXJSE_Value* pValue) {
224 const FX_CHAR* name = utf8Name.c_str();
225
226 v8::Isolate::Scope isolate_scope(GetIsolate());
227 v8::HandleScope handle_scope(GetIsolate());
228 v8::Local<v8::Context> context = NewLocalContext();
229 v8::Context::Scope context_scope(context);
230
231 v8::Local<v8::Value> propvalue =
232 context->Global()->Get(v8::String::NewFromUtf8(
233 GetIsolate(), name, v8::String::kNormalString, utf8Name.GetLength()));
234
235 if (propvalue.IsEmpty()) {
236 pValue->SetUndefined();
237 return false;
238 }
239 pValue->ForceSetValue(propvalue);
240 return true;
241 }
SetValueByName(const CFX_ByteStringC & utf8Name,CFXJSE_Value * pValue)242 bool CJS_Runtime::SetValueByName(const CFX_ByteStringC& utf8Name,
243 CFXJSE_Value* pValue) {
244 if (utf8Name.IsEmpty() || !pValue)
245 return false;
246 const FX_CHAR* name = utf8Name.c_str();
247 v8::Isolate* pIsolate = GetIsolate();
248 v8::Isolate::Scope isolate_scope(pIsolate);
249 v8::HandleScope handle_scope(pIsolate);
250 v8::Local<v8::Context> context = NewLocalContext();
251 v8::Context::Scope context_scope(context);
252
253 // v8::Local<v8::Context> tmpCotext =
254 // v8::Local<v8::Context>::New(GetIsolate(), m_context);
255 v8::Local<v8::Value> propvalue =
256 v8::Local<v8::Value>::New(GetIsolate(), pValue->DirectGetValue());
257 context->Global()->Set(
258 v8::String::NewFromUtf8(pIsolate, name, v8::String::kNormalString,
259 utf8Name.GetLength()),
260 propvalue);
261 return true;
262 }
263 #endif
264