1 // Copyright 2017 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 "fxjs/cjs_v8.h"
8
9 #ifdef PDF_ENABLE_XFA
10 #include "fxjs/cfxjse_context.h"
11 #include "xfa/fxfa/parser/cxfa_object.h"
12 #endif // PDF_ENABLE_XFA
13
CJS_V8(v8::Isolate * isolate)14 CJS_V8::CJS_V8(v8::Isolate* isolate) : m_isolate(isolate) {}
15
~CJS_V8()16 CJS_V8::~CJS_V8() {
17 m_V8PersistentContext.Reset();
18 }
19
GetObjectProperty(v8::Local<v8::Object> pObj,const WideString & wsPropertyName)20 v8::Local<v8::Value> CJS_V8::GetObjectProperty(
21 v8::Local<v8::Object> pObj,
22 const WideString& wsPropertyName) {
23 if (pObj.IsEmpty())
24 return v8::Local<v8::Value>();
25 v8::Local<v8::Value> val;
26 if (!pObj->Get(m_isolate->GetCurrentContext(),
27 NewString(wsPropertyName.AsStringView()))
28 .ToLocal(&val))
29 return v8::Local<v8::Value>();
30 return val;
31 }
32
GetObjectPropertyNames(v8::Local<v8::Object> pObj)33 std::vector<WideString> CJS_V8::GetObjectPropertyNames(
34 v8::Local<v8::Object> pObj) {
35 if (pObj.IsEmpty())
36 return std::vector<WideString>();
37
38 v8::Local<v8::Array> val;
39 v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
40 if (!pObj->GetPropertyNames(context).ToLocal(&val))
41 return std::vector<WideString>();
42
43 std::vector<WideString> result;
44 for (uint32_t i = 0; i < val->Length(); ++i) {
45 result.push_back(ToWideString(val->Get(context, i).ToLocalChecked()));
46 }
47
48 return result;
49 }
50
PutObjectProperty(v8::Local<v8::Object> pObj,const WideString & wsPropertyName,v8::Local<v8::Value> pPut)51 void CJS_V8::PutObjectProperty(v8::Local<v8::Object> pObj,
52 const WideString& wsPropertyName,
53 v8::Local<v8::Value> pPut) {
54 if (pObj.IsEmpty())
55 return;
56 pObj->Set(m_isolate->GetCurrentContext(),
57 NewString(wsPropertyName.AsStringView()), pPut)
58 .FromJust();
59 }
60
NewArray()61 v8::Local<v8::Array> CJS_V8::NewArray() {
62 return v8::Array::New(m_isolate);
63 }
64
PutArrayElement(v8::Local<v8::Array> pArray,unsigned index,v8::Local<v8::Value> pValue)65 unsigned CJS_V8::PutArrayElement(v8::Local<v8::Array> pArray,
66 unsigned index,
67 v8::Local<v8::Value> pValue) {
68 if (pArray.IsEmpty())
69 return 0;
70 if (pArray->Set(m_isolate->GetCurrentContext(), index, pValue).IsNothing())
71 return 0;
72 return 1;
73 }
74
GetArrayElement(v8::Local<v8::Array> pArray,unsigned index)75 v8::Local<v8::Value> CJS_V8::GetArrayElement(v8::Local<v8::Array> pArray,
76 unsigned index) {
77 if (pArray.IsEmpty())
78 return v8::Local<v8::Value>();
79 v8::Local<v8::Value> val;
80 if (!pArray->Get(m_isolate->GetCurrentContext(), index).ToLocal(&val))
81 return v8::Local<v8::Value>();
82 return val;
83 }
84
GetArrayLength(v8::Local<v8::Array> pArray)85 unsigned CJS_V8::GetArrayLength(v8::Local<v8::Array> pArray) {
86 if (pArray.IsEmpty())
87 return 0;
88 return pArray->Length();
89 }
90
NewLocalContext()91 v8::Local<v8::Context> CJS_V8::NewLocalContext() {
92 return v8::Local<v8::Context>::New(m_isolate, m_V8PersistentContext);
93 }
94
GetPersistentContext()95 v8::Local<v8::Context> CJS_V8::GetPersistentContext() {
96 return m_V8PersistentContext.Get(m_isolate);
97 }
98
NewNumber(int number)99 v8::Local<v8::Number> CJS_V8::NewNumber(int number) {
100 return v8::Int32::New(m_isolate, number);
101 }
102
NewNumber(double number)103 v8::Local<v8::Number> CJS_V8::NewNumber(double number) {
104 return v8::Number::New(m_isolate, number);
105 }
106
NewNumber(float number)107 v8::Local<v8::Number> CJS_V8::NewNumber(float number) {
108 return v8::Number::New(m_isolate, (float)number);
109 }
110
NewBoolean(bool b)111 v8::Local<v8::Boolean> CJS_V8::NewBoolean(bool b) {
112 return v8::Boolean::New(m_isolate, b);
113 }
114
NewString(const ByteStringView & str)115 v8::Local<v8::String> CJS_V8::NewString(const ByteStringView& str) {
116 v8::Isolate* pIsolate = m_isolate ? m_isolate : v8::Isolate::GetCurrent();
117 return v8::String::NewFromUtf8(pIsolate, str.unterminated_c_str(),
118 v8::NewStringType::kNormal, str.GetLength())
119 .ToLocalChecked();
120 }
121
NewString(const WideStringView & str)122 v8::Local<v8::String> CJS_V8::NewString(const WideStringView& str) {
123 // Conversion from pdfium's wchar_t wide-strings to v8's uint16_t
124 // wide-strings isn't handled by v8, so use UTF8 as a common
125 // intermediate format.
126 return NewString(FX_UTF8Encode(str).AsStringView());
127 }
128
NewNull()129 v8::Local<v8::Value> CJS_V8::NewNull() {
130 return v8::Null(m_isolate);
131 }
132
NewUndefined()133 v8::Local<v8::Value> CJS_V8::NewUndefined() {
134 return v8::Undefined(m_isolate);
135 }
136
NewDate(double d)137 v8::Local<v8::Date> CJS_V8::NewDate(double d) {
138 return v8::Date::New(m_isolate->GetCurrentContext(), d)
139 .ToLocalChecked()
140 .As<v8::Date>();
141 }
142
ToInt32(v8::Local<v8::Value> pValue)143 int CJS_V8::ToInt32(v8::Local<v8::Value> pValue) {
144 if (pValue.IsEmpty())
145 return 0;
146 v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
147 v8::MaybeLocal<v8::Int32> maybe_int32 = pValue->ToInt32(context);
148 if (maybe_int32.IsEmpty())
149 return 0;
150 return maybe_int32.ToLocalChecked()->Value();
151 }
152
ToBoolean(v8::Local<v8::Value> pValue)153 bool CJS_V8::ToBoolean(v8::Local<v8::Value> pValue) {
154 if (pValue.IsEmpty())
155 return false;
156 v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
157 v8::MaybeLocal<v8::Boolean> maybe_boolean = pValue->ToBoolean(context);
158 if (maybe_boolean.IsEmpty())
159 return false;
160 return maybe_boolean.ToLocalChecked()->Value();
161 }
162
ToDouble(v8::Local<v8::Value> pValue)163 double CJS_V8::ToDouble(v8::Local<v8::Value> pValue) {
164 if (pValue.IsEmpty())
165 return 0.0;
166 v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
167 v8::MaybeLocal<v8::Number> maybe_number = pValue->ToNumber(context);
168 if (maybe_number.IsEmpty())
169 return 0.0;
170 return maybe_number.ToLocalChecked()->Value();
171 }
172
ToWideString(v8::Local<v8::Value> pValue)173 WideString CJS_V8::ToWideString(v8::Local<v8::Value> pValue) {
174 if (pValue.IsEmpty())
175 return WideString();
176 v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
177 v8::MaybeLocal<v8::String> maybe_string = pValue->ToString(context);
178 if (maybe_string.IsEmpty())
179 return WideString();
180 v8::String::Utf8Value s(m_isolate, maybe_string.ToLocalChecked());
181 return WideString::FromUTF8(ByteStringView(*s, s.length()));
182 }
183
ToByteString(v8::Local<v8::Value> pValue)184 ByteString CJS_V8::ToByteString(v8::Local<v8::Value> pValue) {
185 if (pValue.IsEmpty())
186 return ByteString();
187 v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
188 v8::MaybeLocal<v8::String> maybe_string = pValue->ToString(context);
189 if (maybe_string.IsEmpty())
190 return ByteString();
191 v8::String::Utf8Value s(m_isolate, maybe_string.ToLocalChecked());
192 return ByteString(*s);
193 }
194
ToObject(v8::Local<v8::Value> pValue)195 v8::Local<v8::Object> CJS_V8::ToObject(v8::Local<v8::Value> pValue) {
196 if (pValue.IsEmpty() || !pValue->IsObject())
197 return v8::Local<v8::Object>();
198 v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
199 return pValue->ToObject(context).ToLocalChecked();
200 }
201
ToArray(v8::Local<v8::Value> pValue)202 v8::Local<v8::Array> CJS_V8::ToArray(v8::Local<v8::Value> pValue) {
203 if (pValue.IsEmpty() || !pValue->IsArray())
204 return v8::Local<v8::Array>();
205 v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
206 return v8::Local<v8::Array>::Cast(pValue->ToObject(context).ToLocalChecked());
207 }
208
SetConstArray(const WideString & name,v8::Local<v8::Array> array)209 void CJS_V8::SetConstArray(const WideString& name, v8::Local<v8::Array> array) {
210 m_ConstArrays[name] = v8::Global<v8::Array>(GetIsolate(), array);
211 }
212
GetConstArray(const WideString & name)213 v8::Local<v8::Array> CJS_V8::GetConstArray(const WideString& name) {
214 return v8::Local<v8::Array>::New(GetIsolate(), m_ConstArrays[name]);
215 }
216
217 #ifdef PDF_ENABLE_XFA
ToXFAObject(v8::Local<v8::Value> obj)218 CXFA_Object* CJS_V8::ToXFAObject(v8::Local<v8::Value> obj) {
219 ASSERT(!obj.IsEmpty());
220
221 if (!obj->IsObject())
222 return nullptr;
223
224 CFXJSE_HostObject* hostObj =
225 FXJSE_RetrieveObjectBinding(obj.As<v8::Object>(), nullptr);
226 if (!hostObj || hostObj->type() != CFXJSE_HostObject::kXFA)
227 return nullptr;
228 return static_cast<CXFA_Object*>(hostObj);
229 }
230
NewXFAObject(CXFA_Object * obj,v8::Global<v8::FunctionTemplate> & tmpl)231 v8::Local<v8::Value> CJS_V8::NewXFAObject(
232 CXFA_Object* obj,
233 v8::Global<v8::FunctionTemplate>& tmpl) {
234 v8::EscapableHandleScope scope(m_isolate);
235 v8::Local<v8::FunctionTemplate> klass =
236 v8::Local<v8::FunctionTemplate>::New(m_isolate, tmpl);
237 v8::Local<v8::Object> object = klass->InstanceTemplate()->NewInstance();
238 FXJSE_UpdateObjectBinding(object, obj);
239 return scope.Escape(object);
240 }
241 #endif // PDF_ENABLE_XFA
242