Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfxjse_value.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
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/xfa/cfxjse_value.h"
8
9#include <math.h>
10
11#include "fxjs/fxv8.h"
12#include "fxjs/xfa/cfxjse_class.h"
13#include "fxjs/xfa/cfxjse_context.h"
14#include "fxjs/xfa/cfxjse_isolatetracker.h"
15#include "third_party/base/check.h"
16#include "v8/include/v8-container.h"
17#include "v8/include/v8-exception.h"
18#include "v8/include/v8-function.h"
19#include "v8/include/v8-local-handle.h"
20#include "v8/include/v8-primitive.h"
21#include "v8/include/v8-script.h"
22
23namespace {
24
25double ftod(float fNumber) {
26 static_assert(sizeof(float) == 4, "float of incorrect size");
27
28 uint32_t nFloatBits = (uint32_t&)fNumber;
29 uint8_t nExponent = (uint8_t)(nFloatBits >> 23);
30 if (nExponent == 0 || nExponent == 255)
31 return fNumber;
32
33 int8_t nErrExp = nExponent - 150;
34 if (nErrExp >= 0)
35 return fNumber;
36
37 double dwError = pow(2.0, nErrExp);
38 double dwErrorHalf = dwError / 2;
39 double dNumber = fNumber;
40 double dNumberAbs = fabs(fNumber);
41 double dNumberAbsMin = dNumberAbs - dwErrorHalf;
42 double dNumberAbsMax = dNumberAbs + dwErrorHalf;
43 int32_t iErrPos = 0;
44 if (floor(dNumberAbsMin) == floor(dNumberAbsMax)) {
45 dNumberAbsMin = fmod(dNumberAbsMin, 1.0);
46 dNumberAbsMax = fmod(dNumberAbsMax, 1.0);
47 int32_t iErrPosMin = 1;
48 int32_t iErrPosMax = 38;
49 do {
50 int32_t iMid = (iErrPosMin + iErrPosMax) / 2;
51 double dPow = pow(10.0, iMid);
52 if (floor(dNumberAbsMin * dPow) == floor(dNumberAbsMax * dPow)) {
53 iErrPosMin = iMid + 1;
54 } else {
55 iErrPosMax = iMid;
56 }
57 } while (iErrPosMin < iErrPosMax);
58 iErrPos = iErrPosMax;
59 }
60 double dPow = pow(10.0, iErrPos);
61 return fNumber < 0 ? ceil(dNumber * dPow - 0.5) / dPow
62 : floor(dNumber * dPow + 0.5) / dPow;
63}
64
65} // namespace
66
67void FXJSE_ThrowMessage(v8::Isolate* pIsolate, ByteStringView utf8Message) {
68 DCHECK(pIsolate);
70 v8::Local<v8::String> hMessage = fxv8::NewStringHelper(pIsolate, utf8Message);
71 v8::Local<v8::Value> hError = v8::Exception::Error(hMessage);
72 pIsolate->ThrowException(hError);
73}
74
75CFXJSE_Value::CFXJSE_Value() = default;
76
77CFXJSE_Value::CFXJSE_Value(v8::Isolate* pIsolate, v8::Local<v8::Value> value) {
78 ForceSetValue(pIsolate, value);
79}
80
81CFXJSE_Value::~CFXJSE_Value() = default;
82
83CFXJSE_HostObject* CFXJSE_Value::ToHostObject(v8::Isolate* pIsolate) const {
85 return CFXJSE_HostObject::FromV8(
86 v8::Local<v8::Value>::New(pIsolate, m_hValue));
87}
88
89void CFXJSE_Value::SetHostObject(v8::Isolate* pIsolate,
90 CFXJSE_HostObject* pObject,
91 CFXJSE_Class* pClass) {
93 m_hValue.Reset(pIsolate, pObject->NewBoundV8Object(
94 pIsolate, pClass->GetTemplate(pIsolate)));
95}
96
98 v8::Isolate* pIsolate,
99 const std::vector<std::unique_ptr<CFXJSE_Value>>& values) {
101 v8::LocalVector<v8::Value> local_values(pIsolate);
102 local_values.reserve(values.size());
103 for (auto& v : values) {
104 if (v->IsEmpty())
105 local_values.push_back(fxv8::NewUndefinedHelper(pIsolate));
106 else
107 local_values.push_back(v->GetValue(pIsolate));
108 }
109 v8::Local<v8::Array> hArrayObject =
110 v8::Array::New(pIsolate, local_values.data(), local_values.size());
111 m_hValue.Reset(pIsolate, hArrayObject);
112}
113
114void CFXJSE_Value::SetFloat(v8::Isolate* pIsolate, float fFloat) {
115 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
116 m_hValue.Reset(pIsolate, fxv8::NewNumberHelper(pIsolate, ftod(fFloat)));
117}
118
119bool CFXJSE_Value::SetObjectProperty(v8::Isolate* pIsolate,
120 ByteStringView szPropName,
121 CFXJSE_Value* pPropValue) {
122 if (pPropValue->IsEmpty())
123 return false;
124
126 v8::Local<v8::Value> hObject = GetValue(pIsolate);
127 if (!hObject->IsObject())
128 return false;
129
130 return fxv8::ReentrantPutObjectPropertyHelper(
131 pIsolate, hObject.As<v8::Object>(), szPropName,
132 pPropValue->GetValue(pIsolate));
133}
134
135bool CFXJSE_Value::GetObjectProperty(v8::Isolate* pIsolate,
136 ByteStringView szPropName,
137 CFXJSE_Value* pPropValue) {
139 v8::Local<v8::Value> hObject = GetValue(pIsolate);
140 if (!hObject->IsObject())
141 return false;
142
143 pPropValue->ForceSetValue(
144 pIsolate, fxv8::ReentrantGetObjectPropertyHelper(
145 pIsolate, hObject.As<v8::Object>(), szPropName));
146 return true;
147}
148
149bool CFXJSE_Value::GetObjectPropertyByIdx(v8::Isolate* pIsolate,
150 uint32_t uPropIdx,
151 CFXJSE_Value* pPropValue) {
153 v8::Local<v8::Value> hObject = GetValue(pIsolate);
154 if (!hObject->IsArray())
155 return false;
156
157 pPropValue->ForceSetValue(pIsolate,
158 fxv8::ReentrantGetArrayElementHelper(
159 pIsolate, hObject.As<v8::Array>(), uPropIdx));
160 return true;
161}
162
163void CFXJSE_Value::DeleteObjectProperty(v8::Isolate* pIsolate,
164 ByteStringView szPropName) {
166 v8::Local<v8::Value> hObject = v8::Local<v8::Value>::New(pIsolate, m_hValue);
167 if (hObject->IsObject()) {
168 fxv8::ReentrantDeleteObjectPropertyHelper(
169 pIsolate, hObject.As<v8::Object>(), szPropName);
170 }
171}
172
173bool CFXJSE_Value::SetObjectOwnProperty(v8::Isolate* pIsolate,
174 ByteStringView szPropName,
175 CFXJSE_Value* pPropValue) {
177 v8::Local<v8::Value> hObject = v8::Local<v8::Value>::New(pIsolate, m_hValue);
178 if (!hObject->IsObject())
179 return false;
180
181 v8::Local<v8::Value> pValue =
182 v8::Local<v8::Value>::New(pIsolate, pPropValue->m_hValue);
183 return fxv8::ReentrantSetObjectOwnPropertyHelper(
184 pIsolate, hObject.As<v8::Object>(), szPropName, pValue);
185}
186
187v8::Local<v8::Function> CFXJSE_Value::NewBoundFunction(
188 v8::Isolate* pIsolate,
189 v8::Local<v8::Function> hOldFunction,
190 v8::Local<v8::Object> hNewThis) {
191 DCHECK(!hOldFunction.IsEmpty());
192 DCHECK(!hNewThis.IsEmpty());
193
194 CFXJSE_ScopeUtil_RootContext scope(pIsolate);
195 v8::Local<v8::Value> rgArgs[2];
196 rgArgs[0] = hOldFunction;
197 rgArgs[1] = hNewThis;
198 v8::Local<v8::String> hBinderFuncSource = fxv8::NewStringHelper(
199 pIsolate, "(function (fn, obj) { return fn.bind(obj); })");
200 v8::Local<v8::Context> hContext = pIsolate->GetCurrentContext();
201 v8::Local<v8::Function> hBinderFunc =
202 v8::Script::Compile(hContext, hBinderFuncSource)
203 .ToLocalChecked()
204 ->Run(hContext)
205 .ToLocalChecked()
206 .As<v8::Function>();
207 v8::Local<v8::Value> hBoundFunction =
208 hBinderFunc->Call(hContext, hContext->Global(), 2, rgArgs)
209 .ToLocalChecked();
210 if (!fxv8::IsFunction(hBoundFunction))
211 return v8::Local<v8::Function>();
212
213 return hBoundFunction.As<v8::Function>();
214}
215
216v8::Local<v8::Value> CFXJSE_Value::GetValue(v8::Isolate* pIsolate) const {
217 return v8::Local<v8::Value>::New(pIsolate, m_hValue);
218}
219
220bool CFXJSE_Value::IsEmpty() const {
221 return m_hValue.IsEmpty();
222}
223
224bool CFXJSE_Value::IsUndefined(v8::Isolate* pIsolate) const {
225 if (IsEmpty())
226 return false;
227
228 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
229 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
230 return hValue->IsUndefined();
231}
232
233bool CFXJSE_Value::IsNull(v8::Isolate* pIsolate) const {
234 if (IsEmpty())
235 return false;
236
237 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
238 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
239 return hValue->IsNull();
240}
241
242bool CFXJSE_Value::IsBoolean(v8::Isolate* pIsolate) const {
243 if (IsEmpty())
244 return false;
245
246 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
247 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
248 return hValue->IsBoolean();
249}
250
251bool CFXJSE_Value::IsString(v8::Isolate* pIsolate) const {
252 if (IsEmpty())
253 return false;
254
255 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
256 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
257 return hValue->IsString();
258}
259
260bool CFXJSE_Value::IsNumber(v8::Isolate* pIsolate) const {
261 if (IsEmpty())
262 return false;
263
264 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
265 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
266 return hValue->IsNumber();
267}
268
269bool CFXJSE_Value::IsInteger(v8::Isolate* pIsolate) const {
270 if (IsEmpty())
271 return false;
272
273 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
274 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
275 return hValue->IsInt32();
276}
277
278bool CFXJSE_Value::IsObject(v8::Isolate* pIsolate) const {
279 if (IsEmpty())
280 return false;
281
282 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
283 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
284 return hValue->IsObject();
285}
286
287bool CFXJSE_Value::IsArray(v8::Isolate* pIsolate) const {
288 if (IsEmpty())
289 return false;
290
291 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
292 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
293 return hValue->IsArray();
294}
295
296bool CFXJSE_Value::IsFunction(v8::Isolate* pIsolate) const {
297 if (IsEmpty())
298 return false;
299
300 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
301 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
302 return hValue->IsFunction();
303}
304
305bool CFXJSE_Value::ToBoolean(v8::Isolate* pIsolate) const {
306 DCHECK(!IsEmpty());
308 return fxv8::ReentrantToBooleanHelper(
309 pIsolate, v8::Local<v8::Value>::New(pIsolate, m_hValue));
310}
311
312float CFXJSE_Value::ToFloat(v8::Isolate* pIsolate) const {
313 return static_cast<float>(ToDouble(pIsolate));
314}
315
316double CFXJSE_Value::ToDouble(v8::Isolate* pIsolate) const {
317 DCHECK(!IsEmpty());
319 return fxv8::ReentrantToDoubleHelper(
320 pIsolate, v8::Local<v8::Value>::New(pIsolate, m_hValue));
321}
322
323int32_t CFXJSE_Value::ToInteger(v8::Isolate* pIsolate) const {
324 DCHECK(!IsEmpty());
326 return fxv8::ReentrantToInt32Helper(
327 pIsolate, v8::Local<v8::Value>::New(pIsolate, m_hValue));
328}
329
330ByteString CFXJSE_Value::ToString(v8::Isolate* pIsolate) const {
331 DCHECK(!IsEmpty());
333 return fxv8::ReentrantToByteStringHelper(
334 pIsolate, v8::Local<v8::Value>::New(pIsolate, m_hValue));
335}
336
337void CFXJSE_Value::SetUndefined(v8::Isolate* pIsolate) {
338 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
339 m_hValue.Reset(pIsolate, fxv8::NewUndefinedHelper(pIsolate));
340}
341
342void CFXJSE_Value::SetNull(v8::Isolate* pIsolate) {
343 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
344 m_hValue.Reset(pIsolate, fxv8::NewNullHelper(pIsolate));
345}
346
347void CFXJSE_Value::SetBoolean(v8::Isolate* pIsolate, bool bBoolean) {
348 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
349 m_hValue.Reset(pIsolate, fxv8::NewBooleanHelper(pIsolate, bBoolean));
350}
351
352void CFXJSE_Value::SetInteger(v8::Isolate* pIsolate, int32_t nInteger) {
353 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
354 m_hValue.Reset(pIsolate, fxv8::NewNumberHelper(pIsolate, nInteger));
355}
356
357void CFXJSE_Value::SetDouble(v8::Isolate* pIsolate, double dDouble) {
358 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
359 m_hValue.Reset(pIsolate, fxv8::NewNumberHelper(pIsolate, dDouble));
360}
361
362void CFXJSE_Value::SetString(v8::Isolate* pIsolate, ByteStringView szString) {
363 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
364 m_hValue.Reset(pIsolate, fxv8::NewStringHelper(pIsolate, szString));
365}
void FXJSE_ThrowMessage(v8::Isolate *pIsolate, ByteStringView utf8Message)
bool IsBoolean(v8::Isolate *pIsolate) const
CFXJSE_Value(v8::Isolate *pIsolate, v8::Local< v8::Value > value)
void SetArray(v8::Isolate *pIsolate, const std::vector< std::unique_ptr< CFXJSE_Value > > &values)
CFXJSE_HostObject * ToHostObject(v8::Isolate *pIsolate) const
bool GetObjectProperty(v8::Isolate *pIsolate, ByteStringView szPropName, CFXJSE_Value *pPropValue)
bool SetObjectOwnProperty(v8::Isolate *pIsolate, ByteStringView szPropName, CFXJSE_Value *pPropValue)
bool IsString(v8::Isolate *pIsolate) const
bool IsArray(v8::Isolate *pIsolate) const
void SetInteger(v8::Isolate *pIsolate, int32_t nInteger)
bool GetObjectPropertyByIdx(v8::Isolate *pIsolate, uint32_t uPropIdx, CFXJSE_Value *pPropValue)
int32_t ToInteger(v8::Isolate *pIsolate) const
bool SetObjectProperty(v8::Isolate *pIsolate, ByteStringView szPropName, CFXJSE_Value *pPropValue)
bool IsFunction(v8::Isolate *pIsolate) const
bool IsUndefined(v8::Isolate *pIsolate) const
double ToDouble(v8::Isolate *pIsolate) const
bool IsObject(v8::Isolate *pIsolate) const
void SetDouble(v8::Isolate *pIsolate, double dDouble)
bool IsNull(v8::Isolate *pIsolate) const
void SetFloat(v8::Isolate *pIsolate, float fFloat)
void SetString(v8::Isolate *pIsolate, ByteStringView szString)
bool IsEmpty() const
ByteString ToString(v8::Isolate *pIsolate) const
void SetNull(v8::Isolate *pIsolate)
void DeleteObjectProperty(v8::Isolate *pIsolate, ByteStringView szPropName)
void SetHostObject(v8::Isolate *pIsolate, CFXJSE_HostObject *pObject, CFXJSE_Class *pClass)
float ToFloat(v8::Isolate *pIsolate) const
bool ToBoolean(v8::Isolate *pIsolate) const
void SetUndefined(v8::Isolate *pIsolate)
v8::Local< v8::Value > GetValue(v8::Isolate *pIsolate) const
bool IsInteger(v8::Isolate *pIsolate) const
void SetBoolean(v8::Isolate *pIsolate, bool bBoolean)
bool IsNumber(v8::Isolate *pIsolate) const