1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "xfa/src/foxitlib.h" 8 #include "fxv8.h" 9 #include "context.h" 10 #include "class.h" 11 #include "value.h" 12 #include "scope_inline.h" 13 #include "util_inline.h" 14 FXJSE_HCONTEXT FXJSE_Context_Create(FXJSE_HRUNTIME hRuntime, 15 const FXJSE_CLASS* lpGlobalClass, 16 void* lpGlobalObject) { 17 CFXJSE_Context* pContext = CFXJSE_Context::Create( 18 reinterpret_cast<v8::Isolate*>(hRuntime), lpGlobalClass, lpGlobalObject); 19 return reinterpret_cast<FXJSE_HCONTEXT>(pContext); 20 } 21 void FXJSE_Context_Release(FXJSE_HCONTEXT hContext) { 22 CFXJSE_Context* pContext = reinterpret_cast<CFXJSE_Context*>(hContext); 23 if (pContext) { 24 delete pContext; 25 } 26 } 27 FXJSE_HVALUE FXJSE_Context_GetGlobalObject(FXJSE_HCONTEXT hContext) { 28 CFXJSE_Context* pContext = reinterpret_cast<CFXJSE_Context*>(hContext); 29 if (!pContext) { 30 return NULL; 31 } 32 CFXJSE_Value* lpValue = CFXJSE_Value::Create(pContext->GetRuntime()); 33 ASSERT(lpValue); 34 pContext->GetGlobalObject(lpValue); 35 return reinterpret_cast<FXJSE_HVALUE>(lpValue); 36 } 37 FXJSE_HRUNTIME FXJSE_Context_GetRuntime(FXJSE_HCONTEXT hContext) { 38 CFXJSE_Context* pContext = reinterpret_cast<CFXJSE_Context*>(hContext); 39 return pContext ? reinterpret_cast<FXJSE_HRUNTIME>(pContext->GetRuntime()) 40 : NULL; 41 } 42 static const FX_CHAR* szCompatibleModeScripts[] = { 43 "(function (global, list) { 'use strict'; var objname; for (objname in list) { var globalobj = global[objname];\n\ 44 if (globalobj) { list[objname].forEach( function (name) { if (!globalobj[name]) { Object.defineProperty(globalobj, name, {writable: true, enumerable: false, value: \n\ 45 (function (obj) {\n\ 46 if (arguments.length === 0) {\n\ 47 throw new TypeError('missing argument 0 when calling function ' + objname + '.' + name);\n\ 48 }\n\ 49 return globalobj.prototype[name].apply(obj, Array.prototype.slice.call(arguments, 1));\n\ 50 })});}});}}}(this, {String: ['substr', 'toUpperCase']}));", 51 }; 52 void FXJSE_Context_EnableCompatibleMode(FXJSE_HCONTEXT hContext, 53 FX_DWORD dwCompatibleFlags) { 54 for (uint32_t i = 0; i < (uint32_t)FXJSE_COMPATIBLEMODEFLAGCOUNT; i++) { 55 if (dwCompatibleFlags & (1 << i)) { 56 FXJSE_ExecuteScript(hContext, szCompatibleModeScripts[i], NULL, NULL); 57 } 58 } 59 } 60 FX_BOOL FXJSE_ExecuteScript(FXJSE_HCONTEXT hContext, 61 const FX_CHAR* szScript, 62 FXJSE_HVALUE hRetValue, 63 FXJSE_HVALUE hNewThisObject) { 64 CFXJSE_Context* pContext = reinterpret_cast<CFXJSE_Context*>(hContext); 65 ASSERT(pContext); 66 return pContext->ExecuteScript( 67 szScript, reinterpret_cast<CFXJSE_Value*>(hRetValue), 68 reinterpret_cast<CFXJSE_Value*>(hNewThisObject)); 69 } 70 v8::Local<v8::Object> FXJSE_CreateReturnValue(v8::Isolate* pIsolate, 71 v8::TryCatch& trycatch) { 72 v8::Local<v8::Object> hReturnValue = v8::Object::New(pIsolate); 73 if (trycatch.HasCaught()) { 74 v8::Local<v8::Value> hException = trycatch.Exception(); 75 v8::Local<v8::Message> hMessage = trycatch.Message(); 76 if (hException->IsObject()) { 77 v8::Local<v8::Value> hValue; 78 hValue = hException.As<v8::Object>()->Get( 79 v8::String::NewFromUtf8(pIsolate, "name")); 80 if (hValue->IsString() || hValue->IsStringObject()) { 81 hReturnValue->Set(0, hValue); 82 } else { 83 hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error")); 84 } 85 hValue = hException.As<v8::Object>()->Get( 86 v8::String::NewFromUtf8(pIsolate, "message")); 87 if (hValue->IsString() || hValue->IsStringObject()) { 88 hReturnValue->Set(1, hValue); 89 } else { 90 hReturnValue->Set(1, hMessage->Get()); 91 } 92 } else { 93 hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error")); 94 hReturnValue->Set(1, hMessage->Get()); 95 } 96 hReturnValue->Set(2, hException); 97 hReturnValue->Set(3, v8::Integer::New(pIsolate, hMessage->GetLineNumber())); 98 hReturnValue->Set(4, hMessage->GetSourceLine()); 99 hReturnValue->Set(5, 100 v8::Integer::New(pIsolate, hMessage->GetStartColumn())); 101 hReturnValue->Set(6, v8::Integer::New(pIsolate, hMessage->GetEndColumn())); 102 } 103 return hReturnValue; 104 } 105 FX_BOOL FXJSE_ReturnValue_GetMessage(FXJSE_HVALUE hRetValue, 106 CFX_ByteString& utf8Name, 107 CFX_ByteString& utf8Message) { 108 CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hRetValue); 109 if (!lpValue) { 110 return FALSE; 111 } 112 v8::Isolate* pIsolate = lpValue->GetIsolate(); 113 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate); 114 v8::Local<v8::Value> hValue = 115 v8::Local<v8::Value>::New(pIsolate, lpValue->DirectGetValue()); 116 if (!hValue->IsObject()) { 117 return FALSE; 118 } 119 v8::String::Utf8Value hStringVal0( 120 hValue.As<v8::Object>()->Get(0)->ToString()); 121 utf8Name = *hStringVal0; 122 v8::String::Utf8Value hStringVal1( 123 hValue.As<v8::Object>()->Get(1)->ToString()); 124 utf8Message = *hStringVal1; 125 return TRUE; 126 } 127 FX_BOOL FXJSE_ReturnValue_GetLineInfo(FXJSE_HVALUE hRetValue, 128 int32_t& nLine, 129 int32_t& nCol) { 130 CFXJSE_Value* lpValue = reinterpret_cast<CFXJSE_Value*>(hRetValue); 131 if (!lpValue) { 132 return FALSE; 133 } 134 v8::Isolate* pIsolate = lpValue->GetIsolate(); 135 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate); 136 v8::Local<v8::Value> hValue = 137 v8::Local<v8::Value>::New(pIsolate, lpValue->DirectGetValue()); 138 if (!hValue->IsObject()) { 139 return FALSE; 140 } 141 nLine = hValue.As<v8::Object>()->Get(3)->ToInt32()->Value(); 142 nCol = hValue.As<v8::Object>()->Get(5)->ToInt32()->Value(); 143 return TRUE; 144 } 145 CFXJSE_Context* CFXJSE_Context::Create(v8::Isolate* pIsolate, 146 const FXJSE_CLASS* lpGlobalClass, 147 void* lpGlobalObject) { 148 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate); 149 CFXJSE_Context* pContext = new CFXJSE_Context(pIsolate); 150 CFXJSE_Class* lpGlobalClassObj = NULL; 151 v8::Local<v8::ObjectTemplate> hObjectTemplate; 152 if (lpGlobalClass) { 153 lpGlobalClassObj = CFXJSE_Class::Create(pContext, lpGlobalClass, TRUE); 154 ASSERT(lpGlobalClassObj); 155 v8::Local<v8::FunctionTemplate> hFunctionTemplate = 156 v8::Local<v8::FunctionTemplate>::New(pIsolate, 157 lpGlobalClassObj->m_hTemplate); 158 hObjectTemplate = hFunctionTemplate->InstanceTemplate(); 159 } else { 160 hObjectTemplate = v8::ObjectTemplate::New(); 161 hObjectTemplate->SetInternalFieldCount(1); 162 } 163 v8::Local<v8::Context> hNewContext = 164 v8::Context::New(pIsolate, NULL, hObjectTemplate); 165 v8::Local<v8::Context> hRootContext = v8::Local<v8::Context>::New( 166 pIsolate, CFXJSE_RuntimeData::Get(pIsolate)->m_hRootContext); 167 hNewContext->SetSecurityToken(hRootContext->GetSecurityToken()); 168 v8::Local<v8::Object> hGlobalObject = 169 FXJSE_GetGlobalObjectFromContext(hNewContext); 170 FXJSE_UpdateObjectBinding(hGlobalObject, lpGlobalObject); 171 pContext->m_hContext.Reset(pIsolate, hNewContext); 172 return pContext; 173 } 174 CFXJSE_Context::~CFXJSE_Context() { 175 for (int32_t i = 0, count = m_rgClasses.GetSize(); i < count; i++) { 176 CFXJSE_Class* pClass = m_rgClasses[i]; 177 if (pClass) { 178 delete pClass; 179 } 180 } 181 m_rgClasses.RemoveAll(); 182 } 183 void CFXJSE_Context::GetGlobalObject(CFXJSE_Value* pValue) { 184 ASSERT(pValue); 185 CFXJSE_ScopeUtil_IsolateHandleContext scope(this); 186 v8::Local<v8::Context> hContext = 187 v8::Local<v8::Context>::New(m_pIsolate, m_hContext); 188 v8::Local<v8::Object> hGlobalObject = hContext->Global(); 189 pValue->ForceSetValue(hGlobalObject); 190 } 191 FX_BOOL CFXJSE_Context::ExecuteScript(const FX_CHAR* szScript, 192 CFXJSE_Value* lpRetValue, 193 CFXJSE_Value* lpNewThisObject) { 194 CFXJSE_ScopeUtil_IsolateHandleContext scope(this); 195 v8::TryCatch trycatch; 196 v8::Local<v8::String> hScriptString = 197 v8::String::NewFromUtf8(m_pIsolate, szScript); 198 if (lpNewThisObject == NULL) { 199 v8::Local<v8::Script> hScript = v8::Script::Compile(hScriptString); 200 if (!trycatch.HasCaught()) { 201 v8::Local<v8::Value> hValue = hScript->Run(); 202 if (!trycatch.HasCaught()) { 203 if (lpRetValue) { 204 lpRetValue->m_hValue.Reset(m_pIsolate, hValue); 205 } 206 return TRUE; 207 } 208 } 209 if (lpRetValue) { 210 lpRetValue->m_hValue.Reset(m_pIsolate, 211 FXJSE_CreateReturnValue(m_pIsolate, trycatch)); 212 } 213 return FALSE; 214 } else { 215 v8::Local<v8::Value> hNewThis = 216 v8::Local<v8::Value>::New(m_pIsolate, lpNewThisObject->m_hValue); 217 ASSERT(!hNewThis.IsEmpty()); 218 v8::Local<v8::Script> hWrapper = 219 v8::Script::Compile(v8::String::NewFromUtf8( 220 m_pIsolate, "(function () { return eval(arguments[0]); })")); 221 v8::Local<v8::Value> hWrapperValue = hWrapper->Run(); 222 ASSERT(hWrapperValue->IsFunction()); 223 v8::Local<v8::Function> hWrapperFn = hWrapperValue.As<v8::Function>(); 224 if (!trycatch.HasCaught()) { 225 v8::Local<v8::Value> rgArgs[] = {hScriptString}; 226 v8::Local<v8::Value> hValue = 227 hWrapperFn->Call(hNewThis.As<v8::Object>(), 1, rgArgs); 228 if (!trycatch.HasCaught()) { 229 if (lpRetValue) { 230 lpRetValue->m_hValue.Reset(m_pIsolate, hValue); 231 } 232 return TRUE; 233 } 234 } 235 if (lpRetValue) { 236 lpRetValue->m_hValue.Reset(m_pIsolate, 237 FXJSE_CreateReturnValue(m_pIsolate, trycatch)); 238 } 239 return FALSE; 240 } 241 } 242