Home | History | Annotate | Download | only in src
      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