diff options
Diffstat (limited to 'fxjs')
-rw-r--r-- | fxjs/DEPS | 6 | ||||
-rw-r--r-- | fxjs/cfxjse_arguments.cpp | 56 | ||||
-rw-r--r-- | fxjs/cfxjse_class.cpp | 433 | ||||
-rw-r--r-- | fxjs/cfxjse_context.cpp | 255 | ||||
-rw-r--r-- | fxjs/cfxjse_isolatetracker.cpp | 35 | ||||
-rw-r--r-- | fxjs/cfxjse_isolatetracker.h | 70 | ||||
-rw-r--r-- | fxjs/cfxjse_runtimedata.cpp | 105 | ||||
-rw-r--r-- | fxjs/cfxjse_runtimedata.h | 34 | ||||
-rw-r--r-- | fxjs/cfxjse_value.cpp | 519 | ||||
-rw-r--r-- | fxjs/include/cfxjse_arguments.h | 38 | ||||
-rw-r--r-- | fxjs/include/cfxjse_class.h | 45 | ||||
-rw-r--r-- | fxjs/include/cfxjse_context.h | 65 | ||||
-rw-r--r-- | fxjs/include/cfxjse_value.h | 102 | ||||
-rw-r--r-- | fxjs/include/fxjse.h | 74 |
14 files changed, 1837 insertions, 0 deletions
diff --git a/fxjs/DEPS b/fxjs/DEPS new file mode 100644 index 0000000000..18698e4ce4 --- /dev/null +++ b/fxjs/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/fxjs/cfxjse_arguments.cpp b/fxjs/cfxjse_arguments.cpp new file mode 100644 index 0000000000..1ff425d8b1 --- /dev/null +++ b/fxjs/cfxjse_arguments.cpp @@ -0,0 +1,56 @@ +// 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 + +#include "fxjs/include/cfxjse_arguments.h" + +#include "fxjs/include/cfxjse_context.h" +#include "fxjs/include/cfxjse_value.h" + +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; +} diff --git a/fxjs/cfxjse_class.cpp b/fxjs/cfxjse_class.cpp new file mode 100644 index 0000000000..de22af7681 --- /dev/null +++ b/fxjs/cfxjse_class.cpp @@ -0,0 +1,433 @@ +// 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 + +#include "fxjs/include/cfxjse_class.h" + +#include "fxjs/include/cfxjse_context.h" +#include "fxjs/include/cfxjse_value.h" + +namespace { + +void 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()); +} + +void 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()); +} + +void 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()); +} + +void 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()); +} + +void V8ConstructorCallback_Wrapper( + const v8::FunctionCallbackInfo<v8::Value>& info) { + if (!info.IsConstructCall()) + return; + + 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, nullptr); +} + +void 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())); + return; + } + v8::Local<v8::String> local_str = + info.This() + ->ObjectProtoToString(info.GetIsolate()->GetCurrentContext()) + .FromMaybe(v8::Local<v8::String>()); + info.GetReturnValue().Set(local_str); +} + +void 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()); +} + +void 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()->GetCurrentContext(), + DynPropGetterAdapter_MethodCallback, hCallBackInfo, + 0, v8::ConstructorBehavior::kThrow) + .ToLocalChecked()); + } + } +} + +void 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); + } +} + +FX_BOOL 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; +} + +FX_BOOL 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); + return nPropType == FXJSE_ClassPropType_Property ? FALSE : TRUE; + } + return FALSE; +} + +void NamedPropertyQueryCallback( + 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 (DynPropQueryAdapter(lpClass, lpThisValue.get(), szFxPropName)) { + info.GetReturnValue().Set(v8::DontDelete); + return; + } + const int32_t iV8Absent = 64; + info.GetReturnValue().Set(iV8Absent); +} + +void NamedPropertyDeleterCallback( + 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( + !!DynPropDeleterAdapter(lpClass, lpThisValue.get(), szFxPropName)); +} + +void NamedPropertyGetterCallback( + 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())); + DynPropGetterAdapter(lpClass, lpThisValue.get(), szFxPropName, + lpNewValue.get()); + info.GetReturnValue().Set(lpNewValue->DirectGetValue()); +} + +void NamedPropertySetterCallback( + 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); + DynPropSetterAdapter(lpClass, lpThisValue.get(), szFxPropName, lpNewValue); + info.GetReturnValue().Set(value); +} + +void NamedPropertyEnumeratorCallback( + 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); +} + +} // namespace + +// static +CFXJSE_Class* CFXJSE_Class::Create( + CFXJSE_Context* lpContext, + const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition, + FX_BOOL bIsJSGlobal) { + if (!lpContext || !lpClassDefinition) + return nullptr; + + 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 : 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 ? V8GetterCallback_Wrapper + : nullptr, + lpClassDefinition->properties[i].setProc ? V8SetterCallback_Wrapper + : nullptr, + 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++) { + v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New( + pIsolate, V8FunctionCallback_Wrapper, + v8::External::New(pIsolate, const_cast<FXJSE_FUNCTION_DESCRIPTOR*>( + lpClassDefinition->methods + i))); + fun->RemovePrototype(); + hObjectTemplate->Set( + v8::String::NewFromUtf8(pIsolate, lpClassDefinition->methods[i].name), + fun, + 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, 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, V8ClassGlobalConstructorCallback_Wrapper, + v8::External::New(pIsolate, + const_cast<FXJSE_CLASS_DESCRIPTOR*>( + lpClassDefinition)))); + } + } + if (bIsJSGlobal) { + v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New( + pIsolate, Context_GlobalObjToString, + v8::External::New( + pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition))); + fun->RemovePrototype(); + hObjectTemplate->Set(v8::String::NewFromUtf8(pIsolate, "toString"), fun); + } + pClass->m_hTemplate.Reset(lpContext->m_pIsolate, hFunctionTemplate); + lpContext->m_rgClasses.push_back(std::unique_ptr<CFXJSE_Class>(pClass)); + return pClass; +} + +// static +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; +} + +// static +void CFXJSE_Class::SetUpNamedPropHandler( + v8::Isolate* pIsolate, + v8::Local<v8::ObjectTemplate>& hObjectTemplate, + const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition) { + v8::NamedPropertyHandlerConfiguration configuration( + lpClassDefinition->dynPropGetter ? NamedPropertyGetterCallback : 0, + lpClassDefinition->dynPropSetter ? NamedPropertySetterCallback : 0, + lpClassDefinition->dynPropTypeGetter ? NamedPropertyQueryCallback : 0, + lpClassDefinition->dynPropDeleter ? NamedPropertyDeleterCallback : 0, + NamedPropertyEnumeratorCallback, + v8::External::New(pIsolate, + const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)), + v8::PropertyHandlerFlags::kNonMasking); + hObjectTemplate->SetHandler(configuration); +} + +CFXJSE_Class::CFXJSE_Class(CFXJSE_Context* lpContext) + : m_lpClassDefinition(nullptr), m_pContext(lpContext) {} + +CFXJSE_Class::~CFXJSE_Class() {} diff --git a/fxjs/cfxjse_context.cpp b/fxjs/cfxjse_context.cpp new file mode 100644 index 0000000000..4b0d0f67f7 --- /dev/null +++ b/fxjs/cfxjse_context.cpp @@ -0,0 +1,255 @@ +// 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 + +#include "fxjs/include/cfxjse_context.h" + +#include "fxjs/include/cfxjse_class.h" +#include "fxjs/include/cfxjse_value.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 + +// Note, not in the anonymous namespace due to the friend call +// in cfxjse_context.h +// TODO(dsinclair): Remove the friending, use public methods. +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; +}; + +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; +} + +// static +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 = nullptr; + 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); + } + hObjectTemplate->Set( + v8::Symbol::GetToStringTag(pIsolate), + v8::String::NewFromUtf8(pIsolate, "global", v8::NewStringType::kNormal) + .ToLocalChecked()); + v8::Local<v8::Context> hNewContext = + v8::Context::New(pIsolate, nullptr, 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) { + 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/fxjs/cfxjse_isolatetracker.cpp b/fxjs/cfxjse_isolatetracker.cpp new file mode 100644 index 0000000000..9594df3109 --- /dev/null +++ b/fxjs/cfxjse_isolatetracker.cpp @@ -0,0 +1,35 @@ +// 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 + +#include "fxjs/cfxjse_isolatetracker.h" + +#include <algorithm> + +CFXJSE_IsolateTracker::CFXJSE_IsolateTracker() {} + +CFXJSE_IsolateTracker::~CFXJSE_IsolateTracker() {} + +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/fxjs/cfxjse_isolatetracker.h b/fxjs/cfxjse_isolatetracker.h new file mode 100644 index 0000000000..7558416a14 --- /dev/null +++ b/fxjs/cfxjse_isolatetracker.h @@ -0,0 +1,70 @@ +// 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 FXJS_CFXJSE_ISOLATETRACKER_H_ +#define FXJS_CFXJSE_ISOLATETRACKER_H_ + +#include <vector> + +#include "v8/include/v8.h" + +#include "fxjs/cfxjse_runtimedata.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_IsolateTracker { + public: + typedef void (*DisposeCallback)(v8::Isolate*, bool bOwnedIsolate); + + CFXJSE_IsolateTracker(); + ~CFXJSE_IsolateTracker(); + + void Append(v8::Isolate* pIsolate); + void Remove(v8::Isolate* pIsolate, DisposeCallback lpfnDisposeCallback); + void RemoveAll(DisposeCallback lpfnDisposeCallback); + + static CFXJSE_IsolateTracker* g_pInstance; + + protected: + std::vector<v8::Isolate*> m_OwnedIsolates; +}; + +#endif // FXJS_CFXJSE_ISOLATETRACKER_H_ diff --git a/fxjs/cfxjse_runtimedata.cpp b/fxjs/cfxjse_runtimedata.cpp new file mode 100644 index 0000000000..f58f5f852d --- /dev/null +++ b/fxjs/cfxjse_runtimedata.cpp @@ -0,0 +1,105 @@ +// 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 + +#include "fxjs/cfxjse_runtimedata.h" + +#include "fpdfsdk/jsapi/include/fxjs_v8.h" +#include "fxjs/cfxjse_isolatetracker.h" + +namespace { + +// 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); } +}; + +void 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 KillV8() { + v8::V8::Dispose(); +} + +} // namespace + +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(KillV8); +} + +void FXJSE_Finalize() { + if (!CFXJSE_IsolateTracker::g_pInstance) + return; + + CFXJSE_IsolateTracker::g_pInstance->RemoveAll(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, Runtime_DisposeCallback); +} + +CFXJSE_RuntimeData::CFXJSE_RuntimeData(v8::Isolate* pIsolate) + : m_pIsolate(pIsolate) {} + +CFXJSE_RuntimeData::~CFXJSE_RuntimeData() {} + +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::ObjectTemplate> hGlobalTemplate = + hFuncTemplate->InstanceTemplate(); + hGlobalTemplate->Set( + v8::Symbol::GetToStringTag(pIsolate), + v8::String::NewFromUtf8(pIsolate, "global", v8::NewStringType::kNormal) + .ToLocalChecked()); + v8::Local<v8::Context> hContext = + v8::Context::New(pIsolate, 0, hGlobalTemplate); + 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; diff --git a/fxjs/cfxjse_runtimedata.h b/fxjs/cfxjse_runtimedata.h new file mode 100644 index 0000000000..34f8f32d92 --- /dev/null +++ b/fxjs/cfxjse_runtimedata.h @@ -0,0 +1,34 @@ +// 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 FXJS_CFXJSE_RUNTIMEDATA_H_ +#define FXJS_CFXJSE_RUNTIMEDATA_H_ + +#include "v8/include/v8.h" + +class CFXJSE_RuntimeList; + +class CFXJSE_RuntimeData { + public: + ~CFXJSE_RuntimeData(); + + static CFXJSE_RuntimeData* Get(v8::Isolate* pIsolate); + + v8::Isolate* m_pIsolate; + v8::Global<v8::FunctionTemplate> m_hRootContextGlobalTemplate; + v8::Global<v8::Context> m_hRootContext; + + protected: + explicit CFXJSE_RuntimeData(v8::Isolate* pIsolate); + + static CFXJSE_RuntimeData* Create(v8::Isolate* pIsolate); + + private: + CFXJSE_RuntimeData(const CFXJSE_RuntimeData&) = delete; + CFXJSE_RuntimeData& operator=(const CFXJSE_RuntimeData&) = delete; +}; + +#endif // FXJS_CFXJSE_RUNTIMEDATA_H_ diff --git a/fxjs/cfxjse_value.cpp b/fxjs/cfxjse_value.cpp new file mode 100644 index 0000000000..b1fc0784e8 --- /dev/null +++ b/fxjs/cfxjse_value.cpp @@ -0,0 +1,519 @@ +// 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 "fxjs/include/cfxjse_value.h" + +#include <math.h> + +#include "fxjs/include/cfxjse_class.h" +#include "fxjs/include/cfxjse_context.h" + +namespace { + +double ftod(FX_FLOAT fNumber) { + static_assert(sizeof(FX_FLOAT) == 4, "FX_FLOAT of incorrect size"); + + uint32_t nFloatBits = (uint32_t&)fNumber; + uint8_t nExponent = (uint8_t)(nFloatBits >> 23); + if (nExponent == 0 || nExponent == 255) + return fNumber; + + int8_t nErrExp = nExponent - 150; + 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; +} + +} // namespace + +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_Value::CFXJSE_Value(v8::Isolate* pIsolate) : m_pIsolate(pIsolate) {} + +CFXJSE_Value::~CFXJSE_Value() {} + +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); +} + +void CFXJSE_Value::SetFloat(FX_FLOAT fFloat) { + CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); + v8::Local<v8::Value> pValue = v8::Number::New(m_pIsolate, ftod(fFloat)); + m_hValue.Reset(m_pIsolate, pValue); +} + +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; +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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(); +} + +FX_BOOL CFXJSE_Value::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()); +} + +FX_FLOAT CFXJSE_Value::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()); +} + +double CFXJSE_Value::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()); +} + +int32_t CFXJSE_Value::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()); +} + +CFX_ByteString CFXJSE_Value::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); +} + +void CFXJSE_Value::SetUndefined() { + CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); + v8::Local<v8::Value> hValue = v8::Undefined(m_pIsolate); + m_hValue.Reset(m_pIsolate, hValue); +} + +void CFXJSE_Value::SetNull() { + CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); + v8::Local<v8::Value> hValue = v8::Null(m_pIsolate); + m_hValue.Reset(m_pIsolate, hValue); +} + +void CFXJSE_Value::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); +} + +void CFXJSE_Value::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); +} + +void CFXJSE_Value::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); +} + +void CFXJSE_Value::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); +} + +void CFXJSE_Value::SetJSObject() { + CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); + v8::Local<v8::Value> hValue = v8::Object::New(m_pIsolate); + m_hValue.Reset(m_pIsolate, hValue); +} diff --git a/fxjs/include/cfxjse_arguments.h b/fxjs/include/cfxjse_arguments.h new file mode 100644 index 0000000000..e6c8659732 --- /dev/null +++ b/fxjs/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 FXJS_INCLUDE_CFXJSE_ARGUMENTS_H_ +#define FXJS_INCLUDE_CFXJSE_ARGUMENTS_H_ + +#include <memory> + +#include "fxjs/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 // FXJS_INCLUDE_CFXJSE_ARGUMENTS_H_ diff --git a/fxjs/include/cfxjse_class.h b/fxjs/include/cfxjse_class.h new file mode 100644 index 0000000000..13eb1adb7d --- /dev/null +++ b/fxjs/include/cfxjse_class.h @@ -0,0 +1,45 @@ +// 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 FXJS_INCLUDE_CFXJSE_CLASS_H_ +#define FXJS_INCLUDE_CFXJSE_CLASS_H_ + +#include "fxjs/include/cfxjse_arguments.h" +#include "fxjs/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_Class(); + + CFXJSE_Context* GetContext() { return m_pContext; } + v8::Global<v8::FunctionTemplate>& GetTemplate() { return m_hTemplate; } + + protected: + explicit CFXJSE_Class(CFXJSE_Context* 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 // FXJS_INCLUDE_CFXJSE_CLASS_H_ diff --git a/fxjs/include/cfxjse_context.h b/fxjs/include/cfxjse_context.h new file mode 100644 index 0000000000..882258fe57 --- /dev/null +++ b/fxjs/include/cfxjse_context.h @@ -0,0 +1,65 @@ +// 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 FXJS_INCLUDE_CFXJSE_CONTEXT_H_ +#define FXJS_INCLUDE_CFXJSE_CONTEXT_H_ + +#include <memory> +#include <vector> + +#include "core/fxcrt/include/fx_basic.h" +#include "fxjs/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::Isolate* GetRuntime() { 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: + friend class CFXJSE_Class; + friend class CFXJSE_ScopeUtil_IsolateHandleContext; + + 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; +}; + +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 // FXJS_INCLUDE_CFXJSE_CONTEXT_H_ diff --git a/fxjs/include/cfxjse_value.h b/fxjs/include/cfxjse_value.h new file mode 100644 index 0000000000..7bb2c2d235 --- /dev/null +++ b/fxjs/include/cfxjse_value.h @@ -0,0 +1,102 @@ +// 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 FXJS_INCLUDE_CFXJSE_VALUE_H_ +#define FXJS_INCLUDE_CFXJSE_VALUE_H_ + +#include "v8/include/v8.h" + +#include "core/fxcrt/include/fx_string.h" +#include "core/fxcrt/include/fx_system.h" +#include "fxjs/cfxjse_isolatetracker.h" +#include "fxjs/cfxjse_runtimedata.h" + +class CFXJSE_Class; +class CFXJSE_HostObject; + +class CFXJSE_Value { + public: + explicit CFXJSE_Value(v8::Isolate* pIsolate); + ~CFXJSE_Value(); + + FX_BOOL IsUndefined() const; + FX_BOOL IsNull() const; + FX_BOOL IsBoolean() const; + FX_BOOL IsString() const; + FX_BOOL IsNumber() const; + FX_BOOL IsInteger() const; + FX_BOOL IsObject() const; + FX_BOOL IsArray() const; + FX_BOOL IsFunction() const; + FX_BOOL IsDate() const; + FX_BOOL ToBoolean() const; + FX_FLOAT ToFloat() const; + double ToDouble() const; + int32_t ToInteger() const; + CFX_ByteString ToString() const; + CFX_WideString ToWideString() const { + return CFX_WideString::FromUTF8(ToString().AsStringC()); + } + CFXJSE_HostObject* ToHostObject(CFXJSE_Class* lpClass) const; + + void SetUndefined(); + void SetNull(); + void SetBoolean(FX_BOOL bBoolean); + void SetInteger(int32_t nInteger); + void SetDouble(double dDouble); + void SetString(const CFX_ByteStringC& szString); + void SetFloat(FX_FLOAT fFloat); + void SetJSObject(); + + 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::Isolate* GetIsolate() const { return m_pIsolate; } + const v8::Global<v8::Value>& DirectGetValue() const { return m_hValue; } + void ForceSetValue(v8::Local<v8::Value> hValue) { + m_hValue.Reset(m_pIsolate, hValue); + } + 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 // FXJS_INCLUDE_CFXJSE_VALUE_H_ diff --git a/fxjs/include/fxjse.h b/fxjs/include/fxjse.h new file mode 100644 index 0000000000..79c32b053a --- /dev/null +++ b/fxjs/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 FXJS_INCLUDE_FXJSE_H_ +#define FXJS_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 // FXJS_INCLUDE_FXJSE_H_ |