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