blob: e5d5f994d52fa2b74e6ee4ed9c2c943e767c1d2e [file] [log] [blame]
Dan Sinclair1770c022016-03-14 14:14:16 -04001// 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/fxjse/context.h"
8
9#include "xfa/fxjse/class.h"
10#include "xfa/fxjse/scope_inline.h"
Dan Sinclair1770c022016-03-14 14:14:16 -040011#include "xfa/fxjse/value.h"
12
tsepezfb2a8242016-06-01 16:10:41 -070013namespace {
14
15const FX_CHAR szCompatibleModeScript[] =
16 "(function(global, list) {\n"
17 " 'use strict';\n"
18 " var objname;\n"
19 " for (objname in list) {\n"
20 " var globalobj = global[objname];\n"
21 " if (globalobj) {\n"
22 " list[objname].forEach(function(name) {\n"
23 " if (!globalobj[name]) {\n"
24 " Object.defineProperty(globalobj, name, {\n"
25 " writable: true,\n"
26 " enumerable: false,\n"
27 " value: (function(obj) {\n"
28 " if (arguments.length === 0) {\n"
29 " throw new TypeError('missing argument 0 when calling "
30 " function ' + objname + '.' + name);\n"
31 " }\n"
32 " return globalobj.prototype[name].apply(obj, "
33 " Array.prototype.slice.call(arguments, 1));\n"
34 " })\n"
35 " });\n"
36 " }\n"
37 " });\n"
38 " }\n"
39 " }\n"
40 "}(this, {String: ['substr', 'toUpperCase']}));";
41
42} // namespace
43
tsepez3a005f22016-05-27 17:45:00 -070044v8::Local<v8::Object> FXJSE_GetGlobalObjectFromContext(
45 const v8::Local<v8::Context>& hContext) {
46 return hContext->Global()->GetPrototype().As<v8::Object>();
47}
48
49void FXJSE_UpdateObjectBinding(v8::Local<v8::Object>& hObject,
tsepez29adee72016-05-31 14:22:09 -070050 CFXJSE_HostObject* lpNewBinding) {
tsepez3a005f22016-05-27 17:45:00 -070051 ASSERT(!hObject.IsEmpty());
52 ASSERT(hObject->InternalFieldCount() > 0);
tsepez29adee72016-05-31 14:22:09 -070053 hObject->SetAlignedPointerInInternalField(0,
54 static_cast<void*>(lpNewBinding));
tsepez3a005f22016-05-27 17:45:00 -070055}
56
tsepez29adee72016-05-31 14:22:09 -070057CFXJSE_HostObject* FXJSE_RetrieveObjectBinding(
58 const v8::Local<v8::Object>& hJSObject,
59 CFXJSE_Class* lpClass) {
tsepez3a005f22016-05-27 17:45:00 -070060 ASSERT(!hJSObject.IsEmpty());
61 if (!hJSObject->IsObject()) {
tsepez29adee72016-05-31 14:22:09 -070062 return nullptr;
tsepez3a005f22016-05-27 17:45:00 -070063 }
64 v8::Local<v8::Object> hObject = hJSObject;
65 if (hObject->InternalFieldCount() == 0) {
66 v8::Local<v8::Value> hProtoObject = hObject->GetPrototype();
67 if (hProtoObject.IsEmpty() || !hProtoObject->IsObject()) {
tsepez29adee72016-05-31 14:22:09 -070068 return nullptr;
tsepez3a005f22016-05-27 17:45:00 -070069 }
70 hObject = hProtoObject.As<v8::Object>();
71 if (hObject->InternalFieldCount() == 0) {
tsepez29adee72016-05-31 14:22:09 -070072 return nullptr;
tsepez3a005f22016-05-27 17:45:00 -070073 }
74 }
75 if (lpClass) {
76 v8::Local<v8::FunctionTemplate> hClass =
77 v8::Local<v8::FunctionTemplate>::New(
78 lpClass->GetContext()->GetRuntime(), lpClass->GetTemplate());
79 if (!hClass->HasInstance(hObject)) {
tsepez29adee72016-05-31 14:22:09 -070080 return nullptr;
tsepez3a005f22016-05-27 17:45:00 -070081 }
82 }
tsepez29adee72016-05-31 14:22:09 -070083 return static_cast<CFXJSE_HostObject*>(
84 hObject->GetAlignedPointerFromInternalField(0));
tsepez3a005f22016-05-27 17:45:00 -070085}
86
Dan Sinclair1770c022016-03-14 14:14:16 -040087v8::Local<v8::Object> FXJSE_CreateReturnValue(v8::Isolate* pIsolate,
88 v8::TryCatch& trycatch) {
89 v8::Local<v8::Object> hReturnValue = v8::Object::New(pIsolate);
90 if (trycatch.HasCaught()) {
91 v8::Local<v8::Value> hException = trycatch.Exception();
92 v8::Local<v8::Message> hMessage = trycatch.Message();
93 if (hException->IsObject()) {
94 v8::Local<v8::Value> hValue;
95 hValue = hException.As<v8::Object>()->Get(
96 v8::String::NewFromUtf8(pIsolate, "name"));
97 if (hValue->IsString() || hValue->IsStringObject()) {
98 hReturnValue->Set(0, hValue);
99 } else {
100 hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error"));
101 }
102 hValue = hException.As<v8::Object>()->Get(
103 v8::String::NewFromUtf8(pIsolate, "message"));
104 if (hValue->IsString() || hValue->IsStringObject()) {
105 hReturnValue->Set(1, hValue);
106 } else {
107 hReturnValue->Set(1, hMessage->Get());
108 }
109 } else {
110 hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error"));
111 hReturnValue->Set(1, hMessage->Get());
112 }
113 hReturnValue->Set(2, hException);
114 hReturnValue->Set(3, v8::Integer::New(pIsolate, hMessage->GetLineNumber()));
115 hReturnValue->Set(4, hMessage->GetSourceLine());
116 v8::Maybe<int32_t> maybe_int =
117 hMessage->GetStartColumn(pIsolate->GetCurrentContext());
118 hReturnValue->Set(5, v8::Integer::New(pIsolate, maybe_int.FromMaybe(0)));
119 maybe_int = hMessage->GetEndColumn(pIsolate->GetCurrentContext());
120 hReturnValue->Set(6, v8::Integer::New(pIsolate, maybe_int.FromMaybe(0)));
121 }
122 return hReturnValue;
123}
124
tsepeze3b2a4e2016-05-26 12:39:34 -0700125CFXJSE_Context* CFXJSE_Context::Create(
126 v8::Isolate* pIsolate,
127 const FXJSE_CLASS_DESCRIPTOR* lpGlobalClass,
tsepez29adee72016-05-31 14:22:09 -0700128 CFXJSE_HostObject* lpGlobalObject) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400129 CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
130 CFXJSE_Context* pContext = new CFXJSE_Context(pIsolate);
131 CFXJSE_Class* lpGlobalClassObj = NULL;
132 v8::Local<v8::ObjectTemplate> hObjectTemplate;
133 if (lpGlobalClass) {
134 lpGlobalClassObj = CFXJSE_Class::Create(pContext, lpGlobalClass, TRUE);
135 ASSERT(lpGlobalClassObj);
136 v8::Local<v8::FunctionTemplate> hFunctionTemplate =
137 v8::Local<v8::FunctionTemplate>::New(pIsolate,
138 lpGlobalClassObj->m_hTemplate);
139 hObjectTemplate = hFunctionTemplate->InstanceTemplate();
140 } else {
141 hObjectTemplate = v8::ObjectTemplate::New(pIsolate);
142 hObjectTemplate->SetInternalFieldCount(1);
143 }
144 v8::Local<v8::Context> hNewContext =
145 v8::Context::New(pIsolate, NULL, hObjectTemplate);
146 v8::Local<v8::Context> hRootContext = v8::Local<v8::Context>::New(
147 pIsolate, CFXJSE_RuntimeData::Get(pIsolate)->m_hRootContext);
148 hNewContext->SetSecurityToken(hRootContext->GetSecurityToken());
149 v8::Local<v8::Object> hGlobalObject =
150 FXJSE_GetGlobalObjectFromContext(hNewContext);
151 FXJSE_UpdateObjectBinding(hGlobalObject, lpGlobalObject);
152 pContext->m_hContext.Reset(pIsolate, hNewContext);
153 return pContext;
154}
155
tsepez56286b32016-05-17 16:24:34 -0700156CFXJSE_Context::CFXJSE_Context(v8::Isolate* pIsolate) : m_pIsolate(pIsolate) {}
dsinclair769b1372016-06-08 13:12:41 -0700157
tsepez56286b32016-05-17 16:24:34 -0700158CFXJSE_Context::~CFXJSE_Context() {}
Dan Sinclair1770c022016-03-14 14:14:16 -0400159
dsinclair3cace322016-06-09 11:49:22 -0700160std::unique_ptr<CFXJSE_Value> CFXJSE_Context::GetGlobalObject() {
161 std::unique_ptr<CFXJSE_Value> pValue(new CFXJSE_Value(m_pIsolate));
162
Dan Sinclair1770c022016-03-14 14:14:16 -0400163 CFXJSE_ScopeUtil_IsolateHandleContext scope(this);
164 v8::Local<v8::Context> hContext =
165 v8::Local<v8::Context>::New(m_pIsolate, m_hContext);
166 v8::Local<v8::Object> hGlobalObject = hContext->Global();
167 pValue->ForceSetValue(hGlobalObject);
dsinclair3cace322016-06-09 11:49:22 -0700168
169 return pValue;
Dan Sinclair1770c022016-03-14 14:14:16 -0400170}
171
dsinclair769b1372016-06-08 13:12:41 -0700172void CFXJSE_Context::EnableCompatibleMode() {
173 ExecuteScript(szCompatibleModeScript, nullptr, nullptr);
174}
175
Dan Sinclair1770c022016-03-14 14:14:16 -0400176FX_BOOL CFXJSE_Context::ExecuteScript(const FX_CHAR* szScript,
177 CFXJSE_Value* lpRetValue,
178 CFXJSE_Value* lpNewThisObject) {
179 CFXJSE_ScopeUtil_IsolateHandleContext scope(this);
180 v8::TryCatch trycatch(m_pIsolate);
181 v8::Local<v8::String> hScriptString =
182 v8::String::NewFromUtf8(m_pIsolate, szScript);
183 if (lpNewThisObject == NULL) {
184 v8::Local<v8::Script> hScript = v8::Script::Compile(hScriptString);
185 if (!trycatch.HasCaught()) {
186 v8::Local<v8::Value> hValue = hScript->Run();
187 if (!trycatch.HasCaught()) {
188 if (lpRetValue) {
189 lpRetValue->m_hValue.Reset(m_pIsolate, hValue);
190 }
191 return TRUE;
192 }
193 }
194 if (lpRetValue) {
195 lpRetValue->m_hValue.Reset(m_pIsolate,
196 FXJSE_CreateReturnValue(m_pIsolate, trycatch));
197 }
198 return FALSE;
199 } else {
200 v8::Local<v8::Value> hNewThis =
201 v8::Local<v8::Value>::New(m_pIsolate, lpNewThisObject->m_hValue);
202 ASSERT(!hNewThis.IsEmpty());
203 v8::Local<v8::Script> hWrapper =
204 v8::Script::Compile(v8::String::NewFromUtf8(
205 m_pIsolate, "(function () { return eval(arguments[0]); })"));
206 v8::Local<v8::Value> hWrapperValue = hWrapper->Run();
207 ASSERT(hWrapperValue->IsFunction());
208 v8::Local<v8::Function> hWrapperFn = hWrapperValue.As<v8::Function>();
209 if (!trycatch.HasCaught()) {
210 v8::Local<v8::Value> rgArgs[] = {hScriptString};
211 v8::Local<v8::Value> hValue =
212 hWrapperFn->Call(hNewThis.As<v8::Object>(), 1, rgArgs);
213 if (!trycatch.HasCaught()) {
214 if (lpRetValue) {
215 lpRetValue->m_hValue.Reset(m_pIsolate, hValue);
216 }
217 return TRUE;
218 }
219 }
220 if (lpRetValue) {
221 lpRetValue->m_hValue.Reset(m_pIsolate,
222 FXJSE_CreateReturnValue(m_pIsolate, trycatch));
223 }
224 return FALSE;
225 }
226}