1// 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
7#include "xfa/src/foxitlib.h"
8#include "fxv8.h"
9#include "value.h"
10#include "class.h"
11#include <math.h>
12#include "util_inline.h"
13FX_BOOL FXJSE_Value_IsUndefined(FXJSE_HVALUE hValue) {
14  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
15  return lpValue && lpValue->IsUndefined();
16}
17FX_BOOL FXJSE_Value_IsNull(FXJSE_HVALUE hValue) {
18  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
19  return lpValue && lpValue->IsNull();
20}
21FX_BOOL FXJSE_Value_IsBoolean(FXJSE_HVALUE hValue) {
22  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
23  return lpValue && lpValue->IsBoolean();
24}
25FX_BOOL FXJSE_Value_IsUTF8String(FXJSE_HVALUE hValue) {
26  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
27  return lpValue && lpValue->IsString();
28}
29FX_BOOL FXJSE_Value_IsNumber(FXJSE_HVALUE hValue) {
30  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
31  return lpValue && lpValue->IsNumber();
32}
33FX_BOOL FXJSE_Value_IsInteger(FXJSE_HVALUE hValue) {
34  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
35  return lpValue && lpValue->IsInteger();
36}
37FX_BOOL FXJSE_Value_IsObject(FXJSE_HVALUE hValue) {
38  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
39  return lpValue && lpValue->IsObject();
40}
41FX_BOOL FXJSE_Value_IsArray(FXJSE_HVALUE hValue) {
42  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
43  return lpValue && lpValue->IsArray();
44}
45FX_BOOL FXJSE_Value_IsFunction(FXJSE_HVALUE hValue) {
46  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
47  return lpValue && lpValue->IsFunction();
48}
49FX_BOOL FXJSE_Value_IsDate(FXJSE_HVALUE hValue) {
50  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
51  return lpValue && lpValue->IsDate();
52}
53FX_BOOL FXJSE_Value_ToBoolean(FXJSE_HVALUE hValue) {
54  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
55  ASSERT(lpValue);
56  return lpValue->ToBoolean();
57}
58FX_FLOAT FXJSE_Value_ToFloat(FXJSE_HVALUE hValue) {
59  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
60  ASSERT(lpValue);
61  return lpValue->ToFloat();
62}
63FXJSE_DOUBLE FXJSE_Value_ToDouble(FXJSE_HVALUE hValue) {
64  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
65  ASSERT(lpValue);
66  return lpValue->ToDouble();
67}
68void FXJSE_Value_ToUTF8String(FXJSE_HVALUE hValue,
69                              CFX_ByteString& szStrOutput) {
70  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
71  ASSERT(lpValue);
72  return lpValue->ToString(szStrOutput);
73}
74int32_t FXJSE_Value_ToInteger(FXJSE_HVALUE hValue) {
75  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
76  ASSERT(lpValue);
77  return lpValue->ToInteger();
78}
79void* FXJSE_Value_ToObject(FXJSE_HVALUE hValue, FXJSE_HCLASS hClass) {
80  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
81  CFXJSE_Class* lpClass = reinterpret_cast<CFXJSE_Class*>(hClass);
82  ASSERT(lpValue);
83  return lpValue->ToObject(lpClass);
84}
85void FXJSE_Value_SetUndefined(FXJSE_HVALUE hValue) {
86  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
87  ASSERT(lpValue);
88  return lpValue->SetUndefined();
89}
90void FXJSE_Value_SetNull(FXJSE_HVALUE hValue) {
91  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
92  ASSERT(lpValue);
93  return lpValue->SetNull();
94}
95void FXJSE_Value_SetBoolean(FXJSE_HVALUE hValue, FX_BOOL bBoolean) {
96  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
97  ASSERT(lpValue);
98  return lpValue->SetBoolean(bBoolean);
99}
100void FXJSE_Value_SetUTF8String(FXJSE_HVALUE hValue,
101                               const CFX_ByteStringC& szString) {
102  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
103  ASSERT(lpValue);
104  return lpValue->SetString(szString);
105}
106void FXJSE_Value_SetInteger(FXJSE_HVALUE hValue, int32_t nInteger) {
107  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
108  ASSERT(lpValue);
109  return lpValue->SetInteger(nInteger);
110}
111void FXJSE_Value_SetFloat(FXJSE_HVALUE hValue, FX_FLOAT fFloat) {
112  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
113  ASSERT(lpValue);
114  return lpValue->SetFloat(fFloat);
115}
116void FXJSE_Value_SetDouble(FXJSE_HVALUE hValue, FXJSE_DOUBLE dDouble) {
117  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
118  ASSERT(lpValue);
119  return lpValue->SetDouble(dDouble);
120}
121void FXJSE_Value_SetObject(FXJSE_HVALUE hValue,
122                           void* lpObject,
123                           FXJSE_HCLASS hClass) {
124  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
125  CFXJSE_Class* lpClass = reinterpret_cast<CFXJSE_Class*>(hClass);
126  if (lpClass == NULL) {
127    ASSERT(lpObject == NULL);
128    lpValue->SetJSObject();
129  } else if (lpClass != NULL) {
130    lpValue->SetHostObject(lpObject, lpClass);
131  }
132}
133void FXJSE_Value_SetArray(FXJSE_HVALUE hValue,
134                          uint32_t uValueCount,
135                          FXJSE_HVALUE* rgValues) {
136  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
137  return lpValue->SetArray(uValueCount,
138                           reinterpret_cast<CFXJSE_Value**>(rgValues));
139}
140void FXJSE_Value_SetDate(FXJSE_HVALUE hValue, FXJSE_DOUBLE dDouble) {
141  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
142  return lpValue->SetDate(dDouble);
143}
144void FXJSE_Value_Set(FXJSE_HVALUE hValue, FXJSE_HVALUE hOriginalValue) {
145  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
146  CFXJSE_Value* lpOriginalValue =
147      reinterpret_cast<CFXJSE_Value*>(hOriginalValue);
148  ASSERT(lpValue && lpOriginalValue);
149  return lpValue->Assign(lpOriginalValue);
150}
151FX_BOOL FXJSE_Value_GetObjectProp(FXJSE_HVALUE hValue,
152                                  const CFX_ByteStringC& szPropName,
153                                  FXJSE_HVALUE hPropValue) {
154  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
155  CFXJSE_Value* lpPropValue = reinterpret_cast<CFXJSE_Value*>(hPropValue);
156  ASSERT(lpValue && lpPropValue);
157  return lpValue->GetObjectProperty(szPropName, lpPropValue);
158}
159FX_BOOL FXJSE_Value_SetObjectProp(FXJSE_HVALUE hValue,
160                                  const CFX_ByteStringC& szPropName,
161                                  FXJSE_HVALUE hPropValue) {
162  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
163  CFXJSE_Value* lpPropValue = reinterpret_cast<CFXJSE_Value*>(hPropValue);
164  ASSERT(lpValue && lpPropValue);
165  return lpValue->SetObjectProperty(szPropName, lpPropValue);
166}
167FX_BOOL FXJSE_Value_GetObjectPropByIdx(FXJSE_HVALUE hValue,
168                                       uint32_t uPropIdx,
169                                       FXJSE_HVALUE hPropValue) {
170  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
171  CFXJSE_Value* lpPropValue = reinterpret_cast<CFXJSE_Value*>(hPropValue);
172  ASSERT(lpValue && lpPropValue);
173  return lpValue->GetObjectProperty(uPropIdx, lpPropValue);
174}
175FX_BOOL FXJSE_Value_SetObjectPropByIdx(FXJSE_HVALUE hValue,
176                                       uint32_t uPropIdx,
177                                       FXJSE_HVALUE hPropValue) {
178  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
179  CFXJSE_Value* lpPropValue = reinterpret_cast<CFXJSE_Value*>(hPropValue);
180  ASSERT(lpValue && lpPropValue);
181  return lpValue->SetObjectProperty(uPropIdx, lpPropValue);
182}
183FX_BOOL FXJSE_Value_DeleteObjectProp(FXJSE_HVALUE hValue,
184                                     const CFX_ByteStringC& szPropName) {
185  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
186  ASSERT(lpValue);
187  return lpValue->DeleteObjectProperty(szPropName);
188}
189FX_BOOL FXJSE_Value_ObjectHasOwnProp(FXJSE_HVALUE hValue,
190                                     const CFX_ByteStringC& szPropName,
191                                     FX_BOOL bUseTypeGetter) {
192  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
193  ASSERT(lpValue);
194  return lpValue->HasObjectOwnProperty(szPropName, bUseTypeGetter);
195}
196FX_BOOL FXJSE_Value_SetObjectOwnProp(FXJSE_HVALUE hValue,
197                                     const CFX_ByteStringC& szPropName,
198                                     FXJSE_HVALUE hPropValue) {
199  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
200  CFXJSE_Value* lpPropValue = reinterpret_cast<CFXJSE_Value*>(hPropValue);
201  ASSERT(lpValue && lpPropValue);
202  return lpValue->SetObjectOwnProperty(szPropName, lpPropValue);
203}
204FX_BOOL FXJSE_Value_SetFunctionBind(FXJSE_HVALUE hValue,
205                                    FXJSE_HVALUE hOldFunction,
206                                    FXJSE_HVALUE hNewThis) {
207  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
208  CFXJSE_Value* lpOldFunction = reinterpret_cast<CFXJSE_Value*>(hOldFunction);
209  CFXJSE_Value* lpNewThis = reinterpret_cast<CFXJSE_Value*>(hNewThis);
210  ASSERT(lpValue && lpOldFunction && lpNewThis);
211  return lpValue->SetFunctionBind(lpOldFunction, lpNewThis);
212}
213FX_BOOL FXJSE_Value_CallFunction(FXJSE_HVALUE hFunction,
214                                 FXJSE_HVALUE hThis,
215                                 FXJSE_HVALUE hRetValue,
216                                 uint32_t nArgCount,
217                                 FXJSE_HVALUE* lpArgs) {
218  CFXJSE_Value* lpFunction = reinterpret_cast<CFXJSE_Value*>(hFunction);
219  CFXJSE_Value* lpThis = reinterpret_cast<CFXJSE_Value*>(hThis);
220  CFXJSE_Value* lpRetValue = reinterpret_cast<CFXJSE_Value*>(hRetValue);
221  ASSERT(lpFunction);
222  return lpFunction->Call(lpThis, lpRetValue, nArgCount, lpArgs);
223}
224FXJSE_HVALUE FXJSE_Value_Create(FXJSE_HRUNTIME hRuntime) {
225  CFXJSE_Value* lpValue =
226      CFXJSE_Value::Create(reinterpret_cast<v8::Isolate*>(hRuntime));
227  ASSERT(lpValue);
228  return reinterpret_cast<FXJSE_HVALUE>(lpValue);
229}
230void FXJSE_Value_Release(FXJSE_HVALUE hValue) {
231  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
232  if (lpValue) {
233    delete lpValue;
234  }
235}
236FXJSE_HRUNTIME FXJSE_Value_GetRuntime(FXJSE_HVALUE hValue) {
237  CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hValue);
238  ASSERT(lpValue);
239  return reinterpret_cast<FXJSE_HRUNTIME>(lpValue->GetIsolate());
240}
241void FXJSE_ThrowMessage(const CFX_ByteStringC& utf8Name,
242                        const CFX_ByteStringC& utf8Message) {
243  v8::Isolate* pIsolate = v8::Isolate::GetCurrent();
244  ASSERT(pIsolate);
245  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
246  v8::Local<v8::String> hMessage = v8::String::NewFromUtf8(
247      pIsolate, utf8Message.GetCStr(), v8::String::kNormalString,
248      utf8Message.GetLength());
249  v8::Local<v8::Value> hError;
250  if (utf8Name == "RangeError") {
251    hError = v8::Exception::RangeError(hMessage);
252  } else if (utf8Name == "ReferenceError") {
253    hError = v8::Exception::ReferenceError(hMessage);
254  } else if (utf8Name == "SyntaxError") {
255    hError = v8::Exception::SyntaxError(hMessage);
256  } else if (utf8Name == "TypeError") {
257    hError = v8::Exception::TypeError(hMessage);
258  } else {
259    hError = v8::Exception::Error(hMessage);
260    if (utf8Name != "Error" && !utf8Name.IsEmpty()) {
261      hError.As<v8::Object>()->Set(
262          v8::String::NewFromUtf8(pIsolate, "name"),
263          v8::String::NewFromUtf8(pIsolate, utf8Name.GetCStr(),
264                                  v8::String::kNormalString,
265                                  utf8Name.GetLength()));
266    }
267  }
268  pIsolate->ThrowException(hError);
269}
270CFXJSE_Value* CFXJSE_Value::Create(v8::Isolate* pIsolate) {
271  return new CFXJSE_Value(pIsolate);
272}
273void* CFXJSE_Value::ToObject(CFXJSE_Class* lpClass) const {
274  ASSERT(!m_hValue.IsEmpty());
275  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
276  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
277  ASSERT(!hValue.IsEmpty());
278  if (!hValue->IsObject()) {
279    return NULL;
280  }
281  return FXJSE_RetrieveObjectBinding(hValue.As<v8::Object>(), lpClass);
282}
283V8_INLINE static double FXJSE_ftod(FX_FLOAT fNumber) {
284  if (sizeof(FX_FLOAT) != 4) {
285    ASSERT(FALSE);
286    return fNumber;
287  }
288  uint32_t nFloatBits = (uint32_t&)fNumber;
289  uint8_t nExponent = (uint8_t)(nFloatBits >> 16 >> 7);
290  if (nExponent == 0 || nExponent == 255) {
291    return fNumber;
292  }
293  int8_t nErrExp = nExponent - 127 - 23;
294  if (nErrExp >= 0) {
295    return fNumber;
296  }
297  double dwError = pow(2.0, nErrExp), dwErrorHalf = dwError / 2;
298  double dNumber = fNumber, dNumberAbs = fabs(fNumber);
299  double dNumberAbsMin = dNumberAbs - dwErrorHalf,
300         dNumberAbsMax = dNumberAbs + dwErrorHalf;
301  int32_t iErrPos = 0;
302  if (floor(dNumberAbsMin) == floor(dNumberAbsMax)) {
303    dNumberAbsMin = fmod(dNumberAbsMin, 1.0);
304    dNumberAbsMax = fmod(dNumberAbsMax, 1.0);
305    int32_t iErrPosMin = 1, iErrPosMax = 38;
306    do {
307      int32_t iMid = (iErrPosMin + iErrPosMax) / 2;
308      double dPow = pow(10.0, iMid);
309      if (floor(dNumberAbsMin * dPow) == floor(dNumberAbsMax * dPow)) {
310        iErrPosMin = iMid + 1;
311      } else {
312        iErrPosMax = iMid;
313      }
314    } while (iErrPosMin < iErrPosMax);
315    iErrPos = iErrPosMax;
316  }
317  double dPow = pow(10.0, iErrPos);
318  return fNumber < 0 ? ceil(dNumber * dPow - 0.5) / dPow
319                     : floor(dNumber * dPow + 0.5) / dPow;
320}
321void CFXJSE_Value::SetFloat(FX_FLOAT fFloat) {
322  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
323  v8::Local<v8::Value> hValue = v8::Number::New(m_pIsolate, FXJSE_ftod(fFloat));
324  m_hValue.Reset(m_pIsolate, hValue);
325}
326void CFXJSE_Value::SetHostObject(void* lpObject, CFXJSE_Class* lpClass) {
327  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
328  ASSERT(lpClass);
329  v8::Local<v8::FunctionTemplate> hClass =
330      v8::Local<v8::FunctionTemplate>::New(m_pIsolate, lpClass->m_hTemplate);
331  v8::Local<v8::Object> hObject = hClass->InstanceTemplate()->NewInstance();
332  FXJSE_UpdateObjectBinding(hObject, lpObject);
333  m_hValue.Reset(m_pIsolate, hObject);
334}
335void CFXJSE_Value::SetArray(uint32_t uValueCount, CFXJSE_Value** rgValues) {
336  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
337  v8::Local<v8::Array> hArrayObject = v8::Array::New(m_pIsolate, uValueCount);
338  if (rgValues) {
339    for (uint32_t i = 0; i < uValueCount; i++) {
340      if (rgValues[i]) {
341        hArrayObject->Set(i, v8::Local<v8::Value>::New(
342                                 m_pIsolate, rgValues[i]->DirectGetValue()));
343      }
344    }
345  }
346  m_hValue.Reset(m_pIsolate, hArrayObject);
347}
348void CFXJSE_Value::SetDate(FXJSE_DOUBLE dDouble) {
349  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
350  v8::Local<v8::Value> hDate = v8::Date::New(m_pIsolate, dDouble);
351  m_hValue.Reset(m_pIsolate, hDate);
352}
353FX_BOOL CFXJSE_Value::SetObjectProperty(const CFX_ByteStringC& szPropName,
354                                        CFXJSE_Value* lpPropValue) {
355  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
356  v8::Local<v8::Value> hObject =
357      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
358  if (!hObject->IsObject()) {
359    return FALSE;
360  }
361  v8::Local<v8::Value> hPropValue =
362      v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue());
363  return (FX_BOOL)hObject.As<v8::Object>()->Set(
364      v8::String::NewFromUtf8(m_pIsolate, szPropName.GetCStr(),
365                              v8::String::kNormalString,
366                              szPropName.GetLength()),
367      hPropValue);
368}
369FX_BOOL CFXJSE_Value::GetObjectProperty(const CFX_ByteStringC& szPropName,
370                                        CFXJSE_Value* lpPropValue) {
371  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
372  v8::Local<v8::Value> hObject =
373      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
374  if (!hObject->IsObject()) {
375    return FALSE;
376  }
377  v8::Local<v8::Value> hPropValue =
378      hObject.As<v8::Object>()->Get(v8::String::NewFromUtf8(
379          m_pIsolate, szPropName.GetCStr(), v8::String::kNormalString,
380          szPropName.GetLength()));
381  lpPropValue->ForceSetValue(hPropValue);
382  return TRUE;
383}
384FX_BOOL CFXJSE_Value::SetObjectProperty(uint32_t uPropIdx,
385                                        CFXJSE_Value* lpPropValue) {
386  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
387  v8::Local<v8::Value> hObject =
388      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
389  if (!hObject->IsObject()) {
390    return FALSE;
391  }
392  v8::Local<v8::Value> hPropValue =
393      v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue());
394  return (FX_BOOL)hObject.As<v8::Object>()->Set(uPropIdx, hPropValue);
395}
396FX_BOOL CFXJSE_Value::GetObjectProperty(uint32_t uPropIdx,
397                                        CFXJSE_Value* lpPropValue) {
398  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
399  v8::Local<v8::Value> hObject =
400      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
401  if (!hObject->IsObject()) {
402    return FALSE;
403  }
404  v8::Local<v8::Value> hPropValue = hObject.As<v8::Object>()->Get(uPropIdx);
405  lpPropValue->ForceSetValue(hPropValue);
406  return TRUE;
407}
408FX_BOOL CFXJSE_Value::DeleteObjectProperty(const CFX_ByteStringC& szPropName) {
409  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
410  v8::Local<v8::Value> hObject =
411      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
412  if (!hObject->IsObject()) {
413    return FALSE;
414  }
415  hObject.As<v8::Object>()->Delete(v8::String::NewFromUtf8(
416      m_pIsolate, szPropName.GetCStr(), v8::String::kNormalString,
417      szPropName.GetLength()));
418  return TRUE;
419}
420FX_BOOL CFXJSE_Value::HasObjectOwnProperty(const CFX_ByteStringC& szPropName,
421                                           FX_BOOL bUseTypeGetter) {
422  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
423  v8::Local<v8::Value> hObject =
424      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
425  if (!hObject->IsObject()) {
426    return FALSE;
427  }
428  v8::Local<v8::String> hKey = v8::String::NewFromUtf8(
429      m_pIsolate, szPropName.GetCStr(), v8::String::kNormalString,
430      szPropName.GetLength());
431  return hObject.As<v8::Object>()->HasRealNamedProperty(hKey) ||
432         (bUseTypeGetter && hObject.As<v8::Object>()->HasOwnProperty(hKey));
433}
434FX_BOOL CFXJSE_Value::SetObjectOwnProperty(const CFX_ByteStringC& szPropName,
435                                           CFXJSE_Value* lpPropValue) {
436  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
437  v8::Local<v8::Value> hObject =
438      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
439  if (!hObject->IsObject()) {
440    return FALSE;
441  }
442  v8::Local<v8::Value> hValue =
443      v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->m_hValue);
444  return hObject.As<v8::Object>()->ForceSet(
445      v8::String::NewFromUtf8(m_pIsolate, szPropName.GetCStr(),
446                              v8::String::kNormalString,
447                              szPropName.GetLength()),
448      hValue);
449}
450FX_BOOL CFXJSE_Value::SetFunctionBind(CFXJSE_Value* lpOldFunction,
451                                      CFXJSE_Value* lpNewThis) {
452  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
453  v8::Local<v8::Value> rgArgs[2];
454  v8::Local<v8::Value> hOldFunction =
455      v8::Local<v8::Value>::New(m_pIsolate, lpOldFunction->DirectGetValue());
456  if (hOldFunction.IsEmpty() || !hOldFunction->IsFunction()) {
457    return FALSE;
458  }
459  rgArgs[0] = hOldFunction;
460  v8::Local<v8::Value> hNewThis =
461      v8::Local<v8::Value>::New(m_pIsolate, lpNewThis->DirectGetValue());
462  if (hNewThis.IsEmpty()) {
463    return FALSE;
464  }
465  rgArgs[1] = hNewThis;
466  v8::Local<v8::String> hBinderFuncSource =
467      v8::String::NewFromUtf8(m_pIsolate,
468                              "(function (oldfunction, newthis) { return "
469                              "oldfunction.bind(newthis); })");
470  v8::Local<v8::Function> hBinderFunc =
471      v8::Script::Compile(hBinderFuncSource)->Run().As<v8::Function>();
472  v8::Local<v8::Value> hBoundFunction =
473      hBinderFunc->Call(m_pIsolate->GetCurrentContext()->Global(), 2, rgArgs);
474  if (hBoundFunction.IsEmpty() || !hBoundFunction->IsFunction()) {
475    return FALSE;
476  }
477  m_hValue.Reset(m_pIsolate, hBoundFunction);
478  return TRUE;
479}
480#define FXJSE_INVALID_PTR ((void*)(intptr_t)-1)
481FX_BOOL CFXJSE_Value::Call(CFXJSE_Value* lpReceiver,
482                           CFXJSE_Value* lpRetValue,
483                           uint32_t nArgCount,
484                           FXJSE_HVALUE* lpArgs) {
485  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
486  v8::Local<v8::Value> hFunctionValue =
487      v8::Local<v8::Value>::New(m_pIsolate, DirectGetValue());
488  v8::Local<v8::Object> hFunctionObject =
489      !hFunctionValue.IsEmpty() && hFunctionValue->IsObject()
490          ? hFunctionValue.As<v8::Object>()
491          : v8::Local<v8::Object>();
492  v8::TryCatch trycatch;
493  if (hFunctionObject.IsEmpty() || !hFunctionObject->IsCallable()) {
494    if (lpRetValue) {
495      lpRetValue->ForceSetValue(FXJSE_CreateReturnValue(m_pIsolate, trycatch));
496    }
497    return FALSE;
498  }
499  v8::Local<v8::Value> hReturnValue;
500  v8::Local<v8::Value>* lpLocalArgs = NULL;
501  if (nArgCount) {
502    lpLocalArgs = FX_Alloc(v8::Local<v8::Value>, nArgCount);
503    for (uint32_t i = 0; i < nArgCount; i++) {
504      new (lpLocalArgs + i) v8::Local<v8::Value>;
505      CFXJSE_Value* lpArg = (CFXJSE_Value*)lpArgs[i];
506      if (lpArg) {
507        lpLocalArgs[i] =
508            v8::Local<v8::Value>::New(m_pIsolate, lpArg->DirectGetValue());
509      }
510      if (lpLocalArgs[i].IsEmpty()) {
511        lpLocalArgs[i] = v8::Undefined(m_pIsolate);
512      }
513    }
514  }
515  FX_BOOL bRetValue = TRUE;
516  if (lpReceiver == FXJSE_INVALID_PTR) {
517    hReturnValue = hFunctionObject->CallAsConstructor(nArgCount, lpLocalArgs);
518  } else {
519    v8::Local<v8::Value> hReceiver;
520    if (lpReceiver) {
521      hReceiver =
522          v8::Local<v8::Value>::New(m_pIsolate, lpReceiver->DirectGetValue());
523    }
524    if (hReceiver.IsEmpty() || !hReceiver->IsObject()) {
525      hReceiver = v8::Object::New(m_pIsolate);
526    }
527    hReturnValue =
528        hFunctionObject->CallAsFunction(hReceiver, nArgCount, lpLocalArgs);
529  }
530  if (trycatch.HasCaught()) {
531    hReturnValue = FXJSE_CreateReturnValue(m_pIsolate, trycatch);
532    bRetValue = FALSE;
533  }
534  if (lpRetValue) {
535    lpRetValue->ForceSetValue(hReturnValue);
536  }
537  if (lpLocalArgs) {
538    for (uint32_t i = 0; i < nArgCount; i++) {
539      lpLocalArgs[i].~Local();
540    }
541    FX_Free(lpLocalArgs);
542  }
543  return bRetValue;
544}
545