summaryrefslogtreecommitdiff
path: root/fxjse
diff options
context:
space:
mode:
Diffstat (limited to 'fxjse')
-rw-r--r--fxjse/DEPS6
-rw-r--r--fxjse/class.cpp282
-rw-r--r--fxjse/context.cpp226
-rw-r--r--fxjse/context.h63
-rw-r--r--fxjse/dynprop.cpp223
-rw-r--r--fxjse/include/cfxjse_arguments.h38
-rw-r--r--fxjse/include/cfxjse_class.h44
-rw-r--r--fxjse/include/cfxjse_value.h284
-rw-r--r--fxjse/include/fxjse.h74
-rw-r--r--fxjse/runtime.cpp115
-rw-r--r--fxjse/runtime.h46
-rw-r--r--fxjse/scope_inline.h75
-rw-r--r--fxjse/value.cpp297
13 files changed, 1773 insertions, 0 deletions
diff --git a/fxjse/DEPS b/fxjse/DEPS
new file mode 100644
index 0000000000..18698e4ce4
--- /dev/null
+++ b/fxjse/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ '+core/fxcrt/include',
+ # TODO(dsinclair): Layering violation. FXJSE can't include FPDFSDK.
+ '+fpdfsdk/jsapi/include',
+ '+v8/include',
+]
diff --git a/fxjse/class.cpp b/fxjse/class.cpp
new file mode 100644
index 0000000000..bb133fba58
--- /dev/null
+++ b/fxjse/class.cpp
@@ -0,0 +1,282 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjse/include/cfxjse_class.h"
+
+#include "fxjse/context.h"
+#include "fxjse/include/cfxjse_arguments.h"
+#include "fxjse/include/cfxjse_value.h"
+#include "fxjse/scope_inline.h"
+
+static void FXJSE_V8ConstructorCallback_Wrapper(
+ const v8::FunctionCallbackInfo<v8::Value>& info);
+static void FXJSE_V8FunctionCallback_Wrapper(
+ const v8::FunctionCallbackInfo<v8::Value>& info);
+static void FXJSE_V8GetterCallback_Wrapper(
+ v8::Local<v8::String> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info);
+static void FXJSE_V8SetterCallback_Wrapper(
+ v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<void>& info);
+
+static void FXJSE_V8FunctionCallback_Wrapper(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ const FXJSE_FUNCTION_DESCRIPTOR* lpFunctionInfo =
+ static_cast<FXJSE_FUNCTION_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ if (!lpFunctionInfo) {
+ return;
+ }
+ CFX_ByteStringC szFunctionName(lpFunctionInfo->name);
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(info.This());
+ std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
+ CFXJSE_Arguments impl(&info, lpRetValue.get());
+ lpFunctionInfo->callbackProc(lpThisValue.get(), szFunctionName, impl);
+ if (!lpRetValue->DirectGetValue().IsEmpty()) {
+ info.GetReturnValue().Set(lpRetValue->DirectGetValue());
+ }
+}
+
+static void FXJSE_V8ClassGlobalConstructorCallback_Wrapper(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition =
+ static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ if (!lpClassDefinition) {
+ return;
+ }
+ CFX_ByteStringC szFunctionName(lpClassDefinition->name);
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(info.This());
+ std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
+ CFXJSE_Arguments impl(&info, lpRetValue.get());
+ lpClassDefinition->constructor(lpThisValue.get(), szFunctionName, impl);
+ if (!lpRetValue->DirectGetValue().IsEmpty()) {
+ info.GetReturnValue().Set(lpRetValue->DirectGetValue());
+ }
+}
+
+static void FXJSE_V8GetterCallback_Wrapper(
+ v8::Local<v8::String> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ const FXJSE_PROPERTY_DESCRIPTOR* lpPropertyInfo =
+ static_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ if (!lpPropertyInfo) {
+ return;
+ }
+ CFX_ByteStringC szPropertyName(lpPropertyInfo->name);
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ std::unique_ptr<CFXJSE_Value> lpPropValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(info.This());
+ lpPropertyInfo->getProc(lpThisValue.get(), szPropertyName, lpPropValue.get());
+ info.GetReturnValue().Set(lpPropValue->DirectGetValue());
+}
+
+static void FXJSE_V8SetterCallback_Wrapper(
+ v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<void>& info) {
+ const FXJSE_PROPERTY_DESCRIPTOR* lpPropertyInfo =
+ static_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ if (!lpPropertyInfo) {
+ return;
+ }
+ CFX_ByteStringC szPropertyName(lpPropertyInfo->name);
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ std::unique_ptr<CFXJSE_Value> lpPropValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(info.This());
+ lpPropValue->ForceSetValue(value);
+ lpPropertyInfo->setProc(lpThisValue.get(), szPropertyName, lpPropValue.get());
+}
+
+static void FXJSE_V8ConstructorCallback_Wrapper(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition =
+ static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ if (!lpClassDefinition) {
+ return;
+ }
+ ASSERT(info.This()->InternalFieldCount());
+ info.This()->SetAlignedPointerInInternalField(0, NULL);
+}
+
+v8::Isolate* CFXJSE_Arguments::GetRuntime() const {
+ return m_pRetValue->GetIsolate();
+}
+
+int32_t CFXJSE_Arguments::GetLength() const {
+ return m_pInfo->Length();
+}
+
+std::unique_ptr<CFXJSE_Value> CFXJSE_Arguments::GetValue(int32_t index) const {
+ std::unique_ptr<CFXJSE_Value> lpArgValue(
+ new CFXJSE_Value(v8::Isolate::GetCurrent()));
+ lpArgValue->ForceSetValue((*m_pInfo)[index]);
+ return lpArgValue;
+}
+
+FX_BOOL CFXJSE_Arguments::GetBoolean(int32_t index) const {
+ return (*m_pInfo)[index]->BooleanValue();
+}
+
+int32_t CFXJSE_Arguments::GetInt32(int32_t index) const {
+ return static_cast<int32_t>((*m_pInfo)[index]->NumberValue());
+}
+
+FX_FLOAT CFXJSE_Arguments::GetFloat(int32_t index) const {
+ return static_cast<FX_FLOAT>((*m_pInfo)[index]->NumberValue());
+}
+
+CFX_ByteString CFXJSE_Arguments::GetUTF8String(int32_t index) const {
+ v8::Local<v8::String> hString = (*m_pInfo)[index]->ToString();
+ v8::String::Utf8Value szStringVal(hString);
+ return CFX_ByteString(*szStringVal);
+}
+
+CFXJSE_HostObject* CFXJSE_Arguments::GetObject(int32_t index,
+ CFXJSE_Class* pClass) const {
+ v8::Local<v8::Value> hValue = (*m_pInfo)[index];
+ ASSERT(!hValue.IsEmpty());
+ if (!hValue->IsObject())
+ return nullptr;
+ return FXJSE_RetrieveObjectBinding(hValue.As<v8::Object>(), pClass);
+}
+
+CFXJSE_Value* CFXJSE_Arguments::GetReturnValue() {
+ return m_pRetValue;
+}
+
+static void FXJSE_Context_GlobalObjToString(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ if (!lpClass) {
+ return;
+ }
+ if (info.This() == info.Holder() && lpClass->name) {
+ CFX_ByteString szStringVal;
+ szStringVal.Format("[object %s]", lpClass->name);
+ info.GetReturnValue().Set(v8::String::NewFromUtf8(
+ info.GetIsolate(), szStringVal.c_str(), v8::String::kNormalString,
+ szStringVal.GetLength()));
+ } else {
+ v8::Local<v8::String> local_str =
+ info.This()
+ ->ObjectProtoToString(info.GetIsolate()->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::String>());
+ info.GetReturnValue().Set(local_str);
+ }
+}
+
+CFXJSE_Class* CFXJSE_Class::Create(
+ CFXJSE_Context* lpContext,
+ const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition,
+ FX_BOOL bIsJSGlobal) {
+ if (!lpContext || !lpClassDefinition) {
+ return NULL;
+ }
+ CFXJSE_Class* pClass =
+ GetClassFromContext(lpContext, lpClassDefinition->name);
+ if (pClass) {
+ return pClass;
+ }
+ v8::Isolate* pIsolate = lpContext->m_pIsolate;
+ pClass = new CFXJSE_Class(lpContext);
+ pClass->m_szClassName = lpClassDefinition->name;
+ pClass->m_lpClassDefinition = lpClassDefinition;
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
+ v8::Local<v8::FunctionTemplate> hFunctionTemplate = v8::FunctionTemplate::New(
+ pIsolate, bIsJSGlobal ? 0 : FXJSE_V8ConstructorCallback_Wrapper,
+ v8::External::New(
+ pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)));
+ hFunctionTemplate->SetClassName(
+ v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name));
+ hFunctionTemplate->InstanceTemplate()->SetInternalFieldCount(1);
+ v8::Local<v8::ObjectTemplate> hObjectTemplate =
+ hFunctionTemplate->InstanceTemplate();
+ SetUpNamedPropHandler(pIsolate, hObjectTemplate, lpClassDefinition);
+
+ if (lpClassDefinition->propNum) {
+ for (int32_t i = 0; i < lpClassDefinition->propNum; i++) {
+ hObjectTemplate->SetNativeDataProperty(
+ v8::String::NewFromUtf8(pIsolate,
+ lpClassDefinition->properties[i].name),
+ lpClassDefinition->properties[i].getProc
+ ? FXJSE_V8GetterCallback_Wrapper
+ : NULL,
+ lpClassDefinition->properties[i].setProc
+ ? FXJSE_V8SetterCallback_Wrapper
+ : NULL,
+ v8::External::New(pIsolate, const_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
+ lpClassDefinition->properties + i)),
+ static_cast<v8::PropertyAttribute>(v8::DontDelete));
+ }
+ }
+ if (lpClassDefinition->methNum) {
+ for (int32_t i = 0; i < lpClassDefinition->methNum; i++) {
+ hObjectTemplate->Set(
+ v8::String::NewFromUtf8(pIsolate, lpClassDefinition->methods[i].name),
+ v8::FunctionTemplate::New(
+ pIsolate, FXJSE_V8FunctionCallback_Wrapper,
+ v8::External::New(pIsolate,
+ const_cast<FXJSE_FUNCTION_DESCRIPTOR*>(
+ lpClassDefinition->methods + i))),
+ static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
+ }
+ }
+ if (lpClassDefinition->constructor) {
+ if (bIsJSGlobal) {
+ hObjectTemplate->Set(
+ v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name),
+ v8::FunctionTemplate::New(
+ pIsolate, FXJSE_V8ClassGlobalConstructorCallback_Wrapper,
+ v8::External::New(pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ lpClassDefinition))),
+ static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
+ } else {
+ v8::Local<v8::Context> hLocalContext =
+ v8::Local<v8::Context>::New(pIsolate, lpContext->m_hContext);
+ FXJSE_GetGlobalObjectFromContext(hLocalContext)
+ ->Set(v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name),
+ v8::Function::New(
+ pIsolate, FXJSE_V8ClassGlobalConstructorCallback_Wrapper,
+ v8::External::New(pIsolate,
+ const_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ lpClassDefinition))));
+ }
+ }
+ if (bIsJSGlobal) {
+ hObjectTemplate->Set(
+ v8::String::NewFromUtf8(pIsolate, "toString"),
+ v8::FunctionTemplate::New(
+ pIsolate, FXJSE_Context_GlobalObjToString,
+ v8::External::New(pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ lpClassDefinition))));
+ }
+ pClass->m_hTemplate.Reset(lpContext->m_pIsolate, hFunctionTemplate);
+ lpContext->m_rgClasses.push_back(std::unique_ptr<CFXJSE_Class>(pClass));
+ return pClass;
+}
+
+CFXJSE_Class* CFXJSE_Class::GetClassFromContext(CFXJSE_Context* pContext,
+ const CFX_ByteStringC& szName) {
+ for (const auto& pClass : pContext->m_rgClasses) {
+ if (pClass->m_szClassName == szName)
+ return pClass.get();
+ }
+ return nullptr;
+}
diff --git a/fxjse/context.cpp b/fxjse/context.cpp
new file mode 100644
index 0000000000..3ecc3e2321
--- /dev/null
+++ b/fxjse/context.cpp
@@ -0,0 +1,226 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjse/context.h"
+
+#include "fxjse/include/cfxjse_class.h"
+#include "fxjse/include/cfxjse_value.h"
+#include "fxjse/scope_inline.h"
+
+namespace {
+
+const FX_CHAR szCompatibleModeScript[] =
+ "(function(global, list) {\n"
+ " 'use strict';\n"
+ " var objname;\n"
+ " for (objname in list) {\n"
+ " var globalobj = global[objname];\n"
+ " if (globalobj) {\n"
+ " list[objname].forEach(function(name) {\n"
+ " if (!globalobj[name]) {\n"
+ " Object.defineProperty(globalobj, name, {\n"
+ " writable: true,\n"
+ " enumerable: false,\n"
+ " value: (function(obj) {\n"
+ " if (arguments.length === 0) {\n"
+ " throw new TypeError('missing argument 0 when calling "
+ " function ' + objname + '.' + name);\n"
+ " }\n"
+ " return globalobj.prototype[name].apply(obj, "
+ " Array.prototype.slice.call(arguments, 1));\n"
+ " })\n"
+ " });\n"
+ " }\n"
+ " });\n"
+ " }\n"
+ " }\n"
+ "}(this, {String: ['substr', 'toUpperCase']}));";
+
+} // namespace
+
+v8::Local<v8::Object> FXJSE_GetGlobalObjectFromContext(
+ const v8::Local<v8::Context>& hContext) {
+ return hContext->Global()->GetPrototype().As<v8::Object>();
+}
+
+void FXJSE_UpdateObjectBinding(v8::Local<v8::Object>& hObject,
+ CFXJSE_HostObject* lpNewBinding) {
+ ASSERT(!hObject.IsEmpty());
+ ASSERT(hObject->InternalFieldCount() > 0);
+ hObject->SetAlignedPointerInInternalField(0,
+ static_cast<void*>(lpNewBinding));
+}
+
+CFXJSE_HostObject* FXJSE_RetrieveObjectBinding(
+ const v8::Local<v8::Object>& hJSObject,
+ CFXJSE_Class* lpClass) {
+ ASSERT(!hJSObject.IsEmpty());
+ if (!hJSObject->IsObject()) {
+ return nullptr;
+ }
+ v8::Local<v8::Object> hObject = hJSObject;
+ if (hObject->InternalFieldCount() == 0) {
+ v8::Local<v8::Value> hProtoObject = hObject->GetPrototype();
+ if (hProtoObject.IsEmpty() || !hProtoObject->IsObject()) {
+ return nullptr;
+ }
+ hObject = hProtoObject.As<v8::Object>();
+ if (hObject->InternalFieldCount() == 0) {
+ return nullptr;
+ }
+ }
+ if (lpClass) {
+ v8::Local<v8::FunctionTemplate> hClass =
+ v8::Local<v8::FunctionTemplate>::New(
+ lpClass->GetContext()->GetRuntime(), lpClass->GetTemplate());
+ if (!hClass->HasInstance(hObject)) {
+ return nullptr;
+ }
+ }
+ return static_cast<CFXJSE_HostObject*>(
+ hObject->GetAlignedPointerFromInternalField(0));
+}
+
+v8::Local<v8::Object> FXJSE_CreateReturnValue(v8::Isolate* pIsolate,
+ v8::TryCatch& trycatch) {
+ v8::Local<v8::Object> hReturnValue = v8::Object::New(pIsolate);
+ if (trycatch.HasCaught()) {
+ v8::Local<v8::Value> hException = trycatch.Exception();
+ v8::Local<v8::Message> hMessage = trycatch.Message();
+ if (hException->IsObject()) {
+ v8::Local<v8::Value> hValue;
+ hValue = hException.As<v8::Object>()->Get(
+ v8::String::NewFromUtf8(pIsolate, "name"));
+ if (hValue->IsString() || hValue->IsStringObject()) {
+ hReturnValue->Set(0, hValue);
+ } else {
+ hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error"));
+ }
+ hValue = hException.As<v8::Object>()->Get(
+ v8::String::NewFromUtf8(pIsolate, "message"));
+ if (hValue->IsString() || hValue->IsStringObject()) {
+ hReturnValue->Set(1, hValue);
+ } else {
+ hReturnValue->Set(1, hMessage->Get());
+ }
+ } else {
+ hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error"));
+ hReturnValue->Set(1, hMessage->Get());
+ }
+ hReturnValue->Set(2, hException);
+ hReturnValue->Set(3, v8::Integer::New(pIsolate, hMessage->GetLineNumber()));
+ hReturnValue->Set(4, hMessage->GetSourceLine());
+ v8::Maybe<int32_t> maybe_int =
+ hMessage->GetStartColumn(pIsolate->GetCurrentContext());
+ hReturnValue->Set(5, v8::Integer::New(pIsolate, maybe_int.FromMaybe(0)));
+ maybe_int = hMessage->GetEndColumn(pIsolate->GetCurrentContext());
+ hReturnValue->Set(6, v8::Integer::New(pIsolate, maybe_int.FromMaybe(0)));
+ }
+ return hReturnValue;
+}
+
+CFXJSE_Context* CFXJSE_Context::Create(
+ v8::Isolate* pIsolate,
+ const FXJSE_CLASS_DESCRIPTOR* lpGlobalClass,
+ CFXJSE_HostObject* lpGlobalObject) {
+ CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
+ CFXJSE_Context* pContext = new CFXJSE_Context(pIsolate);
+ CFXJSE_Class* lpGlobalClassObj = NULL;
+ v8::Local<v8::ObjectTemplate> hObjectTemplate;
+ if (lpGlobalClass) {
+ lpGlobalClassObj = CFXJSE_Class::Create(pContext, lpGlobalClass, TRUE);
+ ASSERT(lpGlobalClassObj);
+ v8::Local<v8::FunctionTemplate> hFunctionTemplate =
+ v8::Local<v8::FunctionTemplate>::New(pIsolate,
+ lpGlobalClassObj->m_hTemplate);
+ hObjectTemplate = hFunctionTemplate->InstanceTemplate();
+ } else {
+ hObjectTemplate = v8::ObjectTemplate::New(pIsolate);
+ hObjectTemplate->SetInternalFieldCount(1);
+ }
+ v8::Local<v8::Context> hNewContext =
+ v8::Context::New(pIsolate, NULL, hObjectTemplate);
+ v8::Local<v8::Context> hRootContext = v8::Local<v8::Context>::New(
+ pIsolate, CFXJSE_RuntimeData::Get(pIsolate)->m_hRootContext);
+ hNewContext->SetSecurityToken(hRootContext->GetSecurityToken());
+ v8::Local<v8::Object> hGlobalObject =
+ FXJSE_GetGlobalObjectFromContext(hNewContext);
+ FXJSE_UpdateObjectBinding(hGlobalObject, lpGlobalObject);
+ pContext->m_hContext.Reset(pIsolate, hNewContext);
+ return pContext;
+}
+
+CFXJSE_Context::CFXJSE_Context(v8::Isolate* pIsolate) : m_pIsolate(pIsolate) {}
+
+CFXJSE_Context::~CFXJSE_Context() {}
+
+std::unique_ptr<CFXJSE_Value> CFXJSE_Context::GetGlobalObject() {
+ std::unique_ptr<CFXJSE_Value> pValue(new CFXJSE_Value(m_pIsolate));
+
+ CFXJSE_ScopeUtil_IsolateHandleContext scope(this);
+ v8::Local<v8::Context> hContext =
+ v8::Local<v8::Context>::New(m_pIsolate, m_hContext);
+ v8::Local<v8::Object> hGlobalObject = hContext->Global();
+ pValue->ForceSetValue(hGlobalObject);
+
+ return pValue;
+}
+
+void CFXJSE_Context::EnableCompatibleMode() {
+ ExecuteScript(szCompatibleModeScript, nullptr, nullptr);
+}
+
+FX_BOOL CFXJSE_Context::ExecuteScript(const FX_CHAR* szScript,
+ CFXJSE_Value* lpRetValue,
+ CFXJSE_Value* lpNewThisObject) {
+ CFXJSE_ScopeUtil_IsolateHandleContext scope(this);
+ v8::TryCatch trycatch(m_pIsolate);
+ v8::Local<v8::String> hScriptString =
+ v8::String::NewFromUtf8(m_pIsolate, szScript);
+ if (lpNewThisObject == NULL) {
+ v8::Local<v8::Script> hScript = v8::Script::Compile(hScriptString);
+ if (!trycatch.HasCaught()) {
+ v8::Local<v8::Value> hValue = hScript->Run();
+ if (!trycatch.HasCaught()) {
+ if (lpRetValue) {
+ lpRetValue->m_hValue.Reset(m_pIsolate, hValue);
+ }
+ return TRUE;
+ }
+ }
+ if (lpRetValue) {
+ lpRetValue->m_hValue.Reset(m_pIsolate,
+ FXJSE_CreateReturnValue(m_pIsolate, trycatch));
+ }
+ return FALSE;
+ } else {
+ v8::Local<v8::Value> hNewThis =
+ v8::Local<v8::Value>::New(m_pIsolate, lpNewThisObject->m_hValue);
+ ASSERT(!hNewThis.IsEmpty());
+ v8::Local<v8::Script> hWrapper =
+ v8::Script::Compile(v8::String::NewFromUtf8(
+ m_pIsolate, "(function () { return eval(arguments[0]); })"));
+ v8::Local<v8::Value> hWrapperValue = hWrapper->Run();
+ ASSERT(hWrapperValue->IsFunction());
+ v8::Local<v8::Function> hWrapperFn = hWrapperValue.As<v8::Function>();
+ if (!trycatch.HasCaught()) {
+ v8::Local<v8::Value> rgArgs[] = {hScriptString};
+ v8::Local<v8::Value> hValue =
+ hWrapperFn->Call(hNewThis.As<v8::Object>(), 1, rgArgs);
+ if (!trycatch.HasCaught()) {
+ if (lpRetValue) {
+ lpRetValue->m_hValue.Reset(m_pIsolate, hValue);
+ }
+ return TRUE;
+ }
+ }
+ if (lpRetValue) {
+ lpRetValue->m_hValue.Reset(m_pIsolate,
+ FXJSE_CreateReturnValue(m_pIsolate, trycatch));
+ }
+ return FALSE;
+ }
+}
diff --git a/fxjse/context.h b/fxjse/context.h
new file mode 100644
index 0000000000..91356a09b8
--- /dev/null
+++ b/fxjse/context.h
@@ -0,0 +1,63 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJSE_CONTEXT_H_
+#define FXJSE_CONTEXT_H_
+
+#include <memory>
+#include <vector>
+
+#include "core/fxcrt/include/fx_basic.h"
+#include "fxjse/include/fxjse.h"
+#include "v8/include/v8.h"
+
+class CFXJSE_Class;
+class CFXJSE_Value;
+struct FXJSE_CLASS_DESCRIPTOR;
+
+class CFXJSE_Context {
+ public:
+ static CFXJSE_Context* Create(
+ v8::Isolate* pIsolate,
+ const FXJSE_CLASS_DESCRIPTOR* lpGlobalClass = nullptr,
+ CFXJSE_HostObject* lpGlobalObject = nullptr);
+ ~CFXJSE_Context();
+
+ V8_INLINE v8::Isolate* GetRuntime(void) { return m_pIsolate; }
+ std::unique_ptr<CFXJSE_Value> GetGlobalObject();
+ void EnableCompatibleMode();
+ FX_BOOL ExecuteScript(const FX_CHAR* szScript,
+ CFXJSE_Value* lpRetValue,
+ CFXJSE_Value* lpNewThisObject = nullptr);
+
+ protected:
+ CFXJSE_Context();
+ CFXJSE_Context(const CFXJSE_Context&);
+ explicit CFXJSE_Context(v8::Isolate* pIsolate);
+ CFXJSE_Context& operator=(const CFXJSE_Context&);
+
+ v8::Global<v8::Context> m_hContext;
+ v8::Isolate* m_pIsolate;
+ std::vector<std::unique_ptr<CFXJSE_Class>> m_rgClasses;
+
+ friend class CFXJSE_Class;
+ friend class CFXJSE_ScopeUtil_IsolateHandleContext;
+};
+
+v8::Local<v8::Object> FXJSE_CreateReturnValue(v8::Isolate* pIsolate,
+ v8::TryCatch& trycatch);
+
+v8::Local<v8::Object> FXJSE_GetGlobalObjectFromContext(
+ const v8::Local<v8::Context>& hContext);
+
+void FXJSE_UpdateObjectBinding(v8::Local<v8::Object>& hObject,
+ CFXJSE_HostObject* lpNewBinding = nullptr);
+
+CFXJSE_HostObject* FXJSE_RetrieveObjectBinding(
+ const v8::Local<v8::Object>& hJSObject,
+ CFXJSE_Class* lpClass = nullptr);
+
+#endif // FXJSE_CONTEXT_H_
diff --git a/fxjse/dynprop.cpp b/fxjse/dynprop.cpp
new file mode 100644
index 0000000000..34f63f4338
--- /dev/null
+++ b/fxjse/dynprop.cpp
@@ -0,0 +1,223 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjse/include/cfxjse_arguments.h"
+#include "fxjse/include/cfxjse_class.h"
+#include "fxjse/include/cfxjse_value.h"
+
+static void FXJSE_DynPropGetterAdapter_MethodCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ v8::Local<v8::Object> hCallBackInfo = info.Data().As<v8::Object>();
+ FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ hCallBackInfo->GetAlignedPointerFromInternalField(0));
+ v8::Local<v8::String> hPropName =
+ hCallBackInfo->GetInternalField(1).As<v8::String>();
+ ASSERT(lpClass && !hPropName.IsEmpty());
+ v8::String::Utf8Value szPropName(hPropName);
+ CFX_ByteStringC szFxPropName = *szPropName;
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(info.This());
+ std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
+ CFXJSE_Arguments impl(&info, lpRetValue.get());
+ lpClass->dynMethodCall(lpThisValue.get(), szFxPropName, impl);
+ if (!lpRetValue->DirectGetValue().IsEmpty()) {
+ info.GetReturnValue().Set(lpRetValue->DirectGetValue());
+ }
+}
+
+static void FXJSE_DynPropGetterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
+ CFXJSE_Value* pObject,
+ const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* pValue) {
+ ASSERT(lpClass);
+ int32_t nPropType =
+ lpClass->dynPropTypeGetter == nullptr
+ ? FXJSE_ClassPropType_Property
+ : lpClass->dynPropTypeGetter(pObject, szPropName, FALSE);
+ if (nPropType == FXJSE_ClassPropType_Property) {
+ if (lpClass->dynPropGetter) {
+ lpClass->dynPropGetter(pObject, szPropName, pValue);
+ }
+ } else if (nPropType == FXJSE_ClassPropType_Method) {
+ if (lpClass->dynMethodCall && pValue) {
+ v8::Isolate* pIsolate = pValue->GetIsolate();
+ v8::HandleScope hscope(pIsolate);
+ v8::Local<v8::ObjectTemplate> hCallBackInfoTemplate =
+ v8::ObjectTemplate::New(pIsolate);
+ hCallBackInfoTemplate->SetInternalFieldCount(2);
+ v8::Local<v8::Object> hCallBackInfo =
+ hCallBackInfoTemplate->NewInstance();
+ hCallBackInfo->SetAlignedPointerInInternalField(
+ 0, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClass));
+ hCallBackInfo->SetInternalField(
+ 1, v8::String::NewFromUtf8(
+ pIsolate, reinterpret_cast<const char*>(szPropName.raw_str()),
+ v8::String::kNormalString, szPropName.GetLength()));
+ pValue->ForceSetValue(v8::Function::New(
+ pValue->GetIsolate(), FXJSE_DynPropGetterAdapter_MethodCallback,
+ hCallBackInfo));
+ }
+ }
+}
+
+static void FXJSE_DynPropSetterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
+ CFXJSE_Value* pObject,
+ const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* pValue) {
+ ASSERT(lpClass);
+ int32_t nPropType =
+ lpClass->dynPropTypeGetter == nullptr
+ ? FXJSE_ClassPropType_Property
+ : lpClass->dynPropTypeGetter(pObject, szPropName, FALSE);
+ if (nPropType != FXJSE_ClassPropType_Method) {
+ if (lpClass->dynPropSetter) {
+ lpClass->dynPropSetter(pObject, szPropName, pValue);
+ }
+ }
+}
+
+static FX_BOOL FXJSE_DynPropQueryAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
+ CFXJSE_Value* pObject,
+ const CFX_ByteStringC& szPropName) {
+ ASSERT(lpClass);
+ int32_t nPropType =
+ lpClass->dynPropTypeGetter == nullptr
+ ? FXJSE_ClassPropType_Property
+ : lpClass->dynPropTypeGetter(pObject, szPropName, TRUE);
+ return nPropType != FXJSE_ClassPropType_None;
+}
+
+static FX_BOOL FXJSE_DynPropDeleterAdapter(
+ const FXJSE_CLASS_DESCRIPTOR* lpClass,
+ CFXJSE_Value* pObject,
+ const CFX_ByteStringC& szPropName) {
+ ASSERT(lpClass);
+ int32_t nPropType =
+ lpClass->dynPropTypeGetter == nullptr
+ ? FXJSE_ClassPropType_Property
+ : lpClass->dynPropTypeGetter(pObject, szPropName, FALSE);
+ if (nPropType != FXJSE_ClassPropType_Method) {
+ if (lpClass->dynPropDeleter) {
+ return lpClass->dynPropDeleter(pObject, szPropName);
+ } else {
+ return nPropType == FXJSE_ClassPropType_Property ? FALSE : TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void FXJSE_V8_GenericNamedPropertyQueryCallback(
+ v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Integer>& info) {
+ v8::Local<v8::Object> thisObject = info.This();
+ const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ v8::Isolate* pIsolate = info.GetIsolate();
+ v8::HandleScope scope(pIsolate);
+ v8::String::Utf8Value szPropName(property);
+ CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(thisObject);
+ if (FXJSE_DynPropQueryAdapter(lpClass, lpThisValue.get(), szFxPropName)) {
+ info.GetReturnValue().Set(v8::DontDelete);
+ } else {
+ const int32_t iV8Absent = 64;
+ info.GetReturnValue().Set(iV8Absent);
+ }
+}
+
+static void FXJSE_V8_GenericNamedPropertyDeleterCallback(
+ v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Boolean>& info) {
+ v8::Local<v8::Object> thisObject = info.This();
+ const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ v8::Isolate* pIsolate = info.GetIsolate();
+ v8::HandleScope scope(pIsolate);
+ v8::String::Utf8Value szPropName(property);
+ CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(thisObject);
+ info.GetReturnValue().Set(
+ !!FXJSE_DynPropDeleterAdapter(lpClass, lpThisValue.get(), szFxPropName));
+}
+
+static void FXJSE_V8_GenericNamedPropertyGetterCallback(
+ v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Local<v8::Object> thisObject = info.This();
+ const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ v8::String::Utf8Value szPropName(property);
+ CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(thisObject);
+ std::unique_ptr<CFXJSE_Value> lpNewValue(new CFXJSE_Value(info.GetIsolate()));
+ FXJSE_DynPropGetterAdapter(lpClass, lpThisValue.get(), szFxPropName,
+ lpNewValue.get());
+ info.GetReturnValue().Set(lpNewValue->DirectGetValue());
+}
+
+static void FXJSE_V8_GenericNamedPropertySetterCallback(
+ v8::Local<v8::Name> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Local<v8::Object> thisObject = info.This();
+ const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ v8::String::Utf8Value szPropName(property);
+ CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
+ std::unique_ptr<CFXJSE_Value> lpThisValue(
+ new CFXJSE_Value(info.GetIsolate()));
+ lpThisValue->ForceSetValue(thisObject);
+
+ CFXJSE_Value* lpNewValue = new CFXJSE_Value(info.GetIsolate());
+ lpNewValue->ForceSetValue(value);
+ FXJSE_DynPropSetterAdapter(lpClass, lpThisValue.get(), szFxPropName,
+ lpNewValue);
+ info.GetReturnValue().Set(value);
+}
+
+static void FXJSE_V8_GenericNamedPropertyEnumeratorCallback(
+ const v8::PropertyCallbackInfo<v8::Array>& info) {
+ const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+ info.Data().As<v8::External>()->Value());
+ v8::Isolate* pIsolate = info.GetIsolate();
+ v8::Local<v8::Array> newArray = v8::Array::New(pIsolate, lpClass->propNum);
+ for (int i = 0; i < lpClass->propNum; i++) {
+ newArray->Set(
+ i, v8::String::NewFromUtf8(pIsolate, lpClass->properties[i].name));
+ }
+ info.GetReturnValue().Set(newArray);
+}
+
+void CFXJSE_Class::SetUpNamedPropHandler(
+ v8::Isolate* pIsolate,
+ v8::Local<v8::ObjectTemplate>& hObjectTemplate,
+ const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition) {
+ v8::NamedPropertyHandlerConfiguration configuration(
+ lpClassDefinition->dynPropGetter
+ ? FXJSE_V8_GenericNamedPropertyGetterCallback
+ : 0,
+ lpClassDefinition->dynPropSetter
+ ? FXJSE_V8_GenericNamedPropertySetterCallback
+ : 0,
+ lpClassDefinition->dynPropTypeGetter
+ ? FXJSE_V8_GenericNamedPropertyQueryCallback
+ : 0,
+ lpClassDefinition->dynPropDeleter
+ ? FXJSE_V8_GenericNamedPropertyDeleterCallback
+ : 0,
+ FXJSE_V8_GenericNamedPropertyEnumeratorCallback,
+ v8::External::New(pIsolate,
+ const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)),
+ v8::PropertyHandlerFlags::kNonMasking);
+ hObjectTemplate->SetHandler(configuration);
+}
diff --git a/fxjse/include/cfxjse_arguments.h b/fxjse/include/cfxjse_arguments.h
new file mode 100644
index 0000000000..0f9bddaa87
--- /dev/null
+++ b/fxjse/include/cfxjse_arguments.h
@@ -0,0 +1,38 @@
+// Copyright 2016 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJSE_INCLUDE_CFXJSE_ARGUMENTS_H_
+#define FXJSE_INCLUDE_CFXJSE_ARGUMENTS_H_
+
+#include <memory>
+
+#include "fxjse/include/fxjse.h"
+
+class CFXJSE_Class;
+
+class CFXJSE_Arguments {
+ public:
+ CFXJSE_Arguments(const v8::FunctionCallbackInfo<v8::Value>* pInfo,
+ CFXJSE_Value* pRetValue)
+ : m_pInfo(pInfo), m_pRetValue(pRetValue) {}
+
+ v8::Isolate* GetRuntime() const;
+ int32_t GetLength() const;
+ std::unique_ptr<CFXJSE_Value> GetValue(int32_t index) const;
+ FX_BOOL GetBoolean(int32_t index) const;
+ int32_t GetInt32(int32_t index) const;
+ FX_FLOAT GetFloat(int32_t index) const;
+ CFX_ByteString GetUTF8String(int32_t index) const;
+ CFXJSE_HostObject* GetObject(int32_t index,
+ CFXJSE_Class* pClass = nullptr) const;
+ CFXJSE_Value* GetReturnValue();
+
+ private:
+ const v8::FunctionCallbackInfo<v8::Value>* m_pInfo;
+ CFXJSE_Value* m_pRetValue;
+};
+
+#endif // FXJSE_INCLUDE_CFXJSE_ARGUMENTS_H_
diff --git a/fxjse/include/cfxjse_class.h b/fxjse/include/cfxjse_class.h
new file mode 100644
index 0000000000..bb1db6d48c
--- /dev/null
+++ b/fxjse/include/cfxjse_class.h
@@ -0,0 +1,44 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJSE_INCLUDE_CFXJSE_CLASS_H_
+#define FXJSE_INCLUDE_CFXJSE_CLASS_H_
+
+#include "fxjse/include/cfxjse_arguments.h"
+#include "fxjse/include/fxjse.h"
+#include "v8/include/v8.h"
+
+class CFXJSE_Context;
+class CFXJSE_Value;
+
+class CFXJSE_Class {
+ public:
+ static CFXJSE_Class* Create(CFXJSE_Context* pContext,
+ const FXJSE_CLASS_DESCRIPTOR* lpClassDefintion,
+ FX_BOOL bIsJSGlobal = FALSE);
+ static CFXJSE_Class* GetClassFromContext(CFXJSE_Context* pContext,
+ const CFX_ByteStringC& szName);
+ static void SetUpNamedPropHandler(
+ v8::Isolate* pIsolate,
+ v8::Local<v8::ObjectTemplate>& hObjectTemplate,
+ const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition);
+
+ CFXJSE_Context* GetContext() { return m_pContext; }
+ v8::Global<v8::FunctionTemplate>& GetTemplate() { return m_hTemplate; }
+
+ protected:
+ explicit CFXJSE_Class(CFXJSE_Context* lpContext)
+ : m_lpClassDefinition(nullptr), m_pContext(lpContext) {}
+
+ CFX_ByteString m_szClassName;
+ const FXJSE_CLASS_DESCRIPTOR* m_lpClassDefinition;
+ CFXJSE_Context* m_pContext;
+ v8::Global<v8::FunctionTemplate> m_hTemplate;
+ friend class CFXJSE_Context;
+ friend class CFXJSE_Value;
+};
+
+#endif // FXJSE_INCLUDE_CFXJSE_CLASS_H_
diff --git a/fxjse/include/cfxjse_value.h b/fxjse/include/cfxjse_value.h
new file mode 100644
index 0000000000..e01f64cfff
--- /dev/null
+++ b/fxjse/include/cfxjse_value.h
@@ -0,0 +1,284 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJSE_INCLUDE_CFXJSE_VALUE_H_
+#define FXJSE_INCLUDE_CFXJSE_VALUE_H_
+
+#include "fxjse/scope_inline.h"
+
+V8_INLINE static double FXJSE_ftod(FX_FLOAT fNumber) {
+ if (sizeof(FX_FLOAT) != 4) {
+ ASSERT(FALSE);
+ return fNumber;
+ }
+
+ uint32_t nFloatBits = (uint32_t&)fNumber;
+ uint8_t nExponent = (uint8_t)(nFloatBits >> 16 >> 7);
+ if (nExponent == 0 || nExponent == 255)
+ return fNumber;
+
+ int8_t nErrExp = nExponent - 127 - 23;
+ if (nErrExp >= 0)
+ return fNumber;
+
+ double dwError = pow(2.0, nErrExp), dwErrorHalf = dwError / 2;
+ double dNumber = fNumber, dNumberAbs = fabs(fNumber);
+ double dNumberAbsMin = dNumberAbs - dwErrorHalf,
+ dNumberAbsMax = dNumberAbs + dwErrorHalf;
+ int32_t iErrPos = 0;
+ if (floor(dNumberAbsMin) == floor(dNumberAbsMax)) {
+ dNumberAbsMin = fmod(dNumberAbsMin, 1.0);
+ dNumberAbsMax = fmod(dNumberAbsMax, 1.0);
+ int32_t iErrPosMin = 1, iErrPosMax = 38;
+ do {
+ int32_t iMid = (iErrPosMin + iErrPosMax) / 2;
+ double dPow = pow(10.0, iMid);
+ if (floor(dNumberAbsMin * dPow) == floor(dNumberAbsMax * dPow)) {
+ iErrPosMin = iMid + 1;
+ } else {
+ iErrPosMax = iMid;
+ }
+ } while (iErrPosMin < iErrPosMax);
+ iErrPos = iErrPosMax;
+ }
+ double dPow = pow(10.0, iErrPos);
+ return fNumber < 0 ? ceil(dNumber * dPow - 0.5) / dPow
+ : floor(dNumber * dPow + 0.5) / dPow;
+}
+
+class CFXJSE_Value {
+ public:
+ CFXJSE_Value(v8::Isolate* pIsolate) : m_pIsolate(pIsolate) {}
+
+ V8_INLINE FX_BOOL IsUndefined() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsUndefined();
+ }
+ V8_INLINE FX_BOOL IsNull() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsNull();
+ }
+ V8_INLINE FX_BOOL IsBoolean() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsBoolean();
+ }
+ V8_INLINE FX_BOOL IsString() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsString();
+ }
+ V8_INLINE FX_BOOL IsNumber() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsNumber();
+ }
+ V8_INLINE FX_BOOL IsInteger() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsInt32();
+ }
+ V8_INLINE FX_BOOL IsObject() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsObject();
+ }
+ V8_INLINE FX_BOOL IsArray() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsArray();
+ }
+ V8_INLINE FX_BOOL IsFunction() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsFunction();
+ }
+ V8_INLINE FX_BOOL IsDate() const {
+ if (m_hValue.IsEmpty()) {
+ return FALSE;
+ }
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return hValue->IsDate();
+ }
+
+ V8_INLINE FX_BOOL ToBoolean() const {
+ ASSERT(!m_hValue.IsEmpty());
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return static_cast<FX_BOOL>(hValue->BooleanValue());
+ }
+ V8_INLINE FX_FLOAT ToFloat() const {
+ ASSERT(!m_hValue.IsEmpty());
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return static_cast<FX_FLOAT>(hValue->NumberValue());
+ }
+ V8_INLINE double ToDouble() const {
+ ASSERT(!m_hValue.IsEmpty());
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return static_cast<double>(hValue->NumberValue());
+ }
+ V8_INLINE int32_t ToInteger() const {
+ ASSERT(!m_hValue.IsEmpty());
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ return static_cast<int32_t>(hValue->NumberValue());
+ }
+ V8_INLINE CFX_ByteString ToString() const {
+ ASSERT(!m_hValue.IsEmpty());
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ v8::Local<v8::String> hString = hValue->ToString();
+ v8::String::Utf8Value hStringVal(hString);
+ return CFX_ByteString(*hStringVal);
+ }
+ V8_INLINE CFX_WideString ToWideString() const {
+ return CFX_WideString::FromUTF8(ToString().AsStringC());
+ }
+ CFXJSE_HostObject* ToHostObject(CFXJSE_Class* lpClass) const;
+
+ V8_INLINE void SetUndefined() {
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue = v8::Undefined(m_pIsolate);
+ m_hValue.Reset(m_pIsolate, hValue);
+ }
+ V8_INLINE void SetNull() {
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue = v8::Null(m_pIsolate);
+ m_hValue.Reset(m_pIsolate, hValue);
+ }
+ V8_INLINE void SetBoolean(FX_BOOL bBoolean) {
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue =
+ v8::Boolean::New(m_pIsolate, bBoolean != FALSE);
+ m_hValue.Reset(m_pIsolate, hValue);
+ }
+ V8_INLINE void SetInteger(int32_t nInteger) {
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue = v8::Integer::New(m_pIsolate, nInteger);
+ m_hValue.Reset(m_pIsolate, hValue);
+ }
+ V8_INLINE void SetDouble(double dDouble) {
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue = v8::Number::New(m_pIsolate, dDouble);
+ m_hValue.Reset(m_pIsolate, hValue);
+ }
+ V8_INLINE void SetString(const CFX_ByteStringC& szString) {
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> hValue = v8::String::NewFromUtf8(
+ m_pIsolate, reinterpret_cast<const char*>(szString.raw_str()),
+ v8::String::kNormalString, szString.GetLength());
+ m_hValue.Reset(m_pIsolate, hValue);
+ }
+ V8_INLINE void SetFloat(FX_FLOAT fFloat) {
+ CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+ v8::Local<v8::Value> pValue =
+ v8::Number::New(m_pIsolate, FXJSE_ftod(fFloat));
+ m_hValue.Reset(m_pIsolate, pValue);
+ }
+ V8_INLINE void SetJSObject() {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hValue = v8::Object::New(m_pIsolate);
+ m_hValue.Reset(m_pIsolate, hValue);
+ }
+
+ void SetObject(CFXJSE_HostObject* lpObject, CFXJSE_Class* pClass);
+ void SetHostObject(CFXJSE_HostObject* lpObject, CFXJSE_Class* lpClass);
+ void SetArray(uint32_t uValueCount, CFXJSE_Value** rgValues);
+ void SetDate(double dDouble);
+
+ FX_BOOL GetObjectProperty(const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* lpPropValue);
+ FX_BOOL SetObjectProperty(const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* lpPropValue);
+ FX_BOOL GetObjectPropertyByIdx(uint32_t uPropIdx, CFXJSE_Value* lpPropValue);
+ FX_BOOL SetObjectProperty(uint32_t uPropIdx, CFXJSE_Value* lpPropValue);
+ FX_BOOL DeleteObjectProperty(const CFX_ByteStringC& szPropName);
+ FX_BOOL HasObjectOwnProperty(const CFX_ByteStringC& szPropName,
+ FX_BOOL bUseTypeGetter);
+ FX_BOOL SetObjectOwnProperty(const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* lpPropValue);
+ FX_BOOL SetFunctionBind(CFXJSE_Value* lpOldFunction, CFXJSE_Value* lpNewThis);
+ FX_BOOL Call(CFXJSE_Value* lpReceiver,
+ CFXJSE_Value* lpRetValue,
+ uint32_t nArgCount,
+ CFXJSE_Value** lpArgs);
+
+ V8_INLINE v8::Isolate* GetIsolate() const { return m_pIsolate; }
+ V8_INLINE const v8::Global<v8::Value>& DirectGetValue() const {
+ return m_hValue;
+ }
+ V8_INLINE void ForceSetValue(v8::Local<v8::Value> hValue) {
+ m_hValue.Reset(m_pIsolate, hValue);
+ }
+ V8_INLINE void Assign(const CFXJSE_Value* lpValue) {
+ ASSERT(lpValue);
+ if (lpValue) {
+ m_hValue.Reset(m_pIsolate, lpValue->m_hValue);
+ } else {
+ m_hValue.Reset();
+ }
+ }
+
+ private:
+ friend class CFXJSE_Class;
+ friend class CFXJSE_Context;
+
+ CFXJSE_Value();
+ CFXJSE_Value(const CFXJSE_Value&);
+ CFXJSE_Value& operator=(const CFXJSE_Value&);
+
+ v8::Isolate* m_pIsolate;
+ v8::Global<v8::Value> m_hValue;
+};
+
+#endif // FXJSE_INCLUDE_CFXJSE_VALUE_H_
diff --git a/fxjse/include/fxjse.h b/fxjse/include/fxjse.h
new file mode 100644
index 0000000000..f9d6a67e02
--- /dev/null
+++ b/fxjse/include/fxjse.h
@@ -0,0 +1,74 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJSE_INCLUDE_FXJSE_H_
+#define FXJSE_INCLUDE_FXJSE_H_
+
+#include "core/fxcrt/include/fx_string.h"
+#include "core/fxcrt/include/fx_system.h"
+#include "v8/include/v8.h"
+
+class CFXJSE_Arguments;
+class CFXJSE_Value;
+
+// C++ object which can be wrapped by CFXJSE_value.
+class CFXJSE_HostObject {
+ public:
+ virtual ~CFXJSE_HostObject() {}
+};
+
+typedef void (*FXJSE_FuncCallback)(CFXJSE_Value* pThis,
+ const CFX_ByteStringC& szFuncName,
+ CFXJSE_Arguments& args);
+typedef void (*FXJSE_PropAccessor)(CFXJSE_Value* pObject,
+ const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* pValue);
+typedef int32_t (*FXJSE_PropTypeGetter)(CFXJSE_Value* pObject,
+ const CFX_ByteStringC& szPropName,
+ FX_BOOL bQueryIn);
+typedef FX_BOOL (*FXJSE_PropDeleter)(CFXJSE_Value* pObject,
+ const CFX_ByteStringC& szPropName);
+
+enum FXJSE_ClassPropTypes {
+ FXJSE_ClassPropType_None,
+ FXJSE_ClassPropType_Property,
+ FXJSE_ClassPropType_Method
+};
+
+struct FXJSE_FUNCTION_DESCRIPTOR {
+ const FX_CHAR* name;
+ FXJSE_FuncCallback callbackProc;
+};
+
+struct FXJSE_PROPERTY_DESCRIPTOR {
+ const FX_CHAR* name;
+ FXJSE_PropAccessor getProc;
+ FXJSE_PropAccessor setProc;
+};
+
+struct FXJSE_CLASS_DESCRIPTOR {
+ const FX_CHAR* name;
+ FXJSE_FuncCallback constructor;
+ const FXJSE_PROPERTY_DESCRIPTOR* properties;
+ const FXJSE_FUNCTION_DESCRIPTOR* methods;
+ int32_t propNum;
+ int32_t methNum;
+ FXJSE_PropTypeGetter dynPropTypeGetter;
+ FXJSE_PropAccessor dynPropGetter;
+ FXJSE_PropAccessor dynPropSetter;
+ FXJSE_PropDeleter dynPropDeleter;
+ FXJSE_FuncCallback dynMethodCall;
+};
+
+void FXJSE_Initialize();
+void FXJSE_Finalize();
+
+v8::Isolate* FXJSE_Runtime_Create_Own();
+void FXJSE_Runtime_Release(v8::Isolate* pIsolate);
+
+void FXJSE_ThrowMessage(const CFX_ByteStringC& utf8Message);
+
+#endif // FXJSE_INCLUDE_FXJSE_H_
diff --git a/fxjse/runtime.cpp b/fxjse/runtime.cpp
new file mode 100644
index 0000000000..bf171eef7e
--- /dev/null
+++ b/fxjse/runtime.cpp
@@ -0,0 +1,115 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjse/runtime.h"
+
+#include <algorithm>
+
+#include "fpdfsdk/jsapi/include/fxjs_v8.h"
+#include "fxjse/scope_inline.h"
+
+// Duplicates fpdfsdk's cjs_runtime.h, but keeps XFA from depending on it.
+// TODO(tsepez): make a single version of this.
+class FXJSE_ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+ void* Allocate(size_t length) override { return calloc(1, length); }
+ void* AllocateUninitialized(size_t length) override { return malloc(length); }
+ void Free(void* data, size_t length) override { free(data); }
+};
+
+static void FXJSE_KillV8() {
+ v8::V8::Dispose();
+}
+
+void FXJSE_Initialize() {
+ if (!CFXJSE_IsolateTracker::g_pInstance)
+ CFXJSE_IsolateTracker::g_pInstance = new CFXJSE_IsolateTracker;
+
+ static FX_BOOL bV8Initialized = FALSE;
+ if (bV8Initialized)
+ return;
+
+ bV8Initialized = TRUE;
+ atexit(FXJSE_KillV8);
+}
+
+static void FXJSE_Runtime_DisposeCallback(v8::Isolate* pIsolate, bool bOwned) {
+ if (FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate)) {
+ delete pData->m_pFXJSERuntimeData;
+ pData->m_pFXJSERuntimeData = nullptr;
+ }
+ if (bOwned)
+ pIsolate->Dispose();
+}
+
+void FXJSE_Finalize() {
+ if (!CFXJSE_IsolateTracker::g_pInstance)
+ return;
+
+ CFXJSE_IsolateTracker::g_pInstance->RemoveAll(FXJSE_Runtime_DisposeCallback);
+ delete CFXJSE_IsolateTracker::g_pInstance;
+ CFXJSE_IsolateTracker::g_pInstance = nullptr;
+}
+
+v8::Isolate* FXJSE_Runtime_Create_Own() {
+ v8::Isolate::CreateParams params;
+ params.array_buffer_allocator = new FXJSE_ArrayBufferAllocator();
+ v8::Isolate* pIsolate = v8::Isolate::New(params);
+ ASSERT(pIsolate && CFXJSE_IsolateTracker::g_pInstance);
+ CFXJSE_IsolateTracker::g_pInstance->Append(pIsolate);
+ return pIsolate;
+}
+
+void FXJSE_Runtime_Release(v8::Isolate* pIsolate) {
+ if (!pIsolate)
+ return;
+ CFXJSE_IsolateTracker::g_pInstance->Remove(pIsolate,
+ FXJSE_Runtime_DisposeCallback);
+}
+
+CFXJSE_RuntimeData* CFXJSE_RuntimeData::Create(v8::Isolate* pIsolate) {
+ CFXJSE_RuntimeData* pRuntimeData = new CFXJSE_RuntimeData(pIsolate);
+ CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
+ v8::Local<v8::FunctionTemplate> hFuncTemplate =
+ v8::FunctionTemplate::New(pIsolate);
+ v8::Local<v8::Context> hContext =
+ v8::Context::New(pIsolate, 0, hFuncTemplate->InstanceTemplate());
+ hContext->SetSecurityToken(v8::External::New(pIsolate, pIsolate));
+ pRuntimeData->m_hRootContextGlobalTemplate.Reset(pIsolate, hFuncTemplate);
+ pRuntimeData->m_hRootContext.Reset(pIsolate, hContext);
+ return pRuntimeData;
+}
+
+CFXJSE_RuntimeData* CFXJSE_RuntimeData::Get(v8::Isolate* pIsolate) {
+ FXJS_PerIsolateData::SetUp(pIsolate);
+ FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate);
+ if (!pData->m_pFXJSERuntimeData)
+ pData->m_pFXJSERuntimeData = CFXJSE_RuntimeData::Create(pIsolate);
+ return pData->m_pFXJSERuntimeData;
+}
+
+CFXJSE_IsolateTracker* CFXJSE_IsolateTracker::g_pInstance = nullptr;
+
+void CFXJSE_IsolateTracker::Append(v8::Isolate* pIsolate) {
+ m_OwnedIsolates.push_back(pIsolate);
+}
+
+void CFXJSE_IsolateTracker::Remove(
+ v8::Isolate* pIsolate,
+ CFXJSE_IsolateTracker::DisposeCallback lpfnDisposeCallback) {
+ auto it = std::find(m_OwnedIsolates.begin(), m_OwnedIsolates.end(), pIsolate);
+ bool bFound = it != m_OwnedIsolates.end();
+ if (bFound)
+ m_OwnedIsolates.erase(it);
+ lpfnDisposeCallback(pIsolate, bFound);
+}
+
+void CFXJSE_IsolateTracker::RemoveAll(
+ CFXJSE_IsolateTracker::DisposeCallback lpfnDisposeCallback) {
+ for (v8::Isolate* pIsolate : m_OwnedIsolates)
+ lpfnDisposeCallback(pIsolate, true);
+
+ m_OwnedIsolates.clear();
+}
diff --git a/fxjse/runtime.h b/fxjse/runtime.h
new file mode 100644
index 0000000000..e3b4113a50
--- /dev/null
+++ b/fxjse/runtime.h
@@ -0,0 +1,46 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJSE_RUNTIME_H_
+#define FXJSE_RUNTIME_H_
+
+#include <vector>
+
+#include "core/fxcrt/include/fx_basic.h"
+#include "v8/include/v8.h"
+
+class CFXJSE_RuntimeList;
+
+class CFXJSE_RuntimeData {
+ public:
+ static CFXJSE_RuntimeData* Get(v8::Isolate* pIsolate);
+
+ v8::Isolate* m_pIsolate;
+ v8::Global<v8::FunctionTemplate> m_hRootContextGlobalTemplate;
+ v8::Global<v8::Context> m_hRootContext;
+
+ protected:
+ static CFXJSE_RuntimeData* Create(v8::Isolate* pIsolate);
+ CFXJSE_RuntimeData(v8::Isolate* pIsolate) : m_pIsolate(pIsolate) {}
+ CFXJSE_RuntimeData();
+ CFXJSE_RuntimeData(const CFXJSE_RuntimeData&);
+ CFXJSE_RuntimeData& operator=(const CFXJSE_RuntimeData&);
+};
+
+class CFXJSE_IsolateTracker {
+ public:
+ typedef void (*DisposeCallback)(v8::Isolate*, bool bOwnedIsolate);
+ static CFXJSE_IsolateTracker* g_pInstance;
+
+ void Append(v8::Isolate* pIsolate);
+ void Remove(v8::Isolate* pIsolate, DisposeCallback lpfnDisposeCallback);
+ void RemoveAll(DisposeCallback lpfnDisposeCallback);
+
+ protected:
+ std::vector<v8::Isolate*> m_OwnedIsolates;
+};
+
+#endif // FXJSE_RUNTIME_H_
diff --git a/fxjse/scope_inline.h b/fxjse/scope_inline.h
new file mode 100644
index 0000000000..64eb6a79bf
--- /dev/null
+++ b/fxjse/scope_inline.h
@@ -0,0 +1,75 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJSE_SCOPE_INLINE_H_
+#define FXJSE_SCOPE_INLINE_H_
+
+#include "fxjse/context.h"
+#include "fxjse/runtime.h"
+
+class CFXJSE_ScopeUtil_IsolateHandle {
+ public:
+ explicit CFXJSE_ScopeUtil_IsolateHandle(v8::Isolate* pIsolate)
+ : m_isolate(pIsolate), m_iscope(pIsolate), m_hscope(pIsolate) {}
+ v8::Isolate* GetIsolate() { return m_isolate; }
+
+ private:
+ CFXJSE_ScopeUtil_IsolateHandle(const CFXJSE_ScopeUtil_IsolateHandle&) =
+ delete;
+ void operator=(const CFXJSE_ScopeUtil_IsolateHandle&) = delete;
+ void* operator new(size_t size) = delete;
+ void operator delete(void*, size_t) = delete;
+
+ v8::Isolate* m_isolate;
+ v8::Isolate::Scope m_iscope;
+ v8::HandleScope m_hscope;
+};
+
+class CFXJSE_ScopeUtil_IsolateHandleRootContext {
+ public:
+ explicit CFXJSE_ScopeUtil_IsolateHandleRootContext(v8::Isolate* pIsolate)
+ : m_parent(pIsolate),
+ m_cscope(v8::Local<v8::Context>::New(
+ pIsolate,
+ CFXJSE_RuntimeData::Get(pIsolate)->m_hRootContext)) {}
+
+ private:
+ CFXJSE_ScopeUtil_IsolateHandleRootContext(
+ const CFXJSE_ScopeUtil_IsolateHandleRootContext&) = delete;
+ void operator=(const CFXJSE_ScopeUtil_IsolateHandleRootContext&) = delete;
+ void* operator new(size_t size) = delete;
+ void operator delete(void*, size_t) = delete;
+
+ CFXJSE_ScopeUtil_IsolateHandle m_parent;
+ v8::Context::Scope m_cscope;
+};
+
+class CFXJSE_ScopeUtil_IsolateHandleContext {
+ public:
+ explicit CFXJSE_ScopeUtil_IsolateHandleContext(CFXJSE_Context* pContext)
+ : m_context(pContext),
+ m_parent(pContext->m_pIsolate),
+ m_cscope(v8::Local<v8::Context>::New(pContext->m_pIsolate,
+ pContext->m_hContext)) {}
+ v8::Isolate* GetIsolate() { return m_context->m_pIsolate; }
+ v8::Local<v8::Context> GetLocalContext() {
+ return v8::Local<v8::Context>::New(m_context->m_pIsolate,
+ m_context->m_hContext);
+ }
+
+ private:
+ CFXJSE_ScopeUtil_IsolateHandleContext(
+ const CFXJSE_ScopeUtil_IsolateHandleContext&) = delete;
+ void operator=(const CFXJSE_ScopeUtil_IsolateHandleContext&) = delete;
+ void* operator new(size_t size) = delete;
+ void operator delete(void*, size_t) = delete;
+
+ CFXJSE_Context* m_context;
+ CFXJSE_ScopeUtil_IsolateHandle m_parent;
+ v8::Context::Scope m_cscope;
+};
+
+#endif // FXJSE_SCOPE_INLINE_H_
diff --git a/fxjse/value.cpp b/fxjse/value.cpp
new file mode 100644
index 0000000000..a49ee312f3
--- /dev/null
+++ b/fxjse/value.cpp
@@ -0,0 +1,297 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjse/include/cfxjse_value.h"
+
+#include <math.h>
+
+#include "fxjse/context.h"
+#include "fxjse/include/cfxjse_class.h"
+
+void FXJSE_ThrowMessage(const CFX_ByteStringC& utf8Message) {
+ v8::Isolate* pIsolate = v8::Isolate::GetCurrent();
+ ASSERT(pIsolate);
+
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
+ v8::Local<v8::String> hMessage = v8::String::NewFromUtf8(
+ pIsolate, utf8Message.c_str(), v8::String::kNormalString,
+ utf8Message.GetLength());
+ v8::Local<v8::Value> hError = v8::Exception::Error(hMessage);
+ pIsolate->ThrowException(hError);
+}
+
+CFXJSE_HostObject* CFXJSE_Value::ToHostObject(CFXJSE_Class* lpClass) const {
+ ASSERT(!m_hValue.IsEmpty());
+
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> pValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ ASSERT(!pValue.IsEmpty());
+
+ if (!pValue->IsObject())
+ return nullptr;
+
+ return FXJSE_RetrieveObjectBinding(pValue.As<v8::Object>(), lpClass);
+}
+
+void CFXJSE_Value::SetObject(CFXJSE_HostObject* lpObject,
+ CFXJSE_Class* pClass) {
+ if (!pClass) {
+ ASSERT(!lpObject);
+ SetJSObject();
+ return;
+ }
+ SetHostObject(lpObject, pClass);
+}
+
+void CFXJSE_Value::SetHostObject(CFXJSE_HostObject* lpObject,
+ CFXJSE_Class* lpClass) {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ ASSERT(lpClass);
+ v8::Local<v8::FunctionTemplate> hClass =
+ v8::Local<v8::FunctionTemplate>::New(m_pIsolate, lpClass->m_hTemplate);
+ v8::Local<v8::Object> hObject = hClass->InstanceTemplate()->NewInstance();
+ FXJSE_UpdateObjectBinding(hObject, lpObject);
+ m_hValue.Reset(m_pIsolate, hObject);
+}
+
+void CFXJSE_Value::SetArray(uint32_t uValueCount, CFXJSE_Value** rgValues) {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Array> hArrayObject = v8::Array::New(m_pIsolate, uValueCount);
+ if (rgValues) {
+ for (uint32_t i = 0; i < uValueCount; i++) {
+ if (rgValues[i]) {
+ hArrayObject->Set(i, v8::Local<v8::Value>::New(
+ m_pIsolate, rgValues[i]->DirectGetValue()));
+ }
+ }
+ }
+ m_hValue.Reset(m_pIsolate, hArrayObject);
+}
+
+void CFXJSE_Value::SetDate(double dDouble) {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hDate = v8::Date::New(m_pIsolate, dDouble);
+ m_hValue.Reset(m_pIsolate, hDate);
+}
+
+FX_BOOL CFXJSE_Value::SetObjectProperty(const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* lpPropValue) {
+ ASSERT(lpPropValue);
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hObject =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ if (!hObject->IsObject())
+ return FALSE;
+
+ v8::Local<v8::Value> hPropValue =
+ v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue());
+ return (FX_BOOL)hObject.As<v8::Object>()->Set(
+ v8::String::NewFromUtf8(m_pIsolate, szPropName.c_str(),
+ v8::String::kNormalString,
+ szPropName.GetLength()),
+ hPropValue);
+}
+
+FX_BOOL CFXJSE_Value::GetObjectProperty(const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* lpPropValue) {
+ ASSERT(lpPropValue);
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hObject =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ if (!hObject->IsObject())
+ return FALSE;
+
+ v8::Local<v8::Value> hPropValue =
+ hObject.As<v8::Object>()->Get(v8::String::NewFromUtf8(
+ m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
+ szPropName.GetLength()));
+ lpPropValue->ForceSetValue(hPropValue);
+ return TRUE;
+}
+
+FX_BOOL CFXJSE_Value::SetObjectProperty(uint32_t uPropIdx,
+ CFXJSE_Value* lpPropValue) {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hObject =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ if (!hObject->IsObject())
+ return FALSE;
+
+ v8::Local<v8::Value> hPropValue =
+ v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue());
+ return (FX_BOOL)hObject.As<v8::Object>()->Set(uPropIdx, hPropValue);
+}
+
+FX_BOOL CFXJSE_Value::GetObjectPropertyByIdx(uint32_t uPropIdx,
+ CFXJSE_Value* lpPropValue) {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hObject =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ if (!hObject->IsObject())
+ return FALSE;
+
+ v8::Local<v8::Value> hPropValue = hObject.As<v8::Object>()->Get(uPropIdx);
+ lpPropValue->ForceSetValue(hPropValue);
+ return TRUE;
+}
+
+FX_BOOL CFXJSE_Value::DeleteObjectProperty(const CFX_ByteStringC& szPropName) {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hObject =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ if (!hObject->IsObject())
+ return FALSE;
+
+ hObject.As<v8::Object>()->Delete(v8::String::NewFromUtf8(
+ m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
+ szPropName.GetLength()));
+ return TRUE;
+}
+
+FX_BOOL CFXJSE_Value::HasObjectOwnProperty(const CFX_ByteStringC& szPropName,
+ FX_BOOL bUseTypeGetter) {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hObject =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ if (!hObject->IsObject())
+ return FALSE;
+
+ v8::Local<v8::String> hKey = v8::String::NewFromUtf8(
+ m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
+ szPropName.GetLength());
+ return hObject.As<v8::Object>()->HasRealNamedProperty(hKey) ||
+ (bUseTypeGetter &&
+ hObject.As<v8::Object>()
+ ->HasOwnProperty(m_pIsolate->GetCurrentContext(), hKey)
+ .FromMaybe(false));
+}
+
+FX_BOOL CFXJSE_Value::SetObjectOwnProperty(const CFX_ByteStringC& szPropName,
+ CFXJSE_Value* lpPropValue) {
+ ASSERT(lpPropValue);
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hObject =
+ v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+ if (!hObject->IsObject())
+ return FALSE;
+
+ v8::Local<v8::Value> pValue =
+ v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->m_hValue);
+ return hObject.As<v8::Object>()
+ ->DefineOwnProperty(
+ m_pIsolate->GetCurrentContext(),
+ v8::String::NewFromUtf8(m_pIsolate, szPropName.c_str(),
+ v8::String::kNormalString,
+ szPropName.GetLength()),
+ pValue)
+ .FromMaybe(false);
+}
+
+FX_BOOL CFXJSE_Value::SetFunctionBind(CFXJSE_Value* lpOldFunction,
+ CFXJSE_Value* lpNewThis) {
+ ASSERT(lpOldFunction && lpNewThis);
+
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> rgArgs[2];
+ v8::Local<v8::Value> hOldFunction =
+ v8::Local<v8::Value>::New(m_pIsolate, lpOldFunction->DirectGetValue());
+ if (hOldFunction.IsEmpty() || !hOldFunction->IsFunction())
+ return FALSE;
+
+ rgArgs[0] = hOldFunction;
+ v8::Local<v8::Value> hNewThis =
+ v8::Local<v8::Value>::New(m_pIsolate, lpNewThis->DirectGetValue());
+ if (hNewThis.IsEmpty())
+ return FALSE;
+
+ rgArgs[1] = hNewThis;
+ v8::Local<v8::String> hBinderFuncSource =
+ v8::String::NewFromUtf8(m_pIsolate,
+ "(function (oldfunction, newthis) { return "
+ "oldfunction.bind(newthis); })");
+ v8::Local<v8::Function> hBinderFunc =
+ v8::Script::Compile(hBinderFuncSource)->Run().As<v8::Function>();
+ v8::Local<v8::Value> hBoundFunction =
+ hBinderFunc->Call(m_pIsolate->GetCurrentContext()->Global(), 2, rgArgs);
+ if (hBoundFunction.IsEmpty() || !hBoundFunction->IsFunction())
+ return FALSE;
+
+ m_hValue.Reset(m_pIsolate, hBoundFunction);
+ return TRUE;
+}
+
+#define FXJSE_INVALID_PTR ((void*)(intptr_t)-1)
+FX_BOOL CFXJSE_Value::Call(CFXJSE_Value* lpReceiver,
+ CFXJSE_Value* lpRetValue,
+ uint32_t nArgCount,
+ CFXJSE_Value** lpArgs) {
+ CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+ v8::Local<v8::Value> hFunctionValue =
+ v8::Local<v8::Value>::New(m_pIsolate, DirectGetValue());
+ v8::Local<v8::Object> hFunctionObject =
+ !hFunctionValue.IsEmpty() && hFunctionValue->IsObject()
+ ? hFunctionValue.As<v8::Object>()
+ : v8::Local<v8::Object>();
+
+ v8::TryCatch trycatch(m_pIsolate);
+ if (hFunctionObject.IsEmpty() || !hFunctionObject->IsCallable()) {
+ if (lpRetValue)
+ lpRetValue->ForceSetValue(FXJSE_CreateReturnValue(m_pIsolate, trycatch));
+ return FALSE;
+ }
+
+ v8::Local<v8::Value> hReturnValue;
+ v8::Local<v8::Value>* lpLocalArgs = NULL;
+ if (nArgCount) {
+ lpLocalArgs = FX_Alloc(v8::Local<v8::Value>, nArgCount);
+ for (uint32_t i = 0; i < nArgCount; i++) {
+ new (lpLocalArgs + i) v8::Local<v8::Value>;
+ CFXJSE_Value* lpArg = lpArgs[i];
+ if (lpArg) {
+ lpLocalArgs[i] =
+ v8::Local<v8::Value>::New(m_pIsolate, lpArg->DirectGetValue());
+ }
+ if (lpLocalArgs[i].IsEmpty()) {
+ lpLocalArgs[i] = v8::Undefined(m_pIsolate);
+ }
+ }
+ }
+
+ FX_BOOL bRetValue = TRUE;
+ if (lpReceiver == FXJSE_INVALID_PTR) {
+ v8::MaybeLocal<v8::Value> maybe_retvalue =
+ hFunctionObject->CallAsConstructor(m_pIsolate->GetCurrentContext(),
+ nArgCount, lpLocalArgs);
+ hReturnValue = maybe_retvalue.FromMaybe(v8::Local<v8::Value>());
+ } else {
+ v8::Local<v8::Value> hReceiver;
+ if (lpReceiver) {
+ hReceiver =
+ v8::Local<v8::Value>::New(m_pIsolate, lpReceiver->DirectGetValue());
+ }
+ if (hReceiver.IsEmpty() || !hReceiver->IsObject())
+ hReceiver = v8::Object::New(m_pIsolate);
+
+ v8::MaybeLocal<v8::Value> maybe_retvalue = hFunctionObject->CallAsFunction(
+ m_pIsolate->GetCurrentContext(), hReceiver, nArgCount, lpLocalArgs);
+ hReturnValue = maybe_retvalue.FromMaybe(v8::Local<v8::Value>());
+ }
+
+ if (trycatch.HasCaught()) {
+ hReturnValue = FXJSE_CreateReturnValue(m_pIsolate, trycatch);
+ bRetValue = FALSE;
+ }
+
+ if (lpRetValue)
+ lpRetValue->ForceSetValue(hReturnValue);
+
+ if (lpLocalArgs) {
+ for (uint32_t i = 0; i < nArgCount; i++)
+ lpLocalArgs[i].~Local();
+ FX_Free(lpLocalArgs);
+ }
+ return bRetValue;
+}