blob: 743169dd7b38984326bbd0e54281c403ad73d7ff [file] [log] [blame]
Dan Sinclair1770c022016-03-14 14:14:16 -04001// 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.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
dsinclair8bd9ce02016-06-09 13:24:34 -07007#include "fxjse/include/cfxjse_value.h"
Dan Sinclair1770c022016-03-14 14:14:16 -04008
9#include <math.h>
10
dsinclair8bd9ce02016-06-09 13:24:34 -070011#include "fxjse/context.h"
12#include "fxjse/include/cfxjse_class.h"
Dan Sinclair1770c022016-03-14 14:14:16 -040013
dsinclair4044d2d2016-06-13 12:38:29 -070014namespace {
15
16double FXJSE_ftod(FX_FLOAT fNumber) {
17 static_assert(sizeof(FX_FLOAT) == 4, "FX_FLOAT of incorrect size");
18
19 uint32_t nFloatBits = (uint32_t&)fNumber;
20 uint8_t nExponent = (uint8_t)(nFloatBits >> 23);
21 if (nExponent == 0 || nExponent == 255)
22 return fNumber;
23
24 int8_t nErrExp = nExponent - 150;
25 if (nErrExp >= 0)
26 return fNumber;
27
28 double dwError = pow(2.0, nErrExp), dwErrorHalf = dwError / 2;
29 double dNumber = fNumber, dNumberAbs = fabs(fNumber);
30 double dNumberAbsMin = dNumberAbs - dwErrorHalf,
31 dNumberAbsMax = dNumberAbs + dwErrorHalf;
32 int32_t iErrPos = 0;
33 if (floor(dNumberAbsMin) == floor(dNumberAbsMax)) {
34 dNumberAbsMin = fmod(dNumberAbsMin, 1.0);
35 dNumberAbsMax = fmod(dNumberAbsMax, 1.0);
36 int32_t iErrPosMin = 1, iErrPosMax = 38;
37 do {
38 int32_t iMid = (iErrPosMin + iErrPosMax) / 2;
39 double dPow = pow(10.0, iMid);
40 if (floor(dNumberAbsMin * dPow) == floor(dNumberAbsMax * dPow)) {
41 iErrPosMin = iMid + 1;
42 } else {
43 iErrPosMax = iMid;
44 }
45 } while (iErrPosMin < iErrPosMax);
46 iErrPos = iErrPosMax;
47 }
48 double dPow = pow(10.0, iErrPos);
49 return fNumber < 0 ? ceil(dNumber * dPow - 0.5) / dPow
50 : floor(dNumber * dPow + 0.5) / dPow;
51}
52
53} // namespace
54
dsinclair769b1372016-06-08 13:12:41 -070055void FXJSE_ThrowMessage(const CFX_ByteStringC& utf8Message) {
Dan Sinclair1770c022016-03-14 14:14:16 -040056 v8::Isolate* pIsolate = v8::Isolate::GetCurrent();
57 ASSERT(pIsolate);
58
59 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
60 v8::Local<v8::String> hMessage = v8::String::NewFromUtf8(
dsinclair179bebb2016-04-05 11:02:18 -070061 pIsolate, utf8Message.c_str(), v8::String::kNormalString,
Dan Sinclair1770c022016-03-14 14:14:16 -040062 utf8Message.GetLength());
dsinclair769b1372016-06-08 13:12:41 -070063 v8::Local<v8::Value> hError = v8::Exception::Error(hMessage);
Dan Sinclair1770c022016-03-14 14:14:16 -040064 pIsolate->ThrowException(hError);
65}
66
dsinclair8f3074b2016-06-02 17:45:25 -070067CFXJSE_HostObject* CFXJSE_Value::ToHostObject(CFXJSE_Class* lpClass) const {
Dan Sinclair1770c022016-03-14 14:14:16 -040068 ASSERT(!m_hValue.IsEmpty());
69
70 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
dsinclair12a6b0c2016-05-26 11:14:08 -070071 v8::Local<v8::Value> pValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
72 ASSERT(!pValue.IsEmpty());
Dan Sinclair1770c022016-03-14 14:14:16 -040073
dsinclair12a6b0c2016-05-26 11:14:08 -070074 if (!pValue->IsObject())
Dan Sinclair1770c022016-03-14 14:14:16 -040075 return nullptr;
76
dsinclair12a6b0c2016-05-26 11:14:08 -070077 return FXJSE_RetrieveObjectBinding(pValue.As<v8::Object>(), lpClass);
Dan Sinclair1770c022016-03-14 14:14:16 -040078}
79
dsinclairf27aeec2016-06-07 19:36:18 -070080void CFXJSE_Value::SetObject(CFXJSE_HostObject* lpObject,
81 CFXJSE_Class* pClass) {
82 if (!pClass) {
83 ASSERT(!lpObject);
84 SetJSObject();
85 return;
Dan Sinclair1770c022016-03-14 14:14:16 -040086 }
dsinclairf27aeec2016-06-07 19:36:18 -070087 SetHostObject(lpObject, pClass);
Dan Sinclair1770c022016-03-14 14:14:16 -040088}
89
tsepez29adee72016-05-31 14:22:09 -070090void CFXJSE_Value::SetHostObject(CFXJSE_HostObject* lpObject,
91 CFXJSE_Class* lpClass) {
Dan Sinclair1770c022016-03-14 14:14:16 -040092 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
93 ASSERT(lpClass);
94 v8::Local<v8::FunctionTemplate> hClass =
95 v8::Local<v8::FunctionTemplate>::New(m_pIsolate, lpClass->m_hTemplate);
96 v8::Local<v8::Object> hObject = hClass->InstanceTemplate()->NewInstance();
97 FXJSE_UpdateObjectBinding(hObject, lpObject);
98 m_hValue.Reset(m_pIsolate, hObject);
99}
100
101void CFXJSE_Value::SetArray(uint32_t uValueCount, CFXJSE_Value** rgValues) {
102 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
103 v8::Local<v8::Array> hArrayObject = v8::Array::New(m_pIsolate, uValueCount);
104 if (rgValues) {
105 for (uint32_t i = 0; i < uValueCount; i++) {
106 if (rgValues[i]) {
107 hArrayObject->Set(i, v8::Local<v8::Value>::New(
108 m_pIsolate, rgValues[i]->DirectGetValue()));
109 }
110 }
111 }
112 m_hValue.Reset(m_pIsolate, hArrayObject);
113}
114
dsinclair04fd27b2016-03-30 12:59:04 -0700115void CFXJSE_Value::SetDate(double dDouble) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400116 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
117 v8::Local<v8::Value> hDate = v8::Date::New(m_pIsolate, dDouble);
118 m_hValue.Reset(m_pIsolate, hDate);
119}
120
dsinclair4044d2d2016-06-13 12:38:29 -0700121void CFXJSE_Value::SetFloat(FX_FLOAT fFloat) {
122 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
123 v8::Local<v8::Value> pValue = v8::Number::New(m_pIsolate, FXJSE_ftod(fFloat));
124 m_hValue.Reset(m_pIsolate, pValue);
125}
126
Dan Sinclair1770c022016-03-14 14:14:16 -0400127FX_BOOL CFXJSE_Value::SetObjectProperty(const CFX_ByteStringC& szPropName,
128 CFXJSE_Value* lpPropValue) {
dsinclairf27aeec2016-06-07 19:36:18 -0700129 ASSERT(lpPropValue);
Dan Sinclair1770c022016-03-14 14:14:16 -0400130 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
131 v8::Local<v8::Value> hObject =
132 v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
133 if (!hObject->IsObject())
134 return FALSE;
135
136 v8::Local<v8::Value> hPropValue =
137 v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue());
138 return (FX_BOOL)hObject.As<v8::Object>()->Set(
dsinclair179bebb2016-04-05 11:02:18 -0700139 v8::String::NewFromUtf8(m_pIsolate, szPropName.c_str(),
Dan Sinclair1770c022016-03-14 14:14:16 -0400140 v8::String::kNormalString,
141 szPropName.GetLength()),
142 hPropValue);
143}
144
145FX_BOOL CFXJSE_Value::GetObjectProperty(const CFX_ByteStringC& szPropName,
146 CFXJSE_Value* lpPropValue) {
dsinclairf27aeec2016-06-07 19:36:18 -0700147 ASSERT(lpPropValue);
Dan Sinclair1770c022016-03-14 14:14:16 -0400148 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
149 v8::Local<v8::Value> hObject =
150 v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
151 if (!hObject->IsObject())
152 return FALSE;
153
154 v8::Local<v8::Value> hPropValue =
155 hObject.As<v8::Object>()->Get(v8::String::NewFromUtf8(
dsinclair179bebb2016-04-05 11:02:18 -0700156 m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
Dan Sinclair1770c022016-03-14 14:14:16 -0400157 szPropName.GetLength()));
158 lpPropValue->ForceSetValue(hPropValue);
159 return TRUE;
160}
161
162FX_BOOL CFXJSE_Value::SetObjectProperty(uint32_t uPropIdx,
163 CFXJSE_Value* lpPropValue) {
164 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
165 v8::Local<v8::Value> hObject =
166 v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
167 if (!hObject->IsObject())
168 return FALSE;
169
170 v8::Local<v8::Value> hPropValue =
171 v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue());
172 return (FX_BOOL)hObject.As<v8::Object>()->Set(uPropIdx, hPropValue);
173}
174
dsinclairf27aeec2016-06-07 19:36:18 -0700175FX_BOOL CFXJSE_Value::GetObjectPropertyByIdx(uint32_t uPropIdx,
176 CFXJSE_Value* lpPropValue) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400177 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
178 v8::Local<v8::Value> hObject =
179 v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
180 if (!hObject->IsObject())
181 return FALSE;
182
183 v8::Local<v8::Value> hPropValue = hObject.As<v8::Object>()->Get(uPropIdx);
184 lpPropValue->ForceSetValue(hPropValue);
185 return TRUE;
186}
187
188FX_BOOL CFXJSE_Value::DeleteObjectProperty(const CFX_ByteStringC& szPropName) {
189 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
190 v8::Local<v8::Value> hObject =
191 v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
192 if (!hObject->IsObject())
193 return FALSE;
194
195 hObject.As<v8::Object>()->Delete(v8::String::NewFromUtf8(
dsinclair179bebb2016-04-05 11:02:18 -0700196 m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
Dan Sinclair1770c022016-03-14 14:14:16 -0400197 szPropName.GetLength()));
198 return TRUE;
199}
200
201FX_BOOL CFXJSE_Value::HasObjectOwnProperty(const CFX_ByteStringC& szPropName,
202 FX_BOOL bUseTypeGetter) {
203 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
204 v8::Local<v8::Value> hObject =
205 v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
206 if (!hObject->IsObject())
207 return FALSE;
208
209 v8::Local<v8::String> hKey = v8::String::NewFromUtf8(
dsinclair179bebb2016-04-05 11:02:18 -0700210 m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
Dan Sinclair1770c022016-03-14 14:14:16 -0400211 szPropName.GetLength());
212 return hObject.As<v8::Object>()->HasRealNamedProperty(hKey) ||
213 (bUseTypeGetter &&
214 hObject.As<v8::Object>()
215 ->HasOwnProperty(m_pIsolate->GetCurrentContext(), hKey)
216 .FromMaybe(false));
217}
218
219FX_BOOL CFXJSE_Value::SetObjectOwnProperty(const CFX_ByteStringC& szPropName,
220 CFXJSE_Value* lpPropValue) {
dsinclairf27aeec2016-06-07 19:36:18 -0700221 ASSERT(lpPropValue);
Dan Sinclair1770c022016-03-14 14:14:16 -0400222 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
223 v8::Local<v8::Value> hObject =
224 v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
225 if (!hObject->IsObject())
226 return FALSE;
227
dsinclair12a6b0c2016-05-26 11:14:08 -0700228 v8::Local<v8::Value> pValue =
Dan Sinclair1770c022016-03-14 14:14:16 -0400229 v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->m_hValue);
230 return hObject.As<v8::Object>()
231 ->DefineOwnProperty(
232 m_pIsolate->GetCurrentContext(),
dsinclair179bebb2016-04-05 11:02:18 -0700233 v8::String::NewFromUtf8(m_pIsolate, szPropName.c_str(),
Dan Sinclair1770c022016-03-14 14:14:16 -0400234 v8::String::kNormalString,
235 szPropName.GetLength()),
dsinclair12a6b0c2016-05-26 11:14:08 -0700236 pValue)
Dan Sinclair1770c022016-03-14 14:14:16 -0400237 .FromMaybe(false);
238}
239
240FX_BOOL CFXJSE_Value::SetFunctionBind(CFXJSE_Value* lpOldFunction,
241 CFXJSE_Value* lpNewThis) {
dsinclairf27aeec2016-06-07 19:36:18 -0700242 ASSERT(lpOldFunction && lpNewThis);
243
Dan Sinclair1770c022016-03-14 14:14:16 -0400244 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
245 v8::Local<v8::Value> rgArgs[2];
246 v8::Local<v8::Value> hOldFunction =
247 v8::Local<v8::Value>::New(m_pIsolate, lpOldFunction->DirectGetValue());
248 if (hOldFunction.IsEmpty() || !hOldFunction->IsFunction())
249 return FALSE;
250
251 rgArgs[0] = hOldFunction;
252 v8::Local<v8::Value> hNewThis =
253 v8::Local<v8::Value>::New(m_pIsolate, lpNewThis->DirectGetValue());
254 if (hNewThis.IsEmpty())
255 return FALSE;
256
257 rgArgs[1] = hNewThis;
258 v8::Local<v8::String> hBinderFuncSource =
259 v8::String::NewFromUtf8(m_pIsolate,
260 "(function (oldfunction, newthis) { return "
261 "oldfunction.bind(newthis); })");
262 v8::Local<v8::Function> hBinderFunc =
263 v8::Script::Compile(hBinderFuncSource)->Run().As<v8::Function>();
264 v8::Local<v8::Value> hBoundFunction =
265 hBinderFunc->Call(m_pIsolate->GetCurrentContext()->Global(), 2, rgArgs);
266 if (hBoundFunction.IsEmpty() || !hBoundFunction->IsFunction())
267 return FALSE;
268
269 m_hValue.Reset(m_pIsolate, hBoundFunction);
270 return TRUE;
271}
272
273#define FXJSE_INVALID_PTR ((void*)(intptr_t)-1)
274FX_BOOL CFXJSE_Value::Call(CFXJSE_Value* lpReceiver,
275 CFXJSE_Value* lpRetValue,
276 uint32_t nArgCount,
dsinclair12a6b0c2016-05-26 11:14:08 -0700277 CFXJSE_Value** lpArgs) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400278 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
279 v8::Local<v8::Value> hFunctionValue =
280 v8::Local<v8::Value>::New(m_pIsolate, DirectGetValue());
281 v8::Local<v8::Object> hFunctionObject =
282 !hFunctionValue.IsEmpty() && hFunctionValue->IsObject()
283 ? hFunctionValue.As<v8::Object>()
284 : v8::Local<v8::Object>();
285
286 v8::TryCatch trycatch(m_pIsolate);
287 if (hFunctionObject.IsEmpty() || !hFunctionObject->IsCallable()) {
288 if (lpRetValue)
289 lpRetValue->ForceSetValue(FXJSE_CreateReturnValue(m_pIsolate, trycatch));
290 return FALSE;
291 }
292
293 v8::Local<v8::Value> hReturnValue;
294 v8::Local<v8::Value>* lpLocalArgs = NULL;
295 if (nArgCount) {
296 lpLocalArgs = FX_Alloc(v8::Local<v8::Value>, nArgCount);
297 for (uint32_t i = 0; i < nArgCount; i++) {
298 new (lpLocalArgs + i) v8::Local<v8::Value>;
dsinclair12a6b0c2016-05-26 11:14:08 -0700299 CFXJSE_Value* lpArg = lpArgs[i];
Dan Sinclair1770c022016-03-14 14:14:16 -0400300 if (lpArg) {
301 lpLocalArgs[i] =
302 v8::Local<v8::Value>::New(m_pIsolate, lpArg->DirectGetValue());
303 }
304 if (lpLocalArgs[i].IsEmpty()) {
305 lpLocalArgs[i] = v8::Undefined(m_pIsolate);
306 }
307 }
308 }
309
310 FX_BOOL bRetValue = TRUE;
311 if (lpReceiver == FXJSE_INVALID_PTR) {
312 v8::MaybeLocal<v8::Value> maybe_retvalue =
313 hFunctionObject->CallAsConstructor(m_pIsolate->GetCurrentContext(),
314 nArgCount, lpLocalArgs);
315 hReturnValue = maybe_retvalue.FromMaybe(v8::Local<v8::Value>());
316 } else {
317 v8::Local<v8::Value> hReceiver;
318 if (lpReceiver) {
319 hReceiver =
320 v8::Local<v8::Value>::New(m_pIsolate, lpReceiver->DirectGetValue());
321 }
322 if (hReceiver.IsEmpty() || !hReceiver->IsObject())
323 hReceiver = v8::Object::New(m_pIsolate);
324
325 v8::MaybeLocal<v8::Value> maybe_retvalue = hFunctionObject->CallAsFunction(
326 m_pIsolate->GetCurrentContext(), hReceiver, nArgCount, lpLocalArgs);
327 hReturnValue = maybe_retvalue.FromMaybe(v8::Local<v8::Value>());
328 }
329
330 if (trycatch.HasCaught()) {
331 hReturnValue = FXJSE_CreateReturnValue(m_pIsolate, trycatch);
332 bRetValue = FALSE;
333 }
334
335 if (lpRetValue)
336 lpRetValue->ForceSetValue(hReturnValue);
337
338 if (lpLocalArgs) {
339 for (uint32_t i = 0; i < nArgCount; i++)
340 lpLocalArgs[i].~Local();
341 FX_Free(lpLocalArgs);
342 }
343 return bRetValue;
344}