blob: e48d6968667ac45d64ffb00c7fb6d7d09c744c42 [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"
Dan Sinclairf766ad22016-03-14 13:51:24 -040012#include "fpdfsdk/javascript/Document.h"
13#include "fpdfsdk/javascript/Field.h"
14#include "fpdfsdk/javascript/Icon.h"
Dan Sinclairf766ad22016-03-14 13:51:24 -040015#include "fpdfsdk/javascript/JS_Define.h"
16#include "fpdfsdk/javascript/JS_EventHandler.h"
17#include "fpdfsdk/javascript/JS_GlobalData.h"
18#include "fpdfsdk/javascript/JS_Object.h"
19#include "fpdfsdk/javascript/JS_Value.h"
20#include "fpdfsdk/javascript/PublicMethods.h"
21#include "fpdfsdk/javascript/app.h"
dan sinclair95460d82017-10-25 20:25:04 -040022#include "fpdfsdk/javascript/cjs_annot.h"
dan sinclair993a1992017-10-25 20:21:09 -040023#include "fpdfsdk/javascript/cjs_border.h"
24#include "fpdfsdk/javascript/cjs_display.h"
Tom Sepezd6ae2af2017-02-16 11:49:55 -080025#include "fpdfsdk/javascript/cjs_event_context.h"
dan sinclair993a1992017-10-25 20:21:09 -040026#include "fpdfsdk/javascript/cjs_font.h"
dan sinclaird7ac26c2017-10-25 20:30:02 -040027#include "fpdfsdk/javascript/cjs_global.h"
dan sinclair993a1992017-10-25 20:21:09 -040028#include "fpdfsdk/javascript/cjs_globalarrays.h"
29#include "fpdfsdk/javascript/cjs_globalconsts.h"
30#include "fpdfsdk/javascript/cjs_highlight.h"
31#include "fpdfsdk/javascript/cjs_position.h"
32#include "fpdfsdk/javascript/cjs_scalehow.h"
33#include "fpdfsdk/javascript/cjs_scalewhen.h"
34#include "fpdfsdk/javascript/cjs_style.h"
35#include "fpdfsdk/javascript/cjs_zoomtype.h"
Dan Sinclairf766ad22016-03-14 13:51:24 -040036#include "fpdfsdk/javascript/color.h"
37#include "fpdfsdk/javascript/console.h"
38#include "fpdfsdk/javascript/event.h"
Dan Sinclairf766ad22016-03-14 13:51:24 -040039#include "fpdfsdk/javascript/report.h"
40#include "fpdfsdk/javascript/util.h"
dsinclairf34518b2016-09-13 12:03:48 -070041#include "public/fpdf_formfill.h"
Lei Zhangcd2bb302015-12-22 13:49:44 -080042#include "third_party/base/stl_util.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070043
Tom Sepez40e9ff32015-11-30 12:39:54 -080044#ifdef PDF_ENABLE_XFA
dsinclair43554682016-09-29 17:29:48 -070045#include "fxjs/cfxjse_value.h"
Tom Sepez40e9ff32015-11-30 12:39:54 -080046#endif // PDF_ENABLE_XFA
47
Tom Sepez67fd5df2015-10-08 12:24:19 -070048// static
Tom Sepez452b4f32015-10-13 09:27:27 -070049void IJS_Runtime::Initialize(unsigned int slot, void* isolate) {
50 FXJS_Initialize(slot, reinterpret_cast<v8::Isolate*>(isolate));
51}
52
53// static
thestig2d6dda12016-06-28 07:39:09 -070054void IJS_Runtime::Destroy() {
55 FXJS_Release();
56}
57
58// static
dsinclair82e17672016-10-11 12:38:01 -070059IJS_Runtime* IJS_Runtime::Create(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
60 return new CJS_Runtime(pFormFillEnv);
Tom Sepez37458412015-10-06 11:33:46 -070061}
62
Tom Sepez67fd5df2015-10-08 12:24:19 -070063// static
tsepezb4694242016-08-15 16:44:55 -070064CJS_Runtime* CJS_Runtime::CurrentRuntimeFromIsolate(v8::Isolate* pIsolate) {
65 return static_cast<CJS_Runtime*>(
66 CFXJS_Engine::CurrentEngineFromIsolate(pIsolate));
67}
68
dsinclair82e17672016-10-11 12:38:01 -070069CJS_Runtime::CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv)
70 : m_pFormFillEnv(pFormFillEnv),
tsepeza4941912016-08-15 11:40:12 -070071 m_bBlocking(false),
Jochen Eisinger29007842015-08-05 09:02:13 +020072 m_isolateManaged(false) {
tsepezb4694242016-08-15 16:44:55 -070073 v8::Isolate* pIsolate = nullptr;
dsinclair8837c912016-11-01 11:22:37 -070074
dsinclair82e17672016-10-11 12:38:01 -070075 IPDF_JSPLATFORM* pPlatform = m_pFormFillEnv->GetFormFillInfo()->m_pJsPlatform;
Tom Sepez51da0932015-11-25 16:05:49 -080076 if (pPlatform->version <= 2) {
77 unsigned int embedderDataSlot = 0;
78 v8::Isolate* pExternalIsolate = nullptr;
79 if (pPlatform->version == 2) {
80 pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate);
81 embedderDataSlot = pPlatform->m_v8EmbedderSlot;
dsinclaird71bae02016-06-09 14:21:20 -070082 }
83 FXJS_Initialize(embedderDataSlot, pExternalIsolate);
84 }
tsepezb4694242016-08-15 16:44:55 -070085 m_isolateManaged = FXJS_GetIsolate(&pIsolate);
86 SetIsolate(pIsolate);
Tom Sepezd2cc1b92015-04-30 15:19:03 -070087
dsinclair8837c912016-11-01 11:22:37 -070088#ifdef PDF_ENABLE_XFA
tsepezb4694242016-08-15 16:44:55 -070089 v8::Isolate::Scope isolate_scope(pIsolate);
90 v8::HandleScope handle_scope(pIsolate);
Tom Sepez51da0932015-11-25 16:05:49 -080091#endif
dsinclaird71bae02016-06-09 14:21:20 -070092
Lei Zhang3fa115b2015-10-08 12:04:47 -070093 if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
94 DefineJSObjects();
95
Tom Sepezd6ae2af2017-02-16 11:49:55 -080096 IJS_EventContext* pContext = NewEventContext();
tsepezb4694242016-08-15 16:44:55 -070097 InitializeEngine();
Tom Sepezd6ae2af2017-02-16 11:49:55 -080098 ReleaseEventContext(pContext);
dsinclair82e17672016-10-11 12:38:01 -070099 SetFormFillEnvToDocument();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700100}
101
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700102CJS_Runtime::~CJS_Runtime() {
tsepez1c620542016-09-12 09:47:52 -0700103 NotifyObservedPtrs();
tsepezb4694242016-08-15 16:44:55 -0700104 ReleaseEngine();
105 if (m_isolateManaged) {
106 GetIsolate()->Dispose();
107 SetIsolate(nullptr);
108 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700109}
110
Tom Sepez142165e2015-09-11 13:21:50 -0700111void CJS_Runtime::DefineJSObjects() {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700112 v8::Isolate::Scope isolate_scope(GetIsolate());
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700113 v8::HandleScope handle_scope(GetIsolate());
114 v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
115 v8::Context::Scope context_scope(context);
Tom Sepez570875c2015-09-11 08:35:03 -0700116
117 // The call order determines the "ObjDefID" assigned to each class.
118 // ObjDefIDs 0 - 2
tsepezb4694242016-08-15 16:44:55 -0700119 CJS_Border::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
120 CJS_Display::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
121 CJS_Font::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700122
Tom Sepez570875c2015-09-11 08:35:03 -0700123 // ObjDefIDs 3 - 5
tsepezb4694242016-08-15 16:44:55 -0700124 CJS_Highlight::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
125 CJS_Position::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
126 CJS_ScaleHow::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700127
Tom Sepez570875c2015-09-11 08:35:03 -0700128 // ObjDefIDs 6 - 8
tsepezb4694242016-08-15 16:44:55 -0700129 CJS_ScaleWhen::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
130 CJS_Style::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
131 CJS_Zoomtype::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700132
Tom Sepez570875c2015-09-11 08:35:03 -0700133 // ObjDefIDs 9 - 11
tsepezb4694242016-08-15 16:44:55 -0700134 CJS_App::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
135 CJS_Color::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
136 CJS_Console::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700137
Tom Sepez570875c2015-09-11 08:35:03 -0700138 // ObjDefIDs 12 - 14
tsepezb4694242016-08-15 16:44:55 -0700139 CJS_Document::DefineJSObjects(this, FXJSOBJTYPE_GLOBAL);
140 CJS_Event::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
141 CJS_Field::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700142
Tom Sepez570875c2015-09-11 08:35:03 -0700143 // ObjDefIDs 15 - 17
tsepezb4694242016-08-15 16:44:55 -0700144 CJS_Global::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
145 CJS_Icon::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
146 CJS_Util::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
Tom Sepez570875c2015-09-11 08:35:03 -0700147
Tom Sepez142165e2015-09-11 13:21:50 -0700148 // ObjDefIDs 18 - 20 (these can't fail, return void).
tsepezb4694242016-08-15 16:44:55 -0700149 CJS_PublicMethods::DefineJSObjects(this);
Tom Sepez67fd5df2015-10-08 12:24:19 -0700150 CJS_GlobalConsts::DefineJSObjects(this);
151 CJS_GlobalArrays::DefineJSObjects(this);
Tom Sepez570875c2015-09-11 08:35:03 -0700152
tonikitoo618cb1f2016-08-18 20:10:17 -0700153 // ObjDefIDs 21 - 23.
tsepezb4694242016-08-15 16:44:55 -0700154 CJS_TimerObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
155 CJS_PrintParamsObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
tonikitoo618cb1f2016-08-18 20:10:17 -0700156 CJS_Annot::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700157}
158
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800159IJS_EventContext* CJS_Runtime::NewEventContext() {
Dan Sinclair0bb13332017-03-30 16:12:02 -0400160 m_EventContextArray.push_back(pdfium::MakeUnique<CJS_EventContext>(this));
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800161 return m_EventContextArray.back().get();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700162}
163
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800164void CJS_Runtime::ReleaseEventContext(IJS_EventContext* pContext) {
165 auto it = std::find(m_EventContextArray.begin(), m_EventContextArray.end(),
166 pdfium::FakeUniquePtr<CJS_EventContext>(
167 static_cast<CJS_EventContext*>(pContext)));
168 if (it != m_EventContextArray.end())
169 m_EventContextArray.erase(it);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700170}
171
Tom Sepezb1670b52017-02-16 17:01:00 -0800172CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
Tom Sepezd6ae2af2017-02-16 11:49:55 -0800173 return m_EventContextArray.empty() ? nullptr
174 : m_EventContextArray.back().get();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700175}
176
dsinclair82e17672016-10-11 12:38:01 -0700177void CJS_Runtime::SetFormFillEnvToDocument() {
tsepezb4694242016-08-15 16:44:55 -0700178 v8::Isolate::Scope isolate_scope(GetIsolate());
179 v8::HandleScope handle_scope(GetIsolate());
180 v8::Local<v8::Context> context = NewLocalContext();
181 v8::Context::Scope context_scope(context);
182
tsepezb4694242016-08-15 16:44:55 -0700183 v8::Local<v8::Object> pThis = GetThisObj();
184 if (pThis.IsEmpty())
185 return;
186
187 if (CFXJS_Engine::GetObjDefnID(pThis) != CJS_Document::g_nObjDefnID)
188 return;
189
190 CJS_Document* pJSDocument =
191 static_cast<CJS_Document*>(GetObjectPrivate(pThis));
192 if (!pJSDocument)
193 return;
194
195 Document* pDocument = static_cast<Document*>(pJSDocument->GetEmbedObject());
196 if (!pDocument)
197 return;
198
Tom Sepez77f6d0f2017-02-23 12:14:10 -0800199 pDocument->SetFormFillEnv(m_pFormFillEnv.Get());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700200}
201
dsinclair82e17672016-10-11 12:38:01 -0700202CPDFSDK_FormFillEnvironment* CJS_Runtime::GetFormFillEnv() const {
Tom Sepez77f6d0f2017-02-23 12:14:10 -0800203 return m_pFormFillEnv.Get();
weili625ad662016-06-15 11:21:33 -0700204}
205
Ryan Harrison275e2602017-09-18 14:23:18 -0400206int CJS_Runtime::ExecuteScript(const WideString& script, WideString* info) {
Tom Sepez33420902015-10-13 15:00:10 -0700207 FXJSErr error = {};
tsepezb4694242016-08-15 16:44:55 -0700208 int nRet = Execute(script, &error);
Tom Sepez33420902015-10-13 15:00:10 -0700209 if (nRet < 0) {
210 info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline,
211 error.message);
212 }
213 return nRet;
214}
215
Tom Sepez5d0e8432015-09-22 15:50:03 -0700216bool CJS_Runtime::AddEventToSet(const FieldEvent& event) {
217 return m_FieldEventSet.insert(event).second;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700218}
219
Tom Sepez5d0e8432015-09-22 15:50:03 -0700220void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) {
221 m_FieldEventSet.erase(event);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700222}
223
Tom Sepez51da0932015-11-25 16:05:49 -0800224#ifdef PDF_ENABLE_XFA
Ryan Harrison275e2602017-09-18 14:23:18 -0400225WideString ChangeObjName(const WideString& str) {
226 WideString sRet = str;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700227 sRet.Replace(L"_", L".");
228 return sRet;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700229}
Tom Sepez33b42e42017-07-19 13:19:12 -0700230
Ryan Harrison275e2602017-09-18 14:23:18 -0400231bool CJS_Runtime::GetValueByName(const ByteStringView& utf8Name,
tsepez4cf55152016-11-02 14:37:54 -0700232 CFXJSE_Value* pValue) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700233 v8::Isolate::Scope isolate_scope(GetIsolate());
234 v8::HandleScope handle_scope(GetIsolate());
tsepezb4694242016-08-15 16:44:55 -0700235 v8::Local<v8::Context> context = NewLocalContext();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700236 v8::Context::Scope context_scope(context);
Tom Sepez33b42e42017-07-19 13:19:12 -0700237 v8::Local<v8::Value> propvalue = context->Global()->Get(
238 v8::String::NewFromUtf8(GetIsolate(), utf8Name.unterminated_c_str(),
239 v8::String::kNormalString, utf8Name.GetLength()));
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700240 if (propvalue.IsEmpty()) {
dsinclairf27aeec2016-06-07 19:36:18 -0700241 pValue->SetUndefined();
tsepez4cf55152016-11-02 14:37:54 -0700242 return false;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700243 }
dsinclair12a6b0c2016-05-26 11:14:08 -0700244 pValue->ForceSetValue(propvalue);
tsepez4cf55152016-11-02 14:37:54 -0700245 return true;
Bo Xufdc00a72014-10-28 23:03:33 -0700246}
Tom Sepez33b42e42017-07-19 13:19:12 -0700247
Ryan Harrison275e2602017-09-18 14:23:18 -0400248bool CJS_Runtime::SetValueByName(const ByteStringView& utf8Name,
tsepez4cf55152016-11-02 14:37:54 -0700249 CFXJSE_Value* pValue) {
dsinclair12a6b0c2016-05-26 11:14:08 -0700250 if (utf8Name.IsEmpty() || !pValue)
tsepez4cf55152016-11-02 14:37:54 -0700251 return false;
Tom Sepez33b42e42017-07-19 13:19:12 -0700252
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700253 v8::Isolate* pIsolate = GetIsolate();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700254 v8::Isolate::Scope isolate_scope(pIsolate);
255 v8::HandleScope handle_scope(pIsolate);
tsepezb4694242016-08-15 16:44:55 -0700256 v8::Local<v8::Context> context = NewLocalContext();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700257 v8::Context::Scope context_scope(context);
dsinclair12a6b0c2016-05-26 11:14:08 -0700258 v8::Local<v8::Value> propvalue =
259 v8::Local<v8::Value>::New(GetIsolate(), pValue->DirectGetValue());
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700260 context->Global()->Set(
Tom Sepez33b42e42017-07-19 13:19:12 -0700261 v8::String::NewFromUtf8(pIsolate, utf8Name.unterminated_c_str(),
262 v8::String::kNormalString, utf8Name.GetLength()),
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700263 propvalue);
tsepez4cf55152016-11-02 14:37:54 -0700264 return true;
Bo Xufdc00a72014-10-28 23:03:33 -0700265}
Tom Sepez51da0932015-11-25 16:05:49 -0800266#endif
Dan Sinclaire85107b2017-10-24 15:29:22 -0400267
268v8::Local<v8::Value> CJS_Runtime::MaybeCoerceToNumber(
dan sinclair80435cb2017-10-24 21:40:24 -0400269 v8::Local<v8::Value> value) {
Dan Sinclaire85107b2017-10-24 15:29:22 -0400270 bool bAllowNaN = false;
271 if (value->IsString()) {
272 ByteString bstr = ByteString::FromUnicode(ToWideString(value));
273 if (bstr.GetLength() == 0)
274 return value;
275 if (bstr == "NaN")
276 bAllowNaN = true;
277 }
278
279 v8::Isolate* pIsolate = GetIsolate();
280 v8::TryCatch try_catch(pIsolate);
281 v8::MaybeLocal<v8::Number> maybeNum =
282 value->ToNumber(pIsolate->GetCurrentContext());
283 if (maybeNum.IsEmpty())
284 return value;
285
286 v8::Local<v8::Number> num = maybeNum.ToLocalChecked();
287 if (std::isnan(num->Value()) && !bAllowNaN)
288 return value;
289
290 return num;
291}