// 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 "../../../core/include/fxcrt/fx_basic.h" #include "../../../core/include/fxcrt/fx_ext.h" #include "../../include/jsapi/fxjs_v8.h" #include "../../include/fsdk_define.h" #include "time.h" #include #include #define VALUE_NAME_STRING L"string" #define VALUE_NAME_NUMBER L"number" #define VALUE_NAME_BOOLEAN L"boolean" #define VALUE_NAME_DATE L"date" #define VALUE_NAME_OBJECT L"object" #define VALUE_NAME_FXOBJ L"fxobj" #define VALUE_NAME_NULL L"null" #define VALUE_NAME_UNDEFINED L"undefined" static FX_DWORD g_nan[2] = {0,0x7FF80000 }; double g_NaN = (*(double *)g_nan); class CJS_PrivateData: public CFX_Object { public: CJS_PrivateData():ObjDefID(-1), pPrivate(NULL) {} int ObjDefID; FX_LPVOID pPrivate; }; class CJS_ObjDefintion: public CFX_Object { public: CJS_ObjDefintion(v8::Isolate* isolate, const wchar_t* sObjName, FXJSOBJTYPE eObjType, LP_CONSTRUCTOR pConstructor, LP_DESTRUCTOR pDestructor, unsigned bApplyNew): objName(sObjName), objType(eObjType), m_pConstructor(pConstructor), m_pDestructor(pDestructor),m_bApplyNew(bApplyNew),m_bSetAsGlobalObject(FALSE) { v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); v8::Handle objTemplate = ObjectTemplate::New(isolate); objTemplate->SetInternalFieldCount(1); m_objTemplate.Reset(isolate, objTemplate); //Document as the global object. if(FXSYS_wcscmp(sObjName, L"Document") == 0) { m_bSetAsGlobalObject = TRUE; } } ~CJS_ObjDefintion() { m_objTemplate.Reset(); m_StaticObj.Reset(); } public: const wchar_t* objName; FXJSOBJTYPE objType; LP_CONSTRUCTOR m_pConstructor; LP_DESTRUCTOR m_pDestructor; unsigned m_bApplyNew; FX_BOOL m_bSetAsGlobalObject; v8::Persistent m_objTemplate; v8::Persistent m_StaticObj; }; int JS_DefineObj(IJS_Runtime* pJSRuntime, const wchar_t* sObjName, FXJSOBJTYPE eObjType, LP_CONSTRUCTOR pConstructor, LP_DESTRUCTOR pDestructor, unsigned bApplyNew) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); CFX_PtrArray* pArray = (CFX_PtrArray*)isolate->GetData(0); if(!pArray) { pArray = FX_NEW CFX_PtrArray(); isolate->SetData(0, pArray); } CJS_ObjDefintion* pObjDef = FX_NEW CJS_ObjDefintion(isolate, sObjName, eObjType, pConstructor, pDestructor, bApplyNew); pArray->Add(pObjDef); return pArray->GetSize()-1; } int JS_DefineObjMethod(IJS_Runtime* pJSRuntime, int nObjDefnID, const wchar_t* sMethodName, FunctionCallback pMethodCall, unsigned nParamNum) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); CFX_WideString ws = CFX_WideString((FX_LPCWSTR)sMethodName); CFX_ByteString bsMethodName = ws.UTF8Encode(); CFX_PtrArray* pArray = (CFX_PtrArray*)isolate->GetData(0); if(!pArray) return 0; if(nObjDefnID<0 || nObjDefnID>= pArray->GetSize()) return 0; CJS_ObjDefintion* pObjDef = (CJS_ObjDefintion*)pArray->GetAt(nObjDefnID); v8::Local objTemp = v8::Local::New(isolate, pObjDef->m_objTemplate); objTemp->Set(v8::String::NewFromUtf8(isolate, FX_LPCSTR(bsMethodName)), FunctionTemplate::New(isolate, pMethodCall), ReadOnly); pObjDef->m_objTemplate.Reset(isolate,objTemp); return 0; } int JS_DefineObjProperty(IJS_Runtime* pJSRuntime, int nObjDefnID, const wchar_t* sPropName, AccessorGetterCallback pPropGet, AccessorSetterCallback pPropPut) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); CFX_WideString ws = CFX_WideString((FX_LPCWSTR)sPropName); CFX_ByteString bsPropertyName = ws.UTF8Encode(); CFX_PtrArray* pArray = (CFX_PtrArray*)isolate->GetData(0); if(!pArray) return 0; if(nObjDefnID<0 || nObjDefnID>= pArray->GetSize()) return 0; CJS_ObjDefintion* pObjDef = (CJS_ObjDefintion*)pArray->GetAt(nObjDefnID); v8::Local objTemp = v8::Local::New(isolate, pObjDef->m_objTemplate); objTemp->SetAccessor(v8::String::NewFromUtf8(isolate, FX_LPCSTR(bsPropertyName)), pPropGet, pPropPut); pObjDef->m_objTemplate.Reset(isolate,objTemp); return 0; } int JS_DefineObjAllProperties(IJS_Runtime* pJSRuntime, int nObjDefnID, NamedPropertyQueryCallback pPropQurey, NamedPropertyGetterCallback pPropGet, NamedPropertySetterCallback pPropPut, NamedPropertyDeleterCallback pPropDel) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); CFX_PtrArray* pArray = (CFX_PtrArray*)isolate->GetData(0); if(!pArray) return 0; if(nObjDefnID<0 || nObjDefnID>= pArray->GetSize()) return 0; CJS_ObjDefintion* pObjDef = (CJS_ObjDefintion*)pArray->GetAt(nObjDefnID); v8::Local objTemp = v8::Local::New(isolate, pObjDef->m_objTemplate); objTemp->SetNamedPropertyHandler(pPropGet, pPropPut, pPropQurey, pPropDel); pObjDef->m_objTemplate.Reset(isolate,objTemp); return 0; } int JS_DefineObjConst(IJS_Runtime* pJSRuntime, int nObjDefnID, const wchar_t* sConstName, v8::Handle pDefault) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); CFX_PtrArray* pArray = (CFX_PtrArray*)isolate->GetData(0); if(!pArray) return 0; CFX_WideString ws = CFX_WideString((FX_LPCWSTR)sConstName); CFX_ByteString bsConstName = ws.UTF8Encode(); if(nObjDefnID<0 || nObjDefnID>= pArray->GetSize()) return 0; CJS_ObjDefintion* pObjDef = (CJS_ObjDefintion*)pArray->GetAt(nObjDefnID); v8::Local objTemp = v8::Local::New(isolate, pObjDef->m_objTemplate); objTemp->Set(isolate, FX_LPCSTR(bsConstName), pDefault); pObjDef->m_objTemplate.Reset(isolate,objTemp); return 0; } static v8::Persistent& _getGlobalObjectTemplate(IJS_Runtime* pJSRuntime) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); CFX_PtrArray* pArray = (CFX_PtrArray*)isolate->GetData(0); ASSERT(pArray != NULL); for(int i=0; iGetSize(); i++) { CJS_ObjDefintion* pObjDef = (CJS_ObjDefintion*)pArray->GetAt(i); if(pObjDef->m_bSetAsGlobalObject) return pObjDef->m_objTemplate; } static v8::Persistent gloabalObjectTemplate; return gloabalObjectTemplate; } int JS_DefineGlobalMethod(IJS_Runtime* pJSRuntime, const wchar_t* sMethodName, FunctionCallback pMethodCall, unsigned nParamNum) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); CFX_WideString ws = CFX_WideString((FX_LPCWSTR)sMethodName); CFX_ByteString bsMethodName = ws.UTF8Encode(); v8::Local funTempl = FunctionTemplate::New(isolate, pMethodCall); v8::Local objTemp; v8::Persistent& globalObjTemp = _getGlobalObjectTemplate(pJSRuntime); if(globalObjTemp.IsEmpty()) objTemp = ObjectTemplate::New(isolate); else objTemp = v8::Local::New(isolate, globalObjTemp); objTemp->Set(v8::String::NewFromUtf8(isolate, FX_LPCSTR(bsMethodName)), funTempl, ReadOnly); globalObjTemp.Reset(isolate,objTemp); return 0; } int JS_DefineGlobalConst(IJS_Runtime* pJSRuntime, const wchar_t* sConstName, v8::Handle pDefault) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); CFX_WideString ws = CFX_WideString((FX_LPCWSTR)sConstName); CFX_ByteString bsConst= ws.UTF8Encode(); v8::Local objTemp; v8::Persistent& globalObjTemp = _getGlobalObjectTemplate(pJSRuntime); if(globalObjTemp.IsEmpty()) objTemp = ObjectTemplate::New(isolate); else objTemp = v8::Local::New(isolate, globalObjTemp); objTemp->Set(v8::String::NewFromUtf8(isolate, FX_LPCSTR(bsConst)), pDefault, ReadOnly); globalObjTemp.Reset(isolate,objTemp); return 0; } void JS_InitialRuntime(IJS_Runtime* pJSRuntime,IFXJS_Runtime* pFXRuntime, IFXJS_Context* context, v8::Persistent& v8PersistentContext) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); v8::Persistent& globalObjTemp = _getGlobalObjectTemplate(pJSRuntime); v8::Handle v8Context = v8::Context::New(isolate, NULL, v8::Local::New(isolate, globalObjTemp)); v8::Context::Scope context_scope(v8Context); v8::Handle ptr = External::New(isolate, pFXRuntime); v8Context->SetEmbedderData(1, ptr); CFX_PtrArray* pArray = (CFX_PtrArray*)isolate->GetData(0); if(!pArray) return; for(int i=0; iGetSize(); i++) { CJS_ObjDefintion* pObjDef = (CJS_ObjDefintion*)pArray->GetAt(i); CFX_WideString ws = CFX_WideString(pObjDef->objName); CFX_ByteString bs = ws.UTF8Encode(); v8::Handle objName = v8::String::NewFromUtf8(isolate,(FX_LPCSTR)bs, v8::String::kNormalString, bs.GetLength()); if(pObjDef->objType == JS_DYNAMIC) { //Document is set as global object, need to construct it first. if(ws.Equal(L"Document")) { CJS_PrivateData* pPrivateData = FX_NEW CJS_PrivateData; pPrivateData->ObjDefID = i; v8::Handle ptr = External::New(isolate, pPrivateData); v8Context->Global()->GetPrototype()->ToObject()->SetInternalField(0, ptr); if(pObjDef->m_pConstructor) pObjDef->m_pConstructor(context, v8Context->Global()->GetPrototype()->ToObject(), v8Context->Global()->GetPrototype()->ToObject()); } } else { v8::Handle obj = JS_NewFxDynamicObj(pJSRuntime, context, i); v8Context->Global()->Set(objName, obj); pObjDef->m_StaticObj.Reset(isolate, obj); } } v8PersistentContext.Reset(isolate, v8Context); } void JS_ReleaseRuntime(IJS_Runtime* pJSRuntime, v8::Persistent& v8PersistentContext) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); v8::Local context = v8::Local::New(isolate, v8PersistentContext); v8::Context::Scope context_scope(context); CFX_PtrArray* pArray = (CFX_PtrArray*)isolate->GetData(0); if(!pArray) return ; for(int i=0; iGetSize(); i++) { CJS_ObjDefintion* pObjDef = (CJS_ObjDefintion*)pArray->GetAt(i); if(!pObjDef->m_StaticObj.IsEmpty()) { v8::Local pObj = v8::Local::New(isolate, pObjDef->m_StaticObj); if(pObjDef->m_pDestructor) pObjDef->m_pDestructor(pObj); JS_FreePrivate(pObj); } delete pObjDef; } delete pArray; isolate->SetData(0,NULL); } void JS_Initial() { #ifndef FOXIT_CHROME_BUILD v8::V8::InitializeICU(); #endif } void JS_Release() { } int JS_Parse(IJS_Runtime* pJSRuntime, IFXJS_Context* pJSContext, const wchar_t* script, long length, FXJSErr* perror) { v8::Isolate* isolate = (v8::Isolate*)pJSRuntime; v8::Isolate::Scope isolate_scope(isolate); TryCatch try_catch; CFX_WideString wsScript(script); CFX_ByteString bsScript = wsScript.UTF8Encode(); v8::Handle