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"
FXJSE_Context_Create(FXJSE_HRUNTIME hRuntime,const FXJSE_CLASS * lpGlobalClass,void * lpGlobalObject)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 }
FXJSE_Context_Release(FXJSE_HCONTEXT hContext)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 }
FXJSE_Context_GetGlobalObject(FXJSE_HCONTEXT hContext)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 }
FXJSE_Context_GetRuntime(FXJSE_HCONTEXT hContext)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 };
FXJSE_Context_EnableCompatibleMode(FXJSE_HCONTEXT hContext,FX_DWORD dwCompatibleFlags)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 }
FXJSE_ExecuteScript(FXJSE_HCONTEXT hContext,const FX_CHAR * szScript,FXJSE_HVALUE hRetValue,FXJSE_HVALUE hNewThisObject)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 }
FXJSE_CreateReturnValue(v8::Isolate * pIsolate,v8::TryCatch & trycatch)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 }
FXJSE_ReturnValue_GetMessage(FXJSE_HVALUE hRetValue,CFX_ByteString & utf8Name,CFX_ByteString & utf8Message)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 }
FXJSE_ReturnValue_GetLineInfo(FXJSE_HVALUE hRetValue,int32_t & nLine,int32_t & nCol)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 }
Create(v8::Isolate * pIsolate,const FXJSE_CLASS * lpGlobalClass,void * lpGlobalObject)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 }
~CFXJSE_Context()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 }
GetGlobalObject(CFXJSE_Value * pValue)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 }
ExecuteScript(const FX_CHAR * szScript,CFXJSE_Value * lpRetValue,CFXJSE_Value * lpNewThisObject)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