blob: f6e7b2d18a97ddc82b2f94d1fa2143751e64f538 [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
Dan Sinclaire0345a42017-10-30 20:20:42 +00007#include "fxjs/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"
Dan Sinclaire0345a42017-10-30 20:20:42 +000012#include "fxjs/JS_Define.h"
Dan Sinclaire0345a42017-10-30 20:20:42 +000013#include "fxjs/cjs_annot.h"
14#include "fxjs/cjs_app.h"
15#include "fxjs/cjs_border.h"
16#include "fxjs/cjs_color.h"
17#include "fxjs/cjs_console.h"
18#include "fxjs/cjs_display.h"
19#include "fxjs/cjs_document.h"
20#include "fxjs/cjs_event.h"
21#include "fxjs/cjs_event_context.h"
22#include "fxjs/cjs_eventhandler.h"
23#include "fxjs/cjs_field.h"
24#include "fxjs/cjs_font.h"
25#include "fxjs/cjs_global.h"
26#include "fxjs/cjs_globalarrays.h"
27#include "fxjs/cjs_globalconsts.h"
Dan Sinclaira3254622017-10-30 20:24:14 +000028#include "fxjs/cjs_globaldata.h"
Dan Sinclaire0345a42017-10-30 20:20:42 +000029#include "fxjs/cjs_highlight.h"
30#include "fxjs/cjs_icon.h"
31#include "fxjs/cjs_object.h"
32#include "fxjs/cjs_position.h"
33#include "fxjs/cjs_printparamsobj.h"
34#include "fxjs/cjs_publicmethods.h"
35#include "fxjs/cjs_report.h"
36#include "fxjs/cjs_scalehow.h"
37#include "fxjs/cjs_scalewhen.h"
38#include "fxjs/cjs_style.h"
39#include "fxjs/cjs_timerobj.h"
40#include "fxjs/cjs_util.h"
41#include "fxjs/cjs_zoomtype.h"
dsinclairf34518b2016-09-13 12:03:48 -070042#include "public/fpdf_formfill.h"
Lei Zhangcd2bb302015-12-22 13:49:44 -080043#include "third_party/base/stl_util.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070044
Tom Sepez40e9ff32015-11-30 12:39:54 -080045#ifdef PDF_ENABLE_XFA
dsinclair43554682016-09-29 17:29:48 -070046#include "fxjs/cfxjse_value.h"
Tom Sepez40e9ff32015-11-30 12:39:54 -080047#endif // PDF_ENABLE_XFA
48
Tom Sepez67fd5df2015-10-08 12:24:19 -070049// static
Tom Sepeze99ee7f2018-02-01 20:24:43 +000050CJS_Runtime* CJS_Runtime::RuntimeFromIsolateCurrentContext(
51 v8::Isolate* pIsolate) {
tsepezb4694242016-08-15 16:44:55 -070052 return static_cast<CJS_Runtime*>(
Tom Sepeze99ee7f2018-02-01 20:24:43 +000053 CFXJS_Engine::EngineFromIsolateCurrentContext(pIsolate));
tsepezb4694242016-08-15 16:44:55 -070054}
55
dsinclair82e17672016-10-11 12:38:01 -070056CJS_Runtime::CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv)
57 : m_pFormFillEnv(pFormFillEnv),
tsepeza4941912016-08-15 11:40:12 -070058 m_bBlocking(false),
Jochen Eisinger29007842015-08-05 09:02:13 +020059 m_isolateManaged(false) {
tsepezb4694242016-08-15 16:44:55 -070060 v8::Isolate* pIsolate = nullptr;
dsinclair8837c912016-11-01 11:22:37 -070061
dsinclair82e17672016-10-11 12:38:01 -070062 IPDF_JSPLATFORM* pPlatform = m_pFormFillEnv->GetFormFillInfo()->m_pJsPlatform;
Tom Sepez51da0932015-11-25 16:05:49 -080063 if (pPlatform->version <= 2) {
64 unsigned int embedderDataSlot = 0;
65 v8::Isolate* pExternalIsolate = nullptr;
66 if (pPlatform->version == 2) {
Tom Sepez9b8b2172018-04-25 22:12:34 +000067 pExternalIsolate = static_cast<v8::Isolate*>(pPlatform->m_isolate);
Tom Sepez51da0932015-11-25 16:05:49 -080068 embedderDataSlot = pPlatform->m_v8EmbedderSlot;
dsinclaird71bae02016-06-09 14:21:20 -070069 }
70 FXJS_Initialize(embedderDataSlot, pExternalIsolate);
71 }
tsepezb4694242016-08-15 16:44:55 -070072 m_isolateManaged = FXJS_GetIsolate(&pIsolate);
73 SetIsolate(pIsolate);
Tom Sepezd2cc1b92015-04-30 15:19:03 -070074
dsinclair8837c912016-11-01 11:22:37 -070075#ifdef PDF_ENABLE_XFA
tsepezb4694242016-08-15 16:44:55 -070076 v8::Isolate::Scope isolate_scope(pIsolate);
77 v8::HandleScope handle_scope(pIsolate);
Tom Sepez51da0932015-11-25 16:05:49 -080078#endif
dsinclaird71bae02016-06-09 14:21:20 -070079
Lei Zhang3fa115b2015-10-08 12:04:47 -070080 if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
81 DefineJSObjects();
82
Tom Sepezd6ae2af2017-02-16 11:49:55 -080083 IJS_EventContext* pContext = NewEventContext();
tsepezb4694242016-08-15 16:44:55 -070084 InitializeEngine();
Tom Sepezd6ae2af2017-02-16 11:49:55 -080085 ReleaseEventContext(pContext);
dsinclair82e17672016-10-11 12:38:01 -070086 SetFormFillEnvToDocument();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070087}
88
Nico Weber9d8ec5a2015-08-04 13:00:21 -070089CJS_Runtime::~CJS_Runtime() {
tsepez1c620542016-09-12 09:47:52 -070090 NotifyObservedPtrs();
tsepezb4694242016-08-15 16:44:55 -070091 ReleaseEngine();
92 if (m_isolateManaged) {
93 GetIsolate()->Dispose();
94 SetIsolate(nullptr);
95 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070096}
97
Tom Sepez142165e2015-09-11 13:21:50 -070098void CJS_Runtime::DefineJSObjects() {
Nico Weber9d8ec5a2015-08-04 13:00:21 -070099 v8::Isolate::Scope isolate_scope(GetIsolate());
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700100 v8::HandleScope handle_scope(GetIsolate());
101 v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
102 v8::Context::Scope context_scope(context);
Tom Sepez570875c2015-09-11 08:35:03 -0700103
104 // The call order determines the "ObjDefID" assigned to each class.
105 // ObjDefIDs 0 - 2
Dan Sinclairbef4d3e2017-10-26 16:49:38 -0400106 CJS_Border::DefineJSObjects(this);
107 CJS_Display::DefineJSObjects(this);
108 CJS_Font::DefineJSObjects(this);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700109
Tom Sepez570875c2015-09-11 08:35:03 -0700110 // ObjDefIDs 3 - 5
Dan Sinclairbef4d3e2017-10-26 16:49:38 -0400111 CJS_Highlight::DefineJSObjects(this);
112 CJS_Position::DefineJSObjects(this);
113 CJS_ScaleHow::DefineJSObjects(this);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700114
Tom Sepez570875c2015-09-11 08:35:03 -0700115 // ObjDefIDs 6 - 8
Dan Sinclairbef4d3e2017-10-26 16:49:38 -0400116 CJS_ScaleWhen::DefineJSObjects(this);
117 CJS_Style::DefineJSObjects(this);
118 CJS_Zoomtype::DefineJSObjects(this);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700119
Tom Sepez570875c2015-09-11 08:35:03 -0700120 // ObjDefIDs 9 - 11
Dan Sinclairbef4d3e2017-10-26 16:49:38 -0400121 CJS_App::DefineJSObjects(this);
122 CJS_Color::DefineJSObjects(this);
123 CJS_Console::DefineJSObjects(this);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700124
Tom Sepez570875c2015-09-11 08:35:03 -0700125 // ObjDefIDs 12 - 14
Dan Sinclairbef4d3e2017-10-26 16:49:38 -0400126 CJS_Document::DefineJSObjects(this);
127 CJS_Event::DefineJSObjects(this);
128 CJS_Field::DefineJSObjects(this);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700129
Tom Sepez570875c2015-09-11 08:35:03 -0700130 // ObjDefIDs 15 - 17
Dan Sinclairbef4d3e2017-10-26 16:49:38 -0400131 CJS_Global::DefineJSObjects(this);
132 CJS_Icon::DefineJSObjects(this);
133 CJS_Util::DefineJSObjects(this);
Tom Sepez570875c2015-09-11 08:35:03 -0700134
Tom Sepez142165e2015-09-11 13:21:50 -0700135 // ObjDefIDs 18 - 20 (these can't fail, return void).
tsepezb4694242016-08-15 16:44:55 -0700136 CJS_PublicMethods::DefineJSObjects(this);
Tom Sepez67fd5df2015-10-08 12:24:19 -0700137 CJS_GlobalConsts::DefineJSObjects(this);
138 CJS_GlobalArrays::DefineJSObjects(this);
Tom Sepez570875c2015-09-11 08:35:03 -0700139
tonikitoo618cb1f2016-08-18 20:10:17 -0700140 // ObjDefIDs 21 - 23.
Dan Sinclairbef4d3e2017-10-26 16:49:38 -0400141 CJS_TimerObj::DefineJSObjects(this);
142 CJS_PrintParamsObj::DefineJSObjects(this);
143 CJS_Annot::DefineJSObjects(this);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700144}
145
Tom Sepez0784c732018-04-23 18:02:57 +0000146CJS_Runtime* CJS_Runtime::AsCJSRuntime() {
147 return this;
148}
149
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800150IJS_EventContext* CJS_Runtime::NewEventContext() {
Dan Sinclair0bb13332017-03-30 16:12:02 -0400151 m_EventContextArray.push_back(pdfium::MakeUnique<CJS_EventContext>(this));
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800152 return m_EventContextArray.back().get();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700153}
154
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800155void 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);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700161}
162
Tom Sepezb1670b52017-02-16 17:01:00 -0800163CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800164 return m_EventContextArray.empty() ? nullptr
165 : m_EventContextArray.back().get();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700166}
167
dsinclair82e17672016-10-11 12:38:01 -0700168void CJS_Runtime::SetFormFillEnvToDocument() {
tsepezb4694242016-08-15 16:44:55 -0700169 v8::Isolate::Scope isolate_scope(GetIsolate());
170 v8::HandleScope handle_scope(GetIsolate());
Tom Sepez1258f7f2018-02-02 17:37:37 +0000171 v8::Local<v8::Context> context = GetV8Context();
tsepezb4694242016-08-15 16:44:55 -0700172 v8::Context::Scope context_scope(context);
173
tsepezb4694242016-08-15 16:44:55 -0700174 v8::Local<v8::Object> pThis = GetThisObj();
175 if (pThis.IsEmpty())
176 return;
177
Dan Sinclairef299532017-10-26 16:48:30 -0400178 if (CFXJS_Engine::GetObjDefnID(pThis) != CJS_Document::GetObjDefnID())
tsepezb4694242016-08-15 16:44:55 -0700179 return;
180
181 CJS_Document* pJSDocument =
182 static_cast<CJS_Document*>(GetObjectPrivate(pThis));
183 if (!pJSDocument)
184 return;
185
Dan Sinclairf7435522018-02-05 22:27:22 +0000186 pJSDocument->SetFormFillEnv(m_pFormFillEnv.Get());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700187}
188
dsinclair82e17672016-10-11 12:38:01 -0700189CPDFSDK_FormFillEnvironment* CJS_Runtime::GetFormFillEnv() const {
Tom Sepez77f6d0f2017-02-23 12:14:10 -0800190 return m_pFormFillEnv.Get();
weili625ad662016-06-15 11:21:33 -0700191}
192
Ryan Harrison275e2602017-09-18 14:23:18 -0400193int CJS_Runtime::ExecuteScript(const WideString& script, WideString* info) {
Tom Sepez33420902015-10-13 15:00:10 -0700194 FXJSErr error = {};
tsepezb4694242016-08-15 16:44:55 -0700195 int nRet = Execute(script, &error);
Tom Sepez33420902015-10-13 15:00:10 -0700196 if (nRet < 0) {
Ryan Harrison39a076f2017-12-07 18:18:14 +0000197 *info = WideString::Format(L"[ Line: %05d { %ls } ] : %s", error.linnum - 1,
Dan Sinclair3f1c8322017-11-16 21:45:18 +0000198 error.srcline, error.message);
Tom Sepez33420902015-10-13 15:00:10 -0700199 }
200 return nRet;
201}
202
Tom Sepez5d0e8432015-09-22 15:50:03 -0700203bool CJS_Runtime::AddEventToSet(const FieldEvent& event) {
204 return m_FieldEventSet.insert(event).second;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700205}
206
Tom Sepez5d0e8432015-09-22 15:50:03 -0700207void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) {
208 m_FieldEventSet.erase(event);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700209}
210
Tom Sepez51da0932015-11-25 16:05:49 -0800211#ifdef PDF_ENABLE_XFA
Ryan Harrison275e2602017-09-18 14:23:18 -0400212WideString ChangeObjName(const WideString& str) {
213 WideString sRet = str;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700214 sRet.Replace(L"_", L".");
215 return sRet;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700216}
Tom Sepez33b42e42017-07-19 13:19:12 -0700217
Tom Sepez9cbd2dd2018-02-02 17:24:58 +0000218bool CJS_Runtime::GetValueByNameFromGlobalObject(const ByteStringView& utf8Name,
219 CFXJSE_Value* pValue) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700220 v8::Isolate::Scope isolate_scope(GetIsolate());
221 v8::HandleScope handle_scope(GetIsolate());
Tom Sepez1258f7f2018-02-02 17:37:37 +0000222 v8::Local<v8::Context> context = GetV8Context();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700223 v8::Context::Scope context_scope(context);
Tom Sepez33b42e42017-07-19 13:19:12 -0700224 v8::Local<v8::Value> propvalue = context->Global()->Get(
225 v8::String::NewFromUtf8(GetIsolate(), utf8Name.unterminated_c_str(),
226 v8::String::kNormalString, utf8Name.GetLength()));
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700227 if (propvalue.IsEmpty()) {
dsinclairf27aeec2016-06-07 19:36:18 -0700228 pValue->SetUndefined();
tsepez4cf55152016-11-02 14:37:54 -0700229 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700230 }
dsinclair12a6b0c2016-05-26 11:14:08 -0700231 pValue->ForceSetValue(propvalue);
tsepez4cf55152016-11-02 14:37:54 -0700232 return true;
Bo Xufdc00a72014-10-28 23:03:33 -0700233}
Tom Sepez33b42e42017-07-19 13:19:12 -0700234
Tom Sepez9cbd2dd2018-02-02 17:24:58 +0000235bool CJS_Runtime::SetValueByNameInGlobalObject(const ByteStringView& utf8Name,
236 CFXJSE_Value* pValue) {
dsinclair12a6b0c2016-05-26 11:14:08 -0700237 if (utf8Name.IsEmpty() || !pValue)
tsepez4cf55152016-11-02 14:37:54 -0700238 return false;
Tom Sepez33b42e42017-07-19 13:19:12 -0700239
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700240 v8::Isolate* pIsolate = GetIsolate();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700241 v8::Isolate::Scope isolate_scope(pIsolate);
242 v8::HandleScope handle_scope(pIsolate);
Tom Sepez1258f7f2018-02-02 17:37:37 +0000243 v8::Local<v8::Context> context = GetV8Context();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700244 v8::Context::Scope context_scope(context);
dsinclair12a6b0c2016-05-26 11:14:08 -0700245 v8::Local<v8::Value> propvalue =
Tom Sepez1258f7f2018-02-02 17:37:37 +0000246 v8::Local<v8::Value>::New(pIsolate, pValue->DirectGetValue());
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700247 context->Global()->Set(
Tom Sepez33b42e42017-07-19 13:19:12 -0700248 v8::String::NewFromUtf8(pIsolate, utf8Name.unterminated_c_str(),
249 v8::String::kNormalString, utf8Name.GetLength()),
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700250 propvalue);
tsepez4cf55152016-11-02 14:37:54 -0700251 return true;
Bo Xufdc00a72014-10-28 23:03:33 -0700252}
Tom Sepez51da0932015-11-25 16:05:49 -0800253#endif
Dan Sinclaire85107b2017-10-24 15:29:22 -0400254
255v8::Local<v8::Value> CJS_Runtime::MaybeCoerceToNumber(
dan sinclair80435cb2017-10-24 21:40:24 -0400256 v8::Local<v8::Value> value) {
Dan Sinclaire85107b2017-10-24 15:29:22 -0400257 bool bAllowNaN = false;
258 if (value->IsString()) {
259 ByteString bstr = ByteString::FromUnicode(ToWideString(value));
260 if (bstr.GetLength() == 0)
261 return value;
262 if (bstr == "NaN")
263 bAllowNaN = true;
264 }
265
266 v8::Isolate* pIsolate = GetIsolate();
267 v8::TryCatch try_catch(pIsolate);
268 v8::MaybeLocal<v8::Number> maybeNum =
269 value->ToNumber(pIsolate->GetCurrentContext());
270 if (maybeNum.IsEmpty())
271 return value;
272
273 v8::Local<v8::Number> num = maybeNum.ToLocalChecked();
274 if (std::isnan(num->Value()) && !bAllowNaN)
275 return value;
276
277 return num;
278}