xref: /aosp_15_r20/external/pdfium/fxjs/cjs_runtime.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker 
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_runtime.h"
8*3ac0a46fSAndroid Build Coastguard Worker 
9*3ac0a46fSAndroid Build Coastguard Worker #include <math.h>
10*3ac0a46fSAndroid Build Coastguard Worker 
11*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
12*3ac0a46fSAndroid Build Coastguard Worker 
13*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cfx_globaldata.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_annot.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_app.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_border.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_color.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_console.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_display.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_document.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_event.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_event_context.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_field.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_font.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_global.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_globalarrays.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_globalconsts.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_highlight.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_icon.h"
31*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_object.h"
32*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_position.h"
33*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_publicmethods.h"
34*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_scalehow.h"
35*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_scalewhen.h"
36*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_style.h"
37*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_timerobj.h"
38*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_util.h"
39*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/cjs_zoomtype.h"
40*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/fxv8.h"
41*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/js_define.h"
42*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check_op.h"
43*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/v8-context.h"
44*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/v8-exception.h"
45*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/v8-isolate.h"
46*3ac0a46fSAndroid Build Coastguard Worker 
CJS_Runtime(CPDFSDK_FormFillEnvironment * pFormFillEnv)47*3ac0a46fSAndroid Build Coastguard Worker CJS_Runtime::CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv)
48*3ac0a46fSAndroid Build Coastguard Worker     : m_pFormFillEnv(pFormFillEnv) {
49*3ac0a46fSAndroid Build Coastguard Worker   v8::Isolate* pIsolate = nullptr;
50*3ac0a46fSAndroid Build Coastguard Worker   IPDF_JSPLATFORM* pPlatform = m_pFormFillEnv->GetFormFillInfo()->m_pJsPlatform;
51*3ac0a46fSAndroid Build Coastguard Worker   if (pPlatform->version <= 2) {
52*3ac0a46fSAndroid Build Coastguard Worker     // Backwards compatibility - JS now initialized earlier in more modern
53*3ac0a46fSAndroid Build Coastguard Worker     // JSPLATFORM versions.
54*3ac0a46fSAndroid Build Coastguard Worker     unsigned int embedderDataSlot = 0;
55*3ac0a46fSAndroid Build Coastguard Worker     v8::Isolate* pExternalIsolate = nullptr;
56*3ac0a46fSAndroid Build Coastguard Worker     if (pPlatform->version == 2) {
57*3ac0a46fSAndroid Build Coastguard Worker       pExternalIsolate = static_cast<v8::Isolate*>(pPlatform->m_isolate);
58*3ac0a46fSAndroid Build Coastguard Worker       embedderDataSlot = pPlatform->m_v8EmbedderSlot;
59*3ac0a46fSAndroid Build Coastguard Worker     }
60*3ac0a46fSAndroid Build Coastguard Worker     FXJS_Initialize(embedderDataSlot, pExternalIsolate);
61*3ac0a46fSAndroid Build Coastguard Worker   }
62*3ac0a46fSAndroid Build Coastguard Worker   m_isolateManaged = FXJS_GetIsolate(&pIsolate);
63*3ac0a46fSAndroid Build Coastguard Worker   SetIsolate(pIsolate);
64*3ac0a46fSAndroid Build Coastguard Worker 
65*3ac0a46fSAndroid Build Coastguard Worker   v8::Isolate::Scope isolate_scope(pIsolate);
66*3ac0a46fSAndroid Build Coastguard Worker   v8::HandleScope handle_scope(pIsolate);
67*3ac0a46fSAndroid Build Coastguard Worker   if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
68*3ac0a46fSAndroid Build Coastguard Worker     DefineJSObjects();
69*3ac0a46fSAndroid Build Coastguard Worker 
70*3ac0a46fSAndroid Build Coastguard Worker   ScopedEventContext pContext(this);
71*3ac0a46fSAndroid Build Coastguard Worker   InitializeEngine();
72*3ac0a46fSAndroid Build Coastguard Worker   SetFormFillEnvToDocument();
73*3ac0a46fSAndroid Build Coastguard Worker }
74*3ac0a46fSAndroid Build Coastguard Worker 
~CJS_Runtime()75*3ac0a46fSAndroid Build Coastguard Worker CJS_Runtime::~CJS_Runtime() {
76*3ac0a46fSAndroid Build Coastguard Worker   NotifyObservers();
77*3ac0a46fSAndroid Build Coastguard Worker   ReleaseEngine();
78*3ac0a46fSAndroid Build Coastguard Worker   if (m_isolateManaged)
79*3ac0a46fSAndroid Build Coastguard Worker     DisposeIsolate();
80*3ac0a46fSAndroid Build Coastguard Worker }
81*3ac0a46fSAndroid Build Coastguard Worker 
DefineJSObjects()82*3ac0a46fSAndroid Build Coastguard Worker void CJS_Runtime::DefineJSObjects() {
83*3ac0a46fSAndroid Build Coastguard Worker   v8::Isolate::Scope isolate_scope(GetIsolate());
84*3ac0a46fSAndroid Build Coastguard Worker   v8::HandleScope handle_scope(GetIsolate());
85*3ac0a46fSAndroid Build Coastguard Worker   v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
86*3ac0a46fSAndroid Build Coastguard Worker   v8::Context::Scope context_scope(context);
87*3ac0a46fSAndroid Build Coastguard Worker 
88*3ac0a46fSAndroid Build Coastguard Worker   // The call order determines the "ObjDefID" assigned to each class.
89*3ac0a46fSAndroid Build Coastguard Worker   // ObjDefIDs 0 - 2
90*3ac0a46fSAndroid Build Coastguard Worker   CJS_Border::DefineJSObjects(this);
91*3ac0a46fSAndroid Build Coastguard Worker   CJS_Display::DefineJSObjects(this);
92*3ac0a46fSAndroid Build Coastguard Worker   CJS_Font::DefineJSObjects(this);
93*3ac0a46fSAndroid Build Coastguard Worker 
94*3ac0a46fSAndroid Build Coastguard Worker   // ObjDefIDs 3 - 5
95*3ac0a46fSAndroid Build Coastguard Worker   CJS_Highlight::DefineJSObjects(this);
96*3ac0a46fSAndroid Build Coastguard Worker   CJS_Position::DefineJSObjects(this);
97*3ac0a46fSAndroid Build Coastguard Worker   CJS_ScaleHow::DefineJSObjects(this);
98*3ac0a46fSAndroid Build Coastguard Worker 
99*3ac0a46fSAndroid Build Coastguard Worker   // ObjDefIDs 6 - 8
100*3ac0a46fSAndroid Build Coastguard Worker   CJS_ScaleWhen::DefineJSObjects(this);
101*3ac0a46fSAndroid Build Coastguard Worker   CJS_Style::DefineJSObjects(this);
102*3ac0a46fSAndroid Build Coastguard Worker   CJS_Zoomtype::DefineJSObjects(this);
103*3ac0a46fSAndroid Build Coastguard Worker 
104*3ac0a46fSAndroid Build Coastguard Worker   // ObjDefIDs 9 - 11
105*3ac0a46fSAndroid Build Coastguard Worker   CJS_App::DefineJSObjects(this);
106*3ac0a46fSAndroid Build Coastguard Worker   CJS_Color::DefineJSObjects(this);
107*3ac0a46fSAndroid Build Coastguard Worker   CJS_Console::DefineJSObjects(this);
108*3ac0a46fSAndroid Build Coastguard Worker 
109*3ac0a46fSAndroid Build Coastguard Worker   // ObjDefIDs 12 - 14
110*3ac0a46fSAndroid Build Coastguard Worker   CJS_Document::DefineJSObjects(this);
111*3ac0a46fSAndroid Build Coastguard Worker   CJS_Event::DefineJSObjects(this);
112*3ac0a46fSAndroid Build Coastguard Worker   CJS_Field::DefineJSObjects(this);
113*3ac0a46fSAndroid Build Coastguard Worker 
114*3ac0a46fSAndroid Build Coastguard Worker   // ObjDefIDs 15 - 17
115*3ac0a46fSAndroid Build Coastguard Worker   CJS_Global::DefineJSObjects(this);
116*3ac0a46fSAndroid Build Coastguard Worker   CJS_Icon::DefineJSObjects(this);
117*3ac0a46fSAndroid Build Coastguard Worker   CJS_Util::DefineJSObjects(this);
118*3ac0a46fSAndroid Build Coastguard Worker 
119*3ac0a46fSAndroid Build Coastguard Worker   // ObjDefIDs 18 - 20 (these can't fail, return void).
120*3ac0a46fSAndroid Build Coastguard Worker   CJS_PublicMethods::DefineJSObjects(this);
121*3ac0a46fSAndroid Build Coastguard Worker   CJS_GlobalConsts::DefineJSObjects(this);
122*3ac0a46fSAndroid Build Coastguard Worker   CJS_GlobalArrays::DefineJSObjects(this);
123*3ac0a46fSAndroid Build Coastguard Worker 
124*3ac0a46fSAndroid Build Coastguard Worker   // ObjDefIDs 21 - 22.
125*3ac0a46fSAndroid Build Coastguard Worker   CJS_TimerObj::DefineJSObjects(this);
126*3ac0a46fSAndroid Build Coastguard Worker   CJS_Annot::DefineJSObjects(this);
127*3ac0a46fSAndroid Build Coastguard Worker }
128*3ac0a46fSAndroid Build Coastguard Worker 
NewEventContext()129*3ac0a46fSAndroid Build Coastguard Worker IJS_EventContext* CJS_Runtime::NewEventContext() {
130*3ac0a46fSAndroid Build Coastguard Worker   m_EventContextArray.push_back(std::make_unique<CJS_EventContext>(this));
131*3ac0a46fSAndroid Build Coastguard Worker   return m_EventContextArray.back().get();
132*3ac0a46fSAndroid Build Coastguard Worker }
133*3ac0a46fSAndroid Build Coastguard Worker 
ReleaseEventContext(IJS_EventContext * pContext)134*3ac0a46fSAndroid Build Coastguard Worker void CJS_Runtime::ReleaseEventContext(IJS_EventContext* pContext) {
135*3ac0a46fSAndroid Build Coastguard Worker   DCHECK_EQ(pContext, m_EventContextArray.back().get());
136*3ac0a46fSAndroid Build Coastguard Worker   m_EventContextArray.pop_back();
137*3ac0a46fSAndroid Build Coastguard Worker }
138*3ac0a46fSAndroid Build Coastguard Worker 
GetCurrentEventContext() const139*3ac0a46fSAndroid Build Coastguard Worker CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
140*3ac0a46fSAndroid Build Coastguard Worker   return m_EventContextArray.empty() ? nullptr
141*3ac0a46fSAndroid Build Coastguard Worker                                      : m_EventContextArray.back().get();
142*3ac0a46fSAndroid Build Coastguard Worker }
143*3ac0a46fSAndroid Build Coastguard Worker 
GetTimerHandler() const144*3ac0a46fSAndroid Build Coastguard Worker CFX_Timer::HandlerIface* CJS_Runtime::GetTimerHandler() const {
145*3ac0a46fSAndroid Build Coastguard Worker   return m_pFormFillEnv ? m_pFormFillEnv->GetTimerHandler() : nullptr;
146*3ac0a46fSAndroid Build Coastguard Worker }
147*3ac0a46fSAndroid Build Coastguard Worker 
SetFormFillEnvToDocument()148*3ac0a46fSAndroid Build Coastguard Worker void CJS_Runtime::SetFormFillEnvToDocument() {
149*3ac0a46fSAndroid Build Coastguard Worker   v8::Isolate::Scope isolate_scope(GetIsolate());
150*3ac0a46fSAndroid Build Coastguard Worker   v8::HandleScope handle_scope(GetIsolate());
151*3ac0a46fSAndroid Build Coastguard Worker   v8::Local<v8::Context> context = GetV8Context();
152*3ac0a46fSAndroid Build Coastguard Worker   v8::Context::Scope context_scope(context);
153*3ac0a46fSAndroid Build Coastguard Worker 
154*3ac0a46fSAndroid Build Coastguard Worker   v8::Local<v8::Object> pThis = GetThisObj();
155*3ac0a46fSAndroid Build Coastguard Worker   if (pThis.IsEmpty())
156*3ac0a46fSAndroid Build Coastguard Worker     return;
157*3ac0a46fSAndroid Build Coastguard Worker 
158*3ac0a46fSAndroid Build Coastguard Worker   auto pJSDocument = JSGetObject<CJS_Document>(GetIsolate(), pThis);
159*3ac0a46fSAndroid Build Coastguard Worker   if (!pJSDocument)
160*3ac0a46fSAndroid Build Coastguard Worker     return;
161*3ac0a46fSAndroid Build Coastguard Worker 
162*3ac0a46fSAndroid Build Coastguard Worker   pJSDocument->SetFormFillEnv(m_pFormFillEnv.Get());
163*3ac0a46fSAndroid Build Coastguard Worker }
164*3ac0a46fSAndroid Build Coastguard Worker 
GetFormFillEnv() const165*3ac0a46fSAndroid Build Coastguard Worker CPDFSDK_FormFillEnvironment* CJS_Runtime::GetFormFillEnv() const {
166*3ac0a46fSAndroid Build Coastguard Worker   return m_pFormFillEnv.Get();
167*3ac0a46fSAndroid Build Coastguard Worker }
168*3ac0a46fSAndroid Build Coastguard Worker 
ExecuteScript(const WideString & script)169*3ac0a46fSAndroid Build Coastguard Worker absl::optional<IJS_Runtime::JS_Error> CJS_Runtime::ExecuteScript(
170*3ac0a46fSAndroid Build Coastguard Worker     const WideString& script) {
171*3ac0a46fSAndroid Build Coastguard Worker   return Execute(script);
172*3ac0a46fSAndroid Build Coastguard Worker }
173*3ac0a46fSAndroid Build Coastguard Worker 
AddEventToSet(const FieldEvent & event)174*3ac0a46fSAndroid Build Coastguard Worker bool CJS_Runtime::AddEventToSet(const FieldEvent& event) {
175*3ac0a46fSAndroid Build Coastguard Worker   return m_FieldEventSet.insert(event).second;
176*3ac0a46fSAndroid Build Coastguard Worker }
177*3ac0a46fSAndroid Build Coastguard Worker 
RemoveEventFromSet(const FieldEvent & event)178*3ac0a46fSAndroid Build Coastguard Worker void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) {
179*3ac0a46fSAndroid Build Coastguard Worker   m_FieldEventSet.erase(event);
180*3ac0a46fSAndroid Build Coastguard Worker }
181*3ac0a46fSAndroid Build Coastguard Worker 
AsCJSRuntime()182*3ac0a46fSAndroid Build Coastguard Worker CJS_Runtime* CJS_Runtime::AsCJSRuntime() {
183*3ac0a46fSAndroid Build Coastguard Worker   return this;
184*3ac0a46fSAndroid Build Coastguard Worker }
185*3ac0a46fSAndroid Build Coastguard Worker 
GetValueByNameFromGlobalObject(ByteStringView utf8Name)186*3ac0a46fSAndroid Build Coastguard Worker v8::Local<v8::Value> CJS_Runtime::GetValueByNameFromGlobalObject(
187*3ac0a46fSAndroid Build Coastguard Worker     ByteStringView utf8Name) {
188*3ac0a46fSAndroid Build Coastguard Worker   v8::Isolate::Scope isolate_scope(GetIsolate());
189*3ac0a46fSAndroid Build Coastguard Worker   v8::Local<v8::Context> context = GetV8Context();
190*3ac0a46fSAndroid Build Coastguard Worker   v8::Context::Scope context_scope(context);
191*3ac0a46fSAndroid Build Coastguard Worker   v8::Local<v8::String> str = fxv8::NewStringHelper(GetIsolate(), utf8Name);
192*3ac0a46fSAndroid Build Coastguard Worker   v8::MaybeLocal<v8::Value> maybe_value = context->Global()->Get(context, str);
193*3ac0a46fSAndroid Build Coastguard Worker   if (maybe_value.IsEmpty())
194*3ac0a46fSAndroid Build Coastguard Worker     return v8::Local<v8::Value>();
195*3ac0a46fSAndroid Build Coastguard Worker   return maybe_value.ToLocalChecked();
196*3ac0a46fSAndroid Build Coastguard Worker }
197*3ac0a46fSAndroid Build Coastguard Worker 
SetValueByNameInGlobalObject(ByteStringView utf8Name,v8::Local<v8::Value> pValue)198*3ac0a46fSAndroid Build Coastguard Worker bool CJS_Runtime::SetValueByNameInGlobalObject(ByteStringView utf8Name,
199*3ac0a46fSAndroid Build Coastguard Worker                                                v8::Local<v8::Value> pValue) {
200*3ac0a46fSAndroid Build Coastguard Worker   if (utf8Name.IsEmpty() || pValue.IsEmpty())
201*3ac0a46fSAndroid Build Coastguard Worker     return false;
202*3ac0a46fSAndroid Build Coastguard Worker 
203*3ac0a46fSAndroid Build Coastguard Worker   v8::Isolate* pIsolate = GetIsolate();
204*3ac0a46fSAndroid Build Coastguard Worker   v8::Isolate::Scope isolate_scope(pIsolate);
205*3ac0a46fSAndroid Build Coastguard Worker   v8::Local<v8::Context> context = GetV8Context();
206*3ac0a46fSAndroid Build Coastguard Worker   v8::Context::Scope context_scope(context);
207*3ac0a46fSAndroid Build Coastguard Worker   v8::Local<v8::String> str = fxv8::NewStringHelper(pIsolate, utf8Name);
208*3ac0a46fSAndroid Build Coastguard Worker   v8::Maybe<bool> result = context->Global()->Set(context, str, pValue);
209*3ac0a46fSAndroid Build Coastguard Worker   return result.IsJust() && result.FromJust();
210*3ac0a46fSAndroid Build Coastguard Worker }
211*3ac0a46fSAndroid Build Coastguard Worker 
MaybeCoerceToNumber(v8::Local<v8::Value> value)212*3ac0a46fSAndroid Build Coastguard Worker v8::Local<v8::Value> CJS_Runtime::MaybeCoerceToNumber(
213*3ac0a46fSAndroid Build Coastguard Worker     v8::Local<v8::Value> value) {
214*3ac0a46fSAndroid Build Coastguard Worker   bool bAllowNaN = false;
215*3ac0a46fSAndroid Build Coastguard Worker   if (value->IsString()) {
216*3ac0a46fSAndroid Build Coastguard Worker     ByteString bstr = fxv8::ToByteString(GetIsolate(), value.As<v8::String>());
217*3ac0a46fSAndroid Build Coastguard Worker     if (bstr.IsEmpty())
218*3ac0a46fSAndroid Build Coastguard Worker       return value;
219*3ac0a46fSAndroid Build Coastguard Worker     if (bstr == "NaN")
220*3ac0a46fSAndroid Build Coastguard Worker       bAllowNaN = true;
221*3ac0a46fSAndroid Build Coastguard Worker   }
222*3ac0a46fSAndroid Build Coastguard Worker 
223*3ac0a46fSAndroid Build Coastguard Worker   v8::TryCatch try_catch(GetIsolate());
224*3ac0a46fSAndroid Build Coastguard Worker   v8::MaybeLocal<v8::Number> maybeNum =
225*3ac0a46fSAndroid Build Coastguard Worker       value->ToNumber(GetIsolate()->GetCurrentContext());
226*3ac0a46fSAndroid Build Coastguard Worker   if (maybeNum.IsEmpty())
227*3ac0a46fSAndroid Build Coastguard Worker     return value;
228*3ac0a46fSAndroid Build Coastguard Worker 
229*3ac0a46fSAndroid Build Coastguard Worker   v8::Local<v8::Number> num = maybeNum.ToLocalChecked();
230*3ac0a46fSAndroid Build Coastguard Worker   if (isnan(num->Value()) && !bAllowNaN)
231*3ac0a46fSAndroid Build Coastguard Worker     return value;
232*3ac0a46fSAndroid Build Coastguard Worker 
233*3ac0a46fSAndroid Build Coastguard Worker   return num;
234*3ac0a46fSAndroid Build Coastguard Worker }
235