• 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 <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 
CPDFXFA_Context(std::unique_ptr<CPDF_Document> pPDFDoc)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 
~CPDFXFA_Context()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 
CloseXFADoc()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 
SetFormFillEnv(CPDFSDK_FormFillEnvironment * pFormFillEnv)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 
LoadXFADoc()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 
GetPageCount() const128 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 
GetXFAPage(int page_index)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 
GetXFAPage(CXFA_FFPageView * pPage) const167 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 
DeletePage(int page_index)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 
ClearChangeMark()196 void CPDFXFA_Context::ClearChangeMark() {
197   if (m_pFormFillEnv)
198     m_pFormFillEnv->ClearChangeMark();
199 }
200 
GetJSERuntime() const201 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 
GetAppTitle() const211 WideString CPDFXFA_Context::GetAppTitle() const {
212   return L"PDFium";
213 }
214 
GetAppName()215 WideString CPDFXFA_Context::GetAppName() {
216   return m_pFormFillEnv ? m_pFormFillEnv->FFI_GetAppName() : L"";
217 }
218 
GetLanguage()219 WideString CPDFXFA_Context::GetLanguage() {
220   return m_pFormFillEnv ? m_pFormFillEnv->GetLanguage() : L"";
221 }
222 
GetPlatform()223 WideString CPDFXFA_Context::GetPlatform() {
224   return m_pFormFillEnv ? m_pFormFillEnv->GetPlatform() : L"";
225 }
226 
Beep(uint32_t dwType)227 void CPDFXFA_Context::Beep(uint32_t dwType) {
228   if (m_pFormFillEnv)
229     m_pFormFillEnv->JS_appBeep(dwType);
230 }
231 
MsgBox(const WideString & wsMessage,const WideString & wsTitle,uint32_t dwIconType,uint32_t dwButtonType)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 
Response(const WideString & wsQuestion,const WideString & wsTitle,const WideString & wsDefaultAnswer,bool bMark)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 
DownloadURL(const WideString & wsURL)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 
PostRequestURL(const WideString & wsURL,const WideString & wsData,const WideString & wsContentType,const WideString & wsEncode,const WideString & wsHeader,WideString & wsResponse)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 
PutRequestURL(const WideString & wsURL,const WideString & wsData,const WideString & wsEncode)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 
GetTimerMgr()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