Home | History | Annotate | Download | only in javascript
      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 "fpdfsdk/javascript/cjs_runtime.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
     12 #include "fpdfsdk/javascript/Annot.h"
     13 #include "fpdfsdk/javascript/Consts.h"
     14 #include "fpdfsdk/javascript/Document.h"
     15 #include "fpdfsdk/javascript/Field.h"
     16 #include "fpdfsdk/javascript/Icon.h"
     17 #include "fpdfsdk/javascript/JS_Define.h"
     18 #include "fpdfsdk/javascript/JS_EventHandler.h"
     19 #include "fpdfsdk/javascript/JS_GlobalData.h"
     20 #include "fpdfsdk/javascript/JS_Object.h"
     21 #include "fpdfsdk/javascript/JS_Value.h"
     22 #include "fpdfsdk/javascript/PublicMethods.h"
     23 #include "fpdfsdk/javascript/app.h"
     24 #include "fpdfsdk/javascript/cjs_event_context.h"
     25 #include "fpdfsdk/javascript/color.h"
     26 #include "fpdfsdk/javascript/console.h"
     27 #include "fpdfsdk/javascript/event.h"
     28 #include "fpdfsdk/javascript/global.h"
     29 #include "fpdfsdk/javascript/report.h"
     30 #include "fpdfsdk/javascript/util.h"
     31 #include "public/fpdf_formfill.h"
     32 #include "third_party/base/stl_util.h"
     33 
     34 #ifdef PDF_ENABLE_XFA
     35 #include "fxjs/cfxjse_value.h"
     36 #endif  // PDF_ENABLE_XFA
     37 
     38 // static
     39 void IJS_Runtime::Initialize(unsigned int slot, void* isolate) {
     40   FXJS_Initialize(slot, reinterpret_cast<v8::Isolate*>(isolate));
     41 }
     42 
     43 // static
     44 void IJS_Runtime::Destroy() {
     45   FXJS_Release();
     46 }
     47 
     48 // static
     49 IJS_Runtime* IJS_Runtime::Create(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
     50   return new CJS_Runtime(pFormFillEnv);
     51 }
     52 
     53 // static
     54 CJS_Runtime* CJS_Runtime::CurrentRuntimeFromIsolate(v8::Isolate* pIsolate) {
     55   return static_cast<CJS_Runtime*>(
     56       CFXJS_Engine::CurrentEngineFromIsolate(pIsolate));
     57 }
     58 
     59 CJS_Runtime::CJS_Runtime(CPDFSDK_FormFillEnvironment* pFormFillEnv)
     60     : m_pFormFillEnv(pFormFillEnv),
     61       m_bBlocking(false),
     62       m_isolateManaged(false) {
     63   v8::Isolate* pIsolate = nullptr;
     64 
     65   IPDF_JSPLATFORM* pPlatform = m_pFormFillEnv->GetFormFillInfo()->m_pJsPlatform;
     66   if (pPlatform->version <= 2) {
     67     unsigned int embedderDataSlot = 0;
     68     v8::Isolate* pExternalIsolate = nullptr;
     69     if (pPlatform->version == 2) {
     70       pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate);
     71       embedderDataSlot = pPlatform->m_v8EmbedderSlot;
     72     }
     73     FXJS_Initialize(embedderDataSlot, pExternalIsolate);
     74   }
     75   m_isolateManaged = FXJS_GetIsolate(&pIsolate);
     76   SetIsolate(pIsolate);
     77 
     78 #ifdef PDF_ENABLE_XFA
     79   v8::Isolate::Scope isolate_scope(pIsolate);
     80   v8::HandleScope handle_scope(pIsolate);
     81 #endif
     82 
     83   if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
     84     DefineJSObjects();
     85 
     86   IJS_EventContext* pContext = NewEventContext();
     87   InitializeEngine();
     88   ReleaseEventContext(pContext);
     89   SetFormFillEnvToDocument();
     90 }
     91 
     92 CJS_Runtime::~CJS_Runtime() {
     93   NotifyObservedPtrs();
     94   ReleaseEngine();
     95   if (m_isolateManaged) {
     96     GetIsolate()->Dispose();
     97     SetIsolate(nullptr);
     98   }
     99 }
    100 
    101 void CJS_Runtime::DefineJSObjects() {
    102   v8::Isolate::Scope isolate_scope(GetIsolate());
    103   v8::HandleScope handle_scope(GetIsolate());
    104   v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
    105   v8::Context::Scope context_scope(context);
    106 
    107   // The call order determines the "ObjDefID" assigned to each class.
    108   // ObjDefIDs 0 - 2
    109   CJS_Border::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    110   CJS_Display::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    111   CJS_Font::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    112 
    113   // ObjDefIDs 3 - 5
    114   CJS_Highlight::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    115   CJS_Position::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    116   CJS_ScaleHow::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    117 
    118   // ObjDefIDs 6 - 8
    119   CJS_ScaleWhen::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    120   CJS_Style::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    121   CJS_Zoomtype::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    122 
    123   // ObjDefIDs 9 - 11
    124   CJS_App::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    125   CJS_Color::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    126   CJS_Console::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    127 
    128   // ObjDefIDs 12 - 14
    129   CJS_Document::DefineJSObjects(this, FXJSOBJTYPE_GLOBAL);
    130   CJS_Event::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    131   CJS_Field::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
    132 
    133   // ObjDefIDs 15 - 17
    134   CJS_Global::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    135   CJS_Icon::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
    136   CJS_Util::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
    137 
    138   // ObjDefIDs 18 - 20 (these can't fail, return void).
    139   CJS_PublicMethods::DefineJSObjects(this);
    140   CJS_GlobalConsts::DefineJSObjects(this);
    141   CJS_GlobalArrays::DefineJSObjects(this);
    142 
    143   // ObjDefIDs 21 - 23.
    144   CJS_TimerObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
    145   CJS_PrintParamsObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
    146   CJS_Annot::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
    147 }
    148 
    149 IJS_EventContext* CJS_Runtime::NewEventContext() {
    150   m_EventContextArray.push_back(
    151       std::unique_ptr<CJS_EventContext>(new CJS_EventContext(this)));
    152   return m_EventContextArray.back().get();
    153 }
    154 
    155 void CJS_Runtime::ReleaseEventContext(IJS_EventContext* pContext) {
    156   auto it = std::find(m_EventContextArray.begin(), m_EventContextArray.end(),
    157                       pdfium::FakeUniquePtr<CJS_EventContext>(
    158                           static_cast<CJS_EventContext*>(pContext)));
    159   if (it != m_EventContextArray.end())
    160     m_EventContextArray.erase(it);
    161 }
    162 
    163 CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
    164   return m_EventContextArray.empty() ? nullptr
    165                                      : m_EventContextArray.back().get();
    166 }
    167 
    168 void CJS_Runtime::SetFormFillEnvToDocument() {
    169   v8::Isolate::Scope isolate_scope(GetIsolate());
    170   v8::HandleScope handle_scope(GetIsolate());
    171   v8::Local<v8::Context> context = NewLocalContext();
    172   v8::Context::Scope context_scope(context);
    173 
    174   v8::Local<v8::Object> pThis = GetThisObj();
    175   if (pThis.IsEmpty())
    176     return;
    177 
    178   if (CFXJS_Engine::GetObjDefnID(pThis) != CJS_Document::g_nObjDefnID)
    179     return;
    180 
    181   CJS_Document* pJSDocument =
    182       static_cast<CJS_Document*>(GetObjectPrivate(pThis));
    183   if (!pJSDocument)
    184     return;
    185 
    186   Document* pDocument = static_cast<Document*>(pJSDocument->GetEmbedObject());
    187   if (!pDocument)
    188     return;
    189 
    190   pDocument->SetFormFillEnv(m_pFormFillEnv.Get());
    191 }
    192 
    193 CPDFSDK_FormFillEnvironment* CJS_Runtime::GetFormFillEnv() const {
    194   return m_pFormFillEnv.Get();
    195 }
    196 
    197 int CJS_Runtime::ExecuteScript(const CFX_WideString& script,
    198                                CFX_WideString* info) {
    199   FXJSErr error = {};
    200   int nRet = Execute(script, &error);
    201   if (nRet < 0) {
    202     info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline,
    203                  error.message);
    204   }
    205   return nRet;
    206 }
    207 
    208 bool CJS_Runtime::AddEventToSet(const FieldEvent& event) {
    209   return m_FieldEventSet.insert(event).second;
    210 }
    211 
    212 void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) {
    213   m_FieldEventSet.erase(event);
    214 }
    215 
    216 #ifdef PDF_ENABLE_XFA
    217 CFX_WideString ChangeObjName(const CFX_WideString& str) {
    218   CFX_WideString sRet = str;
    219   sRet.Replace(L"_", L".");
    220   return sRet;
    221 }
    222 bool CJS_Runtime::GetValueByName(const CFX_ByteStringC& utf8Name,
    223                                  CFXJSE_Value* pValue) {
    224   const FX_CHAR* name = utf8Name.c_str();
    225 
    226   v8::Isolate::Scope isolate_scope(GetIsolate());
    227   v8::HandleScope handle_scope(GetIsolate());
    228   v8::Local<v8::Context> context = NewLocalContext();
    229   v8::Context::Scope context_scope(context);
    230 
    231   v8::Local<v8::Value> propvalue =
    232       context->Global()->Get(v8::String::NewFromUtf8(
    233           GetIsolate(), name, v8::String::kNormalString, utf8Name.GetLength()));
    234 
    235   if (propvalue.IsEmpty()) {
    236     pValue->SetUndefined();
    237     return false;
    238   }
    239   pValue->ForceSetValue(propvalue);
    240   return true;
    241 }
    242 bool CJS_Runtime::SetValueByName(const CFX_ByteStringC& utf8Name,
    243                                  CFXJSE_Value* pValue) {
    244   if (utf8Name.IsEmpty() || !pValue)
    245     return false;
    246   const FX_CHAR* name = utf8Name.c_str();
    247   v8::Isolate* pIsolate = GetIsolate();
    248   v8::Isolate::Scope isolate_scope(pIsolate);
    249   v8::HandleScope handle_scope(pIsolate);
    250   v8::Local<v8::Context> context = NewLocalContext();
    251   v8::Context::Scope context_scope(context);
    252 
    253   // v8::Local<v8::Context> tmpCotext =
    254   // v8::Local<v8::Context>::New(GetIsolate(), m_context);
    255   v8::Local<v8::Value> propvalue =
    256       v8::Local<v8::Value>::New(GetIsolate(), pValue->DirectGetValue());
    257   context->Global()->Set(
    258       v8::String::NewFromUtf8(pIsolate, name, v8::String::kNormalString,
    259                               utf8Name.GetLength()),
    260       propvalue);
    261   return true;
    262 }
    263 #endif
    264