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