blob: 1d9adc8f74eee54398041533eadd0802161bb68a [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// 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.
Lei Zhanga6d9f0e2015-06-13 00:48:38 -07004
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07005// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
dsinclair64376be2016-03-31 20:03:24 -07007#include "fpdfsdk/javascript/cjs_runtime.h"
Tom Sepez37458412015-10-06 11:33:46 -07008
tsepez41a53ad2016-03-28 16:59:30 -07009#include <algorithm>
10
dsinclair735606d2016-10-05 15:47:02 -070011#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
tonikitoo618cb1f2016-08-18 20:10:17 -070012#include "fpdfsdk/javascript/Annot.h"
Dan Sinclairf766ad22016-03-14 13:51:24 -040013#include "fpdfsdk/javascript/Consts.h"
14#include "fpdfsdk/javascript/Document.h"
15#include "fpdfsdk/javascript/Field.h"
16#include "fpdfsdk/javascript/Icon.h"
Dan Sinclairf766ad22016-03-14 13:51:24 -040017#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"
Tom Sepezd6ae2af2017-02-16 11:49:55 -080024#include "fpdfsdk/javascript/cjs_event_context.h"
Dan Sinclairf766ad22016-03-14 13:51:24 -040025#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"
dsinclairf34518b2016-09-13 12:03:48 -070031#include "public/fpdf_formfill.h"
Lei Zhangcd2bb302015-12-22 13:49:44 -080032#include "third_party/base/stl_util.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070033
Tom Sepez40e9ff32015-11-30 12:39:54 -080034#ifdef PDF_ENABLE_XFA
dsinclair43554682016-09-29 17:29:48 -070035#include "fxjs/cfxjse_value.h"
Tom Sepez40e9ff32015-11-30 12:39:54 -080036#endif // PDF_ENABLE_XFA
37
Tom Sepez67fd5df2015-10-08 12:24:19 -070038// static
Tom Sepez452b4f32015-10-13 09:27:27 -070039void IJS_Runtime::Initialize(unsigned int slot, void* isolate) {
40 FXJS_Initialize(slot, reinterpret_cast<v8::Isolate*>(isolate));
41}
42
43// static
thestig2d6dda12016-06-28 07:39:09 -070044void IJS_Runtime::Destroy() {
45 FXJS_Release();
46}
47
48// static
dsinclair82e17672016-10-11 12:38:01 -070049IJS_Runtime* IJS_Runtime::Create(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
50 return new CJS_Runtime(pFormFillEnv);
Tom Sepez37458412015-10-06 11:33:46 -070051}
52
Tom Sepez67fd5df2015-10-08 12:24:19 -070053// static
tsepezb4694242016-08-15 16:44:55 -070054CJS_Runtime* CJS_Runtime::CurrentRuntimeFromIsolate(v8::Isolate* pIsolate) {
55 return static_cast<CJS_Runtime*>(
56 CFXJS_Engine::CurrentEngineFromIsolate(pIsolate));
57}
58
dsinclair82e17672016-10-11 12:38:01 -070059CJS_Runtime::CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv)
60 : m_pFormFillEnv(pFormFillEnv),
tsepeza4941912016-08-15 11:40:12 -070061 m_bBlocking(false),
Jochen Eisinger29007842015-08-05 09:02:13 +020062 m_isolateManaged(false) {
tsepezb4694242016-08-15 16:44:55 -070063 v8::Isolate* pIsolate = nullptr;
dsinclair8837c912016-11-01 11:22:37 -070064
dsinclair82e17672016-10-11 12:38:01 -070065 IPDF_JSPLATFORM* pPlatform = m_pFormFillEnv->GetFormFillInfo()->m_pJsPlatform;
Tom Sepez51da0932015-11-25 16:05:49 -080066 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;
dsinclaird71bae02016-06-09 14:21:20 -070072 }
73 FXJS_Initialize(embedderDataSlot, pExternalIsolate);
74 }
tsepezb4694242016-08-15 16:44:55 -070075 m_isolateManaged = FXJS_GetIsolate(&pIsolate);
76 SetIsolate(pIsolate);
Tom Sepezd2cc1b92015-04-30 15:19:03 -070077
dsinclair8837c912016-11-01 11:22:37 -070078#ifdef PDF_ENABLE_XFA
tsepezb4694242016-08-15 16:44:55 -070079 v8::Isolate::Scope isolate_scope(pIsolate);
80 v8::HandleScope handle_scope(pIsolate);
Tom Sepez51da0932015-11-25 16:05:49 -080081#endif
dsinclaird71bae02016-06-09 14:21:20 -070082
Lei Zhang3fa115b2015-10-08 12:04:47 -070083 if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
84 DefineJSObjects();
85
Tom Sepezd6ae2af2017-02-16 11:49:55 -080086 IJS_EventContext* pContext = NewEventContext();
tsepezb4694242016-08-15 16:44:55 -070087 InitializeEngine();
Tom Sepezd6ae2af2017-02-16 11:49:55 -080088 ReleaseEventContext(pContext);
dsinclair82e17672016-10-11 12:38:01 -070089 SetFormFillEnvToDocument();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070090}
91
Nico Weber9d8ec5a2015-08-04 13:00:21 -070092CJS_Runtime::~CJS_Runtime() {
tsepez1c620542016-09-12 09:47:52 -070093 NotifyObservedPtrs();
tsepezb4694242016-08-15 16:44:55 -070094 ReleaseEngine();
95 if (m_isolateManaged) {
96 GetIsolate()->Dispose();
97 SetIsolate(nullptr);
98 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070099}
100
Tom Sepez142165e2015-09-11 13:21:50 -0700101void CJS_Runtime::DefineJSObjects() {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700102 v8::Isolate::Scope isolate_scope(GetIsolate());
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700103 v8::HandleScope handle_scope(GetIsolate());
104 v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
105 v8::Context::Scope context_scope(context);
Tom Sepez570875c2015-09-11 08:35:03 -0700106
107 // The call order determines the "ObjDefID" assigned to each class.
108 // ObjDefIDs 0 - 2
tsepezb4694242016-08-15 16:44:55 -0700109 CJS_Border::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
110 CJS_Display::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
111 CJS_Font::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700112
Tom Sepez570875c2015-09-11 08:35:03 -0700113 // ObjDefIDs 3 - 5
tsepezb4694242016-08-15 16:44:55 -0700114 CJS_Highlight::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
115 CJS_Position::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
116 CJS_ScaleHow::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700117
Tom Sepez570875c2015-09-11 08:35:03 -0700118 // ObjDefIDs 6 - 8
tsepezb4694242016-08-15 16:44:55 -0700119 CJS_ScaleWhen::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
120 CJS_Style::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
121 CJS_Zoomtype::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700122
Tom Sepez570875c2015-09-11 08:35:03 -0700123 // ObjDefIDs 9 - 11
tsepezb4694242016-08-15 16:44:55 -0700124 CJS_App::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
125 CJS_Color::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
126 CJS_Console::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700127
Tom Sepez570875c2015-09-11 08:35:03 -0700128 // ObjDefIDs 12 - 14
tsepezb4694242016-08-15 16:44:55 -0700129 CJS_Document::DefineJSObjects(this, FXJSOBJTYPE_GLOBAL);
130 CJS_Event::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
131 CJS_Field::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700132
Tom Sepez570875c2015-09-11 08:35:03 -0700133 // ObjDefIDs 15 - 17
tsepezb4694242016-08-15 16:44:55 -0700134 CJS_Global::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
135 CJS_Icon::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
136 CJS_Util::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
Tom Sepez570875c2015-09-11 08:35:03 -0700137
Tom Sepez142165e2015-09-11 13:21:50 -0700138 // ObjDefIDs 18 - 20 (these can't fail, return void).
tsepezb4694242016-08-15 16:44:55 -0700139 CJS_PublicMethods::DefineJSObjects(this);
Tom Sepez67fd5df2015-10-08 12:24:19 -0700140 CJS_GlobalConsts::DefineJSObjects(this);
141 CJS_GlobalArrays::DefineJSObjects(this);
Tom Sepez570875c2015-09-11 08:35:03 -0700142
tonikitoo618cb1f2016-08-18 20:10:17 -0700143 // ObjDefIDs 21 - 23.
tsepezb4694242016-08-15 16:44:55 -0700144 CJS_TimerObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
145 CJS_PrintParamsObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
tonikitoo618cb1f2016-08-18 20:10:17 -0700146 CJS_Annot::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700147}
148
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800149IJS_EventContext* CJS_Runtime::NewEventContext() {
Dan Sinclair0bb13332017-03-30 16:12:02 -0400150 m_EventContextArray.push_back(pdfium::MakeUnique<CJS_EventContext>(this));
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800151 return m_EventContextArray.back().get();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700152}
153
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800154void CJS_Runtime::ReleaseEventContext(IJS_EventContext* pContext) {
155 auto it = std::find(m_EventContextArray.begin(), m_EventContextArray.end(),
156 pdfium::FakeUniquePtr<CJS_EventContext>(
157 static_cast<CJS_EventContext*>(pContext)));
158 if (it != m_EventContextArray.end())
159 m_EventContextArray.erase(it);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700160}
161
Tom Sepezb1670b52017-02-16 17:01:00 -0800162CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800163 return m_EventContextArray.empty() ? nullptr
164 : m_EventContextArray.back().get();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700165}
166
dsinclair82e17672016-10-11 12:38:01 -0700167void CJS_Runtime::SetFormFillEnvToDocument() {
tsepezb4694242016-08-15 16:44:55 -0700168 v8::Isolate::Scope isolate_scope(GetIsolate());
169 v8::HandleScope handle_scope(GetIsolate());
170 v8::Local<v8::Context> context = NewLocalContext();
171 v8::Context::Scope context_scope(context);
172
tsepezb4694242016-08-15 16:44:55 -0700173 v8::Local<v8::Object> pThis = GetThisObj();
174 if (pThis.IsEmpty())
175 return;
176
177 if (CFXJS_Engine::GetObjDefnID(pThis) != CJS_Document::g_nObjDefnID)
178 return;
179
180 CJS_Document* pJSDocument =
181 static_cast<CJS_Document*>(GetObjectPrivate(pThis));
182 if (!pJSDocument)
183 return;
184
185 Document* pDocument = static_cast<Document*>(pJSDocument->GetEmbedObject());
186 if (!pDocument)
187 return;
188
Tom Sepez77f6d0f2017-02-23 12:14:10 -0800189 pDocument->SetFormFillEnv(m_pFormFillEnv.Get());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700190}
191
dsinclair82e17672016-10-11 12:38:01 -0700192CPDFSDK_FormFillEnvironment* CJS_Runtime::GetFormFillEnv() const {
Tom Sepez77f6d0f2017-02-23 12:14:10 -0800193 return m_pFormFillEnv.Get();
weili625ad662016-06-15 11:21:33 -0700194}
195
Ryan Harrison275e2602017-09-18 14:23:18 -0400196int CJS_Runtime::ExecuteScript(const WideString& script, WideString* info) {
Tom Sepez33420902015-10-13 15:00:10 -0700197 FXJSErr error = {};
tsepezb4694242016-08-15 16:44:55 -0700198 int nRet = Execute(script, &error);
Tom Sepez33420902015-10-13 15:00:10 -0700199 if (nRet < 0) {
200 info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline,
201 error.message);
202 }
203 return nRet;
204}
205
Tom Sepez5d0e8432015-09-22 15:50:03 -0700206bool CJS_Runtime::AddEventToSet(const FieldEvent& event) {
207 return m_FieldEventSet.insert(event).second;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700208}
209
Tom Sepez5d0e8432015-09-22 15:50:03 -0700210void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) {
211 m_FieldEventSet.erase(event);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700212}
213
Tom Sepez51da0932015-11-25 16:05:49 -0800214#ifdef PDF_ENABLE_XFA
Ryan Harrison275e2602017-09-18 14:23:18 -0400215WideString ChangeObjName(const WideString& str) {
216 WideString sRet = str;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700217 sRet.Replace(L"_", L".");
218 return sRet;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700219}
Tom Sepez33b42e42017-07-19 13:19:12 -0700220
Ryan Harrison275e2602017-09-18 14:23:18 -0400221bool CJS_Runtime::GetValueByName(const ByteStringView& utf8Name,
tsepez4cf55152016-11-02 14:37:54 -0700222 CFXJSE_Value* pValue) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700223 v8::Isolate::Scope isolate_scope(GetIsolate());
224 v8::HandleScope handle_scope(GetIsolate());
tsepezb4694242016-08-15 16:44:55 -0700225 v8::Local<v8::Context> context = NewLocalContext();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700226 v8::Context::Scope context_scope(context);
Tom Sepez33b42e42017-07-19 13:19:12 -0700227 v8::Local<v8::Value> propvalue = context->Global()->Get(
228 v8::String::NewFromUtf8(GetIsolate(), utf8Name.unterminated_c_str(),
229 v8::String::kNormalString, utf8Name.GetLength()));
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700230 if (propvalue.IsEmpty()) {
dsinclairf27aeec2016-06-07 19:36:18 -0700231 pValue->SetUndefined();
tsepez4cf55152016-11-02 14:37:54 -0700232 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700233 }
dsinclair12a6b0c2016-05-26 11:14:08 -0700234 pValue->ForceSetValue(propvalue);
tsepez4cf55152016-11-02 14:37:54 -0700235 return true;
Bo Xufdc00a72014-10-28 23:03:33 -0700236}
Tom Sepez33b42e42017-07-19 13:19:12 -0700237
Ryan Harrison275e2602017-09-18 14:23:18 -0400238bool CJS_Runtime::SetValueByName(const ByteStringView& utf8Name,
tsepez4cf55152016-11-02 14:37:54 -0700239 CFXJSE_Value* pValue) {
dsinclair12a6b0c2016-05-26 11:14:08 -0700240 if (utf8Name.IsEmpty() || !pValue)
tsepez4cf55152016-11-02 14:37:54 -0700241 return false;
Tom Sepez33b42e42017-07-19 13:19:12 -0700242
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700243 v8::Isolate* pIsolate = GetIsolate();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700244 v8::Isolate::Scope isolate_scope(pIsolate);
245 v8::HandleScope handle_scope(pIsolate);
tsepezb4694242016-08-15 16:44:55 -0700246 v8::Local<v8::Context> context = NewLocalContext();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700247 v8::Context::Scope context_scope(context);
dsinclair12a6b0c2016-05-26 11:14:08 -0700248 v8::Local<v8::Value> propvalue =
249 v8::Local<v8::Value>::New(GetIsolate(), pValue->DirectGetValue());
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700250 context->Global()->Set(
Tom Sepez33b42e42017-07-19 13:19:12 -0700251 v8::String::NewFromUtf8(pIsolate, utf8Name.unterminated_c_str(),
252 v8::String::kNormalString, utf8Name.GetLength()),
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700253 propvalue);
tsepez4cf55152016-11-02 14:37:54 -0700254 return true;
Bo Xufdc00a72014-10-28 23:03:33 -0700255}
Tom Sepez51da0932015-11-25 16:05:49 -0800256#endif
Dan Sinclaire85107b2017-10-24 15:29:22 -0400257
258v8::Local<v8::Value> CJS_Runtime::MaybeCoerceToNumber(
dan sinclair80435cb2017-10-24 21:40:24 -0400259 v8::Local<v8::Value> value) {
Dan Sinclaire85107b2017-10-24 15:29:22 -0400260 bool bAllowNaN = false;
261 if (value->IsString()) {
262 ByteString bstr = ByteString::FromUnicode(ToWideString(value));
263 if (bstr.GetLength() == 0)
264 return value;
265 if (bstr == "NaN")
266 bAllowNaN = true;
267 }
268
269 v8::Isolate* pIsolate = GetIsolate();
270 v8::TryCatch try_catch(pIsolate);
271 v8::MaybeLocal<v8::Number> maybeNum =
272 value->ToNumber(pIsolate->GetCurrentContext());
273 if (maybeNum.IsEmpty())
274 return value;
275
276 v8::Local<v8::Number> num = maybeNum.ToLocalChecked();
277 if (std::isnan(num->Value()) && !bAllowNaN)
278 return value;
279
280 return num;
281}