Home | History | Annotate | Download | only in fpdfxfa
      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/fpdfxfa/cpdfxfa_context.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 
     12 #include "core/fpdfapi/parser/cpdf_document.h"
     13 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
     14 #include "fpdfsdk/cpdfsdk_interform.h"
     15 #include "fpdfsdk/cpdfsdk_pageview.h"
     16 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
     17 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h"
     18 #include "fpdfsdk/fsdk_define.h"
     19 #include "fxjs/cjs_runtime.h"
     20 #include "fxjs/ijs_runtime.h"
     21 #include "public/fpdf_formfill.h"
     22 #include "third_party/base/ptr_util.h"
     23 #include "third_party/base/stl_util.h"
     24 #include "xfa/fgas/font/cfgas_defaultfontmanager.h"
     25 #include "xfa/fxfa/cxfa_eventparam.h"
     26 #include "xfa/fxfa/cxfa_ffapp.h"
     27 #include "xfa/fxfa/cxfa_ffdoc.h"
     28 #include "xfa/fxfa/cxfa_ffdocview.h"
     29 #include "xfa/fxfa/cxfa_ffpageview.h"
     30 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
     31 #include "xfa/fxfa/cxfa_fontmgr.h"
     32 
     33 #ifndef _WIN32
     34 extern void SetLastError(int err);
     35 extern int GetLastError();
     36 #endif
     37 
     38 CPDFXFA_Context::CPDFXFA_Context(std::unique_ptr<CPDF_Document> pPDFDoc)
     39     : m_pPDFDoc(std::move(pPDFDoc)),
     40       m_pXFAApp(pdfium::MakeUnique<CXFA_FFApp>(this)),
     41       m_DocEnv(this) {
     42   m_pXFAApp->SetDefaultFontMgr(pdfium::MakeUnique<CFGAS_DefaultFontManager>());
     43 }
     44 
     45 CPDFXFA_Context::~CPDFXFA_Context() {
     46   m_nLoadStatus = FXFA_LOADSTATUS_CLOSING;
     47 
     48   // Must happen before we remove the form fill environment.
     49   CloseXFADoc();
     50 
     51   if (m_pFormFillEnv) {
     52     m_pFormFillEnv->ClearAllFocusedAnnots();
     53     // Once we're deleted the FormFillEnvironment will point at a bad underlying
     54     // doc so we need to reset it ...
     55     m_pFormFillEnv->ResetXFADocument();
     56     m_pFormFillEnv.Reset();
     57   }
     58 
     59   m_nLoadStatus = FXFA_LOADSTATUS_CLOSED;
     60 }
     61 
     62 void CPDFXFA_Context::CloseXFADoc() {
     63   if (!m_pXFADoc)
     64     return;
     65 
     66   m_pXFADocView = nullptr;
     67   m_pXFADoc->CloseDoc();
     68   m_pXFADoc.reset();
     69 }
     70 
     71 void CPDFXFA_Context::SetFormFillEnv(
     72     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
     73   // The layout data can have pointers back into the script context. That
     74   // context will be different if the form fill environment closes, so, force
     75   // the layout data to clear.
     76   if (m_pXFADoc && m_pXFADoc->GetXFADoc())
     77     m_pXFADoc->GetXFADoc()->ClearLayoutData();
     78 
     79   m_pFormFillEnv.Reset(pFormFillEnv);
     80 }
     81 
     82 bool CPDFXFA_Context::LoadXFADoc() {
     83   m_nLoadStatus = FXFA_LOADSTATUS_LOADING;
     84   if (!m_pPDFDoc)
     85     return false;
     86 
     87   m_XFAPageList.clear();
     88 
     89   CXFA_FFApp* pApp = GetXFAApp();
     90   if (!pApp)
     91     return false;
     92 
     93   m_pXFADoc = pApp->CreateDoc(&m_DocEnv, m_pPDFDoc.get());
     94   if (!m_pXFADoc) {
     95     SetLastError(FPDF_ERR_XFALOAD);
     96     return false;
     97   }
     98 
     99   m_pXFADoc->StartLoad();
    100   int iStatus = m_pXFADoc->DoLoad();
    101   if (iStatus != XFA_PARSESTATUS_Done) {
    102     CloseXFADoc();
    103     SetLastError(FPDF_ERR_XFALOAD);
    104     return false;
    105   }
    106   m_pXFADoc->StopLoad();
    107   m_pXFADoc->GetXFADoc()->InitScriptContext(GetJSERuntime());
    108 
    109   if (m_pXFADoc->GetFormType() == FormType::kXFAFull)
    110     m_FormType = FormType::kXFAFull;
    111   else
    112     m_FormType = FormType::kXFAForeground;
    113 
    114   m_pXFADocView = m_pXFADoc->CreateDocView();
    115   if (m_pXFADocView->StartLayout() < 0) {
    116     CloseXFADoc();
    117     SetLastError(FPDF_ERR_XFALAYOUT);
    118     return false;
    119   }
    120 
    121   m_pXFADocView->DoLayout();
    122   m_pXFADocView->StopLayout();
    123   m_nLoadStatus = FXFA_LOADSTATUS_LOADED;
    124 
    125   return true;
    126 }
    127 
    128 int CPDFXFA_Context::GetPageCount() const {
    129   if (!m_pPDFDoc && !m_pXFADoc)
    130     return 0;
    131 
    132   switch (m_FormType) {
    133     case FormType::kNone:
    134     case FormType::kAcroForm:
    135     case FormType::kXFAForeground:
    136       if (m_pPDFDoc)
    137         return m_pPDFDoc->GetPageCount();
    138     case FormType::kXFAFull:
    139       if (m_pXFADoc)
    140         return m_pXFADocView->CountPageViews();
    141   }
    142   return 0;
    143 }
    144 
    145 RetainPtr<CPDFXFA_Page> CPDFXFA_Context::GetXFAPage(int page_index) {
    146   if (page_index < 0)
    147     return nullptr;
    148 
    149   if (pdfium::IndexInBounds(m_XFAPageList, page_index)) {
    150     if (m_XFAPageList[page_index])
    151       return m_XFAPageList[page_index];
    152   } else {
    153     m_nPageCount = GetPageCount();
    154     m_XFAPageList.resize(m_nPageCount);
    155   }
    156 
    157   auto pPage = pdfium::MakeRetain<CPDFXFA_Page>(this, page_index);
    158   if (!pPage->LoadPage())
    159     return nullptr;
    160 
    161   if (pdfium::IndexInBounds(m_XFAPageList, page_index))
    162     m_XFAPageList[page_index] = pPage;
    163 
    164   return pPage;
    165 }
    166 
    167 RetainPtr<CPDFXFA_Page> CPDFXFA_Context::GetXFAPage(
    168     CXFA_FFPageView* pPage) const {
    169   if (!pPage)
    170     return nullptr;
    171 
    172   if (!m_pXFADoc)
    173     return nullptr;
    174 
    175   if (m_FormType != FormType::kXFAFull)
    176     return nullptr;
    177 
    178   for (auto& pTempPage : m_XFAPageList) {
    179     if (pTempPage && pTempPage->GetXFAPageView() == pPage)
    180       return pTempPage;
    181   }
    182   return nullptr;
    183 }
    184 
    185 void CPDFXFA_Context::DeletePage(int page_index) {
    186   // Delete from the document first because, if GetPage was never called for
    187   // this |page_index| then |m_XFAPageList| may have size < |page_index| even
    188   // if it's a valid page in the document.
    189   if (m_pPDFDoc)
    190     m_pPDFDoc->DeletePage(page_index);
    191 
    192   if (pdfium::IndexInBounds(m_XFAPageList, page_index))
    193     m_XFAPageList[page_index].Reset();
    194 }
    195 
    196 void CPDFXFA_Context::ClearChangeMark() {
    197   if (m_pFormFillEnv)
    198     m_pFormFillEnv->ClearChangeMark();
    199 }
    200 
    201 v8::Isolate* CPDFXFA_Context::GetJSERuntime() const {
    202   if (!m_pFormFillEnv)
    203     return nullptr;
    204 
    205   // XFA requires V8, if we have V8 then we have a CJS_Runtime and not the stub.
    206   CJS_Runtime* runtime =
    207       static_cast<CJS_Runtime*>(m_pFormFillEnv->GetJSRuntime());
    208   return runtime->GetIsolate();
    209 }
    210 
    211 WideString CPDFXFA_Context::GetAppTitle() const {
    212   return L"PDFium";
    213 }
    214 
    215 WideString CPDFXFA_Context::GetAppName() {
    216   return m_pFormFillEnv ? m_pFormFillEnv->FFI_GetAppName() : L"";
    217 }
    218 
    219 WideString CPDFXFA_Context::GetLanguage() {
    220   return m_pFormFillEnv ? m_pFormFillEnv->GetLanguage() : L"";
    221 }
    222 
    223 WideString CPDFXFA_Context::GetPlatform() {
    224   return m_pFormFillEnv ? m_pFormFillEnv->GetPlatform() : L"";
    225 }
    226 
    227 void CPDFXFA_Context::Beep(uint32_t dwType) {
    228   if (m_pFormFillEnv)
    229     m_pFormFillEnv->JS_appBeep(dwType);
    230 }
    231 
    232 int32_t CPDFXFA_Context::MsgBox(const WideString& wsMessage,
    233                                 const WideString& wsTitle,
    234                                 uint32_t dwIconType,
    235                                 uint32_t dwButtonType) {
    236   if (!m_pFormFillEnv)
    237     return -1;
    238 
    239   uint32_t iconType = 0;
    240   int iButtonType = 0;
    241   switch (dwIconType) {
    242     case XFA_MBICON_Error:
    243       iconType |= 0;
    244       break;
    245     case XFA_MBICON_Warning:
    246       iconType |= 1;
    247       break;
    248     case XFA_MBICON_Question:
    249       iconType |= 2;
    250       break;
    251     case XFA_MBICON_Status:
    252       iconType |= 3;
    253       break;
    254   }
    255   switch (dwButtonType) {
    256     case XFA_MB_OK:
    257       iButtonType |= 0;
    258       break;
    259     case XFA_MB_OKCancel:
    260       iButtonType |= 1;
    261       break;
    262     case XFA_MB_YesNo:
    263       iButtonType |= 2;
    264       break;
    265     case XFA_MB_YesNoCancel:
    266       iButtonType |= 3;
    267       break;
    268   }
    269   int32_t iRet = m_pFormFillEnv->JS_appAlert(wsMessage.c_str(), wsTitle.c_str(),
    270                                              iButtonType, iconType);
    271   switch (iRet) {
    272     case 1:
    273       return XFA_IDOK;
    274     case 2:
    275       return XFA_IDCancel;
    276     case 3:
    277       return XFA_IDNo;
    278     case 4:
    279       return XFA_IDYes;
    280   }
    281   return XFA_IDYes;
    282 }
    283 
    284 WideString CPDFXFA_Context::Response(const WideString& wsQuestion,
    285                                      const WideString& wsTitle,
    286                                      const WideString& wsDefaultAnswer,
    287                                      bool bMark) {
    288   if (!m_pFormFillEnv)
    289     return WideString();
    290 
    291   int nLength = 2048;
    292   std::vector<uint8_t> pBuff(nLength);
    293   nLength = m_pFormFillEnv->JS_appResponse(wsQuestion.c_str(), wsTitle.c_str(),
    294                                            wsDefaultAnswer.c_str(), nullptr,
    295                                            bMark, pBuff.data(), nLength);
    296   if (nLength <= 0)
    297     return WideString();
    298 
    299   nLength = std::min(2046, nLength);
    300   pBuff[nLength] = 0;
    301   pBuff[nLength + 1] = 0;
    302   return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()),
    303                                  nLength / sizeof(uint16_t));
    304 }
    305 
    306 RetainPtr<IFX_SeekableReadStream> CPDFXFA_Context::DownloadURL(
    307     const WideString& wsURL) {
    308   return m_pFormFillEnv ? m_pFormFillEnv->DownloadFromURL(wsURL.c_str())
    309                         : nullptr;
    310 }
    311 
    312 bool CPDFXFA_Context::PostRequestURL(const WideString& wsURL,
    313                                      const WideString& wsData,
    314                                      const WideString& wsContentType,
    315                                      const WideString& wsEncode,
    316                                      const WideString& wsHeader,
    317                                      WideString& wsResponse) {
    318   if (!m_pFormFillEnv)
    319     return false;
    320 
    321   wsResponse = m_pFormFillEnv->PostRequestURL(
    322       wsURL.c_str(), wsData.c_str(), wsContentType.c_str(), wsEncode.c_str(),
    323       wsHeader.c_str());
    324   return true;
    325 }
    326 
    327 bool CPDFXFA_Context::PutRequestURL(const WideString& wsURL,
    328                                     const WideString& wsData,
    329                                     const WideString& wsEncode) {
    330   return m_pFormFillEnv &&
    331          m_pFormFillEnv->PutRequestURL(wsURL.c_str(), wsData.c_str(),
    332                                        wsEncode.c_str());
    333 }
    334 
    335 IFWL_AdapterTimerMgr* CPDFXFA_Context::GetTimerMgr() {
    336   CXFA_FWLAdapterTimerMgr* pAdapter = nullptr;
    337   if (m_pFormFillEnv)
    338     pAdapter = new CXFA_FWLAdapterTimerMgr(m_pFormFillEnv.Get());
    339   return pAdapter;
    340 }
    341