OLD | NEW |
| (Empty) |
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_document.h" | |
8 | |
9 #include "core/fpdfapi/parser/cpdf_document.h" | |
10 #include "fpdfsdk/cpdfsdk_formfillenvironment.h" | |
11 #include "fpdfsdk/cpdfsdk_interform.h" | |
12 #include "fpdfsdk/cpdfsdk_pageview.h" | |
13 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h" | |
14 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h" | |
15 #include "fpdfsdk/fsdk_define.h" | |
16 #include "fpdfsdk/javascript/cjs_runtime.h" | |
17 #include "fpdfsdk/javascript/ijs_runtime.h" | |
18 #include "public/fpdf_formfill.h" | |
19 #include "third_party/base/ptr_util.h" | |
20 #include "xfa/fxfa/cxfa_eventparam.h" | |
21 #include "xfa/fxfa/xfa_ffapp.h" | |
22 #include "xfa/fxfa/xfa_ffdoc.h" | |
23 #include "xfa/fxfa/xfa_ffdocview.h" | |
24 #include "xfa/fxfa/xfa_ffpageview.h" | |
25 #include "xfa/fxfa/xfa_ffwidgethandler.h" | |
26 #include "xfa/fxfa/xfa_fontmgr.h" | |
27 | |
28 #ifndef _WIN32 | |
29 extern void SetLastError(int err); | |
30 extern int GetLastError(); | |
31 #endif | |
32 | |
33 CPDFXFA_Document::CPDFXFA_Document(std::unique_ptr<CPDF_Document> pPDFDoc) | |
34 : m_iDocType(DOCTYPE_PDF), | |
35 m_pPDFDoc(std::move(pPDFDoc)), | |
36 m_pFormFillEnv(nullptr), | |
37 m_pXFADocView(nullptr), | |
38 m_nLoadStatus(FXFA_LOADSTATUS_PRELOAD), | |
39 m_nPageCount(0), | |
40 m_DocEnv(this) { | |
41 m_pXFAApp = pdfium::MakeUnique<CXFA_FFApp>(this); | |
42 m_pXFAApp->SetDefaultFontMgr(pdfium::MakeUnique<CXFA_DefFontMgr>()); | |
43 } | |
44 | |
45 CPDFXFA_Document::~CPDFXFA_Document() { | |
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 = nullptr; | |
57 } | |
58 | |
59 m_nLoadStatus = FXFA_LOADSTATUS_CLOSED; | |
60 } | |
61 | |
62 void CPDFXFA_Document::CloseXFADoc() { | |
63 if (!m_pXFADoc) | |
64 return; | |
65 m_pXFADoc->CloseDoc(); | |
66 m_pXFADoc.reset(); | |
67 m_pXFADocView = nullptr; | |
68 } | |
69 | |
70 void CPDFXFA_Document::SetFormFillEnv( | |
71 CPDFSDK_FormFillEnvironment* pFormFillEnv) { | |
72 // The layout data can have pointers back into the script context. That | |
73 // context will be different if the form fill environment closes, so, force | |
74 // the layout data to clear. | |
75 if (m_pXFADoc && m_pXFADoc->GetXFADoc()) | |
76 m_pXFADoc->GetXFADoc()->ClearLayoutData(); | |
77 | |
78 m_pFormFillEnv = pFormFillEnv; | |
79 } | |
80 | |
81 FX_BOOL CPDFXFA_Document::LoadXFADoc() { | |
82 m_nLoadStatus = FXFA_LOADSTATUS_LOADING; | |
83 | |
84 if (!m_pPDFDoc) | |
85 return FALSE; | |
86 | |
87 m_XFAPageList.RemoveAll(); | |
88 | |
89 CXFA_FFApp* pApp = GetXFAApp(); | |
90 if (!pApp) | |
91 return FALSE; | |
92 | |
93 m_pXFADoc.reset(pApp->CreateDoc(&m_DocEnv, m_pPDFDoc.get())); | |
94 if (!m_pXFADoc) { | |
95 SetLastError(FPDF_ERR_XFALOAD); | |
96 return FALSE; | |
97 } | |
98 | |
99 CXFA_FFDocHandler* pDocHandler = pApp->GetDocHandler(); | |
100 if (!pDocHandler) { | |
101 SetLastError(FPDF_ERR_XFALOAD); | |
102 return FALSE; | |
103 } | |
104 | |
105 m_pXFADoc->StartLoad(); | |
106 int iStatus = m_pXFADoc->DoLoad(nullptr); | |
107 if (iStatus != XFA_PARSESTATUS_Done) { | |
108 CloseXFADoc(); | |
109 SetLastError(FPDF_ERR_XFALOAD); | |
110 return FALSE; | |
111 } | |
112 m_pXFADoc->StopLoad(); | |
113 m_pXFADoc->GetXFADoc()->InitScriptContext(GetJSERuntime()); | |
114 | |
115 if (m_pXFADoc->GetDocType() == XFA_DOCTYPE_Dynamic) | |
116 m_iDocType = DOCTYPE_DYNAMIC_XFA; | |
117 else | |
118 m_iDocType = DOCTYPE_STATIC_XFA; | |
119 | |
120 m_pXFADocView = m_pXFADoc->CreateDocView(XFA_DOCVIEW_View); | |
121 if (m_pXFADocView->StartLayout() < 0) { | |
122 CloseXFADoc(); | |
123 SetLastError(FPDF_ERR_XFALAYOUT); | |
124 return FALSE; | |
125 } | |
126 | |
127 m_pXFADocView->DoLayout(nullptr); | |
128 m_pXFADocView->StopLayout(); | |
129 m_nLoadStatus = FXFA_LOADSTATUS_LOADED; | |
130 | |
131 return TRUE; | |
132 } | |
133 | |
134 int CPDFXFA_Document::GetPageCount() const { | |
135 if (!m_pPDFDoc && !m_pXFADoc) | |
136 return 0; | |
137 | |
138 switch (m_iDocType) { | |
139 case DOCTYPE_PDF: | |
140 case DOCTYPE_STATIC_XFA: | |
141 if (m_pPDFDoc) | |
142 return m_pPDFDoc->GetPageCount(); | |
143 case DOCTYPE_DYNAMIC_XFA: | |
144 if (m_pXFADoc) | |
145 return m_pXFADocView->CountPageViews(); | |
146 default: | |
147 return 0; | |
148 } | |
149 } | |
150 | |
151 CPDFXFA_Page* CPDFXFA_Document::GetXFAPage(int page_index) { | |
152 if (page_index < 0) | |
153 return nullptr; | |
154 | |
155 CPDFXFA_Page* pPage = nullptr; | |
156 int nCount = m_XFAPageList.GetSize(); | |
157 if (nCount > 0 && page_index < nCount) { | |
158 pPage = m_XFAPageList.GetAt(page_index); | |
159 if (pPage) | |
160 pPage->Retain(); | |
161 } else { | |
162 m_nPageCount = GetPageCount(); | |
163 m_XFAPageList.SetSize(m_nPageCount); | |
164 } | |
165 if (pPage) | |
166 return pPage; | |
167 | |
168 pPage = new CPDFXFA_Page(this, page_index); | |
169 if (!pPage->LoadPage()) { | |
170 pPage->Release(); | |
171 return nullptr; | |
172 } | |
173 m_XFAPageList.SetAt(page_index, pPage); | |
174 return pPage; | |
175 } | |
176 | |
177 CPDFXFA_Page* CPDFXFA_Document::GetXFAPage(CXFA_FFPageView* pPage) const { | |
178 if (!pPage) | |
179 return nullptr; | |
180 | |
181 if (!m_pXFADoc) | |
182 return nullptr; | |
183 | |
184 if (m_iDocType != DOCTYPE_DYNAMIC_XFA) | |
185 return nullptr; | |
186 | |
187 int nSize = m_XFAPageList.GetSize(); | |
188 for (int i = 0; i < nSize; i++) { | |
189 CPDFXFA_Page* pTempPage = m_XFAPageList.GetAt(i); | |
190 if (!pTempPage) | |
191 continue; | |
192 if (pTempPage->GetXFAPageView() && pTempPage->GetXFAPageView() == pPage) | |
193 return pTempPage; | |
194 } | |
195 | |
196 return nullptr; | |
197 } | |
198 | |
199 void CPDFXFA_Document::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 || page_index >= m_XFAPageList.GetSize()) | |
207 return; | |
208 | |
209 if (CPDFXFA_Page* pPage = m_XFAPageList.GetAt(page_index)) | |
210 pPage->Release(); | |
211 } | |
212 | |
213 void CPDFXFA_Document::RemovePage(CPDFXFA_Page* page) { | |
214 m_XFAPageList.SetAt(page->GetPageIndex(), nullptr); | |
215 } | |
216 | |
217 void CPDFXFA_Document::ClearChangeMark() { | |
218 if (m_pFormFillEnv) | |
219 m_pFormFillEnv->ClearChangeMark(); | |
220 } | |
221 | |
222 v8::Isolate* CPDFXFA_Document::GetJSERuntime() const { | |
223 if (!m_pFormFillEnv) | |
224 return nullptr; | |
225 | |
226 // XFA requires V8, if we have V8 then we have a CJS_Runtime and not the stub. | |
227 CJS_Runtime* runtime = | |
228 static_cast<CJS_Runtime*>(m_pFormFillEnv->GetJSRuntime()); | |
229 return runtime->GetIsolate(); | |
230 } | |
231 | |
232 void CPDFXFA_Document::GetAppName(CFX_WideString& wsName) { | |
233 if (m_pFormFillEnv) | |
234 wsName = m_pFormFillEnv->FFI_GetAppName(); | |
235 } | |
236 | |
237 void CPDFXFA_Document::GetLanguage(CFX_WideString& wsLanguage) { | |
238 if (m_pFormFillEnv) | |
239 wsLanguage = m_pFormFillEnv->GetLanguage(); | |
240 } | |
241 | |
242 void CPDFXFA_Document::GetPlatform(CFX_WideString& wsPlatform) { | |
243 if (m_pFormFillEnv) | |
244 wsPlatform = m_pFormFillEnv->GetPlatform(); | |
245 } | |
246 | |
247 void CPDFXFA_Document::Beep(uint32_t dwType) { | |
248 if (m_pFormFillEnv) | |
249 m_pFormFillEnv->JS_appBeep(dwType); | |
250 } | |
251 | |
252 int32_t CPDFXFA_Document::MsgBox(const CFX_WideString& wsMessage, | |
253 const CFX_WideString& wsTitle, | |
254 uint32_t dwIconType, | |
255 uint32_t dwButtonType) { | |
256 if (!m_pFormFillEnv) | |
257 return -1; | |
258 | |
259 uint32_t iconType = 0; | |
260 int iButtonType = 0; | |
261 switch (dwIconType) { | |
262 case XFA_MBICON_Error: | |
263 iconType |= 0; | |
264 break; | |
265 case XFA_MBICON_Warning: | |
266 iconType |= 1; | |
267 break; | |
268 case XFA_MBICON_Question: | |
269 iconType |= 2; | |
270 break; | |
271 case XFA_MBICON_Status: | |
272 iconType |= 3; | |
273 break; | |
274 } | |
275 switch (dwButtonType) { | |
276 case XFA_MB_OK: | |
277 iButtonType |= 0; | |
278 break; | |
279 case XFA_MB_OKCancel: | |
280 iButtonType |= 1; | |
281 break; | |
282 case XFA_MB_YesNo: | |
283 iButtonType |= 2; | |
284 break; | |
285 case XFA_MB_YesNoCancel: | |
286 iButtonType |= 3; | |
287 break; | |
288 } | |
289 int32_t iRet = m_pFormFillEnv->JS_appAlert(wsMessage.c_str(), wsTitle.c_str(), | |
290 iButtonType, iconType); | |
291 switch (iRet) { | |
292 case 1: | |
293 return XFA_IDOK; | |
294 case 2: | |
295 return XFA_IDCancel; | |
296 case 3: | |
297 return XFA_IDNo; | |
298 case 4: | |
299 return XFA_IDYes; | |
300 } | |
301 return XFA_IDYes; | |
302 } | |
303 | |
304 CFX_WideString CPDFXFA_Document::Response(const CFX_WideString& wsQuestion, | |
305 const CFX_WideString& wsTitle, | |
306 const CFX_WideString& wsDefaultAnswer, | |
307 FX_BOOL bMark) { | |
308 CFX_WideString wsAnswer; | |
309 if (!m_pFormFillEnv) | |
310 return wsAnswer; | |
311 | |
312 int nLength = 2048; | |
313 char* pBuff = new char[nLength]; | |
314 nLength = m_pFormFillEnv->JS_appResponse(wsQuestion.c_str(), wsTitle.c_str(), | |
315 wsDefaultAnswer.c_str(), nullptr, | |
316 bMark, pBuff, nLength); | |
317 if (nLength > 0) { | |
318 nLength = nLength > 2046 ? 2046 : nLength; | |
319 pBuff[nLength] = 0; | |
320 pBuff[nLength + 1] = 0; | |
321 wsAnswer = CFX_WideString::FromUTF16LE( | |
322 reinterpret_cast<const unsigned short*>(pBuff), | |
323 nLength / sizeof(unsigned short)); | |
324 } | |
325 delete[] pBuff; | |
326 return wsAnswer; | |
327 } | |
328 | |
329 IFX_SeekableReadStream* CPDFXFA_Document::DownloadURL( | |
330 const CFX_WideString& wsURL) { | |
331 return m_pFormFillEnv ? m_pFormFillEnv->DownloadFromURL(wsURL.c_str()) | |
332 : nullptr; | |
333 } | |
334 | |
335 FX_BOOL CPDFXFA_Document::PostRequestURL(const CFX_WideString& wsURL, | |
336 const CFX_WideString& wsData, | |
337 const CFX_WideString& wsContentType, | |
338 const CFX_WideString& wsEncode, | |
339 const CFX_WideString& wsHeader, | |
340 CFX_WideString& wsResponse) { | |
341 if (!m_pFormFillEnv) | |
342 return FALSE; | |
343 | |
344 wsResponse = m_pFormFillEnv->PostRequestURL( | |
345 wsURL.c_str(), wsData.c_str(), wsContentType.c_str(), wsEncode.c_str(), | |
346 wsHeader.c_str()); | |
347 return TRUE; | |
348 } | |
349 | |
350 FX_BOOL CPDFXFA_Document::PutRequestURL(const CFX_WideString& wsURL, | |
351 const CFX_WideString& wsData, | |
352 const CFX_WideString& wsEncode) { | |
353 return m_pFormFillEnv && | |
354 m_pFormFillEnv->PutRequestURL(wsURL.c_str(), wsData.c_str(), | |
355 wsEncode.c_str()); | |
356 } | |
357 | |
358 void CPDFXFA_Document::LoadString(int32_t iStringID, CFX_WideString& wsString) { | |
359 switch (iStringID) { | |
360 case XFA_IDS_ValidateFailed: | |
361 wsString = L"%s validation failed"; | |
362 return; | |
363 case XFA_IDS_CalcOverride: | |
364 wsString = L"Calculate Override"; | |
365 return; | |
366 case XFA_IDS_ModifyField: | |
367 wsString = L"Are you sure you want to modify this field?"; | |
368 return; | |
369 case XFA_IDS_NotModifyField: | |
370 wsString = L"You are not allowed to modify this field."; | |
371 return; | |
372 case XFA_IDS_AppName: | |
373 wsString = L"pdfium"; | |
374 return; | |
375 case XFA_IDS_Unable_TO_SET: | |
376 wsString = L"Unable to set "; | |
377 return; | |
378 case XFA_IDS_INVAlID_PROP_SET: | |
379 wsString = L"Invalid property set operation."; | |
380 return; | |
381 case XFA_IDS_NOT_DEFAUL_VALUE: | |
382 wsString = L" doesn't have a default property."; | |
383 return; | |
384 case XFA_IDS_UNABLE_SET_LANGUAGE: | |
385 wsString = L"Unable to set language value."; | |
386 return; | |
387 case XFA_IDS_UNABLE_SET_NUMPAGES: | |
388 wsString = L"Unable to set numPages value."; | |
389 return; | |
390 case XFA_IDS_UNABLE_SET_PLATFORM: | |
391 wsString = L"Unable to set platform value."; | |
392 return; | |
393 case XFA_IDS_UNABLE_SET_VARIATION: | |
394 wsString = L"Unable to set variation value."; | |
395 return; | |
396 case XFA_IDS_UNABLE_SET_VERSION: | |
397 wsString = L"Unable to set version value."; | |
398 return; | |
399 case XFA_IDS_UNABLE_SET_READY: | |
400 wsString = L"Unable to set ready value."; | |
401 return; | |
402 case XFA_IDS_COMPILER_ERROR: | |
403 wsString = L"Compiler error."; | |
404 return; | |
405 case XFA_IDS_DIVIDE_ZERO: | |
406 wsString = L"Divide by zero."; | |
407 return; | |
408 case XFA_IDS_ACCESS_PROPERTY_IN_NOT_OBJECT: | |
409 wsString = | |
410 L"An attempt was made to reference property '%s' of a non-object in " | |
411 L"SOM expression %s."; | |
412 return; | |
413 case XFA_IDS_INDEX_OUT_OF_BOUNDS: | |
414 wsString = L"Index value is out of bounds."; | |
415 return; | |
416 case XFA_IDS_INCORRECT_NUMBER_OF_METHOD: | |
417 wsString = L"Incorrect number of parameters calling method '%s'."; | |
418 return; | |
419 case XFA_IDS_ARGUMENT_MISMATCH: | |
420 wsString = L"Argument mismatch in property or function argument."; | |
421 return; | |
422 case XFA_IDS_NOT_HAVE_PROPERTY: | |
423 wsString = L"'%s' doesn't have property '%s'."; | |
424 return; | |
425 case XFA_IDS_VIOLATE_BOUNDARY: | |
426 wsString = | |
427 L"The element [%s] has violated its allowable number of occurrences."; | |
428 return; | |
429 case XFA_IDS_SERVER_DENY: | |
430 wsString = L"Server does not permit."; | |
431 return; | |
432 case XFA_IDS_ValidateLimit: | |
433 wsString = | |
434 L"Message limit exceeded. Remaining %d validation errors not " | |
435 L"reported."; | |
436 return; | |
437 case XFA_IDS_ValidateNullWarning: | |
438 wsString = | |
439 L"%s cannot be blank. To ignore validations for %s, click Ignore."; | |
440 return; | |
441 case XFA_IDS_ValidateNullError: | |
442 wsString = L"%s cannot be blank."; | |
443 return; | |
444 case XFA_IDS_ValidateWarning: | |
445 wsString = | |
446 L"The value you entered for %s is invalid. To ignore validations for " | |
447 L"%s, click Ignore."; | |
448 return; | |
449 case XFA_IDS_ValidateError: | |
450 wsString = L"The value you entered for %s is invalid."; | |
451 return; | |
452 } | |
453 } | |
454 | |
455 IFWL_AdapterTimerMgr* CPDFXFA_Document::GetTimerMgr() { | |
456 CXFA_FWLAdapterTimerMgr* pAdapter = nullptr; | |
457 if (m_pFormFillEnv) | |
458 pAdapter = new CXFA_FWLAdapterTimerMgr(m_pFormFillEnv); | |
459 return pAdapter; | |
460 } | |
OLD | NEW |