• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CPDFXFA_Context(std::unique_ptr<CPDF_Document> pPDFDoc)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 
~CPDFXFA_Context()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 
CloseXFADoc()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 
SetFormFillEnv(CPDFSDK_FormFillEnvironment * pFormFillEnv)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 
LoadXFADoc()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 
GetPageCount() const136 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 
GetXFAPage(int page_index)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 
GetXFAPage(CXFA_FFPageView * pPage) const182 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 
DeletePage(int page_index)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 
RemovePage(CPDFXFA_Page * page)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 
ClearChangeMark()222 void CPDFXFA_Context::ClearChangeMark() {
223   if (m_pFormFillEnv)
224     m_pFormFillEnv->ClearChangeMark();
225 }
226 
GetJSERuntime() const227 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 
GetAppTitle() const237 CFX_WideString CPDFXFA_Context::GetAppTitle() const {
238   return L"PDFium";
239 }
240 
GetAppName()241 CFX_WideString CPDFXFA_Context::GetAppName() {
242   return m_pFormFillEnv ? m_pFormFillEnv->FFI_GetAppName() : L"";
243 }
244 
GetLanguage()245 CFX_WideString CPDFXFA_Context::GetLanguage() {
246   return m_pFormFillEnv ? m_pFormFillEnv->GetLanguage() : L"";
247 }
248 
GetPlatform()249 CFX_WideString CPDFXFA_Context::GetPlatform() {
250   return m_pFormFillEnv ? m_pFormFillEnv->GetPlatform() : L"";
251 }
252 
Beep(uint32_t dwType)253 void CPDFXFA_Context::Beep(uint32_t dwType) {
254   if (m_pFormFillEnv)
255     m_pFormFillEnv->JS_appBeep(dwType);
256 }
257 
MsgBox(const CFX_WideString & wsMessage,const CFX_WideString & wsTitle,uint32_t dwIconType,uint32_t dwButtonType)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 
Response(const CFX_WideString & wsQuestion,const CFX_WideString & wsTitle,const CFX_WideString & wsDefaultAnswer,bool bMark)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 
DownloadURL(const CFX_WideString & wsURL)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 
PostRequestURL(const CFX_WideString & wsURL,const CFX_WideString & wsData,const CFX_WideString & wsContentType,const CFX_WideString & wsEncode,const CFX_WideString & wsHeader,CFX_WideString & wsResponse)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 
PutRequestURL(const CFX_WideString & wsURL,const CFX_WideString & wsData,const CFX_WideString & wsEncode)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 
GetTimerMgr()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